31#define DEBUG_TYPE "avr-isel"
32#define PASS_NAME "AVR DAG->DAG Instruction Selection"
41 AVRDAGToDAGISel() =
delete;
48 void PostprocessISelDAG()
override;
52 bool selectAlignedFrameLoad(
SDNode *
N);
53 bool selectAlignedFrameStore(
SDNode *
N);
54 bool selectIndexedLoad(
SDNode *
N);
56 unsigned selectIndexedProgMemLoad(
const LoadSDNode *LD,
MVT VT,
int Bank);
58 bool SelectInlineAsmMemoryOperand(
const SDValue &
Op,
60 std::vector<SDValue> &OutOps)
override;
63#include "AVRGenDAGISel.inc"
66 bool isPostProcessDone;
71 template <
unsigned NodeType>
bool select(
SDNode *
N);
72 bool selectMultiplication(
SDNode *
N);
82 ID, std::make_unique<AVRDAGToDAGISel>(TM, OptLevel)) {}
87char AVRDAGToDAGISelLegacy::ID = 0;
93 isPostProcessDone =
false;
107 MF.getFrameInfo().CreateStackObject(1,
Align(1),
false);
111 MF.getProperties().resetNoVRegs();
116void AVRDAGToDAGISel::PostprocessISelDAG() {
117 if (isPostProcessDone) {
127 MachineFrameInfo &MFI = MF->getFrameInfo();
128 AVRMachineFunctionInfo *AFI = MF->getInfo<AVRMachineFunctionInfo>();
162 isPostProcessDone =
true;
165bool AVRDAGToDAGISel::SelectAddr(SDNode *
Op, SDValue
N, SDValue &
Base,
168 auto DL = CurDAG->getDataLayout();
169 MVT PtrVT = getTargetLowering()->getPointerTy(
DL);
173 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), PtrVT);
174 Disp = CurDAG->getTargetConstant(0, dl, MVT::i8);
181 !CurDAG->isBaseWithConstantOffset(
N)) {
186 int RHSC = (int)
RHS->getZExtValue();
200 Base = CurDAG->getTargetFrameIndex(FI, PtrVT);
201 Disp = CurDAG->getTargetConstant(RHSC, dl, MVT::i16);
213 bool OkI8 = VT == MVT::i8 && RHSC <= 63;
214 bool OkI16 = VT == MVT::i16 && RHSC <= 62;
217 Base =
N.getOperand(0);
218 Disp = CurDAG->getTargetConstant(RHSC, dl, MVT::i8);
227bool AVRDAGToDAGISel::selectAlignedFrameLoad(SDNode *
N) {
229 const SDValue LDB =
LD->getBasePtr();
261 if (Alignment == 1) {
269 switch (
LD->getMemoryVT().getSimpleVT().SimpleTy) {
271 Opcode = AVR::LDRdPtr;
274 Opcode = AVR::LDWRdPtr;
282 MVT
PointerTy = getTargetLowering()->getPointerTy(CurDAG->getDataLayout());
283 Register StackReg = MF->getInfo<AVRMachineFunctionInfo>()->AlignedStackReg;
286 SDValue
Offset = CurDAG->getTargetConstant(InOffset, SDLoc(
N), MVT::i16);
290 CurDAG->getRegister(StackReg,
PointerTy));
292 CurDAG->SelectNodeTo(
N, Opcode,
LD->getMemoryVT().getSimpleVT(), MVT::Other,
293 SDValue(ResNode, 0),
LD->getChain());
298bool AVRDAGToDAGISel::selectAlignedFrameStore(SDNode *
N) {
300 const SDValue STB =
ST->getBasePtr();
332 if (Alignment == 1) {
340 switch (
ST->getMemoryVT().getSimpleVT().SimpleTy) {
342 Opcode = AVR::STPtrRr;
345 Opcode = AVR::STWPtrRr;
353 MVT
PointerTy = getTargetLowering()->getPointerTy(CurDAG->getDataLayout());
354 Register StackReg = MF->getInfo<AVRMachineFunctionInfo>()->AlignedStackReg;
357 SDValue
Offset = CurDAG->getTargetConstant(InOffset, SDLoc(
N), MVT::i16);
361 CurDAG->getRegister(StackReg,
PointerTy));
363 SDNode *ResNode = CurDAG->getMachineNode(
364 Opcode, SDLoc(
N), MVT::Other,
365 {SDValue(AddrNode, 0),
ST->getValue(),
ST->getChain()});
369 ReplaceUses(SDValue(
N, 0), SDValue(ResNode, 0));
370 CurDAG->RemoveDeadNode(
N);
375bool AVRDAGToDAGISel::selectIndexedLoad(SDNode *
N) {
378 MVT VT =
LD->getMemoryVT().getSimpleVT();
379 auto PtrVT = getTargetLowering()->getPointerTy(CurDAG->getDataLayout());
394 if ((!isPre && Offs != 1) || (isPre && Offs != -1)) {
398 Opcode = (isPre) ? AVR::LDRdPtrPd : AVR::LDRdPtrPi;
402 if ((!isPre && Offs != 2) || (isPre && Offs != -2)) {
406 Opcode = (isPre) ? AVR::LDWRdPtrPd : AVR::LDWRdPtrPi;
414 CurDAG->getMachineNode(Opcode, SDLoc(
N), VT, PtrVT, MVT::Other,
415 LD->getBasePtr(),
LD->getChain());
416 ReplaceUses(
N, ResNode);
417 CurDAG->RemoveDeadNode(
N);
422unsigned AVRDAGToDAGISel::selectIndexedProgMemLoad(
const LoadSDNode *LD, MVT VT,
430 assert((Bank == 0 || Subtarget->hasELPM()) &&
431 "cannot load from extended program memory on this mcu");
436 if (VT.
SimpleTy == MVT::i8 && Offs == 1 && Bank == 0)
437 Opcode = AVR::LPMRdZPi;
447bool AVRDAGToDAGISel::SelectInlineAsmMemoryOperand(
449 std::vector<SDValue> &OutOps) {
450 assert((ConstraintCode == InlineAsm::ConstraintCode::m ||
451 ConstraintCode == InlineAsm::ConstraintCode::Q) &&
452 "Unexpected asm memory constraint");
454 MachineRegisterInfo &RI = MF->getRegInfo();
455 const AVRSubtarget &STI = MF->getSubtarget<AVRSubtarget>();
458 auto DL = CurDAG->getDataLayout();
465 OutOps.push_back(
Op);
472 if (SelectAddr(
Op.getNode(),
Op,
Base, Disp)) {
473 OutOps.push_back(
Base);
474 OutOps.push_back(Disp);
483 if (
Op.getOpcode() == AVRISD::WRAPPER) {
484 SDValue
Sub =
Op.getOperand(0);
486 (
Sub.getValueType() == MVT::i16 ||
Sub.getValueType() == MVT::i8)) {
487 OutOps.push_back(
Sub);
495 SDValue CopyFromRegOp =
Op->getOperand(0);
496 SDValue ImmOp =
Op->getOperand(1);
503 RegisterSDNode *RegNode =
506 CanHandleRegImmOpt &= (Register::isVirtualRegister(
Reg) ||
507 AVR::PTRDISPREGSRegClass.contains(
Reg));
509 CanHandleRegImmOpt =
false;
514 if (CanHandleRegImmOpt) {
518 SDLoc dl(CopyFromRegOp);
523 CurDAG->getCopyToReg(CopyFromRegOp, dl, VReg, CopyFromRegOp);
525 SDValue NewCopyFromRegOp =
526 CurDAG->getCopyFromReg(CopyToReg, dl, VReg, TL.getPointerTy(
DL));
528 Base = NewCopyFromRegOp;
530 Base = CopyFromRegOp;
534 Disp = CurDAG->getTargetConstant(ImmNode->
getZExtValue(), dl, MVT::i8);
539 OutOps.push_back(
Base);
540 OutOps.push_back(Disp);
553 CurDAG->getCopyFromReg(CopyToReg, dl, VReg, TL.getPointerTy(
DL));
555 OutOps.push_back(CopyFromReg);
562template <>
bool AVRDAGToDAGISel::select<ISD::FrameIndex>(
SDNode *
N) {
563 auto DL = CurDAG->getDataLayout();
564 auto PointerTy = getTargetLowering()->getPointerTy(
DL);
569 uint64_t Alignment = MF->getFrameInfo().getObjectAlign(FI).value();
571 if (Alignment == 1) {
573 CurDAG->getRegister(AVR::R29R28,
PointerTy));
578 CurDAG->getRegister(StackReg,
PointerTy));
584template <>
bool AVRDAGToDAGISel::select<ISD::STORE>(
SDNode *
N) {
585 if (selectAlignedFrameStore(
N)) {
592 SDValue BasePtr = ST->getBasePtr();
602 if (!RN || (RN->getReg() != AVR::SP)) {
606 int CST = (int)BasePtr.getConstantOperandVal(1);
607 SDValue Chain = ST->getChain();
608 EVT VT = ST->getValue().getValueType();
612 unsigned Opc = (VT == MVT::i16) ? AVR::STDWSPQRr : AVR::STDSPQRr;
614 SDNode *ResNode = CurDAG->getMachineNode(
Opc,
DL, MVT::Other,
Ops);
620 CurDAG->RemoveDeadNode(
N);
625template <>
bool AVRDAGToDAGISel::select<ISD::LOAD>(
SDNode *
N) {
628 return selectAlignedFrameLoad(
N) || selectIndexedLoad(
N);
631 if (!Subtarget->hasLPM())
635 if (ProgMemBank < 0 || ProgMemBank > 5)
637 if (ProgMemBank > 0 && !Subtarget->hasELPM())
642 MVT VT = LD->getMemoryVT().getSimpleVT();
643 SDValue Chain = LD->getChain();
644 SDValue Ptr = LD->getBasePtr();
648 Chain = CurDAG->getCopyToReg(Chain,
DL, AVR::R31R30, Ptr,
SDValue());
649 Ptr = CurDAG->getCopyFromReg(Chain,
DL, AVR::R31R30, MVT::i16,
653 if (
unsigned LPMOpc = selectIndexedProgMemLoad(LD, VT, ProgMemBank)) {
655 if (ProgMemBank == 0) {
657 CurDAG->getMachineNode(LPMOpc,
DL, VT, MVT::i16, MVT::Other, Ptr);
661 SDValue NC = CurDAG->getTargetConstant(ProgMemBank,
DL, MVT::i8);
662 auto *NP = CurDAG->getMachineNode(AVR::LDIRdK,
DL, MVT::i8,
NC);
663 ResNode = CurDAG->getMachineNode(LPMOpc,
DL, VT, MVT::i16, MVT::Other,
670 if (ProgMemBank == 0) {
671 unsigned Opc = Subtarget->hasLPMX() ? AVR::LPMRdZ : AVR::LPMBRdZ;
672 ResNode = CurDAG->getMachineNode(
Opc,
DL, MVT::i8, MVT::Other, Ptr);
676 SDValue NC = CurDAG->getTargetConstant(ProgMemBank,
DL, MVT::i8);
677 auto *NP = CurDAG->getMachineNode(AVR::LDIRdK,
DL, MVT::i8,
NC);
678 ResNode = CurDAG->getMachineNode(AVR::ELPMBRdZ,
DL, MVT::i8, MVT::Other,
683 if (ProgMemBank == 0) {
685 CurDAG->getMachineNode(AVR::LPMWRdZ,
DL, MVT::i16, MVT::Other, Ptr);
689 SDValue NC = CurDAG->getTargetConstant(ProgMemBank,
DL, MVT::i8);
690 auto *NP = CurDAG->getMachineNode(AVR::LDIRdK,
DL, MVT::i8,
NC);
691 ResNode = CurDAG->getMachineNode(AVR::ELPMWRdZ,
DL, MVT::i16,
692 MVT::Other, Ptr,
SDValue(NP, 0));
705 CurDAG->RemoveDeadNode(
N);
710template <>
bool AVRDAGToDAGISel::select<AVRISD::CALL>(
SDNode *
N) {
714 unsigned LastOpNum =
N->getNumOperands() - 1;
717 unsigned Op = Callee.getOpcode();
723 if (
N->getOperand(LastOpNum).getValueType() == MVT::Glue) {
728 Chain = CurDAG->getCopyToReg(Chain,
DL, AVR::R31R30, Callee, InGlue);
730 Ops.push_back(CurDAG->getRegister(AVR::R31R30, MVT::i16));
733 for (
unsigned i = 2, e = LastOpNum + 1; i != e; ++i) {
734 Ops.push_back(
N->getOperand(i));
737 Ops.push_back(Chain);
740 SDNode *ResNode = CurDAG->getMachineNode(
741 Subtarget->hasEIJMPCALL() ? AVR::EICALL : AVR::ICALL,
DL, MVT::Other,
746 CurDAG->RemoveDeadNode(
N);
751template <>
bool AVRDAGToDAGISel::select<ISD::BRIND>(
SDNode *
N) {
757 Chain = CurDAG->getCopyToReg(Chain,
DL, AVR::R31R30, JmpAddr);
758 SDNode *ResNode = CurDAG->getMachineNode(AVR::IJMP,
DL, MVT::Other, Chain);
761 CurDAG->RemoveDeadNode(
N);
766bool AVRDAGToDAGISel::selectMultiplication(llvm::SDNode *
N) {
768 MVT
Type =
N->getSimpleValueType(0);
770 assert(
Type == MVT::i8 &&
"unexpected value type");
773 unsigned MachineOp =
isSigned ? AVR::MULSRdRr : AVR::MULRdRr;
775 SDValue Lhs =
N->getOperand(0);
776 SDValue Rhs =
N->getOperand(1);
777 SDNode *
Mul = CurDAG->getMachineNode(MachineOp,
DL, MVT::Glue, Lhs, Rhs);
778 SDValue InChain = CurDAG->getEntryNode();
779 SDValue InGlue = SDValue(
Mul, 0);
782 if (
N->hasAnyUseOfValue(0)) {
784 CurDAG->getCopyFromReg(InChain,
DL, AVR::R0,
Type, InGlue);
786 ReplaceUses(SDValue(
N, 0), CopyFromLo);
793 if (
N->hasAnyUseOfValue(1)) {
795 CurDAG->getCopyFromReg(InChain,
DL, AVR::R1,
Type, InGlue);
797 ReplaceUses(SDValue(
N, 1), CopyFromHi);
803 CurDAG->RemoveDeadNode(
N);
811void AVRDAGToDAGISel::Select(SDNode *
N) {
813 if (
N->isMachineOpcode()) {
827bool AVRDAGToDAGISel::trySelect(SDNode *
N) {
828 unsigned Opcode =
N->getOpcode();
838 return selectMultiplication(
N);
858 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.
AVRISelDAGToDAGPass(AVRTargetMachine &TM, CodeGenOptLevel OptLevel)
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 instruction together with a pair of addresses f...
SelectionDAGISelPass(std::unique_ptr< SelectionDAGISel > Selector)
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.
FunctionPass * createAVRISelDagLegacyPass(AVRTargetMachine &TM, CodeGenOptLevel OptLevel)
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)
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.
Implement std::hash so that hash_code can be used in STL containers.
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.