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();
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());
157 int Offs = cast<ConstantSDNode>(
LD->getOffset())->getSExtValue();
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");
201 int Offs = cast<ConstantSDNode>(
LD->getOffset())->getSExtValue();
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");
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);
261 cast<RegisterSDNode>(CopyFromRegOp->
getOperand(1));
264 AVR::PTRDISPREGSRegClass.contains(Reg));
266 CanHandleRegImmOpt =
false;
271 if (CanHandleRegImmOpt) {
274 if (RI.
getRegClass(Reg) != &AVR::PTRDISPREGSRegClass) {
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();
322 int FI = cast<FrameIndexSDNode>(
N)->getIndex();
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();
338 if (isa<FrameIndexSDNode>(BasePtr) || isa<ConstantSDNode>(BasePtr) ||
343 const RegisterSDNode *RN = dyn_cast<RegisterSDNode>(BasePtr.getOperand(0));
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();
354 SDValue Ops[] = {BasePtr.getOperand(0),
Offset, ST->getValue(), Chain};
355 unsigned Opc = (VT == MVT::i16) ? AVR::STDWSPQRr : AVR::STDSPQRr;
357 SDNode *ResNode = CurDAG->getMachineNode(Opc,
DL, MVT::Other, Ops);
360 CurDAG->setNodeMemRefs(cast<MachineSDNode>(ResNode), {ST->getMemOperand()});
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;
417 CurDAG->getMachineNode(Opc,
DL, MVT::i8, MVT::Other,
Ptr);
421 SDValue NC = CurDAG->getTargetConstant(ProgMemBank,
DL, MVT::i8);
422 auto *NP = CurDAG->getMachineNode(AVR::LDIRdK,
DL, MVT::i8,
NC);
423 ResNode = CurDAG->getMachineNode(AVR::ELPMBRdZ,
DL, MVT::i8, MVT::Other,
428 if (ProgMemBank == 0) {
430 CurDAG->getMachineNode(AVR::LPMWRdZ,
DL, MVT::i16, MVT::Other,
Ptr);
434 SDValue NC = CurDAG->getTargetConstant(ProgMemBank,
DL, MVT::i8);
435 auto *NP = CurDAG->getMachineNode(AVR::LDIRdK,
DL, MVT::i8,
NC);
436 ResNode = CurDAG->getMachineNode(AVR::ELPMWRdZ,
DL, MVT::i16,
446 CurDAG->setNodeMemRefs(cast<MachineSDNode>(ResNode), {LD->getMemOperand()});
450 CurDAG->RemoveDeadNode(
N);
455template <>
bool AVRDAGToDAGISel::select<AVRISD::CALL>(
SDNode *
N) {
459 unsigned LastOpNum =
N->getNumOperands() - 1;
462 unsigned Op = Callee.getOpcode();
468 if (
N->getOperand(LastOpNum).getValueType() == MVT::Glue) {
473 Chain = CurDAG->getCopyToReg(Chain,
DL, AVR::R31R30, Callee, InGlue);
475 Ops.
push_back(CurDAG->getRegister(AVR::R31R30, MVT::i16));
478 for (
unsigned i = 2, e = LastOpNum + 1; i != e; ++i) {
485 SDNode *ResNode = CurDAG->getMachineNode(
486 Subtarget->hasEIJMPCALL() ? AVR::EICALL : AVR::ICALL,
DL, MVT::Other,
491 CurDAG->RemoveDeadNode(
N);
496template <>
bool AVRDAGToDAGISel::select<ISD::BRIND>(
SDNode *
N) {
502 Chain = CurDAG->getCopyToReg(Chain,
DL, AVR::R31R30, JmpAddr);
503 SDNode *ResNode = CurDAG->getMachineNode(AVR::IJMP,
DL, MVT::Other, Chain);
506 CurDAG->RemoveDeadNode(
N);
513 MVT Type =
N->getSimpleValueType(0);
515 assert(
Type == MVT::i8 &&
"unexpected value type");
518 unsigned MachineOp =
isSigned ? AVR::MULSRdRr : AVR::MULRdRr;
522 SDNode *
Mul = CurDAG->getMachineNode(MachineOp,
DL, MVT::Glue, Lhs, Rhs);
523 SDValue InChain = CurDAG->getEntryNode();
527 if (
N->hasAnyUseOfValue(0)) {
529 CurDAG->getCopyFromReg(InChain,
DL, AVR::R0,
Type, InGlue);
531 ReplaceUses(
SDValue(
N, 0), CopyFromLo);
538 if (
N->hasAnyUseOfValue(1)) {
540 CurDAG->getCopyFromReg(InChain,
DL, AVR::R1,
Type, InGlue);
542 ReplaceUses(
SDValue(
N, 1), CopyFromHi);
548 CurDAG->RemoveDeadNode(
N);
556void AVRDAGToDAGISel::Select(
SDNode *
N) {
558 if (
N->isMachineOpcode()) {
572bool AVRDAGToDAGISel::trySelect(
SDNode *
N) {
573 unsigned Opcode =
N->getOpcode();
584 return selectMultiplication(
N);
600 return new AVRDAGToDAGISelLegacy(TM, OptLevel);
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)
#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.