1 //===-- SparcISelDAGToDAG.cpp - A dag to dag inst selector for Sparc ------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file defines an instruction selector for the SPARC target.
11 //===----------------------------------------------------------------------===//
13 #include "SparcTargetMachine.h"
14 #include "llvm/CodeGen/MachineRegisterInfo.h"
15 #include "llvm/CodeGen/SelectionDAGISel.h"
16 #include "llvm/IR/Intrinsics.h"
17 #include "llvm/Support/Debug.h"
18 #include "llvm/Support/ErrorHandling.h"
19 #include "llvm/Support/raw_ostream.h"
22 //===----------------------------------------------------------------------===//
23 // Instruction Selector Implementation
24 //===----------------------------------------------------------------------===//
26 //===--------------------------------------------------------------------===//
27 /// SparcDAGToDAGISel - SPARC specific code to select SPARC machine
28 /// instructions for SelectionDAG operations.
31 class SparcDAGToDAGISel
: public SelectionDAGISel
{
32 /// Subtarget - Keep a pointer to the Sparc Subtarget around so that we can
33 /// make the right decision when generating code for different targets.
34 const SparcSubtarget
*Subtarget
;
36 explicit SparcDAGToDAGISel(SparcTargetMachine
&tm
) : SelectionDAGISel(tm
) {}
38 bool runOnMachineFunction(MachineFunction
&MF
) override
{
39 Subtarget
= &MF
.getSubtarget
<SparcSubtarget
>();
40 return SelectionDAGISel::runOnMachineFunction(MF
);
43 void Select(SDNode
*N
) override
;
45 // Complex Pattern Selectors.
46 bool SelectADDRrr(SDValue N
, SDValue
&R1
, SDValue
&R2
);
47 bool SelectADDRri(SDValue N
, SDValue
&Base
, SDValue
&Offset
);
49 /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
50 /// inline asm expressions.
51 bool SelectInlineAsmMemoryOperand(const SDValue
&Op
,
52 unsigned ConstraintID
,
53 std::vector
<SDValue
> &OutOps
) override
;
55 StringRef
getPassName() const override
{
56 return "SPARC DAG->DAG Pattern Instruction Selection";
59 // Include the pieces autogenerated from the target description.
60 #include "SparcGenDAGISel.inc"
63 SDNode
* getGlobalBaseReg();
64 bool tryInlineAsm(SDNode
*N
);
66 } // end anonymous namespace
68 SDNode
* SparcDAGToDAGISel::getGlobalBaseReg() {
69 unsigned GlobalBaseReg
= Subtarget
->getInstrInfo()->getGlobalBaseReg(MF
);
70 return CurDAG
->getRegister(GlobalBaseReg
,
71 TLI
->getPointerTy(CurDAG
->getDataLayout()))
75 bool SparcDAGToDAGISel::SelectADDRri(SDValue Addr
,
76 SDValue
&Base
, SDValue
&Offset
) {
77 if (FrameIndexSDNode
*FIN
= dyn_cast
<FrameIndexSDNode
>(Addr
)) {
78 Base
= CurDAG
->getTargetFrameIndex(
79 FIN
->getIndex(), TLI
->getPointerTy(CurDAG
->getDataLayout()));
80 Offset
= CurDAG
->getTargetConstant(0, SDLoc(Addr
), MVT::i32
);
83 if (Addr
.getOpcode() == ISD::TargetExternalSymbol
||
84 Addr
.getOpcode() == ISD::TargetGlobalAddress
||
85 Addr
.getOpcode() == ISD::TargetGlobalTLSAddress
)
86 return false; // direct calls.
88 if (Addr
.getOpcode() == ISD::ADD
) {
89 if (ConstantSDNode
*CN
= dyn_cast
<ConstantSDNode
>(Addr
.getOperand(1))) {
90 if (isInt
<13>(CN
->getSExtValue())) {
91 if (FrameIndexSDNode
*FIN
=
92 dyn_cast
<FrameIndexSDNode
>(Addr
.getOperand(0))) {
93 // Constant offset from frame ref.
94 Base
= CurDAG
->getTargetFrameIndex(
95 FIN
->getIndex(), TLI
->getPointerTy(CurDAG
->getDataLayout()));
97 Base
= Addr
.getOperand(0);
99 Offset
= CurDAG
->getTargetConstant(CN
->getZExtValue(), SDLoc(Addr
),
104 if (Addr
.getOperand(0).getOpcode() == SPISD::Lo
) {
105 Base
= Addr
.getOperand(1);
106 Offset
= Addr
.getOperand(0).getOperand(0);
109 if (Addr
.getOperand(1).getOpcode() == SPISD::Lo
) {
110 Base
= Addr
.getOperand(0);
111 Offset
= Addr
.getOperand(1).getOperand(0);
116 Offset
= CurDAG
->getTargetConstant(0, SDLoc(Addr
), MVT::i32
);
120 bool SparcDAGToDAGISel::SelectADDRrr(SDValue Addr
, SDValue
&R1
, SDValue
&R2
) {
121 if (Addr
.getOpcode() == ISD::FrameIndex
) return false;
122 if (Addr
.getOpcode() == ISD::TargetExternalSymbol
||
123 Addr
.getOpcode() == ISD::TargetGlobalAddress
||
124 Addr
.getOpcode() == ISD::TargetGlobalTLSAddress
)
125 return false; // direct calls.
127 if (Addr
.getOpcode() == ISD::ADD
) {
128 if (ConstantSDNode
*CN
= dyn_cast
<ConstantSDNode
>(Addr
.getOperand(1)))
129 if (isInt
<13>(CN
->getSExtValue()))
130 return false; // Let the reg+imm pattern catch this!
131 if (Addr
.getOperand(0).getOpcode() == SPISD::Lo
||
132 Addr
.getOperand(1).getOpcode() == SPISD::Lo
)
133 return false; // Let the reg+imm pattern catch this!
134 R1
= Addr
.getOperand(0);
135 R2
= Addr
.getOperand(1);
140 R2
= CurDAG
->getRegister(SP::G0
, TLI
->getPointerTy(CurDAG
->getDataLayout()));
145 // Re-assemble i64 arguments split up in SelectionDAGBuilder's
146 // visitInlineAsm / GetRegistersForValue functions.
148 // Note: This function was copied from, and is essentially identical
149 // to ARMISelDAGToDAG::SelectInlineAsm. It is very unfortunate that
150 // such hacking-up is necessary; a rethink of how inline asm operands
151 // are handled may be in order to make doing this more sane.
153 // TODO: fix inline asm support so I can simply tell it that 'i64'
154 // inputs to asm need to be allocated to the IntPair register type,
155 // and have that work. Then, delete this function.
156 bool SparcDAGToDAGISel::tryInlineAsm(SDNode
*N
){
157 std::vector
<SDValue
> AsmNodeOperands
;
159 bool Changed
= false;
160 unsigned NumOps
= N
->getNumOperands();
162 // Normally, i64 data is bounded to two arbitrary GPRs for "%r"
163 // constraint. However, some instructions (e.g. ldd/std) require
164 // (even/even+1) GPRs.
166 // So, here, we check for this case, and mutate the inlineasm to use
167 // a single IntPair register instead, which guarantees such even/odd
171 SDValue Glue
= N
->getGluedNode() ? N
->getOperand(NumOps
-1)
172 : SDValue(nullptr,0);
174 SmallVector
<bool, 8> OpChanged
;
175 // Glue node will be appended late.
176 for(unsigned i
= 0, e
= N
->getGluedNode() ? NumOps
- 1 : NumOps
; i
< e
; ++i
) {
177 SDValue op
= N
->getOperand(i
);
178 AsmNodeOperands
.push_back(op
);
180 if (i
< InlineAsm::Op_FirstOperand
)
183 if (ConstantSDNode
*C
= dyn_cast
<ConstantSDNode
>(N
->getOperand(i
))) {
184 Flag
= C
->getZExtValue();
185 Kind
= InlineAsm::getKind(Flag
);
190 // Immediate operands to inline asm in the SelectionDAG are modeled with
191 // two operands. The first is a constant of value InlineAsm::Kind_Imm, and
192 // the second is a constant with the value of the immediate. If we get here
193 // and we have a Kind_Imm, skip the next operand, and continue.
194 if (Kind
== InlineAsm::Kind_Imm
) {
195 SDValue op
= N
->getOperand(++i
);
196 AsmNodeOperands
.push_back(op
);
200 unsigned NumRegs
= InlineAsm::getNumOperandRegisters(Flag
);
202 OpChanged
.push_back(false);
205 bool IsTiedToChangedOp
= false;
206 // If it's a use that is tied with a previous def, it has no
207 // reg class constraint.
208 if (Changed
&& InlineAsm::isUseOperandTiedToDef(Flag
, DefIdx
))
209 IsTiedToChangedOp
= OpChanged
[DefIdx
];
211 if (Kind
!= InlineAsm::Kind_RegUse
&& Kind
!= InlineAsm::Kind_RegDef
212 && Kind
!= InlineAsm::Kind_RegDefEarlyClobber
)
216 bool HasRC
= InlineAsm::hasRegClassConstraint(Flag
, RC
);
217 if ((!IsTiedToChangedOp
&& (!HasRC
|| RC
!= SP::IntRegsRegClassID
))
221 assert((i
+2 < NumOps
) && "Invalid number of operands in inline asm");
222 SDValue V0
= N
->getOperand(i
+1);
223 SDValue V1
= N
->getOperand(i
+2);
224 unsigned Reg0
= cast
<RegisterSDNode
>(V0
)->getReg();
225 unsigned Reg1
= cast
<RegisterSDNode
>(V1
)->getReg();
227 MachineRegisterInfo
&MRI
= MF
->getRegInfo();
229 if (Kind
== InlineAsm::Kind_RegDef
||
230 Kind
== InlineAsm::Kind_RegDefEarlyClobber
) {
231 // Replace the two GPRs with 1 GPRPair and copy values from GPRPair to
232 // the original GPRs.
234 Register GPVR
= MRI
.createVirtualRegister(&SP::IntPairRegClass
);
235 PairedReg
= CurDAG
->getRegister(GPVR
, MVT::v2i32
);
236 SDValue Chain
= SDValue(N
,0);
238 SDNode
*GU
= N
->getGluedUser();
239 SDValue RegCopy
= CurDAG
->getCopyFromReg(Chain
, dl
, GPVR
, MVT::v2i32
,
242 // Extract values from a GPRPair reg and copy to the original GPR reg.
243 SDValue Sub0
= CurDAG
->getTargetExtractSubreg(SP::sub_even
, dl
, MVT::i32
,
245 SDValue Sub1
= CurDAG
->getTargetExtractSubreg(SP::sub_odd
, dl
, MVT::i32
,
247 SDValue T0
= CurDAG
->getCopyToReg(Sub0
, dl
, Reg0
, Sub0
,
248 RegCopy
.getValue(1));
249 SDValue T1
= CurDAG
->getCopyToReg(Sub1
, dl
, Reg1
, Sub1
, T0
.getValue(1));
251 // Update the original glue user.
252 std::vector
<SDValue
> Ops(GU
->op_begin(), GU
->op_end()-1);
253 Ops
.push_back(T1
.getValue(1));
254 CurDAG
->UpdateNodeOperands(GU
, Ops
);
257 // For Kind == InlineAsm::Kind_RegUse, we first copy two GPRs into a
258 // GPRPair and then pass the GPRPair to the inline asm.
259 SDValue Chain
= AsmNodeOperands
[InlineAsm::Op_InputChain
];
261 // As REG_SEQ doesn't take RegisterSDNode, we copy them first.
262 SDValue T0
= CurDAG
->getCopyFromReg(Chain
, dl
, Reg0
, MVT::i32
,
264 SDValue T1
= CurDAG
->getCopyFromReg(Chain
, dl
, Reg1
, MVT::i32
,
266 SDValue Pair
= SDValue(
267 CurDAG
->getMachineNode(
268 TargetOpcode::REG_SEQUENCE
, dl
, MVT::v2i32
,
270 CurDAG
->getTargetConstant(SP::IntPairRegClassID
, dl
,
273 CurDAG
->getTargetConstant(SP::sub_even
, dl
, MVT::i32
),
275 CurDAG
->getTargetConstant(SP::sub_odd
, dl
, MVT::i32
),
279 // Copy REG_SEQ into a GPRPair-typed VR and replace the original two
280 // i32 VRs of inline asm with it.
281 Register GPVR
= MRI
.createVirtualRegister(&SP::IntPairRegClass
);
282 PairedReg
= CurDAG
->getRegister(GPVR
, MVT::v2i32
);
283 Chain
= CurDAG
->getCopyToReg(T1
, dl
, GPVR
, Pair
, T1
.getValue(1));
285 AsmNodeOperands
[InlineAsm::Op_InputChain
] = Chain
;
286 Glue
= Chain
.getValue(1);
291 if(PairedReg
.getNode()) {
292 OpChanged
[OpChanged
.size() -1 ] = true;
293 Flag
= InlineAsm::getFlagWord(Kind
, 1 /* RegNum*/);
294 if (IsTiedToChangedOp
)
295 Flag
= InlineAsm::getFlagWordForMatchingOp(Flag
, DefIdx
);
297 Flag
= InlineAsm::getFlagWordForRegClass(Flag
, SP::IntPairRegClassID
);
298 // Replace the current flag.
299 AsmNodeOperands
[AsmNodeOperands
.size() -1] = CurDAG
->getTargetConstant(
301 // Add the new register node and skip the original two GPRs.
302 AsmNodeOperands
.push_back(PairedReg
);
303 // Skip the next two GPRs.
309 AsmNodeOperands
.push_back(Glue
);
313 SelectInlineAsmMemoryOperands(AsmNodeOperands
, SDLoc(N
));
315 SDValue New
= CurDAG
->getNode(N
->getOpcode(), SDLoc(N
),
316 CurDAG
->getVTList(MVT::Other
, MVT::Glue
), AsmNodeOperands
);
318 ReplaceNode(N
, New
.getNode());
322 void SparcDAGToDAGISel::Select(SDNode
*N
) {
324 if (N
->isMachineOpcode()) {
326 return; // Already selected.
329 switch (N
->getOpcode()) {
332 case ISD::INLINEASM_BR
: {
337 case SPISD::GLOBAL_BASE_REG
:
338 ReplaceNode(N
, getGlobalBaseReg());
343 // sdivx / udivx handle 64-bit divides.
344 if (N
->getValueType(0) == MVT::i64
)
346 // FIXME: should use a custom expander to expose the SRA to the dag.
347 SDValue DivLHS
= N
->getOperand(0);
348 SDValue DivRHS
= N
->getOperand(1);
350 // Set the Y register to the high-part.
352 if (N
->getOpcode() == ISD::SDIV
) {
353 TopPart
= SDValue(CurDAG
->getMachineNode(SP::SRAri
, dl
, MVT::i32
, DivLHS
,
354 CurDAG
->getTargetConstant(31, dl
, MVT::i32
)),
357 TopPart
= CurDAG
->getRegister(SP::G0
, MVT::i32
);
359 TopPart
= CurDAG
->getCopyToReg(CurDAG
->getEntryNode(), dl
, SP::Y
, TopPart
,
363 // FIXME: Handle div by immediate.
364 unsigned Opcode
= N
->getOpcode() == ISD::SDIV
? SP::SDIVrr
: SP::UDIVrr
;
365 CurDAG
->SelectNodeTo(N
, Opcode
, MVT::i32
, DivLHS
, DivRHS
, TopPart
);
374 /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
375 /// inline asm expressions.
377 SparcDAGToDAGISel::SelectInlineAsmMemoryOperand(const SDValue
&Op
,
378 unsigned ConstraintID
,
379 std::vector
<SDValue
> &OutOps
) {
381 switch (ConstraintID
) {
382 default: return true;
383 case InlineAsm::Constraint_i
:
384 case InlineAsm::Constraint_o
:
385 case InlineAsm::Constraint_m
: // memory
386 if (!SelectADDRrr(Op
, Op0
, Op1
))
387 SelectADDRri(Op
, Op0
, Op1
);
391 OutOps
.push_back(Op0
);
392 OutOps
.push_back(Op1
);
396 /// createSparcISelDag - This pass converts a legalized DAG into a
397 /// SPARC-specific DAG, ready for instruction scheduling.
399 FunctionPass
*llvm::createSparcISelDag(SparcTargetMachine
&TM
) {
400 return new SparcDAGToDAGISel(TM
);