Index: lib/Transforms/InstCombine/InstCombineSelect.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineSelect.cpp +++ lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -911,6 +911,16 @@ return V; } +/// Returns true if all users of @p Val are Select instructions. +static bool onlySelectAsUser(const Value &Val) { + for (const Use &U : Val.uses()) { + Instruction *User = cast(U.getUser()); + if (User->getOpcode() != Instruction::Select) + return false; + } + return true; +} + Instruction *InstCombiner::visitSelectInst(SelectInst &SI) { Value *CondVal = SI.getCondition(); Value *TrueVal = SI.getTrueValue(); @@ -1214,6 +1224,29 @@ if (isa(CondVal)) { return ReplaceInstUsesWith(SI, FalseVal); } + } else { + // Avoid arithmetic on i1 types if we can express it with a series of + // selects this usually results in better target code as C0 and C1 + // don't need to be materialized in an integer register. + + // select((C0 & C1), a, b) -> select(C0, select(C1, a, b), b) + if (const Instruction *And = dyn_cast(CondVal)) + if (And->getOpcode() == Instruction::And && onlySelectAsUser(*CondVal)) { + Value *InnerSelect = Builder->CreateSelect(And->getOperand(1), TrueVal, + FalseVal, SI.getName()+".0"); + SI.setOperand(0, And->getOperand(0)); + SI.setOperand(1, InnerSelect); + return &SI; + } + // select((C0 | C1), a, b) -> select(C0, a, select(C1, a, b)) + if (const Instruction *Or = dyn_cast(CondVal)) + if (Or->getOpcode() == Instruction::Or && onlySelectAsUser(*CondVal)) { + Value *InnerSelect = Builder->CreateSelect(Or->getOperand(1), TrueVal, + FalseVal, SI.getName()+".0"); + SI.setOperand(0, Or->getOperand(0)); + SI.setOperand(2, InnerSelect); + return &SI; + } } return nullptr; Index: test/Transforms/InstCombine/select.ll =================================================================== --- test/Transforms/InstCombine/select.ll +++ test/Transforms/InstCombine/select.ll @@ -1492,3 +1492,31 @@ %v = load i128* %p ret i128 %v } + +define i32 @test_select_and(i32 %a, i32 %r0, i32 %r1, i32 %v1, i32 %v2) { + ; CHECK-LABEL: @test_select_and( + ; CHECK: %[[C0:.*]] = icmp sge i32 %a, %v1 + ; CHECK-NEXT: %[[C1:.*]] = icmp slt i32 %a, %v2 + ; CHECK-NEXT: %[[SEL0:.*]] = select i1 %[[C1]], i32 %r0, i32 %r1 + ; CHECK-NEXT: %[[SEL1:.*]] = select i1 %[[C0]], i32 %[[SEL0]], i32 %r1 + ; CHECK-NEXT: ret i32 %[[SEL1]] + %c0 = icmp sge i32 %a, %v1 + %c1 = icmp slt i32 %a, %v2 + %and = and i1 %c0, %c1 + %res = select i1 %and, i32 %r0, i32 %r1 + ret i32 %res +} + +define i32 @test_select_or(i32 %a, i32 %r0, i32 %r1, i32 %v1, i32 %v2) { + ; CHECK-LABEL: @test_select_or( + ; CHECK: %[[C0:.*]] = icmp sge i32 %a, %v1 + ; CHECK-NEXT: %[[C1:.*]] = icmp slt i32 %a, %v2 + ; CHECK-NEXT: %[[SEL0:.*]] = select i1 %[[C1]], i32 %r0, i32 %r1 + ; CHECK-NEXT: %[[SEL1:.*]] = select i1 %[[C0]], i32 %r0, i32 %[[SEL0]] + ; CHECK-NEXT: ret i32 %[[SEL1]] + %c0 = icmp sge i32 %a, %v1 + %c1 = icmp slt i32 %a, %v2 + %and = or i1 %c0, %c1 + %res = select i1 %and, i32 %r0, i32 %r1 + ret i32 %res +} Index: test/Transforms/Reassociate/basictest.ll =================================================================== --- test/Transforms/Reassociate/basictest.ll +++ test/Transforms/Reassociate/basictest.ll @@ -212,7 +212,7 @@ %A = icmp ne i32 %X1, 0 %B = icmp slt i32 %X2, %X3 %C = and i1 %A, %B - %D = select i1 %C, i32 %X1, i32 0 + %D = zext i1 %C to i32 ret i32 %D ; CHECK-LABEL: @test15 ; CHECK: and i1 %A, %B