41#define DEBUG_TYPE "m68k-isel"
42#define PASS_NAME "M68k DAG->DAG Pattern Instruction Selection"
48struct M68kISelAddressMode {
61 enum class Base { RegBase, FrameIndexBase };
81 unsigned char SymbolFlags;
83 M68kISelAddressMode(AddrType AT)
84 : AM(AT),
BaseType(Base::RegBase), Disp(0), BaseFrameIndex(0), IndexReg(),
85 Scale(1), GV(
nullptr), CP(
nullptr), BlockAddr(
nullptr), ES(
nullptr),
88 bool hasSymbolicDisplacement()
const {
89 return GV !=
nullptr || CP !=
nullptr || ES !=
nullptr ||
90 MCSym !=
nullptr || JT != -1 || BlockAddr !=
nullptr;
93 bool hasBase()
const {
94 return BaseType == Base::FrameIndexBase || BaseReg.getNode() !=
nullptr;
97 bool hasFrameIndex()
const {
return BaseType == Base::FrameIndexBase; }
99 bool hasBaseReg()
const {
100 return BaseType == Base::RegBase && BaseReg.getNode() !=
nullptr;
103 bool hasIndexReg()
const {
108 bool isDispAddrType()
const {
109 return AM == AddrType::ARII || AM == AddrType::PCI ||
110 AM == AddrType::ARID || AM == AddrType::PCD || AM == AddrType::AL;
113 unsigned getDispSize()
const {
129 bool hasDisp()
const {
return getDispSize() != 0; }
130 bool isDisp8()
const {
return getDispSize() == 8; }
131 bool isDisp16()
const {
return getDispSize() == 16; }
132 bool isDisp32()
const {
return getDispSize() == 32; }
135 bool isPCRelative()
const {
139 return RegNode->getReg() == M68k::PC;
150#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
152 dbgs() <<
"M68kISelAddressMode " <<
this;
153 dbgs() <<
"\nDisp: " << Disp;
154 dbgs() <<
", BaseReg: ";
155 if (BaseReg.getNode())
156 BaseReg.getNode()->dump();
159 dbgs() <<
", BaseFI: " << BaseFrameIndex;
160 dbgs() <<
", IndexReg: ";
165 dbgs() <<
", Scale: " << Scale;
177struct CallSeqChainInfo {
180 SDNode *Node =
nullptr;
184 bool Multiple =
false;
187static bool isCallSeqNode(
const SDNode *
N) {
191 if (
N->isMachineOpcode()) {
192 unsigned Opc =
N->getMachineOpcode();
193 return Opc == M68k::ADJCALLSTACKDOWN ||
Opc == M68k::ADJCALLSTACKUP;
198static CallSeqChainInfo getCallSeqChainInfo(
SDValue Chain) {
203 while (!Worklist.
empty()) {
205 if (!CN || !Visited.
insert(CN).second)
208 if (isCallSeqNode(CN)) {
211 else if (Found != CN)
212 return CallSeqChainInfo{
nullptr,
true};
217 if (
Op.getValueType() == MVT::Other)
223 if (
Op.getValueType() == MVT::Other) {
224 if (Worklist.
size() == 8) {
227 return CallSeqChainInfo{
nullptr,
true};
235 return CallSeqChainInfo{Found,
false};
243static bool isSafeStoreLoad(
SDNode *
N) {
252 CallSeqChainInfo LoadInfo = getCallSeqChainInfo(
LD->getChain());
253 CallSeqChainInfo
StoreInfo = getCallSeqChainInfo(
ST->getChain());
254 if (LoadInfo.Multiple ||
StoreInfo.Multiple)
263 M68kDAGToDAGISel() =
delete;
265 explicit M68kDAGToDAGISel(M68kTargetMachine &TM)
266 : SelectionDAGISel(TM), Subtarget(nullptr) {}
268 bool runOnMachineFunction(MachineFunction &MF)
override;
269 bool IsProfitableToFold(
SDValue N, SDNode *U, SDNode *Root)
const override;
274 const M68kSubtarget *Subtarget;
277#include "M68kGenDAGISel.inc"
281 const M68kTargetMachine &getTargetMachine() {
282 return static_cast<const M68kTargetMachine &
>(TM);
285 void Select(SDNode *
N)
override;
292 bool foldOffsetIntoAddress(uint64_t
Offset, M68kISelAddressMode &AM);
294 bool matchLoadInAddress(LoadSDNode *
N, M68kISelAddressMode &AM);
295 bool matchAddress(
SDValue N, M68kISelAddressMode &AM);
296 bool matchAddressBase(
SDValue N, M68kISelAddressMode &AM);
297 bool matchAddressRecursively(
SDValue N, M68kISelAddressMode &AM,
299 bool matchADD(
SDValue &
N, M68kISelAddressMode &AM,
unsigned Depth);
300 bool matchWrapper(
SDValue N, M68kISelAddressMode &AM);
302 std::pair<bool, SDNode *> selectNode(SDNode *Node);
316 bool SelectInlineAsmMemoryOperand(
const SDValue &
Op,
318 std::vector<SDValue> &OutOps)
override;
323 inline bool getFrameIndexAddress(M68kISelAddressMode &AM,
const SDLoc &
DL,
325 if (AM.BaseType == M68kISelAddressMode::Base::FrameIndexBase) {
326 Disp = getI32Imm(AM.Disp,
DL);
327 Base = CurDAG->getTargetFrameIndex(
328 AM.BaseFrameIndex, TLI->getPointerTy(CurDAG->getDataLayout()));
336 inline bool getSymbolicDisplacement(M68kISelAddressMode &AM,
const SDLoc &
DL,
339 Sym = CurDAG->getTargetGlobalAddress(AM.GV, SDLoc(), MVT::i32, AM.Disp,
345 Sym = CurDAG->getTargetConstantPool(AM.CP, MVT::i32, AM.Alignment,
346 AM.Disp, AM.SymbolFlags);
351 assert(!AM.Disp &&
"Non-zero displacement is ignored with ES.");
352 Sym = CurDAG->getTargetExternalSymbol(AM.ES, MVT::i32, AM.SymbolFlags);
357 assert(!AM.Disp &&
"Non-zero displacement is ignored with MCSym.");
358 assert(AM.SymbolFlags == 0 &&
"oo");
359 Sym = CurDAG->getMCSymbol(AM.MCSym, MVT::i32);
364 assert(!AM.Disp &&
"Non-zero displacement is ignored with JT.");
365 Sym = CurDAG->getTargetJumpTable(AM.JT, MVT::i32, AM.SymbolFlags);
370 Sym = CurDAG->getTargetBlockAddress(AM.BlockAddr, MVT::i32, AM.Disp,
379 inline SDValue getI8Imm(int64_t Imm,
const SDLoc &
DL) {
380 return CurDAG->getSignedTargetConstant(Imm,
DL, MVT::i8);
384 inline SDValue getI16Imm(int64_t Imm,
const SDLoc &
DL) {
385 return CurDAG->getSignedTargetConstant(Imm,
DL, MVT::i16);
389 inline SDValue getI32Imm(int64_t Imm,
const SDLoc &
DL) {
390 return CurDAG->getSignedTargetConstant(Imm,
DL, MVT::i32);
395 const M68kInstrInfo *getInstrInfo()
const {
396 return Subtarget->getInstrInfo();
402 SDNode *getGlobalBaseReg();
408 explicit M68kDAGToDAGISelLegacy(M68kTargetMachine &TM)
409 : SelectionDAGISelLegacy(ID, std::make_unique<M68kDAGToDAGISel>(TM)) {}
412char M68kDAGToDAGISelLegacy::ID;
424 switch (U->getOpcode()) {
453 return new M68kDAGToDAGISelLegacy(TM);
457 if (!AM.isDispAddrType())
460 return isIntN(AM.getDispSize() - 1, AM.Disp);
464 if (!AM.isDispAddrType())
466 return isIntN(AM.getDispSize(), Val);
472SDNode *M68kDAGToDAGISel::getGlobalBaseReg() {
473 unsigned GlobalBaseReg = getInstrInfo()->getGlobalBaseReg(MF);
474 auto &
DL = MF->getDataLayout();
475 return CurDAG->getRegister(GlobalBaseReg, TLI->getPointerTy(
DL)).getNode();
478bool M68kDAGToDAGISel::foldOffsetIntoAddress(uint64_t
Offset,
479 M68kISelAddressMode &AM) {
481 if (
Offset != 0 && (AM.ES || AM.MCSym))
484 int64_t Val = AM.Disp +
Offset;
500bool M68kDAGToDAGISel::matchAddressBase(
SDValue N, M68kISelAddressMode &AM) {
504 if (!AM.hasIndexReg()) {
515 AM.BaseType = M68kISelAddressMode::Base::RegBase;
521bool M68kDAGToDAGISel::matchLoadInAddress(LoadSDNode *
N,
522 M68kISelAddressMode &AM) {
526bool M68kDAGToDAGISel::matchAddressRecursively(
SDValue N,
527 M68kISelAddressMode &AM,
533 return matchAddressBase(
N, AM);
538 if (AM.isPCRelative()) {
544 if (foldOffsetIntoAddress(Cst->getSExtValue(), AM))
549 switch (
N.getOpcode()) {
555 if (foldOffsetIntoAddress(Val, AM))
560 case M68kISD::Wrapper:
561 case M68kISD::WrapperPC:
562 if (matchWrapper(
N, AM))
578 if (CurDAG->haveNoCommonBitsSet(
N.getOperand(0),
N.getOperand(1)) &&
584 if (matchADD(
N, AM,
Depth))
589 if (AM.isDispAddrType() &&
590 AM.BaseType == M68kISelAddressMode::Base::RegBase &&
592 AM.BaseType = M68kISelAddressMode::Base::FrameIndexBase;
606 return matchAddressBase(
N, AM);
611bool M68kDAGToDAGISel::matchAddress(
SDValue N, M68kISelAddressMode &AM) {
619 return matchAddressRecursively(
N, AM, 0);
622bool M68kDAGToDAGISel::matchADD(
SDValue &
N, M68kISelAddressMode &AM,
626 HandleSDNode Handle(
N);
628 M68kISelAddressMode Backup = AM;
629 if (matchAddressRecursively(
N.getOperand(0), AM,
Depth + 1) &&
630 matchAddressRecursively(Handle.getValue().getOperand(1), AM,
Depth + 1)) {
636 if (matchAddressRecursively(Handle.getValue().getOperand(1), AM,
Depth + 1) &&
637 matchAddressRecursively(Handle.getValue().getOperand(0), AM,
Depth + 1)) {
645 if (!AM.hasBase() && !AM.hasIndexReg()) {
646 N = Handle.getValue();
653 N = Handle.getValue();
661bool M68kDAGToDAGISel::matchWrapper(
SDValue N, M68kISelAddressMode &AM) {
664 if (AM.hasSymbolicDisplacement())
669 if (
N.getOpcode() == M68kISD::WrapperPC) {
672 M68kISelAddressMode Backup = AM;
679 AM.GV =
G->getGlobal();
680 AM.SymbolFlags =
G->getTargetFlags();
681 if (!foldOffsetIntoAddress(
G->getOffset(), AM)) {
686 AM.CP = CP->getConstVal();
687 AM.Alignment = CP->getAlign();
688 AM.SymbolFlags = CP->getTargetFlags();
689 if (!foldOffsetIntoAddress(CP->getOffset(), AM)) {
694 AM.ES = S->getSymbol();
695 AM.SymbolFlags = S->getTargetFlags();
697 AM.MCSym = S->getMCSymbol();
699 AM.JT = J->getIndex();
700 AM.SymbolFlags = J->getTargetFlags();
702 AM.BlockAddr = BA->getBlockAddress();
703 AM.SymbolFlags = BA->getTargetFlags();
704 if (!foldOffsetIntoAddress(BA->getOffset(), AM)) {
711 AM.setBaseReg(CurDAG->getRegister(M68k::PC, MVT::i32));
716 if (!AM.isDisp32()) {
720 if (
N.getOpcode() == M68kISD::Wrapper) {
722 AM.GV =
G->getGlobal();
723 AM.Disp +=
G->getOffset();
724 AM.SymbolFlags =
G->getTargetFlags();
726 AM.CP = CP->getConstVal();
727 AM.Alignment = CP->getAlign();
728 AM.Disp += CP->getOffset();
729 AM.SymbolFlags = CP->getTargetFlags();
731 AM.ES = S->getSymbol();
732 AM.SymbolFlags = S->getTargetFlags();
734 AM.MCSym = S->getMCSymbol();
736 AM.JT = J->getIndex();
737 AM.SymbolFlags = J->getTargetFlags();
739 AM.BlockAddr = BA->getBlockAddress();
740 AM.Disp += BA->getOffset();
741 AM.SymbolFlags = BA->getTargetFlags();
754void M68kDAGToDAGISel::Select(SDNode *Node) {
755 unsigned Opcode =
Node->getOpcode();
760 if (
Node->isMachineOpcode()) {
771 SDValue GOT = CurDAG->getTargetExternalSymbol(
774 CurDAG->getMachineNode(M68k::LEA32q,
DL, MVT::i32, GOT);
775 ReplaceNode(Node, Res);
779 case M68kISD::GLOBAL_BASE_REG:
780 ReplaceNode(Node, getGlobalBaseReg());
813bool M68kDAGToDAGISel::SelectARID(SDNode *Parent,
SDValue N,
SDValue &Disp,
816 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARID);
818 if (!matchAddress(
N, AM))
821 if (AM.isPCRelative()) {
822 LLVM_DEBUG(
dbgs() <<
"REJECT: Cannot match PC relative address\n");
827 if (getFrameIndexAddress(AM, SDLoc(
N), Disp,
Base)) {
832 if (AM.hasIndexReg()) {
837 if (!AM.hasBaseReg()) {
844 if (getSymbolicDisplacement(AM, SDLoc(
N), Disp)) {
846 "Should not be any displacement");
857 Disp = getI16Imm(AM.Disp, SDLoc(
N));
864 switch (
N.getOpcode()) {
868 [](
const SDUse &U) { return isAddressBase(U.get()); });
869 case M68kISD::Wrapper:
870 case M68kISD::WrapperPC:
871 case M68kISD::GLOBAL_BASE_REG:
893bool M68kDAGToDAGISel::SelectARII(SDNode *Parent,
SDValue N,
SDValue &Disp,
895 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARII);
898 if (!matchAddress(
N, AM))
901 if (AM.isPCRelative()) {
906 if (!AM.hasIndexReg()) {
911 if (!AM.hasBaseReg()) {
924 if (AM.hasSymbolicDisplacement()) {
925 LLVM_DEBUG(
dbgs() <<
"REJECT, Cannot match symbolic displacement\n");
937 Disp = getI8Imm(AM.Disp, SDLoc(
N));
943bool M68kDAGToDAGISel::SelectAL(SDNode *Parent,
SDValue N,
SDValue &Sym) {
945 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::AL);
947 if (!matchAddress(
N, AM)) {
952 if (AM.isPCRelative()) {
953 LLVM_DEBUG(
dbgs() <<
"REJECT: Cannot match PC relative address\n");
962 if (AM.hasIndexReg()) {
967 if (getSymbolicDisplacement(AM, SDLoc(
N), Sym)) {
973 Sym = getI32Imm(AM.Disp, SDLoc(
N));
983bool M68kDAGToDAGISel::SelectPCD(SDNode *Parent,
SDValue N,
SDValue &Disp) {
985 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::PCD);
987 if (!matchAddress(
N, AM))
990 if (!AM.isPCRelative()) {
995 if (AM.hasIndexReg()) {
1000 if (getSymbolicDisplacement(AM, SDLoc(
N), Disp)) {
1005 Disp = getI16Imm(AM.Disp, SDLoc(
N));
1011bool M68kDAGToDAGISel::SelectPCI(SDNode *Parent,
SDValue N,
SDValue &Disp,
1014 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::PCI);
1016 if (!matchAddress(
N, AM))
1019 if (!AM.isPCRelative()) {
1024 if (!AM.hasIndexReg()) {
1029 Index = AM.IndexReg;
1031 if (getSymbolicDisplacement(AM, SDLoc(
N), Disp)) {
1032 assert(!AM.Disp &&
"Should not be any displacement");
1037 Disp = getI8Imm(AM.Disp, SDLoc(
N));
1043bool M68kDAGToDAGISel::SelectPCIBD(SDNode *Parent,
SDValue N,
SDValue &Disp,
1047 if (SelectPCI(Parent,
N, Disp, Index)) {
1048 Scale = CurDAG->getTargetConstant(1, SDLoc(
N), MVT::i8);
1055 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARI);
1057 if (!matchAddress(
N, AM)) {
1062 if (AM.isPCRelative()) {
1063 LLVM_DEBUG(
dbgs() <<
"REJECT: Cannot match PC relative address\n");
1068 if (AM.hasIndexReg() || AM.Disp != 0) {
1074 if (AM.hasSymbolicDisplacement()) {
1079 if (AM.hasBaseReg()) {
1088bool M68kDAGToDAGISel::SelectInlineAsmMemoryOperand(
1090 std::vector<SDValue> &OutOps) {
1096 auto addKind = [
this](
SDValue &Opnd, AMK
Kind) ->
bool {
1097 Opnd = CurDAG->getTargetConstant(
unsigned(Kind), SDLoc(), MVT::i32);
1101 switch (ConstraintID) {
1103 case InlineAsm::ConstraintCode::m: {
1110 if (SelectARII(
nullptr,
Op, Operands[1], Operands[2], Operands[3]) &&
1111 addKind(Operands[0], AMK::f)) {
1112 OutOps.insert(OutOps.end(), &Operands[0], Operands + 4);
1116 if ((SelectPCI(
nullptr,
Op, Operands[1], Operands[2]) &&
1117 addKind(Operands[0], AMK::k)) ||
1118 (SelectARID(
nullptr,
Op, Operands[1], Operands[2]) &&
1119 addKind(Operands[0], AMK::p))) {
1120 OutOps.insert(OutOps.end(), &Operands[0], Operands + 3);
1124 if ((SelectPCD(
nullptr,
Op, Operands[1]) && addKind(Operands[0], AMK::q)) ||
1125 (SelectARI(
nullptr,
Op, Operands[1]) && addKind(Operands[0], AMK::j)) ||
1126 (SelectAL(
nullptr,
Op, Operands[1]) && addKind(Operands[0], AMK::b))) {
1127 OutOps.insert(OutOps.end(), {Operands[0], Operands[1]});
1134 case InlineAsm::ConstraintCode::Q: {
1139 if (SelectARI(
nullptr,
Op,
Base) && addKind(AMKind, AMK::j)) {
1140 OutOps.insert(OutOps.end(), {AMKind, Base});
1146 case InlineAsm::ConstraintCode::Um: {
1149 if (SelectARID(
nullptr,
Op,
Offset,
Base) && addKind(AMKind, AMK::p)) {
1150 OutOps.insert(OutOps.end(), {AMKind, Offset, Base});
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU Register Bank Select
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
This file provides various utilities for inspecting and working with the control flow graph in LLVM I...
static bool doesDispFit(M68kISelAddressMode &AM, int64_t Val)
static bool allowARIDWithDisp(SDNode *Parent)
static bool doesDispFitFI(M68kISelAddressMode &AM)
static bool isAddressBase(const SDValue &N)
static bool AllowARIIWithZeroDisp(SDNode *Parent)
This file declares the M68k specific subclass of MachineFunctionInfo.
This file contains the M68k implementation of the TargetRegisterInfo class.
This file declares the M68k specific subclass of TargetMachine.
This file contains the entry points for global functions defined in the M68k target library,...
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
BaseType
A given derived pointer can have multiple base pointers through phi/selects.
static bool initGlobalBaseReg(MachineFunction &MF)
The address of a basic block.
This is an important base class in LLVM.
FunctionPass class - This class is used to implement most global optimizations.
unsigned getTargetFlags() const
const GlobalValue * getGlobal() const
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Represents one node in the SelectionDAG.
LLVM_ABI void dump() const
Dump this node, for debugging.
unsigned getOpcode() const
Return the SelectionDAG opcode value for this node.
iterator_range< value_op_iterator > op_values() const
Represents a use of a SDNode.
Unlike LLVM values, Selection DAG nodes may return multiple values as the result of a computation.
SDNode * getNode() const
get the SDNode which holds the desired result
const SDValue & getOperand(unsigned i) const
SelectionDAGISel - This is the common base class used for SelectionDAG-based pattern-matching instruc...
virtual bool runOnMachineFunction(MachineFunction &mf)
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ ATOMIC_STORE
OUTCHAIN = ATOMIC_STORE(INCHAIN, val, ptr) This corresponds to "store atomic" instruction.
@ ADDC
Carry-setting nodes for multiple precision addition and subtraction.
@ 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...
@ ATOMIC_LOAD
Val, OUTCHAIN = ATOMIC_LOAD(INCHAIN, ptr) This corresponds to "load atomic" instruction.
@ ATOMIC_CMP_SWAP
Val, OUTCHAIN = ATOMIC_CMP_SWAP(INCHAIN, ptr, cmp, swap) For double-word atomic operations: ValLo,...
@ GLOBAL_OFFSET_TABLE
The address of the GOT.
@ TokenFactor
TokenFactor - This node takes multiple tokens as input and produces a single token result.
@ CALLSEQ_START
CALLSEQ_START/CALLSEQ_END - These operators mark the beginning and end of a call sequence,...
@ MO_GOTPCREL
On a symbol operand this indicates that the immediate is offset to the GOT entry for the symbol name ...
@ GlobalBaseReg
The result of the mflr at function entry, used for PIC code.
NodeAddr< NodeBase * > Node
This is an optimization pass for GlobalISel generic memory operations.
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
LLVM_ABI bool isNullConstant(SDValue V)
Returns true if V is a constant integer zero.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
auto dyn_cast_or_null(const Y &Val)
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
FunctionPass * createM68kISelDag(M68kTargetMachine &TM)
This pass converts a legalized DAG into a M68k-specific DAG, ready for instruction scheduling.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
constexpr bool isIntN(unsigned N, int64_t x)
Checks if an signed integer fits into the given (dynamic) bit width.
This struct is a compact representation of a valid (non-zero power of two) alignment.