LLVM 17.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
230 bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,
231 std::vector<SDValue> &OutOps) override;
232
233 // If Address Mode represents Frame Index store FI in Disp and
234 // Displacement bit size in Base. These values are read symmetrically by
235 // M68kRegisterInfo::eliminateFrameIndex method
236 inline bool getFrameIndexAddress(M68kISelAddressMode &AM, const SDLoc &DL,
237 SDValue &Disp, SDValue &Base) {
238 if (AM.BaseType == M68kISelAddressMode::Base::FrameIndexBase) {
239 Disp = getI32Imm(AM.Disp, DL);
240 Base = CurDAG->getTargetFrameIndex(
241 AM.BaseFrameIndex, TLI->getPointerTy(CurDAG->getDataLayout()));
242 return true;
243 }
244
245 return false;
246 }
247
248 // Gets a symbol plus optional displacement
249 inline bool getSymbolicDisplacement(M68kISelAddressMode &AM, const SDLoc &DL,
250 SDValue &Sym) {
251 if (AM.GV) {
252 Sym = CurDAG->getTargetGlobalAddress(AM.GV, SDLoc(), MVT::i32, AM.Disp,
253 AM.SymbolFlags);
254 return true;
255 }
256
257 if (AM.CP) {
258 Sym = CurDAG->getTargetConstantPool(AM.CP, MVT::i32, AM.Alignment,
259 AM.Disp, AM.SymbolFlags);
260 return true;
261 }
262
263 if (AM.ES) {
264 assert(!AM.Disp && "Non-zero displacement is ignored with ES.");
265 Sym = CurDAG->getTargetExternalSymbol(AM.ES, MVT::i32, AM.SymbolFlags);
266 return true;
267 }
268
269 if (AM.MCSym) {
270 assert(!AM.Disp && "Non-zero displacement is ignored with MCSym.");
271 assert(AM.SymbolFlags == 0 && "oo");
272 Sym = CurDAG->getMCSymbol(AM.MCSym, MVT::i32);
273 return true;
274 }
275
276 if (AM.JT != -1) {
277 assert(!AM.Disp && "Non-zero displacement is ignored with JT.");
278 Sym = CurDAG->getTargetJumpTable(AM.JT, MVT::i32, AM.SymbolFlags);
279 return true;
280 }
281
282 if (AM.BlockAddr) {
283 Sym = CurDAG->getTargetBlockAddress(AM.BlockAddr, MVT::i32, AM.Disp,
284 AM.SymbolFlags);
285 return true;
286 }
287
288 return false;
289 }
290
291 /// Return a target constant with the specified value of type i8.
292 inline SDValue getI8Imm(int64_t Imm, const SDLoc &DL) {
293 return CurDAG->getTargetConstant(Imm, DL, MVT::i8);
294 }
295
296 /// Return a target constant with the specified value of type i8.
297 inline SDValue getI16Imm(int64_t Imm, const SDLoc &DL) {
298 return CurDAG->getTargetConstant(Imm, DL, MVT::i16);
299 }
300
301 /// Return a target constant with the specified value, of type i32.
302 inline SDValue getI32Imm(int64_t Imm, const SDLoc &DL) {
303 return CurDAG->getTargetConstant(Imm, DL, MVT::i32);
304 }
305
306 /// Return a reference to the TargetInstrInfo, casted to the target-specific
307 /// type.
308 const M68kInstrInfo *getInstrInfo() const {
309 return Subtarget->getInstrInfo();
310 }
311
312 /// Return an SDNode that returns the value of the global base register.
313 /// Output instructions required to initialize the global base register,
314 /// if necessary.
315 SDNode *getGlobalBaseReg();
316};
317
318char M68kDAGToDAGISel::ID;
319
320} // namespace
321
322INITIALIZE_PASS(M68kDAGToDAGISel, DEBUG_TYPE, PASS_NAME, false, false)
323
324bool M68kDAGToDAGISel::IsProfitableToFold(SDValue N, SDNode *U,
325 SDNode *Root) const {
326 if (OptLevel == CodeGenOpt::None)
327 return false;
328
329 if (U == Root) {
330 switch (U->getOpcode()) {
331 default:
332 return true;
333 case M68kISD::SUB:
334 case ISD::SUB:
335 // Prefer NEG instruction when zero subtracts a value.
336 // e.g.
337 // move.l #0, %d0
338 // sub.l (4,%sp), %d0
339 // vs.
340 // move.l (4,%sp), %d0
341 // neg.l %d0
342 if (llvm::isNullConstant(U->getOperand(0)))
343 return false;
344 break;
345 }
346 }
347
348 return true;
349}
350
351bool M68kDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) {
352 Subtarget = &MF.getSubtarget<M68kSubtarget>();
354}
355
356/// This pass converts a legalized DAG into a M68k-specific DAG,
357/// ready for instruction scheduling.
359 return new M68kDAGToDAGISel(TM);
360}
361
362static bool doesDispFitFI(M68kISelAddressMode &AM) {
363 if (!AM.isDispAddrType())
364 return false;
365 // -1 to make sure that resolved FI will fit into Disp field
366 return isIntN(AM.getDispSize() - 1, AM.Disp);
367}
368
369static bool doesDispFit(M68kISelAddressMode &AM, int64_t Val) {
370 if (!AM.isDispAddrType())
371 return false;
372 return isIntN(AM.getDispSize(), Val);
373}
374
375/// Return an SDNode that returns the value of the global base register.
376/// Output instructions required to initialize the global base register,
377/// if necessary.
378SDNode *M68kDAGToDAGISel::getGlobalBaseReg() {
379 unsigned GlobalBaseReg = getInstrInfo()->getGlobalBaseReg(MF);
380 auto &DL = MF->getDataLayout();
381 return CurDAG->getRegister(GlobalBaseReg, TLI->getPointerTy(DL)).getNode();
382}
383
384bool M68kDAGToDAGISel::foldOffsetIntoAddress(uint64_t Offset,
385 M68kISelAddressMode &AM) {
386 // Cannot combine ExternalSymbol displacements with integer offsets.
387 if (Offset != 0 && (AM.ES || AM.MCSym))
388 return false;
389
390 int64_t Val = AM.Disp + Offset;
391
392 if (doesDispFit(AM, Val)) {
393 AM.Disp = Val;
394 return true;
395 }
396
397 return false;
398}
399
400//===----------------------------------------------------------------------===//
401// Matchers
402//===----------------------------------------------------------------------===//
403
404/// Helper for MatchAddress. Add the specified node to the
405/// specified addressing mode without any further recursion.
406bool M68kDAGToDAGISel::matchAddressBase(SDValue N, M68kISelAddressMode &AM) {
407 // Is the base register already occupied?
408 if (AM.hasBase()) {
409 // If so, check to see if the scale index register is set.
410 if (!AM.hasIndexReg()) {
411 AM.IndexReg = N;
412 AM.Scale = 1;
413 return true;
414 }
415
416 // Otherwise, we cannot select it.
417 return false;
418 }
419
420 // Default, generate it as a register.
421 AM.BaseType = M68kISelAddressMode::Base::RegBase;
422 AM.BaseReg = N;
423 return true;
424}
425
426/// TODO Add TLS support
427bool M68kDAGToDAGISel::matchLoadInAddress(LoadSDNode *N,
428 M68kISelAddressMode &AM) {
429 return false;
430}
431
432bool M68kDAGToDAGISel::matchAddressRecursively(SDValue N,
433 M68kISelAddressMode &AM,
434 unsigned Depth) {
435 SDLoc DL(N);
436
437 // Limit recursion.
438 if (Depth > 5)
439 return matchAddressBase(N, AM);
440
441 // If this is already a %PC relative address, we can only merge immediates
442 // into it. Instead of handling this in every case, we handle it here.
443 // PC relative addressing: %PC + 16-bit displacement!
444 if (AM.isPCRelative()) {
445 // FIXME JumpTable and ExternalSymbol address currently don't like
446 // displacements. It isn't very important, but should be fixed for
447 // consistency.
448
449 if (ConstantSDNode *Cst = dyn_cast<ConstantSDNode>(N))
450 if (foldOffsetIntoAddress(Cst->getSExtValue(), AM))
451 return true;
452 return false;
453 }
454
455 switch (N.getOpcode()) {
456 default:
457 break;
458
459 case ISD::Constant: {
460 uint64_t Val = cast<ConstantSDNode>(N)->getSExtValue();
461 if (foldOffsetIntoAddress(Val, AM))
462 return true;
463 break;
464 }
465
466 case M68kISD::Wrapper:
468 if (matchWrapper(N, AM))
469 return true;
470 break;
471
472 case ISD::LOAD:
473 if (matchLoadInAddress(cast<LoadSDNode>(N), AM))
474 return true;
475 break;
476
477 case ISD::OR:
478 // We want to look through a transform in InstCombine and DAGCombiner that
479 // turns 'add' into 'or', so we can treat this 'or' exactly like an 'add'.
480 // Example: (or (and x, 1), (shl y, 3)) --> (add (and x, 1), (shl y, 3))
481 // An 'lea' can then be used to match the shift (multiply) and add:
482 // and $1, %esi
483 // lea (%rsi, %rdi, 8), %rax
484 if (CurDAG->haveNoCommonBitsSet(N.getOperand(0), N.getOperand(1)) &&
485 matchADD(N, AM, Depth))
486 return true;
487 break;
488
489 case ISD::ADD:
490 if (matchADD(N, AM, Depth))
491 return true;
492 break;
493
494 case ISD::FrameIndex:
495 if (AM.isDispAddrType() &&
496 AM.BaseType == M68kISelAddressMode::Base::RegBase &&
497 AM.BaseReg.getNode() == nullptr && doesDispFitFI(AM)) {
498 AM.BaseType = M68kISelAddressMode::Base::FrameIndexBase;
499 AM.BaseFrameIndex = cast<FrameIndexSDNode>(N)->getIndex();
500 return true;
501 }
502 break;
503 }
504
505 return matchAddressBase(N, AM);
506}
507
508/// Add the specified node to the specified addressing mode, returning true if
509/// it cannot be done. This just pattern matches for the addressing mode.
510bool M68kDAGToDAGISel::matchAddress(SDValue N, M68kISelAddressMode &AM) {
511 // TODO: Post-processing: Convert lea(,%reg,2) to lea(%reg,%reg), which has
512 // a smaller encoding and avoids a scaled-index.
513 // And make sure it is an indexed mode
514
515 // TODO: Post-processing: Convert foo to foo(%pc), even in non-PIC mode,
516 // because it has a smaller encoding.
517 // Make sure this must be done only if PC* modes are currently being matched
518 return matchAddressRecursively(N, AM, 0);
519}
520
521bool M68kDAGToDAGISel::matchADD(SDValue &N, M68kISelAddressMode &AM,
522 unsigned Depth) {
523 // Add an artificial use to this node so that we can keep track of
524 // it if it gets CSE'd with a different node.
525 HandleSDNode Handle(N);
526
527 M68kISelAddressMode Backup = AM;
528 if (matchAddressRecursively(N.getOperand(0), AM, Depth + 1) &&
529 matchAddressRecursively(Handle.getValue().getOperand(1), AM, Depth + 1)) {
530 return true;
531 }
532 AM = Backup;
533
534 // Try again after commuting the operands.
535 if (matchAddressRecursively(Handle.getValue().getOperand(1), AM, Depth + 1) &&
536 matchAddressRecursively(Handle.getValue().getOperand(0), AM, Depth + 1)) {
537 return true;
538 }
539 AM = Backup;
540
541 // If we couldn't fold both operands into the address at the same time,
542 // see if we can just put each operand into a register and fold at least
543 // the add.
544 if (!AM.hasBase() && !AM.hasIndexReg()) {
545 N = Handle.getValue();
546 AM.BaseReg = N.getOperand(0);
547 AM.IndexReg = N.getOperand(1);
548 AM.Scale = 1;
549 return true;
550 }
551
552 N = Handle.getValue();
553 return false;
554}
555
556/// Try to match M68kISD::Wrapper and M68kISD::WrapperPC nodes into an
557/// addressing mode. These wrap things that will resolve down into a symbol
558/// reference. If no match is possible, this returns true, otherwise it returns
559/// false.
560bool M68kDAGToDAGISel::matchWrapper(SDValue N, M68kISelAddressMode &AM) {
561 // If the addressing mode already has a symbol as the displacement, we can
562 // never match another symbol.
563 if (AM.hasSymbolicDisplacement())
564 return false;
565
566 SDValue N0 = N.getOperand(0);
567
568 if (N.getOpcode() == M68kISD::WrapperPC) {
569
570 // If cannot match here just restore the old version
571 M68kISelAddressMode Backup = AM;
572
573 if (AM.hasBase()) {
574 return false;
575 }
576
577 if (auto *G = dyn_cast<GlobalAddressSDNode>(N0)) {
578 AM.GV = G->getGlobal();
579 AM.SymbolFlags = G->getTargetFlags();
580 if (!foldOffsetIntoAddress(G->getOffset(), AM)) {
581 AM = Backup;
582 return false;
583 }
584 } else if (auto *CP = dyn_cast<ConstantPoolSDNode>(N0)) {
585 AM.CP = CP->getConstVal();
586 AM.Alignment = CP->getAlign();
587 AM.SymbolFlags = CP->getTargetFlags();
588 if (!foldOffsetIntoAddress(CP->getOffset(), AM)) {
589 AM = Backup;
590 return false;
591 }
592 } else if (auto *S = dyn_cast<ExternalSymbolSDNode>(N0)) {
593 AM.ES = S->getSymbol();
594 AM.SymbolFlags = S->getTargetFlags();
595 } else if (auto *S = dyn_cast<MCSymbolSDNode>(N0)) {
596 AM.MCSym = S->getMCSymbol();
597 } else if (auto *J = dyn_cast<JumpTableSDNode>(N0)) {
598 AM.JT = J->getIndex();
599 AM.SymbolFlags = J->getTargetFlags();
600 } else if (auto *BA = dyn_cast<BlockAddressSDNode>(N0)) {
601 AM.BlockAddr = BA->getBlockAddress();
602 AM.SymbolFlags = BA->getTargetFlags();
603 if (!foldOffsetIntoAddress(BA->getOffset(), AM)) {
604 AM = Backup;
605 return false;
606 }
607 } else
608 llvm_unreachable("Unhandled symbol reference node.");
609
610 AM.setBaseReg(CurDAG->getRegister(M68k::PC, MVT::i32));
611 return true;
612 }
613
614 // This wrapper requires 32bit disp/imm field for Medium CM
615 if (!AM.isDisp32()) {
616 return false;
617 }
618
619 if (N.getOpcode() == M68kISD::Wrapper) {
620 if (auto *G = dyn_cast<GlobalAddressSDNode>(N0)) {
621 AM.GV = G->getGlobal();
622 AM.Disp += G->getOffset();
623 AM.SymbolFlags = G->getTargetFlags();
624 } else if (auto *CP = dyn_cast<ConstantPoolSDNode>(N0)) {
625 AM.CP = CP->getConstVal();
626 AM.Alignment = CP->getAlign();
627 AM.Disp += CP->getOffset();
628 AM.SymbolFlags = CP->getTargetFlags();
629 } else if (auto *S = dyn_cast<ExternalSymbolSDNode>(N0)) {
630 AM.ES = S->getSymbol();
631 AM.SymbolFlags = S->getTargetFlags();
632 } else if (auto *S = dyn_cast<MCSymbolSDNode>(N0)) {
633 AM.MCSym = S->getMCSymbol();
634 } else if (auto *J = dyn_cast<JumpTableSDNode>(N0)) {
635 AM.JT = J->getIndex();
636 AM.SymbolFlags = J->getTargetFlags();
637 } else if (auto *BA = dyn_cast<BlockAddressSDNode>(N0)) {
638 AM.BlockAddr = BA->getBlockAddress();
639 AM.Disp += BA->getOffset();
640 AM.SymbolFlags = BA->getTargetFlags();
641 } else
642 llvm_unreachable("Unhandled symbol reference node.");
643 return true;
644 }
645
646 return false;
647}
648
649//===----------------------------------------------------------------------===//
650// Selectors
651//===----------------------------------------------------------------------===//
652
653void M68kDAGToDAGISel::Select(SDNode *Node) {
654 unsigned Opcode = Node->getOpcode();
655 SDLoc DL(Node);
656
657 LLVM_DEBUG(dbgs() << "Selecting: "; Node->dump(CurDAG); dbgs() << '\n');
658
659 if (Node->isMachineOpcode()) {
660 LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << '\n');
661 Node->setNodeId(-1);
662 return; // Already selected.
663 }
664
665 switch (Opcode) {
666 default:
667 break;
668
670 SDValue GOT = CurDAG->getTargetExternalSymbol(
671 "_GLOBAL_OFFSET_TABLE_", MVT::i32, M68kII::MO_GOTPCREL);
672 MachineSDNode *Res =
673 CurDAG->getMachineNode(M68k::LEA32q, DL, MVT::i32, GOT);
674 ReplaceNode(Node, Res);
675 return;
676 }
677
679 ReplaceNode(Node, getGlobalBaseReg());
680 return;
681 }
682
683 SelectCode(Node);
684}
685
686bool M68kDAGToDAGISel::SelectARIPI(SDNode *Parent, SDValue N, SDValue &Base) {
687 LLVM_DEBUG(dbgs() << "Selecting AddrType::ARIPI: ");
688 LLVM_DEBUG(dbgs() << "NOT IMPLEMENTED\n");
689 return false;
690}
691
692bool M68kDAGToDAGISel::SelectARIPD(SDNode *Parent, SDValue N, SDValue &Base) {
693 LLVM_DEBUG(dbgs() << "Selecting AddrType::ARIPD: ");
694 LLVM_DEBUG(dbgs() << "NOT IMPLEMENTED\n");
695 return false;
696}
697
698bool M68kDAGToDAGISel::SelectARID(SDNode *Parent, SDValue N, SDValue &Disp,
699 SDValue &Base) {
700 LLVM_DEBUG(dbgs() << "Selecting AddrType::ARID: ");
701 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARID);
702
703 if (!matchAddress(N, AM))
704 return false;
705
706 if (AM.isPCRelative()) {
707 LLVM_DEBUG(dbgs() << "REJECT: Cannot match PC relative address\n");
708 return false;
709 }
710
711 // If this is a frame index, grab it
712 if (getFrameIndexAddress(AM, SDLoc(N), Disp, Base)) {
713 LLVM_DEBUG(dbgs() << "SUCCESS matched FI\n");
714 return true;
715 }
716
717 if (AM.hasIndexReg()) {
718 LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index\n");
719 return false;
720 }
721
722 if (!AM.hasBaseReg()) {
723 LLVM_DEBUG(dbgs() << "REJECT: No Base reg\n");
724 return false;
725 }
726
727 if (getSymbolicDisplacement(AM, SDLoc(N), Disp)) {
728 assert(!AM.Disp && "Should not be any displacement");
729 LLVM_DEBUG(dbgs() << "SUCCESS, matched Symbol\n");
730 return true;
731 }
732
733 // Give a chance to AddrType::ARI
734 if (AM.Disp == 0) {
735 LLVM_DEBUG(dbgs() << "REJECT: No displacement\n");
736 return false;
737 }
738
739 Base = AM.BaseReg;
740 Disp = getI16Imm(AM.Disp, SDLoc(N));
741
742 LLVM_DEBUG(dbgs() << "SUCCESS\n");
743 return true;
744}
745
746static bool isAddressBase(const SDValue &N) {
747 switch (N.getOpcode()) {
748 case ISD::ADD:
749 case ISD::ADDC:
750 return llvm::any_of(N.getNode()->ops(),
751 [](const SDUse &U) { return isAddressBase(U.get()); });
752 case M68kISD::Wrapper:
755 return true;
756 default:
757 return false;
758 }
759}
760
761bool M68kDAGToDAGISel::SelectARII(SDNode *Parent, SDValue N, SDValue &Disp,
763 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARII);
764 LLVM_DEBUG(dbgs() << "Selecting AddrType::ARII: ");
765
766 if (!matchAddress(N, AM))
767 return false;
768
769 if (AM.isPCRelative()) {
770 LLVM_DEBUG(dbgs() << "REJECT: PC relative\n");
771 return false;
772 }
773
774 if (!AM.hasIndexReg()) {
775 LLVM_DEBUG(dbgs() << "REJECT: No Index\n");
776 return false;
777 }
778
779 if (!AM.hasBaseReg()) {
780 LLVM_DEBUG(dbgs() << "REJECT: No Base\n");
781 return false;
782 }
783
784 if (!isAddressBase(AM.BaseReg) && isAddressBase(AM.IndexReg)) {
785 Base = AM.IndexReg;
786 Index = AM.BaseReg;
787 } else {
788 Base = AM.BaseReg;
789 Index = AM.IndexReg;
790 }
791
792 if (AM.hasSymbolicDisplacement()) {
793 LLVM_DEBUG(dbgs() << "REJECT, Cannot match symbolic displacement\n");
794 return false;
795 }
796
797 // The idea here is that we want to use AddrType::ARII without displacement
798 // only if necessary like memory operations, otherwise this must be lowered
799 // into addition
800 if (AM.Disp == 0 && (!Parent || (Parent->getOpcode() != ISD::LOAD &&
801 Parent->getOpcode() != ISD::STORE))) {
802 LLVM_DEBUG(dbgs() << "REJECT: Displacement is Zero\n");
803 return false;
804 }
805
806 Disp = getI8Imm(AM.Disp, SDLoc(N));
807
808 LLVM_DEBUG(dbgs() << "SUCCESS\n");
809 return true;
810}
811
812bool M68kDAGToDAGISel::SelectAL(SDNode *Parent, SDValue N, SDValue &Sym) {
813 LLVM_DEBUG(dbgs() << "Selecting AddrType::AL: ");
814 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::AL);
815
816 if (!matchAddress(N, AM)) {
817 LLVM_DEBUG(dbgs() << "REJECT: Match failed\n");
818 return false;
819 }
820
821 if (AM.isPCRelative()) {
822 LLVM_DEBUG(dbgs() << "REJECT: Cannot match PC relative address\n");
823 return false;
824 }
825
826 if (AM.hasBase()) {
827 LLVM_DEBUG(dbgs() << "REJECT: Cannot match Base\n");
828 return false;
829 }
830
831 if (AM.hasIndexReg()) {
832 LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index\n");
833 return false;
834 }
835
836 if (getSymbolicDisplacement(AM, SDLoc(N), Sym)) {
837 LLVM_DEBUG(dbgs() << "SUCCESS: Matched symbol\n");
838 return true;
839 }
840
841 if (AM.Disp) {
842 Sym = getI32Imm(AM.Disp, SDLoc(N));
843 LLVM_DEBUG(dbgs() << "SUCCESS\n");
844 return true;
845 }
846
847 LLVM_DEBUG(dbgs() << "REJECT: Not Symbol or Disp\n");
848 return false;
849 ;
850}
851
852bool M68kDAGToDAGISel::SelectPCD(SDNode *Parent, SDValue N, SDValue &Disp) {
853 LLVM_DEBUG(dbgs() << "Selecting AddrType::PCD: ");
854 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::PCD);
855
856 if (!matchAddress(N, AM))
857 return false;
858
859 if (!AM.isPCRelative()) {
860 LLVM_DEBUG(dbgs() << "REJECT: Not PC relative\n");
861 return false;
862 }
863
864 if (AM.hasIndexReg()) {
865 LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index\n");
866 return false;
867 }
868
869 if (getSymbolicDisplacement(AM, SDLoc(N), Disp)) {
870 LLVM_DEBUG(dbgs() << "SUCCESS, matched Symbol\n");
871 return true;
872 }
873
874 Disp = getI16Imm(AM.Disp, SDLoc(N));
875
876 LLVM_DEBUG(dbgs() << "SUCCESS\n");
877 return true;
878}
879
880bool M68kDAGToDAGISel::SelectPCI(SDNode *Parent, SDValue N, SDValue &Disp,
881 SDValue &Index) {
882 LLVM_DEBUG(dbgs() << "Selecting AddrType::PCI: ");
883 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::PCI);
884
885 if (!matchAddress(N, AM))
886 return false;
887
888 if (!AM.isPCRelative()) {
889 LLVM_DEBUG(dbgs() << "REJECT: Not PC relative\n");
890 return false;
891 }
892
893 if (!AM.hasIndexReg()) {
894 LLVM_DEBUG(dbgs() << "REJECT: No Index\n");
895 return false;
896 }
897
898 Index = AM.IndexReg;
899
900 if (getSymbolicDisplacement(AM, SDLoc(N), Disp)) {
901 assert(!AM.Disp && "Should not be any displacement");
902 LLVM_DEBUG(dbgs() << "SUCCESS, matched Symbol\n");
903 return true;
904 }
905
906 Disp = getI8Imm(AM.Disp, SDLoc(N));
907
908 LLVM_DEBUG(dbgs() << "SUCCESS\n");
909 return true;
910}
911
912bool M68kDAGToDAGISel::SelectARI(SDNode *Parent, SDValue N, SDValue &Base) {
913 LLVM_DEBUG(dbgs() << "Selecting AddrType::ARI: ");
914 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARI);
915
916 if (!matchAddress(N, AM)) {
917 LLVM_DEBUG(dbgs() << "REJECT: Match failed\n");
918 return false;
919 }
920
921 if (AM.isPCRelative()) {
922 LLVM_DEBUG(dbgs() << "REJECT: Cannot match PC relative address\n");
923 return false;
924 }
925
926 // AddrType::ARI does not use these
927 if (AM.hasIndexReg() || AM.Disp != 0) {
928 LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index or Disp\n");
929 return false;
930 }
931
932 // Must be matched by AddrType::AL
933 if (AM.hasSymbolicDisplacement()) {
934 LLVM_DEBUG(dbgs() << "REJECT: Cannot match Symbolic Disp\n");
935 return false;
936 }
937
938 if (AM.hasBaseReg()) {
939 Base = AM.BaseReg;
940 LLVM_DEBUG(dbgs() << "SUCCESS\n");
941 return true;
942 }
943
944 return false;
945}
946
947bool M68kDAGToDAGISel::SelectInlineAsmMemoryOperand(
948 const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) {
949 // In order to tell AsmPrinter the exact addressing mode we select here, which
950 // might comprise of multiple SDValues (hence MachineOperands), a 32-bit
951 // immediate value is prepended to the list of selected SDValues to indicate
952 // the addressing mode kind.
953 using AMK = M68k::MemAddrModeKind;
954 auto addKind = [this](SDValue &Opnd, AMK Kind) -> bool {
955 Opnd = CurDAG->getTargetConstant(unsigned(Kind), SDLoc(), MVT::i32);
956 return true;
957 };
958
959 switch (ConstraintID) {
960 // Generic memory operand.
962 // Try every supported (memory) addressing modes.
963 SDValue Operands[4];
964
965 // TODO: The ordering of the following SelectXXX is relatively...arbitrary,
966 // right now we simply sort them by descending complexity. Maybe we should
967 // adjust this by code model and/or relocation mode in the future.
968 if (SelectARII(nullptr, Op, Operands[1], Operands[2], Operands[3]) &&
969 addKind(Operands[0], AMK::f)) {
970 OutOps.insert(OutOps.end(), &Operands[0], Operands + 4);
971 return false;
972 }
973
974 if ((SelectPCI(nullptr, Op, Operands[1], Operands[2]) &&
975 addKind(Operands[0], AMK::k)) ||
976 (SelectARID(nullptr, Op, Operands[1], Operands[2]) &&
977 addKind(Operands[0], AMK::p))) {
978 OutOps.insert(OutOps.end(), &Operands[0], Operands + 3);
979 return false;
980 }
981
982 if ((SelectPCD(nullptr, Op, Operands[1]) && addKind(Operands[0], AMK::q)) ||
983 (SelectARI(nullptr, Op, Operands[1]) && addKind(Operands[0], AMK::j)) ||
984 (SelectAL(nullptr, Op, Operands[1]) && addKind(Operands[0], AMK::b))) {
985 OutOps.insert(OutOps.end(), {Operands[0], Operands[1]});
986 return false;
987 }
988
989 return true;
990 }
991 // 'Q': Address register indirect addressing.
993 SDValue AMKind, Base;
994 // 'j' addressing mode.
995 // TODO: Add support for 'o' and 'e' after their
996 // select functions are implemented.
997 if (SelectARI(nullptr, Op, Base) && addKind(AMKind, AMK::j)) {
998 OutOps.insert(OutOps.end(), {AMKind, Base});
999 return false;
1000 }
1001 return true;
1002 }
1003 // 'U': Address register indirect w/ constant offset addressing.
1005 SDValue AMKind, Base, Offset;
1006 // 'p' addressing mode.
1007 if (SelectARID(nullptr, Op, Offset, Base) && addKind(AMKind, AMK::p)) {
1008 OutOps.insert(OutOps.end(), {AMKind, Offset, Base});
1009 return false;
1010 }
1011 return true;
1012 }
1013 default:
1014 return true;
1015 }
1016}
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
amdgpu AMDGPU Register Bank Select
#define LLVM_DEBUG(X)
Definition: Debug.h:101
Symbol * Sym
Definition: ELF_riscv.cpp:463
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:874
This is an important base class in LLVM.
Definition: Constant.h:41
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:311
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:41
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 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...
virtual bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, std::vector< SDValue > &OutOps)
SelectInlineAsmMemoryOperand - Select the specified address as a target addressing mode,...
#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:1005
@ FrameIndex
Definition: ISDOpcodes.h:80
@ GLOBAL_OFFSET_TABLE
The address of the GOT.
Definition: ISDOpcodes.h:87
@ 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:440
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:1826
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:261
#define N
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39