diff --git a/llvm/lib/Transforms/Scalar/GVNHoist.cpp b/llvm/lib/Transforms/Scalar/GVNHoist.cpp index 9ca6ea04f4d5..cf2181b34ebf 100644 --- a/llvm/lib/Transforms/Scalar/GVNHoist.cpp +++ b/llvm/lib/Transforms/Scalar/GVNHoist.cpp @@ -574,7 +574,8 @@ public: llvm_unreachable("Both I and J must be from same BB"); } - bool makeOperandsAvailable(Instruction *Repl, BasicBlock *HoistPt) const { + bool makeOperandsAvailable(Instruction *Repl, BasicBlock *HoistPt, + const SmallVecInsn &InstructionsToHoist) const { // Check whether the GEP of a ld/st can be synthesized at HoistPt. GetElementPtrInst *Gep = nullptr; Instruction *Val = nullptr; @@ -606,7 +607,15 @@ public: // Conservatively discard any optimization hints, they may differ on the // other paths. ClonedGep->dropUnknownNonDebugMetadata(); - ClonedGep->clearSubclassOptionalData(); + for (const Instruction *OtherInst : InstructionsToHoist) { + const GetElementPtrInst *OtherGep; + if (auto *OtherLd = dyn_cast(OtherInst)) + OtherGep = cast(OtherLd->getPointerOperand()); + else + OtherGep = cast( + cast(OtherInst)->getPointerOperand()); + ClonedGep->intersectOptionalDataWith(OtherGep); + } Repl->replaceUsesOfWith(Gep, ClonedGep); // Also copy Val. @@ -616,6 +625,11 @@ public: // Conservatively discard any optimization hints, they may differ on the // other paths. ClonedVal->dropUnknownNonDebugMetadata(); + for (const Instruction *OtherInst : InstructionsToHoist) { + const auto *OtherVal = + cast(cast(OtherInst)->getValueOperand()); + ClonedVal->intersectOptionalDataWith(OtherVal); + } ClonedVal->clearSubclassOptionalData(); Repl->replaceUsesOfWith(Val, ClonedVal); } @@ -652,7 +666,7 @@ public: // The order in which hoistings are done may influence the availability // of operands. if (!allOperandsAvailable(Repl, HoistPt) && - !makeOperandsAvailable(Repl, HoistPt)) + !makeOperandsAvailable(Repl, HoistPt, InstructionsToHoist)) continue; Repl->moveBefore(HoistPt->getTerminator()); // TBAA may differ on one of the other paths, we need to get rid of diff --git a/llvm/test/Transforms/GVN/hoist-md.ll b/llvm/test/Transforms/GVN/hoist-md.ll index 14cc848868e7..8661542c03e6 100644 --- a/llvm/test/Transforms/GVN/hoist-md.ll +++ b/llvm/test/Transforms/GVN/hoist-md.ll @@ -21,6 +21,50 @@ if.end: ; preds = %if.else, %if.then ; CHECK: store i32 2, i32* %x, align 4 ; CHECK-NEXT: br i1 %b +define void @test2(i1 %b, i32* %x) { +entry: + br i1 %b, label %if.then, label %if.else + +if.then: ; preds = %entry + %gep1 = getelementptr inbounds i32, i32* %x, i64 1 + store i32 2, i32* %gep1, align 4, !tbaa !1 + br label %if.end + +if.else: ; preds = %entry + %gep2 = getelementptr inbounds i32, i32* %x, i64 1 + store i32 2, i32* %gep2, align 4, !tbaa !5 + br label %if.end + +if.end: ; preds = %if.else, %if.then + ret void +} +; CHECK-LABEL: define void @test2( +; CHECK: %[[gep:.*]] = getelementptr inbounds i32, i32* %x, i64 1 +; CHECK: store i32 2, i32* %[[gep]], align 4 +; CHECK-NEXT: br i1 %b + +define void @test3(i1 %b, i32* %x) { +entry: + br i1 %b, label %if.then, label %if.else + +if.then: ; preds = %entry + %gep1 = getelementptr inbounds i32, i32* %x, i64 1 + store i32 2, i32* %gep1, align 4, !tbaa !1 + br label %if.end + +if.else: ; preds = %entry + %gep2 = getelementptr i32, i32* %x, i64 1 + store i32 2, i32* %gep2, align 4, !tbaa !5 + br label %if.end + +if.end: ; preds = %if.else, %if.then + ret void +} +; CHECK-LABEL: define void @test3( +; CHECK: %[[gep:.*]] = getelementptr i32, i32* %x, i64 1 +; CHECK: store i32 2, i32* %[[gep]], align 4 +; CHECK-NEXT: br i1 %b + !1 = !{!2, !2, i64 0} !2 = !{!"int", !3, i64 0} !3 = !{!"omnipotent char", !4, i64 0}