Index: llvm/trunk/lib/Transforms/Scalar/LoopUnswitch.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/LoopUnswitch.cpp +++ llvm/trunk/lib/Transforms/Scalar/LoopUnswitch.cpp @@ -47,6 +47,7 @@ #include "llvm/IR/Dominators.h" #include "llvm/IR/Function.h" #include "llvm/IR/Instructions.h" +#include "llvm/IR/InstrTypes.h" #include "llvm/IR/Module.h" #include "llvm/IR/MDBuilder.h" #include "llvm/Support/CommandLine.h" @@ -235,6 +236,11 @@ TerminatorInst *TI); void SimplifyCode(std::vector &Worklist, Loop *L); + + /// Given that the Invariant is not equal to Val. Simplify instructions + /// in the loop. + Value *SimplifyInstructionWithNotEqual(Instruction *Inst, Value *Invariant, + Constant *Val); }; } @@ -1218,10 +1224,21 @@ if (!UI || !L->contains(UI)) continue; - Worklist.push_back(UI); + // At this point, we know LIC is definitely not Val. Try to use some simple + // logic to simplify the user w.r.t. to the context. + if (Value *Replacement = SimplifyInstructionWithNotEqual(UI, LIC, Val)) { + if (LI->replacementPreservesLCSSAForm(UI, Replacement)) { + // This in-loop instruction has been simplified w.r.t. its context, + // i.e. LIC != Val, make sure we propagate its replacement value to + // all its users. + ReplaceUsesOfWith(UI, Replacement, Worklist, L, LPM); + continue; + } + } - // TODO: We could do other simplifications, for example, turning - // 'icmp eq LIC, Val' -> false. + // Unable to simplify with non-valueness, push it into the worklist so that + // SimplifyCode can attempt to simplify it. + Worklist.push_back(UI); // If we know that LIC is not Val, use this info to simplify code. SwitchInst *SI = dyn_cast(UI); @@ -1362,3 +1379,27 @@ } } } + +/// Simple simplifications we can do given the information that Cond is +/// definitely not equal to Val. +Value *LoopUnswitch::SimplifyInstructionWithNotEqual(Instruction *Inst, + Value *Invariant, + Constant *Val) { + // icmp eq cond, val -> false + ICmpInst *CI = dyn_cast(Inst); + if (CI && CI->isEquality()) { + Value *Op0 = CI->getOperand(0); + Value *Op1 = CI->getOperand(1); + if ((Op0 == Invariant && Op1 == Val) || (Op0 == Val && Op1 == Invariant)) { + LLVMContext &Ctx = Inst->getContext(); + if (CI->getPredicate() == CmpInst::ICMP_EQ) + return ConstantInt::getFalse(Ctx); + else + return ConstantInt::getTrue(Ctx); + } + } + + // FIXME: there may be other opportunities, e.g. comparison with floating + // point, or Invariant - Val != 0, etc. + return nullptr; +} Index: llvm/trunk/test/Transforms/LoopUnswitch/simplify-with-nonvalness.ll =================================================================== --- llvm/trunk/test/Transforms/LoopUnswitch/simplify-with-nonvalness.ll +++ llvm/trunk/test/Transforms/LoopUnswitch/simplify-with-nonvalness.ll @@ -0,0 +1,58 @@ +; RUN: opt < %s -loop-unswitch -verify-loop-info -S < %s 2>&1 | FileCheck %s + +; There are 1 case and 1 default case in the switch. after we unswitch, we know the +; %a is definitely not 0 in one of the unswitched loop, make sure we take advantage +; of that and simplify the branches in the loop. +; +; CHECK: define void @simplify_with_nonvalness( + +; This is the loop in which we know %a is definitely 0. +; CHECK: sw.bb.us: +; CHECK: br i1 true, label %if.then.us, label %if.end.us + +; This is the loop in which we do not know what %a is but we know %a is definitely NOT 0. +; Make sure we use that information to simplify. +; The icmp eq i32 %a, 0 in one of the unswitched loop is simplified to false. +; CHECK: sw.bb.split: +; CHECK: br i1 false, label %if.then, label %if.end + +define void @simplify_with_nonvalness(i32 %a) #0 { +entry: + br label %for.cond + +for.cond: + %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ] + %cmp = icmp slt i32 %i.0, 1024 + br i1 %cmp, label %for.body, label %for.end + +for.body: + switch i32 %a, label %sw.default [ + i32 0, label %sw.bb + ] + +sw.bb: + %cmp1 = icmp eq i32 %a, 0 + br i1 %cmp1, label %if.then, label %if.end + +if.then: + call void (...) @bar() + br label %if.end + +if.end: + br label %sw.epilog + +sw.default: + br label %sw.epilog + +sw.epilog: + br label %for.inc + +for.inc: + %inc = add nsw i32 %i.0, 1 + br label %for.cond + +for.end: + ret void +} + +declare void @bar(...)