Beispiel #1
0
AliasClass AliasClass::operator|(AliasClass o) const {
  if (auto const c = precise_union(o)) return *c;

  auto const unioned = static_cast<rep>(m_bits | o.m_bits);

  // If they have the same stag, try to merge them with unionData.
  auto stag1 = m_stag;
  auto stag2 = o.m_stag;
  if (stag1 == stag2) return unionData(unioned, *this, o);

  // If one of the alias classes have a non-None stag, we can only keep it if
  // the other doesn't have the corresponding bit set.
  if (stag1 != STag::None && (o.m_bits & stagBit(stag1))) stag1 = STag::None;
  if (stag2 != STag::None && (m_bits & stagBit(stag2))) stag2 = STag::None;

  auto ret = AliasClass{unioned};
  if (stag1 == stag2) return ret;       // both None.

  // Note: union operations are guaranteed to be commutative, so if there are
  // two non-None stags, we have to consistently choose between them. For now
  // we keep the one with a smaller `rep' value, instead of discarding both.
  const AliasClass* chosen = &o;
  auto stag = stag2;
  if (stag1 != STag::None) {
    if (stag2 == STag::None || stagBit(stag1) < stagBit(stag2)) {
      chosen = this;
      stag = stag1;
    }
  }

  switch (stag) {
  case STag::None:
    break;
  case STag::Frame:   new (&ret.m_frame) AFrame(chosen->m_frame); break;
  case STag::Prop:    new (&ret.m_prop) AProp(chosen->m_prop); break;
  case STag::ElemI:   new (&ret.m_elemI) AElemI(chosen->m_elemI); break;
  case STag::ElemS:   new (&ret.m_elemS) AElemS(chosen->m_elemS); break;
  case STag::Stack:   new (&ret.m_stack) AStack(chosen->m_stack); break;
  case STag::MIState: new (&ret.m_mis) AMIState(chosen->m_mis); break;
  case STag::Ref:     new (&ret.m_ref) ARef(chosen->m_ref); break;
  }
  ret.m_stag = stag;
  return ret;
}
Beispiel #2
0
TEST(AliasClass, IterUnion) {
  IRUnit unit{test_context};
  auto const marker = BCMarker::Dummy();
  auto const FP = unit.gen(DefFP, marker)->dst();

  {
    AliasClass const iterP0 = AIterPos { FP, 0 };
    AliasClass const iterP1 = AIterPos { FP, 1 };
    auto const u1 = iterP0 | iterP1;
    EXPECT_EQ(u1, AIterPosAny);
    EXPECT_TRUE(iterP0 <= AIterPosAny);
    EXPECT_FALSE(iterP0 <= AIterBaseAny);
  }

  {
    AliasClass const iterP0 = AIterPos { FP, 0 };
    AliasClass const iterB0 = AIterBase { FP, 0 };
    AliasClass const iterP1 = AIterPos { FP, 1 };
    auto const u1 = iterP0 | iterB0;
    EXPECT_TRUE(iterP0 <= u1);
    EXPECT_TRUE(iterB0 <= u1);
    EXPECT_FALSE(u1 <= AIterPosAny);
    EXPECT_FALSE(u1 <= AIterBaseAny);
    EXPECT_TRUE(u1 <= (AIterPosAny | AIterBaseAny));
    EXPECT_FALSE(iterP1 <= u1);
    EXPECT_FALSE(iterP1 <= iterP0);
    EXPECT_FALSE(iterP1 <= iterB0);

    EXPECT_TRUE(!!u1.iterPos());
    EXPECT_TRUE(!!u1.iterBase());
    EXPECT_TRUE(!u1.is_iterPos());
    EXPECT_TRUE(!u1.is_iterBase());
  }

  {
    AliasClass const local = AFrame { FP, 0 };
    AliasClass const iter  = AIterPos { FP, 0 };
    auto const u1 = local | iter;
    EXPECT_TRUE(local <= u1);
    EXPECT_TRUE(iter <= u1);
    EXPECT_FALSE(!!u1.is_iterPos());
    EXPECT_FALSE(!!u1.is_frame());
    EXPECT_TRUE(!!u1.frame());  // locals are preferred in unions to iters
    EXPECT_FALSE(!!u1.iterPos());
  }

  {
    AliasClass const iterP0 = AIterPos { FP, 0 };
    AliasClass const iterB0 = AIterBase { FP, 0 };
    AliasClass const iterP1 = AIterPos { FP, 1 };
    AliasClass const iterB1 = AIterBase { FP, 1 };

    EXPECT_FALSE(iterP0.maybe(iterP1));
    EXPECT_FALSE(iterB0.maybe(iterB1));

    auto const u1 = iterP0 | iterB0;
    auto const u2 = iterP1 | iterB1;
    EXPECT_FALSE(u1 == u2);
    EXPECT_FALSE(u1.maybe(u2));
    EXPECT_FALSE(u1 <= u2);
    EXPECT_FALSE(u2 <= u1);

    EXPECT_TRUE(iterB1 <= u2);
    EXPECT_TRUE(iterP1 <= u2);
    EXPECT_FALSE(iterP0 <= u2);
    EXPECT_FALSE(iterB0 <= u2);

    auto const u3 = u1 | iterP1;
    EXPECT_FALSE(!!u3.iterPos());
    EXPECT_FALSE(!!u3.iterBase());
    EXPECT_TRUE(iterP1 <= u3);
    EXPECT_TRUE(iterP0 <= u3);
    EXPECT_TRUE(iterB0 <= u3);
    EXPECT_TRUE(u1 <= u3);
    EXPECT_TRUE(u2.maybe(u3));

    // u2 <= u3 isn't 'really' true, but operator| is conservative and makes u3
    // too big for that right now.
    EXPECT_TRUE(!u1.precise_union(iterP1));
  }
}