1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 20:51:52 +01:00

[x86] improve CMOV codegen by pushing add into operands

This is not the transform direction we want in general,
but by the time we have a CMOV, we've already tried
everything else that could be better.
The transform increases the uses of the other add operand,
but that is safe according to Alive2:
https://alive2.llvm.org/ce/z/Yn6p-A

We could probably extend this to other binops (not just add).
This is the motivating pattern discussed in:
https://llvm.org/PR51069

The test with i8 shows a missed fold because there's a trunc
sitting in front of the add. That can be handled with a small
follow-up.

Differential Revision: https://reviews.llvm.org/D106607
This commit is contained in:
Sanjay Patel 2021-07-23 09:01:26 -04:00
parent caa4165d5e
commit 845cd9f16b
2 changed files with 46 additions and 12 deletions

View File

@ -49867,6 +49867,41 @@ static SDValue matchPMADDWD_2(SelectionDAG &DAG, SDValue N0, SDValue N1,
PMADDBuilder);
}
/// CMOV of constants requires materializing constant operands in registers.
/// Try to fold those constants into an 'add' instruction to reduce instruction
/// count. We do this with CMOV rather the generic 'select' because there are
/// earlier folds that may be used to turn select-of-constants into logic hacks.
static SDValue pushAddIntoCmovOfConsts(SDNode *N, SelectionDAG &DAG) {
// This checks for a zero operand because add-of-0 gets simplified away.
// TODO: Allow generating an extra add?
auto isSuitableCmov = [](SDValue V) {
if (V.getOpcode() != X86ISD::CMOV || !V.hasOneUse())
return false;
return isa<ConstantSDNode>(V.getOperand(0)) &&
isa<ConstantSDNode>(V.getOperand(1)) &&
(isNullConstant(V.getOperand(0)) || isNullConstant(V.getOperand(1)));
};
// Match an appropriate CMOV as the first operand of the add.
SDValue Cmov = N->getOperand(0);
SDValue OtherOp = N->getOperand(1);
if (!isSuitableCmov(Cmov))
std::swap(Cmov, OtherOp);
if (!isSuitableCmov(Cmov))
return SDValue();
// add (cmov C, 0), OtherOp --> cmov (add OtherOp, C), OtherOp
// add (cmov 0, C), OtherOp --> cmov OtherOp, (add OtherOp, C)
SDLoc DL(N);
SDValue FalseOp = Cmov.getOperand(0);
SDValue TrueOp = Cmov.getOperand(1);
EVT VT = N->getValueType(0);
FalseOp = DAG.getNode(ISD::ADD, DL, VT, OtherOp, FalseOp);
TrueOp = DAG.getNode(ISD::ADD, DL, VT, OtherOp, TrueOp);
return DAG.getNode(X86ISD::CMOV, DL, VT, FalseOp, TrueOp, Cmov.getOperand(2),
Cmov.getOperand(3));
}
static SDValue combineAdd(SDNode *N, SelectionDAG &DAG,
TargetLowering::DAGCombinerInfo &DCI,
const X86Subtarget &Subtarget) {
@ -49874,6 +49909,9 @@ static SDValue combineAdd(SDNode *N, SelectionDAG &DAG,
SDValue Op0 = N->getOperand(0);
SDValue Op1 = N->getOperand(1);
if (SDValue Select = pushAddIntoCmovOfConsts(N, DAG))
return Select;
if (SDValue MAdd = matchPMADDWD(DAG, Op0, Op1, SDLoc(N), VT, Subtarget))
return MAdd;
if (SDValue MAdd = matchPMADDWD_2(DAG, Op0, Op1, SDLoc(N), VT, Subtarget))

View File

@ -4,11 +4,9 @@
define i64 @select_consts_i64(i64 %offset, i32 %x) {
; CHECK-LABEL: select_consts_i64:
; CHECK: # %bb.0:
; CHECK-NEXT: xorl %ecx, %ecx
; CHECK-NEXT: leaq 42(%rdi), %rax
; CHECK-NEXT: testl %esi, %esi
; CHECK-NEXT: movl $42, %eax
; CHECK-NEXT: cmovneq %rcx, %rax
; CHECK-NEXT: addq %rdi, %rax
; CHECK-NEXT: cmovneq %rdi, %rax
; CHECK-NEXT: retq
%b = icmp eq i32 %x, 0
%s = select i1 %b, i64 42, i64 0
@ -19,11 +17,10 @@ define i64 @select_consts_i64(i64 %offset, i32 %x) {
define i32 @select_consts_i32(i32 %offset, i64 %x) {
; CHECK-LABEL: select_consts_i32:
; CHECK: # %bb.0:
; CHECK-NEXT: xorl %ecx, %ecx
; CHECK-NEXT: # kill: def $edi killed $edi def $rdi
; CHECK-NEXT: leal 43(%rdi), %eax
; CHECK-NEXT: cmpq $42, %rsi
; CHECK-NEXT: movl $43, %eax
; CHECK-NEXT: cmovgel %ecx, %eax
; CHECK-NEXT: addl %edi, %eax
; CHECK-NEXT: cmovgel %edi, %eax
; CHECK-NEXT: retq
%b = icmp sgt i64 %x, 41
%s = select i1 %b, i32 0, i32 43
@ -34,11 +31,10 @@ define i32 @select_consts_i32(i32 %offset, i64 %x) {
define i16 @select_consts_i16(i16 %offset, i1 %b) {
; CHECK-LABEL: select_consts_i16:
; CHECK: # %bb.0:
; CHECK-NEXT: xorl %ecx, %ecx
; CHECK-NEXT: # kill: def $edi killed $edi def $rdi
; CHECK-NEXT: leal 44(%rdi), %eax
; CHECK-NEXT: testb $1, %sil
; CHECK-NEXT: movl $44, %eax
; CHECK-NEXT: cmovel %ecx, %eax
; CHECK-NEXT: addl %edi, %eax
; CHECK-NEXT: cmovel %edi, %eax
; CHECK-NEXT: # kill: def $ax killed $ax killed $eax
; CHECK-NEXT: retq
%s = select i1 %b, i16 44, i16 0