22#define DEBUG_TYPE "avr-isel"
23#define PASS_NAME "AVR DAG->DAG Instruction Selection"
34 AVRDAGToDAGISel() =
delete;
43 bool selectIndexedLoad(
SDNode *
N);
44 unsigned selectIndexedProgMemLoad(
const LoadSDNode *LD,
MVT VT,
int Bank);
48 std::vector<SDValue> &OutOps)
override;
51#include "AVRGenDAGISel.inc"
57 template <
unsigned NodeType>
bool select(
SDNode *
N);
58 bool selectMultiplication(
SDNode *
N);
65char AVRDAGToDAGISel::ID = 0;
77 auto DL = CurDAG->getDataLayout();
78 MVT PtrVT = getTargetLowering()->getPointerTy(
DL);
82 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), PtrVT);
83 Disp = CurDAG->getTargetConstant(0, dl, MVT::i8);
90 !CurDAG->isBaseWithConstantOffset(
N)) {
94 if (
const ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(
N.getOperand(1))) {
95 int RHSC = (int)
RHS->getZExtValue();
107 int FI = cast<FrameIndexSDNode>(
N.getOperand(0))->getIndex();
109 Base = CurDAG->getTargetFrameIndex(FI, PtrVT);
110 Disp = CurDAG->getTargetConstant(RHSC, dl, MVT::i16);
117 MVT VT = cast<MemSDNode>(
Op)->getMemoryVT().getSimpleVT();
120 if (isUInt<6>(RHSC) && (VT == MVT::i8 || VT == MVT::i16)) {
121 Base =
N.getOperand(0);
122 Disp = CurDAG->getTargetConstant(RHSC, dl, MVT::i8);
131bool AVRDAGToDAGISel::selectIndexedLoad(
SDNode *
N) {
134 MVT VT =
LD->getMemoryVT().getSimpleVT();
135 auto PtrVT = getTargetLowering()->getPointerTy(CurDAG->getDataLayout());
146 int Offs = cast<ConstantSDNode>(
LD->getOffset())->getSExtValue();
150 if ((!isPre && Offs != 1) || (isPre && Offs != -1)) {
154 Opcode = (isPre) ? AVR::LDRdPtrPd : AVR::LDRdPtrPi;
158 if ((!isPre && Offs != 2) || (isPre && Offs != -2)) {
162 Opcode = (isPre) ? AVR::LDWRdPtrPd : AVR::LDWRdPtrPi;
170 CurDAG->getMachineNode(
Opcode,
SDLoc(
N), VT, PtrVT, MVT::Other,
171 LD->getBasePtr(),
LD->getChain());
172 ReplaceUses(
N, ResNode);
173 CurDAG->RemoveDeadNode(
N);
178unsigned AVRDAGToDAGISel::selectIndexedProgMemLoad(
const LoadSDNode *LD,
MVT VT,
186 assert((Bank == 0 || Subtarget->hasELPM()) &&
187 "cannot load from extended program memory on this mcu");
190 int Offs = cast<ConstantSDNode>(
LD->getOffset())->getSExtValue();
192 if (VT.
SimpleTy == MVT::i8 && Offs == 1 && Bank == 0)
203bool AVRDAGToDAGISel::SelectInlineAsmMemoryOperand(
205 std::vector<SDValue> &OutOps) {
206 assert((ConstraintCode == InlineAsm::ConstraintCode::m ||
207 ConstraintCode == InlineAsm::ConstraintCode::Q) &&
208 "Unexpected asm memory constraint");
214 auto DL = CurDAG->getDataLayout();
221 OutOps.push_back(
Op);
228 if (SelectAddr(
Op.getNode(),
Op,
Base, Disp)) {
229 OutOps.push_back(
Base);
230 OutOps.push_back(Disp);
241 SDValue CopyFromRegOp =
Op->getOperand(0);
250 cast<RegisterSDNode>(CopyFromRegOp->
getOperand(1));
253 AVR::PTRDISPREGSRegClass.contains(Reg));
255 CanHandleRegImmOpt =
false;
260 if (CanHandleRegImmOpt) {
263 if (RI.
getRegClass(Reg) != &AVR::PTRDISPREGSRegClass) {
264 SDLoc dl(CopyFromRegOp);
269 CurDAG->getCopyToReg(CopyFromRegOp, dl, VReg, CopyFromRegOp);
272 CurDAG->getCopyFromReg(CopyToReg, dl, VReg, TL.getPointerTy(
DL));
274 Base = NewCopyFromRegOp;
276 Base = CopyFromRegOp;
280 Disp = CurDAG->getTargetConstant(ImmNode->
getZExtValue(), dl, MVT::i8);
285 OutOps.push_back(
Base);
286 OutOps.push_back(Disp);
299 CurDAG->getCopyFromReg(CopyToReg, dl, VReg, TL.getPointerTy(
DL));
301 OutOps.push_back(CopyFromReg);
306template <>
bool AVRDAGToDAGISel::select<ISD::FrameIndex>(
SDNode *
N) {
307 auto DL = CurDAG->getDataLayout();
311 int FI = cast<FrameIndexSDNode>(
N)->getIndex();
313 CurDAG->getTargetFrameIndex(FI, getTargetLowering()->getPointerTy(
DL));
315 CurDAG->SelectNodeTo(
N, AVR::FRMIDX, getTargetLowering()->getPointerTy(
DL),
316 TFI, CurDAG->getTargetConstant(0,
SDLoc(
N), MVT::i16));
320template <>
bool AVRDAGToDAGISel::select<ISD::STORE>(
SDNode *
N) {
324 SDValue BasePtr = ST->getBasePtr();
327 if (isa<FrameIndexSDNode>(BasePtr) || isa<ConstantSDNode>(BasePtr) ||
332 const RegisterSDNode *RN = dyn_cast<RegisterSDNode>(BasePtr.getOperand(0));
334 if (!RN || (RN->getReg() != AVR::SP)) {
338 int CST = (int)cast<ConstantSDNode>(BasePtr.getOperand(1))->getZExtValue();
339 SDValue Chain = ST->getChain();
340 EVT VT = ST->getValue().getValueType();
343 SDValue Ops[] = {BasePtr.getOperand(0),
Offset, ST->getValue(), Chain};
344 unsigned Opc = (VT == MVT::i16) ? AVR::STDWSPQRr : AVR::STDSPQRr;
346 SDNode *ResNode = CurDAG->getMachineNode(Opc,
DL, MVT::Other, Ops);
349 CurDAG->setNodeMemRefs(cast<MachineSDNode>(ResNode), {ST->getMemOperand()});
352 CurDAG->RemoveDeadNode(
N);
357template <>
bool AVRDAGToDAGISel::select<ISD::LOAD>(
SDNode *
N) {
361 return selectIndexedLoad(
N);
364 if (!Subtarget->hasLPM())
368 if (ProgMemBank < 0 || ProgMemBank > 5)
370 if (ProgMemBank > 0 && !Subtarget->hasELPM())
375 MVT VT = LD->getMemoryVT().getSimpleVT();
376 SDValue Chain = LD->getChain();
381 Chain = CurDAG->getCopyToReg(Chain,
DL, AVR::R31R30,
Ptr,
SDValue());
382 Ptr = CurDAG->getCopyFromReg(Chain,
DL, AVR::R31R30, MVT::i16,
386 if (
unsigned LPMOpc = selectIndexedProgMemLoad(LD, VT, ProgMemBank)) {
388 if (ProgMemBank == 0) {
390 CurDAG->getMachineNode(LPMOpc,
DL, VT, MVT::i16, MVT::Other,
Ptr);
394 SDValue NC = CurDAG->getTargetConstant(ProgMemBank,
DL, MVT::i8);
395 auto *NP = CurDAG->getMachineNode(AVR::LDIRdK,
DL, MVT::i8,
NC);
396 ResNode = CurDAG->getMachineNode(LPMOpc,
DL, VT, MVT::i16, MVT::Other,
403 if (ProgMemBank == 0) {
404 unsigned Opc = Subtarget->hasLPMX() ? AVR::LPMRdZ : AVR::LPMBRdZ;
406 CurDAG->getMachineNode(Opc,
DL, MVT::i8, MVT::Other,
Ptr);
410 SDValue NC = CurDAG->getTargetConstant(ProgMemBank,
DL, MVT::i8);
411 auto *NP = CurDAG->getMachineNode(AVR::LDIRdK,
DL, MVT::i8,
NC);
412 ResNode = CurDAG->getMachineNode(AVR::ELPMBRdZ,
DL, MVT::i8, MVT::Other,
417 if (ProgMemBank == 0) {
419 CurDAG->getMachineNode(AVR::LPMWRdZ,
DL, MVT::i16, MVT::Other,
Ptr);
423 SDValue NC = CurDAG->getTargetConstant(ProgMemBank,
DL, MVT::i8);
424 auto *NP = CurDAG->getMachineNode(AVR::LDIRdK,
DL, MVT::i8,
NC);
425 ResNode = CurDAG->getMachineNode(AVR::ELPMWRdZ,
DL, MVT::i16,
435 CurDAG->setNodeMemRefs(cast<MachineSDNode>(ResNode), {LD->getMemOperand()});
439 CurDAG->RemoveDeadNode(
N);
444template <>
bool AVRDAGToDAGISel::select<AVRISD::CALL>(
SDNode *
N) {
448 unsigned LastOpNum =
N->getNumOperands() - 1;
451 unsigned Op = Callee.getOpcode();
457 if (
N->getOperand(LastOpNum).getValueType() == MVT::Glue) {
462 Chain = CurDAG->getCopyToReg(Chain,
DL, AVR::R31R30, Callee, InGlue);
464 Ops.
push_back(CurDAG->getRegister(AVR::R31R30, MVT::i16));
467 for (
unsigned i = 2, e = LastOpNum + 1; i != e; ++i) {
474 SDNode *ResNode = CurDAG->getMachineNode(
475 Subtarget->hasEIJMPCALL() ? AVR::EICALL : AVR::ICALL,
DL, MVT::Other,
480 CurDAG->RemoveDeadNode(
N);
485template <>
bool AVRDAGToDAGISel::select<ISD::BRIND>(
SDNode *
N) {
491 Chain = CurDAG->getCopyToReg(Chain,
DL, AVR::R31R30, JmpAddr);
492 SDNode *ResNode = CurDAG->getMachineNode(AVR::IJMP,
DL, MVT::Other, Chain);
495 CurDAG->RemoveDeadNode(
N);
502 MVT Type =
N->getSimpleValueType(0);
504 assert(
Type == MVT::i8 &&
"unexpected value type");
507 unsigned MachineOp =
isSigned ? AVR::MULSRdRr : AVR::MULRdRr;
511 SDNode *
Mul = CurDAG->getMachineNode(MachineOp,
DL, MVT::Glue, Lhs, Rhs);
512 SDValue InChain = CurDAG->getEntryNode();
516 if (
N->hasAnyUseOfValue(0)) {
518 CurDAG->getCopyFromReg(InChain,
DL, AVR::R0,
Type, InGlue);
520 ReplaceUses(
SDValue(
N, 0), CopyFromLo);
527 if (
N->hasAnyUseOfValue(1)) {
529 CurDAG->getCopyFromReg(InChain,
DL, AVR::R1,
Type, InGlue);
531 ReplaceUses(
SDValue(
N, 1), CopyFromHi);
537 CurDAG->RemoveDeadNode(
N);
545void AVRDAGToDAGISel::Select(
SDNode *
N) {
547 if (
N->isMachineOpcode()) {
561bool AVRDAGToDAGISel::trySelect(
SDNode *
N) {
562 unsigned Opcode =
N->getOpcode();
573 return selectMultiplication(
N);
589 return new AVRDAGToDAGISel(
TM, OptLevel);
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
amdgpu AMDGPU Register Bank Select
bool AVRDAGToDAGISel::select< ISD::LOAD >(SDNode *N)
bool AVRDAGToDAGISel::select< ISD::FrameIndex >(SDNode *N)
bool AVRDAGToDAGISel::select< ISD::BRIND >(SDNode *N)
bool AVRDAGToDAGISel::select< AVRISD::CALL >(SDNode *N)
bool AVRDAGToDAGISel::select< ISD::STORE >(SDNode *N)
static bool isSigned(unsigned int Opcode)
const char LLVMTargetMachineRef TM
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static constexpr uint32_t Opcode
bool ult(const APInt &RHS) const
Unsigned less than comparison.
A specific AVR target MCU.
const AVRTargetLowering * getTargetLowering() const override
A generic AVR implementation.
uint64_t getZExtValue() const
const APInt & getAPIntValue() const
This class represents an Operation in the Expression.
FunctionPass class - This class is used to implement most global optimizations.
This class is used to represent ISD::LOAD nodes.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
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.
static constexpr bool isVirtualRegister(unsigned Reg)
Return true if the specified register number is in the virtual register namespace.
Wrapper class for IR location info (IR ordering and DebugLoc) to be passed into SDNode creation funct...
Represents one node in the SelectionDAG.
unsigned getOpcode() const
Return the SelectionDAG opcode value for this node.
const SDValue & getOperand(unsigned Num) const
EVT getValueType(unsigned ResNo) const
Return the type of a specified result.
Unlike LLVM values, Selection DAG nodes may return multiple values as the result of a computation.
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,...
bool runOnMachineFunction(MachineFunction &MF) override
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
This class is used to represent ISD::STORE nodes.
This class defines information used to lower LLVM code to legal SelectionDAG operators that the targe...
The instances of the Type class are immutable: once they are created, they are never changed.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ CALL
Represents an abstract call instruction, which includes a bunch of information.
bool isProgramMemoryAccess(MemSDNode const *N)
int getProgramMemoryBank(MemSDNode const *N)
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ SMUL_LOHI
SMUL_LOHI/UMUL_LOHI - Multiply two integers of type iN, producing a signed/unsigned value of type i[2...
@ ADD
Simple integer binary arithmetic operators.
@ LOAD
LOAD and STORE have token chains as their first operand, then the same operands as an LLVM load/store...
@ BRIND
BRIND - Indirect branch.
@ CopyFromReg
CopyFromReg - This node indicates that the input value is a virtual or physical register that is defi...
@ TargetGlobalAddress
TargetGlobalAddress - Like GlobalAddress, but the DAG does no folding or anything else with this node...
@ CopyToReg
CopyToReg - This node has three operands: a chain, a register number to set to this value,...
MemIndexedMode
MemIndexedMode enum - This enum defines the load / store indexed addressing modes.
Reg
All possible values of the reg field in the ModR/M byte.
This is an optimization pass for GlobalISel generic memory operations.
FunctionPass * createAVRISelDag(AVRTargetMachine &TM, CodeGenOptLevel OptLevel)
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
CodeGenOptLevel
Code generation optimization level.
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.