1 //===-- SparcISelDAGToDAG.cpp - A dag to dag inst selector for Sparc ------===//
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 file defines an instruction selector for the SPARC target.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "SparcTargetMachine.h"
15 #include "llvm/CodeGen/MachineRegisterInfo.h"
16 #include "llvm/CodeGen/SelectionDAGISel.h"
17 #include "llvm/IR/Intrinsics.h"
18 #include "llvm/Support/Compiler.h"
19 #include "llvm/Support/Debug.h"
20 #include "llvm/Support/ErrorHandling.h"
21 #include "llvm/Support/raw_ostream.h"
22 using namespace llvm;
23
24 //===----------------------------------------------------------------------===//
25 // Instruction Selector Implementation
26 //===----------------------------------------------------------------------===//
27
28 //===--------------------------------------------------------------------===//
29 /// SparcDAGToDAGISel - SPARC specific code to select SPARC machine
30 /// instructions for SelectionDAG operations.
31 ///
32 namespace {
33 class SparcDAGToDAGISel : public SelectionDAGISel {
34 /// Subtarget - Keep a pointer to the Sparc Subtarget around so that we can
35 /// make the right decision when generating code for different targets.
36 const SparcSubtarget *Subtarget;
37 public:
SparcDAGToDAGISel(SparcTargetMachine & tm)38 explicit SparcDAGToDAGISel(SparcTargetMachine &tm) : SelectionDAGISel(tm) {}
39
runOnMachineFunction(MachineFunction & MF)40 bool runOnMachineFunction(MachineFunction &MF) override {
41 Subtarget = &MF.getSubtarget<SparcSubtarget>();
42 return SelectionDAGISel::runOnMachineFunction(MF);
43 }
44
45 SDNode *Select(SDNode *N) override;
46
47 // Complex Pattern Selectors.
48 bool SelectADDRrr(SDValue N, SDValue &R1, SDValue &R2);
49 bool SelectADDRri(SDValue N, SDValue &Base, SDValue &Offset);
50
51 /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
52 /// inline asm expressions.
53 bool SelectInlineAsmMemoryOperand(const SDValue &Op,
54 unsigned ConstraintID,
55 std::vector<SDValue> &OutOps) override;
56
getPassName() const57 const char *getPassName() const override {
58 return "SPARC DAG->DAG Pattern Instruction Selection";
59 }
60
61 // Include the pieces autogenerated from the target description.
62 #include "SparcGenDAGISel.inc"
63
64 private:
65 SDNode* getGlobalBaseReg();
66 SDNode *SelectInlineAsm(SDNode *N);
67 };
68 } // end anonymous namespace
69
getGlobalBaseReg()70 SDNode* SparcDAGToDAGISel::getGlobalBaseReg() {
71 unsigned GlobalBaseReg = Subtarget->getInstrInfo()->getGlobalBaseReg(MF);
72 return CurDAG->getRegister(GlobalBaseReg,
73 TLI->getPointerTy(CurDAG->getDataLayout()))
74 .getNode();
75 }
76
SelectADDRri(SDValue Addr,SDValue & Base,SDValue & Offset)77 bool SparcDAGToDAGISel::SelectADDRri(SDValue Addr,
78 SDValue &Base, SDValue &Offset) {
79 if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
80 Base = CurDAG->getTargetFrameIndex(
81 FIN->getIndex(), TLI->getPointerTy(CurDAG->getDataLayout()));
82 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
83 return true;
84 }
85 if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
86 Addr.getOpcode() == ISD::TargetGlobalAddress ||
87 Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
88 return false; // direct calls.
89
90 if (Addr.getOpcode() == ISD::ADD) {
91 if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) {
92 if (isInt<13>(CN->getSExtValue())) {
93 if (FrameIndexSDNode *FIN =
94 dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) {
95 // Constant offset from frame ref.
96 Base = CurDAG->getTargetFrameIndex(
97 FIN->getIndex(), TLI->getPointerTy(CurDAG->getDataLayout()));
98 } else {
99 Base = Addr.getOperand(0);
100 }
101 Offset = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr),
102 MVT::i32);
103 return true;
104 }
105 }
106 if (Addr.getOperand(0).getOpcode() == SPISD::Lo) {
107 Base = Addr.getOperand(1);
108 Offset = Addr.getOperand(0).getOperand(0);
109 return true;
110 }
111 if (Addr.getOperand(1).getOpcode() == SPISD::Lo) {
112 Base = Addr.getOperand(0);
113 Offset = Addr.getOperand(1).getOperand(0);
114 return true;
115 }
116 }
117 Base = Addr;
118 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
119 return true;
120 }
121
SelectADDRrr(SDValue Addr,SDValue & R1,SDValue & R2)122 bool SparcDAGToDAGISel::SelectADDRrr(SDValue Addr, SDValue &R1, SDValue &R2) {
123 if (Addr.getOpcode() == ISD::FrameIndex) return false;
124 if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
125 Addr.getOpcode() == ISD::TargetGlobalAddress ||
126 Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
127 return false; // direct calls.
128
129 if (Addr.getOpcode() == ISD::ADD) {
130 if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
131 if (isInt<13>(CN->getSExtValue()))
132 return false; // Let the reg+imm pattern catch this!
133 if (Addr.getOperand(0).getOpcode() == SPISD::Lo ||
134 Addr.getOperand(1).getOpcode() == SPISD::Lo)
135 return false; // Let the reg+imm pattern catch this!
136 R1 = Addr.getOperand(0);
137 R2 = Addr.getOperand(1);
138 return true;
139 }
140
141 R1 = Addr;
142 R2 = CurDAG->getRegister(SP::G0, TLI->getPointerTy(CurDAG->getDataLayout()));
143 return true;
144 }
145
146
147 // Re-assemble i64 arguments split up in SelectionDAGBuilder's
148 // visitInlineAsm / GetRegistersForValue functions.
149 //
150 // Note: This function was copied from, and is essentially identical
151 // to ARMISelDAGToDAG::SelectInlineAsm. It is very unfortunate that
152 // such hacking-up is necessary; a rethink of how inline asm operands
153 // are handled may be in order to make doing this more sane.
154 //
155 // TODO: fix inline asm support so I can simply tell it that 'i64'
156 // inputs to asm need to be allocated to the IntPair register type,
157 // and have that work. Then, delete this function.
SelectInlineAsm(SDNode * N)158 SDNode *SparcDAGToDAGISel::SelectInlineAsm(SDNode *N){
159 std::vector<SDValue> AsmNodeOperands;
160 unsigned Flag, Kind;
161 bool Changed = false;
162 unsigned NumOps = N->getNumOperands();
163
164 // Normally, i64 data is bounded to two arbitrary GPRs for "%r"
165 // constraint. However, some instructions (e.g. ldd/std) require
166 // (even/even+1) GPRs.
167
168 // So, here, we check for this case, and mutate the inlineasm to use
169 // a single IntPair register instead, which guarantees such even/odd
170 // placement.
171
172 SDLoc dl(N);
173 SDValue Glue = N->getGluedNode() ? N->getOperand(NumOps-1)
174 : SDValue(nullptr,0);
175
176 SmallVector<bool, 8> OpChanged;
177 // Glue node will be appended late.
178 for(unsigned i = 0, e = N->getGluedNode() ? NumOps - 1 : NumOps; i < e; ++i) {
179 SDValue op = N->getOperand(i);
180 AsmNodeOperands.push_back(op);
181
182 if (i < InlineAsm::Op_FirstOperand)
183 continue;
184
185 if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(N->getOperand(i))) {
186 Flag = C->getZExtValue();
187 Kind = InlineAsm::getKind(Flag);
188 }
189 else
190 continue;
191
192 // Immediate operands to inline asm in the SelectionDAG are modeled with
193 // two operands. The first is a constant of value InlineAsm::Kind_Imm, and
194 // the second is a constant with the value of the immediate. If we get here
195 // and we have a Kind_Imm, skip the next operand, and continue.
196 if (Kind == InlineAsm::Kind_Imm) {
197 SDValue op = N->getOperand(++i);
198 AsmNodeOperands.push_back(op);
199 continue;
200 }
201
202 unsigned NumRegs = InlineAsm::getNumOperandRegisters(Flag);
203 if (NumRegs)
204 OpChanged.push_back(false);
205
206 unsigned DefIdx = 0;
207 bool IsTiedToChangedOp = false;
208 // If it's a use that is tied with a previous def, it has no
209 // reg class constraint.
210 if (Changed && InlineAsm::isUseOperandTiedToDef(Flag, DefIdx))
211 IsTiedToChangedOp = OpChanged[DefIdx];
212
213 if (Kind != InlineAsm::Kind_RegUse && Kind != InlineAsm::Kind_RegDef
214 && Kind != InlineAsm::Kind_RegDefEarlyClobber)
215 continue;
216
217 unsigned RC;
218 bool HasRC = InlineAsm::hasRegClassConstraint(Flag, RC);
219 if ((!IsTiedToChangedOp && (!HasRC || RC != SP::IntRegsRegClassID))
220 || NumRegs != 2)
221 continue;
222
223 assert((i+2 < NumOps) && "Invalid number of operands in inline asm");
224 SDValue V0 = N->getOperand(i+1);
225 SDValue V1 = N->getOperand(i+2);
226 unsigned Reg0 = cast<RegisterSDNode>(V0)->getReg();
227 unsigned Reg1 = cast<RegisterSDNode>(V1)->getReg();
228 SDValue PairedReg;
229 MachineRegisterInfo &MRI = MF->getRegInfo();
230
231 if (Kind == InlineAsm::Kind_RegDef ||
232 Kind == InlineAsm::Kind_RegDefEarlyClobber) {
233 // Replace the two GPRs with 1 GPRPair and copy values from GPRPair to
234 // the original GPRs.
235
236 unsigned GPVR = MRI.createVirtualRegister(&SP::IntPairRegClass);
237 PairedReg = CurDAG->getRegister(GPVR, MVT::v2i32);
238 SDValue Chain = SDValue(N,0);
239
240 SDNode *GU = N->getGluedUser();
241 SDValue RegCopy = CurDAG->getCopyFromReg(Chain, dl, GPVR, MVT::v2i32,
242 Chain.getValue(1));
243
244 // Extract values from a GPRPair reg and copy to the original GPR reg.
245 SDValue Sub0 = CurDAG->getTargetExtractSubreg(SP::sub_even, dl, MVT::i32,
246 RegCopy);
247 SDValue Sub1 = CurDAG->getTargetExtractSubreg(SP::sub_odd, dl, MVT::i32,
248 RegCopy);
249 SDValue T0 = CurDAG->getCopyToReg(Sub0, dl, Reg0, Sub0,
250 RegCopy.getValue(1));
251 SDValue T1 = CurDAG->getCopyToReg(Sub1, dl, Reg1, Sub1, T0.getValue(1));
252
253 // Update the original glue user.
254 std::vector<SDValue> Ops(GU->op_begin(), GU->op_end()-1);
255 Ops.push_back(T1.getValue(1));
256 CurDAG->UpdateNodeOperands(GU, Ops);
257 }
258 else {
259 // For Kind == InlineAsm::Kind_RegUse, we first copy two GPRs into a
260 // GPRPair and then pass the GPRPair to the inline asm.
261 SDValue Chain = AsmNodeOperands[InlineAsm::Op_InputChain];
262
263 // As REG_SEQ doesn't take RegisterSDNode, we copy them first.
264 SDValue T0 = CurDAG->getCopyFromReg(Chain, dl, Reg0, MVT::i32,
265 Chain.getValue(1));
266 SDValue T1 = CurDAG->getCopyFromReg(Chain, dl, Reg1, MVT::i32,
267 T0.getValue(1));
268 SDValue Pair = SDValue(
269 CurDAG->getMachineNode(
270 TargetOpcode::REG_SEQUENCE, dl, MVT::v2i32,
271 {
272 CurDAG->getTargetConstant(SP::IntPairRegClassID, dl,
273 MVT::i32),
274 T0,
275 CurDAG->getTargetConstant(SP::sub_even, dl, MVT::i32),
276 T1,
277 CurDAG->getTargetConstant(SP::sub_odd, dl, MVT::i32),
278 }),
279 0);
280
281 // Copy REG_SEQ into a GPRPair-typed VR and replace the original two
282 // i32 VRs of inline asm with it.
283 unsigned GPVR = MRI.createVirtualRegister(&SP::IntPairRegClass);
284 PairedReg = CurDAG->getRegister(GPVR, MVT::v2i32);
285 Chain = CurDAG->getCopyToReg(T1, dl, GPVR, Pair, T1.getValue(1));
286
287 AsmNodeOperands[InlineAsm::Op_InputChain] = Chain;
288 Glue = Chain.getValue(1);
289 }
290
291 Changed = true;
292
293 if(PairedReg.getNode()) {
294 OpChanged[OpChanged.size() -1 ] = true;
295 Flag = InlineAsm::getFlagWord(Kind, 1 /* RegNum*/);
296 if (IsTiedToChangedOp)
297 Flag = InlineAsm::getFlagWordForMatchingOp(Flag, DefIdx);
298 else
299 Flag = InlineAsm::getFlagWordForRegClass(Flag, SP::IntPairRegClassID);
300 // Replace the current flag.
301 AsmNodeOperands[AsmNodeOperands.size() -1] = CurDAG->getTargetConstant(
302 Flag, dl, MVT::i32);
303 // Add the new register node and skip the original two GPRs.
304 AsmNodeOperands.push_back(PairedReg);
305 // Skip the next two GPRs.
306 i += 2;
307 }
308 }
309
310 if (Glue.getNode())
311 AsmNodeOperands.push_back(Glue);
312 if (!Changed)
313 return nullptr;
314
315 SDValue New = CurDAG->getNode(ISD::INLINEASM, SDLoc(N),
316 CurDAG->getVTList(MVT::Other, MVT::Glue), AsmNodeOperands);
317 New->setNodeId(-1);
318 return New.getNode();
319 }
320
Select(SDNode * N)321 SDNode *SparcDAGToDAGISel::Select(SDNode *N) {
322 SDLoc dl(N);
323 if (N->isMachineOpcode()) {
324 N->setNodeId(-1);
325 return nullptr; // Already selected.
326 }
327
328 switch (N->getOpcode()) {
329 default: break;
330 case ISD::INLINEASM: {
331 SDNode *ResNode = SelectInlineAsm(N);
332 if (ResNode)
333 return ResNode;
334 break;
335 }
336 case SPISD::GLOBAL_BASE_REG:
337 return getGlobalBaseReg();
338
339 case ISD::SDIV:
340 case ISD::UDIV: {
341 // sdivx / udivx handle 64-bit divides.
342 if (N->getValueType(0) == MVT::i64)
343 break;
344 // FIXME: should use a custom expander to expose the SRA to the dag.
345 SDValue DivLHS = N->getOperand(0);
346 SDValue DivRHS = N->getOperand(1);
347
348 // Set the Y register to the high-part.
349 SDValue TopPart;
350 if (N->getOpcode() == ISD::SDIV) {
351 TopPart = SDValue(CurDAG->getMachineNode(SP::SRAri, dl, MVT::i32, DivLHS,
352 CurDAG->getTargetConstant(31, dl, MVT::i32)),
353 0);
354 } else {
355 TopPart = CurDAG->getRegister(SP::G0, MVT::i32);
356 }
357 TopPart = CurDAG->getCopyToReg(CurDAG->getEntryNode(), dl, SP::Y, TopPart,
358 SDValue())
359 .getValue(1);
360
361 // FIXME: Handle div by immediate.
362 unsigned Opcode = N->getOpcode() == ISD::SDIV ? SP::SDIVrr : SP::UDIVrr;
363 return CurDAG->SelectNodeTo(N, Opcode, MVT::i32, DivLHS, DivRHS,
364 TopPart);
365 }
366 case ISD::MULHU:
367 case ISD::MULHS: {
368 // FIXME: Handle mul by immediate.
369 SDValue MulLHS = N->getOperand(0);
370 SDValue MulRHS = N->getOperand(1);
371 unsigned Opcode = N->getOpcode() == ISD::MULHU ? SP::UMULrr : SP::SMULrr;
372 SDNode *Mul =
373 CurDAG->getMachineNode(Opcode, dl, MVT::i32, MVT::i32, MulLHS, MulRHS);
374 SDValue ResultHigh = SDValue(Mul, 1);
375 ReplaceUses(SDValue(N, 0), ResultHigh);
376 return nullptr;
377 }
378 }
379
380 return SelectCode(N);
381 }
382
383
384 /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
385 /// inline asm expressions.
386 bool
SelectInlineAsmMemoryOperand(const SDValue & Op,unsigned ConstraintID,std::vector<SDValue> & OutOps)387 SparcDAGToDAGISel::SelectInlineAsmMemoryOperand(const SDValue &Op,
388 unsigned ConstraintID,
389 std::vector<SDValue> &OutOps) {
390 SDValue Op0, Op1;
391 switch (ConstraintID) {
392 default: return true;
393 case InlineAsm::Constraint_i:
394 case InlineAsm::Constraint_m: // memory
395 if (!SelectADDRrr(Op, Op0, Op1))
396 SelectADDRri(Op, Op0, Op1);
397 break;
398 }
399
400 OutOps.push_back(Op0);
401 OutOps.push_back(Op1);
402 return false;
403 }
404
405 /// createSparcISelDag - This pass converts a legalized DAG into a
406 /// SPARC-specific DAG, ready for instruction scheduling.
407 ///
createSparcISelDag(SparcTargetMachine & TM)408 FunctionPass *llvm::createSparcISelDag(SparcTargetMachine &TM) {
409 return new SparcDAGToDAGISel(TM);
410 }
411