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 @@ -113,6 +113,12 @@ class FunctionDifferenceEngine { DifferenceEngine &Engine; + // Some initializers may reference the variable we're currently checking. This + // can cause an infinite loop. The Saved[LR]HS ivars can be checked to prevent + // recursing. + const Value *SavedLHS; + const Value *SavedRHS; + /// The current mapping from old local values to new local values. DenseMap Values; @@ -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,12 +471,40 @@ 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; } bool equivalentAsOperands(const ConstantExpr *L, const ConstantExpr *R) { if (L == R) return true; + if (L->getOpcode() != R->getOpcode()) return false; @@ -492,9 +526,23 @@ if (L->getNumOperands() != R->getNumOperands()) return false; - for (unsigned I = 0, E = L->getNumOperands(); I != E; ++I) - if (!equivalentAsOperands(L->getOperand(I), R->getOperand(I))) + for (unsigned I = 0, E = L->getNumOperands(); I != E; ++I) { + const auto *LOp = L->getOperand(I); + const auto *ROp = R->getOperand(I); + + if (LOp == SavedLHS || ROp == SavedRHS) { + if (LOp != SavedLHS || ROp != SavedRHS) + // If the left and right operands aren't both re-analyzing the + // variable, then the initialiers don't match, so report "false". + // Otherwise, we skip these operands.. + return false; + + continue; + } + + if (!equivalentAsOperands(LOp, ROp)) return false; + } return true; } @@ -530,6 +578,10 @@ public: FunctionDifferenceEngine(DifferenceEngine &Engine) : Engine(Engine), Queue(QueueSorter(*this_())) {} + FunctionDifferenceEngine(DifferenceEngine &Engine, const Value *SavedLHS, + const Value *SavedRHS) + : Engine(Engine), SavedLHS(SavedLHS), SavedRHS(SavedRHS), + Queue(QueueSorter(*this_())) {} void diff(const Function *L, const Function *R) { if (L->arg_size() != R->arg_size()) @@ -785,8 +837,8 @@ const GlobalVariable *GVR = cast(R); if (GVL->hasLocalLinkage() && GVL->hasUniqueInitializer() && GVR->hasLocalLinkage() && GVR->hasUniqueInitializer()) - return FunctionDifferenceEngine(*this).equivalentAsOperands( - GVL->getInitializer(), GVR->getInitializer()); + return FunctionDifferenceEngine(*this, GVL, GVR) + .equivalentAsOperands(GVL->getInitializer(), GVR->getInitializer()); } return L->getName() == R->getName();