diff --git a/include/llvm/Target/TargetLowering.h b/include/llvm/Target/TargetLowering.h index ab91413e764..b03d35a00b2 100644 --- a/include/llvm/Target/TargetLowering.h +++ b/include/llvm/Target/TargetLowering.h @@ -1388,6 +1388,13 @@ public: Action != TypeSplitVector; } + /// Return true if a select of constants (select Cond, C1, C2) should be + /// transformed into simple math ops with the condition value. For example: + /// select Cond, C1, C1-1 --> add (zext Cond), C1-1 + virtual bool convertSelectOfConstantsToMath() const { + return false; + } + //===--------------------------------------------------------------------===// // TargetLowering Configuration Methods - These methods should be invoked by // the derived class constructor to configure this object for the target. diff --git a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index 8ac41197b62..5b29f18c79b 100644 --- a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -5725,8 +5725,6 @@ SDValue DAGCombiner::foldSelectOfConstants(SDNode *N) { // transforms in the other direction (create a select from a zext/sext). There // is also a target-independent combine here in DAGCombiner in the other // direction for (select Cond, -1, 0) when the condition is not i1. - // TODO: This could be generalized for any 2 constants that differ by 1: - // add ({s/z}ext Cond), C if (CondVT == MVT::i1 && !LegalOperations) { if (C1->isNullValue() && C2->isOne()) { // select Cond, 0, 1 --> zext (!Cond) @@ -5754,6 +5752,25 @@ SDValue DAGCombiner::foldSelectOfConstants(SDNode *N) { Cond = DAG.getNode(ISD::SIGN_EXTEND, DL, VT, Cond); return Cond; } + + // For any constants that differ by 1, we can transform the select into an + // extend and add. Use a target hook because some targets may prefer to + // transform in the other direction. + if (TLI.convertSelectOfConstantsToMath()) { + if (C1->getAPIntValue() - 1 == C2->getAPIntValue()) { + // select Cond, C1, C1-1 --> add (zext Cond), C1-1 + if (VT != MVT::i1) + Cond = DAG.getNode(ISD::ZERO_EXTEND, DL, VT, Cond); + return DAG.getNode(ISD::ADD, DL, VT, Cond, N2); + } + if (C1->getAPIntValue() + 1 == C2->getAPIntValue()) { + // select Cond, C1, C1+1 --> add (sext Cond), C1+1 + if (VT != MVT::i1) + Cond = DAG.getNode(ISD::SIGN_EXTEND, DL, VT, Cond); + return DAG.getNode(ISD::ADD, DL, VT, Cond, N2); + } + } + return SDValue(); } diff --git a/lib/Target/PowerPC/PPCISelLowering.h b/lib/Target/PowerPC/PPCISelLowering.h index d12cd4ab1f3..caaeaa97b0f 100644 --- a/lib/Target/PowerPC/PPCISelLowering.h +++ b/lib/Target/PowerPC/PPCISelLowering.h @@ -711,6 +711,10 @@ namespace llvm { bool shouldConvertConstantLoadToIntImm(const APInt &Imm, Type *Ty) const override; + bool convertSelectOfConstantsToMath() const override { + return true; + } + bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const override; bool getTgtMemIntrinsic(IntrinsicInfo &Info, diff --git a/lib/Target/X86/X86ISelLowering.h b/lib/Target/X86/X86ISelLowering.h index 14c5531a51b..d9acc1357ec 100644 --- a/lib/Target/X86/X86ISelLowering.h +++ b/lib/Target/X86/X86ISelLowering.h @@ -991,6 +991,10 @@ namespace llvm { bool shouldConvertConstantLoadToIntImm(const APInt &Imm, Type *Ty) const override; + bool convertSelectOfConstantsToMath() const override { + return true; + } + /// Return true if EXTRACT_SUBVECTOR is cheap for this result type /// with this index. bool isExtractSubvectorCheap(EVT ResVT, unsigned Index) const override; diff --git a/test/CodeGen/PowerPC/crbits.ll b/test/CodeGen/PowerPC/crbits.ll index b894a361d26..a85237195c5 100644 --- a/test/CodeGen/PowerPC/crbits.ll +++ b/test/CodeGen/PowerPC/crbits.ll @@ -142,7 +142,7 @@ entry: ret i32 %cond ; CHECK-LABEL: @exttest7 -; CHECK-DAG: cmplwi {{[0-9]+}}, 3, 5 +; CHECK-DAG: cmpwi {{[0-9]+}}, 3, 5 ; CHECK-DAG: li [[REG1:[0-9]+]], 8 ; CHECK-DAG: li [[REG2:[0-9]+]], 7 ; CHECK: isel 3, [[REG2]], [[REG1]], diff --git a/test/CodeGen/PowerPC/select_const.ll b/test/CodeGen/PowerPC/select_const.ll index 142a482bcc1..29548123be8 100644 --- a/test/CodeGen/PowerPC/select_const.ll +++ b/test/CodeGen/PowerPC/select_const.ll @@ -218,70 +218,29 @@ define i32 @select_neg1_or_0_signext(i1 signext %cond) { ; select Cond, C+1, C --> add (zext Cond), C define i32 @select_Cplus1_C(i1 %cond) { -; ISEL-LABEL: select_Cplus1_C: -; ISEL: # BB#0: -; ISEL-NEXT: andi. 3, 3, 1 -; ISEL-NEXT: li 4, 42 -; ISEL-NEXT: li 3, 41 -; ISEL-NEXT: isel 3, 4, 3, 1 -; ISEL-NEXT: blr -; -; NO_ISEL-LABEL: select_Cplus1_C: -; NO_ISEL: # BB#0: -; NO_ISEL-NEXT: andi. 3, 3, 1 -; NO_ISEL-NEXT: li 4, 42 -; NO_ISEL-NEXT: li 3, 41 -; NO_ISEL-NEXT: bc 12, 1, .LBB12_1 -; NO_ISEL-NEXT: blr -; NO_ISEL-NEXT: .LBB12_1: -; NO_ISEL-NEXT: addi 3, 4, 0 -; NO_ISEL-NEXT: blr +; ALL-LABEL: select_Cplus1_C: +; ALL: # BB#0: +; ALL-NEXT: clrldi 3, 3, 63 +; ALL-NEXT: addi 3, 3, 41 +; ALL-NEXT: blr %sel = select i1 %cond, i32 42, i32 41 ret i32 %sel } define i32 @select_Cplus1_C_zeroext(i1 zeroext %cond) { -; ISEL-LABEL: select_Cplus1_C_zeroext: -; ISEL: # BB#0: -; ISEL-NEXT: andi. 3, 3, 1 -; ISEL-NEXT: li 4, 42 -; ISEL-NEXT: li 3, 41 -; ISEL-NEXT: isel 3, 4, 3, 1 -; ISEL-NEXT: blr -; -; NO_ISEL-LABEL: select_Cplus1_C_zeroext: -; NO_ISEL: # BB#0: -; NO_ISEL-NEXT: andi. 3, 3, 1 -; NO_ISEL-NEXT: li 4, 42 -; NO_ISEL-NEXT: li 3, 41 -; NO_ISEL-NEXT: bc 12, 1, .LBB13_1 -; NO_ISEL-NEXT: blr -; NO_ISEL-NEXT: .LBB13_1: -; NO_ISEL-NEXT: addi 3, 4, 0 -; NO_ISEL-NEXT: blr +; ALL-LABEL: select_Cplus1_C_zeroext: +; ALL: # BB#0: +; ALL-NEXT: addi 3, 3, 41 +; ALL-NEXT: blr %sel = select i1 %cond, i32 42, i32 41 ret i32 %sel } define i32 @select_Cplus1_C_signext(i1 signext %cond) { -; ISEL-LABEL: select_Cplus1_C_signext: -; ISEL: # BB#0: -; ISEL-NEXT: andi. 3, 3, 1 -; ISEL-NEXT: li 4, 42 -; ISEL-NEXT: li 3, 41 -; ISEL-NEXT: isel 3, 4, 3, 1 -; ISEL-NEXT: blr -; -; NO_ISEL-LABEL: select_Cplus1_C_signext: -; NO_ISEL: # BB#0: -; NO_ISEL-NEXT: andi. 3, 3, 1 -; NO_ISEL-NEXT: li 4, 42 -; NO_ISEL-NEXT: li 3, 41 -; NO_ISEL-NEXT: bc 12, 1, .LBB14_1 -; NO_ISEL-NEXT: blr -; NO_ISEL-NEXT: .LBB14_1: -; NO_ISEL-NEXT: addi 3, 4, 0 -; NO_ISEL-NEXT: blr +; ALL-LABEL: select_Cplus1_C_signext: +; ALL: # BB#0: +; ALL-NEXT: subfic 3, 3, 41 +; ALL-NEXT: blr %sel = select i1 %cond, i32 42, i32 41 ret i32 %sel } @@ -289,70 +248,29 @@ define i32 @select_Cplus1_C_signext(i1 signext %cond) { ; select Cond, C, C+1 --> add (sext Cond), C define i32 @select_C_Cplus1(i1 %cond) { -; ISEL-LABEL: select_C_Cplus1: -; ISEL: # BB#0: -; ISEL-NEXT: andi. 3, 3, 1 -; ISEL-NEXT: li 4, 41 -; ISEL-NEXT: li 3, 42 -; ISEL-NEXT: isel 3, 4, 3, 1 -; ISEL-NEXT: blr -; -; NO_ISEL-LABEL: select_C_Cplus1: -; NO_ISEL: # BB#0: -; NO_ISEL-NEXT: andi. 3, 3, 1 -; NO_ISEL-NEXT: li 4, 41 -; NO_ISEL-NEXT: li 3, 42 -; NO_ISEL-NEXT: bc 12, 1, .LBB15_1 -; NO_ISEL-NEXT: blr -; NO_ISEL-NEXT: .LBB15_1: -; NO_ISEL-NEXT: addi 3, 4, 0 -; NO_ISEL-NEXT: blr +; ALL-LABEL: select_C_Cplus1: +; ALL: # BB#0: +; ALL-NEXT: clrldi 3, 3, 63 +; ALL-NEXT: subfic 3, 3, 42 +; ALL-NEXT: blr %sel = select i1 %cond, i32 41, i32 42 ret i32 %sel } define i32 @select_C_Cplus1_zeroext(i1 zeroext %cond) { -; ISEL-LABEL: select_C_Cplus1_zeroext: -; ISEL: # BB#0: -; ISEL-NEXT: andi. 3, 3, 1 -; ISEL-NEXT: li 4, 41 -; ISEL-NEXT: li 3, 42 -; ISEL-NEXT: isel 3, 4, 3, 1 -; ISEL-NEXT: blr -; -; NO_ISEL-LABEL: select_C_Cplus1_zeroext: -; NO_ISEL: # BB#0: -; NO_ISEL-NEXT: andi. 3, 3, 1 -; NO_ISEL-NEXT: li 4, 41 -; NO_ISEL-NEXT: li 3, 42 -; NO_ISEL-NEXT: bc 12, 1, .LBB16_1 -; NO_ISEL-NEXT: blr -; NO_ISEL-NEXT: .LBB16_1: -; NO_ISEL-NEXT: addi 3, 4, 0 -; NO_ISEL-NEXT: blr +; ALL-LABEL: select_C_Cplus1_zeroext: +; ALL: # BB#0: +; ALL-NEXT: subfic 3, 3, 42 +; ALL-NEXT: blr %sel = select i1 %cond, i32 41, i32 42 ret i32 %sel } define i32 @select_C_Cplus1_signext(i1 signext %cond) { -; ISEL-LABEL: select_C_Cplus1_signext: -; ISEL: # BB#0: -; ISEL-NEXT: andi. 3, 3, 1 -; ISEL-NEXT: li 4, 41 -; ISEL-NEXT: li 3, 42 -; ISEL-NEXT: isel 3, 4, 3, 1 -; ISEL-NEXT: blr -; -; NO_ISEL-LABEL: select_C_Cplus1_signext: -; NO_ISEL: # BB#0: -; NO_ISEL-NEXT: andi. 3, 3, 1 -; NO_ISEL-NEXT: li 4, 41 -; NO_ISEL-NEXT: li 3, 42 -; NO_ISEL-NEXT: bc 12, 1, .LBB17_1 -; NO_ISEL-NEXT: blr -; NO_ISEL-NEXT: .LBB17_1: -; NO_ISEL-NEXT: addi 3, 4, 0 -; NO_ISEL-NEXT: blr +; ALL-LABEL: select_C_Cplus1_signext: +; ALL: # BB#0: +; ALL-NEXT: addi 3, 3, 42 +; ALL-NEXT: blr %sel = select i1 %cond, i32 41, i32 42 ret i32 %sel } @@ -583,48 +501,22 @@ define i8 @sel_constants_srem_constant(i1 %cond) { } define i8 @sel_constants_urem_constant(i1 %cond) { -; ISEL-LABEL: sel_constants_urem_constant: -; ISEL: # BB#0: -; ISEL-NEXT: andi. 3, 3, 1 -; ISEL-NEXT: li 4, 2 -; ISEL-NEXT: li 3, 3 -; ISEL-NEXT: isel 3, 4, 3, 1 -; ISEL-NEXT: blr -; -; NO_ISEL-LABEL: sel_constants_urem_constant: -; NO_ISEL: # BB#0: -; NO_ISEL-NEXT: andi. 3, 3, 1 -; NO_ISEL-NEXT: li 4, 2 -; NO_ISEL-NEXT: li 3, 3 -; NO_ISEL-NEXT: bc 12, 1, .LBB27_1 -; NO_ISEL-NEXT: blr -; NO_ISEL-NEXT: .LBB27_1: -; NO_ISEL-NEXT: addi 3, 4, 0 -; NO_ISEL-NEXT: blr +; ALL-LABEL: sel_constants_urem_constant: +; ALL: # BB#0: +; ALL-NEXT: rlwinm 3, 3, 0, 31, 31 +; ALL-NEXT: subfic 3, 3, 3 +; ALL-NEXT: blr %sel = select i1 %cond, i8 -4, i8 23 %bo = urem i8 %sel, 5 ret i8 %bo } define i8 @sel_constants_and_constant(i1 %cond) { -; ISEL-LABEL: sel_constants_and_constant: -; ISEL: # BB#0: -; ISEL-NEXT: andi. 3, 3, 1 -; ISEL-NEXT: li 4, 4 -; ISEL-NEXT: li 3, 5 -; ISEL-NEXT: isel 3, 4, 3, 1 -; ISEL-NEXT: blr -; -; NO_ISEL-LABEL: sel_constants_and_constant: -; NO_ISEL: # BB#0: -; NO_ISEL-NEXT: andi. 3, 3, 1 -; NO_ISEL-NEXT: li 4, 4 -; NO_ISEL-NEXT: li 3, 5 -; NO_ISEL-NEXT: bc 12, 1, .LBB28_1 -; NO_ISEL-NEXT: blr -; NO_ISEL-NEXT: .LBB28_1: -; NO_ISEL-NEXT: addi 3, 4, 0 -; NO_ISEL-NEXT: blr +; ALL-LABEL: sel_constants_and_constant: +; ALL: # BB#0: +; ALL-NEXT: rlwinm 3, 3, 0, 31, 31 +; ALL-NEXT: subfic 3, 3, 5 +; ALL-NEXT: blr %sel = select i1 %cond, i8 -4, i8 23 %bo = and i8 %sel, 5 ret i8 %bo diff --git a/test/CodeGen/X86/avx512-insert-extract.ll b/test/CodeGen/X86/avx512-insert-extract.ll index 9373b4d5007..aee4c6367e2 100644 --- a/test/CodeGen/X86/avx512-insert-extract.ll +++ b/test/CodeGen/X86/avx512-insert-extract.ll @@ -1411,10 +1411,8 @@ define zeroext i8 @test_extractelement_v2i1(<2 x i64> %a, <2 x i64> %b) { ; KNL-NEXT: vpxor %xmm2, %xmm1, %xmm1 ; KNL-NEXT: vpxor %xmm2, %xmm0, %xmm0 ; KNL-NEXT: vpcmpgtq %xmm1, %xmm0, %xmm0 -; KNL-NEXT: vmovq %xmm0, %rax -; KNL-NEXT: testb $1, %al -; KNL-NEXT: sete %al -; KNL-NEXT: addb $3, %al +; KNL-NEXT: vpextrb $0, %xmm0, %eax +; KNL-NEXT: addb $4, %al ; KNL-NEXT: movzbl %al, %eax ; KNL-NEXT: retq ; @@ -1527,9 +1525,7 @@ define zeroext i8 @test_extractelement_v64i1(<64 x i8> %a, <64 x i8> %b) { ; KNL-NEXT: vpcmpgtb %ymm2, %ymm0, %ymm0 ; KNL-NEXT: vextracti128 $1, %ymm0, %xmm0 ; KNL-NEXT: vpextrb $15, %xmm0, %eax -; KNL-NEXT: testb $1, %al -; KNL-NEXT: sete %al -; KNL-NEXT: addb $3, %al +; KNL-NEXT: addb $4, %al ; KNL-NEXT: movzbl %al, %eax ; KNL-NEXT: retq ; diff --git a/test/CodeGen/X86/avx512-select.ll b/test/CodeGen/X86/avx512-select.ll index 3f427298c17..a2e5a14f78d 100644 --- a/test/CodeGen/X86/avx512-select.ll +++ b/test/CodeGen/X86/avx512-select.ll @@ -149,10 +149,7 @@ define i8 @select07(i8 %a.0, i8 %b.0, i8 %m) { define i64 @pr30249() { ; CHECK-LABEL: pr30249: ; CHECK: ## BB#0: -; CHECK-NEXT: xorl %ecx, %ecx -; CHECK-NEXT: cmpb $1, %cl -; CHECK-NEXT: movl $1, %eax -; CHECK-NEXT: adcxq %rcx, %rax +; CHECK-NEXT: movl $2, %eax ; CHECK-NEXT: retq %v = select i1 undef , i64 1, i64 2 ret i64 %v diff --git a/test/CodeGen/X86/select_const.ll b/test/CodeGen/X86/select_const.ll index 716ee70d926..a97e7c299e7 100644 --- a/test/CodeGen/X86/select_const.ll +++ b/test/CodeGen/X86/select_const.ll @@ -174,10 +174,9 @@ define i32 @select_Cplus1_C_signext(i1 signext %cond) { define i32 @select_C_Cplus1(i1 %cond) { ; CHECK-LABEL: select_C_Cplus1: ; CHECK: # BB#0: -; CHECK-NEXT: andb $1, %dil -; CHECK-NEXT: cmpb $1, %dil -; CHECK-NEXT: movl $41, %eax -; CHECK-NEXT: adcl $0, %eax +; CHECK-NEXT: andl $1, %edi +; CHECK-NEXT: movl $42, %eax +; CHECK-NEXT: subl %edi, %eax ; CHECK-NEXT: retq %sel = select i1 %cond, i32 41, i32 42 ret i32 %sel @@ -186,9 +185,9 @@ define i32 @select_C_Cplus1(i1 %cond) { define i32 @select_C_Cplus1_zeroext(i1 zeroext %cond) { ; CHECK-LABEL: select_C_Cplus1_zeroext: ; CHECK: # BB#0: -; CHECK-NEXT: cmpb $1, %dil -; CHECK-NEXT: movl $41, %eax -; CHECK-NEXT: adcl $0, %eax +; CHECK-NEXT: movzbl %dil, %ecx +; CHECK-NEXT: movl $42, %eax +; CHECK-NEXT: subl %ecx, %eax ; CHECK-NEXT: retq %sel = select i1 %cond, i32 41, i32 42 ret i32 %sel @@ -198,9 +197,9 @@ define i32 @select_C_Cplus1_signext(i1 signext %cond) { ; CHECK-LABEL: select_C_Cplus1_signext: ; CHECK: # BB#0: ; CHECK-NEXT: andb $1, %dil -; CHECK-NEXT: cmpb $1, %dil -; CHECK-NEXT: movl $41, %eax -; CHECK-NEXT: adcl $0, %eax +; CHECK-NEXT: movzbl %dil, %ecx +; CHECK-NEXT: movl $42, %eax +; CHECK-NEXT: subl %ecx, %eax ; CHECK-NEXT: retq %sel = select i1 %cond, i32 41, i32 42 ret i32 %sel