Index: llvm/trunk/lib/Transforms/InstCombine/InstCombineSelect.cpp =================================================================== --- llvm/trunk/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ llvm/trunk/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -1178,20 +1178,38 @@ return NV; if (SelectInst *TrueSI = dyn_cast(TrueVal)) { + // select(C, select(C, a, b), c) -> select(C, a, c) if (TrueSI->getCondition() == CondVal) { if (SI.getTrueValue() == TrueSI->getTrueValue()) return nullptr; SI.setOperand(1, TrueSI->getTrueValue()); return &SI; } + // select(C0, select(C1, a, b), b) -> select(C0&C1, a, b) + // We choose this as normal form to enable folding on the And and shortening + // paths for the values (this helps GetUnderlyingObjects() for example). + if (TrueSI->getFalseValue() == FalseVal && TrueSI->hasOneUse()) { + Value *And = Builder->CreateAnd(CondVal, TrueSI->getCondition()); + SI.setOperand(0, And); + SI.setOperand(1, TrueSI->getTrueValue()); + return &SI; + } } if (SelectInst *FalseSI = dyn_cast(FalseVal)) { + // select(C, a, select(C, b, c)) -> select(C, a, c) if (FalseSI->getCondition() == CondVal) { if (SI.getFalseValue() == FalseSI->getFalseValue()) return nullptr; SI.setOperand(2, FalseSI->getFalseValue()); return &SI; } + // select(C0, a, select(C1, a, b)) -> select(C0|C1, a, b) + if (FalseSI->getTrueValue() == TrueVal && FalseSI->hasOneUse()) { + Value *Or = Builder->CreateOr(CondVal, FalseSI->getCondition()); + SI.setOperand(0, Or); + SI.setOperand(2, FalseSI->getFalseValue()); + return &SI; + } } if (BinaryOperator::isNot(CondVal)) { Index: llvm/trunk/test/Transforms/InstCombine/select.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/select.ll +++ llvm/trunk/test/Transforms/InstCombine/select.ll @@ -1492,3 +1492,31 @@ %v = load i128* %p ret i128 %v } + +define i32 @test_select_select0(i32 %a, i32 %r0, i32 %r1, i32 %v1, i32 %v2) { + ; CHECK-LABEL: @test_select_select0( + ; CHECK: %[[C0:.*]] = icmp sge i32 %a, %v1 + ; CHECK-NEXT: %[[C1:.*]] = icmp slt i32 %a, %v2 + ; CHECK-NEXT: %[[C:.*]] = and i1 %[[C1]], %[[C0]] + ; CHECK-NEXT: %[[SEL:.*]] = select i1 %[[C]], i32 %r0, i32 %r1 + ; CHECK-NEXT: ret i32 %[[SEL]] + %c0 = icmp sge i32 %a, %v1 + %s0 = select i1 %c0, i32 %r0, i32 %r1 + %c1 = icmp slt i32 %a, %v2 + %s1 = select i1 %c1, i32 %s0, i32 %r1 + ret i32 %s1 +} + +define i32 @test_select_select1(i32 %a, i32 %r0, i32 %r1, i32 %v1, i32 %v2) { + ; CHECK-LABEL: @test_select_select1( + ; CHECK: %[[C0:.*]] = icmp sge i32 %a, %v1 + ; CHECK-NEXT: %[[C1:.*]] = icmp slt i32 %a, %v2 + ; CHECK-NEXT: %[[C:.*]] = or i1 %[[C1]], %[[C0]] + ; CHECK-NEXT: %[[SEL:.*]] = select i1 %[[C]], i32 %r0, i32 %r1 + ; CHECK-NEXT: ret i32 %[[SEL]] + %c0 = icmp sge i32 %a, %v1 + %s0 = select i1 %c0, i32 %r0, i32 %r1 + %c1 = icmp slt i32 %a, %v2 + %s1 = select i1 %c1, i32 %r0, i32 %s0 + ret i32 %s1 +}