When unsafe math is used, we can use commutative FMAX and FMIN. In some cases

this allows for better code generation.

Added a new DAGCombine transformation to convert FMAX and FMIN to FMANC and
FMINC, which are commutative.

For example:

  movaps  %xmm0, %xmm1
  movsd LC(%rip), %xmm0
  minsd %xmm1, %xmm0

becomes:

  minsd LC(%rip), %xmm0

llvm-svn: 162187
This commit is contained in:
Nadav Rotem 2012-08-19 13:06:16 +00:00
parent fd4fe7061c
commit 178250ad87
5 changed files with 91 additions and 51 deletions

View File

@ -11463,6 +11463,8 @@ const char *X86TargetLowering::getTargetNodeName(unsigned Opcode) const {
case X86ISD::FHSUB: return "X86ISD::FHSUB";
case X86ISD::FMAX: return "X86ISD::FMAX";
case X86ISD::FMIN: return "X86ISD::FMIN";
case X86ISD::FMAXC: return "X86ISD::FMAXC";
case X86ISD::FMINC: return "X86ISD::FMINC";
case X86ISD::FRSQRT: return "X86ISD::FRSQRT";
case X86ISD::FRCP: return "X86ISD::FRCP";
case X86ISD::TLSADDR: return "X86ISD::TLSADDR";
@ -15368,6 +15370,29 @@ static SDValue PerformFORCombine(SDNode *N, SelectionDAG &DAG) {
return SDValue();
}
/// PerformFMinFMaxCombine - Do target-specific dag combines on X86ISD::FMIN and
/// X86ISD::FMAX nodes.
static SDValue PerformFMinFMaxCombine(SDNode *N, SelectionDAG &DAG) {
assert(N->getOpcode() == X86ISD::FMIN || N->getOpcode() == X86ISD::FMAX);
// Only perform optimizations if UnsafeMath is used.
if (!DAG.getTarget().Options.UnsafeFPMath)
return SDValue();
// If we run in unsafe-math mode, then convert the FMAX and FMIN nodes
// into FMINC and MMAXC, which are Commutative operations.
unsigned NewOp = 0;
switch (N->getOpcode()) {
default: llvm_unreachable("unknown opcode");
case X86ISD::FMIN: NewOp = X86ISD::FMINC; break;
case X86ISD::FMAX: NewOp = X86ISD::FMAXC; break;
}
return DAG.getNode(NewOp, N->getDebugLoc(), N->getValueType(0),
N->getOperand(0), N->getOperand(1));
}
/// PerformFANDCombine - Do target-specific dag combines on X86ISD::FAND nodes.
static SDValue PerformFANDCombine(SDNode *N, SelectionDAG &DAG) {
// FAND(0.0, x) -> 0.0
@ -15849,6 +15874,8 @@ SDValue X86TargetLowering::PerformDAGCombine(SDNode *N,
case ISD::FSUB: return PerformFSUBCombine(N, DAG, Subtarget);
case X86ISD::FXOR:
case X86ISD::FOR: return PerformFORCombine(N, DAG);
case X86ISD::FMIN:
case X86ISD::FMAX: return PerformFMinFMaxCombine(N, DAG);
case X86ISD::FAND: return PerformFANDCombine(N, DAG);
case X86ISD::BT: return PerformBTCombine(N, DAG, DCI);
case X86ISD::VZEXT_MOVL: return PerformVZEXT_MOVLCombine(N, DAG);

View File

@ -195,6 +195,9 @@ namespace llvm {
///
FMAX, FMIN,
/// FMAXC, FMINC - Commutative FMIN and FMAX.
FMAXC, FMINC,
/// FRSQRT, FRCP - Floating point reciprocal-sqrt and reciprocal
/// approximation. Note that these typically require refinement
/// in order to obtain suitable precision.

View File

@ -29,6 +29,13 @@ def SDTX86VFCMP : SDTypeProfile<1, 3, [SDTCisInt<0>, SDTCisSameAs<1, 2>,
def X86fmin : SDNode<"X86ISD::FMIN", SDTFPBinOp>;
def X86fmax : SDNode<"X86ISD::FMAX", SDTFPBinOp>;
// Commutative and Associative FMIN and FMAX.
def X86fminc : SDNode<"X86ISD::FMINC", SDTFPBinOp,
[SDNPCommutative, SDNPAssociative]>;
def X86fmaxc : SDNode<"X86ISD::FMAXC", SDTFPBinOp,
[SDNPCommutative, SDNPAssociative]>;
def X86fand : SDNode<"X86ISD::FAND", SDTFPBinOp,
[SDNPCommutative, SDNPAssociative]>;
def X86for : SDNode<"X86ISD::FOR", SDTFPBinOp,
@ -73,11 +80,12 @@ def X86vzmovl : SDNode<"X86ISD::VZEXT_MOVL",
SDTypeProfile<1, 1, [SDTCisSameAs<0,1>]>>;
def X86vzmovly : SDNode<"X86ISD::VZEXT_MOVL",
SDTypeProfile<1, 1, [SDTCisVec<0>, SDTCisVec<1>,
SDTypeProfile<1, 1, [SDTCisVec<0>, SDTCisVec<1>,
SDTCisOpSmallerThanOp<1, 0> ]>>;
def X86vsmovl : SDNode<"X86ISD::VSEXT_MOVL",
SDTypeProfile<1, 1, [SDTCisVec<0>, SDTCisInt<1>, SDTCisInt<0>]>>;
SDTypeProfile<1, 1,
[SDTCisVec<0>, SDTCisInt<1>, SDTCisInt<0>]>>;
def X86vzload : SDNode<"X86ISD::VZEXT_LOAD", SDTLoad,
[SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>;

View File

@ -2872,7 +2872,8 @@ let isCommutable = 0 in {
basic_sse12_fp_binop_s_int<0x5C, "sub", SSE_ALU_ITINS_S, 0>,
VEX_4V, VEX_LIG;
defm VSUB : basic_sse12_fp_binop_p<0x5C, "sub", fsub, SSE_ALU_ITINS_P, 0>,
basic_sse12_fp_binop_p_y<0x5C, "sub", fsub, SSE_ALU_ITINS_P>, VEX_4V;
basic_sse12_fp_binop_p_y<0x5C, "sub", fsub, SSE_ALU_ITINS_P>,
VEX_4V;
defm VDIV : basic_sse12_fp_binop_s<0x5E, "div", fdiv, SSE_DIV_ITINS_S, 0>,
basic_sse12_fp_binop_s_int<0x5E, "div", SSE_DIV_ITINS_S, 0>,
VEX_4V, VEX_LIG;
@ -2923,6 +2924,23 @@ let Constraints = "$src1 = $dst" in {
}
}
let isCommutable = 1, isCodeGenOnly = 1 in {
defm VMAXC: basic_sse12_fp_binop_s<0x5F, "max", X86fmaxc, SSE_ALU_ITINS_S, 0>,
VEX_4V, VEX_LIG;
defm VMAXC: basic_sse12_fp_binop_p<0x5F, "max", X86fmaxc, SSE_ALU_ITINS_P, 0>,
basic_sse12_fp_binop_p_y<0x5F, "max", X86fmaxc, SSE_ALU_ITINS_P>, VEX_4V;
defm VMINC: basic_sse12_fp_binop_s<0x5D, "min", X86fminc, SSE_ALU_ITINS_S, 0>,
VEX_4V, VEX_LIG;
defm VMINC: basic_sse12_fp_binop_p<0x5D, "min", X86fminc, SSE_ALU_ITINS_P, 0>,
basic_sse12_fp_binop_p_y<0x5D, "min", X86fminc, SSE_ALU_ITINS_P>, VEX_4V;
let Constraints = "$src1 = $dst" in {
defm MAXC: basic_sse12_fp_binop_s<0x5F, "max", X86fmaxc, SSE_ALU_ITINS_S>,
basic_sse12_fp_binop_p<0x5F, "max", X86fmaxc, SSE_ALU_ITINS_P>;
defm MINC: basic_sse12_fp_binop_s<0x5D, "min", X86fminc, SSE_ALU_ITINS_S>,
basic_sse12_fp_binop_p<0x5D, "min", X86fminc, SSE_ALU_ITINS_P>;
}
}
/// Unop Arithmetic
/// In addition, we also have a special variant of the scalar form here to
/// represent the associated intrinsic operation. This form is unlike the

View File

@ -47,8 +47,7 @@ define double @olt(double %x, double %y) nounwind {
; CHECK-NEXT: movap{{[sd]}} %xmm1, %xmm0
; CHECK-NEXT: ret
; UNSAFE: ogt_inverse:
; UNSAFE-NEXT: minsd %xmm0, %xmm1
; UNSAFE-NEXT: movap{{[sd]}} %xmm1, %xmm0
; UNSAFE-NEXT: minsd %xmm1, %xmm0
; UNSAFE-NEXT: ret
; FINITE: ogt_inverse:
; FINITE-NEXT: minsd %xmm0, %xmm1
@ -65,8 +64,7 @@ define double @ogt_inverse(double %x, double %y) nounwind {
; CHECK-NEXT: movap{{[sd]}} %xmm1, %xmm0
; CHECK-NEXT: ret
; UNSAFE: olt_inverse:
; UNSAFE-NEXT: maxsd %xmm0, %xmm1
; UNSAFE-NEXT: movap{{[sd]}} %xmm1, %xmm0
; UNSAFE-NEXT: maxsd %xmm1, %xmm0
; UNSAFE-NEXT: ret
; FINITE: olt_inverse:
; FINITE-NEXT: maxsd %xmm0, %xmm1
@ -107,8 +105,7 @@ define double @ole(double %x, double %y) nounwind {
; CHECK: oge_inverse:
; CHECK-NEXT: ucomisd %xmm1, %xmm0
; UNSAFE: oge_inverse:
; UNSAFE-NEXT: minsd %xmm0, %xmm1
; UNSAFE-NEXT: movap{{[sd]}} %xmm1, %xmm0
; UNSAFE-NEXT: minsd %xmm1, %xmm0
; UNSAFE-NEXT: ret
; FINITE: oge_inverse:
; FINITE-NEXT: minsd %xmm0, %xmm1
@ -123,8 +120,7 @@ define double @oge_inverse(double %x, double %y) nounwind {
; CHECK: ole_inverse:
; CHECK-NEXT: ucomisd %xmm0, %xmm1
; UNSAFE: ole_inverse:
; UNSAFE-NEXT: maxsd %xmm0, %xmm1
; UNSAFE-NEXT: movap{{[sd]}} %xmm1, %xmm0
; UNSAFE-NEXT: maxsd %xmm1, %xmm0
; UNSAFE-NEXT: ret
; FINITE: ole_inverse:
; FINITE-NEXT: maxsd %xmm0, %xmm1
@ -142,7 +138,8 @@ define double @ole_inverse(double %x, double %y) nounwind {
; CHECK-NEXT: ret
; UNSAFE: ogt_x:
; UNSAFE-NEXT: xorp{{[sd]}} %xmm1, %xmm1
; UNSAFE-NEXT: maxsd %xmm1, %xmm0
; UNSAFE-NEXT: maxsd %xmm0, %xmm1
; UNSAFE-NEXT: movap{{[sd]}} %xmm1, %xmm0
; UNSAFE-NEXT: ret
; FINITE: ogt_x:
; FINITE-NEXT: xorp{{[sd]}} %xmm1, %xmm1
@ -160,7 +157,8 @@ define double @ogt_x(double %x) nounwind {
; CHECK-NEXT: ret
; UNSAFE: olt_x:
; UNSAFE-NEXT: xorp{{[sd]}} %xmm1, %xmm1
; UNSAFE-NEXT: minsd %xmm1, %xmm0
; UNSAFE-NEXT: minsd %xmm0, %xmm1
; UNSAFE-NEXT: movap{{[sd]}} %xmm1, %xmm0
; UNSAFE-NEXT: ret
; FINITE: olt_x:
; FINITE-NEXT: xorp{{[sd]}} %xmm1, %xmm1
@ -218,7 +216,8 @@ define double @olt_inverse_x(double %x) nounwind {
; CHECK: ucomisd %xmm1, %xmm0
; UNSAFE: oge_x:
; UNSAFE-NEXT: xorp{{[sd]}} %xmm1, %xmm1
; UNSAFE-NEXT: maxsd %xmm1, %xmm0
; UNSAFE-NEXT: maxsd %xmm0, %xmm1
; UNSAFE-NEXT: movap{{[sd]}} %xmm1, %xmm0
; UNSAFE-NEXT: ret
; FINITE: oge_x:
; FINITE-NEXT: xorp{{[sd]}} %xmm1, %xmm1
@ -234,7 +233,8 @@ define double @oge_x(double %x) nounwind {
; CHECK: ucomisd %xmm0, %xmm1
; UNSAFE: ole_x:
; UNSAFE-NEXT: xorp{{[sd]}} %xmm1, %xmm1
; UNSAFE-NEXT: minsd %xmm1, %xmm0
; UNSAFE-NEXT: minsd %xmm0, %xmm1
; UNSAFE-NEXT: movap{{[sd]}} %xmm1, %xmm0
; UNSAFE-NEXT: ret
; FINITE: ole_x:
; FINITE-NEXT: xorp{{[sd]}} %xmm1, %xmm1
@ -313,8 +313,7 @@ define double @ult(double %x, double %y) nounwind {
; CHECK: ugt_inverse:
; CHECK: ucomisd %xmm0, %xmm1
; UNSAFE: ugt_inverse:
; UNSAFE-NEXT: minsd %xmm0, %xmm1
; UNSAFE-NEXT: movap{{[sd]}} %xmm1, %xmm0
; UNSAFE-NEXT: minsd %xmm1, %xmm0
; UNSAFE-NEXT: ret
; FINITE: ugt_inverse:
; FINITE-NEXT: minsd %xmm0, %xmm1
@ -329,8 +328,7 @@ define double @ugt_inverse(double %x, double %y) nounwind {
; CHECK: ult_inverse:
; CHECK: ucomisd %xmm1, %xmm0
; UNSAFE: ult_inverse:
; UNSAFE-NEXT: maxsd %xmm0, %xmm1
; UNSAFE-NEXT: movap{{[sd]}} %xmm1, %xmm0
; UNSAFE-NEXT: maxsd %xmm1, %xmm0
; UNSAFE-NEXT: ret
; FINITE: ult_inverse:
; FINITE-NEXT: maxsd %xmm0, %xmm1
@ -378,8 +376,7 @@ define double @ule(double %x, double %y) nounwind {
; CHECK-NEXT: minsd %xmm1, %xmm0
; CHECK-NEXT: ret
; UNSAFE: uge_inverse:
; UNSAFE-NEXT: minsd %xmm0, %xmm1
; UNSAFE-NEXT: movap{{[sd]}} %xmm1, %xmm0
; UNSAFE-NEXT: minsd %xmm1, %xmm0
; UNSAFE-NEXT: ret
; FINITE: uge_inverse:
; FINITE-NEXT: minsd %xmm0, %xmm1
@ -395,8 +392,7 @@ define double @uge_inverse(double %x, double %y) nounwind {
; CHECK-NEXT: maxsd %xmm1, %xmm0
; CHECK-NEXT: ret
; UNSAFE: ule_inverse:
; UNSAFE-NEXT: maxsd %xmm0, %xmm1
; UNSAFE-NEXT: movap{{[sd]}} %xmm1, %xmm0
; UNSAFE-NEXT: maxsd %xmm1, %xmm0
; UNSAFE-NEXT: ret
; FINITE: ule_inverse:
; FINITE-NEXT: maxsd %xmm0, %xmm1
@ -412,7 +408,8 @@ define double @ule_inverse(double %x, double %y) nounwind {
; CHECK: ucomisd %xmm0, %xmm1
; UNSAFE: ugt_x:
; UNSAFE-NEXT: xorp{{[sd]}} %xmm1, %xmm1
; UNSAFE-NEXT: maxsd %xmm1, %xmm0
; UNSAFE-NEXT: maxsd %xmm0, %xmm1
; UNSAFE-NEXT: movap{{[sd]}} %xmm1, %xmm0
; UNSAFE-NEXT: ret
; FINITE: ugt_x:
; FINITE-NEXT: xorp{{[sd]}} %xmm1, %xmm1
@ -428,7 +425,8 @@ define double @ugt_x(double %x) nounwind {
; CHECK: ucomisd %xmm1, %xmm0
; UNSAFE: ult_x:
; UNSAFE-NEXT: xorp{{[sd]}} %xmm1, %xmm1
; UNSAFE-NEXT: minsd %xmm1, %xmm0
; UNSAFE-NEXT: minsd %xmm0, %xmm1
; UNSAFE-NEXT: movap{{[sd]}} %xmm1, %xmm0
; UNSAFE-NEXT: ret
; FINITE: ult_x:
; FINITE-NEXT: xorp{{[sd]}} %xmm1, %xmm1
@ -483,7 +481,8 @@ define double @ult_inverse_x(double %x) nounwind {
; CHECK-NEXT: ret
; UNSAFE: uge_x:
; UNSAFE-NEXT: xorp{{[sd]}} %xmm1, %xmm1
; UNSAFE-NEXT: maxsd %xmm1, %xmm0
; UNSAFE-NEXT: maxsd %xmm0, %xmm1
; UNSAFE-NEXT: movap{{[sd]}} %xmm1, %xmm0
; UNSAFE-NEXT: ret
; FINITE: uge_x:
; FINITE-NEXT: xorp{{[sd]}} %xmm1, %xmm1
@ -502,7 +501,8 @@ define double @uge_x(double %x) nounwind {
; CHECK-NEXT: ret
; UNSAFE: ule_x:
; UNSAFE-NEXT: xorp{{[sd]}} %xmm1, %xmm1
; UNSAFE-NEXT: minsd %xmm1, %xmm0
; UNSAFE-NEXT: minsd %xmm0, %xmm1
; UNSAFE-NEXT: movap{{[sd]}} %xmm1, %xmm0
; UNSAFE-NEXT: ret
; FINITE: ule_x:
; FINITE-NEXT: xorp{{[sd]}} %xmm1, %xmm1
@ -590,9 +590,7 @@ define double @olt_y(double %x) nounwind {
; CHECK-NEXT: movap{{[sd]}} %xmm1, %xmm0
; CHECK-NEXT: ret
; UNSAFE: ogt_inverse_y:
; UNSAFE-NEXT: movsd {{[^,]*}}, %xmm1
; UNSAFE-NEXT: minsd %xmm0, %xmm1
; UNSAFE-NEXT: movap{{[sd]}} %xmm1, %xmm0
; UNSAFE-NEXT: minsd {{[^,]*}}, %xmm0
; UNSAFE-NEXT: ret
; FINITE: ogt_inverse_y:
; FINITE-NEXT: movsd {{[^,]*}}, %xmm1
@ -611,9 +609,7 @@ define double @ogt_inverse_y(double %x) nounwind {
; CHECK-NEXT: movap{{[sd]}} %xmm1, %xmm0
; CHECK-NEXT: ret
; UNSAFE: olt_inverse_y:
; UNSAFE-NEXT: movsd {{[^,]*}}, %xmm1
; UNSAFE-NEXT: maxsd %xmm0, %xmm1
; UNSAFE-NEXT: movap{{[sd]}} %xmm1, %xmm0
; UNSAFE-NEXT: maxsd {{[^,]*}}, %xmm0
; UNSAFE-NEXT: ret
; FINITE: olt_inverse_y:
; FINITE-NEXT: movsd {{[^,]*}}, %xmm1
@ -657,9 +653,7 @@ define double @ole_y(double %x) nounwind {
; CHECK: oge_inverse_y:
; CHECK: ucomisd %xmm
; UNSAFE: oge_inverse_y:
; UNSAFE-NEXT: movsd {{[^,]*}}, %xmm1
; UNSAFE-NEXT: minsd %xmm0, %xmm1
; UNSAFE-NEXT: movap{{[sd]}} %xmm1, %xmm0
; UNSAFE-NEXT: minsd {{[^,]*}}, %xmm0
; UNSAFE-NEXT: ret
; FINITE: oge_inverse_y:
; FINITE-NEXT: movsd {{[^,]*}}, %xmm1
@ -675,9 +669,7 @@ define double @oge_inverse_y(double %x) nounwind {
; CHECK: ole_inverse_y:
; CHECK: ucomisd %xmm
; UNSAFE: ole_inverse_y:
; UNSAFE-NEXT: movsd {{[^,]*}}, %xmm1
; UNSAFE-NEXT: maxsd %xmm0, %xmm1
; UNSAFE-NEXT: movap{{[sd]}} %xmm1, %xmm0
; UNSAFE-NEXT: maxsd {{[^,]*}}, %xmm0
; UNSAFE-NEXT: ret
; FINITE: ole_inverse_y:
; FINITE-NEXT: movsd {{[^,]*}}, %xmm1
@ -721,9 +713,7 @@ define double @ult_y(double %x) nounwind {
; CHECK: ugt_inverse_y:
; CHECK: ucomisd %xmm
; UNSAFE: ugt_inverse_y:
; UNSAFE-NEXT: movsd {{[^,]*}}, %xmm1
; UNSAFE-NEXT: minsd %xmm0, %xmm1
; UNSAFE-NEXT: movap{{[sd]}} %xmm1, %xmm0
; UNSAFE-NEXT: minsd {{[^,]*}}, %xmm0
; UNSAFE-NEXT: ret
; FINITE: ugt_inverse_y:
; FINITE-NEXT: movsd {{[^,]*}}, %xmm1
@ -739,9 +729,7 @@ define double @ugt_inverse_y(double %x) nounwind {
; CHECK: ult_inverse_y:
; CHECK: ucomisd %xmm
; UNSAFE: ult_inverse_y:
; UNSAFE-NEXT: movsd {{[^,]*}}, %xmm1
; UNSAFE-NEXT: maxsd %xmm0, %xmm1
; UNSAFE-NEXT: movap{{[sd]}} %xmm1, %xmm0
; UNSAFE-NEXT: maxsd {{[^,]*}}, %xmm0
; UNSAFE-NEXT: ret
; FINITE: ult_inverse_y:
; FINITE-NEXT: movsd {{[^,]*}}, %xmm1
@ -792,9 +780,7 @@ define double @ule_y(double %x) nounwind {
; CHECK-NEXT: minsd {{[^,]*}}, %xmm0
; CHECK-NEXT: ret
; UNSAFE: uge_inverse_y:
; UNSAFE-NEXT: movsd {{[^,]*}}, %xmm1
; UNSAFE-NEXT: minsd %xmm0, %xmm1
; UNSAFE-NEXT: movap{{[sd]}} %xmm1, %xmm0
; UNSAFE-NEXT: minsd {{[^,]*}}, %xmm0
; UNSAFE-NEXT: ret
; FINITE: uge_inverse_y:
; FINITE-NEXT: movsd {{[^,]*}}, %xmm1
@ -811,9 +797,7 @@ define double @uge_inverse_y(double %x) nounwind {
; CHECK-NEXT: maxsd {{[^,]*}}, %xmm0
; CHECK-NEXT: ret
; UNSAFE: ule_inverse_y:
; UNSAFE-NEXT: movsd {{[^,]*}}, %xmm1
; UNSAFE-NEXT: maxsd %xmm0, %xmm1
; UNSAFE-NEXT: movap{{[sd]}} %xmm1, %xmm0
; UNSAFE-NEXT: maxsd {{[^,]*}}, %xmm0
; UNSAFE-NEXT: ret
; FINITE: ule_inverse_y:
; FINITE-NEXT: movsd {{[^,]*}}, %xmm1