Beispiel #1
0
void cgStElem(IRLS& env, const IRInstruction* inst) {
  auto const rbase = srcLoc(env, inst, 0).reg();
  auto const ridx = srcLoc(env, inst, 1).reg();
  auto const idx = inst->src(1);
  auto& v = vmain(env);

  if (idx->hasConstVal() && deltaFits(idx->intVal(), sz::dword)) {
    storeTV(v, rbase[idx->intVal()], srcLoc(env, inst, 2), inst->src(2));
  } else {
    storeTV(v, rbase[ridx], srcLoc(env, inst, 2), inst->src(2));
  }
}
Beispiel #2
0
void cgLdElem(IRLS& env, const IRInstruction* inst) {
  auto const rbase = srcLoc(env, inst, 0).reg();
  auto const ridx = srcLoc(env, inst, 1).reg();
  auto const idx = inst->src(1);
  auto& v = vmain(env);

  if (idx->hasConstVal() && deltaFits(idx->intVal(), sz::dword)) {
    loadTV(v, inst->dst(), dstLoc(env, inst, 0), rbase[idx->intVal()]);
  } else {
    loadTV(v, inst->dst(), dstLoc(env, inst, 0), rbase[ridx]);
  }
}
Beispiel #3
0
void cgCheckRange(IRLS& env, const IRInstruction* inst) {
  auto valTmp = inst->src(0);
  auto dst = dstLoc(env, inst, 0).reg();
  auto val = srcLoc(env, inst, 0).reg();
  auto limit = srcLoc(env, inst, 1).reg();
  auto& v = vmain(env);

  ConditionCode cc;
  auto const sf = v.makeReg();

  if (valTmp->hasConstVal()) {
    // Try to put the constant in a position that can get imm-folded.  A
    // suffiently smart imm-folder could handle this for us.  Note that this is
    // an arch-agnostic API bleed.
    v << cmpq{val, limit, sf};
    cc = CC_A;
  } else {
    v << cmpq{limit, val, sf};
    cc = CC_B;
  }
  v << setcc{cc, sf, dst};
}
Beispiel #4
0
bool Type::operator<=(Type rhs) const {
  auto const lhs = *this;

  // Check for any members in lhs.m_bits that aren't in rhs.m_bits.
  if ((lhs.m_bits & rhs.m_bits) != lhs.m_bits) {
    return false;
  }

  // Check for Bottom; all the remaining cases assume `lhs' is not Bottom.
  if (lhs.m_bits == kBottom) return true;

  // If `rhs' is a constant, we must be the same constant.
  if (rhs.m_hasConstVal) {
    assertx(!rhs.isUnion());
    return lhs.m_hasConstVal && lhs.m_extra == rhs.m_extra;
  }

  // Make sure lhs's ptr kind is a subtype of rhs's.
  if (!ptrSubsetOf(lhs.ptrKind(), rhs.ptrKind())) {
    return false;
  }

  // If rhs isn't specialized no further checking is needed.
  if (!rhs.isSpecialized()) {
    return true;
  }

  if (lhs.hasConstVal(TArr)) {
    // Arrays can be specialized in different ways, here we check if the
    // constant array fits the kind()/type() of the specialization of rhs, if
    // any.
    auto const lhs_arr = lhs.arrVal();
    auto const rhs_as = rhs.arrSpec();
    return arrayFitsSpec(lhs_arr, rhs_as);
  }

  // Compare specializations only if `rhs' is specialized.
  return lhs.spec() <= rhs.spec();
}
Beispiel #5
0
Type Type::operator-(Type rhs) const {
  auto lhs = *this;
  if (rhs == TBottom) return lhs;
  if (lhs <= rhs) return TBottom;
  if (lhs.hasConstVal()) return lhs;    // not covered by rhs.

  // If `rhs' has a constant value, but `lhs' doesn't, conservatively return
  // `lhs', rather than trying to represent things like "everything except
  // Int<24>". Boolean is a special case.
  if (rhs.m_hasConstVal) {
    if (rhs <= TBool && lhs <= TBool) {
      auto const res = !rhs.boolVal();
      if (lhs.hasConstVal() && lhs.boolVal() != res) return TBottom;
      return cns(res);
    }
    return lhs;
  }

  // For each component C, we should subtract C_rhs from C_lhs iff every other
  // component of lhs that can intersect with C is subsumed by the
  // corresponding component of rhs. This prevents us from removing members of
  // lhs that weren't present in rhs, but would be casualties of removing
  // certain bits in lhs.
  //
  // As an example, consider PtrToRMembInt - PtrToRefStr. Simple subtraction of
  // each component would yield PtrToMembInt, but that would mean we removed
  // PtrToRefInt from the lhs despite it not being in rhs. Checking if Int is a
  // subset of Str shows us that removing Ref from lhs would erase types not
  // present in rhs.
  //
  // In practice, it's more concise to eagerly do each subtraction, then check
  // for components that went to Bottom as a way of seeing which components of
  // lhs were subsets of the corresponding components in rhs. When we find a
  // component that we weren't supposed to subtract, just restore lhs's
  // original value.
  auto bits = lhs.m_bits & ~rhs.m_bits;
  auto ptr = lhs.ptrKind() - rhs.ptrKind();
  auto arrSpec = lhs.arrSpec() - rhs.arrSpec();
  auto clsSpec = lhs.clsSpec() - rhs.clsSpec();

  auto const have_gen_bits = (bits & kGen) != 0;
  auto const have_arr_bits = supports(bits, SpecKind::Array);
  auto const have_cls_bits = supports(bits, SpecKind::Class);
  auto const have_ptr      = ptr != Ptr::Bottom;
  auto const have_arr_spec = arrSpec != ArraySpec::Bottom;
  auto const have_cls_spec = clsSpec != ClassSpec::Bottom;

  // ptr can only interact with clsSpec if lhs.m_bits has at least one kGen
  // member of kClsSpecBits.
  auto const have_ptr_cls = supports(lhs.m_bits & kGen, SpecKind::Class);

  // bits
  if (have_ptr) bits |= lhs.m_bits & kGen;
  if (have_arr_spec) bits |= lhs.m_bits & kArrSpecBits;
  if (have_cls_spec) bits |= lhs.m_bits & kClsSpecBits;

  // ptr
  if (have_gen_bits || have_arr_spec || (have_cls_spec && have_ptr_cls)) {
    ptr = lhs.ptrKind();
  }

  // specs
  if (have_ptr || have_arr_bits) arrSpec = lhs.arrSpec();
  if ((have_ptr && have_ptr_cls) || have_cls_bits) clsSpec = lhs.clsSpec();

  return Type{bits, ptr}.specialize({arrSpec, clsSpec});
}
Beispiel #6
0
TEST(Type, Const) {
  auto five = Type::cns(5);
  EXPECT_LT(five, TInt);
  EXPECT_NE(five, TInt);
  EXPECT_TRUE(five.hasConstVal());
  EXPECT_EQ(5, five.intVal());
  EXPECT_TRUE(five.hasConstVal(TInt));
  EXPECT_TRUE(five.hasConstVal(5));
  EXPECT_FALSE(five.hasConstVal(5.0));
  EXPECT_TRUE(TGen.maybe(five));
  EXPECT_EQ(TInt, five | TInt);
  EXPECT_EQ(TInt, five | Type::cns(10));
  EXPECT_EQ(five, five | Type::cns(5));
  EXPECT_EQ(five, Type::cns(5) & five);
  EXPECT_EQ(five, five & TInt);
  EXPECT_EQ(five, TGen & five);
  EXPECT_EQ("Int<5>", five.toString());
  EXPECT_EQ(five, five - TArr);
  EXPECT_EQ(five, five - Type::cns(1));
  EXPECT_EQ(TInt, TInt - five); // conservative
  EXPECT_EQ(TBottom, five - TInt);
  EXPECT_EQ(TBottom, five - five);
  EXPECT_EQ(TPtrToGen,
            (TPtrToGen|TNullptr) - TNullptr);
  EXPECT_EQ(TInt, five.dropConstVal());
  EXPECT_TRUE(!five.maybe(Type::cns(2)));

  auto True = Type::cns(true);
  EXPECT_EQ("Bool<true>", True.toString());
  EXPECT_LT(True, TBool);
  EXPECT_NE(True, TBool);
  EXPECT_TRUE(True.hasConstVal());
  EXPECT_EQ(true, True.boolVal());
  EXPECT_TRUE(TUncounted.maybe(True));
  EXPECT_FALSE(five <= True);
  EXPECT_FALSE(five > True);

  EXPECT_TRUE(!five.maybe(True));
  EXPECT_EQ(TInt | TBool, five | True);
  EXPECT_EQ(TBottom, five & True);
  EXPECT_EQ(Type::cns(false), TBool - True);

  auto array = make_packed_array(1, 2, 3, 4);
  auto arrData = ArrayData::GetScalarArray(array.get());
  auto constArray = Type::cns(arrData);
  auto packedArray = Type::Array(ArrayData::kPackedKind);
  auto mixedArray = Type::Array(ArrayData::kMixedKind);

  EXPECT_TRUE(constArray <= packedArray);
  EXPECT_TRUE(constArray < packedArray);
  EXPECT_FALSE(packedArray <= constArray);
  EXPECT_TRUE(constArray <= constArray);
  EXPECT_FALSE(packedArray <= mixedArray);
  EXPECT_FALSE(mixedArray <= packedArray);
  EXPECT_FALSE(constArray <= mixedArray);
  EXPECT_EQ(constArray, constArray & packedArray);

  ArrayTypeTable::Builder ratBuilder;
  auto rat1 = ratBuilder.packedn(RepoAuthType::Array::Empty::No,
                                 RepoAuthType(RepoAuthType::Tag::Str));
  auto ratArray1 = Type::Array(rat1);
  auto rat2 = ratBuilder.packedn(RepoAuthType::Array::Empty::No,
                                 RepoAuthType(RepoAuthType::Tag::Int));
  auto ratArray2 = Type::Array(rat2);
  EXPECT_EQ(TArr, ratArray1 & ratArray2);
  EXPECT_TRUE(ratArray1 < TArr);
  EXPECT_TRUE(ratArray1 <= ratArray1);
  EXPECT_TRUE(ratArray1 < (TArr|TObj));
  EXPECT_FALSE(ratArray1 < ratArray2);
  EXPECT_NE(ratArray1, ratArray2);

  auto packedRat = packedArray & ratArray1;
  EXPECT_EQ("Arr=PackedKind:N([Str])", packedRat.toString());
  EXPECT_TRUE(packedRat <= packedArray);
  EXPECT_TRUE(packedRat < packedArray);
  EXPECT_TRUE(packedRat <= ratArray1);
  EXPECT_TRUE(packedRat < ratArray1);
  EXPECT_EQ(packedRat, packedRat & packedArray);
  EXPECT_EQ(packedRat, packedRat & ratArray1);
}