[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
http://llvm.org/bugs/show_bug.cgi?id=12850.
Many, many thanks
Andy
// 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())
&&
A.getComplexFloatImag().bitwiseIsEqual(B.getComplexFloatImag());
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
false;
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 =
BaseOrMemberType::getFromOpaqueValue(PathA[I].BaseOrMember).getPointer();
const Decl *BaseOrMemberB =
BaseOrMemberType::getFromOpaqueValue(PathB[I].BaseOrMember).getPointer();
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