xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/M68k/M68kISelDAGToDAG.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
104eeddc0SDimitry Andric //===-- M68kISelDAGToDAG.cpp - M68k Dag to Dag Inst Selector ----*- C++ -*-===//
2fe6060f1SDimitry Andric //
3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fe6060f1SDimitry Andric //
7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
8fe6060f1SDimitry Andric ///
9fe6060f1SDimitry Andric /// \file
10fe6060f1SDimitry Andric /// This file defines an instruction selector for the M68K target.
11fe6060f1SDimitry Andric ///
12fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
13fe6060f1SDimitry Andric 
14fe6060f1SDimitry Andric #include "M68k.h"
15fe6060f1SDimitry Andric 
16fe6060f1SDimitry Andric #include "M68kMachineFunction.h"
17fe6060f1SDimitry Andric #include "M68kRegisterInfo.h"
18fe6060f1SDimitry Andric #include "M68kTargetMachine.h"
19fe6060f1SDimitry Andric 
20fe6060f1SDimitry Andric #include "llvm/CodeGen/MachineConstantPool.h"
21fe6060f1SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
22fe6060f1SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
23fe6060f1SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
24fe6060f1SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
25fe6060f1SDimitry Andric #include "llvm/CodeGen/SelectionDAGISel.h"
26fe6060f1SDimitry Andric #include "llvm/CodeGen/SelectionDAGNodes.h"
27fe6060f1SDimitry Andric #include "llvm/IR/CFG.h"
28fe6060f1SDimitry Andric #include "llvm/IR/GlobalValue.h"
29fe6060f1SDimitry Andric #include "llvm/IR/Instructions.h"
30fe6060f1SDimitry Andric #include "llvm/IR/Intrinsics.h"
31fe6060f1SDimitry Andric #include "llvm/IR/Type.h"
32fe6060f1SDimitry Andric #include "llvm/Support/Alignment.h"
33fe6060f1SDimitry Andric #include "llvm/Support/Debug.h"
34fe6060f1SDimitry Andric #include "llvm/Support/ErrorHandling.h"
35fe6060f1SDimitry Andric #include "llvm/Support/MathExtras.h"
36fe6060f1SDimitry Andric #include "llvm/Support/raw_ostream.h"
37fe6060f1SDimitry Andric #include "llvm/Target/TargetMachine.h"
38fe6060f1SDimitry Andric 
39fe6060f1SDimitry Andric using namespace llvm;
40fe6060f1SDimitry Andric 
41fe6060f1SDimitry Andric #define DEBUG_TYPE "m68k-isel"
42bdd1243dSDimitry Andric #define PASS_NAME "M68k DAG->DAG Pattern Instruction Selection"
43fe6060f1SDimitry Andric 
44fe6060f1SDimitry Andric namespace {
45fe6060f1SDimitry Andric 
46fe6060f1SDimitry Andric // For reference, the full order of operands for memory references is:
47fe6060f1SDimitry Andric // (Operand), Displacement, Base, Index, Scale
48fe6060f1SDimitry Andric struct M68kISelAddressMode {
49fe6060f1SDimitry Andric   enum class AddrType {
50fe6060f1SDimitry Andric     ARI,   // Address Register Indirect
51fe6060f1SDimitry Andric     ARIPI, // Address Register Indirect with Postincrement
52fe6060f1SDimitry Andric     ARIPD, // Address Register Indirect with Postdecrement
53fe6060f1SDimitry Andric     ARID,  // Address Register Indirect with Displacement
54fe6060f1SDimitry Andric     ARII,  // Address Register Indirect with Index
55fe6060f1SDimitry Andric     PCD,   // Program Counter Indirect with Displacement
56fe6060f1SDimitry Andric     PCI,   // Program Counter Indirect with Index
57fe6060f1SDimitry Andric     AL,    // Absolute
58fe6060f1SDimitry Andric   };
59fe6060f1SDimitry Andric   AddrType AM;
60fe6060f1SDimitry Andric 
61fe6060f1SDimitry Andric   enum class Base { RegBase, FrameIndexBase };
62fe6060f1SDimitry Andric   Base BaseType;
63fe6060f1SDimitry Andric 
64fe6060f1SDimitry Andric   int64_t Disp;
65fe6060f1SDimitry Andric 
66fe6060f1SDimitry Andric   // This is really a union, discriminated by BaseType!
67fe6060f1SDimitry Andric   SDValue BaseReg;
68fe6060f1SDimitry Andric   int BaseFrameIndex;
69fe6060f1SDimitry Andric 
70fe6060f1SDimitry Andric   SDValue IndexReg;
71fe6060f1SDimitry Andric   unsigned Scale;
72fe6060f1SDimitry Andric 
73fe6060f1SDimitry Andric   const GlobalValue *GV;
74fe6060f1SDimitry Andric   const Constant *CP;
75fe6060f1SDimitry Andric   const BlockAddress *BlockAddr;
76fe6060f1SDimitry Andric   const char *ES;
77fe6060f1SDimitry Andric   MCSymbol *MCSym;
78fe6060f1SDimitry Andric   int JT;
79fe6060f1SDimitry Andric   Align Alignment; // CP alignment.
80fe6060f1SDimitry Andric 
81fe6060f1SDimitry Andric   unsigned char SymbolFlags; // M68kII::MO_*
82fe6060f1SDimitry Andric 
83fe6060f1SDimitry Andric   M68kISelAddressMode(AddrType AT)
84fe6060f1SDimitry Andric       : AM(AT), BaseType(Base::RegBase), Disp(0), BaseFrameIndex(0), IndexReg(),
85fe6060f1SDimitry Andric         Scale(1), GV(nullptr), CP(nullptr), BlockAddr(nullptr), ES(nullptr),
86fe6060f1SDimitry Andric         MCSym(nullptr), JT(-1), Alignment(), SymbolFlags(M68kII::MO_NO_FLAG) {}
87fe6060f1SDimitry Andric 
88fe6060f1SDimitry Andric   bool hasSymbolicDisplacement() const {
89fe6060f1SDimitry Andric     return GV != nullptr || CP != nullptr || ES != nullptr ||
90fe6060f1SDimitry Andric            MCSym != nullptr || JT != -1 || BlockAddr != nullptr;
91fe6060f1SDimitry Andric   }
92fe6060f1SDimitry Andric 
93fe6060f1SDimitry Andric   bool hasBase() const {
94fe6060f1SDimitry Andric     return BaseType == Base::FrameIndexBase || BaseReg.getNode() != nullptr;
95fe6060f1SDimitry Andric   }
96fe6060f1SDimitry Andric 
97fe6060f1SDimitry Andric   bool hasFrameIndex() const { return BaseType == Base::FrameIndexBase; }
98fe6060f1SDimitry Andric 
99fe6060f1SDimitry Andric   bool hasBaseReg() const {
100fe6060f1SDimitry Andric     return BaseType == Base::RegBase && BaseReg.getNode() != nullptr;
101fe6060f1SDimitry Andric   }
102fe6060f1SDimitry Andric 
103fe6060f1SDimitry Andric   bool hasIndexReg() const {
104fe6060f1SDimitry Andric     return BaseType == Base::RegBase && IndexReg.getNode() != nullptr;
105fe6060f1SDimitry Andric   }
106fe6060f1SDimitry Andric 
107fe6060f1SDimitry Andric   /// True if address mode type supports displacement
108fe6060f1SDimitry Andric   bool isDispAddrType() const {
109fe6060f1SDimitry Andric     return AM == AddrType::ARII || AM == AddrType::PCI ||
110fe6060f1SDimitry Andric            AM == AddrType::ARID || AM == AddrType::PCD || AM == AddrType::AL;
111fe6060f1SDimitry Andric   }
112fe6060f1SDimitry Andric 
113fe6060f1SDimitry Andric   unsigned getDispSize() const {
114fe6060f1SDimitry Andric     switch (AM) {
115fe6060f1SDimitry Andric     default:
116fe6060f1SDimitry Andric       return 0;
117fe6060f1SDimitry Andric     case AddrType::ARII:
118fe6060f1SDimitry Andric     case AddrType::PCI:
119fe6060f1SDimitry Andric       return 8;
120fe6060f1SDimitry Andric     // These two in the next chip generations can hold upto 32 bit
121fe6060f1SDimitry Andric     case AddrType::ARID:
122fe6060f1SDimitry Andric     case AddrType::PCD:
123fe6060f1SDimitry Andric       return 16;
124fe6060f1SDimitry Andric     case AddrType::AL:
125fe6060f1SDimitry Andric       return 32;
126fe6060f1SDimitry Andric     }
127fe6060f1SDimitry Andric   }
128fe6060f1SDimitry Andric 
129fe6060f1SDimitry Andric   bool hasDisp() const { return getDispSize() != 0; }
130fe6060f1SDimitry Andric   bool isDisp8() const { return getDispSize() == 8; }
131fe6060f1SDimitry Andric   bool isDisp16() const { return getDispSize() == 16; }
132fe6060f1SDimitry Andric   bool isDisp32() const { return getDispSize() == 32; }
133fe6060f1SDimitry Andric 
134fe6060f1SDimitry Andric   /// Return true if this addressing mode is already PC-relative.
135fe6060f1SDimitry Andric   bool isPCRelative() const {
136fe6060f1SDimitry Andric     if (BaseType != Base::RegBase)
137fe6060f1SDimitry Andric       return false;
138fe6060f1SDimitry Andric     if (auto *RegNode = dyn_cast_or_null<RegisterSDNode>(BaseReg.getNode()))
139fe6060f1SDimitry Andric       return RegNode->getReg() == M68k::PC;
140fe6060f1SDimitry Andric     return false;
141fe6060f1SDimitry Andric   }
142fe6060f1SDimitry Andric 
143fe6060f1SDimitry Andric   void setBaseReg(SDValue Reg) {
144fe6060f1SDimitry Andric     BaseType = Base::RegBase;
145fe6060f1SDimitry Andric     BaseReg = Reg;
146fe6060f1SDimitry Andric   }
147fe6060f1SDimitry Andric 
148fe6060f1SDimitry Andric   void setIndexReg(SDValue Reg) { IndexReg = Reg; }
149fe6060f1SDimitry Andric 
150fe6060f1SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
151fe6060f1SDimitry Andric   void dump() {
152fe6060f1SDimitry Andric     dbgs() << "M68kISelAddressMode " << this;
153fe6060f1SDimitry Andric     dbgs() << "\nDisp: " << Disp;
154fe6060f1SDimitry Andric     dbgs() << ", BaseReg: ";
155fe6060f1SDimitry Andric     if (BaseReg.getNode())
156fe6060f1SDimitry Andric       BaseReg.getNode()->dump();
157fe6060f1SDimitry Andric     else
158fe6060f1SDimitry Andric       dbgs() << "null";
159fe6060f1SDimitry Andric     dbgs() << ", BaseFI: " << BaseFrameIndex;
160fe6060f1SDimitry Andric     dbgs() << ", IndexReg: ";
161fe6060f1SDimitry Andric     if (IndexReg.getNode()) {
162fe6060f1SDimitry Andric       IndexReg.getNode()->dump();
163fe6060f1SDimitry Andric     } else {
164fe6060f1SDimitry Andric       dbgs() << "null";
165fe6060f1SDimitry Andric       dbgs() << ", Scale: " << Scale;
166fe6060f1SDimitry Andric     }
167fe6060f1SDimitry Andric     dbgs() << '\n';
168fe6060f1SDimitry Andric   }
169fe6060f1SDimitry Andric #endif
170fe6060f1SDimitry Andric };
171fe6060f1SDimitry Andric } // end anonymous namespace
172fe6060f1SDimitry Andric 
173fe6060f1SDimitry Andric namespace {
174fe6060f1SDimitry Andric 
175fe6060f1SDimitry Andric class M68kDAGToDAGISel : public SelectionDAGISel {
176fe6060f1SDimitry Andric public:
177bdd1243dSDimitry Andric   M68kDAGToDAGISel() = delete;
178bdd1243dSDimitry Andric 
179bdd1243dSDimitry Andric   explicit M68kDAGToDAGISel(M68kTargetMachine &TM)
180*0fca6ea1SDimitry Andric       : SelectionDAGISel(TM), Subtarget(nullptr) {}
181fe6060f1SDimitry Andric 
182fe6060f1SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
18381ad6265SDimitry Andric   bool IsProfitableToFold(SDValue N, SDNode *U, SDNode *Root) const override;
184fe6060f1SDimitry Andric 
185fe6060f1SDimitry Andric private:
186fe6060f1SDimitry Andric   /// Keep a pointer to the M68kSubtarget around so that we can
187fe6060f1SDimitry Andric   /// make the right decision when generating code for different targets.
188fe6060f1SDimitry Andric   const M68kSubtarget *Subtarget;
189fe6060f1SDimitry Andric 
190fe6060f1SDimitry Andric // Include the pieces autogenerated from the target description.
191fe6060f1SDimitry Andric #include "M68kGenDAGISel.inc"
192fe6060f1SDimitry Andric 
193fe6060f1SDimitry Andric   /// getTargetMachine - Return a reference to the TargetMachine, casted
194fe6060f1SDimitry Andric   /// to the target-specific type.
195fe6060f1SDimitry Andric   const M68kTargetMachine &getTargetMachine() {
196fe6060f1SDimitry Andric     return static_cast<const M68kTargetMachine &>(TM);
197fe6060f1SDimitry Andric   }
198fe6060f1SDimitry Andric 
199fe6060f1SDimitry Andric   void Select(SDNode *N) override;
200fe6060f1SDimitry Andric 
201fe6060f1SDimitry Andric   // Insert instructions to initialize the global base register in the
202fe6060f1SDimitry Andric   // first MBB of the function.
203fe6060f1SDimitry Andric   // HMM... do i need this?
204fe6060f1SDimitry Andric   void initGlobalBaseReg(MachineFunction &MF);
205fe6060f1SDimitry Andric 
206fe6060f1SDimitry Andric   bool foldOffsetIntoAddress(uint64_t Offset, M68kISelAddressMode &AM);
207fe6060f1SDimitry Andric 
208fe6060f1SDimitry Andric   bool matchLoadInAddress(LoadSDNode *N, M68kISelAddressMode &AM);
209fe6060f1SDimitry Andric   bool matchAddress(SDValue N, M68kISelAddressMode &AM);
210fe6060f1SDimitry Andric   bool matchAddressBase(SDValue N, M68kISelAddressMode &AM);
211fe6060f1SDimitry Andric   bool matchAddressRecursively(SDValue N, M68kISelAddressMode &AM,
212fe6060f1SDimitry Andric                                unsigned Depth);
213fe6060f1SDimitry Andric   bool matchADD(SDValue &N, M68kISelAddressMode &AM, unsigned Depth);
214fe6060f1SDimitry Andric   bool matchWrapper(SDValue N, M68kISelAddressMode &AM);
215fe6060f1SDimitry Andric 
216fe6060f1SDimitry Andric   std::pair<bool, SDNode *> selectNode(SDNode *Node);
217fe6060f1SDimitry Andric 
218fe6060f1SDimitry Andric   bool SelectARI(SDNode *Parent, SDValue N, SDValue &Base);
219fe6060f1SDimitry Andric   bool SelectARIPI(SDNode *Parent, SDValue N, SDValue &Base);
220fe6060f1SDimitry Andric   bool SelectARIPD(SDNode *Parent, SDValue N, SDValue &Base);
221fe6060f1SDimitry Andric   bool SelectARID(SDNode *Parent, SDValue N, SDValue &Imm, SDValue &Base);
222fe6060f1SDimitry Andric   bool SelectARII(SDNode *Parent, SDValue N, SDValue &Imm, SDValue &Base,
223fe6060f1SDimitry Andric                   SDValue &Index);
224fe6060f1SDimitry Andric   bool SelectAL(SDNode *Parent, SDValue N, SDValue &Sym);
225fe6060f1SDimitry Andric   bool SelectPCD(SDNode *Parent, SDValue N, SDValue &Imm);
226fe6060f1SDimitry Andric   bool SelectPCI(SDNode *Parent, SDValue N, SDValue &Imm, SDValue &Index);
227fe6060f1SDimitry Andric 
2285f757f3fSDimitry Andric   bool SelectInlineAsmMemoryOperand(const SDValue &Op,
2295f757f3fSDimitry Andric                                     InlineAsm::ConstraintCode ConstraintID,
23006c3fb27SDimitry Andric                                     std::vector<SDValue> &OutOps) override;
23106c3fb27SDimitry Andric 
232fe6060f1SDimitry Andric   // If Address Mode represents Frame Index store FI in Disp and
233fe6060f1SDimitry Andric   // Displacement bit size in Base. These values are read symmetrically by
234fe6060f1SDimitry Andric   // M68kRegisterInfo::eliminateFrameIndex method
235fe6060f1SDimitry Andric   inline bool getFrameIndexAddress(M68kISelAddressMode &AM, const SDLoc &DL,
236fe6060f1SDimitry Andric                                    SDValue &Disp, SDValue &Base) {
237fe6060f1SDimitry Andric     if (AM.BaseType == M68kISelAddressMode::Base::FrameIndexBase) {
238fe6060f1SDimitry Andric       Disp = getI32Imm(AM.Disp, DL);
239fe6060f1SDimitry Andric       Base = CurDAG->getTargetFrameIndex(
240fe6060f1SDimitry Andric           AM.BaseFrameIndex, TLI->getPointerTy(CurDAG->getDataLayout()));
241fe6060f1SDimitry Andric       return true;
242fe6060f1SDimitry Andric     }
243fe6060f1SDimitry Andric 
244fe6060f1SDimitry Andric     return false;
245fe6060f1SDimitry Andric   }
246fe6060f1SDimitry Andric 
247fe6060f1SDimitry Andric   // Gets a symbol plus optional displacement
248fe6060f1SDimitry Andric   inline bool getSymbolicDisplacement(M68kISelAddressMode &AM, const SDLoc &DL,
249fe6060f1SDimitry Andric                                       SDValue &Sym) {
250fe6060f1SDimitry Andric     if (AM.GV) {
251fe6060f1SDimitry Andric       Sym = CurDAG->getTargetGlobalAddress(AM.GV, SDLoc(), MVT::i32, AM.Disp,
252fe6060f1SDimitry Andric                                            AM.SymbolFlags);
253fe6060f1SDimitry Andric       return true;
254fe6060f1SDimitry Andric     }
255fe6060f1SDimitry Andric 
256fe6060f1SDimitry Andric     if (AM.CP) {
257fe6060f1SDimitry Andric       Sym = CurDAG->getTargetConstantPool(AM.CP, MVT::i32, AM.Alignment,
258fe6060f1SDimitry Andric                                           AM.Disp, AM.SymbolFlags);
259fe6060f1SDimitry Andric       return true;
260fe6060f1SDimitry Andric     }
261fe6060f1SDimitry Andric 
262fe6060f1SDimitry Andric     if (AM.ES) {
263fe6060f1SDimitry Andric       assert(!AM.Disp && "Non-zero displacement is ignored with ES.");
264fe6060f1SDimitry Andric       Sym = CurDAG->getTargetExternalSymbol(AM.ES, MVT::i32, AM.SymbolFlags);
265fe6060f1SDimitry Andric       return true;
266fe6060f1SDimitry Andric     }
267fe6060f1SDimitry Andric 
268fe6060f1SDimitry Andric     if (AM.MCSym) {
269fe6060f1SDimitry Andric       assert(!AM.Disp && "Non-zero displacement is ignored with MCSym.");
270fe6060f1SDimitry Andric       assert(AM.SymbolFlags == 0 && "oo");
271fe6060f1SDimitry Andric       Sym = CurDAG->getMCSymbol(AM.MCSym, MVT::i32);
272fe6060f1SDimitry Andric       return true;
273fe6060f1SDimitry Andric     }
274fe6060f1SDimitry Andric 
275fe6060f1SDimitry Andric     if (AM.JT != -1) {
276fe6060f1SDimitry Andric       assert(!AM.Disp && "Non-zero displacement is ignored with JT.");
277fe6060f1SDimitry Andric       Sym = CurDAG->getTargetJumpTable(AM.JT, MVT::i32, AM.SymbolFlags);
278fe6060f1SDimitry Andric       return true;
279fe6060f1SDimitry Andric     }
280fe6060f1SDimitry Andric 
281fe6060f1SDimitry Andric     if (AM.BlockAddr) {
282fe6060f1SDimitry Andric       Sym = CurDAG->getTargetBlockAddress(AM.BlockAddr, MVT::i32, AM.Disp,
283fe6060f1SDimitry Andric                                           AM.SymbolFlags);
284fe6060f1SDimitry Andric       return true;
285fe6060f1SDimitry Andric     }
286fe6060f1SDimitry Andric 
287fe6060f1SDimitry Andric     return false;
288fe6060f1SDimitry Andric   }
289fe6060f1SDimitry Andric 
290fe6060f1SDimitry Andric   /// Return a target constant with the specified value of type i8.
291fe6060f1SDimitry Andric   inline SDValue getI8Imm(int64_t Imm, const SDLoc &DL) {
292fe6060f1SDimitry Andric     return CurDAG->getTargetConstant(Imm, DL, MVT::i8);
293fe6060f1SDimitry Andric   }
294fe6060f1SDimitry Andric 
295fe6060f1SDimitry Andric   /// Return a target constant with the specified value of type i8.
296fe6060f1SDimitry Andric   inline SDValue getI16Imm(int64_t Imm, const SDLoc &DL) {
297fe6060f1SDimitry Andric     return CurDAG->getTargetConstant(Imm, DL, MVT::i16);
298fe6060f1SDimitry Andric   }
299fe6060f1SDimitry Andric 
300fe6060f1SDimitry Andric   /// Return a target constant with the specified value, of type i32.
301fe6060f1SDimitry Andric   inline SDValue getI32Imm(int64_t Imm, const SDLoc &DL) {
302fe6060f1SDimitry Andric     return CurDAG->getTargetConstant(Imm, DL, MVT::i32);
303fe6060f1SDimitry Andric   }
304fe6060f1SDimitry Andric 
305fe6060f1SDimitry Andric   /// Return a reference to the TargetInstrInfo, casted to the target-specific
306fe6060f1SDimitry Andric   /// type.
307fe6060f1SDimitry Andric   const M68kInstrInfo *getInstrInfo() const {
308fe6060f1SDimitry Andric     return Subtarget->getInstrInfo();
309fe6060f1SDimitry Andric   }
310fe6060f1SDimitry Andric 
311fe6060f1SDimitry Andric   /// Return an SDNode that returns the value of the global base register.
312fe6060f1SDimitry Andric   /// Output instructions required to initialize the global base register,
313fe6060f1SDimitry Andric   /// if necessary.
314fe6060f1SDimitry Andric   SDNode *getGlobalBaseReg();
315fe6060f1SDimitry Andric };
316bdd1243dSDimitry Andric 
317*0fca6ea1SDimitry Andric class M68kDAGToDAGISelLegacy : public SelectionDAGISelLegacy {
318*0fca6ea1SDimitry Andric public:
319*0fca6ea1SDimitry Andric   static char ID;
320*0fca6ea1SDimitry Andric   explicit M68kDAGToDAGISelLegacy(M68kTargetMachine &TM)
321*0fca6ea1SDimitry Andric       : SelectionDAGISelLegacy(ID, std::make_unique<M68kDAGToDAGISel>(TM)) {}
322*0fca6ea1SDimitry Andric };
323*0fca6ea1SDimitry Andric 
324*0fca6ea1SDimitry Andric char M68kDAGToDAGISelLegacy::ID;
325bdd1243dSDimitry Andric 
326fe6060f1SDimitry Andric } // namespace
327fe6060f1SDimitry Andric 
328*0fca6ea1SDimitry Andric INITIALIZE_PASS(M68kDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false)
329bdd1243dSDimitry Andric 
33081ad6265SDimitry Andric bool M68kDAGToDAGISel::IsProfitableToFold(SDValue N, SDNode *U,
33181ad6265SDimitry Andric                                           SDNode *Root) const {
3325f757f3fSDimitry Andric   if (OptLevel == CodeGenOptLevel::None)
33381ad6265SDimitry Andric     return false;
33481ad6265SDimitry Andric 
33581ad6265SDimitry Andric   if (U == Root) {
33681ad6265SDimitry Andric     switch (U->getOpcode()) {
33781ad6265SDimitry Andric     default:
33881ad6265SDimitry Andric       return true;
33981ad6265SDimitry Andric     case M68kISD::SUB:
34081ad6265SDimitry Andric     case ISD::SUB:
34181ad6265SDimitry Andric       // Prefer NEG instruction when zero subtracts a value.
34281ad6265SDimitry Andric       // e.g.
34381ad6265SDimitry Andric       //   move.l	#0, %d0
34481ad6265SDimitry Andric       //   sub.l	(4,%sp), %d0
34581ad6265SDimitry Andric       // vs.
34681ad6265SDimitry Andric       //   move.l	(4,%sp), %d0
34781ad6265SDimitry Andric       //   neg.l	%d0
34881ad6265SDimitry Andric       if (llvm::isNullConstant(U->getOperand(0)))
34981ad6265SDimitry Andric         return false;
35081ad6265SDimitry Andric       break;
35181ad6265SDimitry Andric     }
35281ad6265SDimitry Andric   }
35381ad6265SDimitry Andric 
35481ad6265SDimitry Andric   return true;
35581ad6265SDimitry Andric }
35681ad6265SDimitry Andric 
357fe6060f1SDimitry Andric bool M68kDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) {
35881ad6265SDimitry Andric   Subtarget = &MF.getSubtarget<M68kSubtarget>();
359fe6060f1SDimitry Andric   return SelectionDAGISel::runOnMachineFunction(MF);
360fe6060f1SDimitry Andric }
361fe6060f1SDimitry Andric 
362fe6060f1SDimitry Andric /// This pass converts a legalized DAG into a M68k-specific DAG,
363fe6060f1SDimitry Andric /// ready for instruction scheduling.
364fe6060f1SDimitry Andric FunctionPass *llvm::createM68kISelDag(M68kTargetMachine &TM) {
365*0fca6ea1SDimitry Andric   return new M68kDAGToDAGISelLegacy(TM);
366fe6060f1SDimitry Andric }
367fe6060f1SDimitry Andric 
368fe6060f1SDimitry Andric static bool doesDispFitFI(M68kISelAddressMode &AM) {
369fe6060f1SDimitry Andric   if (!AM.isDispAddrType())
370fe6060f1SDimitry Andric     return false;
371fe6060f1SDimitry Andric   // -1 to make sure that resolved FI will fit into Disp field
372fe6060f1SDimitry Andric   return isIntN(AM.getDispSize() - 1, AM.Disp);
373fe6060f1SDimitry Andric }
374fe6060f1SDimitry Andric 
375fe6060f1SDimitry Andric static bool doesDispFit(M68kISelAddressMode &AM, int64_t Val) {
376fe6060f1SDimitry Andric   if (!AM.isDispAddrType())
377fe6060f1SDimitry Andric     return false;
378fe6060f1SDimitry Andric   return isIntN(AM.getDispSize(), Val);
379fe6060f1SDimitry Andric }
380fe6060f1SDimitry Andric 
381fe6060f1SDimitry Andric /// Return an SDNode that returns the value of the global base register.
382fe6060f1SDimitry Andric /// Output instructions required to initialize the global base register,
383fe6060f1SDimitry Andric /// if necessary.
384fe6060f1SDimitry Andric SDNode *M68kDAGToDAGISel::getGlobalBaseReg() {
385fe6060f1SDimitry Andric   unsigned GlobalBaseReg = getInstrInfo()->getGlobalBaseReg(MF);
386fe6060f1SDimitry Andric   auto &DL = MF->getDataLayout();
387fe6060f1SDimitry Andric   return CurDAG->getRegister(GlobalBaseReg, TLI->getPointerTy(DL)).getNode();
388fe6060f1SDimitry Andric }
389fe6060f1SDimitry Andric 
390fe6060f1SDimitry Andric bool M68kDAGToDAGISel::foldOffsetIntoAddress(uint64_t Offset,
391fe6060f1SDimitry Andric                                              M68kISelAddressMode &AM) {
392fe6060f1SDimitry Andric   // Cannot combine ExternalSymbol displacements with integer offsets.
393fe6060f1SDimitry Andric   if (Offset != 0 && (AM.ES || AM.MCSym))
394fe6060f1SDimitry Andric     return false;
395fe6060f1SDimitry Andric 
396fe6060f1SDimitry Andric   int64_t Val = AM.Disp + Offset;
397fe6060f1SDimitry Andric 
398fe6060f1SDimitry Andric   if (doesDispFit(AM, Val)) {
399fe6060f1SDimitry Andric     AM.Disp = Val;
400fe6060f1SDimitry Andric     return true;
401fe6060f1SDimitry Andric   }
402fe6060f1SDimitry Andric 
403fe6060f1SDimitry Andric   return false;
404fe6060f1SDimitry Andric }
405fe6060f1SDimitry Andric 
406fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
407fe6060f1SDimitry Andric // Matchers
408fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
409fe6060f1SDimitry Andric 
410fe6060f1SDimitry Andric /// Helper for MatchAddress. Add the specified node to the
411fe6060f1SDimitry Andric /// specified addressing mode without any further recursion.
412fe6060f1SDimitry Andric bool M68kDAGToDAGISel::matchAddressBase(SDValue N, M68kISelAddressMode &AM) {
413fe6060f1SDimitry Andric   // Is the base register already occupied?
414fe6060f1SDimitry Andric   if (AM.hasBase()) {
415fe6060f1SDimitry Andric     // If so, check to see if the scale index register is set.
416fe6060f1SDimitry Andric     if (!AM.hasIndexReg()) {
417fe6060f1SDimitry Andric       AM.IndexReg = N;
418fe6060f1SDimitry Andric       AM.Scale = 1;
419fe6060f1SDimitry Andric       return true;
420fe6060f1SDimitry Andric     }
421fe6060f1SDimitry Andric 
422fe6060f1SDimitry Andric     // Otherwise, we cannot select it.
423fe6060f1SDimitry Andric     return false;
424fe6060f1SDimitry Andric   }
425fe6060f1SDimitry Andric 
426fe6060f1SDimitry Andric   // Default, generate it as a register.
427fe6060f1SDimitry Andric   AM.BaseType = M68kISelAddressMode::Base::RegBase;
428fe6060f1SDimitry Andric   AM.BaseReg = N;
429fe6060f1SDimitry Andric   return true;
430fe6060f1SDimitry Andric }
431fe6060f1SDimitry Andric 
432fe6060f1SDimitry Andric /// TODO Add TLS support
433fe6060f1SDimitry Andric bool M68kDAGToDAGISel::matchLoadInAddress(LoadSDNode *N,
434fe6060f1SDimitry Andric                                           M68kISelAddressMode &AM) {
435fe6060f1SDimitry Andric   return false;
436fe6060f1SDimitry Andric }
437fe6060f1SDimitry Andric 
438fe6060f1SDimitry Andric bool M68kDAGToDAGISel::matchAddressRecursively(SDValue N,
439fe6060f1SDimitry Andric                                                M68kISelAddressMode &AM,
440fe6060f1SDimitry Andric                                                unsigned Depth) {
441fe6060f1SDimitry Andric   SDLoc DL(N);
442fe6060f1SDimitry Andric 
443fe6060f1SDimitry Andric   // Limit recursion.
444fe6060f1SDimitry Andric   if (Depth > 5)
445fe6060f1SDimitry Andric     return matchAddressBase(N, AM);
446fe6060f1SDimitry Andric 
447fe6060f1SDimitry Andric   // If this is already a %PC relative address, we can only merge immediates
448fe6060f1SDimitry Andric   // into it.  Instead of handling this in every case, we handle it here.
449fe6060f1SDimitry Andric   // PC relative addressing: %PC + 16-bit displacement!
450fe6060f1SDimitry Andric   if (AM.isPCRelative()) {
451fe6060f1SDimitry Andric     // FIXME JumpTable and ExternalSymbol address currently don't like
452fe6060f1SDimitry Andric     // displacements.  It isn't very important, but should be fixed for
453fe6060f1SDimitry Andric     // consistency.
454fe6060f1SDimitry Andric 
455fe6060f1SDimitry Andric     if (ConstantSDNode *Cst = dyn_cast<ConstantSDNode>(N))
456fe6060f1SDimitry Andric       if (foldOffsetIntoAddress(Cst->getSExtValue(), AM))
457fe6060f1SDimitry Andric         return true;
458fe6060f1SDimitry Andric     return false;
459fe6060f1SDimitry Andric   }
460fe6060f1SDimitry Andric 
461fe6060f1SDimitry Andric   switch (N.getOpcode()) {
462fe6060f1SDimitry Andric   default:
463fe6060f1SDimitry Andric     break;
464fe6060f1SDimitry Andric 
465fe6060f1SDimitry Andric   case ISD::Constant: {
466fe6060f1SDimitry Andric     uint64_t Val = cast<ConstantSDNode>(N)->getSExtValue();
467fe6060f1SDimitry Andric     if (foldOffsetIntoAddress(Val, AM))
468fe6060f1SDimitry Andric       return true;
469fe6060f1SDimitry Andric     break;
470fe6060f1SDimitry Andric   }
471fe6060f1SDimitry Andric 
472fe6060f1SDimitry Andric   case M68kISD::Wrapper:
473fe6060f1SDimitry Andric   case M68kISD::WrapperPC:
474fe6060f1SDimitry Andric     if (matchWrapper(N, AM))
475fe6060f1SDimitry Andric       return true;
476fe6060f1SDimitry Andric     break;
477fe6060f1SDimitry Andric 
478fe6060f1SDimitry Andric   case ISD::LOAD:
479fe6060f1SDimitry Andric     if (matchLoadInAddress(cast<LoadSDNode>(N), AM))
480fe6060f1SDimitry Andric       return true;
481fe6060f1SDimitry Andric     break;
482fe6060f1SDimitry Andric 
483fe6060f1SDimitry Andric   case ISD::OR:
484fe6060f1SDimitry Andric     // We want to look through a transform in InstCombine and DAGCombiner that
485fe6060f1SDimitry Andric     // turns 'add' into 'or', so we can treat this 'or' exactly like an 'add'.
486fe6060f1SDimitry Andric     // Example: (or (and x, 1), (shl y, 3)) --> (add (and x, 1), (shl y, 3))
487fe6060f1SDimitry Andric     // An 'lea' can then be used to match the shift (multiply) and add:
488fe6060f1SDimitry Andric     // and $1, %esi
489fe6060f1SDimitry Andric     // lea (%rsi, %rdi, 8), %rax
490fe6060f1SDimitry Andric     if (CurDAG->haveNoCommonBitsSet(N.getOperand(0), N.getOperand(1)) &&
491fe6060f1SDimitry Andric         matchADD(N, AM, Depth))
492fe6060f1SDimitry Andric       return true;
493fe6060f1SDimitry Andric     break;
494fe6060f1SDimitry Andric 
495fe6060f1SDimitry Andric   case ISD::ADD:
496fe6060f1SDimitry Andric     if (matchADD(N, AM, Depth))
497fe6060f1SDimitry Andric       return true;
498fe6060f1SDimitry Andric     break;
499fe6060f1SDimitry Andric 
500fe6060f1SDimitry Andric   case ISD::FrameIndex:
501fe6060f1SDimitry Andric     if (AM.isDispAddrType() &&
502fe6060f1SDimitry Andric         AM.BaseType == M68kISelAddressMode::Base::RegBase &&
503fe6060f1SDimitry Andric         AM.BaseReg.getNode() == nullptr && doesDispFitFI(AM)) {
504fe6060f1SDimitry Andric       AM.BaseType = M68kISelAddressMode::Base::FrameIndexBase;
505fe6060f1SDimitry Andric       AM.BaseFrameIndex = cast<FrameIndexSDNode>(N)->getIndex();
506fe6060f1SDimitry Andric       return true;
507fe6060f1SDimitry Andric     }
508fe6060f1SDimitry Andric     break;
50906c3fb27SDimitry Andric 
51006c3fb27SDimitry Andric   case ISD::TargetGlobalTLSAddress: {
51106c3fb27SDimitry Andric     GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(N);
51206c3fb27SDimitry Andric     AM.GV = GA->getGlobal();
51306c3fb27SDimitry Andric     AM.SymbolFlags = GA->getTargetFlags();
51406c3fb27SDimitry Andric     return true;
51506c3fb27SDimitry Andric   }
516fe6060f1SDimitry Andric   }
517fe6060f1SDimitry Andric 
518fe6060f1SDimitry Andric   return matchAddressBase(N, AM);
519fe6060f1SDimitry Andric }
520fe6060f1SDimitry Andric 
521fe6060f1SDimitry Andric /// Add the specified node to the specified addressing mode, returning true if
522fe6060f1SDimitry Andric /// it cannot be done. This just pattern matches for the addressing mode.
523fe6060f1SDimitry Andric bool M68kDAGToDAGISel::matchAddress(SDValue N, M68kISelAddressMode &AM) {
524fe6060f1SDimitry Andric   // TODO: Post-processing: Convert lea(,%reg,2) to lea(%reg,%reg), which has
525fe6060f1SDimitry Andric   // a smaller encoding and avoids a scaled-index.
526fe6060f1SDimitry Andric   // And make sure it is an indexed mode
527fe6060f1SDimitry Andric 
528fe6060f1SDimitry Andric   // TODO: Post-processing: Convert foo to foo(%pc), even in non-PIC mode,
529fe6060f1SDimitry Andric   // because it has a smaller encoding.
530fe6060f1SDimitry Andric   // Make sure this must be done only if PC* modes are currently being matched
531fe6060f1SDimitry Andric   return matchAddressRecursively(N, AM, 0);
532fe6060f1SDimitry Andric }
533fe6060f1SDimitry Andric 
534fe6060f1SDimitry Andric bool M68kDAGToDAGISel::matchADD(SDValue &N, M68kISelAddressMode &AM,
535fe6060f1SDimitry Andric                                 unsigned Depth) {
536fe6060f1SDimitry Andric   // Add an artificial use to this node so that we can keep track of
537fe6060f1SDimitry Andric   // it if it gets CSE'd with a different node.
538fe6060f1SDimitry Andric   HandleSDNode Handle(N);
539fe6060f1SDimitry Andric 
540fe6060f1SDimitry Andric   M68kISelAddressMode Backup = AM;
541fe6060f1SDimitry Andric   if (matchAddressRecursively(N.getOperand(0), AM, Depth + 1) &&
542fe6060f1SDimitry Andric       matchAddressRecursively(Handle.getValue().getOperand(1), AM, Depth + 1)) {
543fe6060f1SDimitry Andric     return true;
544fe6060f1SDimitry Andric   }
545fe6060f1SDimitry Andric   AM = Backup;
546fe6060f1SDimitry Andric 
547fe6060f1SDimitry Andric   // Try again after commuting the operands.
548fe6060f1SDimitry Andric   if (matchAddressRecursively(Handle.getValue().getOperand(1), AM, Depth + 1) &&
549fe6060f1SDimitry Andric       matchAddressRecursively(Handle.getValue().getOperand(0), AM, Depth + 1)) {
550fe6060f1SDimitry Andric     return true;
551fe6060f1SDimitry Andric   }
552fe6060f1SDimitry Andric   AM = Backup;
553fe6060f1SDimitry Andric 
554fe6060f1SDimitry Andric   // If we couldn't fold both operands into the address at the same time,
555fe6060f1SDimitry Andric   // see if we can just put each operand into a register and fold at least
556fe6060f1SDimitry Andric   // the add.
557fe6060f1SDimitry Andric   if (!AM.hasBase() && !AM.hasIndexReg()) {
558fe6060f1SDimitry Andric     N = Handle.getValue();
559fe6060f1SDimitry Andric     AM.BaseReg = N.getOperand(0);
560fe6060f1SDimitry Andric     AM.IndexReg = N.getOperand(1);
561fe6060f1SDimitry Andric     AM.Scale = 1;
562fe6060f1SDimitry Andric     return true;
563fe6060f1SDimitry Andric   }
564fe6060f1SDimitry Andric 
565fe6060f1SDimitry Andric   N = Handle.getValue();
566fe6060f1SDimitry Andric   return false;
567fe6060f1SDimitry Andric }
568fe6060f1SDimitry Andric 
569fe6060f1SDimitry Andric /// Try to match M68kISD::Wrapper and M68kISD::WrapperPC nodes into an
570fe6060f1SDimitry Andric /// addressing mode. These wrap things that will resolve down into a symbol
571fe6060f1SDimitry Andric /// reference. If no match is possible, this returns true, otherwise it returns
572fe6060f1SDimitry Andric /// false.
573fe6060f1SDimitry Andric bool M68kDAGToDAGISel::matchWrapper(SDValue N, M68kISelAddressMode &AM) {
574fe6060f1SDimitry Andric   // If the addressing mode already has a symbol as the displacement, we can
575fe6060f1SDimitry Andric   // never match another symbol.
576fe6060f1SDimitry Andric   if (AM.hasSymbolicDisplacement())
577fe6060f1SDimitry Andric     return false;
578fe6060f1SDimitry Andric 
579fe6060f1SDimitry Andric   SDValue N0 = N.getOperand(0);
580fe6060f1SDimitry Andric 
581fe6060f1SDimitry Andric   if (N.getOpcode() == M68kISD::WrapperPC) {
582fe6060f1SDimitry Andric 
583fe6060f1SDimitry Andric     // If cannot match here just restore the old version
584fe6060f1SDimitry Andric     M68kISelAddressMode Backup = AM;
585fe6060f1SDimitry Andric 
586fe6060f1SDimitry Andric     if (AM.hasBase()) {
587fe6060f1SDimitry Andric       return false;
588fe6060f1SDimitry Andric     }
589fe6060f1SDimitry Andric 
590fe6060f1SDimitry Andric     if (auto *G = dyn_cast<GlobalAddressSDNode>(N0)) {
591fe6060f1SDimitry Andric       AM.GV = G->getGlobal();
592fe6060f1SDimitry Andric       AM.SymbolFlags = G->getTargetFlags();
593fe6060f1SDimitry Andric       if (!foldOffsetIntoAddress(G->getOffset(), AM)) {
594fe6060f1SDimitry Andric         AM = Backup;
595fe6060f1SDimitry Andric         return false;
596fe6060f1SDimitry Andric       }
597fe6060f1SDimitry Andric     } else if (auto *CP = dyn_cast<ConstantPoolSDNode>(N0)) {
598fe6060f1SDimitry Andric       AM.CP = CP->getConstVal();
599fe6060f1SDimitry Andric       AM.Alignment = CP->getAlign();
600fe6060f1SDimitry Andric       AM.SymbolFlags = CP->getTargetFlags();
601fe6060f1SDimitry Andric       if (!foldOffsetIntoAddress(CP->getOffset(), AM)) {
602fe6060f1SDimitry Andric         AM = Backup;
603fe6060f1SDimitry Andric         return false;
604fe6060f1SDimitry Andric       }
605fe6060f1SDimitry Andric     } else if (auto *S = dyn_cast<ExternalSymbolSDNode>(N0)) {
606fe6060f1SDimitry Andric       AM.ES = S->getSymbol();
607fe6060f1SDimitry Andric       AM.SymbolFlags = S->getTargetFlags();
608fe6060f1SDimitry Andric     } else if (auto *S = dyn_cast<MCSymbolSDNode>(N0)) {
609fe6060f1SDimitry Andric       AM.MCSym = S->getMCSymbol();
610fe6060f1SDimitry Andric     } else if (auto *J = dyn_cast<JumpTableSDNode>(N0)) {
611fe6060f1SDimitry Andric       AM.JT = J->getIndex();
612fe6060f1SDimitry Andric       AM.SymbolFlags = J->getTargetFlags();
613fe6060f1SDimitry Andric     } else if (auto *BA = dyn_cast<BlockAddressSDNode>(N0)) {
614fe6060f1SDimitry Andric       AM.BlockAddr = BA->getBlockAddress();
615fe6060f1SDimitry Andric       AM.SymbolFlags = BA->getTargetFlags();
616fe6060f1SDimitry Andric       if (!foldOffsetIntoAddress(BA->getOffset(), AM)) {
617fe6060f1SDimitry Andric         AM = Backup;
618fe6060f1SDimitry Andric         return false;
619fe6060f1SDimitry Andric       }
620fe6060f1SDimitry Andric     } else
621fe6060f1SDimitry Andric       llvm_unreachable("Unhandled symbol reference node.");
622fe6060f1SDimitry Andric 
623fe6060f1SDimitry Andric     AM.setBaseReg(CurDAG->getRegister(M68k::PC, MVT::i32));
624fe6060f1SDimitry Andric     return true;
625fe6060f1SDimitry Andric   }
626fe6060f1SDimitry Andric 
627fe6060f1SDimitry Andric   // This wrapper requires 32bit disp/imm field for Medium CM
628fe6060f1SDimitry Andric   if (!AM.isDisp32()) {
629fe6060f1SDimitry Andric     return false;
630fe6060f1SDimitry Andric   }
631fe6060f1SDimitry Andric 
632fe6060f1SDimitry Andric   if (N.getOpcode() == M68kISD::Wrapper) {
633fe6060f1SDimitry Andric     if (auto *G = dyn_cast<GlobalAddressSDNode>(N0)) {
634fe6060f1SDimitry Andric       AM.GV = G->getGlobal();
635fe6060f1SDimitry Andric       AM.Disp += G->getOffset();
636fe6060f1SDimitry Andric       AM.SymbolFlags = G->getTargetFlags();
637fe6060f1SDimitry Andric     } else if (auto *CP = dyn_cast<ConstantPoolSDNode>(N0)) {
638fe6060f1SDimitry Andric       AM.CP = CP->getConstVal();
639fe6060f1SDimitry Andric       AM.Alignment = CP->getAlign();
640fe6060f1SDimitry Andric       AM.Disp += CP->getOffset();
641fe6060f1SDimitry Andric       AM.SymbolFlags = CP->getTargetFlags();
642fe6060f1SDimitry Andric     } else if (auto *S = dyn_cast<ExternalSymbolSDNode>(N0)) {
643fe6060f1SDimitry Andric       AM.ES = S->getSymbol();
644fe6060f1SDimitry Andric       AM.SymbolFlags = S->getTargetFlags();
645fe6060f1SDimitry Andric     } else if (auto *S = dyn_cast<MCSymbolSDNode>(N0)) {
646fe6060f1SDimitry Andric       AM.MCSym = S->getMCSymbol();
647fe6060f1SDimitry Andric     } else if (auto *J = dyn_cast<JumpTableSDNode>(N0)) {
648fe6060f1SDimitry Andric       AM.JT = J->getIndex();
649fe6060f1SDimitry Andric       AM.SymbolFlags = J->getTargetFlags();
650fe6060f1SDimitry Andric     } else if (auto *BA = dyn_cast<BlockAddressSDNode>(N0)) {
651fe6060f1SDimitry Andric       AM.BlockAddr = BA->getBlockAddress();
652fe6060f1SDimitry Andric       AM.Disp += BA->getOffset();
653fe6060f1SDimitry Andric       AM.SymbolFlags = BA->getTargetFlags();
654fe6060f1SDimitry Andric     } else
655fe6060f1SDimitry Andric       llvm_unreachable("Unhandled symbol reference node.");
656fe6060f1SDimitry Andric     return true;
657fe6060f1SDimitry Andric   }
658fe6060f1SDimitry Andric 
659fe6060f1SDimitry Andric   return false;
660fe6060f1SDimitry Andric }
661fe6060f1SDimitry Andric 
662fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
663fe6060f1SDimitry Andric // Selectors
664fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
665fe6060f1SDimitry Andric 
666fe6060f1SDimitry Andric void M68kDAGToDAGISel::Select(SDNode *Node) {
667fe6060f1SDimitry Andric   unsigned Opcode = Node->getOpcode();
668fe6060f1SDimitry Andric   SDLoc DL(Node);
669fe6060f1SDimitry Andric 
670fe6060f1SDimitry Andric   LLVM_DEBUG(dbgs() << "Selecting: "; Node->dump(CurDAG); dbgs() << '\n');
671fe6060f1SDimitry Andric 
672fe6060f1SDimitry Andric   if (Node->isMachineOpcode()) {
673fe6060f1SDimitry Andric     LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << '\n');
674fe6060f1SDimitry Andric     Node->setNodeId(-1);
675fe6060f1SDimitry Andric     return; // Already selected.
676fe6060f1SDimitry Andric   }
677fe6060f1SDimitry Andric 
678fe6060f1SDimitry Andric   switch (Opcode) {
679fe6060f1SDimitry Andric   default:
680fe6060f1SDimitry Andric     break;
681fe6060f1SDimitry Andric 
68206c3fb27SDimitry Andric   case ISD::GLOBAL_OFFSET_TABLE: {
68306c3fb27SDimitry Andric     SDValue GOT = CurDAG->getTargetExternalSymbol(
68406c3fb27SDimitry Andric         "_GLOBAL_OFFSET_TABLE_", MVT::i32, M68kII::MO_GOTPCREL);
68506c3fb27SDimitry Andric     MachineSDNode *Res =
68606c3fb27SDimitry Andric         CurDAG->getMachineNode(M68k::LEA32q, DL, MVT::i32, GOT);
68706c3fb27SDimitry Andric     ReplaceNode(Node, Res);
68806c3fb27SDimitry Andric     return;
68906c3fb27SDimitry Andric   }
69006c3fb27SDimitry Andric 
691fe6060f1SDimitry Andric   case M68kISD::GLOBAL_BASE_REG:
692fe6060f1SDimitry Andric     ReplaceNode(Node, getGlobalBaseReg());
693fe6060f1SDimitry Andric     return;
694fe6060f1SDimitry Andric   }
695fe6060f1SDimitry Andric 
696fe6060f1SDimitry Andric   SelectCode(Node);
697fe6060f1SDimitry Andric }
698fe6060f1SDimitry Andric 
699fe6060f1SDimitry Andric bool M68kDAGToDAGISel::SelectARIPI(SDNode *Parent, SDValue N, SDValue &Base) {
700fe6060f1SDimitry Andric   LLVM_DEBUG(dbgs() << "Selecting AddrType::ARIPI: ");
701fe6060f1SDimitry Andric   LLVM_DEBUG(dbgs() << "NOT IMPLEMENTED\n");
702fe6060f1SDimitry Andric   return false;
703fe6060f1SDimitry Andric }
704fe6060f1SDimitry Andric 
705fe6060f1SDimitry Andric bool M68kDAGToDAGISel::SelectARIPD(SDNode *Parent, SDValue N, SDValue &Base) {
706fe6060f1SDimitry Andric   LLVM_DEBUG(dbgs() << "Selecting AddrType::ARIPD: ");
707fe6060f1SDimitry Andric   LLVM_DEBUG(dbgs() << "NOT IMPLEMENTED\n");
708fe6060f1SDimitry Andric   return false;
709fe6060f1SDimitry Andric }
710fe6060f1SDimitry Andric 
711fe6060f1SDimitry Andric bool M68kDAGToDAGISel::SelectARID(SDNode *Parent, SDValue N, SDValue &Disp,
712fe6060f1SDimitry Andric                                   SDValue &Base) {
713fe6060f1SDimitry Andric   LLVM_DEBUG(dbgs() << "Selecting AddrType::ARID: ");
714fe6060f1SDimitry Andric   M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARID);
715fe6060f1SDimitry Andric 
716fe6060f1SDimitry Andric   if (!matchAddress(N, AM))
717fe6060f1SDimitry Andric     return false;
718fe6060f1SDimitry Andric 
719fe6060f1SDimitry Andric   if (AM.isPCRelative()) {
720fe6060f1SDimitry Andric     LLVM_DEBUG(dbgs() << "REJECT: Cannot match PC relative address\n");
721fe6060f1SDimitry Andric     return false;
722fe6060f1SDimitry Andric   }
723fe6060f1SDimitry Andric 
724fe6060f1SDimitry Andric   // If this is a frame index, grab it
725fe6060f1SDimitry Andric   if (getFrameIndexAddress(AM, SDLoc(N), Disp, Base)) {
726fe6060f1SDimitry Andric     LLVM_DEBUG(dbgs() << "SUCCESS matched FI\n");
727fe6060f1SDimitry Andric     return true;
728fe6060f1SDimitry Andric   }
729fe6060f1SDimitry Andric 
730fe6060f1SDimitry Andric   if (AM.hasIndexReg()) {
731fe6060f1SDimitry Andric     LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index\n");
732fe6060f1SDimitry Andric     return false;
733fe6060f1SDimitry Andric   }
734fe6060f1SDimitry Andric 
735fe6060f1SDimitry Andric   if (!AM.hasBaseReg()) {
736fe6060f1SDimitry Andric     LLVM_DEBUG(dbgs() << "REJECT: No Base reg\n");
737fe6060f1SDimitry Andric     return false;
738fe6060f1SDimitry Andric   }
739fe6060f1SDimitry Andric 
74006c3fb27SDimitry Andric   Base = AM.BaseReg;
74106c3fb27SDimitry Andric 
742fe6060f1SDimitry Andric   if (getSymbolicDisplacement(AM, SDLoc(N), Disp)) {
743fe6060f1SDimitry Andric     assert(!AM.Disp && "Should not be any displacement");
744fe6060f1SDimitry Andric     LLVM_DEBUG(dbgs() << "SUCCESS, matched Symbol\n");
745fe6060f1SDimitry Andric     return true;
746fe6060f1SDimitry Andric   }
747fe6060f1SDimitry Andric 
748fe6060f1SDimitry Andric   // Give a chance to AddrType::ARI
749fe6060f1SDimitry Andric   if (AM.Disp == 0) {
750fe6060f1SDimitry Andric     LLVM_DEBUG(dbgs() << "REJECT: No displacement\n");
751fe6060f1SDimitry Andric     return false;
752fe6060f1SDimitry Andric   }
753fe6060f1SDimitry Andric 
754fe6060f1SDimitry Andric   Disp = getI16Imm(AM.Disp, SDLoc(N));
755fe6060f1SDimitry Andric 
756fe6060f1SDimitry Andric   LLVM_DEBUG(dbgs() << "SUCCESS\n");
757fe6060f1SDimitry Andric   return true;
758fe6060f1SDimitry Andric }
759fe6060f1SDimitry Andric 
760fe6060f1SDimitry Andric static bool isAddressBase(const SDValue &N) {
761fe6060f1SDimitry Andric   switch (N.getOpcode()) {
762fe6060f1SDimitry Andric   case ISD::ADD:
763fe6060f1SDimitry Andric   case ISD::ADDC:
764fe6060f1SDimitry Andric     return llvm::any_of(N.getNode()->ops(),
765fe6060f1SDimitry Andric                         [](const SDUse &U) { return isAddressBase(U.get()); });
766fe6060f1SDimitry Andric   case M68kISD::Wrapper:
767fe6060f1SDimitry Andric   case M68kISD::WrapperPC:
768fe6060f1SDimitry Andric   case M68kISD::GLOBAL_BASE_REG:
769fe6060f1SDimitry Andric     return true;
770fe6060f1SDimitry Andric   default:
771fe6060f1SDimitry Andric     return false;
772fe6060f1SDimitry Andric   }
773fe6060f1SDimitry Andric }
774fe6060f1SDimitry Andric 
775fe6060f1SDimitry Andric bool M68kDAGToDAGISel::SelectARII(SDNode *Parent, SDValue N, SDValue &Disp,
776fe6060f1SDimitry Andric                                   SDValue &Base, SDValue &Index) {
777fe6060f1SDimitry Andric   M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARII);
778fe6060f1SDimitry Andric   LLVM_DEBUG(dbgs() << "Selecting AddrType::ARII: ");
779fe6060f1SDimitry Andric 
780fe6060f1SDimitry Andric   if (!matchAddress(N, AM))
781fe6060f1SDimitry Andric     return false;
782fe6060f1SDimitry Andric 
783fe6060f1SDimitry Andric   if (AM.isPCRelative()) {
784fe6060f1SDimitry Andric     LLVM_DEBUG(dbgs() << "REJECT: PC relative\n");
785fe6060f1SDimitry Andric     return false;
786fe6060f1SDimitry Andric   }
787fe6060f1SDimitry Andric 
788fe6060f1SDimitry Andric   if (!AM.hasIndexReg()) {
789fe6060f1SDimitry Andric     LLVM_DEBUG(dbgs() << "REJECT: No Index\n");
790fe6060f1SDimitry Andric     return false;
791fe6060f1SDimitry Andric   }
792fe6060f1SDimitry Andric 
793fe6060f1SDimitry Andric   if (!AM.hasBaseReg()) {
794fe6060f1SDimitry Andric     LLVM_DEBUG(dbgs() << "REJECT: No Base\n");
795fe6060f1SDimitry Andric     return false;
796fe6060f1SDimitry Andric   }
797fe6060f1SDimitry Andric 
798fe6060f1SDimitry Andric   if (!isAddressBase(AM.BaseReg) && isAddressBase(AM.IndexReg)) {
799fe6060f1SDimitry Andric     Base = AM.IndexReg;
800fe6060f1SDimitry Andric     Index = AM.BaseReg;
801fe6060f1SDimitry Andric   } else {
802fe6060f1SDimitry Andric     Base = AM.BaseReg;
803fe6060f1SDimitry Andric     Index = AM.IndexReg;
804fe6060f1SDimitry Andric   }
805fe6060f1SDimitry Andric 
806fe6060f1SDimitry Andric   if (AM.hasSymbolicDisplacement()) {
807fe6060f1SDimitry Andric     LLVM_DEBUG(dbgs() << "REJECT, Cannot match symbolic displacement\n");
808fe6060f1SDimitry Andric     return false;
809fe6060f1SDimitry Andric   }
810fe6060f1SDimitry Andric 
811fe6060f1SDimitry Andric   // The idea here is that we want to use AddrType::ARII without displacement
812fe6060f1SDimitry Andric   // only if necessary like memory operations, otherwise this must be lowered
813fe6060f1SDimitry Andric   // into addition
814fe6060f1SDimitry Andric   if (AM.Disp == 0 && (!Parent || (Parent->getOpcode() != ISD::LOAD &&
815fe6060f1SDimitry Andric                                    Parent->getOpcode() != ISD::STORE))) {
816fe6060f1SDimitry Andric     LLVM_DEBUG(dbgs() << "REJECT: Displacement is Zero\n");
817fe6060f1SDimitry Andric     return false;
818fe6060f1SDimitry Andric   }
819fe6060f1SDimitry Andric 
820fe6060f1SDimitry Andric   Disp = getI8Imm(AM.Disp, SDLoc(N));
821fe6060f1SDimitry Andric 
822fe6060f1SDimitry Andric   LLVM_DEBUG(dbgs() << "SUCCESS\n");
823fe6060f1SDimitry Andric   return true;
824fe6060f1SDimitry Andric }
825fe6060f1SDimitry Andric 
826fe6060f1SDimitry Andric bool M68kDAGToDAGISel::SelectAL(SDNode *Parent, SDValue N, SDValue &Sym) {
827fe6060f1SDimitry Andric   LLVM_DEBUG(dbgs() << "Selecting AddrType::AL: ");
828fe6060f1SDimitry Andric   M68kISelAddressMode AM(M68kISelAddressMode::AddrType::AL);
829fe6060f1SDimitry Andric 
830fe6060f1SDimitry Andric   if (!matchAddress(N, AM)) {
831fe6060f1SDimitry Andric     LLVM_DEBUG(dbgs() << "REJECT: Match failed\n");
832fe6060f1SDimitry Andric     return false;
833fe6060f1SDimitry Andric   }
834fe6060f1SDimitry Andric 
835fe6060f1SDimitry Andric   if (AM.isPCRelative()) {
836fe6060f1SDimitry Andric     LLVM_DEBUG(dbgs() << "REJECT: Cannot match PC relative address\n");
837fe6060f1SDimitry Andric     return false;
838fe6060f1SDimitry Andric   }
839fe6060f1SDimitry Andric 
840fe6060f1SDimitry Andric   if (AM.hasBase()) {
841fe6060f1SDimitry Andric     LLVM_DEBUG(dbgs() << "REJECT: Cannot match Base\n");
842fe6060f1SDimitry Andric     return false;
843fe6060f1SDimitry Andric   }
844fe6060f1SDimitry Andric 
845fe6060f1SDimitry Andric   if (AM.hasIndexReg()) {
846fe6060f1SDimitry Andric     LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index\n");
847fe6060f1SDimitry Andric     return false;
848fe6060f1SDimitry Andric   }
849fe6060f1SDimitry Andric 
850fe6060f1SDimitry Andric   if (getSymbolicDisplacement(AM, SDLoc(N), Sym)) {
851fe6060f1SDimitry Andric     LLVM_DEBUG(dbgs() << "SUCCESS: Matched symbol\n");
852fe6060f1SDimitry Andric     return true;
853fe6060f1SDimitry Andric   }
854fe6060f1SDimitry Andric 
855fe6060f1SDimitry Andric   if (AM.Disp) {
856fe6060f1SDimitry Andric     Sym = getI32Imm(AM.Disp, SDLoc(N));
857fe6060f1SDimitry Andric     LLVM_DEBUG(dbgs() << "SUCCESS\n");
858fe6060f1SDimitry Andric     return true;
859fe6060f1SDimitry Andric   }
860fe6060f1SDimitry Andric 
861fe6060f1SDimitry Andric   LLVM_DEBUG(dbgs() << "REJECT: Not Symbol or Disp\n");
862fe6060f1SDimitry Andric   return false;
863fe6060f1SDimitry Andric   ;
864fe6060f1SDimitry Andric }
865fe6060f1SDimitry Andric 
866fe6060f1SDimitry Andric bool M68kDAGToDAGISel::SelectPCD(SDNode *Parent, SDValue N, SDValue &Disp) {
867fe6060f1SDimitry Andric   LLVM_DEBUG(dbgs() << "Selecting AddrType::PCD: ");
868fe6060f1SDimitry Andric   M68kISelAddressMode AM(M68kISelAddressMode::AddrType::PCD);
869fe6060f1SDimitry Andric 
870fe6060f1SDimitry Andric   if (!matchAddress(N, AM))
871fe6060f1SDimitry Andric     return false;
872fe6060f1SDimitry Andric 
873fe6060f1SDimitry Andric   if (!AM.isPCRelative()) {
874fe6060f1SDimitry Andric     LLVM_DEBUG(dbgs() << "REJECT: Not PC relative\n");
875fe6060f1SDimitry Andric     return false;
876fe6060f1SDimitry Andric   }
877fe6060f1SDimitry Andric 
878fe6060f1SDimitry Andric   if (AM.hasIndexReg()) {
879fe6060f1SDimitry Andric     LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index\n");
880fe6060f1SDimitry Andric     return false;
881fe6060f1SDimitry Andric   }
882fe6060f1SDimitry Andric 
883fe6060f1SDimitry Andric   if (getSymbolicDisplacement(AM, SDLoc(N), Disp)) {
884fe6060f1SDimitry Andric     LLVM_DEBUG(dbgs() << "SUCCESS, matched Symbol\n");
885fe6060f1SDimitry Andric     return true;
886fe6060f1SDimitry Andric   }
887fe6060f1SDimitry Andric 
888fe6060f1SDimitry Andric   Disp = getI16Imm(AM.Disp, SDLoc(N));
889fe6060f1SDimitry Andric 
890fe6060f1SDimitry Andric   LLVM_DEBUG(dbgs() << "SUCCESS\n");
891fe6060f1SDimitry Andric   return true;
892fe6060f1SDimitry Andric }
893fe6060f1SDimitry Andric 
894fe6060f1SDimitry Andric bool M68kDAGToDAGISel::SelectPCI(SDNode *Parent, SDValue N, SDValue &Disp,
895fe6060f1SDimitry Andric                                  SDValue &Index) {
896fe6060f1SDimitry Andric   LLVM_DEBUG(dbgs() << "Selecting AddrType::PCI: ");
897fe6060f1SDimitry Andric   M68kISelAddressMode AM(M68kISelAddressMode::AddrType::PCI);
898fe6060f1SDimitry Andric 
899fe6060f1SDimitry Andric   if (!matchAddress(N, AM))
900fe6060f1SDimitry Andric     return false;
901fe6060f1SDimitry Andric 
902fe6060f1SDimitry Andric   if (!AM.isPCRelative()) {
903fe6060f1SDimitry Andric     LLVM_DEBUG(dbgs() << "REJECT: Not PC relative\n");
904fe6060f1SDimitry Andric     return false;
905fe6060f1SDimitry Andric   }
906fe6060f1SDimitry Andric 
907fe6060f1SDimitry Andric   if (!AM.hasIndexReg()) {
908fe6060f1SDimitry Andric     LLVM_DEBUG(dbgs() << "REJECT: No Index\n");
909fe6060f1SDimitry Andric     return false;
910fe6060f1SDimitry Andric   }
911fe6060f1SDimitry Andric 
912fe6060f1SDimitry Andric   Index = AM.IndexReg;
913fe6060f1SDimitry Andric 
914fe6060f1SDimitry Andric   if (getSymbolicDisplacement(AM, SDLoc(N), Disp)) {
915fe6060f1SDimitry Andric     assert(!AM.Disp && "Should not be any displacement");
916fe6060f1SDimitry Andric     LLVM_DEBUG(dbgs() << "SUCCESS, matched Symbol\n");
917fe6060f1SDimitry Andric     return true;
918fe6060f1SDimitry Andric   }
919fe6060f1SDimitry Andric 
920fe6060f1SDimitry Andric   Disp = getI8Imm(AM.Disp, SDLoc(N));
921fe6060f1SDimitry Andric 
922fe6060f1SDimitry Andric   LLVM_DEBUG(dbgs() << "SUCCESS\n");
923fe6060f1SDimitry Andric   return true;
924fe6060f1SDimitry Andric }
925fe6060f1SDimitry Andric 
926fe6060f1SDimitry Andric bool M68kDAGToDAGISel::SelectARI(SDNode *Parent, SDValue N, SDValue &Base) {
927fe6060f1SDimitry Andric   LLVM_DEBUG(dbgs() << "Selecting AddrType::ARI: ");
928fe6060f1SDimitry Andric   M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARI);
929fe6060f1SDimitry Andric 
930fe6060f1SDimitry Andric   if (!matchAddress(N, AM)) {
931fe6060f1SDimitry Andric     LLVM_DEBUG(dbgs() << "REJECT: Match failed\n");
932fe6060f1SDimitry Andric     return false;
933fe6060f1SDimitry Andric   }
934fe6060f1SDimitry Andric 
935fe6060f1SDimitry Andric   if (AM.isPCRelative()) {
936fe6060f1SDimitry Andric     LLVM_DEBUG(dbgs() << "REJECT: Cannot match PC relative address\n");
937fe6060f1SDimitry Andric     return false;
938fe6060f1SDimitry Andric   }
939fe6060f1SDimitry Andric 
940fe6060f1SDimitry Andric   // AddrType::ARI does not use these
941fe6060f1SDimitry Andric   if (AM.hasIndexReg() || AM.Disp != 0) {
942fe6060f1SDimitry Andric     LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index or Disp\n");
943fe6060f1SDimitry Andric     return false;
944fe6060f1SDimitry Andric   }
945fe6060f1SDimitry Andric 
946fe6060f1SDimitry Andric   // Must be matched by AddrType::AL
947fe6060f1SDimitry Andric   if (AM.hasSymbolicDisplacement()) {
948fe6060f1SDimitry Andric     LLVM_DEBUG(dbgs() << "REJECT: Cannot match Symbolic Disp\n");
949fe6060f1SDimitry Andric     return false;
950fe6060f1SDimitry Andric   }
951fe6060f1SDimitry Andric 
952fe6060f1SDimitry Andric   if (AM.hasBaseReg()) {
953fe6060f1SDimitry Andric     Base = AM.BaseReg;
954fe6060f1SDimitry Andric     LLVM_DEBUG(dbgs() << "SUCCESS\n");
955fe6060f1SDimitry Andric     return true;
956fe6060f1SDimitry Andric   }
957fe6060f1SDimitry Andric 
958fe6060f1SDimitry Andric   return false;
959fe6060f1SDimitry Andric }
96006c3fb27SDimitry Andric 
96106c3fb27SDimitry Andric bool M68kDAGToDAGISel::SelectInlineAsmMemoryOperand(
9625f757f3fSDimitry Andric     const SDValue &Op, InlineAsm::ConstraintCode ConstraintID,
9635f757f3fSDimitry Andric     std::vector<SDValue> &OutOps) {
96406c3fb27SDimitry Andric   // In order to tell AsmPrinter the exact addressing mode we select here, which
96506c3fb27SDimitry Andric   // might comprise of multiple SDValues (hence MachineOperands), a 32-bit
96606c3fb27SDimitry Andric   // immediate value is prepended to the list of selected SDValues to indicate
96706c3fb27SDimitry Andric   // the addressing mode kind.
96806c3fb27SDimitry Andric   using AMK = M68k::MemAddrModeKind;
96906c3fb27SDimitry Andric   auto addKind = [this](SDValue &Opnd, AMK Kind) -> bool {
97006c3fb27SDimitry Andric     Opnd = CurDAG->getTargetConstant(unsigned(Kind), SDLoc(), MVT::i32);
97106c3fb27SDimitry Andric     return true;
97206c3fb27SDimitry Andric   };
97306c3fb27SDimitry Andric 
97406c3fb27SDimitry Andric   switch (ConstraintID) {
97506c3fb27SDimitry Andric   // Generic memory operand.
9765f757f3fSDimitry Andric   case InlineAsm::ConstraintCode::m: {
97706c3fb27SDimitry Andric     // Try every supported (memory) addressing modes.
97806c3fb27SDimitry Andric     SDValue Operands[4];
97906c3fb27SDimitry Andric 
98006c3fb27SDimitry Andric     // TODO: The ordering of the following SelectXXX is relatively...arbitrary,
98106c3fb27SDimitry Andric     // right now we simply sort them by descending complexity. Maybe we should
98206c3fb27SDimitry Andric     // adjust this by code model and/or relocation mode in the future.
98306c3fb27SDimitry Andric     if (SelectARII(nullptr, Op, Operands[1], Operands[2], Operands[3]) &&
98406c3fb27SDimitry Andric         addKind(Operands[0], AMK::f)) {
98506c3fb27SDimitry Andric       OutOps.insert(OutOps.end(), &Operands[0], Operands + 4);
98606c3fb27SDimitry Andric       return false;
98706c3fb27SDimitry Andric     }
98806c3fb27SDimitry Andric 
98906c3fb27SDimitry Andric     if ((SelectPCI(nullptr, Op, Operands[1], Operands[2]) &&
99006c3fb27SDimitry Andric          addKind(Operands[0], AMK::k)) ||
99106c3fb27SDimitry Andric         (SelectARID(nullptr, Op, Operands[1], Operands[2]) &&
99206c3fb27SDimitry Andric          addKind(Operands[0], AMK::p))) {
99306c3fb27SDimitry Andric       OutOps.insert(OutOps.end(), &Operands[0], Operands + 3);
99406c3fb27SDimitry Andric       return false;
99506c3fb27SDimitry Andric     }
99606c3fb27SDimitry Andric 
99706c3fb27SDimitry Andric     if ((SelectPCD(nullptr, Op, Operands[1]) && addKind(Operands[0], AMK::q)) ||
99806c3fb27SDimitry Andric         (SelectARI(nullptr, Op, Operands[1]) && addKind(Operands[0], AMK::j)) ||
99906c3fb27SDimitry Andric         (SelectAL(nullptr, Op, Operands[1]) && addKind(Operands[0], AMK::b))) {
100006c3fb27SDimitry Andric       OutOps.insert(OutOps.end(), {Operands[0], Operands[1]});
100106c3fb27SDimitry Andric       return false;
100206c3fb27SDimitry Andric     }
100306c3fb27SDimitry Andric 
100406c3fb27SDimitry Andric     return true;
100506c3fb27SDimitry Andric   }
100606c3fb27SDimitry Andric   // 'Q': Address register indirect addressing.
10075f757f3fSDimitry Andric   case InlineAsm::ConstraintCode::Q: {
100806c3fb27SDimitry Andric     SDValue AMKind, Base;
100906c3fb27SDimitry Andric     // 'j' addressing mode.
101006c3fb27SDimitry Andric     // TODO: Add support for 'o' and 'e' after their
101106c3fb27SDimitry Andric     // select functions are implemented.
101206c3fb27SDimitry Andric     if (SelectARI(nullptr, Op, Base) && addKind(AMKind, AMK::j)) {
101306c3fb27SDimitry Andric       OutOps.insert(OutOps.end(), {AMKind, Base});
101406c3fb27SDimitry Andric       return false;
101506c3fb27SDimitry Andric     }
101606c3fb27SDimitry Andric     return true;
101706c3fb27SDimitry Andric   }
101806c3fb27SDimitry Andric   // 'U': Address register indirect w/ constant offset addressing.
10195f757f3fSDimitry Andric   case InlineAsm::ConstraintCode::Um: {
102006c3fb27SDimitry Andric     SDValue AMKind, Base, Offset;
102106c3fb27SDimitry Andric     // 'p' addressing mode.
102206c3fb27SDimitry Andric     if (SelectARID(nullptr, Op, Offset, Base) && addKind(AMKind, AMK::p)) {
102306c3fb27SDimitry Andric       OutOps.insert(OutOps.end(), {AMKind, Offset, Base});
102406c3fb27SDimitry Andric       return false;
102506c3fb27SDimitry Andric     }
102606c3fb27SDimitry Andric     return true;
102706c3fb27SDimitry Andric   }
102806c3fb27SDimitry Andric   default:
102906c3fb27SDimitry Andric     return true;
103006c3fb27SDimitry Andric   }
103106c3fb27SDimitry Andric }
1032