Index: include/llvm/Transforms/Utils/Local.h =================================================================== --- include/llvm/Transforms/Utils/Local.h +++ include/llvm/Transforms/Utils/Local.h @@ -59,14 +59,16 @@ int BonusInstThreshold; bool ConvertSwitchToLookupTable; bool NeedCanonicalLoop; + bool SinkCommonInsts; AssumptionCache *AC; SimplifyCFGOptions(int BonusThreshold = 1, bool SwitchToLookup = false, - bool CanonicalLoops = true, + bool CanonicalLoops = true, bool SinkCommon = false, AssumptionCache *AssumpCache = nullptr) : BonusInstThreshold(BonusThreshold), ConvertSwitchToLookupTable(SwitchToLookup), NeedCanonicalLoop(CanonicalLoops), + SinkCommonInsts(SinkCommon), AC(AssumpCache) {} }; Index: lib/Transforms/Scalar/SimplifyCFGPass.cpp =================================================================== --- lib/Transforms/Scalar/SimplifyCFGPass.cpp +++ lib/Transforms/Scalar/SimplifyCFGPass.cpp @@ -202,12 +202,14 @@ int BonusInstThreshold; bool ConvertSwitchToLookupTable; bool KeepCanonicalLoops; + bool SinkCommonInsts; BaseCFGSimplifyPass(int T, bool ConvertSwitch, bool KeepLoops, + bool SinkCommon, std::function Ftor, char &ID) : FunctionPass(ID), PredicateFtor(std::move(Ftor)), ConvertSwitchToLookupTable(ConvertSwitch), - KeepCanonicalLoops(KeepLoops) { + KeepCanonicalLoops(KeepLoops), SinkCommonInsts(SinkCommon) { BonusInstThreshold = (T == -1) ? UserBonusInstThreshold : T; } bool runOnFunction(Function &F) override { @@ -220,7 +222,7 @@ getAnalysis().getTTI(F); return simplifyFunctionCFG(F, TTI, {BonusInstThreshold, ConvertSwitchToLookupTable, - KeepCanonicalLoops, AC}); + KeepCanonicalLoops, SinkCommonInsts, AC}); } void getAnalysisUsage(AnalysisUsage &AU) const override { @@ -235,7 +237,7 @@ CFGSimplifyPass(int T = -1, std::function Ftor = nullptr) - : BaseCFGSimplifyPass(T, false, true, Ftor, ID) { + : BaseCFGSimplifyPass(T, false, true, false, Ftor, ID) { initializeCFGSimplifyPassPass(*PassRegistry::getPassRegistry()); } }; @@ -245,7 +247,7 @@ LateCFGSimplifyPass(int T = -1, std::function Ftor = nullptr) - : BaseCFGSimplifyPass(T, true, false, Ftor, ID) { + : BaseCFGSimplifyPass(T, true, false, true, Ftor, ID) { initializeLateCFGSimplifyPassPass(*PassRegistry::getPassRegistry()); } }; Index: lib/Transforms/Utils/SimplifyCFG.cpp =================================================================== --- lib/Transforms/Utils/SimplifyCFG.cpp +++ lib/Transforms/Utils/SimplifyCFG.cpp @@ -5681,7 +5681,7 @@ BasicBlock *BB = BI->getParent(); BasicBlock *Succ = BI->getSuccessor(0); - if (SinkCommon && SinkThenElseCodeToEnd(BI)) + if (SinkCommon && Options.SinkCommonInsts && SinkThenElseCodeToEnd(BI)) return true; // If the Terminator is the only non-phi instruction, simplify the block. Index: test/Transforms/PhaseOrdering/earlycse-before-latesimplifycfg.ll =================================================================== --- test/Transforms/PhaseOrdering/earlycse-before-latesimplifycfg.ll +++ test/Transforms/PhaseOrdering/earlycse-before-latesimplifycfg.ll @@ -0,0 +1,41 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -O1 -S < %s | FileCheck %s + +; PR34603 - https://bugs.llvm.org/show_bug.cgi?id=34603 +; We should have a select of doubles, not a select of double pointers. +; SimplifyCFG should not flatten this before early-cse has a chance to eliminate redundant ops. + +define double @max_of_loads(double* %x, double* %y, i64 %i) { +; CHECK-LABEL: @max_of_loads( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[XI_PTR:%.*]] = getelementptr double, double* [[X:%.*]], i64 [[I:%.*]] +; CHECK-NEXT: [[YI_PTR:%.*]] = getelementptr double, double* [[Y:%.*]], i64 [[I]] +; CHECK-NEXT: [[XI:%.*]] = load double, double* [[XI_PTR]], align 8 +; CHECK-NEXT: [[YI:%.*]] = load double, double* [[YI_PTR]], align 8 +; CHECK-NEXT: [[CMP:%.*]] = fcmp ogt double [[XI]], [[YI]] +; CHECK-NEXT: [[XI_YI:%.*]] = select i1 [[CMP]], double [[XI]], double [[YI]] +; CHECK-NEXT: ret double [[XI_YI]] +; +entry: + %xi_ptr = getelementptr double, double* %x, i64 %i + %yi_ptr = getelementptr double, double* %y, i64 %i + %xi = load double, double* %xi_ptr + %yi = load double, double* %yi_ptr + %cmp = fcmp ogt double %xi, %yi + br i1 %cmp, label %if, label %else + +if: + %xi_ptr_again = getelementptr double, double* %x, i64 %i + %xi_again = load double, double* %xi_ptr_again + br label %end + +else: + %yi_ptr_again = getelementptr double, double* %y, i64 %i + %yi_again = load double, double* %yi_ptr_again + br label %end + +end: + %max = phi double [ %xi_again, %if ], [ %yi_again, %else ] + ret double %max +} + Index: test/Transforms/SimplifyCFG/no-md-sink.ll =================================================================== --- test/Transforms/SimplifyCFG/no-md-sink.ll +++ test/Transforms/SimplifyCFG/no-md-sink.ll @@ -1,4 +1,4 @@ -; RUN: opt < %s -simplifycfg -S | FileCheck %s +; RUN: opt < %s -latesimplifycfg -S | FileCheck %s define i1 @test1(i1 zeroext %flag, i8* %y) #0 { entry: Index: test/Transforms/SimplifyCFG/sink-common-code.ll =================================================================== --- test/Transforms/SimplifyCFG/sink-common-code.ll +++ test/Transforms/SimplifyCFG/sink-common-code.ll @@ -1,4 +1,5 @@ -; RUN: opt < %s -simplifycfg -S | FileCheck %s +; RUN: opt < %s -simplifycfg -S | FileCheck %s --check-prefix=EARLY +; RUN: opt < %s -latesimplifycfg -S | FileCheck %s define zeroext i1 @test1(i1 zeroext %flag, i32 %blksA, i32 %blksB, i32 %nblks) { entry: @@ -842,6 +843,65 @@ ; CHECK: insertvalue ; CHECK-NOT: insertvalue +; PR34603 - https://bugs.llvm.org/show_bug.cgi?id=34603 +; We should only sink things like this late because it interferes with early-cse and other passes. + +define double @max_of_loads(double* %x, double* %y, i64 %i) { +; EARLY-LABEL: @max_of_loads( +; EARLY-NEXT: entry: +; EARLY-NEXT: [[XI_PTR:%.*]] = getelementptr double, double* [[X:%.*]], i64 [[I:%.*]] +; EARLY-NEXT: [[YI_PTR:%.*]] = getelementptr double, double* [[Y:%.*]], i64 [[I]] +; EARLY-NEXT: [[XI:%.*]] = load double, double* [[XI_PTR]] +; EARLY-NEXT: [[YI:%.*]] = load double, double* [[YI_PTR]] +; EARLY-NEXT: [[CMP:%.*]] = fcmp ogt double [[XI]], [[YI]] +; EARLY-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[ELSE:%.*]] +; EARLY: if: +; EARLY-NEXT: [[XI_PTR_AGAIN:%.*]] = getelementptr double, double* [[X]], i64 [[I]] +; EARLY-NEXT: [[XI_AGAIN:%.*]] = load double, double* [[XI_PTR_AGAIN]] +; EARLY-NEXT: br label [[END:%.*]] +; EARLY: else: +; EARLY-NEXT: [[YI_PTR_AGAIN:%.*]] = getelementptr double, double* [[Y]], i64 [[I]] +; EARLY-NEXT: [[YI_AGAIN:%.*]] = load double, double* [[YI_PTR_AGAIN]] +; EARLY-NEXT: br label [[END]] +; EARLY: end: +; EARLY-NEXT: [[MAX:%.*]] = phi double [ [[XI_AGAIN]], [[IF]] ], [ [[YI_AGAIN]], [[ELSE]] ] +; EARLY-NEXT: ret double [[MAX]] +; +; CHECK-LABEL: @max_of_loads( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[XI_PTR:%.*]] = getelementptr double, double* [[X:%.*]], i64 [[I:%.*]] +; CHECK-NEXT: [[YI_PTR:%.*]] = getelementptr double, double* [[Y:%.*]], i64 [[I]] +; CHECK-NEXT: [[XI:%.*]] = load double, double* [[XI_PTR]] +; CHECK-NEXT: [[YI:%.*]] = load double, double* [[YI_PTR]] +; CHECK-NEXT: [[CMP:%.*]] = fcmp ogt double [[XI]], [[YI]] +; CHECK-NEXT: [[Y_SINK:%.*]] = select i1 [[CMP]], double* [[X]], double* [[Y]] +; CHECK-NEXT: [[YI_PTR_AGAIN:%.*]] = getelementptr double, double* [[Y_SINK]], i64 [[I]] +; CHECK-NEXT: [[YI_AGAIN:%.*]] = load double, double* [[YI_PTR_AGAIN]] +; CHECK-NEXT: ret double [[YI_AGAIN]] +; +entry: + %xi_ptr = getelementptr double, double* %x, i64 %i + %yi_ptr = getelementptr double, double* %y, i64 %i + %xi = load double, double* %xi_ptr + %yi = load double, double* %yi_ptr + %cmp = fcmp ogt double %xi, %yi + br i1 %cmp, label %if, label %else + +if: + %xi_ptr_again = getelementptr double, double* %x, i64 %i + %xi_again = load double, double* %xi_ptr_again + br label %end + +else: + %yi_ptr_again = getelementptr double, double* %y, i64 %i + %yi_again = load double, double* %yi_ptr_again + br label %end + +end: + %max = phi double [ %xi_again, %if ], [ %yi_again, %else ] + ret double %max +} + ; CHECK: ![[TBAA]] = !{![[TYPE:[0-9]]], ![[TYPE]], i64 0} ; CHECK: ![[TYPE]] = !{!"float", ![[TEXT:[0-9]]]} ; CHECK: ![[TEXT]] = !{!"an example type tree"}