1 //===-- SparcISelDAGToDAG.cpp - A dag to dag inst selector for Sparc ------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file defines an instruction selector for the SPARC target.
12 //===----------------------------------------------------------------------===//
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"
24 //===----------------------------------------------------------------------===//
25 // Instruction Selector Implementation
26 //===----------------------------------------------------------------------===//
28 //===--------------------------------------------------------------------===//
29 /// SparcDAGToDAGISel - SPARC specific code to select SPARC machine
30 /// instructions for SelectionDAG operations.
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;
38 explicit SparcDAGToDAGISel(SparcTargetMachine &tm) : SelectionDAGISel(tm) {}
40 bool runOnMachineFunction(MachineFunction &MF) override {
41 Subtarget = &MF.getSubtarget<SparcSubtarget>();
42 return SelectionDAGISel::runOnMachineFunction(MF);
45 SDNode *Select(SDNode *N) override;
47 // Complex Pattern Selectors.
48 bool SelectADDRrr(SDValue N, SDValue &R1, SDValue &R2);
49 bool SelectADDRri(SDValue N, SDValue &Base, SDValue &Offset);
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;
57 const char *getPassName() const override {
58 return "SPARC DAG->DAG Pattern Instruction Selection";
61 // Include the pieces autogenerated from the target description.
62 #include "SparcGenDAGISel.inc"
65 SDNode* getGlobalBaseReg();
66 SDNode *SelectInlineAsm(SDNode *N);
68 } // end anonymous namespace
70 SDNode* SparcDAGToDAGISel::getGlobalBaseReg() {
71 unsigned GlobalBaseReg = Subtarget->getInstrInfo()->getGlobalBaseReg(MF);
72 return CurDAG->getRegister(GlobalBaseReg,
73 TLI->getPointerTy(CurDAG->getDataLayout()))
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);
85 if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
86 Addr.getOpcode() == ISD::TargetGlobalAddress ||
87 Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
88 return false; // direct calls.
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()));
99 Base = Addr.getOperand(0);
101 Offset = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr),
106 if (Addr.getOperand(0).getOpcode() == SPISD::Lo) {
107 Base = Addr.getOperand(1);
108 Offset = Addr.getOperand(0).getOperand(0);
111 if (Addr.getOperand(1).getOpcode() == SPISD::Lo) {
112 Base = Addr.getOperand(0);
113 Offset = Addr.getOperand(1).getOperand(0);
118 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
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.
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);
142 R2 = CurDAG->getRegister(SP::G0, TLI->getPointerTy(CurDAG->getDataLayout()));
147 // Re-assemble i64 arguments split up in SelectionDAGBuilder's
148 // visitInlineAsm / GetRegistersForValue functions.
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.
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.
158 SDNode *SparcDAGToDAGISel::SelectInlineAsm(SDNode *N){
159 std::vector<SDValue> AsmNodeOperands;
161 bool Changed = false;
162 unsigned NumOps = N->getNumOperands();
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.
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
173 SDValue Glue = N->getGluedNode() ? N->getOperand(NumOps-1)
174 : SDValue(nullptr,0);
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);
182 if (i < InlineAsm::Op_FirstOperand)
185 if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(N->getOperand(i))) {
186 Flag = C->getZExtValue();
187 Kind = InlineAsm::getKind(Flag);
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);
202 unsigned NumRegs = InlineAsm::getNumOperandRegisters(Flag);
204 OpChanged.push_back(false);
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];
213 if (Kind != InlineAsm::Kind_RegUse && Kind != InlineAsm::Kind_RegDef
214 && Kind != InlineAsm::Kind_RegDefEarlyClobber)
218 bool HasRC = InlineAsm::hasRegClassConstraint(Flag, RC);
219 if ((!IsTiedToChangedOp && (!HasRC || RC != SP::IntRegsRegClassID))
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();
229 MachineRegisterInfo &MRI = MF->getRegInfo();
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.
236 unsigned GPVR = MRI.createVirtualRegister(&SP::IntPairRegClass);
237 PairedReg = CurDAG->getRegister(GPVR, MVT::v2i32);
238 SDValue Chain = SDValue(N,0);
240 SDNode *GU = N->getGluedUser();
241 SDValue RegCopy = CurDAG->getCopyFromReg(Chain, dl, GPVR, MVT::v2i32,
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,
247 SDValue Sub1 = CurDAG->getTargetExtractSubreg(SP::sub_odd, dl, MVT::i32,
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));
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);
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];
263 // As REG_SEQ doesn't take RegisterSDNode, we copy them first.
264 SDValue T0 = CurDAG->getCopyFromReg(Chain, dl, Reg0, MVT::i32,
266 SDValue T1 = CurDAG->getCopyFromReg(Chain, dl, Reg1, MVT::i32,
268 SDValue Pair = SDValue(
269 CurDAG->getMachineNode(
270 TargetOpcode::REG_SEQUENCE, dl, MVT::v2i32,
272 CurDAG->getTargetConstant(SP::IntPairRegClassID, dl,
275 CurDAG->getTargetConstant(SP::sub_even, dl, MVT::i32),
277 CurDAG->getTargetConstant(SP::sub_odd, dl, MVT::i32),
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));
287 AsmNodeOperands[InlineAsm::Op_InputChain] = Chain;
288 Glue = Chain.getValue(1);
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);
299 Flag = InlineAsm::getFlagWordForRegClass(Flag, SP::IntPairRegClassID);
300 // Replace the current flag.
301 AsmNodeOperands[AsmNodeOperands.size() -1] = CurDAG->getTargetConstant(
303 // Add the new register node and skip the original two GPRs.
304 AsmNodeOperands.push_back(PairedReg);
305 // Skip the next two GPRs.
311 AsmNodeOperands.push_back(Glue);
315 SDValue New = CurDAG->getNode(ISD::INLINEASM, SDLoc(N),
316 CurDAG->getVTList(MVT::Other, MVT::Glue), AsmNodeOperands);
318 return New.getNode();
321 SDNode *SparcDAGToDAGISel::Select(SDNode *N) {
323 if (N->isMachineOpcode()) {
325 return nullptr; // Already selected.
328 switch (N->getOpcode()) {
330 case ISD::INLINEASM: {
331 SDNode *ResNode = SelectInlineAsm(N);
336 case SPISD::GLOBAL_BASE_REG:
337 return getGlobalBaseReg();
341 // sdivx / udivx handle 64-bit divides.
342 if (N->getValueType(0) == MVT::i64)
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);
348 // Set the Y register to the high-part.
350 if (N->getOpcode() == ISD::SDIV) {
351 TopPart = SDValue(CurDAG->getMachineNode(SP::SRAri, dl, MVT::i32, DivLHS,
352 CurDAG->getTargetConstant(31, dl, MVT::i32)),
355 TopPart = CurDAG->getRegister(SP::G0, MVT::i32);
357 TopPart = CurDAG->getCopyToReg(CurDAG->getEntryNode(), dl, SP::Y, TopPart,
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,
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;
373 CurDAG->getMachineNode(Opcode, dl, MVT::i32, MVT::i32, MulLHS, MulRHS);
374 SDValue ResultHigh = SDValue(Mul, 1);
375 ReplaceUses(SDValue(N, 0), ResultHigh);
380 return SelectCode(N);
384 /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
385 /// inline asm expressions.
387 SparcDAGToDAGISel::SelectInlineAsmMemoryOperand(const SDValue &Op,
388 unsigned ConstraintID,
389 std::vector<SDValue> &OutOps) {
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);
400 OutOps.push_back(Op0);
401 OutOps.push_back(Op1);
405 /// createSparcISelDag - This pass converts a legalized DAG into a
406 /// SPARC-specific DAG, ready for instruction scheduling.
408 FunctionPass *llvm::createSparcISelDag(SparcTargetMachine &TM) {
409 return new SparcDAGToDAGISel(TM);