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);
252 SDValue CopyFromRegOp =
Op->getOperand(0);
260 RegisterSDNode *RegNode =
263 CanHandleRegImmOpt &= (Register::isVirtualRegister(
Reg) ||
264 AVR::PTRDISPREGSRegClass.contains(
Reg));
266 CanHandleRegImmOpt =
false;
271 if (CanHandleRegImmOpt) {
275 SDLoc dl(CopyFromRegOp);
280 CurDAG->getCopyToReg(CopyFromRegOp, dl, VReg, CopyFromRegOp);
283 CurDAG->getCopyFromReg(CopyToReg, dl, VReg, TL.getPointerTy(
DL));
285 Base = NewCopyFromRegOp;
287 Base = CopyFromRegOp;
291 Disp = CurDAG->getTargetConstant(ImmNode->
getZExtValue(), dl, MVT::i8);
296 OutOps.push_back(
Base);
297 OutOps.push_back(Disp);
310 CurDAG->getCopyFromReg(CopyToReg, dl, VReg, TL.getPointerTy(
DL));
312 OutOps.push_back(CopyFromReg);
317template <>
bool AVRDAGToDAGISel::select<ISD::FrameIndex>(
SDNode *
N) {
318 auto DL = CurDAG->getDataLayout();
324 CurDAG->getTargetFrameIndex(FI, getTargetLowering()->getPointerTy(
DL));
326 CurDAG->SelectNodeTo(
N, AVR::FRMIDX, getTargetLowering()->getPointerTy(
DL),
327 TFI, CurDAG->getTargetConstant(0,
SDLoc(
N), MVT::i16));
331template <>
bool AVRDAGToDAGISel::select<ISD::STORE>(
SDNode *
N) {
335 SDValue BasePtr = ST->getBasePtr();
345 if (!RN || (RN->getReg() != AVR::SP)) {
349 int CST = (int)BasePtr.getConstantOperandVal(1);
350 SDValue Chain = ST->getChain();
351 EVT VT = ST->getValue().getValueType();
355 unsigned Opc = (VT == MVT::i16) ? AVR::STDWSPQRr : AVR::STDSPQRr;
357 SDNode *ResNode = CurDAG->getMachineNode(
Opc,
DL, MVT::Other,
Ops);
363 CurDAG->RemoveDeadNode(
N);
368template <>
bool AVRDAGToDAGISel::select<ISD::LOAD>(
SDNode *
N) {
372 return selectIndexedLoad(
N);
375 if (!Subtarget->hasLPM())
379 if (ProgMemBank < 0 || ProgMemBank > 5)
381 if (ProgMemBank > 0 && !Subtarget->hasELPM())
386 MVT VT = LD->getMemoryVT().getSimpleVT();
387 SDValue Chain = LD->getChain();
392 Chain = CurDAG->getCopyToReg(Chain,
DL, AVR::R31R30,
Ptr,
SDValue());
393 Ptr = CurDAG->getCopyFromReg(Chain,
DL, AVR::R31R30, MVT::i16,
397 if (
unsigned LPMOpc = selectIndexedProgMemLoad(LD, VT, ProgMemBank)) {
399 if (ProgMemBank == 0) {
401 CurDAG->getMachineNode(LPMOpc,
DL, VT, MVT::i16, MVT::Other,
Ptr);
405 SDValue NC = CurDAG->getTargetConstant(ProgMemBank,
DL, MVT::i8);
406 auto *NP = CurDAG->getMachineNode(AVR::LDIRdK,
DL, MVT::i8,
NC);
407 ResNode = CurDAG->getMachineNode(LPMOpc,
DL, VT, MVT::i16, MVT::Other,
414 if (ProgMemBank == 0) {
415 unsigned Opc = Subtarget->hasLPMX() ? AVR::LPMRdZ : AVR::LPMBRdZ;
416 ResNode = CurDAG->getMachineNode(
Opc,
DL, MVT::i8, MVT::Other,
Ptr);
420 SDValue NC = CurDAG->getTargetConstant(ProgMemBank,
DL, MVT::i8);
421 auto *NP = CurDAG->getMachineNode(AVR::LDIRdK,
DL, MVT::i8,
NC);
422 ResNode = CurDAG->getMachineNode(AVR::ELPMBRdZ,
DL, MVT::i8, MVT::Other,
427 if (ProgMemBank == 0) {
429 CurDAG->getMachineNode(AVR::LPMWRdZ,
DL, MVT::i16, MVT::Other,
Ptr);
433 SDValue NC = CurDAG->getTargetConstant(ProgMemBank,
DL, MVT::i8);
434 auto *NP = CurDAG->getMachineNode(AVR::LDIRdK,
DL, MVT::i8,
NC);
435 ResNode = CurDAG->getMachineNode(AVR::ELPMWRdZ,
DL, MVT::i16,
449 CurDAG->RemoveDeadNode(
N);
454template <>
bool AVRDAGToDAGISel::select<AVRISD::CALL>(
SDNode *
N) {
458 unsigned LastOpNum =
N->getNumOperands() - 1;
461 unsigned Op = Callee.getOpcode();
467 if (
N->getOperand(LastOpNum).getValueType() == MVT::Glue) {
472 Chain = CurDAG->getCopyToReg(Chain,
DL, AVR::R31R30, Callee, InGlue);
474 Ops.push_back(CurDAG->getRegister(AVR::R31R30, MVT::i16));
477 for (
unsigned i = 2, e = LastOpNum + 1; i != e; ++i) {
478 Ops.push_back(
N->getOperand(i));
481 Ops.push_back(Chain);
484 SDNode *ResNode = CurDAG->getMachineNode(
485 Subtarget->hasEIJMPCALL() ? AVR::EICALL : AVR::ICALL,
DL, MVT::Other,
490 CurDAG->RemoveDeadNode(
N);
495template <>
bool AVRDAGToDAGISel::select<ISD::BRIND>(
SDNode *
N) {
501 Chain = CurDAG->getCopyToReg(Chain,
DL, AVR::R31R30, JmpAddr);
502 SDNode *ResNode = CurDAG->getMachineNode(AVR::IJMP,
DL, MVT::Other, Chain);
505 CurDAG->RemoveDeadNode(
N);
510bool AVRDAGToDAGISel::selectMultiplication(llvm::SDNode *
N) {
512 MVT
Type =
N->getSimpleValueType(0);
514 assert(
Type == MVT::i8 &&
"unexpected value type");
517 unsigned MachineOp =
isSigned ? AVR::MULSRdRr : AVR::MULRdRr;
521 SDNode *
Mul = CurDAG->getMachineNode(MachineOp,
DL, MVT::Glue, Lhs, Rhs);
522 SDValue InChain = CurDAG->getEntryNode();
526 if (
N->hasAnyUseOfValue(0)) {
528 CurDAG->getCopyFromReg(InChain,
DL, AVR::R0,
Type, InGlue);
530 ReplaceUses(
SDValue(
N, 0), CopyFromLo);
537 if (
N->hasAnyUseOfValue(1)) {
539 CurDAG->getCopyFromReg(InChain,
DL, AVR::R1,
Type, InGlue);
541 ReplaceUses(
SDValue(
N, 1), CopyFromHi);
547 CurDAG->RemoveDeadNode(
N);
555void AVRDAGToDAGISel::Select(SDNode *
N) {
557 if (
N->isMachineOpcode()) {
571bool AVRDAGToDAGISel::trySelect(SDNode *
N) {
572 unsigned Opcode =
N->getOpcode();
582 return selectMultiplication(
N);
598 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 int 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.
@ 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.
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.