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