Index: lib/Transforms/Scalar/LoopUnswitch.cpp =================================================================== --- lib/Transforms/Scalar/LoopUnswitch.cpp +++ lib/Transforms/Scalar/LoopUnswitch.cpp @@ -38,6 +38,7 @@ #include "llvm/Analysis/LoopPass.h" #include "llvm/Analysis/ScalarEvolution.h" #include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/Analysis/ValueTracking.h" #include "llvm/Analysis/BlockFrequencyInfoImpl.h" #include "llvm/Analysis/BlockFrequencyInfo.h" #include "llvm/Analysis/BranchProbabilityInfo.h" @@ -239,11 +240,13 @@ bool TryTrivialLoopUnswitch(bool &Changed); bool UnswitchIfProfitable(Value *LoopCond, Constant *Val, + bool NeedFreeze = true, TerminatorInst *TI = nullptr); void UnswitchTrivialCondition(Loop *L, Value *Cond, Constant *Val, - BasicBlock *ExitBlock, TerminatorInst *TI); + BasicBlock *ExitBlock, bool NeedFreeze, + TerminatorInst *TI); void UnswitchNontrivialCondition(Value *LIC, Constant *OnVal, Loop *L, - TerminatorInst *TI); + bool NeedFreeze, TerminatorInst *TI); void RewriteLoopBodyWithConditionConstant(Loop *L, Value *LIC, Constant *Val, bool isEqual); @@ -595,7 +598,7 @@ Value *LoopCond = FindLIVLoopCondition(Guard->getOperand(0), currentLoop, Changed); if (LoopCond && - UnswitchIfProfitable(LoopCond, ConstantInt::getTrue(Context))) { + UnswitchIfProfitable(LoopCond, ConstantInt::getTrue(Context), true)) { // NB! Unswitching (if successful) could have erased some of the // instructions in Guards leaving dangling pointers there. This is fine // because we're returning now, and won't look at Guards again. @@ -636,7 +639,7 @@ Value *LoopCond = FindLIVLoopCondition(BI->getCondition(), currentLoop, Changed); if (LoopCond && - UnswitchIfProfitable(LoopCond, ConstantInt::getTrue(Context), TI)) { + UnswitchIfProfitable(LoopCond, ConstantInt::getTrue(Context), true, TI)) { ++NumBranches; return true; } @@ -666,7 +669,7 @@ if (!UnswitchVal) continue; - if (UnswitchIfProfitable(LoopCond, UnswitchVal)) { + if (UnswitchIfProfitable(LoopCond, UnswitchVal, true)) { ++NumSwitches; return true; } @@ -680,7 +683,8 @@ Value *LoopCond = FindLIVLoopCondition(SI->getCondition(), currentLoop, Changed); if (LoopCond && UnswitchIfProfitable(LoopCond, - ConstantInt::getTrue(Context))) { + ConstantInt::getTrue(Context), + true)) { ++NumSelects; return true; } @@ -743,6 +747,7 @@ /// simplify the loop. If we decide that this is profitable, /// unswitch the loop, reprocess the pieces, then return true. bool LoopUnswitch::UnswitchIfProfitable(Value *LoopCond, Constant *Val, + bool NeedFreeze, TerminatorInst *TI) { // Check to see if it would be profitable to unswitch current loop. if (!BranchesInfo.CostAllowsUnswitching()) { @@ -754,7 +759,7 @@ return false; } - UnswitchNontrivialCondition(LoopCond, Val, currentLoop, TI); + UnswitchNontrivialCondition(LoopCond, Val, currentLoop, NeedFreeze, TI); return true; } @@ -810,6 +815,27 @@ SplitCriticalEdge(BI, 1, Options); } +static void FreezeBranchCondition(Value *&LIC, BasicBlock *LoopPreheader) { + if (isGuaranteedNotToBeUndefOrPoison(LIC)) + // It is unnecessary to freeze the condition. + return; + + IRBuilder<> Builder(LoopPreheader); + if (isa(LIC)) { + // Terminator with a return value. + // Create a freeze instruction, and put it just before the old + // branch instruction (in loop preheader) + assert (isa(LIC) && "Unknown terminator instruction"); + FreezeInst *FI = new FreezeInst(LIC, LIC->getName() + ".fr"); + FI->insertBefore(LoopPreheader->getTerminator()); + LIC = FI; + } else { + // Put freeze at def of LIC, and replace all uses with the new freeze + LIC = Builder.CreateFreezeAtDef(LIC, LoopPreheader->getParent(), + LIC->getName() + ".fr"); + } +} + /// Given a loop that has a trivial unswitchable condition in it (a cond branch /// from its header block to its latch block, where the path through the loop /// that doesn't execute its body has no side-effects), unswitch it. This @@ -817,6 +843,7 @@ /// outside of the loop and updating loop info. void LoopUnswitch::UnswitchTrivialCondition(Loop *L, Value *Cond, Constant *Val, BasicBlock *ExitBlock, + bool NeedFreeze, TerminatorInst *TI) { DEBUG(dbgs() << "loop-unswitch: Trivial-Unswitch loop %" << loopHeader->getName() << " [" << L->getBlocks().size() @@ -840,6 +867,10 @@ assert(!L->contains(ExitBlock) && "Exit block is in the loop?"); BasicBlock *NewExit = SplitBlock(ExitBlock, &ExitBlock->front(), DT, LI); + // If necessary, freeze the branch condition so it does not introduce UB. + if (NeedFreeze) + FreezeBranchCondition(Cond, loopPreheader); + // Okay, now we have a position to branch from and a position to branch to, // insert the new conditional branch. EmitPreheaderBranchOnCondition(Cond, Val, NewExit, NewPH, @@ -954,7 +985,7 @@ return false; // Can't handle this. UnswitchTrivialCondition(currentLoop, LoopCond, CondVal, LoopExitBB, - CurrentTerm); + true, CurrentTerm); ++NumBranches; return true; } else if (SwitchInst *SI = dyn_cast(CurrentTerm)) { @@ -997,7 +1028,7 @@ return false; // Can't handle this. UnswitchTrivialCondition(currentLoop, LoopCond, CondVal, LoopExitBB, - nullptr); + true, nullptr); ++NumSwitches; return true; } @@ -1025,7 +1056,8 @@ /// Split it into loop versions and test the condition outside of either loop. /// Return the loops created as Out1/Out2. void LoopUnswitch::UnswitchNontrivialCondition(Value *LIC, Constant *Val, - Loop *L, TerminatorInst *TI) { + Loop *L, bool NeedFreeze, + TerminatorInst *TI) { Function *F = loopHeader->getParent(); DEBUG(dbgs() << "loop-unswitch: Unswitching loop %" << loopHeader->getName() << " [" << L->getBlocks().size() @@ -1143,6 +1175,10 @@ assert(OldBR->isUnconditional() && OldBR->getSuccessor(0) == LoopBlocks[0] && "Preheader splitting did not work correctly!"); + // If necessary, freeze the branch condition so it does not introduce UB. + if (NeedFreeze) + FreezeBranchCondition(LIC, loopPreheader); + // Emit the new branch that selects between the two versions of this loop. EmitPreheaderBranchOnCondition(LIC, Val, NewBlocks[0], LoopBlocks[0], OldBR, TI); Index: test/Transforms/LoopUnswitch/2011-11-18-SimpleSwitch.ll =================================================================== --- test/Transforms/LoopUnswitch/2011-11-18-SimpleSwitch.ll +++ test/Transforms/LoopUnswitch/2011-11-18-SimpleSwitch.ll @@ -5,7 +5,8 @@ ; STATS: 1 loop-simplify - Number of pre-header or exit blocks inserted ; STATS: 2 loop-unswitch - Number of switches unswitched -; CHECK: %1 = icmp eq i32 %c, 1 +; CHECK: %c.fr = freeze i32 %c +; CHECK-NEXT: %1 = icmp eq i32 %c.fr, 1 ; CHECK-NEXT: br i1 %1, label %.split.us, label %..split_crit_edge ; CHECK: ..split_crit_edge: ; preds = %0 @@ -24,7 +25,7 @@ ; CHECK-NEXT: br label %loop_begin.backedge.us ; CHECK: .split: ; preds = %..split_crit_edge -; CHECK-NEXT: %2 = icmp eq i32 %c, 2 +; CHECK-NEXT: %2 = icmp eq i32 %c.fr, 2 ; CHECK-NEXT: br i1 %2, label %.split.split.us, label %.split..split.split_crit_edge ; CHECK: .split..split.split_crit_edge: ; preds = %.split @@ -49,7 +50,7 @@ ; CHECK: loop_begin: ; preds = %loop_begin.backedge, %.split.split ; CHECK-NEXT: %var_val = load i32, i32* %var -; CHECK-NEXT: switch i32 %c, label %default.us-lcssa.us-lcssa [ +; CHECK-NEXT: switch i32 %c.fr, label %default.us-lcssa.us-lcssa [ ; CHECK-NEXT: i32 1, label %inc ; CHECK-NEXT: i32 2, label %dec ; CHECK-NEXT: ] Index: test/Transforms/LoopUnswitch/2011-11-18-TwoSwitches-Threshold.ll =================================================================== --- test/Transforms/LoopUnswitch/2011-11-18-TwoSwitches-Threshold.ll +++ test/Transforms/LoopUnswitch/2011-11-18-TwoSwitches-Threshold.ll @@ -7,7 +7,9 @@ ; ModuleID = '../llvm/test/Transforms/LoopUnswitch/2011-11-18-TwoSwitches.ll' -; CHECK: %1 = icmp eq i32 %c, 1 +; CHECK: %c.fr = freeze i32 %c + +; CHECK: %1 = icmp eq i32 %c.fr, 1 ; CHECK-NEXT: br i1 %1, label %.split.us, label %..split_crit_edge ; CHECK: ..split_crit_edge: ; preds = %0 @@ -33,7 +35,7 @@ ; CHECK-NEXT: br label %loop_begin ; CHECK: loop_begin: ; preds = %loop_begin.backedge, %.split -; CHECK: switch i32 %c, label %second_switch [ +; CHECK: switch i32 %c.fr, label %second_switch [ ; CHECK-NEXT: i32 1, label %loop_begin.inc_crit_edge ; CHECK-NEXT: ] Index: test/Transforms/LoopUnswitch/2011-11-18-TwoSwitches.ll =================================================================== --- test/Transforms/LoopUnswitch/2011-11-18-TwoSwitches.ll +++ test/Transforms/LoopUnswitch/2011-11-18-TwoSwitches.ll @@ -5,14 +5,17 @@ ; STATS: 1 loop-simplify - Number of pre-header or exit blocks inserted ; STATS: 3 loop-unswitch - Number of switches unswitched -; CHECK: %1 = icmp eq i32 %c, 1 +; CHECK: %c.fr = freeze i32 %c + +; CHECK: %d.fr = freeze i32 %d +; CHECK-NEXT: %1 = icmp eq i32 %c.fr, 1 ; CHECK-NEXT: br i1 %1, label %.split.us, label %..split_crit_edge ; CHECK: ..split_crit_edge: ; preds = %0 ; CHECK-NEXT: br label %.split ; CHECK: .split.us: ; preds = %0 -; CHECK-NEXT: %2 = icmp eq i32 %d, 1 +; CHECK-NEXT: %2 = icmp eq i32 %d.fr, 1 ; CHECK-NEXT: br i1 %2, label %.split.us.split.us, label %.split.us..split.us.split_crit_edge ; CHECK: .split.us..split.us.split_crit_edge: ; preds = %.split.us @@ -43,7 +46,7 @@ ; CHECK-NEXT: i32 1, label %inc.us ; CHECK: second_switch.us: ; preds = %loop_begin.us -; CHECK-NEXT: switch i32 %d, label %default.us [ +; CHECK-NEXT: switch i32 %d.fr, label %default.us [ ; CHECK-NEXT: i32 1, label %second_switch.us.inc.us_crit_edge ; CHECK-NEXT: ] @@ -55,7 +58,7 @@ ; CHECK-NEXT: br label %loop_begin.backedge.us ; CHECK: .split: ; preds = %..split_crit_edge -; CHECK-NEXT: %3 = icmp eq i32 %d, 1 +; CHECK-NEXT: %3 = icmp eq i32 %d.fr, 1 ; CHECK-NEXT: br i1 %3, label %.split.split.us, label %.split..split.split_crit_edge ; CHECK: .split..split.split_crit_edge: ; preds = %.split @@ -66,7 +69,7 @@ ; CHECK: loop_begin.us1: ; preds = %loop_begin.backedge.us6, %.split.split.us ; CHECK-NEXT: %var_val.us2 = load i32, i32* %var -; CHECK-NEXT: switch i32 %c, label %second_switch.us3 [ +; CHECK-NEXT: switch i32 %c.fr, label %second_switch.us3 [ ; CHECK-NEXT: i32 1, label %loop_begin.inc_crit_edge.us ; CHECK-NEXT: ] @@ -87,7 +90,7 @@ ; CHECK: loop_begin: ; preds = %loop_begin.backedge, %.split.split ; CHECK-NEXT: %var_val = load i32, i32* %var -; CHECK-NEXT: switch i32 %c, label %second_switch [ +; CHECK-NEXT: switch i32 %c.fr, label %second_switch [ ; CHECK-NEXT: i32 1, label %loop_begin.inc_crit_edge ; CHECK-NEXT: ] @@ -95,7 +98,7 @@ ; CHECK-NEXT: br i1 true, label %us-unreachable.us-lcssa, label %inc ; CHECK: second_switch: ; preds = %loop_begin -; CHECK-NEXT: switch i32 %d, label %default [ +; CHECK-NEXT: switch i32 %d.fr, label %default [ ; CHECK-NEXT: i32 1, label %second_switch.inc_crit_edge ; CHECK-NEXT: ] Index: test/Transforms/LoopUnswitch/2015-06-17-Metadata.ll =================================================================== --- test/Transforms/LoopUnswitch/2015-06-17-Metadata.ll +++ test/Transforms/LoopUnswitch/2015-06-17-Metadata.ll @@ -16,7 +16,8 @@ %cmp1 = icmp eq i32 %a, 12345 br i1 %cmp1, label %if.then, label %if.else, !prof !0 ; CHECK: %cmp1 = icmp eq i32 %a, 12345 -; CHECK-NEXT: br i1 %cmp1, label %for.body.us, label %for.body, !prof !0 +; CHECK-NEXT: %cmp1.fr = freeze i1 %cmp1 +; CHECK-NEXT: br i1 %cmp1.fr, label %for.body.us, label %for.body, !prof !0 if.then: ; preds = %for.body ; CHECK: for.body.us: ; CHECK: add nsw i32 %{{.*}}, 123 @@ -53,7 +54,8 @@ br label %for.body ;CHECK: entry: ;CHECK-NEXT: %cmp1 = icmp eq i32 1, 2 -;CHECK-NEXT: br i1 %cmp1, label %for.body, label %for.cond.cleanup.split, !prof !1 +;CHECK-NEXT: %cmp1.fr = freeze i1 %cmp1 +;CHECK-NEXT: br i1 %cmp1.fr, label %for.body, label %for.cond.cleanup.split, !prof !1 ;CHECK: for.body: for.body: ; preds = %for.inc, %entry %inc.i = phi i32 [ 0, %entry ], [ %inc, %if.then ] Index: test/Transforms/LoopUnswitch/copy-metadata.ll =================================================================== --- test/Transforms/LoopUnswitch/copy-metadata.ll +++ test/Transforms/LoopUnswitch/copy-metadata.ll @@ -3,7 +3,8 @@ ; This test checks if unswitched condition preserve make.implicit metadata. define i32 @test(i1 %cond) { -; CHECK: br i1 %cond, label %..split_crit_edge, label %.loop_exit.split_crit_edge, !make.implicit !0 +; CHECK: %cond.fr = freeze i1 %cond +; CHECK: br i1 %cond.fr, label %..split_crit_edge, label %.loop_exit.split_crit_edge, !make.implicit !0 br label %loop_begin loop_begin: Index: test/Transforms/LoopUnswitch/freeze.ll =================================================================== --- /dev/null +++ test/Transforms/LoopUnswitch/freeze.ll @@ -0,0 +1,348 @@ +; 6 test cases which must introduce a freeze instruction after loop unswitch +; RUN: opt < %s -loop-simplify -loop-rotate -loop-unswitch -S | FileCheck %s + +@x = common global i32 0, align 4 +define i32 @emptyf() { +entry: + ret i32 0 +} +declare i32 @g(i32) +declare i32 @h(i32) + +; int f_freeze1(int a, int b){ +; int sum = 0; +; for(int i = 0; i < a; i++){ +; g(0); +; if(b == 0){ +; sum += g(i); +; } +; sum++; +; } +; return sum; +; } + +; CHECK: define i32 @f_freeze1(i32 %a, i32 %b) { +define i32 @f_freeze1(i32 %a, i32 %b) { +entry: + br label %for.cond + +; CHECK: %cmp1 = icmp eq i32 %b, 0 +; CHECK-NEXT: %cmp1.fr = freeze i1 %cmp1 +; CHECK-NEXT: br i1 %cmp1.fr, label %for.body.lr.ph.split.us, label %for.body.lr.ph.for.body.lr.ph.split_crit_edge + +for.cond: ; preds = %for.inc, %entry + %sum.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ] + %i.0 = phi i32 [ 0, %entry ], [ %inc3, %for.inc ] + %cmp = icmp slt i32 %i.0, %a + br i1 %cmp, label %for.body, label %for.end + +for.body: ; preds = %for.cond + %call = call i32 @g(i32 0) + %cmp1 = icmp eq i32 %b, 0 + br i1 %cmp1, label %if.then, label %if.end + +if.then: ; preds = %for.body + %call2 = call i32 @g(i32 %i.0) + %add = add nsw i32 %sum.0, %call2 + br label %if.end + +if.end: ; preds = %if.then, %for.body + %sum.1 = phi i32 [ %add, %if.then ], [ %sum.0, %for.body ] + %inc = add nsw i32 %sum.1, 1 + br label %for.inc + +for.inc: ; preds = %if.end + %inc3 = add nsw i32 %i.0, 1 + br label %for.cond + +for.end: ; preds = %for.cond + ret i32 %sum.0 +} + +; int f_freeze2(int a, int b){ +; int sum = 0; +; for(int i = 0; i < a; i++){ +; g(0); +; if(b == 0){ +; sum += g(i); +; }else{ +; sum += h(i); +; } +; } +; return sum; +; } + +; CHECK: define i32 @f_freeze2(i32 %a, i32 %b) { +define i32 @f_freeze2(i32 %a, i32 %b) { +entry: + br label %for.cond + +; CHECK: %cmp1 = icmp eq i32 %b, 0 +; CHECK-NEXT: %cmp1.fr = freeze i1 %cmp1 +; CHECK-NEXT: br i1 %cmp1.fr, label %for.body.lr.ph.split.us, label %for.body.lr.ph.for.body.lr.ph.split_crit_edge + +for.cond: ; preds = %for.inc, %entry + %sum.0 = phi i32 [ 0, %entry ], [ %sum.1, %for.inc ] + %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ] + %cmp = icmp slt i32 %i.0, %a + br i1 %cmp, label %for.body, label %for.end + +for.body: ; preds = %for.cond + %call = call i32 @g(i32 0) + %cmp1 = icmp eq i32 %b, 0 + br i1 %cmp1, label %if.then, label %if.else + +if.then: ; preds = %for.body + %call2 = call i32 @g(i32 %i.0) + %add = add nsw i32 %sum.0, %call2 + br label %if.end + +if.else: ; preds = %for.body + %call3 = call i32 @h(i32 %i.0) + %add4 = add nsw i32 %sum.0, %call3 + br label %if.end + +if.end: ; preds = %if.else, %if.then + %sum.1 = phi i32 [ %add, %if.then ], [ %add4, %if.else ] + br label %for.inc + +for.inc: ; preds = %if.end + %inc = add nsw i32 %i.0, 1 + br label %for.cond + +for.end: ; preds = %for.cond + ret i32 %sum.0 +} + + +; int f_freeze3(int a, int b){ +; int sum = 0; +; for(int i = 0; i < a; i++){ +; if(x == 0) { +; emptyf(); +; } +; // Unswitching the below branch +; if(b == 0){ +; sum += g(i); +; } +; sum++; +; } +; return sum; +; } + +; CHECK: define i32 @f_freeze3(i32 %a, i32 %b) { +define i32 @f_freeze3(i32 %a, i32 %b) { +entry: + br label %for.cond + +; CHECK: %cmp2 = icmp eq i32 %b, 0 +; CHECK-NEXT: %cmp2.fr = freeze i1 %cmp2 +; CHECK-NEXT: br i1 %cmp2.fr, label %for.body.lr.ph.split.us, label %for.body.lr.ph.for.body.lr.ph.split_crit_edge + +for.cond: ; preds = %for.inc, %entry + %sum.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ] + %i.0 = phi i32 [ 0, %entry ], [ %inc6, %for.inc ] + %cmp = icmp slt i32 %i.0, %a + br i1 %cmp, label %for.body, label %for.end + +for.body: ; preds = %for.cond + %0 = load i32, i32* @x, align 4 + %cmp1 = icmp eq i32 %0, 0 + br i1 %cmp1, label %if.then, label %if.end + +if.then: ; preds = %for.body + %call = call i32 @emptyf() + br label %if.end + +if.end: ; preds = %if.then, %for.body + %cmp2 = icmp eq i32 %b, 0 + br i1 %cmp2, label %if.then3, label %if.end5 + +if.then3: ; preds = %if.end + %call4 = call i32 @g(i32 %i.0) + %add = add nsw i32 %sum.0, %call4 + br label %if.end5 + +if.end5: ; preds = %if.then3, %if.end + %sum.1 = phi i32 [ %add, %if.then3 ], [ %sum.0, %if.end ] + %inc = add nsw i32 %sum.1, 1 + br label %for.inc + +for.inc: ; preds = %if.end5 + %inc6 = add nsw i32 %i.0, 1 + br label %for.cond + +for.end: ; preds = %for.cond + ret i32 %sum.0 +} + +; int f_freeze4(int a, int b){ +; int sum = 0; +; for(int i = 0; i < a; i++){ +; if(x == 0) { +; emptyf(); +; } +; // Unswitching the below branch +; if(b == 0){ +; sum += g(i); +; }else{ +; sum += h(i); +; } +; } +; return sum; +; } + +; CHECK: define i32 @f_freeze4(i32 %a, i32 %b) { +define i32 @f_freeze4(i32 %a, i32 %b) { +entry: + br label %for.cond + +; CHECK: %cmp2 = icmp eq i32 %b, 0 +; CHECK-NEXT: %cmp2.fr = freeze i1 %cmp2 +; CHECK-NEXT: br i1 %cmp2.fr, label %for.body.lr.ph.split.us, label %for.body.lr.ph.for.body.lr.ph.split_crit_edge + +for.cond: ; preds = %for.inc, %entry + %sum.0 = phi i32 [ 0, %entry ], [ %sum.1, %for.inc ] + %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ] + %cmp = icmp slt i32 %i.0, %a + br i1 %cmp, label %for.body, label %for.end + +for.body: ; preds = %for.cond + %0 = load i32, i32* @x, align 4 + %cmp1 = icmp eq i32 %0, 0 + br i1 %cmp1, label %if.then, label %if.end + +if.then: ; preds = %for.body + %call = call i32 @emptyf() + br label %if.end + +if.end: ; preds = %if.then, %for.body + %cmp2 = icmp eq i32 %b, 0 + br i1 %cmp2, label %if.then3, label %if.else + +if.then3: ; preds = %if.end + %call4 = call i32 @g(i32 %i.0) + %add = add nsw i32 %sum.0, %call4 + br label %if.end7 + +if.else: ; preds = %if.end + %call5 = call i32 @h(i32 %i.0) + %add6 = add nsw i32 %sum.0, %call5 + br label %if.end7 + +if.end7: ; preds = %if.else, %if.then3 + %sum.1 = phi i32 [ %add, %if.then3 ], [ %add6, %if.else ] + br label %for.inc + +for.inc: ; preds = %if.end7 + %inc = add nsw i32 %i.0, 1 + br label %for.cond + +for.end: ; preds = %for.cond + ret i32 %sum.0 +} + +; int f_freeze5(int a, int b){ +; int sum = 0; +; for(int i = 0; i < a; i++){ +; sum++; +; if(b == 0){ +; sum += g(i); +; } +; } +; return sum; +; } + +; CHECK: define i32 @f_freeze5(i32 %a, i32 %b) { +define i32 @f_freeze5(i32 %a, i32 %b) { +entry: + br label %for.cond + +; CHECK: %cmp1 = icmp eq i32 %b, 0 +; CHECK-NEXT: %cmp1.fr = freeze i1 %cmp1 +; CHECK-NEXT: br i1 %cmp1.fr, label %for.body.lr.ph.split.us, label %for.body.lr.ph.for.body.lr.ph.split_crit_edge + +for.cond: ; preds = %for.inc, %entry + %sum.0 = phi i32 [ 0, %entry ], [ %sum.1, %for.inc ] + %i.0 = phi i32 [ 0, %entry ], [ %inc2, %for.inc ] + %cmp = icmp slt i32 %i.0, %a + br i1 %cmp, label %for.body, label %for.end + +for.body: ; preds = %for.cond + %inc = add nsw i32 %sum.0, 1 + %cmp1 = icmp eq i32 %b, 0 + br i1 %cmp1, label %if.then, label %if.end + +if.then: ; preds = %for.body + %call = call i32 @g(i32 %i.0) + %add = add nsw i32 %inc, %call + br label %if.end + +if.end: ; preds = %if.then, %for.body + %sum.1 = phi i32 [ %add, %if.then ], [ %inc, %for.body ] + br label %for.inc + +for.inc: ; preds = %if.end + %inc2 = add nsw i32 %i.0, 1 + br label %for.cond + +for.end: ; preds = %for.cond + ret i32 %sum.0 +} + +; int f_freeze6(int a, int b){ +; int sum = 0; +; for(int i = 0; i < a; i++){ +; sum++; +; if(b == 0){ +; sum += g(i); +; }else{ +; sum += h(i); +; } +; } +; return sum; +; } + +; CHECK: define i32 @f_freeze6(i32 %a, i32 %b) { +define i32 @f_freeze6(i32 %a, i32 %b) { +entry: + br label %for.cond + +; CHECK: %cmp1 = icmp eq i32 %b, 0 +; CHECK-NEXT: %cmp1.fr = freeze i1 %cmp1 +; CHECK-NEXT: br i1 %cmp1.fr, label %for.body.lr.ph.split.us, label %for.body.lr.ph.for.body.lr.ph.split_crit_edge + +for.cond: ; preds = %for.inc, %entry + %sum.0 = phi i32 [ 0, %entry ], [ %sum.1, %for.inc ] + %i.0 = phi i32 [ 0, %entry ], [ %inc4, %for.inc ] + %cmp = icmp slt i32 %i.0, %a + br i1 %cmp, label %for.body, label %for.end + +for.body: ; preds = %for.cond + %inc = add nsw i32 %sum.0, 1 + %cmp1 = icmp eq i32 %b, 0 + br i1 %cmp1, label %if.then, label %if.else + +if.then: ; preds = %for.body + %call = call i32 @g(i32 %i.0) + %add = add nsw i32 %inc, %call + br label %if.end + +if.else: ; preds = %for.body + %call2 = call i32 @h(i32 %i.0) + %add3 = add nsw i32 %inc, %call2 + br label %if.end + +if.end: ; preds = %if.else, %if.then + %sum.1 = phi i32 [ %add, %if.then ], [ %add3, %if.else ] + br label %for.inc + +for.inc: ; preds = %if.end + %inc4 = add nsw i32 %i.0, 1 + br label %for.cond + +for.end: ; preds = %for.cond + ret i32 %sum.0 +} + + Index: test/Transforms/LoopUnswitch/infinite-loop.ll =================================================================== --- test/Transforms/LoopUnswitch/infinite-loop.ll +++ test/Transforms/LoopUnswitch/infinite-loop.ll @@ -13,10 +13,12 @@ ; CHECK-LABEL: @func_16( ; CHECK-NEXT: entry: -; CHECK-NEXT: br i1 %a, label %entry.split, label %abort0.split +; CHECK-NEXT: %b.fr = freeze i1 %b +; CHECK-NEXT: %a.fr = freeze i1 %a +; CHECK-NEXT: br i1 %a.fr, label %entry.split, label %abort0.split ; CHECK: entry.split: -; CHECK-NEXT: br i1 %b, label %for.body, label %abort1.split +; CHECK-NEXT: br i1 %b.fr, label %for.body, label %abort1.split ; CHECK: for.body: ; CHECK-NEXT: br label %for.body Index: test/Transforms/LoopUnswitch/msan.ll =================================================================== --- test/Transforms/LoopUnswitch/msan.ll +++ test/Transforms/LoopUnswitch/msan.ll @@ -122,7 +122,8 @@ entry: ; CHECK: %[[Y:.*]] = load i64, i64* @y, align 8 ; CHECK-NEXT: %[[YB:.*]] = icmp eq i64 %[[Y]], 0 -; CHECK-NEXT: br i1 %[[YB]], +; CHECK-NEXT: %[[YB]].fr = freeze i1 %[[YB]] +; CHECK-NEXT: br i1 %[[YB]].fr, %x2 = alloca i8, align 1 %frombool1 = zext i1 %x to i8 Index: test/Transforms/LoopUnswitch/trivial-unswitch.ll =================================================================== --- test/Transforms/LoopUnswitch/trivial-unswitch.ll +++ test/Transforms/LoopUnswitch/trivial-unswitch.ll @@ -5,13 +5,15 @@ ; after unswitching the first one. -; CHECK: br i1 %cond1, label %..split_crit_edge, label %.loop_exit.split_crit_edge +; CHECK: %cond2.fr = freeze i1 %cond2 +; CHECK: %cond1.fr = freeze i1 %cond1 +; CHECK: br i1 %cond1.fr, label %..split_crit_edge, label %.loop_exit.split_crit_edge ; CHECK: ..split_crit_edge: ; preds = %0 ; CHECK: br label %.split ; CHECK: .split: ; preds = %..split_crit_edge -; CHECK: br i1 %cond2, label %.split..split.split_crit_edge, label %.split.loop_exit.split1_crit_edge +; CHECK: br i1 %cond2.fr, label %.split..split.split_crit_edge, label %.split.loop_exit.split1_crit_edge ; CHECK: .split..split.split_crit_edge: ; preds = %.split ; CHECK: br label %.split.split @@ -44,4 +46,4 @@ ret i32 0 } -declare void @some_func() noreturn \ No newline at end of file +declare void @some_func() noreturn