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