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

source code of llvm/lib/Target/M68k/M68kISelDAGToDAG.cpp