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