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//===----------------------------------------------------------------------===// 19#define DEBUG_TYPE "sparc-isel" 20#define PASS_NAME "SPARC DAG->DAG Pattern Instruction Selection" 22//===----------------------------------------------------------------------===// 23// Instruction Selector Implementation 24//===----------------------------------------------------------------------===// 26//===--------------------------------------------------------------------===// 27/// SparcDAGToDAGISel - SPARC specific code to select SPARC machine 28/// instructions for SelectionDAG operations. 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. 37 SparcDAGToDAGISel() =
delete;
48// Complex Pattern Selectors. 52 /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for 53 /// inline asm expressions. 56 std::vector<SDValue> &OutOps)
override;
58// Include the pieces autogenerated from the target description. 59#include "SparcGenDAGISel.inc" 72}
// end anonymous namespace 74char SparcDAGToDAGISelLegacy::ID = 0;
78SDNode* SparcDAGToDAGISel::getGlobalBaseReg() {
80return CurDAG->getRegister(GlobalBaseReg,
81 TLI->getPointerTy(CurDAG->getDataLayout()))
88Base = CurDAG->getTargetFrameIndex(
89 FIN->getIndex(), TLI->getPointerTy(CurDAG->getDataLayout()));
96returnfalse;
// direct calls. 100if (isInt<13>(CN->getSExtValue())) {
102 dyn_cast<FrameIndexSDNode>(
Addr.getOperand(0))) {
103// Constant offset from frame ref. 104Base = CurDAG->getTargetFrameIndex(
105 FIN->getIndex(), TLI->getPointerTy(CurDAG->getDataLayout()));
109Offset = CurDAG->getSignedTargetConstant(CN->getSExtValue(),
135returnfalse;
// direct calls. 139if (isInt<13>(CN->getSExtValue()))
140returnfalse;
// Let the reg+imm pattern catch this! 143returnfalse;
// Let the reg+imm pattern catch this! 144 R1 =
Addr.getOperand(0);
150R2 = CurDAG->getRegister(SP::G0, TLI->getPointerTy(CurDAG->getDataLayout()));
155// Re-assemble i64 arguments split up in SelectionDAGBuilder's 156// visitInlineAsm / GetRegistersForValue functions. 158// Note: This function was copied from, and is essentially identical 159// to ARMISelDAGToDAG::SelectInlineAsm. It is very unfortunate that 160// such hacking-up is necessary; a rethink of how inline asm operands 161// are handled may be in order to make doing this more sane. 163// TODO: fix inline asm support so I can simply tell it that 'i64' 164// inputs to asm need to be allocated to the IntPair register type, 165// and have that work. Then, delete this function. 166bool SparcDAGToDAGISel::tryInlineAsm(
SDNode *
N){
167 std::vector<SDValue> AsmNodeOperands;
170unsigned NumOps =
N->getNumOperands();
172// Normally, i64 data is bounded to two arbitrary GPRs for "%r" 173// constraint. However, some instructions (e.g. ldd/std) require 174// (even/even+1) GPRs. 176// So, here, we check for this case, and mutate the inlineasm to use 177// a single IntPair register instead, which guarantees such even/odd 184// Glue node will be appended late. 185for(
unsigned i = 0, e =
N->getGluedNode() ? NumOps - 1 : NumOps; i < e; ++i) {
187 AsmNodeOperands.push_back(
op);
192if (
constauto *
C = dyn_cast<ConstantSDNode>(
N->getOperand(i)))
197// Immediate operands to inline asm in the SelectionDAG are modeled with 198// two operands. The first is a constant of value InlineAsm::Kind::Imm, and 199// the second is a constant with the value of the immediate. If we get here 200// and we have a Kind::Imm, skip the next operand, and continue. 201if (
Flag.isImmKind()) {
203 AsmNodeOperands.push_back(
op);
207constunsigned NumRegs =
Flag.getNumOperandRegisters();
212bool IsTiedToChangedOp =
false;
213// If it's a use that is tied with a previous def, it has no 214// reg class constraint. 215if (Changed &&
Flag.isUseOperandTiedToDef(DefIdx))
216 IsTiedToChangedOp = OpChanged[DefIdx];
218if (!
Flag.isRegUseKind() && !
Flag.isRegDefKind() &&
219 !
Flag.isRegDefEarlyClobberKind())
223constbool HasRC =
Flag.hasRegClassConstraint(RC);
224if ((!IsTiedToChangedOp && (!HasRC || RC != SP::IntRegsRegClassID))
228assert((i+2 < NumOps) &&
"Invalid number of operands in inline asm");
231Register Reg0 = cast<RegisterSDNode>(V0)->getReg();
232Register Reg1 = cast<RegisterSDNode>(V1)->getReg();
236if (
Flag.isRegDefKind() ||
Flag.isRegDefEarlyClobberKind()) {
237// Replace the two GPRs with 1 GPRPair and copy values from GPRPair to 240Register GPVR =
MRI.createVirtualRegister(&SP::IntPairRegClass);
241 PairedReg = CurDAG->getRegister(GPVR, MVT::v2i32);
245SDValue RegCopy = CurDAG->getCopyFromReg(Chain, dl, GPVR, MVT::v2i32,
248// Extract values from a GPRPair reg and copy to the original GPR reg. 249SDValue Sub0 = CurDAG->getTargetExtractSubreg(SP::sub_even, dl, MVT::i32,
251SDValue Sub1 = CurDAG->getTargetExtractSubreg(SP::sub_odd, dl, MVT::i32,
253SDValue T0 = CurDAG->getCopyToReg(Sub0, dl, Reg0, Sub0,
257// Update the original glue user. 259 Ops.push_back(
T1.getValue(1));
260 CurDAG->UpdateNodeOperands(GU, Ops);
262// For Kind == InlineAsm::Kind::RegUse, we first copy two GPRs into a 263// GPRPair and then pass the GPRPair to the inline asm. 266// As REG_SEQ doesn't take RegisterSDNode, we copy them first. 267SDValue T0 = CurDAG->getCopyFromReg(Chain, dl, Reg0, MVT::i32,
269SDValueT1 = CurDAG->getCopyFromReg(Chain, dl, Reg1, MVT::i32,
272 CurDAG->getMachineNode(
273 TargetOpcode::REG_SEQUENCE, dl, MVT::v2i32,
275 CurDAG->getTargetConstant(SP::IntPairRegClassID, dl,
278 CurDAG->getTargetConstant(SP::sub_even, dl, MVT::i32),
280 CurDAG->getTargetConstant(SP::sub_odd, dl, MVT::i32),
284// Copy REG_SEQ into a GPRPair-typed VR and replace the original two 285// i32 VRs of inline asm with it. 286Register GPVR =
MRI.createVirtualRegister(&SP::IntPairRegClass);
287 PairedReg = CurDAG->getRegister(GPVR, MVT::v2i32);
288 Chain = CurDAG->getCopyToReg(T1, dl, GPVR, Pair,
T1.getValue(1));
297 OpChanged[OpChanged.
size() -1 ] =
true;
299if (IsTiedToChangedOp)
300Flag.setMatchingOp(DefIdx);
302Flag.setRegClass(SP::IntPairRegClassID);
303// Replace the current flag. 304 AsmNodeOperands[AsmNodeOperands.size() -1] = CurDAG->getTargetConstant(
306// Add the new register node and skip the original two GPRs. 307 AsmNodeOperands.push_back(PairedReg);
308// Skip the next two GPRs. 314 AsmNodeOperands.push_back(Glue);
318 SelectInlineAsmMemoryOperands(AsmNodeOperands,
SDLoc(
N));
321 CurDAG->getVTList(MVT::Other, MVT::Glue), AsmNodeOperands);
323 ReplaceNode(
N,
New.getNode());
327void SparcDAGToDAGISel::Select(
SDNode *
N) {
329if (
N->isMachineOpcode()) {
331return;
// Already selected. 334switch (
N->getOpcode()) {
343 ReplaceNode(
N, getGlobalBaseReg());
348// sdivx / udivx handle 64-bit divides. 349if (
N->getValueType(0) == MVT::i64)
351// FIXME: should use a custom expander to expose the SRA to the dag. 355// Set the Y register to the high-part. 358 TopPart =
SDValue(CurDAG->getMachineNode(SP::SRAri, dl, MVT::i32, DivLHS,
359 CurDAG->getTargetConstant(31, dl, MVT::i32)),
362 TopPart = CurDAG->getRegister(SP::G0, MVT::i32);
364 TopPart = CurDAG->getCopyToReg(CurDAG->getEntryNode(), dl, SP::Y, TopPart,
368// FIXME: Handle div by immediate. 369unsigned Opcode =
N->getOpcode() ==
ISD::SDIV ? SP::SDIVrr : SP::UDIVrr;
370 CurDAG->SelectNodeTo(
N, Opcode, MVT::i32, DivLHS, DivRHS, TopPart);
379/// SelectInlineAsmMemoryOperand - Implement addressing mode selection for 380/// inline asm expressions. 381bool SparcDAGToDAGISel::SelectInlineAsmMemoryOperand(
383 std::vector<SDValue> &OutOps) {
385switch (ConstraintID) {
387case InlineAsm::ConstraintCode::o:
388case InlineAsm::ConstraintCode::m:
// memory 389if (!SelectADDRrr(
Op, Op0, Op1))
390 SelectADDRri(
Op, Op0, Op1);
394 OutOps.push_back(Op0);
395 OutOps.push_back(Op1);
399/// createSparcISelDag - This pass converts a legalized DAG into a 400/// SPARC-specific DAG, ready for instruction scheduling. 403returnnew SparcDAGToDAGISelLegacy(TM);
unsigned const MachineRegisterInfo * MRI
AMDGPU Register Bank Select
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This class represents an Operation in the Expression.
FunctionPass class - This class is used to implement most global optimizations.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
Wrapper class representing virtual and physical registers.
Wrapper class for IR location info (IR ordering and DebugLoc) to be passed into SDNode creation funct...
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
SelectionDAGISel - This is the common base class used for SelectionDAG-based pattern-matching instruc...
virtual bool SelectInlineAsmMemoryOperand(const SDValue &Op, InlineAsm::ConstraintCode ConstraintID, std::vector< SDValue > &OutOps)
SelectInlineAsmMemoryOperand - Select the specified address as a target addressing mode,...
virtual bool runOnMachineFunction(MachineFunction &mf)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
@ C
The default llvm calling convention, compatible with C.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ ADD
Simple integer binary arithmetic operators.
@ TargetGlobalAddress
TargetGlobalAddress - Like GlobalAddress, but the DAG does no folding or anything else with this node...
@ INLINEASM_BR
INLINEASM_BR - Branching version of inline asm. Used by asm-goto.
@ INLINEASM
INLINEASM - Represents an inline asm block.
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.
FunctionPass * createSparcISelDag(SparcTargetMachine &TM)
createSparcISelDag - This pass converts a legalized DAG into a SPARC-specific DAG,...