radeon/llvm: Add custom SDNode for FRACT
[mesa.git] / src / gallium / drivers / radeon / AMDGPUISelLowering.cpp
1 //===-- AMDGPUISelLowering.cpp - AMDGPU Common DAG lowering functions -----===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This is the parent TargetLowering class for hardware code gen targets.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "AMDGPUISelLowering.h"
15 #include "AMDILIntrinsicInfo.h"
16 #include "AMDGPUUtil.h"
17 #include "llvm/CodeGen/MachineRegisterInfo.h"
18
19 using namespace llvm;
20
21 AMDGPUTargetLowering::AMDGPUTargetLowering(TargetMachine &TM) :
22 AMDILTargetLowering(TM)
23 {
24 // We need to custom lower some of the intrinsics
25 setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom);
26
27 setOperationAction(ISD::SELECT_CC, MVT::f32, Custom);
28 setOperationAction(ISD::SELECT_CC, MVT::i32, Custom);
29 }
30
31 SDValue AMDGPUTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG)
32 const
33 {
34 switch (Op.getOpcode()) {
35 default: return AMDILTargetLowering::LowerOperation(Op, DAG);
36 case ISD::INTRINSIC_WO_CHAIN: return LowerINTRINSIC_WO_CHAIN(Op, DAG);
37 case ISD::SELECT_CC: return LowerSELECT_CC(Op, DAG);
38 }
39 }
40
41 SDValue AMDGPUTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
42 SelectionDAG &DAG) const
43 {
44 unsigned IntrinsicID = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
45 DebugLoc DL = Op.getDebugLoc();
46 EVT VT = Op.getValueType();
47
48 switch (IntrinsicID) {
49 default: return Op;
50 case AMDGPUIntrinsic::AMDIL_abs:
51 return LowerIntrinsicIABS(Op, DAG);
52 case AMDGPUIntrinsic::AMDGPU_lrp:
53 return LowerIntrinsicLRP(Op, DAG);
54 case AMDGPUIntrinsic::AMDIL_fraction:
55 return DAG.getNode(AMDGPUISD::FRACT, DL, VT, Op.getOperand(1));
56 case AMDGPUIntrinsic::AMDIL_mad:
57 return DAG.getNode(AMDILISD::MAD, DL, VT, Op.getOperand(1),
58 Op.getOperand(2), Op.getOperand(3));
59 case AMDGPUIntrinsic::AMDIL_max:
60 return DAG.getNode(AMDGPUISD::FMAX, DL, VT, Op.getOperand(1),
61 Op.getOperand(2));
62 case AMDGPUIntrinsic::AMDGPU_imax:
63 return DAG.getNode(AMDGPUISD::SMAX, DL, VT, Op.getOperand(1),
64 Op.getOperand(2));
65 case AMDGPUIntrinsic::AMDGPU_umax:
66 return DAG.getNode(AMDGPUISD::UMAX, DL, VT, Op.getOperand(1),
67 Op.getOperand(2));
68 case AMDGPUIntrinsic::AMDIL_min:
69 return DAG.getNode(AMDGPUISD::FMIN, DL, VT, Op.getOperand(1),
70 Op.getOperand(2));
71 case AMDGPUIntrinsic::AMDGPU_imin:
72 return DAG.getNode(AMDGPUISD::SMIN, DL, VT, Op.getOperand(1),
73 Op.getOperand(2));
74 case AMDGPUIntrinsic::AMDGPU_umin:
75 return DAG.getNode(AMDGPUISD::UMIN, DL, VT, Op.getOperand(1),
76 Op.getOperand(2));
77 }
78 }
79
80 ///IABS(a) = SMAX(sub(0, a), a)
81 SDValue AMDGPUTargetLowering::LowerIntrinsicIABS(SDValue Op,
82 SelectionDAG &DAG) const
83 {
84
85 DebugLoc DL = Op.getDebugLoc();
86 EVT VT = Op.getValueType();
87 SDValue Neg = DAG.getNode(ISD::SUB, DL, VT, DAG.getConstant(0, VT),
88 Op.getOperand(1));
89
90 return DAG.getNode(AMDGPUISD::SMAX, DL, VT, Neg, Op.getOperand(1));
91 }
92
93 /// Linear Interpolation
94 /// LRP(a, b, c) = muladd(a, b, (1 - a) * c)
95 SDValue AMDGPUTargetLowering::LowerIntrinsicLRP(SDValue Op,
96 SelectionDAG &DAG) const
97 {
98 DebugLoc DL = Op.getDebugLoc();
99 EVT VT = Op.getValueType();
100 SDValue OneSubA = DAG.getNode(ISD::FSUB, DL, VT,
101 DAG.getConstantFP(1.0f, MVT::f32),
102 Op.getOperand(1));
103 SDValue OneSubAC = DAG.getNode(ISD::FMUL, DL, VT, OneSubA,
104 Op.getOperand(3));
105 return DAG.getNode(AMDILISD::MAD, DL, VT, Op.getOperand(1),
106 Op.getOperand(2),
107 OneSubAC);
108 }
109
110 SDValue AMDGPUTargetLowering::LowerSELECT_CC(SDValue Op,
111 SelectionDAG &DAG) const
112 {
113 DebugLoc DL = Op.getDebugLoc();
114 EVT VT = Op.getValueType();
115
116 SDValue LHS = Op.getOperand(0);
117 SDValue RHS = Op.getOperand(1);
118 SDValue True = Op.getOperand(2);
119 SDValue False = Op.getOperand(3);
120 SDValue CC = Op.getOperand(4);
121 ISD::CondCode CCOpcode = cast<CondCodeSDNode>(CC)->get();
122 SDValue Temp;
123
124 // LHS and RHS are guaranteed to be the same value type
125 EVT CompareVT = LHS.getValueType();
126
127 // We need all the operands of SELECT_CC to have the same value type, so if
128 // necessary we need to convert LHS and RHS to be the same type True and
129 // False. True and False are guaranteed to have the same type as this
130 // SELECT_CC node.
131
132 if (CompareVT != VT) {
133 ISD::NodeType ConversionOp = ISD::DELETED_NODE;
134 if (VT == MVT::f32 && CompareVT == MVT::i32) {
135 if (isUnsignedIntSetCC(CCOpcode)) {
136 ConversionOp = ISD::UINT_TO_FP;
137 } else {
138 ConversionOp = ISD::SINT_TO_FP;
139 }
140 } else if (VT == MVT::i32 && CompareVT == MVT::f32) {
141 ConversionOp = ISD::FP_TO_SINT;
142 } else {
143 // I don't think there will be any other type pairings.
144 assert(!"Unhandled operand type parings in SELECT_CC");
145 }
146 // XXX Check the value of LHS and RHS and avoid creating sequences like
147 // (FTOI (ITOF))
148 LHS = DAG.getNode(ConversionOp, DL, VT, LHS);
149 RHS = DAG.getNode(ConversionOp, DL, VT, RHS);
150 }
151
152 // If True is a hardware TRUE value and False is a hardware FALSE value or
153 // vice-versa we can handle this with a native instruction (SET* instructions).
154 if ((isHWTrueValue(True) && isHWFalseValue(False))) {
155 return DAG.getNode(ISD::SELECT_CC, DL, VT, LHS, RHS, True, False, CC);
156 }
157
158 // XXX If True is a hardware TRUE value and False is a hardware FALSE value,
159 // we can handle this with a native instruction, but we need to swap true
160 // and false and change the conditional.
161 if (isHWTrueValue(False) && isHWFalseValue(True)) {
162 }
163
164 // XXX Check if we can lower this to a SELECT or if it is supported by a native
165 // operation. (The code below does this but we don't have the Instruction
166 // selection patterns to do this yet.
167 #if 0
168 if (isZero(LHS) || isZero(RHS)) {
169 SDValue Cond = (isZero(LHS) ? RHS : LHS);
170 bool SwapTF = false;
171 switch (CCOpcode) {
172 case ISD::SETOEQ:
173 case ISD::SETUEQ:
174 case ISD::SETEQ:
175 SwapTF = true;
176 // Fall through
177 case ISD::SETONE:
178 case ISD::SETUNE:
179 case ISD::SETNE:
180 // We can lower to select
181 if (SwapTF) {
182 Temp = True;
183 True = False;
184 False = Temp;
185 }
186 // CNDE
187 return DAG.getNode(ISD::SELECT, DL, VT, Cond, True, False);
188 default:
189 // Supported by a native operation (CNDGE, CNDGT)
190 return DAG.getNode(ISD::SELECT_CC, DL, VT, LHS, RHS, True, False, CC);
191 }
192 }
193 #endif
194
195 // If we make it this for it means we have no native instructions to handle
196 // this SELECT_CC, so we must lower it.
197 SDValue HWTrue, HWFalse;
198
199 if (VT == MVT::f32) {
200 HWTrue = DAG.getConstantFP(1.0f, VT);
201 HWFalse = DAG.getConstantFP(0.0f, VT);
202 } else if (VT == MVT::i32) {
203 HWTrue = DAG.getConstant(-1, VT);
204 HWFalse = DAG.getConstant(0, VT);
205 }
206 else {
207 assert(!"Unhandled value type in LowerSELECT_CC");
208 }
209
210 // Lower this unsupported SELECT_CC into a combination of two supported
211 // SELECT_CC operations.
212 SDValue Cond = DAG.getNode(ISD::SELECT_CC, DL, VT, LHS, RHS, HWTrue, HWFalse, CC);
213
214 return DAG.getNode(ISD::SELECT, DL, VT, Cond, True, False);
215 }
216
217 //===----------------------------------------------------------------------===//
218 // Helper functions
219 //===----------------------------------------------------------------------===//
220
221 bool AMDGPUTargetLowering::isHWTrueValue(SDValue Op) const
222 {
223 if (ConstantFPSDNode * CFP = dyn_cast<ConstantFPSDNode>(Op)) {
224 return CFP->isExactlyValue(1.0);
225 }
226 if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) {
227 return C->isAllOnesValue();
228 }
229 return false;
230 }
231
232 bool AMDGPUTargetLowering::isHWFalseValue(SDValue Op) const
233 {
234 if (ConstantFPSDNode * CFP = dyn_cast<ConstantFPSDNode>(Op)) {
235 return CFP->getValueAPF().isZero();
236 }
237 if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) {
238 return C->isNullValue();
239 }
240 return false;
241 }
242
243 void AMDGPUTargetLowering::addLiveIn(MachineInstr * MI,
244 MachineFunction * MF, MachineRegisterInfo & MRI,
245 const TargetInstrInfo * TII, unsigned reg) const
246 {
247 AMDGPU::utilAddLiveIn(MF, MRI, TII, reg, MI->getOperand(0).getReg());
248 }
249
250 #define NODE_NAME_CASE(node) case AMDGPUISD::node: return #node;
251
252 const char* AMDGPUTargetLowering::getTargetNodeName(unsigned Opcode) const
253 {
254 switch (Opcode) {
255 default: return AMDILTargetLowering::getTargetNodeName(Opcode);
256
257 NODE_NAME_CASE(FRACT)
258 NODE_NAME_CASE(FMAX)
259 NODE_NAME_CASE(SMAX)
260 NODE_NAME_CASE(UMAX)
261 NODE_NAME_CASE(FMIN)
262 NODE_NAME_CASE(SMIN)
263 NODE_NAME_CASE(UMIN)
264 }
265 }