diff --git a/llvm/test/tools/llvm-diff/initializers.ll b/llvm/test/tools/llvm-diff/initializers.ll --- a/llvm/test/tools/llvm-diff/initializers.ll +++ b/llvm/test/tools/llvm-diff/initializers.ll @@ -10,3 +10,29 @@ %1 = getelementptr [2 x i16*], [2 x i16*]* @gv2, i64 0, i64 undef ret void } + +; A named structure may be renamed when the right module is read. This is due +; to the LLParser being different between the left and right modules, and the +; context renaming one. + +%struct.ty1 = type { i16, i16 } + +@gv3 = internal global [1 x %struct.ty1] [%struct.ty1 { i16 928, i16 0 }], align 16 + +define void @bar() { + %1 = getelementptr [1 x %struct.ty1], [1 x %struct.ty1]* @gv3, i64 0, i64 undef + ret void +} + +; An initializer may reference the variable it's initializing via bitcast / +; GEP. Check that it doesn't cause an infinite loop. + +%struct.mutex = type { %struct.list_head } +%struct.list_head = type { %struct.list_head*, %struct.list_head* } + +@vmx_l1d_flush_mutex = internal global %struct.mutex { %struct.list_head { %struct.list_head* bitcast (i8* getelementptr (i8, i8* bitcast (%struct.mutex* @vmx_l1d_flush_mutex to i8*), i64 16) to %struct.list_head*), %struct.list_head* bitcast (i8* getelementptr (i8, i8* bitcast (%struct.mutex* @vmx_l1d_flush_mutex to i8*), i64 16) to %struct.list_head*) } }, align 8 + +define internal i32 @qux() { + call void undef(%struct.mutex* @vmx_l1d_flush_mutex) + ret i32 undef +} diff --git a/llvm/tools/llvm-diff/DifferenceEngine.cpp b/llvm/tools/llvm-diff/DifferenceEngine.cpp --- a/llvm/tools/llvm-diff/DifferenceEngine.cpp +++ b/llvm/tools/llvm-diff/DifferenceEngine.cpp @@ -404,6 +404,12 @@ return false; } +private: + // Some instructions may reference the variable we're currently checking. This + // can cause an infinite loop. Prevent this by checking if we're trying to + // analyzze the variable we're currently checking. + const Value *CurrentLGV; + public: bool equivalentAsOperands(const Constant *L, const Constant *R) { // Use equality as a preliminary filter. @@ -412,7 +418,7 @@ if (L->getValueID() != R->getValueID()) return false; - + // Ask the engine about global values. if (isa(L)) return Engine.equivalentAsOperands(cast(L), @@ -465,6 +471,33 @@ return true; } + // If L and R are ConstantStructs, compare each field and type. + if (isa(L)) { + const ConstantStruct *CSL = cast(L); + const ConstantStruct *CSR = cast(R); + + const StructType *LTy = cast(CSL->getType()); + const StructType *RTy = cast(CSR->getType()); + + // The StructTypes should have the same attributes. Don't use + // isLayoutIdentical(), because that just checks the element pointers, + // which may not work here. + if (LTy->getNumElements() != RTy->getNumElements() || + LTy->isPacked() != RTy->isPacked()) + return false; + + for (unsigned I = 0; I < LTy->getNumElements(); I++) { + const Value *LAgg = CSL->getAggregateElement(I); + const Value *RAgg = CSR->getAggregateElement(I); + + if (!equivalentAsOperands(LAgg, RAgg)) { + return false; + } + } + + return true; + } + return false; } @@ -492,14 +525,22 @@ if (L->getNumOperands() != R->getNumOperands()) return false; - for (unsigned I = 0, E = L->getNumOperands(); I != E; ++I) + for (unsigned I = 0, E = L->getNumOperands(); I != E; ++I) { + if (L->getOperand(I) == CurrentLGV) + continue; + if (!equivalentAsOperands(L->getOperand(I), R->getOperand(I))) return false; + } return true; } - bool equivalentAsOperands(const Value *L, const Value *R) { + bool equivalentAsOperands(const Value *L, const Value *R, + const GlobalValue *LGV = nullptr) { + if (LGV) + CurrentLGV = LGV; + // Fall out if the values have different kind. // This possibly shouldn't take priority over oracles. if (L->getValueID() != R->getValueID()) @@ -786,7 +827,7 @@ if (GVL->hasLocalLinkage() && GVL->hasUniqueInitializer() && GVR->hasLocalLinkage() && GVR->hasUniqueInitializer()) return FunctionDifferenceEngine(*this).equivalentAsOperands( - GVL->getInitializer(), GVR->getInitializer()); + GVL->getInitializer(), GVR->getInitializer(), GVL); } return L->getName() == R->getName();