LLVM 24.0.0git
SparcISelDAGToDAG.cpp
Go to the documentation of this file.
1//===-- SparcISelDAGToDAG.cpp - A dag to dag inst selector for Sparc ------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines an instruction selector for the SPARC target.
10//
11//===----------------------------------------------------------------------===//
12
13#include "Sparc.h"
15#include "SparcTargetMachine.h"
20using namespace llvm;
21
22#define DEBUG_TYPE "sparc-isel"
23#define PASS_NAME "SPARC DAG->DAG Pattern Instruction Selection"
24
25//===----------------------------------------------------------------------===//
26// Instruction Selector Implementation
27//===----------------------------------------------------------------------===//
28
29//===--------------------------------------------------------------------===//
30/// SparcDAGToDAGISel - SPARC specific code to select SPARC machine
31/// instructions for SelectionDAG operations.
32///
33namespace {
34class SparcDAGToDAGISel : public SelectionDAGISel {
35 /// Subtarget - Keep a pointer to the Sparc Subtarget around so that we can
36 /// make the right decision when generating code for different targets.
37 const SparcSubtarget *Subtarget = nullptr;
38
39public:
40 SparcDAGToDAGISel() = delete;
41
42 explicit SparcDAGToDAGISel(SparcTargetMachine &tm, CodeGenOptLevel OptLevel)
43 : SelectionDAGISel(tm, OptLevel) {}
44
45 bool runOnMachineFunction(MachineFunction &MF) override {
46 Subtarget = &MF.getSubtarget<SparcSubtarget>();
48 }
49
50 void Select(SDNode *N) override;
51
52 // Complex Pattern Selectors.
53 bool SelectADDRrr(SDValue N, SDValue &R1, SDValue &R2);
54 bool SelectADDRri(SDValue N, SDValue &Base, SDValue &Offset);
55 bool SelectForceADDRrr(SDValue N, SDValue &Base, SDValue &Disp);
56
57 /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
58 /// inline asm expressions.
59 bool SelectInlineAsmMemoryOperand(const SDValue &Op,
60 InlineAsm::ConstraintCode ConstraintID,
61 std::vector<SDValue> &OutOps) override;
62
63 // Include the pieces autogenerated from the target description.
64#include "SparcGenDAGISel.inc"
65
66private:
67 SDNode* getGlobalBaseReg();
68 bool tryInlineAsm(SDNode *N);
69};
70
71class SparcDAGToDAGISelLegacy : public SelectionDAGISelLegacy {
72public:
73 static char ID;
74 explicit SparcDAGToDAGISelLegacy(SparcTargetMachine &tm,
75 CodeGenOptLevel OptLevel)
77 ID, std::make_unique<SparcDAGToDAGISel>(tm, OptLevel)) {}
78};
79} // end anonymous namespace
80
81char SparcDAGToDAGISelLegacy::ID = 0;
82
83INITIALIZE_PASS(SparcDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false)
84
85SDNode* SparcDAGToDAGISel::getGlobalBaseReg() {
86 Register GlobalBaseReg = Subtarget->getInstrInfo()->getGlobalBaseReg(MF);
87 return CurDAG->getRegister(GlobalBaseReg,
88 TLI->getPointerTy(CurDAG->getDataLayout()))
89 .getNode();
90}
91
92bool SparcDAGToDAGISel::SelectADDRri(SDValue Addr,
94 if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
95 Base = CurDAG->getTargetFrameIndex(
96 FIN->getIndex(), TLI->getPointerTy(CurDAG->getDataLayout()));
97 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
98 return true;
99 }
100 if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
103 return false; // direct calls.
104
105 if (Addr.getOpcode() == ISD::ADD) {
106 if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) {
107 if (isInt<13>(CN->getSExtValue())) {
108 if (FrameIndexSDNode *FIN =
110 // Constant offset from frame ref.
111 Base = CurDAG->getTargetFrameIndex(
112 FIN->getIndex(), TLI->getPointerTy(CurDAG->getDataLayout()));
113 } else {
114 Base = Addr.getOperand(0);
115 }
116 Offset = CurDAG->getSignedTargetConstant(CN->getSExtValue(),
117 SDLoc(Addr), MVT::i32);
118 return true;
119 }
120 }
121 if (Addr.getOperand(0).getOpcode() == SPISD::Lo) {
122 Base = Addr.getOperand(1);
123 Offset = Addr.getOperand(0).getOperand(0);
124 return true;
125 }
126 if (Addr.getOperand(1).getOpcode() == SPISD::Lo) {
127 Base = Addr.getOperand(0);
128 Offset = Addr.getOperand(1).getOperand(0);
129 return true;
130 }
131 }
132 Base = Addr;
133 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
134 return true;
135}
136
137bool SparcDAGToDAGISel::SelectADDRrr(SDValue Addr, SDValue &R1, SDValue &R2) {
138 if (Addr.getOpcode() == ISD::FrameIndex) return false;
139 if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
142 return false; // direct calls.
143
144 if (Addr.getOpcode() == ISD::ADD) {
145 if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
146 if (isInt<13>(CN->getSExtValue()))
147 return false; // Let the reg+imm pattern catch this!
148 if (Addr.getOperand(0).getOpcode() == SPISD::Lo ||
149 Addr.getOperand(1).getOpcode() == SPISD::Lo)
150 return false; // Let the reg+imm pattern catch this!
151 R1 = Addr.getOperand(0);
152 R2 = Addr.getOperand(1);
153 return true;
154 }
155
156 R1 = Addr;
157 R2 = CurDAG->getRegister(SP::G0, TLI->getPointerTy(CurDAG->getDataLayout()));
158 return true;
159}
160
161bool SparcDAGToDAGISel::SelectForceADDRrr(SDValue Addr, SDValue &Base,
162 SDValue &Disp) {
163 if (SelectADDRrr(Addr, Base, Disp))
164 return true;
165
166 // Otherwise we'll use the full address in base and set the offset part to
167 // zero.
168 Base = Addr;
169 Disp =
170 CurDAG->getRegister(SP::G0, TLI->getPointerTy(CurDAG->getDataLayout()));
171 return true;
172}
173
174// Re-assemble i64 arguments split up in SelectionDAGBuilder's
175// visitInlineAsm / GetRegistersForValue functions.
176//
177// Note: This function was copied from, and is essentially identical
178// to ARMISelDAGToDAG::SelectInlineAsm. It is very unfortunate that
179// such hacking-up is necessary; a rethink of how inline asm operands
180// are handled may be in order to make doing this more sane.
181//
182// TODO: fix inline asm support so I can simply tell it that 'i64'
183// inputs to asm need to be allocated to the IntPair register type,
184// and have that work. Then, delete this function.
185bool SparcDAGToDAGISel::tryInlineAsm(SDNode *N){
186 std::vector<SDValue> AsmNodeOperands;
187 InlineAsm::Flag Flag;
188 bool Changed = false;
189 unsigned NumOps = N->getNumOperands();
190
191 // Normally, i64 data is bounded to two arbitrary GPRs for "%r"
192 // constraint. However, some instructions (e.g. ldd/std) require
193 // (even/even+1) GPRs.
194
195 // So, here, we check for this case, and mutate the inlineasm to use
196 // a single IntPair register instead, which guarantees such even/odd
197 // placement.
198
199 SDLoc dl(N);
200 SDValue Glue = N->getGluedNode() ? N->getOperand(NumOps - 1) : SDValue();
201
202 SmallVector<bool, 8> OpChanged;
203 // Glue node will be appended late.
204 for(unsigned i = 0, e = N->getGluedNode() ? NumOps - 1 : NumOps; i < e; ++i) {
205 SDValue op = N->getOperand(i);
206 AsmNodeOperands.push_back(op);
207
209 continue;
210
211 if (const auto *C = dyn_cast<ConstantSDNode>(N->getOperand(i)))
212 Flag = InlineAsm::Flag(C->getZExtValue());
213 else
214 continue;
215
216 // Immediate operands to inline asm in the SelectionDAG are modeled with
217 // two operands. The first is a constant of value InlineAsm::Kind::Imm, and
218 // the second is a constant with the value of the immediate. If we get here
219 // and we have a Kind::Imm, skip the next operand, and continue.
220 if (Flag.isImmKind()) {
221 SDValue op = N->getOperand(++i);
222 AsmNodeOperands.push_back(op);
223 continue;
224 }
225
226 const unsigned NumRegs = Flag.getNumOperandRegisters();
227 if (NumRegs)
228 OpChanged.push_back(false);
229
230 unsigned DefIdx = 0;
231 bool IsTiedToChangedOp = false;
232 // If it's a use that is tied with a previous def, it has no
233 // reg class constraint.
234 if (Changed && Flag.isUseOperandTiedToDef(DefIdx))
235 IsTiedToChangedOp = OpChanged[DefIdx];
236
237 if (!Flag.isRegUseKind() && !Flag.isRegDefKind() &&
238 !Flag.isRegDefEarlyClobberKind())
239 continue;
240
241 unsigned RC;
242 const bool HasRC = Flag.hasRegClassConstraint(RC);
243 if ((!IsTiedToChangedOp && (!HasRC || RC != SP::IntRegsRegClassID))
244 || NumRegs != 2)
245 continue;
246
247 assert((i+2 < NumOps) && "Invalid number of operands in inline asm");
248 SDValue V0 = N->getOperand(i+1);
249 SDValue V1 = N->getOperand(i+2);
250 Register Reg0 = cast<RegisterSDNode>(V0)->getReg();
251 Register Reg1 = cast<RegisterSDNode>(V1)->getReg();
252 SDValue PairedReg;
253 MachineRegisterInfo &MRI = MF->getRegInfo();
254
255 if (Flag.isRegDefKind() || Flag.isRegDefEarlyClobberKind()) {
256 // Replace the two GPRs with 1 GPRPair and copy values from GPRPair to
257 // the original GPRs.
258
259 Register GPVR = MRI.createVirtualRegister(&SP::IntPairRegClass);
260 PairedReg = CurDAG->getRegister(GPVR, MVT::v2i32);
261 SDValue Chain = SDValue(N,0);
262
263 SDNode *GU = N->getGluedUser();
264 SDValue RegCopy = CurDAG->getCopyFromReg(Chain, dl, GPVR, MVT::v2i32,
265 Chain.getValue(1));
266
267 // Extract values from a GPRPair reg and copy to the original GPR reg.
268 SDValue Sub0 = CurDAG->getTargetExtractSubreg(SP::sub_even, dl, MVT::i32,
269 RegCopy);
270 SDValue Sub1 = CurDAG->getTargetExtractSubreg(SP::sub_odd, dl, MVT::i32,
271 RegCopy);
272 SDValue T0 = CurDAG->getCopyToReg(Sub0, dl, Reg0, Sub0,
273 RegCopy.getValue(1));
274 SDValue T1 = CurDAG->getCopyToReg(Sub1, dl, Reg1, Sub1, T0.getValue(1));
275
276 // Update the original glue user.
277 std::vector<SDValue> Ops(GU->op_begin(), GU->op_end()-1);
278 Ops.push_back(T1.getValue(1));
279 CurDAG->UpdateNodeOperands(GU, Ops);
280 } else {
281 // For Kind == InlineAsm::Kind::RegUse, we first copy two GPRs into a
282 // GPRPair and then pass the GPRPair to the inline asm.
283 SDValue Chain = AsmNodeOperands[InlineAsm::Op_InputChain];
284
285 // As REG_SEQ doesn't take RegisterSDNode, we copy them first.
286 SDValue T0 = CurDAG->getCopyFromReg(Chain, dl, Reg0, MVT::i32,
287 Chain.getValue(1));
288 SDValue T1 = CurDAG->getCopyFromReg(Chain, dl, Reg1, MVT::i32,
289 T0.getValue(1));
290 SDValue Pair = SDValue(
291 CurDAG->getMachineNode(
292 TargetOpcode::REG_SEQUENCE, dl, MVT::v2i32,
293 {
294 CurDAG->getTargetConstant(SP::IntPairRegClassID, dl,
295 MVT::i32),
296 T0,
297 CurDAG->getTargetConstant(SP::sub_even, dl, MVT::i32),
298 T1,
299 CurDAG->getTargetConstant(SP::sub_odd, dl, MVT::i32),
300 }),
301 0);
302
303 // Copy REG_SEQ into a GPRPair-typed VR and replace the original two
304 // i32 VRs of inline asm with it.
305 Register GPVR = MRI.createVirtualRegister(&SP::IntPairRegClass);
306 PairedReg = CurDAG->getRegister(GPVR, MVT::v2i32);
307 Chain = CurDAG->getCopyToReg(T1, dl, GPVR, Pair, T1.getValue(1));
308
309 AsmNodeOperands[InlineAsm::Op_InputChain] = Chain;
310 Glue = Chain.getValue(1);
311 }
312
313 Changed = true;
314
315 if(PairedReg.getNode()) {
316 OpChanged[OpChanged.size() -1 ] = true;
317 Flag = InlineAsm::Flag(Flag.getKind(), 1 /* RegNum*/);
318 if (IsTiedToChangedOp)
319 Flag.setMatchingOp(DefIdx);
320 else
321 Flag.setRegClass(SP::IntPairRegClassID);
322 // Replace the current flag.
323 AsmNodeOperands[AsmNodeOperands.size() -1] = CurDAG->getTargetConstant(
324 Flag, dl, MVT::i32);
325 // Add the new register node and skip the original two GPRs.
326 AsmNodeOperands.push_back(PairedReg);
327 // Skip the next two GPRs.
328 i += 2;
329 }
330 }
331
332 if (Glue.getNode())
333 AsmNodeOperands.push_back(Glue);
334 if (!Changed)
335 return false;
336
337 SelectInlineAsmMemoryOperands(AsmNodeOperands, SDLoc(N));
338
339 SDValue New = CurDAG->getNode(N->getOpcode(), SDLoc(N),
340 CurDAG->getVTList(MVT::Other, MVT::Glue), AsmNodeOperands);
341 New->setNodeId(-1);
342 ReplaceNode(N, New.getNode());
343 return true;
344}
345
346void SparcDAGToDAGISel::Select(SDNode *N) {
347 SDLoc dl(N);
348 if (N->isMachineOpcode()) {
349 N->setNodeId(-1);
350 return; // Already selected.
351 }
352
353 switch (N->getOpcode()) {
354 default: break;
355 case ISD::INLINEASM:
356 case ISD::INLINEASM_BR: {
357 if (tryInlineAsm(N))
358 return;
359 break;
360 }
361 case SPISD::GLOBAL_BASE_REG:
362 ReplaceNode(N, getGlobalBaseReg());
363 return;
364
365 case ISD::SDIV:
366 case ISD::UDIV: {
367 // sdivx / udivx handle 64-bit divides.
368 if (N->getValueType(0) == MVT::i64)
369 break;
370 // FIXME: should use a custom expander to expose the SRA to the dag.
371 SDValue DivLHS = N->getOperand(0);
372 SDValue DivRHS = N->getOperand(1);
373
374 // Set the Y register to the high-part.
375 SDValue TopPart;
376 if (N->getOpcode() == ISD::SDIV) {
377 TopPart = SDValue(CurDAG->getMachineNode(SP::SRAri, dl, MVT::i32, DivLHS,
378 CurDAG->getTargetConstant(31, dl, MVT::i32)),
379 0);
380 } else {
381 TopPart = CurDAG->getRegister(SP::G0, MVT::i32);
382 }
383 TopPart = CurDAG->getCopyToReg(CurDAG->getEntryNode(), dl, SP::Y, TopPart,
384 SDValue())
385 .getValue(1);
386
387 // FIXME: Handle div by immediate.
388 unsigned Opcode = N->getOpcode() == ISD::SDIV ? SP::SDIVrr : SP::UDIVrr;
389 CurDAG->SelectNodeTo(N, Opcode, MVT::i32, DivLHS, DivRHS, TopPart);
390 return;
391 }
392 }
393
394 SelectCode(N);
395}
396
397
398/// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
399/// inline asm expressions.
400bool SparcDAGToDAGISel::SelectInlineAsmMemoryOperand(
401 const SDValue &Op, InlineAsm::ConstraintCode ConstraintID,
402 std::vector<SDValue> &OutOps) {
403 SDValue Op0, Op1;
404 switch (ConstraintID) {
405 default: return true;
406 case InlineAsm::ConstraintCode::o:
407 case InlineAsm::ConstraintCode::m: // memory
408 if (!SelectADDRrr(Op, Op0, Op1))
409 SelectADDRri(Op, Op0, Op1);
410 break;
411 }
412
413 OutOps.push_back(Op0);
414 OutOps.push_back(Op1);
415 return false;
416}
417
419 CodeGenOptLevel OptLevel)
420 : SelectionDAGISelPass(std::make_unique<SparcDAGToDAGISel>(TM, OptLevel)) {}
421
422/// createSparcISelDag - This pass converts a legalized DAG into a
423/// SPARC-specific DAG, ready for instruction scheduling.
424///
427 CodeGenOptLevel OptLevel) {
428 return new SparcDAGToDAGISelLegacy(TM, OptLevel);
429}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU Register Bank Select
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
#define DEBUG_TYPE
#define op(i)
const size_t AbstractManglingParser< Derived, Alloc >::NumOps
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
#define R2(n)
Promote Memory to Register
Definition Mem2Reg.cpp:110
#define T1
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
MachineRegisterInfo & MRI
#define PASS_NAME
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:312
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
Wrapper class representing virtual and physical registers.
Definition Register.h:20
Represents one node in the SelectionDAG.
op_iterator op_end() const
op_iterator op_begin() const
Unlike LLVM values, Selection DAG nodes may return multiple values as the result of a computation.
SDNode * getNode() const
get the SDNode which holds the desired result
SDValue getValue(unsigned R) const
const SDValue & getOperand(unsigned i) const
unsigned getOpcode() const
SelectionDAGISelPass(std::unique_ptr< SelectionDAGISel > Selector)
SelectionDAGISel - This is the common base class used for SelectionDAG-based pattern-matching instruc...
virtual bool runOnMachineFunction(MachineFunction &mf)
void push_back(const T &Elt)
SparcDAGToDAGISelPass(SparcTargetMachine &TM, CodeGenOptLevel OptLevel)
@ ADD
Simple integer binary arithmetic operators.
Definition ISDOpcodes.h:266
@ TargetExternalSymbol
Definition ISDOpcodes.h:192
@ TargetGlobalAddress
TargetGlobalAddress - Like GlobalAddress, but the DAG does no folding or anything else with this node...
Definition ISDOpcodes.h:187
@ INLINEASM_BR
INLINEASM_BR - Branching version of inline asm. Used by asm-goto.
@ INLINEASM
INLINEASM - Represents an inline asm block.
@ TargetGlobalTLSAddress
Definition ISDOpcodes.h:188
Flag
These should be considered private to the implementation of the MCInstrDesc class.
@ GlobalBaseReg
The result of the mflr at function entry, used for PIC code.
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:577
constexpr bool isInt(int64_t x)
Checks if an integer fits into the given bit width.
Definition MathExtras.h:166
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
CodeGenOptLevel
Code generation optimization level.
Definition CodeGen.h:280
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
DWARFExpression::Operation Op
FunctionPass * createSparcDAGToDAGISelLegacyPass(SparcTargetMachine &TM, CodeGenOptLevel OptLevel)
createSparcISelDag - This pass converts a legalized DAG into a SPARC-specific DAG,...
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:878
#define N