LLVM 19.0.0git
M68kISelDAGToDAG.cpp
Go to the documentation of this file.
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
27#include "llvm/IR/CFG.h"
28#include "llvm/IR/GlobalValue.h"
30#include "llvm/IR/Intrinsics.h"
31#include "llvm/IR/Type.h"
33#include "llvm/Support/Debug.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 };
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>(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
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(AM.Disp, DL);
241 Base = CurDAG->getTargetFrameIndex(
242 AM.BaseFrameIndex, TLI->getPointerTy(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(U->getOperand(0)))
344 return false;
345 break;
346 }
347 }
348
349 return true;
350}
351
352bool M68kDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) {
353 Subtarget = &MF.getSubtarget<M68kSubtarget>();
355}
356
357/// This pass converts a legalized DAG into a M68k-specific DAG,
358/// ready for instruction scheduling.
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(AM.getDispSize() - 1, AM.Disp);
368}
369
370static bool doesDispFit(M68kISelAddressMode &AM, int64_t Val) {
371 if (!AM.isDispAddrType())
372 return false;
373 return isIntN(AM.getDispSize(), 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(GlobalBaseReg, 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>(N))
451 if (foldOffsetIntoAddress(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>(N)->getSExtValue();
462 if (foldOffsetIntoAddress(Val, AM))
463 return true;
464 break;
465 }
466
467 case M68kISD::Wrapper:
469 if (matchWrapper(N, AM))
470 return true;
471 break;
472
473 case ISD::LOAD:
474 if (matchLoadInAddress(cast<LoadSDNode>(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(N.getOperand(0), N.getOperand(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>(N)->getIndex();
501 return true;
502 }
503 break;
504
506 GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(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, 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.getOperand(0), AM, Depth + 1) &&
537 matchAddressRecursively(Handle.getValue().getOperand(1), AM, Depth + 1)) {
538 return true;
539 }
540 AM = Backup;
541
542 // Try again after commuting the operands.
543 if (matchAddressRecursively(Handle.getValue().getOperand(1), AM, Depth + 1) &&
544 matchAddressRecursively(Handle.getValue().getOperand(0), AM, 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(0);
555 AM.IndexReg = N.getOperand(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(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>(N0)) {
586 AM.GV = G->getGlobal();
587 AM.SymbolFlags = G->getTargetFlags();
588 if (!foldOffsetIntoAddress(G->getOffset(), AM)) {
589 AM = Backup;
590 return false;
591 }
592 } else if (auto *CP = dyn_cast<ConstantPoolSDNode>(N0)) {
593 AM.CP = CP->getConstVal();
594 AM.Alignment = CP->getAlign();
595 AM.SymbolFlags = CP->getTargetFlags();
596 if (!foldOffsetIntoAddress(CP->getOffset(), AM)) {
597 AM = Backup;
598 return false;
599 }
600 } else if (auto *S = dyn_cast<ExternalSymbolSDNode>(N0)) {
601 AM.ES = S->getSymbol();
602 AM.SymbolFlags = S->getTargetFlags();
603 } else if (auto *S = dyn_cast<MCSymbolSDNode>(N0)) {
604 AM.MCSym = S->getMCSymbol();
605 } else if (auto *J = dyn_cast<JumpTableSDNode>(N0)) {
606 AM.JT = J->getIndex();
607 AM.SymbolFlags = J->getTargetFlags();
608 } else if (auto *BA = dyn_cast<BlockAddressSDNode>(N0)) {
609 AM.BlockAddr = BA->getBlockAddress();
610 AM.SymbolFlags = BA->getTargetFlags();
611 if (!foldOffsetIntoAddress(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::PC, MVT::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>(N0)) {
629 AM.GV = G->getGlobal();
630 AM.Disp += G->getOffset();
631 AM.SymbolFlags = G->getTargetFlags();
632 } else if (auto *CP = dyn_cast<ConstantPoolSDNode>(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>(N0)) {
638 AM.ES = S->getSymbol();
639 AM.SymbolFlags = S->getTargetFlags();
640 } else if (auto *S = dyn_cast<MCSymbolSDNode>(N0)) {
641 AM.MCSym = S->getMCSymbol();
642 } else if (auto *J = dyn_cast<JumpTableSDNode>(N0)) {
643 AM.JT = J->getIndex();
644 AM.SymbolFlags = J->getTargetFlags();
645 } else if (auto *BA = dyn_cast<BlockAddressSDNode>(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
678 SDValue GOT = CurDAG->getTargetExternalSymbol(
679 "_GLOBAL_OFFSET_TABLE_", MVT::i32, M68kII::MO_GOTPCREL);
680 MachineSDNode *Res =
681 CurDAG->getMachineNode(M68k::LEA32q, DL, MVT::i32, GOT);
682 ReplaceNode(Node, Res);
683 return;
684 }
685
687 ReplaceNode(Node, 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, 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, SDLoc(N), 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(AM.Disp, 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(N.getNode()->ops(),
760 [](const SDUse &U) { return isAddressBase(U.get()); });
761 case M68kISD::Wrapper:
764 return true;
765 default:
766 return false;
767 }
768}
769
770bool M68kDAGToDAGISel::SelectARII(SDNode *Parent, SDValue N, SDValue &Disp,
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(AM.BaseReg) && isAddressBase(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(AM.Disp, 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, SDLoc(N), Sym)) {
846 LLVM_DEBUG(dbgs() << "SUCCESS: Matched symbol\n");
847 return true;
848 }
849
850 if (AM.Disp) {
851 Sym = getI32Imm(AM.Disp, 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, SDLoc(N), Disp)) {
879 LLVM_DEBUG(dbgs() << "SUCCESS, matched Symbol\n");
880 return true;
881 }
882
883 Disp = getI16Imm(AM.Disp, 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, SDLoc(N), 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(AM.Disp, 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(nullptr, Op, Operands[1], Operands[2], Operands[3]) &&
979 addKind(Operands[0], AMK::f)) {
980 OutOps.insert(OutOps.end(), &Operands[0], Operands + 4);
981 return false;
982 }
983
984 if ((SelectPCI(nullptr, Op, Operands[1], Operands[2]) &&
985 addKind(Operands[0], AMK::k)) ||
986 (SelectARID(nullptr, Op, Operands[1], Operands[2]) &&
987 addKind(Operands[0], AMK::p))) {
988 OutOps.insert(OutOps.end(), &Operands[0], Operands + 3);
989 return false;
990 }
991
992 if ((SelectPCD(nullptr, Op, Operands[1]) && addKind(Operands[0], AMK::q)) ||
993 (SelectARI(nullptr, Op, Operands[1]) && addKind(Operands[0], AMK::j)) ||
994 (SelectAL(nullptr, Op, Operands[1]) && addKind(Operands[0], AMK::b))) {
995 OutOps.insert(OutOps.end(), {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(nullptr, Op, Base) && addKind(AMKind, AMK::j)) {
1008 OutOps.insert(OutOps.end(), {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(nullptr, Op, Offset, Base) && addKind(AMKind, AMK::p)) {
1018 OutOps.insert(OutOps.end(), {AMKind, Offset, Base});
1019 return false;
1020 }
1021 return true;
1022 }
1023 default:
1024 return true;
1025 }
1026}
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
amdgpu AMDGPU Register Bank Select
#define LLVM_DEBUG(X)
Definition: Debug.h:101
Symbol * Sym
Definition: ELF_riscv.cpp:479
This file provides various utilities for inspecting and working with the control flow graph in LLVM I...
static bool doesDispFit(M68kISelAddressMode &AM, int64_t Val)
static bool doesDispFitFI(M68kISelAddressMode &AM)
static bool isAddressBase(const SDValue &N)
#define PASS_NAME
#define DEBUG_TYPE
This file declares the M68k specific subclass of MachineFunctionInfo.
This file contains the M68k implementation of the TargetRegisterInfo class.
This file declares the M68k specific subclass of TargetMachine.
This file contains the entry points for global functions defined in the M68k target library,...
#define G(x, y, z)
Definition: MD5.cpp:56
mir Rename Register Operands
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
const char LLVMTargetMachineRef TM
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:38
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
DEMANGLE_DUMP_METHOD void dump() const
The address of a basic block.
Definition: Constants.h:889
This is an important base class in LLVM.
Definition: Constant.h:41
This class represents an Operation in the Expression.
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:311
const GlobalValue * getGlobal() const
This class is used to form a handle around another node that is persistent and is updated across invo...
This class is used to represent ISD::LOAD nodes.
const M68kInstrInfo * getInstrInfo() const override
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition: MCSymbol.h:40
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
An SDNode that represents everything that will be needed to construct a MachineInstr.
Wrapper class for IR location info (IR ordering and DebugLoc) to be passed into SDNode creation funct...
Represents one node in the SelectionDAG.
void dump() const
Dump this node, for debugging.
unsigned getOpcode() const
Return the SelectionDAG opcode value for this node.
Represents a use of a SDNode.
Unlike LLVM values, Selection DAG nodes may return multiple values as the result of a computation.
SDNode * getNode() const
get the SDNode which holds the desired result
SelectionDAGISel - This is the common base class used for SelectionDAG-based pattern-matching instruc...
virtual bool SelectInlineAsmMemoryOperand(const SDValue &Op, InlineAsm::ConstraintCode ConstraintID, std::vector< SDValue > &OutOps)
SelectInlineAsmMemoryOperand - Select the specified address as a target addressing mode,...
virtual bool IsProfitableToFold(SDValue N, SDNode *U, SDNode *Root) const
IsProfitableToFold - Returns true if it's profitable to fold the specific operand node N of U during ...
bool runOnMachineFunction(MachineFunction &MF) override
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
@ ADDC
Carry-setting nodes for multiple precision addition and subtraction.
Definition: ISDOpcodes.h:269
@ ADD
Simple integer binary arithmetic operators.
Definition: ISDOpcodes.h:239
@ LOAD
LOAD and STORE have token chains as their first operand, then the same operands as an LLVM load/store...
Definition: ISDOpcodes.h:1037
@ FrameIndex
Definition: ISDOpcodes.h:80
@ GLOBAL_OFFSET_TABLE
The address of the GOT.
Definition: ISDOpcodes.h:87
@ TargetGlobalTLSAddress
Definition: ISDOpcodes.h:165
@ MO_GOTPCREL
On a symbol operand this indicates that the immediate is offset to the GOT entry for the symbol name ...
Definition: M68kBaseInfo.h:153
@ WrapperPC
Special wrapper used under M68k PIC mode for PC relative displacements.
@ Wrapper
A wrapper node for TargetConstantPool, TargetExternalSymbol, and TargetGlobalAddress.
@ GlobalBaseReg
The result of the mflr at function entry, used for PIC code.
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
@ Offset
Definition: DWP.cpp:456
bool isNullConstant(SDValue V)
Returns true if V is a constant integer zero.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1729
FunctionPass * createM68kISelDag(M68kTargetMachine &TM)
This pass converts a legalized DAG into a M68k-specific DAG, ready for instruction scheduling.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
bool isIntN(unsigned N, int64_t x)
Checks if an signed integer fits into the given (dynamic) bit width.
Definition: MathExtras.h:244
#define N
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39