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;
290 void initGlobalBaseReg(MachineFunction &MF);
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);
314 bool SelectInlineAsmMemoryOperand(
const SDValue &
Op,
316 std::vector<SDValue> &OutOps)
override;
321 inline bool getFrameIndexAddress(M68kISelAddressMode &AM,
const SDLoc &
DL,
323 if (AM.BaseType == M68kISelAddressMode::Base::FrameIndexBase) {
324 Disp = getI32Imm(AM.Disp,
DL);
325 Base = CurDAG->getTargetFrameIndex(
326 AM.BaseFrameIndex, TLI->getPointerTy(CurDAG->getDataLayout()));
334 inline bool getSymbolicDisplacement(M68kISelAddressMode &AM,
const SDLoc &
DL,
337 Sym = CurDAG->getTargetGlobalAddress(AM.GV, SDLoc(), MVT::i32, AM.Disp,
343 Sym = CurDAG->getTargetConstantPool(AM.CP, MVT::i32, AM.Alignment,
344 AM.Disp, AM.SymbolFlags);
349 assert(!AM.Disp &&
"Non-zero displacement is ignored with ES.");
350 Sym = CurDAG->getTargetExternalSymbol(AM.ES, MVT::i32, AM.SymbolFlags);
355 assert(!AM.Disp &&
"Non-zero displacement is ignored with MCSym.");
356 assert(AM.SymbolFlags == 0 &&
"oo");
357 Sym = CurDAG->getMCSymbol(AM.MCSym, MVT::i32);
362 assert(!AM.Disp &&
"Non-zero displacement is ignored with JT.");
363 Sym = CurDAG->getTargetJumpTable(AM.JT, MVT::i32, AM.SymbolFlags);
368 Sym = CurDAG->getTargetBlockAddress(AM.BlockAddr, MVT::i32, AM.Disp,
377 inline SDValue getI8Imm(int64_t Imm,
const SDLoc &
DL) {
378 return CurDAG->getSignedTargetConstant(Imm,
DL, MVT::i8);
382 inline SDValue getI16Imm(int64_t Imm,
const SDLoc &
DL) {
383 return CurDAG->getSignedTargetConstant(Imm,
DL, MVT::i16);
387 inline SDValue getI32Imm(int64_t Imm,
const SDLoc &
DL) {
388 return CurDAG->getSignedTargetConstant(Imm,
DL, MVT::i32);
393 const M68kInstrInfo *getInstrInfo()
const {
394 return Subtarget->getInstrInfo();
400 SDNode *getGlobalBaseReg();
406 explicit M68kDAGToDAGISelLegacy(M68kTargetMachine &TM)
407 : SelectionDAGISelLegacy(ID, std::make_unique<M68kDAGToDAGISel>(TM)) {}
410char M68kDAGToDAGISelLegacy::ID;
422 switch (U->getOpcode()) {
451 return new M68kDAGToDAGISelLegacy(TM);
455 if (!AM.isDispAddrType())
458 return isIntN(AM.getDispSize() - 1, AM.Disp);
462 if (!AM.isDispAddrType())
464 return isIntN(AM.getDispSize(), Val);
470SDNode *M68kDAGToDAGISel::getGlobalBaseReg() {
471 unsigned GlobalBaseReg = getInstrInfo()->getGlobalBaseReg(MF);
472 auto &
DL = MF->getDataLayout();
473 return CurDAG->getRegister(GlobalBaseReg, TLI->getPointerTy(
DL)).getNode();
476bool M68kDAGToDAGISel::foldOffsetIntoAddress(uint64_t
Offset,
477 M68kISelAddressMode &AM) {
479 if (
Offset != 0 && (AM.ES || AM.MCSym))
482 int64_t Val = AM.Disp +
Offset;
498bool M68kDAGToDAGISel::matchAddressBase(
SDValue N, M68kISelAddressMode &AM) {
502 if (!AM.hasIndexReg()) {
513 AM.BaseType = M68kISelAddressMode::Base::RegBase;
519bool M68kDAGToDAGISel::matchLoadInAddress(LoadSDNode *
N,
520 M68kISelAddressMode &AM) {
524bool M68kDAGToDAGISel::matchAddressRecursively(
SDValue N,
525 M68kISelAddressMode &AM,
531 return matchAddressBase(
N, AM);
536 if (AM.isPCRelative()) {
542 if (foldOffsetIntoAddress(Cst->getSExtValue(), AM))
547 switch (
N.getOpcode()) {
553 if (foldOffsetIntoAddress(Val, AM))
558 case M68kISD::Wrapper:
559 case M68kISD::WrapperPC:
560 if (matchWrapper(
N, AM))
576 if (CurDAG->haveNoCommonBitsSet(
N.getOperand(0),
N.getOperand(1)) &&
582 if (matchADD(
N, AM,
Depth))
587 if (AM.isDispAddrType() &&
588 AM.BaseType == M68kISelAddressMode::Base::RegBase &&
590 AM.BaseType = M68kISelAddressMode::Base::FrameIndexBase;
604 return matchAddressBase(
N, AM);
609bool M68kDAGToDAGISel::matchAddress(
SDValue N, M68kISelAddressMode &AM) {
617 return matchAddressRecursively(
N, AM, 0);
620bool M68kDAGToDAGISel::matchADD(
SDValue &
N, M68kISelAddressMode &AM,
624 HandleSDNode Handle(
N);
626 M68kISelAddressMode Backup = AM;
627 if (matchAddressRecursively(
N.getOperand(0), AM,
Depth + 1) &&
628 matchAddressRecursively(Handle.getValue().getOperand(1), AM,
Depth + 1)) {
634 if (matchAddressRecursively(Handle.getValue().getOperand(1), AM,
Depth + 1) &&
635 matchAddressRecursively(Handle.getValue().getOperand(0), AM,
Depth + 1)) {
643 if (!AM.hasBase() && !AM.hasIndexReg()) {
644 N = Handle.getValue();
651 N = Handle.getValue();
659bool M68kDAGToDAGISel::matchWrapper(
SDValue N, M68kISelAddressMode &AM) {
662 if (AM.hasSymbolicDisplacement())
667 if (
N.getOpcode() == M68kISD::WrapperPC) {
670 M68kISelAddressMode Backup = AM;
677 AM.GV =
G->getGlobal();
678 AM.SymbolFlags =
G->getTargetFlags();
679 if (!foldOffsetIntoAddress(
G->getOffset(), AM)) {
684 AM.CP = CP->getConstVal();
685 AM.Alignment = CP->getAlign();
686 AM.SymbolFlags = CP->getTargetFlags();
687 if (!foldOffsetIntoAddress(CP->getOffset(), AM)) {
692 AM.ES = S->getSymbol();
693 AM.SymbolFlags = S->getTargetFlags();
695 AM.MCSym = S->getMCSymbol();
697 AM.JT = J->getIndex();
698 AM.SymbolFlags = J->getTargetFlags();
700 AM.BlockAddr = BA->getBlockAddress();
701 AM.SymbolFlags = BA->getTargetFlags();
702 if (!foldOffsetIntoAddress(BA->getOffset(), AM)) {
709 AM.setBaseReg(CurDAG->getRegister(M68k::PC, MVT::i32));
714 if (!AM.isDisp32()) {
718 if (
N.getOpcode() == M68kISD::Wrapper) {
720 AM.GV =
G->getGlobal();
721 AM.Disp +=
G->getOffset();
722 AM.SymbolFlags =
G->getTargetFlags();
724 AM.CP = CP->getConstVal();
725 AM.Alignment = CP->getAlign();
726 AM.Disp += CP->getOffset();
727 AM.SymbolFlags = CP->getTargetFlags();
729 AM.ES = S->getSymbol();
730 AM.SymbolFlags = S->getTargetFlags();
732 AM.MCSym = S->getMCSymbol();
734 AM.JT = J->getIndex();
735 AM.SymbolFlags = J->getTargetFlags();
737 AM.BlockAddr = BA->getBlockAddress();
738 AM.Disp += BA->getOffset();
739 AM.SymbolFlags = BA->getTargetFlags();
752void M68kDAGToDAGISel::Select(SDNode *Node) {
753 unsigned Opcode =
Node->getOpcode();
758 if (
Node->isMachineOpcode()) {
769 SDValue GOT = CurDAG->getTargetExternalSymbol(
772 CurDAG->getMachineNode(M68k::LEA32q,
DL, MVT::i32, GOT);
773 ReplaceNode(Node, Res);
777 case M68kISD::GLOBAL_BASE_REG:
778 ReplaceNode(Node, getGlobalBaseReg());
811bool M68kDAGToDAGISel::SelectARID(SDNode *Parent,
SDValue N,
SDValue &Disp,
814 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARID);
816 if (!matchAddress(
N, AM))
819 if (AM.isPCRelative()) {
820 LLVM_DEBUG(
dbgs() <<
"REJECT: Cannot match PC relative address\n");
825 if (getFrameIndexAddress(AM, SDLoc(
N), Disp,
Base)) {
830 if (AM.hasIndexReg()) {
835 if (!AM.hasBaseReg()) {
842 if (getSymbolicDisplacement(AM, SDLoc(
N), Disp)) {
844 "Should not be any displacement");
855 Disp = getI16Imm(AM.Disp, SDLoc(
N));
862 switch (
N.getOpcode()) {
866 [](
const SDUse &U) { return isAddressBase(U.get()); });
867 case M68kISD::Wrapper:
868 case M68kISD::WrapperPC:
869 case M68kISD::GLOBAL_BASE_REG:
891bool M68kDAGToDAGISel::SelectARII(SDNode *Parent,
SDValue N,
SDValue &Disp,
893 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARII);
896 if (!matchAddress(
N, AM))
899 if (AM.isPCRelative()) {
904 if (!AM.hasIndexReg()) {
909 if (!AM.hasBaseReg()) {
922 if (AM.hasSymbolicDisplacement()) {
923 LLVM_DEBUG(
dbgs() <<
"REJECT, Cannot match symbolic displacement\n");
935 Disp = getI8Imm(AM.Disp, SDLoc(
N));
941bool M68kDAGToDAGISel::SelectAL(SDNode *Parent,
SDValue N,
SDValue &Sym) {
943 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::AL);
945 if (!matchAddress(
N, AM)) {
950 if (AM.isPCRelative()) {
951 LLVM_DEBUG(
dbgs() <<
"REJECT: Cannot match PC relative address\n");
960 if (AM.hasIndexReg()) {
965 if (getSymbolicDisplacement(AM, SDLoc(
N), Sym)) {
971 Sym = getI32Imm(AM.Disp, SDLoc(
N));
981bool M68kDAGToDAGISel::SelectPCD(SDNode *Parent,
SDValue N,
SDValue &Disp) {
983 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::PCD);
985 if (!matchAddress(
N, AM))
988 if (!AM.isPCRelative()) {
993 if (AM.hasIndexReg()) {
998 if (getSymbolicDisplacement(AM, SDLoc(
N), Disp)) {
1003 Disp = getI16Imm(AM.Disp, SDLoc(
N));
1009bool M68kDAGToDAGISel::SelectPCI(SDNode *Parent,
SDValue N,
SDValue &Disp,
1012 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::PCI);
1014 if (!matchAddress(
N, AM))
1017 if (!AM.isPCRelative()) {
1022 if (!AM.hasIndexReg()) {
1027 Index = AM.IndexReg;
1029 if (getSymbolicDisplacement(AM, SDLoc(
N), Disp)) {
1030 assert(!AM.Disp &&
"Should not be any displacement");
1035 Disp = getI8Imm(AM.Disp, SDLoc(
N));
1043 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARI);
1045 if (!matchAddress(
N, AM)) {
1050 if (AM.isPCRelative()) {
1051 LLVM_DEBUG(
dbgs() <<
"REJECT: Cannot match PC relative address\n");
1056 if (AM.hasIndexReg() || AM.Disp != 0) {
1062 if (AM.hasSymbolicDisplacement()) {
1067 if (AM.hasBaseReg()) {
1076bool M68kDAGToDAGISel::SelectInlineAsmMemoryOperand(
1078 std::vector<SDValue> &OutOps) {
1084 auto addKind = [
this](
SDValue &Opnd, AMK
Kind) ->
bool {
1085 Opnd = CurDAG->getTargetConstant(
unsigned(Kind), SDLoc(), MVT::i32);
1089 switch (ConstraintID) {
1091 case InlineAsm::ConstraintCode::m: {
1098 if (SelectARII(
nullptr,
Op, Operands[1], Operands[2], Operands[3]) &&
1099 addKind(Operands[0], AMK::f)) {
1100 OutOps.insert(OutOps.end(), &Operands[0], Operands + 4);
1104 if ((SelectPCI(
nullptr,
Op, Operands[1], Operands[2]) &&
1105 addKind(Operands[0], AMK::k)) ||
1106 (SelectARID(
nullptr,
Op, Operands[1], Operands[2]) &&
1107 addKind(Operands[0], AMK::p))) {
1108 OutOps.insert(OutOps.end(), &Operands[0], Operands + 3);
1112 if ((SelectPCD(
nullptr,
Op, Operands[1]) && addKind(Operands[0], AMK::q)) ||
1113 (SelectARI(
nullptr,
Op, Operands[1]) && addKind(Operands[0], AMK::j)) ||
1114 (SelectAL(
nullptr,
Op, Operands[1]) && addKind(Operands[0], AMK::b))) {
1115 OutOps.insert(OutOps.end(), {Operands[0], Operands[1]});
1122 case InlineAsm::ConstraintCode::Q: {
1127 if (SelectARI(
nullptr,
Op,
Base) && addKind(AMKind, AMK::j)) {
1128 OutOps.insert(OutOps.end(), {AMKind, Base});
1134 case InlineAsm::ConstraintCode::Um: {
1137 if (SelectARID(
nullptr,
Op,
Offset,
Base) && addKind(AMKind, AMK::p)) {
1138 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.
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.