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);
44 bool SelectInlineAsmMemoryOperand(
const SDValue &
Op,
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)) {
101 int RHSC = (int)
RHS->getZExtValue();
115 Base = CurDAG->getTargetFrameIndex(FI, PtrVT);
116 Disp = CurDAG->getTargetConstant(RHSC, dl, MVT::i16);
128 bool OkI8 = VT == MVT::i8 && RHSC <= 63;
129 bool OkI16 = VT == MVT::i16 && RHSC <= 62;
132 Base =
N.getOperand(0);
133 Disp = CurDAG->getTargetConstant(RHSC, dl, MVT::i8);
142bool AVRDAGToDAGISel::selectIndexedLoad(SDNode *
N) {
145 MVT VT =
LD->getMemoryVT().getSimpleVT();
146 auto PtrVT = getTargetLowering()->getPointerTy(CurDAG->getDataLayout());
161 if ((!isPre && Offs != 1) || (isPre && Offs != -1)) {
165 Opcode = (isPre) ? AVR::LDRdPtrPd : AVR::LDRdPtrPi;
169 if ((!isPre && Offs != 2) || (isPre && Offs != -2)) {
173 Opcode = (isPre) ? AVR::LDWRdPtrPd : AVR::LDWRdPtrPi;
181 CurDAG->getMachineNode(Opcode, SDLoc(
N), VT, PtrVT, MVT::Other,
182 LD->getBasePtr(),
LD->getChain());
183 ReplaceUses(
N, ResNode);
184 CurDAG->RemoveDeadNode(
N);
189unsigned AVRDAGToDAGISel::selectIndexedProgMemLoad(
const LoadSDNode *LD, MVT VT,
197 assert((Bank == 0 || Subtarget->hasELPM()) &&
198 "cannot load from extended program memory on this mcu");
203 if (VT.
SimpleTy == MVT::i8 && Offs == 1 && Bank == 0)
204 Opcode = AVR::LPMRdZPi;
214bool AVRDAGToDAGISel::SelectInlineAsmMemoryOperand(
216 std::vector<SDValue> &OutOps) {
217 assert((ConstraintCode == InlineAsm::ConstraintCode::m ||
218 ConstraintCode == InlineAsm::ConstraintCode::Q) &&
219 "Unexpected asm memory constraint");
221 MachineRegisterInfo &RI = MF->getRegInfo();
222 const AVRSubtarget &STI = MF->getSubtarget<AVRSubtarget>();
225 auto DL = CurDAG->getDataLayout();
232 OutOps.push_back(
Op);
239 if (SelectAddr(
Op.getNode(),
Op,
Base, Disp)) {
240 OutOps.push_back(
Base);
241 OutOps.push_back(Disp);
250 if (
Op.getOpcode() == AVRISD::WRAPPER) {
253 (
Sub.getValueType() == MVT::i16 ||
Sub.getValueType() == MVT::i8)) {
254 OutOps.push_back(
Sub);
262 SDValue CopyFromRegOp =
Op->getOperand(0);
270 RegisterSDNode *RegNode =
273 CanHandleRegImmOpt &= (Register::isVirtualRegister(
Reg) ||
274 AVR::PTRDISPREGSRegClass.contains(
Reg));
276 CanHandleRegImmOpt =
false;
281 if (CanHandleRegImmOpt) {
285 SDLoc dl(CopyFromRegOp);
290 CurDAG->getCopyToReg(CopyFromRegOp, dl, VReg, CopyFromRegOp);
293 CurDAG->getCopyFromReg(CopyToReg, dl, VReg, TL.getPointerTy(
DL));
295 Base = NewCopyFromRegOp;
297 Base = CopyFromRegOp;
301 Disp = CurDAG->getTargetConstant(ImmNode->
getZExtValue(), dl, MVT::i8);
306 OutOps.push_back(
Base);
307 OutOps.push_back(Disp);
320 CurDAG->getCopyFromReg(CopyToReg, dl, VReg, TL.getPointerTy(
DL));
322 OutOps.push_back(CopyFromReg);
327template <>
bool AVRDAGToDAGISel::select<ISD::FrameIndex>(
SDNode *
N) {
328 auto DL = CurDAG->getDataLayout();
334 CurDAG->getTargetFrameIndex(FI, getTargetLowering()->getPointerTy(
DL));
336 CurDAG->SelectNodeTo(
N, AVR::FRMIDX, getTargetLowering()->getPointerTy(
DL),
337 TFI, CurDAG->getTargetConstant(0,
SDLoc(
N), MVT::i16));
341template <>
bool AVRDAGToDAGISel::select<ISD::STORE>(
SDNode *
N) {
345 SDValue BasePtr = ST->getBasePtr();
355 if (!RN || (RN->getReg() != AVR::SP)) {
359 int CST = (int)BasePtr.getConstantOperandVal(1);
360 SDValue Chain = ST->getChain();
361 EVT VT = ST->getValue().getValueType();
365 unsigned Opc = (VT == MVT::i16) ? AVR::STDWSPQRr : AVR::STDSPQRr;
367 SDNode *ResNode = CurDAG->getMachineNode(
Opc,
DL, MVT::Other,
Ops);
373 CurDAG->RemoveDeadNode(
N);
378template <>
bool AVRDAGToDAGISel::select<ISD::LOAD>(
SDNode *
N) {
382 return selectIndexedLoad(
N);
385 if (!Subtarget->hasLPM())
389 if (ProgMemBank < 0 || ProgMemBank > 5)
391 if (ProgMemBank > 0 && !Subtarget->hasELPM())
396 MVT VT = LD->getMemoryVT().getSimpleVT();
397 SDValue Chain = LD->getChain();
398 SDValue Ptr = LD->getBasePtr();
402 Chain = CurDAG->getCopyToReg(Chain,
DL, AVR::R31R30, Ptr,
SDValue());
403 Ptr = CurDAG->getCopyFromReg(Chain,
DL, AVR::R31R30, MVT::i16,
407 if (
unsigned LPMOpc = selectIndexedProgMemLoad(LD, VT, ProgMemBank)) {
409 if (ProgMemBank == 0) {
411 CurDAG->getMachineNode(LPMOpc,
DL, VT, MVT::i16, MVT::Other, Ptr);
415 SDValue NC = CurDAG->getTargetConstant(ProgMemBank,
DL, MVT::i8);
416 auto *NP = CurDAG->getMachineNode(AVR::LDIRdK,
DL, MVT::i8,
NC);
417 ResNode = CurDAG->getMachineNode(LPMOpc,
DL, VT, MVT::i16, MVT::Other,
424 if (ProgMemBank == 0) {
425 unsigned Opc = Subtarget->hasLPMX() ? AVR::LPMRdZ : AVR::LPMBRdZ;
426 ResNode = CurDAG->getMachineNode(
Opc,
DL, MVT::i8, MVT::Other, Ptr);
430 SDValue NC = CurDAG->getTargetConstant(ProgMemBank,
DL, MVT::i8);
431 auto *NP = CurDAG->getMachineNode(AVR::LDIRdK,
DL, MVT::i8,
NC);
432 ResNode = CurDAG->getMachineNode(AVR::ELPMBRdZ,
DL, MVT::i8, MVT::Other,
437 if (ProgMemBank == 0) {
439 CurDAG->getMachineNode(AVR::LPMWRdZ,
DL, MVT::i16, MVT::Other, Ptr);
443 SDValue NC = CurDAG->getTargetConstant(ProgMemBank,
DL, MVT::i8);
444 auto *NP = CurDAG->getMachineNode(AVR::LDIRdK,
DL, MVT::i8,
NC);
445 ResNode = CurDAG->getMachineNode(AVR::ELPMWRdZ,
DL, MVT::i16,
446 MVT::Other, Ptr,
SDValue(NP, 0));
459 CurDAG->RemoveDeadNode(
N);
464template <>
bool AVRDAGToDAGISel::select<AVRISD::CALL>(
SDNode *
N) {
468 unsigned LastOpNum =
N->getNumOperands() - 1;
471 unsigned Op = Callee.getOpcode();
477 if (
N->getOperand(LastOpNum).getValueType() == MVT::Glue) {
482 Chain = CurDAG->getCopyToReg(Chain,
DL, AVR::R31R30, Callee, InGlue);
484 Ops.push_back(CurDAG->getRegister(AVR::R31R30, MVT::i16));
487 for (
unsigned i = 2, e = LastOpNum + 1; i != e; ++i) {
488 Ops.push_back(
N->getOperand(i));
491 Ops.push_back(Chain);
494 SDNode *ResNode = CurDAG->getMachineNode(
495 Subtarget->hasEIJMPCALL() ? AVR::EICALL : AVR::ICALL,
DL, MVT::Other,
500 CurDAG->RemoveDeadNode(
N);
505template <>
bool AVRDAGToDAGISel::select<ISD::BRIND>(
SDNode *
N) {
511 Chain = CurDAG->getCopyToReg(Chain,
DL, AVR::R31R30, JmpAddr);
512 SDNode *ResNode = CurDAG->getMachineNode(AVR::IJMP,
DL, MVT::Other, Chain);
515 CurDAG->RemoveDeadNode(
N);
520bool AVRDAGToDAGISel::selectMultiplication(llvm::SDNode *
N) {
522 MVT
Type =
N->getSimpleValueType(0);
524 assert(
Type == MVT::i8 &&
"unexpected value type");
527 unsigned MachineOp =
isSigned ? AVR::MULSRdRr : AVR::MULRdRr;
531 SDNode *
Mul = CurDAG->getMachineNode(MachineOp,
DL, MVT::Glue, Lhs, Rhs);
532 SDValue InChain = CurDAG->getEntryNode();
536 if (
N->hasAnyUseOfValue(0)) {
538 CurDAG->getCopyFromReg(InChain,
DL, AVR::R0,
Type, InGlue);
540 ReplaceUses(
SDValue(
N, 0), CopyFromLo);
547 if (
N->hasAnyUseOfValue(1)) {
549 CurDAG->getCopyFromReg(InChain,
DL, AVR::R1,
Type, InGlue);
551 ReplaceUses(
SDValue(
N, 1), CopyFromHi);
557 CurDAG->RemoveDeadNode(
N);
565void AVRDAGToDAGISel::Select(SDNode *
N) {
567 if (
N->isMachineOpcode()) {
581bool AVRDAGToDAGISel::trySelect(SDNode *
N) {
582 unsigned Opcode =
N->getOpcode();
592 return selectMultiplication(
N);
608 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 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.
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.
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
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.
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.
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
FunctionPass * createAVRISelDag(AVRTargetMachine &TM, CodeGenOptLevel OptLevel)
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
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.