30#define DEBUG_TYPE "avr-isel"
31#define PASS_NAME "AVR DAG->DAG Instruction Selection"
40 AVRDAGToDAGISel() =
delete;
47 void PostprocessISelDAG()
override;
51 bool selectAlignedFrameLoad(
SDNode *
N);
52 bool selectAlignedFrameStore(
SDNode *
N);
53 bool selectIndexedLoad(
SDNode *
N);
55 unsigned selectIndexedProgMemLoad(
const LoadSDNode *LD,
MVT VT,
int Bank);
57 bool SelectInlineAsmMemoryOperand(
const SDValue &
Op,
59 std::vector<SDValue> &OutOps)
override;
62#include "AVRGenDAGISel.inc"
65 bool isPostProcessDone;
70 template <
unsigned NodeType>
bool select(
SDNode *
N);
71 bool selectMultiplication(
SDNode *
N);
81 ID, std::make_unique<AVRDAGToDAGISel>(TM, OptLevel)) {}
86char AVRDAGToDAGISelLegacy::ID = 0;
92 isPostProcessDone =
false;
106 MF.getFrameInfo().CreateStackObject(1,
Align(1),
false);
110 MF.getProperties().resetNoVRegs();
115void AVRDAGToDAGISel::PostprocessISelDAG() {
116 if (isPostProcessDone) {
126 MachineFrameInfo &MFI = MF->getFrameInfo();
127 AVRMachineFunctionInfo *AFI = MF->getInfo<AVRMachineFunctionInfo>();
161 isPostProcessDone =
true;
167 auto DL = CurDAG->getDataLayout();
168 MVT PtrVT = getTargetLowering()->getPointerTy(
DL);
172 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), PtrVT);
173 Disp = CurDAG->getTargetConstant(0, dl, MVT::i8);
180 !CurDAG->isBaseWithConstantOffset(
N)) {
185 int RHSC = (int)
RHS->getZExtValue();
199 Base = CurDAG->getTargetFrameIndex(FI, PtrVT);
200 Disp = CurDAG->getTargetConstant(RHSC, dl, MVT::i16);
212 bool OkI8 = VT == MVT::i8 && RHSC <= 63;
213 bool OkI16 = VT == MVT::i16 && RHSC <= 62;
216 Base =
N.getOperand(0);
217 Disp = CurDAG->getTargetConstant(RHSC, dl, MVT::i8);
226bool AVRDAGToDAGISel::selectAlignedFrameLoad(SDNode *
N) {
260 if (Alignment == 1) {
268 switch (
LD->getMemoryVT().getSimpleVT().SimpleTy) {
270 Opcode = AVR::LDRdPtr;
273 Opcode = AVR::LDWRdPtr;
281 MVT
PointerTy = getTargetLowering()->getPointerTy(CurDAG->getDataLayout());
282 Register StackReg = MF->getInfo<AVRMachineFunctionInfo>()->AlignedStackReg;
285 SDValue Offset = CurDAG->getTargetConstant(InOffset, SDLoc(
N), MVT::i16);
289 CurDAG->getRegister(StackReg,
PointerTy));
291 CurDAG->SelectNodeTo(
N, Opcode,
LD->getMemoryVT().getSimpleVT(), MVT::Other,
297bool AVRDAGToDAGISel::selectAlignedFrameStore(SDNode *
N) {
331 if (Alignment == 1) {
339 switch (
ST->getMemoryVT().getSimpleVT().SimpleTy) {
341 Opcode = AVR::STPtrRr;
344 Opcode = AVR::STWPtrRr;
352 MVT
PointerTy = getTargetLowering()->getPointerTy(CurDAG->getDataLayout());
353 Register StackReg = MF->getInfo<AVRMachineFunctionInfo>()->AlignedStackReg;
356 SDValue Offset = CurDAG->getTargetConstant(InOffset, SDLoc(
N), MVT::i16);
360 CurDAG->getRegister(StackReg,
PointerTy));
362 SDNode *ResNode = CurDAG->getMachineNode(
363 Opcode, SDLoc(
N), MVT::Other,
364 {
SDValue(AddrNode, 0),
ST->getValue(),
ST->getChain()});
369 CurDAG->RemoveDeadNode(
N);
374bool AVRDAGToDAGISel::selectIndexedLoad(SDNode *
N) {
377 MVT VT =
LD->getMemoryVT().getSimpleVT();
378 auto PtrVT = getTargetLowering()->getPointerTy(CurDAG->getDataLayout());
393 if ((!isPre && Offs != 1) || (isPre && Offs != -1)) {
397 Opcode = (isPre) ? AVR::LDRdPtrPd : AVR::LDRdPtrPi;
401 if ((!isPre && Offs != 2) || (isPre && Offs != -2)) {
405 Opcode = (isPre) ? AVR::LDWRdPtrPd : AVR::LDWRdPtrPi;
413 CurDAG->getMachineNode(Opcode, SDLoc(
N), VT, PtrVT, MVT::Other,
414 LD->getBasePtr(),
LD->getChain());
415 ReplaceUses(
N, ResNode);
416 CurDAG->RemoveDeadNode(
N);
421unsigned AVRDAGToDAGISel::selectIndexedProgMemLoad(
const LoadSDNode *LD, MVT VT,
429 assert((Bank == 0 || Subtarget->hasELPM()) &&
430 "cannot load from extended program memory on this mcu");
435 if (VT.
SimpleTy == MVT::i8 && Offs == 1 && Bank == 0)
436 Opcode = AVR::LPMRdZPi;
446bool AVRDAGToDAGISel::SelectInlineAsmMemoryOperand(
448 std::vector<SDValue> &OutOps) {
449 assert((ConstraintCode == InlineAsm::ConstraintCode::m ||
450 ConstraintCode == InlineAsm::ConstraintCode::Q) &&
451 "Unexpected asm memory constraint");
453 MachineRegisterInfo &RI = MF->getRegInfo();
454 const AVRSubtarget &STI = MF->getSubtarget<AVRSubtarget>();
457 auto DL = CurDAG->getDataLayout();
464 OutOps.push_back(
Op);
471 if (SelectAddr(
Op.getNode(),
Op,
Base, Disp)) {
472 OutOps.push_back(
Base);
473 OutOps.push_back(Disp);
482 if (
Op.getOpcode() == AVRISD::WRAPPER) {
485 (
Sub.getValueType() == MVT::i16 ||
Sub.getValueType() == MVT::i8)) {
486 OutOps.push_back(
Sub);
494 SDValue CopyFromRegOp =
Op->getOperand(0);
502 RegisterSDNode *RegNode =
505 CanHandleRegImmOpt &= (Register::isVirtualRegister(
Reg) ||
506 AVR::PTRDISPREGSRegClass.contains(
Reg));
508 CanHandleRegImmOpt =
false;
513 if (CanHandleRegImmOpt) {
517 SDLoc dl(CopyFromRegOp);
522 CurDAG->getCopyToReg(CopyFromRegOp, dl, VReg, CopyFromRegOp);
525 CurDAG->getCopyFromReg(CopyToReg, dl, VReg, TL.getPointerTy(
DL));
527 Base = NewCopyFromRegOp;
529 Base = CopyFromRegOp;
533 Disp = CurDAG->getTargetConstant(ImmNode->
getZExtValue(), dl, MVT::i8);
538 OutOps.push_back(
Base);
539 OutOps.push_back(Disp);
552 CurDAG->getCopyFromReg(CopyToReg, dl, VReg, TL.getPointerTy(
DL));
554 OutOps.push_back(CopyFromReg);
561template <>
bool AVRDAGToDAGISel::select<ISD::FrameIndex>(
SDNode *
N) {
562 auto DL = CurDAG->getDataLayout();
563 auto PointerTy = getTargetLowering()->getPointerTy(
DL);
568 uint64_t Alignment = MF->getFrameInfo().getObjectAlign(FI).value();
570 if (Alignment == 1) {
572 CurDAG->getRegister(AVR::R29R28,
PointerTy));
577 CurDAG->getRegister(StackReg,
PointerTy));
583template <>
bool AVRDAGToDAGISel::select<ISD::STORE>(
SDNode *
N) {
584 if (selectAlignedFrameStore(
N)) {
591 SDValue BasePtr = ST->getBasePtr();
601 if (!RN || (RN->getReg() != AVR::SP)) {
605 int CST = (int)BasePtr.getConstantOperandVal(1);
606 SDValue Chain = ST->getChain();
607 EVT VT = ST->getValue().getValueType();
611 unsigned Opc = (VT == MVT::i16) ? AVR::STDWSPQRr : AVR::STDSPQRr;
613 SDNode *ResNode = CurDAG->getMachineNode(
Opc,
DL, MVT::Other,
Ops);
619 CurDAG->RemoveDeadNode(
N);
624template <>
bool AVRDAGToDAGISel::select<ISD::LOAD>(
SDNode *
N) {
627 return selectAlignedFrameLoad(
N) || selectIndexedLoad(
N);
630 if (!Subtarget->hasLPM())
634 if (ProgMemBank < 0 || ProgMemBank > 5)
636 if (ProgMemBank > 0 && !Subtarget->hasELPM())
641 MVT VT = LD->getMemoryVT().getSimpleVT();
642 SDValue Chain = LD->getChain();
643 SDValue Ptr = LD->getBasePtr();
647 Chain = CurDAG->getCopyToReg(Chain,
DL, AVR::R31R30, Ptr,
SDValue());
648 Ptr = CurDAG->getCopyFromReg(Chain,
DL, AVR::R31R30, MVT::i16,
652 if (
unsigned LPMOpc = selectIndexedProgMemLoad(LD, VT, ProgMemBank)) {
654 if (ProgMemBank == 0) {
656 CurDAG->getMachineNode(LPMOpc,
DL, VT, MVT::i16, MVT::Other, Ptr);
660 SDValue NC = CurDAG->getTargetConstant(ProgMemBank,
DL, MVT::i8);
661 auto *NP = CurDAG->getMachineNode(AVR::LDIRdK,
DL, MVT::i8,
NC);
662 ResNode = CurDAG->getMachineNode(LPMOpc,
DL, VT, MVT::i16, MVT::Other,
669 if (ProgMemBank == 0) {
670 unsigned Opc = Subtarget->hasLPMX() ? AVR::LPMRdZ : AVR::LPMBRdZ;
671 ResNode = CurDAG->getMachineNode(
Opc,
DL, MVT::i8, MVT::Other, Ptr);
675 SDValue NC = CurDAG->getTargetConstant(ProgMemBank,
DL, MVT::i8);
676 auto *NP = CurDAG->getMachineNode(AVR::LDIRdK,
DL, MVT::i8,
NC);
677 ResNode = CurDAG->getMachineNode(AVR::ELPMBRdZ,
DL, MVT::i8, MVT::Other,
682 if (ProgMemBank == 0) {
684 CurDAG->getMachineNode(AVR::LPMWRdZ,
DL, MVT::i16, MVT::Other, Ptr);
688 SDValue NC = CurDAG->getTargetConstant(ProgMemBank,
DL, MVT::i8);
689 auto *NP = CurDAG->getMachineNode(AVR::LDIRdK,
DL, MVT::i8,
NC);
690 ResNode = CurDAG->getMachineNode(AVR::ELPMWRdZ,
DL, MVT::i16,
691 MVT::Other, Ptr,
SDValue(NP, 0));
704 CurDAG->RemoveDeadNode(
N);
709template <>
bool AVRDAGToDAGISel::select<AVRISD::CALL>(
SDNode *
N) {
713 unsigned LastOpNum =
N->getNumOperands() - 1;
716 unsigned Op = Callee.getOpcode();
722 if (
N->getOperand(LastOpNum).getValueType() == MVT::Glue) {
727 Chain = CurDAG->getCopyToReg(Chain,
DL, AVR::R31R30, Callee, InGlue);
729 Ops.push_back(CurDAG->getRegister(AVR::R31R30, MVT::i16));
732 for (
unsigned i = 2, e = LastOpNum + 1; i != e; ++i) {
733 Ops.push_back(
N->getOperand(i));
736 Ops.push_back(Chain);
739 SDNode *ResNode = CurDAG->getMachineNode(
740 Subtarget->hasEIJMPCALL() ? AVR::EICALL : AVR::ICALL,
DL, MVT::Other,
745 CurDAG->RemoveDeadNode(
N);
750template <>
bool AVRDAGToDAGISel::select<ISD::BRIND>(
SDNode *
N) {
756 Chain = CurDAG->getCopyToReg(Chain,
DL, AVR::R31R30, JmpAddr);
757 SDNode *ResNode = CurDAG->getMachineNode(AVR::IJMP,
DL, MVT::Other, Chain);
760 CurDAG->RemoveDeadNode(
N);
765bool AVRDAGToDAGISel::selectMultiplication(llvm::SDNode *
N) {
767 MVT
Type =
N->getSimpleValueType(0);
769 assert(
Type == MVT::i8 &&
"unexpected value type");
772 unsigned MachineOp =
isSigned ? AVR::MULSRdRr : AVR::MULRdRr;
776 SDNode *
Mul = CurDAG->getMachineNode(MachineOp,
DL, MVT::Glue, Lhs, Rhs);
777 SDValue InChain = CurDAG->getEntryNode();
781 if (
N->hasAnyUseOfValue(0)) {
783 CurDAG->getCopyFromReg(InChain,
DL, AVR::R0,
Type, InGlue);
785 ReplaceUses(
SDValue(
N, 0), CopyFromLo);
792 if (
N->hasAnyUseOfValue(1)) {
794 CurDAG->getCopyFromReg(InChain,
DL, AVR::R1,
Type, InGlue);
796 ReplaceUses(
SDValue(
N, 1), CopyFromHi);
802 CurDAG->RemoveDeadNode(
N);
810void AVRDAGToDAGISel::Select(SDNode *
N) {
812 if (
N->isMachineOpcode()) {
826bool AVRDAGToDAGISel::trySelect(SDNode *
N) {
827 unsigned Opcode =
N->getOpcode();
837 return selectMultiplication(
N);
853 return new AVRDAGToDAGISelLegacy(TM, OptLevel);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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 Opcode)
const HexagonInstrInfo * TII
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
Promote Memory to Register
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
bool ult(const APInt &RHS) const
Unsigned less than comparison.
Contains AVR-specific information for each MachineFunction.
unsigned AlignedStackObjectIdx
A specific AVR target MCU.
const AVRTargetLowering * getTargetLowering() const override
A generic AVR implementation.
uint64_t getZExtValue() const
const APInt & getAPIntValue() const
FunctionPass class - This class is used to implement most global optimizations.
This class is used to represent ISD::LOAD nodes.
void setMaxAlign(Align Alignment)
Overwrite alignment of this function's frame.
void setObjectOffset(int ObjectIdx, int64_t SPOffset)
Set the stack frame offset of the specified object.
void setObjectSize(int ObjectIdx, int64_t Size)
Change the size of the specified stack object.
void setStackID(int ObjectIdx, uint8_t ID)
Align getObjectAlign(int ObjectIdx) const
Return the alignment of the specified stack object.
int64_t getObjectSize(int ObjectIdx) const
Return the size of the specified object.
void RemoveStackObject(int ObjectIdx)
Remove or mark dead a statically sized stack object.
int getObjectIndexEnd() const
Return one past the maximum frame object index.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
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
Storage of either a normal Value address, or a select condition together with a pair of addresses for...
SelectionDAGISel - This is the common base class used for SelectionDAG-based pattern-matching instruc...
virtual bool runOnMachineFunction(MachineFunction &mf)
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.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
bool isProgramMemoryAccess(MemSDNode const *N)
int getProgramMemoryBank(MemSDNode const *N)
@ 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.
This is an optimization pass for GlobalISel generic memory operations.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Register createVirtualRegister(SPIRVTypeInst SpvType, SPIRVGlobalRegistry *GR, MachineRegisterInfo *MRI, const MachineFunction &MF)
FunctionPass * createAVRISelDag(AVRTargetMachine &TM, CodeGenOptLevel OptLevel)
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
constexpr uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
CodeGenOptLevel
Code generation optimization level.
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
@ Sub
Subtraction of integers.
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
This struct is a compact representation of a valid (non-zero power of two) alignment.
constexpr uint64_t value() const
This is a hole in the type system and should not be abused.