Index: lib/Analysis/ValueTracking.cpp =================================================================== --- lib/Analysis/ValueTracking.cpp +++ lib/Analysis/ValueTracking.cpp @@ -3214,6 +3214,8 @@ switch (Inst->getOpcode()) { default: return true; + //TODO: Div, rem and shifts can probably be smarter about non-constant values, + //and use known bits. case Instruction::UDiv: case Instruction::URem: { // x / y is undefined if y == 0. @@ -3241,6 +3243,20 @@ // The numerator *might* be MinSignedValue. return false; } + case Instruction::AShr: + case Instruction::LShr: + case Instruction::Shl: { + // A shift is undefined if the second operand is equal or larger than + // the number of bits in the first operand. + const APInt *ShiftAmt; + unsigned BitWidth = + cast(Inst->getOperand(0)->getType()->getScalarType()) + ->getBitWidth(); + if (!match(Inst->getOperand(1), m_APInt(ShiftAmt))) + return false; + + return (ShiftAmt->getZExtValue() < BitWidth); + } case Instruction::Load: { const LoadInst *LI = cast(Inst); if (!LI->isUnordered() || Index: test/Transforms/SimplifyCFG/speculat-shift.ll =================================================================== --- test/Transforms/SimplifyCFG/speculat-shift.ll +++ test/Transforms/SimplifyCFG/speculat-shift.ll @@ -0,0 +1,146 @@ +; RUN: opt -S -simplifycfg < %s | FileCheck %s + + +; CHECK-LABEL: @ashr_test_static_good( +; CHECK: select i1 %cmp, i32 %shift, i32 0 +define i32 @ashr_test_static_good(i32 %a, i32 %b) { +entry: + %cmp = icmp eq i32 %a, %b + br i1 %cmp, label %cond.true, label %cond.end + +cond.true: + %shift = ashr i32 %b, 1 + br label %cond.end + +cond.end: + %cond = phi i32 [ %shift, %cond.true ], [ 0, %entry ] + ret i32 %cond +} + +; CHECK-LABEL: @ashr_test_static_bad( +; CHECK: %cond = phi i32 [ %shift, %cond.true ], [ 0, %entry ] +define i32 @ashr_test_static_bad(i32 %a, i32 %b) { +entry: + %cmp = icmp eq i32 %a, %b + br i1 %cmp, label %cond.true, label %cond.end + +cond.true: + %shift = ashr i32 %b, 40 + br label %cond.end + +cond.end: + %cond = phi i32 [ %shift, %cond.true ], [ 0, %entry ] + ret i32 %cond +} + +; CHECK-LABEL: @ashr_test_dynamic( +; CHECK: %cond = phi i32 [ %shift, %cond.true ], [ 0, %entry ] +define i32 @ashr_test_dynamic(i32 %a, i32 %b) { +entry: + %cmp = icmp eq i32 %a, %b + br i1 %cmp, label %cond.true, label %cond.end + +cond.true: + %shift = ashr i32 %b, %a + br label %cond.end + +cond.end: + %cond = phi i32 [ %shift, %cond.true ], [ 0, %entry ] + ret i32 %cond +} + +; CHECK-LABEL: @lshr_test_static_good( +; CHECK: select i1 %cmp, i32 %shift, i32 0 +define i32 @lshr_test_static_good(i32 %a, i32 %b) { +entry: + %cmp = icmp eq i32 %a, %b + br i1 %cmp, label %cond.true, label %cond.end + +cond.true: + %shift = lshr i32 %b, 1 + br label %cond.end + +cond.end: + %cond = phi i32 [ %shift, %cond.true ], [ 0, %entry ] + ret i32 %cond +} + +; CHECK-LABEL: @lshr_test_static_bad( +; CHECK: %cond = phi i32 [ %shift, %cond.true ], [ 0, %entry ] +define i32 @lshr_test_static_bad(i32 %a, i32 %b) { +entry: + %cmp = icmp eq i32 %a, %b + br i1 %cmp, label %cond.true, label %cond.end + +cond.true: + %shift = lshr i32 %b, 40 + br label %cond.end + +cond.end: + %cond = phi i32 [ %shift, %cond.true ], [ 0, %entry ] + ret i32 %cond +} + +; CHECK-LABEL: @lshr_test_dynamic( +; CHECK: %cond = phi i32 [ %shift, %cond.true ], [ 0, %entry ] +define i32 @lshr_test_dynamic(i32 %a, i32 %b) { +entry: + %cmp = icmp eq i32 %a, %b + br i1 %cmp, label %cond.true, label %cond.end + +cond.true: + %shift = lshr i32 %b, %a + br label %cond.end + +cond.end: + %cond = phi i32 [ %shift, %cond.true ], [ 0, %entry ] + ret i32 %cond +} + +; CHECK-LABEL: @shl_test_static_good( +; CHECK: select i1 %cmp, i32 %shift, i32 0 +define i32 @shl_test_static_good(i32 %a, i32 %b) { +entry: + %cmp = icmp eq i32 %a, %b + br i1 %cmp, label %cond.true, label %cond.end + +cond.true: + %shift = shl i32 %b, 1 + br label %cond.end + +cond.end: + %cond = phi i32 [ %shift, %cond.true ], [ 0, %entry ] + ret i32 %cond +} + +; CHECK-LABEL: @shl_test_static_bad( +; CHECK: %cond = phi i32 [ %shift, %cond.true ], [ 0, %entry ] +define i32 @shl_test_static_bad(i32 %a, i32 %b) { +entry: + %cmp = icmp eq i32 %a, %b + br i1 %cmp, label %cond.true, label %cond.end + +cond.true: + %shift = shl i32 %b, 40 + br label %cond.end + +cond.end: + %cond = phi i32 [ %shift, %cond.true ], [ 0, %entry ] + ret i32 %cond +} + +; CHECK-LABEL: @shl_test_dynamic( +; CHECK: %cond = phi i32 [ %shift, %cond.true ], [ 0, %entry ] +define i32 @shl_test_dynamic(i32 %a, i32 %b) { +entry: + %cmp = icmp eq i32 %a, %b + br i1 %cmp, label %cond.true, label %cond.end + +cond.true: + %shift = shl i32 %b, %a + br label %cond.end + +cond.end: + %cond = phi i32 [ %shift, %cond.true ], [ 0, %entry ] + ret i32 %cond +}