22#define DEBUG_TYPE "avr-isel"
23#define PASS_NAME "AVR DAG->DAG Instruction Selection"
32 AVRDAGToDAGISel() =
delete;
41 bool selectIndexedLoad(
SDNode *
N);
42 unsigned selectIndexedProgMemLoad(
const LoadSDNode *LD,
MVT VT,
int Bank);
46 std::vector<SDValue> &OutOps)
override;
49#include "AVRGenDAGISel.inc"
55 template <
unsigned NodeType>
bool select(
SDNode *
N);
56 bool selectMultiplication(
SDNode *
N);
66 ID, std::make_unique<AVRDAGToDAGISel>(
TM, OptLevel)) {}
71char AVRDAGToDAGISelLegacy::ID = 0;
83 auto DL = CurDAG->getDataLayout();
84 MVT PtrVT = getTargetLowering()->getPointerTy(
DL);
88 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), PtrVT);
89 Disp = CurDAG->getTargetConstant(0, dl, MVT::i8);
96 !CurDAG->isBaseWithConstantOffset(
N)) {
100 if (
const ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(
N.getOperand(1))) {
101 int RHSC = (int)
RHS->getZExtValue();
113 int FI = cast<FrameIndexSDNode>(
N.getOperand(0))->getIndex();
115 Base = CurDAG->getTargetFrameIndex(FI, PtrVT);
116 Disp = CurDAG->getTargetConstant(RHSC, dl, MVT::i16);
123 MVT VT = cast<MemSDNode>(
Op)->getMemoryVT().getSimpleVT();
126 if (isUInt<6>(RHSC) && (VT == MVT::i8 || VT == MVT::i16)) {
127 Base =
N.getOperand(0);
128 Disp = CurDAG->getTargetConstant(RHSC, dl, MVT::i8);
137bool AVRDAGToDAGISel::selectIndexedLoad(
SDNode *
N) {
140 MVT VT =
LD->getMemoryVT().getSimpleVT();
141 auto PtrVT = getTargetLowering()->getPointerTy(CurDAG->getDataLayout());
152 int Offs = cast<ConstantSDNode>(
LD->getOffset())->getSExtValue();
156 if ((!isPre && Offs != 1) || (isPre && Offs != -1)) {
160 Opcode = (isPre) ? AVR::LDRdPtrPd : AVR::LDRdPtrPi;
164 if ((!isPre && Offs != 2) || (isPre && Offs != -2)) {
168 Opcode = (isPre) ? AVR::LDWRdPtrPd : AVR::LDWRdPtrPi;
176 CurDAG->getMachineNode(Opcode,
SDLoc(
N), VT, PtrVT, MVT::Other,
177 LD->getBasePtr(),
LD->getChain());
178 ReplaceUses(
N, ResNode);
179 CurDAG->RemoveDeadNode(
N);
184unsigned AVRDAGToDAGISel::selectIndexedProgMemLoad(
const LoadSDNode *LD,
MVT VT,
192 assert((Bank == 0 || Subtarget->hasELPM()) &&
193 "cannot load from extended program memory on this mcu");
196 int Offs = cast<ConstantSDNode>(
LD->getOffset())->getSExtValue();
198 if (VT.
SimpleTy == MVT::i8 && Offs == 1 && Bank == 0)
199 Opcode = AVR::LPMRdZPi;
209bool AVRDAGToDAGISel::SelectInlineAsmMemoryOperand(
211 std::vector<SDValue> &OutOps) {
212 assert((ConstraintCode == InlineAsm::ConstraintCode::m ||
213 ConstraintCode == InlineAsm::ConstraintCode::Q) &&
214 "Unexpected asm memory constraint");
220 auto DL = CurDAG->getDataLayout();
227 OutOps.push_back(
Op);
234 if (SelectAddr(
Op.getNode(),
Op,
Base, Disp)) {
235 OutOps.push_back(
Base);
236 OutOps.push_back(Disp);
247 SDValue CopyFromRegOp =
Op->getOperand(0);
256 cast<RegisterSDNode>(CopyFromRegOp->
getOperand(1));
259 AVR::PTRDISPREGSRegClass.contains(Reg));
261 CanHandleRegImmOpt =
false;
266 if (CanHandleRegImmOpt) {
269 if (RI.
getRegClass(Reg) != &AVR::PTRDISPREGSRegClass) {
270 SDLoc dl(CopyFromRegOp);
275 CurDAG->getCopyToReg(CopyFromRegOp, dl, VReg, CopyFromRegOp);
278 CurDAG->getCopyFromReg(CopyToReg, dl, VReg, TL.getPointerTy(
DL));
280 Base = NewCopyFromRegOp;
282 Base = CopyFromRegOp;
286 Disp = CurDAG->getTargetConstant(ImmNode->
getZExtValue(), dl, MVT::i8);
291 OutOps.push_back(
Base);
292 OutOps.push_back(Disp);
305 CurDAG->getCopyFromReg(CopyToReg, dl, VReg, TL.getPointerTy(
DL));
307 OutOps.push_back(CopyFromReg);
312template <>
bool AVRDAGToDAGISel::select<ISD::FrameIndex>(
SDNode *
N) {
313 auto DL = CurDAG->getDataLayout();
317 int FI = cast<FrameIndexSDNode>(
N)->getIndex();
319 CurDAG->getTargetFrameIndex(FI, getTargetLowering()->getPointerTy(
DL));
321 CurDAG->SelectNodeTo(
N, AVR::FRMIDX, getTargetLowering()->getPointerTy(
DL),
322 TFI, CurDAG->getTargetConstant(0,
SDLoc(
N), MVT::i16));
326template <>
bool AVRDAGToDAGISel::select<ISD::STORE>(
SDNode *
N) {
330 SDValue BasePtr = ST->getBasePtr();
333 if (isa<FrameIndexSDNode>(BasePtr) || isa<ConstantSDNode>(BasePtr) ||
338 const RegisterSDNode *RN = dyn_cast<RegisterSDNode>(BasePtr.getOperand(0));
340 if (!RN || (RN->getReg() != AVR::SP)) {
344 int CST = (int)BasePtr.getConstantOperandVal(1);
345 SDValue Chain = ST->getChain();
346 EVT VT = ST->getValue().getValueType();
349 SDValue Ops[] = {BasePtr.getOperand(0),
Offset, ST->getValue(), Chain};
350 unsigned Opc = (VT == MVT::i16) ? AVR::STDWSPQRr : AVR::STDSPQRr;
352 SDNode *ResNode = CurDAG->getMachineNode(Opc,
DL, MVT::Other, Ops);
355 CurDAG->setNodeMemRefs(cast<MachineSDNode>(ResNode), {ST->getMemOperand()});
358 CurDAG->RemoveDeadNode(
N);
363template <>
bool AVRDAGToDAGISel::select<ISD::LOAD>(
SDNode *
N) {
367 return selectIndexedLoad(
N);
370 if (!Subtarget->hasLPM())
374 if (ProgMemBank < 0 || ProgMemBank > 5)
376 if (ProgMemBank > 0 && !Subtarget->hasELPM())
381 MVT VT = LD->getMemoryVT().getSimpleVT();
382 SDValue Chain = LD->getChain();
387 Chain = CurDAG->getCopyToReg(Chain,
DL, AVR::R31R30,
Ptr,
SDValue());
388 Ptr = CurDAG->getCopyFromReg(Chain,
DL, AVR::R31R30, MVT::i16,
392 if (
unsigned LPMOpc = selectIndexedProgMemLoad(LD, VT, ProgMemBank)) {
394 if (ProgMemBank == 0) {
396 CurDAG->getMachineNode(LPMOpc,
DL, VT, MVT::i16, MVT::Other,
Ptr);
400 SDValue NC = CurDAG->getTargetConstant(ProgMemBank,
DL, MVT::i8);
401 auto *NP = CurDAG->getMachineNode(AVR::LDIRdK,
DL, MVT::i8,
NC);
402 ResNode = CurDAG->getMachineNode(LPMOpc,
DL, VT, MVT::i16, MVT::Other,
409 if (ProgMemBank == 0) {
410 unsigned Opc = Subtarget->hasLPMX() ? AVR::LPMRdZ : AVR::LPMBRdZ;
412 CurDAG->getMachineNode(Opc,
DL, MVT::i8, MVT::Other,
Ptr);
416 SDValue NC = CurDAG->getTargetConstant(ProgMemBank,
DL, MVT::i8);
417 auto *NP = CurDAG->getMachineNode(AVR::LDIRdK,
DL, MVT::i8,
NC);
418 ResNode = CurDAG->getMachineNode(AVR::ELPMBRdZ,
DL, MVT::i8, MVT::Other,
423 if (ProgMemBank == 0) {
425 CurDAG->getMachineNode(AVR::LPMWRdZ,
DL, MVT::i16, MVT::Other,
Ptr);
429 SDValue NC = CurDAG->getTargetConstant(ProgMemBank,
DL, MVT::i8);
430 auto *NP = CurDAG->getMachineNode(AVR::LDIRdK,
DL, MVT::i8,
NC);
431 ResNode = CurDAG->getMachineNode(AVR::ELPMWRdZ,
DL, MVT::i16,
441 CurDAG->setNodeMemRefs(cast<MachineSDNode>(ResNode), {LD->getMemOperand()});
445 CurDAG->RemoveDeadNode(
N);
450template <>
bool AVRDAGToDAGISel::select<AVRISD::CALL>(
SDNode *
N) {
454 unsigned LastOpNum =
N->getNumOperands() - 1;
457 unsigned Op = Callee.getOpcode();
463 if (
N->getOperand(LastOpNum).getValueType() == MVT::Glue) {
468 Chain = CurDAG->getCopyToReg(Chain,
DL, AVR::R31R30, Callee, InGlue);
470 Ops.
push_back(CurDAG->getRegister(AVR::R31R30, MVT::i16));
473 for (
unsigned i = 2, e = LastOpNum + 1; i != e; ++i) {
480 SDNode *ResNode = CurDAG->getMachineNode(
481 Subtarget->hasEIJMPCALL() ? AVR::EICALL : AVR::ICALL,
DL, MVT::Other,
486 CurDAG->RemoveDeadNode(
N);
491template <>
bool AVRDAGToDAGISel::select<ISD::BRIND>(
SDNode *
N) {
497 Chain = CurDAG->getCopyToReg(Chain,
DL, AVR::R31R30, JmpAddr);
498 SDNode *ResNode = CurDAG->getMachineNode(AVR::IJMP,
DL, MVT::Other, Chain);
501 CurDAG->RemoveDeadNode(
N);
508 MVT Type =
N->getSimpleValueType(0);
510 assert(
Type == MVT::i8 &&
"unexpected value type");
513 unsigned MachineOp =
isSigned ? AVR::MULSRdRr : AVR::MULRdRr;
517 SDNode *
Mul = CurDAG->getMachineNode(MachineOp,
DL, MVT::Glue, Lhs, Rhs);
518 SDValue InChain = CurDAG->getEntryNode();
522 if (
N->hasAnyUseOfValue(0)) {
524 CurDAG->getCopyFromReg(InChain,
DL, AVR::R0,
Type, InGlue);
526 ReplaceUses(
SDValue(
N, 0), CopyFromLo);
533 if (
N->hasAnyUseOfValue(1)) {
535 CurDAG->getCopyFromReg(InChain,
DL, AVR::R1,
Type, InGlue);
537 ReplaceUses(
SDValue(
N, 1), CopyFromHi);
543 CurDAG->RemoveDeadNode(
N);
551void AVRDAGToDAGISel::Select(
SDNode *
N) {
553 if (
N->isMachineOpcode()) {
567bool AVRDAGToDAGISel::trySelect(
SDNode *
N) {
568 unsigned Opcode =
N->getOpcode();
579 return selectMultiplication(
N);
595 return new AVRDAGToDAGISelLegacy(
TM, OptLevel);
amdgpu AMDGPU Register Bank Select
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
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())
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,...
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.
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.