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