[cfe-dev] Help with APValue comparisons

Andy Gibbs andyg1001 at hotmail.co.uk
Fri Jun 15 00:38:10 PDT 2012

Hi Jordan,

Thanks for your pointers.  I've implemented an "isEqual" function as below. 
If you have time, would you mind having a quick skim through please to see 
if I've caught the right idea.  At the moment, it holds up to the testing I 
have performed so far, but I'm always working on more test-cases!

At this point, my concern is not that isEqual may not fully distinguish two 
APValues that *are* equal, more that it should never say two APValues are 
equal when they aren't.  False negatives are much less of an issue than 
false positives!

I haven't implemented equality checking for member pointers, yet.  Again, 
this is due to a lack of understand on exactly how to implement this check 
(it seems even the dump / printPretty functions have not been fully 
implemented for this type).

If you think my approach is valid, then I will post a tentative patch for 

Many, many thanks


// static member function of APValue
bool APValue::isEqual(const APValue &A, const APValue &B) {
  if (A.getKind() != B.getKind())
    return false;

  switch (A.getKind()) {
    case Uninitialized:
      return true;

    case Int:
      return (A.getInt() == B.getInt());

    case Float:
      return A.getFloat().bitwiseIsEqual(B.getFloat());

    case ComplexInt:
      return (A.getComplexIntReal() == B.getComplexIntReal()) &&
             (A.getComplexIntImag() == B.getComplexIntImag());

    case ComplexFloat:
      return A.getComplexFloatReal().bitwiseIsEqual(B.getComplexFloatReal()) 

    case Vector: {
      unsigned len = A.getVectorLength();
      if (len != B.getVectorLength()) return false;
      for (unsigned i = 0; i != len; ++i) {
        if (!isEqual(A.getVectorElt(i), B.getVectorElt(i)))
          return false;
      return true;

    case Array: {
      unsigned len = A.getArraySize();
      if (len != B.getArraySize()) return false;

      APValue FillerA, FillerB;
      if (A.hasArrayFiller()) FillerA = A.getArrayFiller();
      if (B.hasArrayFiller()) FillerB = B.getArrayFiller();

      // Two arrays are equal if their initialised elements are equal,
      // but also where one array is more initialised than another, where
      // those additional initialised elements are equal to the filler
      // of the other.  If they both contain uninitialised elements, the
      // fillers must also match.
      for (unsigned i = 0, a = A.getArrayInitializedElts(),
                           b = B.getArrayInitializedElts(); i != len; ++i) {
        if (!isEqual(
              (i < a) ? A.getArrayInitializedElt(i) : FillerA,
              (i < b) ? B.getArrayInitializedElt(i) : FillerB))
          return false;
        if (i >= a && i >= b) // all the initialised elements *and* the
          break;              // fillers have been compared; we're equal!
      return true;

    case Struct: {
      unsigned bases = A.getStructNumBases();
      if (bases != B.getStructNumBases()) return false;

      unsigned fields = A.getStructNumFields();
      if (fields != B.getStructNumFields()) return false;

      for (unsigned i = 0; i != bases; ++i) {
        if (!isEqual(A.getStructBase(i), B.getStructBase(i)))
          return false;

      for (unsigned i = 0; i != fields; ++i) {
        if (!isEqual(A.getStructField(i), B.getStructField(i)))
          return false;

      return true;

    case Union:
      return (A.getUnionField() == B.getUnionField()) &&
             (isEqual(A.getUnionValue(), B.getUnionValue()));

    case AddrLabelDiff:
      return (A.getAddrLabelDiffLHS() == B.getAddrLabelDiffLHS()) &&
             (A.getAddrLabelDiffRHS() == B.getAddrLabelDiffRHS());

    case LValue: {
      LValueBase BaseA = A.getLValueBase();
      LValueBase BaseB = B.getLValueBase();

      // null pointers are not comparable
      if (!BaseA || !BaseB || BaseA.isNull() || BaseB.isNull()) return 

      bool IsValueDecl = BaseA.is<const ValueDecl*>();
      if (IsValueDecl != BaseB.is<const ValueDecl*>()) return false;

      QualType ElemTy;
      if (IsValueDecl) {
        const ValueDecl *VD = BaseA.get<const ValueDecl*>();
        ElemTy = VD->getType();
        if (VD != BaseB.get<const ValueDecl*>()) return false;
      } else {
        const Expr *E = BaseA.get<const Expr*>();
        ElemTy = E->getType();
        if (E != BaseB.get<const Expr*>()) return false;

      bool HasPath = A.hasLValuePath();
      if (HasPath != B.hasLValuePath()) return false;

      if (!HasPath) {
        return A.getLValueOffset() == B.getLValueOffset();

      ArrayRef<LValuePathEntry> PathA = A.getLValuePath();
      ArrayRef<LValuePathEntry> PathB = B.getLValuePath();
      if (PathA.size() != PathB.size()) return false;

      for (unsigned I = 0, N = PathA.size(); I != N; ++I) {
        if (ElemTy->getAs<RecordType>()) {
          const Decl *BaseOrMemberA = 
          const Decl *BaseOrMemberB = 

          if (BaseOrMemberA != BaseOrMemberB) return false;
          if (const CXXRecordDecl *RD = 
dyn_cast<CXXRecordDecl>(BaseOrMemberA)) {
            const Type *T = RD->getTypeForDecl();
            assert(T && "getTypeForDecl did not return a valid value");
            ElemTy = QualType(T, 0);
          } else {
            const ValueDecl *VD = cast<ValueDecl>(BaseOrMemberA);
            ElemTy = VD->getType();
        } else {
          if (PathA[I].ArrayIndex != PathB[I].ArrayIndex) return false;

          assert(dyn_cast<ArrayType>(ElemTy) && "Unexpected ElemTy");
          ElemTy = dyn_cast<ArrayType>(ElemTy)->getElementType();

      return true;

    case MemberPointer:
      llvm_unreachable("isEqual unimplemented for this APValue kind!");
      return false;
  llvm_unreachable("Unknown APValue kind!");
  return false;

More information about the cfe-dev mailing list