1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-23 11:13:28 +01:00

R600/SI: Fix fmin_legacy / fmax_legacy matching for SI

select_cc is expanded on SI, so this was never matched.

llvm-svn: 221941
This commit is contained in:
Matt Arsenault 2014-11-13 23:03:09 +00:00
parent 2fa78fff68
commit 08233590d4
8 changed files with 187 additions and 58 deletions

View File

@ -378,6 +378,7 @@ AMDGPUTargetLowering::AMDGPUTargetLowering(TargetMachine &TM) :
setOperationAction(ISD::FNEARBYINT, MVT::f64, Custom); setOperationAction(ISD::FNEARBYINT, MVT::f64, Custom);
setTargetDAGCombine(ISD::MUL); setTargetDAGCombine(ISD::MUL);
setTargetDAGCombine(ISD::SELECT);
setTargetDAGCombine(ISD::SELECT_CC); setTargetDAGCombine(ISD::SELECT_CC);
setTargetDAGCombine(ISD::STORE); setTargetDAGCombine(ISD::STORE);
@ -999,21 +1000,21 @@ SDValue AMDGPUTargetLowering::LowerIntrinsicLRP(SDValue Op,
} }
/// \brief Generate Min/Max node /// \brief Generate Min/Max node
SDValue AMDGPUTargetLowering::CombineMinMax(SDNode *N, SDValue AMDGPUTargetLowering::CombineMinMax(SDLoc DL,
EVT VT,
SDValue LHS,
SDValue RHS,
SDValue True,
SDValue False,
SDValue CC,
SelectionDAG &DAG) const { SelectionDAG &DAG) const {
SDLoc DL(N); if (VT != MVT::f32 &&
EVT VT = N->getValueType(0); (VT != MVT::f64 ||
Subtarget->getGeneration() < AMDGPUSubtarget::SOUTHERN_ISLANDS))
SDValue LHS = N->getOperand(0); return SDValue();
SDValue RHS = N->getOperand(1);
SDValue True = N->getOperand(2); if (!(LHS == True && RHS == False) && !(LHS == False && RHS == True))
SDValue False = N->getOperand(3);
SDValue CC = N->getOperand(4);
if (VT != MVT::f32 ||
!((LHS == True && RHS == False) || (LHS == False && RHS == True))) {
return SDValue(); return SDValue();
}
ISD::CondCode CCOpcode = cast<CondCodeSDNode>(CC)->get(); ISD::CondCode CCOpcode = cast<CondCodeSDNode>(CC)->get();
switch (CCOpcode) { switch (CCOpcode) {
@ -1029,14 +1030,15 @@ SDValue AMDGPUTargetLowering::CombineMinMax(SDNode *N,
case ISD::SETTRUE2: case ISD::SETTRUE2:
case ISD::SETUO: case ISD::SETUO:
case ISD::SETO: case ISD::SETO:
llvm_unreachable("Operation should already be optimised!"); break;
case ISD::SETULE: case ISD::SETULE:
case ISD::SETULT: case ISD::SETULT:
case ISD::SETOLE: case ISD::SETOLE:
case ISD::SETOLT: case ISD::SETOLT:
case ISD::SETLE: case ISD::SETLE:
case ISD::SETLT: { case ISD::SETLT: {
unsigned Opc = (LHS == True) ? AMDGPUISD::FMIN : AMDGPUISD::FMAX; unsigned Opc
= (LHS == True) ? AMDGPUISD::FMIN_LEGACY : AMDGPUISD::FMAX_LEGACY;
return DAG.getNode(Opc, DL, VT, LHS, RHS); return DAG.getNode(Opc, DL, VT, LHS, RHS);
} }
case ISD::SETGT: case ISD::SETGT:
@ -1045,7 +1047,8 @@ SDValue AMDGPUTargetLowering::CombineMinMax(SDNode *N,
case ISD::SETOGE: case ISD::SETOGE:
case ISD::SETUGT: case ISD::SETUGT:
case ISD::SETOGT: { case ISD::SETOGT: {
unsigned Opc = (LHS == True) ? AMDGPUISD::FMAX : AMDGPUISD::FMIN; unsigned Opc
= (LHS == True) ? AMDGPUISD::FMAX_LEGACY : AMDGPUISD::FMIN_LEGACY;
return DAG.getNode(Opc, DL, VT, LHS, RHS); return DAG.getNode(Opc, DL, VT, LHS, RHS);
} }
case ISD::SETCC_INVALID: case ISD::SETCC_INVALID:
@ -2111,7 +2114,35 @@ SDValue AMDGPUTargetLowering::PerformDAGCombine(SDNode *N,
return SDValue(); return SDValue();
} }
case ISD::SELECT_CC: { case ISD::SELECT_CC: {
return CombineMinMax(N, DAG); SDLoc DL(N);
EVT VT = N->getValueType(0);
SDValue LHS = N->getOperand(0);
SDValue RHS = N->getOperand(1);
SDValue True = N->getOperand(2);
SDValue False = N->getOperand(3);
SDValue CC = N->getOperand(4);
return CombineMinMax(DL, VT, LHS, RHS, True, False, CC, DAG);
}
case ISD::SELECT: {
SDValue Cond = N->getOperand(0);
if (Cond.getOpcode() == ISD::SETCC) {
SDLoc DL(N);
EVT VT = N->getValueType(0);
SDValue LHS = Cond.getOperand(0);
SDValue RHS = Cond.getOperand(1);
SDValue CC = Cond.getOperand(2);
SDValue True = N->getOperand(1);
SDValue False = N->getOperand(2);
return CombineMinMax(DL, VT, LHS, RHS, True, False, CC, DAG);
}
break;
} }
case AMDGPUISD::BFE_I32: case AMDGPUISD::BFE_I32:
case AMDGPUISD::BFE_U32: { case AMDGPUISD::BFE_U32: {
@ -2289,10 +2320,10 @@ const char* AMDGPUTargetLowering::getTargetNodeName(unsigned Opcode) const {
NODE_NAME_CASE(FRACT) NODE_NAME_CASE(FRACT)
NODE_NAME_CASE(CLAMP) NODE_NAME_CASE(CLAMP)
NODE_NAME_CASE(MAD) NODE_NAME_CASE(MAD)
NODE_NAME_CASE(FMAX) NODE_NAME_CASE(FMAX_LEGACY)
NODE_NAME_CASE(SMAX) NODE_NAME_CASE(SMAX)
NODE_NAME_CASE(UMAX) NODE_NAME_CASE(UMAX)
NODE_NAME_CASE(FMIN) NODE_NAME_CASE(FMIN_LEGACY)
NODE_NAME_CASE(SMIN) NODE_NAME_CASE(SMIN)
NODE_NAME_CASE(UMIN) NODE_NAME_CASE(UMIN)
NODE_NAME_CASE(URECIP) NODE_NAME_CASE(URECIP)

View File

@ -140,7 +140,14 @@ public:
SDValue LowerIntrinsicIABS(SDValue Op, SelectionDAG &DAG) const; SDValue LowerIntrinsicIABS(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerIntrinsicLRP(SDValue Op, SelectionDAG &DAG) const; SDValue LowerIntrinsicLRP(SDValue Op, SelectionDAG &DAG) const;
SDValue CombineMinMax(SDNode *N, SelectionDAG &DAG) const; SDValue CombineMinMax(SDLoc DL,
EVT VT,
SDValue LHS,
SDValue RHS,
SDValue True,
SDValue False,
SDValue CC,
SelectionDAG &DAG) const;
const char* getTargetNodeName(unsigned Opcode) const override; const char* getTargetNodeName(unsigned Opcode) const override;
virtual SDNode *PostISelFolding(MachineSDNode *N, virtual SDNode *PostISelFolding(MachineSDNode *N,
@ -188,10 +195,10 @@ enum {
// Denormals handled on some parts. // Denormals handled on some parts.
COS_HW, COS_HW,
SIN_HW, SIN_HW,
FMAX, FMAX_LEGACY,
SMAX, SMAX,
UMAX, UMAX,
FMIN, FMIN_LEGACY,
SMIN, SMIN,
UMIN, UMIN,
URECIP, URECIP,

View File

@ -58,9 +58,12 @@ def AMDGPUrsq_clamped : SDNode<"AMDGPUISD::RSQ_CLAMPED", SDTFPUnaryOp>;
def AMDGPUldexp : SDNode<"AMDGPUISD::LDEXP", AMDGPULdExpOp>; def AMDGPUldexp : SDNode<"AMDGPUISD::LDEXP", AMDGPULdExpOp>;
// out = max(a, b) a and b are floats // out = max(a, b) a and b are floats, where a nan comparison fails.
def AMDGPUfmax : SDNode<"AMDGPUISD::FMAX", SDTFPBinOp, // This is not commutative because this gives the second operand:
[SDNPCommutative, SDNPAssociative] // x < nan ? x : nan -> nan
// nan < x ? nan : x -> x
def AMDGPUfmax_legacy : SDNode<"AMDGPUISD::FMAX_LEGACY", SDTFPBinOp,
[SDNPAssociative]
>; >;
def AMDGPUclamp : SDNode<"AMDGPUISD::CLAMP", SDTFPTernaryOp, []>; def AMDGPUclamp : SDNode<"AMDGPUISD::CLAMP", SDTFPTernaryOp, []>;
@ -76,9 +79,9 @@ def AMDGPUumax : SDNode<"AMDGPUISD::UMAX", SDTIntBinOp,
[SDNPCommutative, SDNPAssociative] [SDNPCommutative, SDNPAssociative]
>; >;
// out = min(a, b) a and b are floats // out = min(a, b) a and b are floats, where a nan comparison fails.
def AMDGPUfmin : SDNode<"AMDGPUISD::FMIN", SDTFPBinOp, def AMDGPUfmin_legacy : SDNode<"AMDGPUISD::FMIN_LEGACY", SDTFPBinOp,
[SDNPCommutative, SDNPAssociative] [SDNPAssociative]
>; >;
// out = min(a, b) a snd b are signed ints // out = min(a, b) a snd b are signed ints

View File

@ -674,8 +674,9 @@ def ADD : R600_2OP_Helper <0x0, "ADD", fadd>;
// Non-IEEE MUL: 0 * anything = 0 // Non-IEEE MUL: 0 * anything = 0
def MUL : R600_2OP_Helper <0x1, "MUL NON-IEEE", int_AMDGPU_mul>; def MUL : R600_2OP_Helper <0x1, "MUL NON-IEEE", int_AMDGPU_mul>;
def MUL_IEEE : R600_2OP_Helper <0x2, "MUL_IEEE", fmul>; def MUL_IEEE : R600_2OP_Helper <0x2, "MUL_IEEE", fmul>;
def MAX : R600_2OP_Helper <0x3, "MAX", AMDGPUfmax>; // TODO: Do these actually match the regular fmin/fmax behavior?
def MIN : R600_2OP_Helper <0x4, "MIN", AMDGPUfmin>; def MAX : R600_2OP_Helper <0x3, "MAX", AMDGPUfmax_legacy>;
def MIN : R600_2OP_Helper <0x4, "MIN", AMDGPUfmin_legacy>;
// For the SET* instructions there is a naming conflict in TargetSelectionDAG.td, // For the SET* instructions there is a naming conflict in TargetSelectionDAG.td,
// so some of the instruction names don't match the asm string. // so some of the instruction names don't match the asm string.

View File

@ -1398,11 +1398,11 @@ defm V_MUL_U32_U24 : VOP2Inst <vop2<0xb>, "v_mul_u32_u24",
defm V_MIN_LEGACY_F32 : VOP2Inst <vop2<0xd>, "v_min_legacy_f32", defm V_MIN_LEGACY_F32 : VOP2Inst <vop2<0xd>, "v_min_legacy_f32",
VOP_F32_F32_F32, AMDGPUfmin VOP_F32_F32_F32, AMDGPUfmin_legacy
>; >;
defm V_MAX_LEGACY_F32 : VOP2Inst <vop2<0xe>, "v_max_legacy_f32", defm V_MAX_LEGACY_F32 : VOP2Inst <vop2<0xe>, "v_max_legacy_f32",
VOP_F32_F32_F32, AMDGPUfmax VOP_F32_F32_F32, AMDGPUfmax_legacy
>; >;
defm V_MIN_F32 : VOP2Inst <vop2<0xf>, "v_min_f32", VOP_F32_F32_F32, fminnum>; defm V_MIN_F32 : VOP2Inst <vop2<0xf>, "v_min_f32", VOP_F32_F32_F32, fminnum>;

View File

@ -1,60 +1,55 @@
; RUN: llc < %s -march=r600 -mcpu=tahiti -verify-machineinstrs | FileCheck %s ; RUN: llc < %s -march=r600 -mcpu=tahiti -verify-machineinstrs | FileCheck %s
; CHECK: {{^}}flt_f64: ; CHECK-LABEL: {{^}}flt_f64:
; CHECK: v_cmp_lt_f64_e64 {{s[[0-9]+:[0-9]+], v[[0-9]+:[0-9]+], v[[0-9]+:[0-9]+]}} ; CHECK: v_cmp_lt_f64_e64 {{s[[0-9]+:[0-9]+], v[[0-9]+:[0-9]+], v[[0-9]+:[0-9]+]}}
define void @flt_f64(i32 addrspace(1)* %out, double addrspace(1)* %in1,
define void @flt_f64(double addrspace(1)* %out, double addrspace(1)* %in1,
double addrspace(1)* %in2) { double addrspace(1)* %in2) {
%r0 = load double addrspace(1)* %in1 %r0 = load double addrspace(1)* %in1
%r1 = load double addrspace(1)* %in2 %r1 = load double addrspace(1)* %in2
%r2 = fcmp ult double %r0, %r1 %r2 = fcmp ult double %r0, %r1
%r3 = select i1 %r2, double %r0, double %r1 %r3 = zext i1 %r2 to i32
store double %r3, double addrspace(1)* %out store i32 %r3, i32 addrspace(1)* %out
ret void ret void
} }
; CHECK: {{^}}fle_f64: ; CHECK-LABEL: {{^}}fle_f64:
; CHECK: v_cmp_le_f64_e64 {{s[[0-9]+:[0-9]+], v[[0-9]+:[0-9]+], v[[0-9]+:[0-9]+]}} ; CHECK: v_cmp_le_f64_e64 {{s[[0-9]+:[0-9]+], v[[0-9]+:[0-9]+], v[[0-9]+:[0-9]+]}}
define void @fle_f64(i32 addrspace(1)* %out, double addrspace(1)* %in1,
define void @fle_f64(double addrspace(1)* %out, double addrspace(1)* %in1,
double addrspace(1)* %in2) { double addrspace(1)* %in2) {
%r0 = load double addrspace(1)* %in1 %r0 = load double addrspace(1)* %in1
%r1 = load double addrspace(1)* %in2 %r1 = load double addrspace(1)* %in2
%r2 = fcmp ule double %r0, %r1 %r2 = fcmp ule double %r0, %r1
%r3 = select i1 %r2, double %r0, double %r1 %r3 = zext i1 %r2 to i32
store double %r3, double addrspace(1)* %out store i32 %r3, i32 addrspace(1)* %out
ret void ret void
} }
; CHECK: {{^}}fgt_f64: ; CHECK-LABEL: {{^}}fgt_f64:
; CHECK: v_cmp_gt_f64_e64 {{s[[0-9]+:[0-9]+], v[[0-9]+:[0-9]+], v[[0-9]+:[0-9]+]}} ; CHECK: v_cmp_gt_f64_e64 {{s[[0-9]+:[0-9]+], v[[0-9]+:[0-9]+], v[[0-9]+:[0-9]+]}}
define void @fgt_f64(i32 addrspace(1)* %out, double addrspace(1)* %in1,
define void @fgt_f64(double addrspace(1)* %out, double addrspace(1)* %in1,
double addrspace(1)* %in2) { double addrspace(1)* %in2) {
%r0 = load double addrspace(1)* %in1 %r0 = load double addrspace(1)* %in1
%r1 = load double addrspace(1)* %in2 %r1 = load double addrspace(1)* %in2
%r2 = fcmp ugt double %r0, %r1 %r2 = fcmp ugt double %r0, %r1
%r3 = select i1 %r2, double %r0, double %r1 %r3 = zext i1 %r2 to i32
store double %r3, double addrspace(1)* %out store i32 %r3, i32 addrspace(1)* %out
ret void ret void
} }
; CHECK: {{^}}fge_f64: ; CHECK-LABEL: {{^}}fge_f64:
; CHECK: v_cmp_ge_f64_e64 {{s[[0-9]+:[0-9]+], v[[0-9]+:[0-9]+], v[[0-9]+:[0-9]+]}} ; CHECK: v_cmp_ge_f64_e64 {{s[[0-9]+:[0-9]+], v[[0-9]+:[0-9]+], v[[0-9]+:[0-9]+]}}
define void @fge_f64(i32 addrspace(1)* %out, double addrspace(1)* %in1,
define void @fge_f64(double addrspace(1)* %out, double addrspace(1)* %in1,
double addrspace(1)* %in2) { double addrspace(1)* %in2) {
%r0 = load double addrspace(1)* %in1 %r0 = load double addrspace(1)* %in1
%r1 = load double addrspace(1)* %in2 %r1 = load double addrspace(1)* %in2
%r2 = fcmp uge double %r0, %r1 %r2 = fcmp uge double %r0, %r1
%r3 = select i1 %r2, double %r0, double %r1 %r3 = zext i1 %r2 to i32
store double %r3, double addrspace(1)* %out store i32 %r3, i32 addrspace(1)* %out
ret void ret void
} }
; CHECK: {{^}}fne_f64: ; CHECK-LABEL: {{^}}fne_f64:
; CHECK: v_cmp_neq_f64_e32 vcc, {{v[[0-9]+:[0-9]+], v[[0-9]+:[0-9]+]}} ; CHECK: v_cmp_neq_f64_e32 vcc, {{v[[0-9]+:[0-9]+], v[[0-9]+:[0-9]+]}}
define void @fne_f64(double addrspace(1)* %out, double addrspace(1)* %in1, define void @fne_f64(double addrspace(1)* %out, double addrspace(1)* %in1,
double addrspace(1)* %in2) { double addrspace(1)* %in2) {
%r0 = load double addrspace(1)* %in1 %r0 = load double addrspace(1)* %in1
@ -65,9 +60,8 @@ define void @fne_f64(double addrspace(1)* %out, double addrspace(1)* %in1,
ret void ret void
} }
; CHECK: {{^}}feq_f64: ; CHECK-LABEL: {{^}}feq_f64:
; CHECK: v_cmp_eq_f64_e64 {{s[[0-9]+:[0-9]+], v[[0-9]+:[0-9]+], v[[0-9]+:[0-9]+]}} ; CHECK: v_cmp_eq_f64_e64 {{s[[0-9]+:[0-9]+], v[[0-9]+:[0-9]+], v[[0-9]+:[0-9]+]}}
define void @feq_f64(double addrspace(1)* %out, double addrspace(1)* %in1, define void @feq_f64(double addrspace(1)* %out, double addrspace(1)* %in1,
double addrspace(1)* %in2) { double addrspace(1)* %in2) {
%r0 = load double addrspace(1)* %in1 %r0 = load double addrspace(1)* %in1

View File

@ -0,0 +1,42 @@
; RUN: llc -march=r600 -mcpu=SI < %s | FileCheck -check-prefix=SI -check-prefix=FUNC %s
; RUN: llc -march=r600 -mcpu=redwood < %s | FileCheck -check-prefix=EG -check-prefix=FUNC %s
; FUNC-LABEL: @test_fmax_legacy_uge_f32
; SI: v_max_legacy_f32_e32
; EG: MAX
define void @test_fmax_legacy_uge_f32(float addrspace(1)* %out, float %a, float %b) nounwind {
%cmp = fcmp uge float %a, %b
%val = select i1 %cmp, float %a, float %b
store float %val, float addrspace(1)* %out, align 4
ret void
}
; FUNC-LABEL: @test_fmax_legacy_oge_f32
; SI: v_max_legacy_f32_e32
; EG: MAX
define void @test_fmax_legacy_oge_f32(float addrspace(1)* %out, float %a, float %b) nounwind {
%cmp = fcmp oge float %a, %b
%val = select i1 %cmp, float %a, float %b
store float %val, float addrspace(1)* %out, align 4
ret void
}
; FUNC-LABEL: @test_fmax_legacy_ugt_f32
; SI: v_max_legacy_f32_e32
; EG: MAX
define void @test_fmax_legacy_ugt_f32(float addrspace(1)* %out, float %a, float %b) nounwind {
%cmp = fcmp ugt float %a, %b
%val = select i1 %cmp, float %a, float %b
store float %val, float addrspace(1)* %out, align 4
ret void
}
; FUNC-LABEL: @test_fmax_legacy_ogt_f32
; SI: v_max_legacy_f32_e32
; EG: MAX
define void @test_fmax_legacy_ogt_f32(float addrspace(1)* %out, float %a, float %b) nounwind {
%cmp = fcmp ogt float %a, %b
%val = select i1 %cmp, float %a, float %b
store float %val, float addrspace(1)* %out, align 4
ret void
}

View File

@ -0,0 +1,51 @@
; RUN: llc -march=r600 -mcpu=SI < %s | FileCheck -check-prefix=SI -check-prefix=FUNC %s
; RUN: llc -march=r600 -mcpu=redwood < %s | FileCheck -check-prefix=EG -check-prefix=FUNC %s
; FUNC-LABEL: @test_fmin_legacy_f32
; EG: MIN *
; SI: v_min_legacy_f32_e32
define void @test_fmin_legacy_f32(<4 x float> addrspace(1)* %out, <4 x float> inreg %reg0) nounwind {
%r0 = extractelement <4 x float> %reg0, i32 0
%r1 = extractelement <4 x float> %reg0, i32 1
%r2 = fcmp uge float %r0, %r1
%r3 = select i1 %r2, float %r1, float %r0
%vec = insertelement <4 x float> undef, float %r3, i32 0
store <4 x float> %vec, <4 x float> addrspace(1)* %out, align 16
ret void
}
; FUNC-LABEL: @test_fmin_legacy_ule_f32
; SI: v_min_legacy_f32_e32
define void @test_fmin_legacy_ule_f32(float addrspace(1)* %out, float %a, float %b) nounwind {
%cmp = fcmp ule float %a, %b
%val = select i1 %cmp, float %a, float %b
store float %val, float addrspace(1)* %out, align 4
ret void
}
; FUNC-LABEL: @test_fmin_legacy_ole_f32
; SI: v_min_legacy_f32_e32
define void @test_fmin_legacy_ole_f32(float addrspace(1)* %out, float %a, float %b) nounwind {
%cmp = fcmp ole float %a, %b
%val = select i1 %cmp, float %a, float %b
store float %val, float addrspace(1)* %out, align 4
ret void
}
; FUNC-LABEL: @test_fmin_legacy_olt_f32
; SI: v_min_legacy_f32_e32
define void @test_fmin_legacy_olt_f32(float addrspace(1)* %out, float %a, float %b) nounwind {
%cmp = fcmp olt float %a, %b
%val = select i1 %cmp, float %a, float %b
store float %val, float addrspace(1)* %out, align 4
ret void
}
; FUNC-LABEL: @test_fmin_legacy_ult_f32
; SI: v_min_legacy_f32_e32
define void @test_fmin_legacy_ult_f32(float addrspace(1)* %out, float %a, float %b) nounwind {
%cmp = fcmp ult float %a, %b
%val = select i1 %cmp, float %a, float %b
store float %val, float addrspace(1)* %out, align 4
ret void
}