diff --git a/llvm/lib/Transforms/Scalar/SCCP.cpp b/llvm/lib/Transforms/Scalar/SCCP.cpp --- a/llvm/lib/Transforms/Scalar/SCCP.cpp +++ b/llvm/lib/Transforms/Scalar/SCCP.cpp @@ -901,16 +901,10 @@ LatticeVal TVal = getValueState(I.getTrueValue()); LatticeVal FVal = getValueState(I.getFalseValue()); - // select ?, C, C -> C. - if (isConstant(TVal) && isConstant(FVal) && - getConstant(TVal) == getConstant(FVal)) - return (void)markConstant(&I, getConstant(FVal)); - - if (TVal.isUnknown()) // select ?, undef, X -> X. - return (void)mergeInValue(&I, FVal); - if (FVal.isUnknown()) // select ?, X, undef -> X. - return (void)mergeInValue(&I, TVal); - markOverdefined(&I); + bool Changed = ValueState[&I].mergeIn(TVal, DL); + Changed |= ValueState[&I].mergeIn(FVal, DL); + if (Changed) + pushToWorkListMsg(ValueState[&I], &I); } // Handle Unary Operators. diff --git a/llvm/test/Transforms/SCCP/ip-ranges-select.ll b/llvm/test/Transforms/SCCP/ip-ranges-select.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/SCCP/ip-ranges-select.ll @@ -0,0 +1,96 @@ +; RUN: opt < %s -ipsccp -S | FileCheck %s + +define internal i1 @f1(i32 %x, i32 %y, i1 %cmp) { +; CHECK-LABEL: define internal i1 @f1(i32 %x, i32 %y, i1 %cmp) { +; CHECK-NEXT: %sel.1 = select i1 %cmp, i32 %x, i32 %y +; CHECK-NEXT: %c.2 = icmp sgt i32 %sel.1, 100 +; CHECK-NEXT: %c.3 = icmp eq i32 %sel.1, 50 +; CHECK-NEXT: %res.1 = add i1 false, %c.2 +; CHECK-NEXT: %res.2 = add i1 %res.1, %c.3 +; CHECK-NEXT: %res.3 = add i1 %res.2, false +; CHECK-NEXT: ret i1 %res.3 +; + %sel.1 = select i1 %cmp, i32 %x, i32 %y + %c.1 = icmp sgt i32 %sel.1, 300 + %c.2 = icmp sgt i32 %sel.1, 100 + %c.3 = icmp eq i32 %sel.1, 50 + %c.4 = icmp slt i32 %sel.1, 9 + %res.1 = add i1 %c.1, %c.2 + %res.2 = add i1 %res.1, %c.3 + %res.3 = add i1 %res.2, %c.4 + ret i1 %res.3 +} + +define i1 @caller1(i1 %cmp) { +; CHECK-LABEL: define i1 @caller1(i1 %cmp) { +; CHECK-NEXT: %call.1 = tail call i1 @f1(i32 10, i32 100, i1 %cmp) +; CHECK-NEXT: %call.2 = tail call i1 @f1(i32 20, i32 200, i1 %cmp) +; CHECK-NEXT: %res = and i1 %call.1, %call.2 +; CHECK-NEXT: ret i1 %res +; + %call.1 = tail call i1 @f1(i32 10, i32 100, i1 %cmp) + %call.2 = tail call i1 @f1(i32 20, i32 200, i1 %cmp) + %res = and i1 %call.1, %call.2 + ret i1 %res +} + + +define i1 @f2(i32 %x, i32 %y, i1 %cmp) { +; CHECK-LABEL: define i1 @f2(i32 %x, i32 %y, i1 %cmp) { +; CHECK-NEXT: %sel.1 = select i1 %cmp, i32 %x, i32 %y +; CHECK-NEXT: %c.1 = icmp sgt i32 %sel.1, 300 +; CHECK-NEXT: %c.2 = icmp sgt i32 %sel.1, 100 +; CHECK-NEXT: %c.3 = icmp eq i32 %sel.1, 50 +; CHECK-NEXT: %c.4 = icmp slt i32 %sel.1, 9 +; CHECK-NEXT: %res.1 = add i1 %c.1, %c.2 +; CHECK-NEXT: %res.2 = add i1 %res.1, %c.3 +; CHECK-NEXT: %res.3 = add i1 %res.2, %c.4 +; CHECK-NEXT: ret i1 %res.3 +; + %sel.1 = select i1 %cmp, i32 %x, i32 %y + %c.1 = icmp sgt i32 %sel.1, 300 + %c.2 = icmp sgt i32 %sel.1, 100 + %c.3 = icmp eq i32 %sel.1, 50 + %c.4 = icmp slt i32 %sel.1, 9 + %res.1 = add i1 %c.1, %c.2 + %res.2 = add i1 %res.1, %c.3 + %res.3 = add i1 %res.2, %c.4 + ret i1 %res.3 +} + +define i1 @caller2(i32 %y, i1 %cmp) { +; CHECK-LABEL: define i1 @caller2(i32 %y, i1 %cmp) { +; CHECK-NEXT: %call.1 = tail call i1 @f2(i32 10, i32 %y, i1 %cmp) +; CHECK-NEXT: %call.2 = tail call i1 @f2(i32 20, i32 %y, i1 %cmp) +; CHECK-NEXT: %res = and i1 %call.1, %call.2 +; CHECK-NEXT: ret i1 %res +; + %call.1 = tail call i1 @f2(i32 10, i32 %y, i1 %cmp) + %call.2 = tail call i1 @f2(i32 20, i32 %y, i1 %cmp) + %res = and i1 %call.1, %call.2 + ret i1 %res +} + +@GV = external global i32 + +define i32 @f3_constantexpr_cond(i32 %x, i32 %y) { +; CHECK-LABEL: define i32 @f3_constantexpr_cond(i32 %x, i32 %y) +; CHECK-NEXT: %sel.1 = select i1 icmp eq (i32* bitcast (i32 (i32, i32)* @f3_constantexpr_cond to i32*), i32* @GV), i32 %x, i32 %y +; CHECK-NEXT: ret i32 %sel.1 +; + %sel.1 = select i1 icmp eq (i32* bitcast (i32 (i32, i32)* @f3_constantexpr_cond to i32*), i32* @GV), i32 %x, i32 %y + ret i32 %sel.1 +} + +define i32 @caller3(i32 %y) { +; CHECK-LABEL: define i32 @caller3(i32 %y) { +; CHECK-NEXT: %call.1 = tail call i32 @f3_constantexpr_cond(i32 10, i32 %y) +; CHECK-NEXT: %call.2 = tail call i32 @f3_constantexpr_cond(i32 20, i32 %y) +; CHECK-NEXT: %res = and i32 %call.1, %call.2 +; CHECK-NEXT: ret i32 %res +; + %call.1 = tail call i32 @f3_constantexpr_cond(i32 10, i32 %y) + %call.2 = tail call i32 @f3_constantexpr_cond(i32 20, i32 %y) + %res = and i32 %call.1, %call.2 + ret i32 %res +} diff --git a/llvm/test/Transforms/SCCP/select.ll b/llvm/test/Transforms/SCCP/select.ll --- a/llvm/test/Transforms/SCCP/select.ll +++ b/llvm/test/Transforms/SCCP/select.ll @@ -1,12 +1,40 @@ -; RUN: opt < %s -sccp -S | not grep select +; RUN: opt < %s -sccp -S | FileCheck %s define i32 @test1(i1 %C) { +; CHECK-LABEL: define i32 @test1( +; CHECK-NEXT: ret i32 0 +; %X = select i1 %C, i32 0, i32 0 ; [#uses=1] ret i32 %X } define i32 @test2(i1 %C) { +; CHECK-LABEL: define i32 @test2( +; CHECK-NEXT: ret i32 0 +; %X = select i1 %C, i32 0, i32 undef ; [#uses=1] ret i32 %X } +define i1 @f2(i32 %x, i1 %cmp) { +; CHECK-LABEL: define i1 @f2(i32 %x, i1 %cmp) { +; CHECK-NEXT: %sel.1 = select i1 %cmp, i32 %x, i32 10 +; CHECK-NEXT: %c.1 = icmp sgt i32 %sel.1, 300 +; CHECK-NEXT: %c.2 = icmp sgt i32 %sel.1, 100 +; CHECK-NEXT: %c.3 = icmp eq i32 %sel.1, 50 +; CHECK-NEXT: %c.4 = icmp slt i32 %sel.1, 9 +; CHECK-NEXT: %res.1 = add i1 %c.1, %c.2 +; CHECK-NEXT: %res.2 = add i1 %res.1, %c.3 +; CHECK-NEXT: %res.3 = add i1 %res.2, %c.4 +; CHECK-NEXT: ret i1 %res.3 +; + %sel.1 = select i1 %cmp, i32 %x, i32 10 + %c.1 = icmp sgt i32 %sel.1, 300 + %c.2 = icmp sgt i32 %sel.1, 100 + %c.3 = icmp eq i32 %sel.1, 50 + %c.4 = icmp slt i32 %sel.1, 9 + %res.1 = add i1 %c.1, %c.2 + %res.2 = add i1 %res.1, %c.3 + %res.3 = add i1 %res.2, %c.4 + ret i1 %res.3 +}