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
39 using namespace llvm;
40
41 #define DEBUG_TYPE "m68k-isel"
42 #define PASS_NAME "M68k DAG->DAG Pattern Instruction Selection"
43
44 namespace {
45
46 // For reference, the full order of operands for memory references is:
47 // (Operand), Displacement, Base, Index, Scale
48 struct 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
M68kISelAddressMode__anon69dd31c00111::M68kISelAddressMode83 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
hasSymbolicDisplacement__anon69dd31c00111::M68kISelAddressMode88 bool hasSymbolicDisplacement() const {
89 return GV != nullptr || CP != nullptr || ES != nullptr ||
90 MCSym != nullptr || JT != -1 || BlockAddr != nullptr;
91 }
92
hasBase__anon69dd31c00111::M68kISelAddressMode93 bool hasBase() const {
94 return BaseType == Base::FrameIndexBase || BaseReg.getNode() != nullptr;
95 }
96
hasFrameIndex__anon69dd31c00111::M68kISelAddressMode97 bool hasFrameIndex() const { return BaseType == Base::FrameIndexBase; }
98
hasBaseReg__anon69dd31c00111::M68kISelAddressMode99 bool hasBaseReg() const {
100 return BaseType == Base::RegBase && BaseReg.getNode() != nullptr;
101 }
102
hasIndexReg__anon69dd31c00111::M68kISelAddressMode103 bool hasIndexReg() const {
104 return BaseType == Base::RegBase && IndexReg.getNode() != nullptr;
105 }
106
107 /// True if address mode type supports displacement
isDispAddrType__anon69dd31c00111::M68kISelAddressMode108 bool isDispAddrType() const {
109 return AM == AddrType::ARII || AM == AddrType::PCI ||
110 AM == AddrType::ARID || AM == AddrType::PCD || AM == AddrType::AL;
111 }
112
getDispSize__anon69dd31c00111::M68kISelAddressMode113 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
hasDisp__anon69dd31c00111::M68kISelAddressMode129 bool hasDisp() const { return getDispSize() != 0; }
isDisp8__anon69dd31c00111::M68kISelAddressMode130 bool isDisp8() const { return getDispSize() == 8; }
isDisp16__anon69dd31c00111::M68kISelAddressMode131 bool isDisp16() const { return getDispSize() == 16; }
isDisp32__anon69dd31c00111::M68kISelAddressMode132 bool isDisp32() const { return getDispSize() == 32; }
133
134 /// Return true if this addressing mode is already PC-relative.
isPCRelative__anon69dd31c00111::M68kISelAddressMode135 bool isPCRelative() const {
136 if (BaseType != Base::RegBase)
137 return false;
138 if (auto *RegNode = dyn_cast_or_null<RegisterSDNode>(BaseReg.getNode()))
139 return RegNode->getReg() == M68k::PC;
140 return false;
141 }
142
setBaseReg__anon69dd31c00111::M68kISelAddressMode143 void setBaseReg(SDValue Reg) {
144 BaseType = Base::RegBase;
145 BaseReg = Reg;
146 }
147
setIndexReg__anon69dd31c00111::M68kISelAddressMode148 void setIndexReg(SDValue Reg) { IndexReg = Reg; }
149
150 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump__anon69dd31c00111::M68kISelAddressMode151 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
173 namespace {
174
175 class M68kDAGToDAGISel : public SelectionDAGISel {
176 public:
177 static char ID;
178
179 M68kDAGToDAGISel() = delete;
180
M68kDAGToDAGISel(M68kTargetMachine & TM)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
187 private:
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.
getTargetMachine()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 // If Address Mode represents Frame Index store FI in Disp and
231 // Displacement bit size in Base. These values are read symmetrically by
232 // M68kRegisterInfo::eliminateFrameIndex method
getFrameIndexAddress(M68kISelAddressMode & AM,const SDLoc & DL,SDValue & Disp,SDValue & Base)233 inline bool getFrameIndexAddress(M68kISelAddressMode &AM, const SDLoc &DL,
234 SDValue &Disp, SDValue &Base) {
235 if (AM.BaseType == M68kISelAddressMode::Base::FrameIndexBase) {
236 Disp = getI32Imm(AM.Disp, DL);
237 Base = CurDAG->getTargetFrameIndex(
238 AM.BaseFrameIndex, TLI->getPointerTy(CurDAG->getDataLayout()));
239 return true;
240 }
241
242 return false;
243 }
244
245 // Gets a symbol plus optional displacement
getSymbolicDisplacement(M68kISelAddressMode & AM,const SDLoc & DL,SDValue & Sym)246 inline bool getSymbolicDisplacement(M68kISelAddressMode &AM, const SDLoc &DL,
247 SDValue &Sym) {
248 if (AM.GV) {
249 Sym = CurDAG->getTargetGlobalAddress(AM.GV, SDLoc(), MVT::i32, AM.Disp,
250 AM.SymbolFlags);
251 return true;
252 }
253
254 if (AM.CP) {
255 Sym = CurDAG->getTargetConstantPool(AM.CP, MVT::i32, AM.Alignment,
256 AM.Disp, AM.SymbolFlags);
257 return true;
258 }
259
260 if (AM.ES) {
261 assert(!AM.Disp && "Non-zero displacement is ignored with ES.");
262 Sym = CurDAG->getTargetExternalSymbol(AM.ES, MVT::i32, AM.SymbolFlags);
263 return true;
264 }
265
266 if (AM.MCSym) {
267 assert(!AM.Disp && "Non-zero displacement is ignored with MCSym.");
268 assert(AM.SymbolFlags == 0 && "oo");
269 Sym = CurDAG->getMCSymbol(AM.MCSym, MVT::i32);
270 return true;
271 }
272
273 if (AM.JT != -1) {
274 assert(!AM.Disp && "Non-zero displacement is ignored with JT.");
275 Sym = CurDAG->getTargetJumpTable(AM.JT, MVT::i32, AM.SymbolFlags);
276 return true;
277 }
278
279 if (AM.BlockAddr) {
280 Sym = CurDAG->getTargetBlockAddress(AM.BlockAddr, MVT::i32, AM.Disp,
281 AM.SymbolFlags);
282 return true;
283 }
284
285 return false;
286 }
287
288 /// Return a target constant with the specified value of type i8.
getI8Imm(int64_t Imm,const SDLoc & DL)289 inline SDValue getI8Imm(int64_t Imm, const SDLoc &DL) {
290 return CurDAG->getTargetConstant(Imm, DL, MVT::i8);
291 }
292
293 /// Return a target constant with the specified value of type i8.
getI16Imm(int64_t Imm,const SDLoc & DL)294 inline SDValue getI16Imm(int64_t Imm, const SDLoc &DL) {
295 return CurDAG->getTargetConstant(Imm, DL, MVT::i16);
296 }
297
298 /// Return a target constant with the specified value, of type i32.
getI32Imm(int64_t Imm,const SDLoc & DL)299 inline SDValue getI32Imm(int64_t Imm, const SDLoc &DL) {
300 return CurDAG->getTargetConstant(Imm, DL, MVT::i32);
301 }
302
303 /// Return a reference to the TargetInstrInfo, casted to the target-specific
304 /// type.
getInstrInfo() const305 const M68kInstrInfo *getInstrInfo() const {
306 return Subtarget->getInstrInfo();
307 }
308
309 /// Return an SDNode that returns the value of the global base register.
310 /// Output instructions required to initialize the global base register,
311 /// if necessary.
312 SDNode *getGlobalBaseReg();
313 };
314
315 char M68kDAGToDAGISel::ID;
316
317 } // namespace
318
INITIALIZE_PASS(M68kDAGToDAGISel,DEBUG_TYPE,PASS_NAME,false,false)319 INITIALIZE_PASS(M68kDAGToDAGISel, DEBUG_TYPE, PASS_NAME, false, false)
320
321 bool M68kDAGToDAGISel::IsProfitableToFold(SDValue N, SDNode *U,
322 SDNode *Root) const {
323 if (OptLevel == CodeGenOpt::None)
324 return false;
325
326 if (U == Root) {
327 switch (U->getOpcode()) {
328 default:
329 return true;
330 case M68kISD::SUB:
331 case ISD::SUB:
332 // Prefer NEG instruction when zero subtracts a value.
333 // e.g.
334 // move.l #0, %d0
335 // sub.l (4,%sp), %d0
336 // vs.
337 // move.l (4,%sp), %d0
338 // neg.l %d0
339 if (llvm::isNullConstant(U->getOperand(0)))
340 return false;
341 break;
342 }
343 }
344
345 return true;
346 }
347
runOnMachineFunction(MachineFunction & MF)348 bool M68kDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) {
349 Subtarget = &MF.getSubtarget<M68kSubtarget>();
350 return SelectionDAGISel::runOnMachineFunction(MF);
351 }
352
353 /// This pass converts a legalized DAG into a M68k-specific DAG,
354 /// ready for instruction scheduling.
createM68kISelDag(M68kTargetMachine & TM)355 FunctionPass *llvm::createM68kISelDag(M68kTargetMachine &TM) {
356 return new M68kDAGToDAGISel(TM);
357 }
358
doesDispFitFI(M68kISelAddressMode & AM)359 static bool doesDispFitFI(M68kISelAddressMode &AM) {
360 if (!AM.isDispAddrType())
361 return false;
362 // -1 to make sure that resolved FI will fit into Disp field
363 return isIntN(AM.getDispSize() - 1, AM.Disp);
364 }
365
doesDispFit(M68kISelAddressMode & AM,int64_t Val)366 static bool doesDispFit(M68kISelAddressMode &AM, int64_t Val) {
367 if (!AM.isDispAddrType())
368 return false;
369 return isIntN(AM.getDispSize(), Val);
370 }
371
372 /// Return an SDNode that returns the value of the global base register.
373 /// Output instructions required to initialize the global base register,
374 /// if necessary.
getGlobalBaseReg()375 SDNode *M68kDAGToDAGISel::getGlobalBaseReg() {
376 unsigned GlobalBaseReg = getInstrInfo()->getGlobalBaseReg(MF);
377 auto &DL = MF->getDataLayout();
378 return CurDAG->getRegister(GlobalBaseReg, TLI->getPointerTy(DL)).getNode();
379 }
380
foldOffsetIntoAddress(uint64_t Offset,M68kISelAddressMode & AM)381 bool M68kDAGToDAGISel::foldOffsetIntoAddress(uint64_t Offset,
382 M68kISelAddressMode &AM) {
383 // Cannot combine ExternalSymbol displacements with integer offsets.
384 if (Offset != 0 && (AM.ES || AM.MCSym))
385 return false;
386
387 int64_t Val = AM.Disp + Offset;
388
389 if (doesDispFit(AM, Val)) {
390 AM.Disp = Val;
391 return true;
392 }
393
394 return false;
395 }
396
397 //===----------------------------------------------------------------------===//
398 // Matchers
399 //===----------------------------------------------------------------------===//
400
401 /// Helper for MatchAddress. Add the specified node to the
402 /// specified addressing mode without any further recursion.
matchAddressBase(SDValue N,M68kISelAddressMode & AM)403 bool M68kDAGToDAGISel::matchAddressBase(SDValue N, M68kISelAddressMode &AM) {
404 // Is the base register already occupied?
405 if (AM.hasBase()) {
406 // If so, check to see if the scale index register is set.
407 if (!AM.hasIndexReg()) {
408 AM.IndexReg = N;
409 AM.Scale = 1;
410 return true;
411 }
412
413 // Otherwise, we cannot select it.
414 return false;
415 }
416
417 // Default, generate it as a register.
418 AM.BaseType = M68kISelAddressMode::Base::RegBase;
419 AM.BaseReg = N;
420 return true;
421 }
422
423 /// TODO Add TLS support
matchLoadInAddress(LoadSDNode * N,M68kISelAddressMode & AM)424 bool M68kDAGToDAGISel::matchLoadInAddress(LoadSDNode *N,
425 M68kISelAddressMode &AM) {
426 return false;
427 }
428
matchAddressRecursively(SDValue N,M68kISelAddressMode & AM,unsigned Depth)429 bool M68kDAGToDAGISel::matchAddressRecursively(SDValue N,
430 M68kISelAddressMode &AM,
431 unsigned Depth) {
432 SDLoc DL(N);
433
434 // Limit recursion.
435 if (Depth > 5)
436 return matchAddressBase(N, AM);
437
438 // If this is already a %PC relative address, we can only merge immediates
439 // into it. Instead of handling this in every case, we handle it here.
440 // PC relative addressing: %PC + 16-bit displacement!
441 if (AM.isPCRelative()) {
442 // FIXME JumpTable and ExternalSymbol address currently don't like
443 // displacements. It isn't very important, but should be fixed for
444 // consistency.
445
446 if (ConstantSDNode *Cst = dyn_cast<ConstantSDNode>(N))
447 if (foldOffsetIntoAddress(Cst->getSExtValue(), AM))
448 return true;
449 return false;
450 }
451
452 switch (N.getOpcode()) {
453 default:
454 break;
455
456 case ISD::Constant: {
457 uint64_t Val = cast<ConstantSDNode>(N)->getSExtValue();
458 if (foldOffsetIntoAddress(Val, AM))
459 return true;
460 break;
461 }
462
463 case M68kISD::Wrapper:
464 case M68kISD::WrapperPC:
465 if (matchWrapper(N, AM))
466 return true;
467 break;
468
469 case ISD::LOAD:
470 if (matchLoadInAddress(cast<LoadSDNode>(N), AM))
471 return true;
472 break;
473
474 case ISD::OR:
475 // We want to look through a transform in InstCombine and DAGCombiner that
476 // turns 'add' into 'or', so we can treat this 'or' exactly like an 'add'.
477 // Example: (or (and x, 1), (shl y, 3)) --> (add (and x, 1), (shl y, 3))
478 // An 'lea' can then be used to match the shift (multiply) and add:
479 // and $1, %esi
480 // lea (%rsi, %rdi, 8), %rax
481 if (CurDAG->haveNoCommonBitsSet(N.getOperand(0), N.getOperand(1)) &&
482 matchADD(N, AM, Depth))
483 return true;
484 break;
485
486 case ISD::ADD:
487 if (matchADD(N, AM, Depth))
488 return true;
489 break;
490
491 case ISD::FrameIndex:
492 if (AM.isDispAddrType() &&
493 AM.BaseType == M68kISelAddressMode::Base::RegBase &&
494 AM.BaseReg.getNode() == nullptr && doesDispFitFI(AM)) {
495 AM.BaseType = M68kISelAddressMode::Base::FrameIndexBase;
496 AM.BaseFrameIndex = cast<FrameIndexSDNode>(N)->getIndex();
497 return true;
498 }
499 break;
500 }
501
502 return matchAddressBase(N, AM);
503 }
504
505 /// Add the specified node to the specified addressing mode, returning true if
506 /// it cannot be done. This just pattern matches for the addressing mode.
matchAddress(SDValue N,M68kISelAddressMode & AM)507 bool M68kDAGToDAGISel::matchAddress(SDValue N, M68kISelAddressMode &AM) {
508 // TODO: Post-processing: Convert lea(,%reg,2) to lea(%reg,%reg), which has
509 // a smaller encoding and avoids a scaled-index.
510 // And make sure it is an indexed mode
511
512 // TODO: Post-processing: Convert foo to foo(%pc), even in non-PIC mode,
513 // because it has a smaller encoding.
514 // Make sure this must be done only if PC* modes are currently being matched
515 return matchAddressRecursively(N, AM, 0);
516 }
517
matchADD(SDValue & N,M68kISelAddressMode & AM,unsigned Depth)518 bool M68kDAGToDAGISel::matchADD(SDValue &N, M68kISelAddressMode &AM,
519 unsigned Depth) {
520 // Add an artificial use to this node so that we can keep track of
521 // it if it gets CSE'd with a different node.
522 HandleSDNode Handle(N);
523
524 M68kISelAddressMode Backup = AM;
525 if (matchAddressRecursively(N.getOperand(0), AM, Depth + 1) &&
526 matchAddressRecursively(Handle.getValue().getOperand(1), AM, Depth + 1)) {
527 return true;
528 }
529 AM = Backup;
530
531 // Try again after commuting the operands.
532 if (matchAddressRecursively(Handle.getValue().getOperand(1), AM, Depth + 1) &&
533 matchAddressRecursively(Handle.getValue().getOperand(0), AM, Depth + 1)) {
534 return true;
535 }
536 AM = Backup;
537
538 // If we couldn't fold both operands into the address at the same time,
539 // see if we can just put each operand into a register and fold at least
540 // the add.
541 if (!AM.hasBase() && !AM.hasIndexReg()) {
542 N = Handle.getValue();
543 AM.BaseReg = N.getOperand(0);
544 AM.IndexReg = N.getOperand(1);
545 AM.Scale = 1;
546 return true;
547 }
548
549 N = Handle.getValue();
550 return false;
551 }
552
553 /// Try to match M68kISD::Wrapper and M68kISD::WrapperPC nodes into an
554 /// addressing mode. These wrap things that will resolve down into a symbol
555 /// reference. If no match is possible, this returns true, otherwise it returns
556 /// false.
matchWrapper(SDValue N,M68kISelAddressMode & AM)557 bool M68kDAGToDAGISel::matchWrapper(SDValue N, M68kISelAddressMode &AM) {
558 // If the addressing mode already has a symbol as the displacement, we can
559 // never match another symbol.
560 if (AM.hasSymbolicDisplacement())
561 return false;
562
563 SDValue N0 = N.getOperand(0);
564
565 if (N.getOpcode() == M68kISD::WrapperPC) {
566
567 // If cannot match here just restore the old version
568 M68kISelAddressMode Backup = AM;
569
570 if (AM.hasBase()) {
571 return false;
572 }
573
574 if (auto *G = dyn_cast<GlobalAddressSDNode>(N0)) {
575 AM.GV = G->getGlobal();
576 AM.SymbolFlags = G->getTargetFlags();
577 if (!foldOffsetIntoAddress(G->getOffset(), AM)) {
578 AM = Backup;
579 return false;
580 }
581 } else if (auto *CP = dyn_cast<ConstantPoolSDNode>(N0)) {
582 AM.CP = CP->getConstVal();
583 AM.Alignment = CP->getAlign();
584 AM.SymbolFlags = CP->getTargetFlags();
585 if (!foldOffsetIntoAddress(CP->getOffset(), AM)) {
586 AM = Backup;
587 return false;
588 }
589 } else if (auto *S = dyn_cast<ExternalSymbolSDNode>(N0)) {
590 AM.ES = S->getSymbol();
591 AM.SymbolFlags = S->getTargetFlags();
592 } else if (auto *S = dyn_cast<MCSymbolSDNode>(N0)) {
593 AM.MCSym = S->getMCSymbol();
594 } else if (auto *J = dyn_cast<JumpTableSDNode>(N0)) {
595 AM.JT = J->getIndex();
596 AM.SymbolFlags = J->getTargetFlags();
597 } else if (auto *BA = dyn_cast<BlockAddressSDNode>(N0)) {
598 AM.BlockAddr = BA->getBlockAddress();
599 AM.SymbolFlags = BA->getTargetFlags();
600 if (!foldOffsetIntoAddress(BA->getOffset(), AM)) {
601 AM = Backup;
602 return false;
603 }
604 } else
605 llvm_unreachable("Unhandled symbol reference node.");
606
607 AM.setBaseReg(CurDAG->getRegister(M68k::PC, MVT::i32));
608 return true;
609 }
610
611 // This wrapper requires 32bit disp/imm field for Medium CM
612 if (!AM.isDisp32()) {
613 return false;
614 }
615
616 if (N.getOpcode() == M68kISD::Wrapper) {
617 if (auto *G = dyn_cast<GlobalAddressSDNode>(N0)) {
618 AM.GV = G->getGlobal();
619 AM.Disp += G->getOffset();
620 AM.SymbolFlags = G->getTargetFlags();
621 } else if (auto *CP = dyn_cast<ConstantPoolSDNode>(N0)) {
622 AM.CP = CP->getConstVal();
623 AM.Alignment = CP->getAlign();
624 AM.Disp += CP->getOffset();
625 AM.SymbolFlags = CP->getTargetFlags();
626 } else if (auto *S = dyn_cast<ExternalSymbolSDNode>(N0)) {
627 AM.ES = S->getSymbol();
628 AM.SymbolFlags = S->getTargetFlags();
629 } else if (auto *S = dyn_cast<MCSymbolSDNode>(N0)) {
630 AM.MCSym = S->getMCSymbol();
631 } else if (auto *J = dyn_cast<JumpTableSDNode>(N0)) {
632 AM.JT = J->getIndex();
633 AM.SymbolFlags = J->getTargetFlags();
634 } else if (auto *BA = dyn_cast<BlockAddressSDNode>(N0)) {
635 AM.BlockAddr = BA->getBlockAddress();
636 AM.Disp += BA->getOffset();
637 AM.SymbolFlags = BA->getTargetFlags();
638 } else
639 llvm_unreachable("Unhandled symbol reference node.");
640 return true;
641 }
642
643 return false;
644 }
645
646 //===----------------------------------------------------------------------===//
647 // Selectors
648 //===----------------------------------------------------------------------===//
649
Select(SDNode * Node)650 void M68kDAGToDAGISel::Select(SDNode *Node) {
651 unsigned Opcode = Node->getOpcode();
652 SDLoc DL(Node);
653
654 LLVM_DEBUG(dbgs() << "Selecting: "; Node->dump(CurDAG); dbgs() << '\n');
655
656 if (Node->isMachineOpcode()) {
657 LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << '\n');
658 Node->setNodeId(-1);
659 return; // Already selected.
660 }
661
662 switch (Opcode) {
663 default:
664 break;
665
666 case M68kISD::GLOBAL_BASE_REG:
667 ReplaceNode(Node, getGlobalBaseReg());
668 return;
669 }
670
671 SelectCode(Node);
672 }
673
SelectARIPI(SDNode * Parent,SDValue N,SDValue & Base)674 bool M68kDAGToDAGISel::SelectARIPI(SDNode *Parent, SDValue N, SDValue &Base) {
675 LLVM_DEBUG(dbgs() << "Selecting AddrType::ARIPI: ");
676 LLVM_DEBUG(dbgs() << "NOT IMPLEMENTED\n");
677 return false;
678 }
679
SelectARIPD(SDNode * Parent,SDValue N,SDValue & Base)680 bool M68kDAGToDAGISel::SelectARIPD(SDNode *Parent, SDValue N, SDValue &Base) {
681 LLVM_DEBUG(dbgs() << "Selecting AddrType::ARIPD: ");
682 LLVM_DEBUG(dbgs() << "NOT IMPLEMENTED\n");
683 return false;
684 }
685
SelectARID(SDNode * Parent,SDValue N,SDValue & Disp,SDValue & Base)686 bool M68kDAGToDAGISel::SelectARID(SDNode *Parent, SDValue N, SDValue &Disp,
687 SDValue &Base) {
688 LLVM_DEBUG(dbgs() << "Selecting AddrType::ARID: ");
689 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARID);
690
691 if (!matchAddress(N, AM))
692 return false;
693
694 if (AM.isPCRelative()) {
695 LLVM_DEBUG(dbgs() << "REJECT: Cannot match PC relative address\n");
696 return false;
697 }
698
699 // If this is a frame index, grab it
700 if (getFrameIndexAddress(AM, SDLoc(N), Disp, Base)) {
701 LLVM_DEBUG(dbgs() << "SUCCESS matched FI\n");
702 return true;
703 }
704
705 if (AM.hasIndexReg()) {
706 LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index\n");
707 return false;
708 }
709
710 if (!AM.hasBaseReg()) {
711 LLVM_DEBUG(dbgs() << "REJECT: No Base reg\n");
712 return false;
713 }
714
715 if (getSymbolicDisplacement(AM, SDLoc(N), Disp)) {
716 assert(!AM.Disp && "Should not be any displacement");
717 LLVM_DEBUG(dbgs() << "SUCCESS, matched Symbol\n");
718 return true;
719 }
720
721 // Give a chance to AddrType::ARI
722 if (AM.Disp == 0) {
723 LLVM_DEBUG(dbgs() << "REJECT: No displacement\n");
724 return false;
725 }
726
727 Base = AM.BaseReg;
728 Disp = getI16Imm(AM.Disp, SDLoc(N));
729
730 LLVM_DEBUG(dbgs() << "SUCCESS\n");
731 return true;
732 }
733
isAddressBase(const SDValue & N)734 static bool isAddressBase(const SDValue &N) {
735 switch (N.getOpcode()) {
736 case ISD::ADD:
737 case ISD::ADDC:
738 return llvm::any_of(N.getNode()->ops(),
739 [](const SDUse &U) { return isAddressBase(U.get()); });
740 case M68kISD::Wrapper:
741 case M68kISD::WrapperPC:
742 case M68kISD::GLOBAL_BASE_REG:
743 return true;
744 default:
745 return false;
746 }
747 }
748
SelectARII(SDNode * Parent,SDValue N,SDValue & Disp,SDValue & Base,SDValue & Index)749 bool M68kDAGToDAGISel::SelectARII(SDNode *Parent, SDValue N, SDValue &Disp,
750 SDValue &Base, SDValue &Index) {
751 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARII);
752 LLVM_DEBUG(dbgs() << "Selecting AddrType::ARII: ");
753
754 if (!matchAddress(N, AM))
755 return false;
756
757 if (AM.isPCRelative()) {
758 LLVM_DEBUG(dbgs() << "REJECT: PC relative\n");
759 return false;
760 }
761
762 if (!AM.hasIndexReg()) {
763 LLVM_DEBUG(dbgs() << "REJECT: No Index\n");
764 return false;
765 }
766
767 if (!AM.hasBaseReg()) {
768 LLVM_DEBUG(dbgs() << "REJECT: No Base\n");
769 return false;
770 }
771
772 if (!isAddressBase(AM.BaseReg) && isAddressBase(AM.IndexReg)) {
773 Base = AM.IndexReg;
774 Index = AM.BaseReg;
775 } else {
776 Base = AM.BaseReg;
777 Index = AM.IndexReg;
778 }
779
780 if (AM.hasSymbolicDisplacement()) {
781 LLVM_DEBUG(dbgs() << "REJECT, Cannot match symbolic displacement\n");
782 return false;
783 }
784
785 // The idea here is that we want to use AddrType::ARII without displacement
786 // only if necessary like memory operations, otherwise this must be lowered
787 // into addition
788 if (AM.Disp == 0 && (!Parent || (Parent->getOpcode() != ISD::LOAD &&
789 Parent->getOpcode() != ISD::STORE))) {
790 LLVM_DEBUG(dbgs() << "REJECT: Displacement is Zero\n");
791 return false;
792 }
793
794 Disp = getI8Imm(AM.Disp, SDLoc(N));
795
796 LLVM_DEBUG(dbgs() << "SUCCESS\n");
797 return true;
798 }
799
SelectAL(SDNode * Parent,SDValue N,SDValue & Sym)800 bool M68kDAGToDAGISel::SelectAL(SDNode *Parent, SDValue N, SDValue &Sym) {
801 LLVM_DEBUG(dbgs() << "Selecting AddrType::AL: ");
802 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::AL);
803
804 if (!matchAddress(N, AM)) {
805 LLVM_DEBUG(dbgs() << "REJECT: Match failed\n");
806 return false;
807 }
808
809 if (AM.isPCRelative()) {
810 LLVM_DEBUG(dbgs() << "REJECT: Cannot match PC relative address\n");
811 return false;
812 }
813
814 if (AM.hasBase()) {
815 LLVM_DEBUG(dbgs() << "REJECT: Cannot match Base\n");
816 return false;
817 }
818
819 if (AM.hasIndexReg()) {
820 LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index\n");
821 return false;
822 }
823
824 if (getSymbolicDisplacement(AM, SDLoc(N), Sym)) {
825 LLVM_DEBUG(dbgs() << "SUCCESS: Matched symbol\n");
826 return true;
827 }
828
829 if (AM.Disp) {
830 Sym = getI32Imm(AM.Disp, SDLoc(N));
831 LLVM_DEBUG(dbgs() << "SUCCESS\n");
832 return true;
833 }
834
835 LLVM_DEBUG(dbgs() << "REJECT: Not Symbol or Disp\n");
836 return false;
837 ;
838 }
839
SelectPCD(SDNode * Parent,SDValue N,SDValue & Disp)840 bool M68kDAGToDAGISel::SelectPCD(SDNode *Parent, SDValue N, SDValue &Disp) {
841 LLVM_DEBUG(dbgs() << "Selecting AddrType::PCD: ");
842 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::PCD);
843
844 if (!matchAddress(N, AM))
845 return false;
846
847 if (!AM.isPCRelative()) {
848 LLVM_DEBUG(dbgs() << "REJECT: Not PC relative\n");
849 return false;
850 }
851
852 if (AM.hasIndexReg()) {
853 LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index\n");
854 return false;
855 }
856
857 if (getSymbolicDisplacement(AM, SDLoc(N), Disp)) {
858 LLVM_DEBUG(dbgs() << "SUCCESS, matched Symbol\n");
859 return true;
860 }
861
862 Disp = getI16Imm(AM.Disp, SDLoc(N));
863
864 LLVM_DEBUG(dbgs() << "SUCCESS\n");
865 return true;
866 }
867
SelectPCI(SDNode * Parent,SDValue N,SDValue & Disp,SDValue & Index)868 bool M68kDAGToDAGISel::SelectPCI(SDNode *Parent, SDValue N, SDValue &Disp,
869 SDValue &Index) {
870 LLVM_DEBUG(dbgs() << "Selecting AddrType::PCI: ");
871 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::PCI);
872
873 if (!matchAddress(N, AM))
874 return false;
875
876 if (!AM.isPCRelative()) {
877 LLVM_DEBUG(dbgs() << "REJECT: Not PC relative\n");
878 return false;
879 }
880
881 if (!AM.hasIndexReg()) {
882 LLVM_DEBUG(dbgs() << "REJECT: No Index\n");
883 return false;
884 }
885
886 Index = AM.IndexReg;
887
888 if (getSymbolicDisplacement(AM, SDLoc(N), Disp)) {
889 assert(!AM.Disp && "Should not be any displacement");
890 LLVM_DEBUG(dbgs() << "SUCCESS, matched Symbol\n");
891 return true;
892 }
893
894 Disp = getI8Imm(AM.Disp, SDLoc(N));
895
896 LLVM_DEBUG(dbgs() << "SUCCESS\n");
897 return true;
898 }
899
SelectARI(SDNode * Parent,SDValue N,SDValue & Base)900 bool M68kDAGToDAGISel::SelectARI(SDNode *Parent, SDValue N, SDValue &Base) {
901 LLVM_DEBUG(dbgs() << "Selecting AddrType::ARI: ");
902 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARI);
903
904 if (!matchAddress(N, AM)) {
905 LLVM_DEBUG(dbgs() << "REJECT: Match failed\n");
906 return false;
907 }
908
909 if (AM.isPCRelative()) {
910 LLVM_DEBUG(dbgs() << "REJECT: Cannot match PC relative address\n");
911 return false;
912 }
913
914 // AddrType::ARI does not use these
915 if (AM.hasIndexReg() || AM.Disp != 0) {
916 LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index or Disp\n");
917 return false;
918 }
919
920 // Must be matched by AddrType::AL
921 if (AM.hasSymbolicDisplacement()) {
922 LLVM_DEBUG(dbgs() << "REJECT: Cannot match Symbolic Disp\n");
923 return false;
924 }
925
926 if (AM.hasBaseReg()) {
927 Base = AM.BaseReg;
928 LLVM_DEBUG(dbgs() << "SUCCESS\n");
929 return true;
930 }
931
932 return false;
933 }
934