xref: /llvm-project/llvm/lib/Target/M68k/M68kSubtarget.cpp (revision 2f40e3e713efb550c05ff5f911ab4ce2e4a8dddf)
1 //===-- M68kSubtarget.cpp - M68k Subtarget Information ----------*- 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 implements the M68k specific subclass of TargetSubtargetInfo.
11 ///
12 //===----------------------------------------------------------------------===//
13 
14 #include "M68kSubtarget.h"
15 #include "GISel/M68kCallLowering.h"
16 #include "GISel/M68kLegalizerInfo.h"
17 #include "GISel/M68kRegisterBankInfo.h"
18 
19 #include "M68k.h"
20 #include "M68kMachineFunction.h"
21 #include "M68kRegisterInfo.h"
22 #include "M68kTargetMachine.h"
23 
24 #include "llvm/CodeGen/MachineJumpTableInfo.h"
25 #include "llvm/IR/Attributes.h"
26 #include "llvm/IR/Function.h"
27 #include "llvm/MC/TargetRegistry.h"
28 #include "llvm/Support/CommandLine.h"
29 #include "llvm/Support/ErrorHandling.h"
30 
31 using namespace llvm;
32 
33 #define DEBUG_TYPE "m68k-subtarget"
34 
35 #define GET_SUBTARGETINFO_TARGET_DESC
36 #define GET_SUBTARGETINFO_CTOR
37 #include "M68kGenSubtargetInfo.inc"
38 
39 extern bool FixGlobalBaseReg;
40 
41 /// Select the M68k CPU for the given triple and cpu name.
42 static StringRef selectM68kCPU(Triple TT, StringRef CPU) {
43   if (CPU.empty() || CPU == "generic") {
44     CPU = "M68000";
45   }
46   return CPU;
47 }
48 
49 void M68kSubtarget::anchor() {}
50 
51 M68kSubtarget::M68kSubtarget(const Triple &TT, StringRef CPU, StringRef FS,
52                              const M68kTargetMachine &TM)
53     : M68kGenSubtargetInfo(TT, CPU, /*TuneCPU*/ CPU, FS), TM(TM), TSInfo(),
54       InstrInfo(initializeSubtargetDependencies(CPU, TT, FS, TM)),
55       FrameLowering(*this, this->getStackAlignment()), TLInfo(TM, *this),
56       TargetTriple(TT) {
57   CallLoweringInfo.reset(new M68kCallLowering(*getTargetLowering()));
58   Legalizer.reset(new M68kLegalizerInfo(*this));
59 
60   auto *RBI = new M68kRegisterBankInfo(*getRegisterInfo());
61   RegBankInfo.reset(RBI);
62   InstSelector.reset(createM68kInstructionSelector(TM, *this, *RBI));
63 }
64 
65 const CallLowering *M68kSubtarget::getCallLowering() const {
66   return CallLoweringInfo.get();
67 }
68 
69 InstructionSelector *M68kSubtarget::getInstructionSelector() const {
70   return InstSelector.get();
71 }
72 
73 const LegalizerInfo *M68kSubtarget::getLegalizerInfo() const {
74   return Legalizer.get();
75 }
76 
77 const RegisterBankInfo *M68kSubtarget::getRegBankInfo() const {
78   return RegBankInfo.get();
79 }
80 
81 bool M68kSubtarget::isPositionIndependent() const {
82   return TM.isPositionIndependent();
83 }
84 
85 bool M68kSubtarget::isLegalToCallImmediateAddr() const { return true; }
86 
87 M68kSubtarget &M68kSubtarget::initializeSubtargetDependencies(
88     StringRef CPU, Triple TT, StringRef FS, const M68kTargetMachine &TM) {
89   std::string CPUName = selectM68kCPU(TT, CPU).str();
90 
91   // Parse features string.
92   ParseSubtargetFeatures(CPUName, CPUName, FS);
93 
94   // Initialize scheduling itinerary for the specified CPU.
95   InstrItins = getInstrItineraryForCPU(CPUName);
96 
97   stackAlignment = 8;
98 
99   return *this;
100 }
101 
102 //===----------------------------------------------------------------------===//
103 // Code Model
104 //
105 // Key assumptions:
106 //  - Whenever possible we use pc-rel encoding since it is smaller(16 bit) than
107 //    absolute(32 bit).
108 //  - GOT is reachable within 16 bit offset for both Small and Medium models.
109 //  - Code section is reachable within 16 bit offset for both models.
110 //
111 //  ---------------------+-------------------------+--------------------------
112 //                       |          Small          |          Medium
113 //                       +-------------------------+------------+-------------
114 //                       |   Static   |    PIC     |   Static   |    PIC
115 //  ---------------------+------------+------------+------------+-------------
116 //                branch |   pc-rel   |   pc-rel   |   pc-rel   |   pc-rel
117 //  ---------------------+------------+------------+------------+-------------
118 //           call global |  absolute  |    @PLT    |  absolute  |    @PLT
119 //  ---------------------+------------+------------+------------+-------------
120 //         call internal |   pc-rel   |   pc-rel   |   pc-rel   |   pc-rel
121 //  ---------------------+------------+------------+------------+-------------
122 //            data local |   pc-rel   |   pc-rel   |  ~pc-rel   |  ^pc-rel
123 //  ---------------------+------------+------------+------------+-------------
124 //       data local big* |   pc-rel   |   pc-rel   |  absolute  |  @GOTOFF
125 //  ---------------------+------------+------------+------------+-------------
126 //           data global |   pc-rel   |  @GOTPCREL |  ~pc-rel   |  @GOTPCREL
127 //  ---------------------+------------+------------+------------+-------------
128 //      data global big* |   pc-rel   |  @GOTPCREL |  absolute  |  @GOTPCREL
129 //  ---------------------+------------+------------+------------+-------------
130 //                       |          Large          |
131 //                       +-------------------------+
132 //                       |   Static   |    PIC     |
133 //  ---------------------+------------+------------+
134 //                branch |  absolute  |   pc-rel   |
135 //  ---------------------+------------+------------+
136 //           call global |  absolute  |    @PLT    |
137 //  ---------------------+------------+------------+
138 //         call internal |  absolute  |   pc-rel   |
139 //  ---------------------+------------+------------+
140 //            data local |  absolute  |  @GOTOFF   |
141 //  ---------------------+------------+------------+
142 //       data local big* |  absolute  |  @GOTOFF   |
143 //  ---------------------+------------+------------+
144 //           data global |  absolute  |  @GOTOFF   |
145 //  ---------------------+------------+------------+
146 //      data global big* |  absolute  |  @GOTOFF   |
147 //  ---------------------+------------+------------+
148 //
149 // * Big data potentially cannot be reached within 16 bit offset and requires
150 //   special handling for old(x00 and x10) CPUs. Normally these symbols go into
151 //   separate .ldata section which mapped after normal .data and .text, but I
152 //   don't really know how this must be done for M68k atm... will try to dig
153 //   this info out from GCC. For now CPUs prior to M68020 will use static ref
154 //   for Static Model and @GOT based references for PIC.
155 //
156 // ~ These are absolute for older CPUs for now.
157 // ^ These are @GOTOFF for older CPUs for now.
158 //===----------------------------------------------------------------------===//
159 
160 /// Classify a blockaddress reference for the current subtarget according to how
161 /// we should reference it in a non-pcrel context.
162 unsigned char M68kSubtarget::classifyBlockAddressReference() const {
163   switch (TM.getCodeModel()) {
164   default:
165     llvm_unreachable("Unsupported code model");
166   case CodeModel::Small:
167   case CodeModel::Kernel:
168   case CodeModel::Medium: {
169     return M68kII::MO_PC_RELATIVE_ADDRESS;
170   }
171   case CodeModel::Large: {
172     if (isPositionIndependent()) {
173       return M68kII::MO_PC_RELATIVE_ADDRESS;
174     } else {
175       return M68kII::MO_ABSOLUTE_ADDRESS;
176     }
177   }
178   }
179 }
180 
181 unsigned char
182 M68kSubtarget::classifyLocalReference(const GlobalValue *GV) const {
183   switch (TM.getCodeModel()) {
184   default:
185     llvm_unreachable("Unsupported code model");
186   case CodeModel::Small:
187   case CodeModel::Kernel: {
188     return M68kII::MO_PC_RELATIVE_ADDRESS;
189   }
190   case CodeModel::Medium: {
191     if (isPositionIndependent()) {
192       // On M68020 and better we can fit big any data offset into dips field.
193       if (atLeastM68020()) {
194         return M68kII::MO_PC_RELATIVE_ADDRESS;
195       }
196       // Otherwise we could check the data size and make sure it will fit into
197       // 16 bit offset. For now we will be conservative and go with @GOTOFF
198       return M68kII::MO_GOTOFF;
199     } else {
200       if (atLeastM68020()) {
201         return M68kII::MO_PC_RELATIVE_ADDRESS;
202       }
203       return M68kII::MO_ABSOLUTE_ADDRESS;
204     }
205   }
206   case CodeModel::Large: {
207     if (isPositionIndependent()) {
208       return M68kII::MO_GOTOFF;
209     } else {
210       return M68kII::MO_ABSOLUTE_ADDRESS;
211     }
212   }
213   }
214 }
215 
216 unsigned char M68kSubtarget::classifyExternalReference(const Module &M) const {
217   if (TM.shouldAssumeDSOLocal(nullptr))
218     return classifyLocalReference(nullptr);
219 
220   if (isPositionIndependent())
221     return M68kII::MO_GOTPCREL;
222 
223   return M68kII::MO_GOT;
224 }
225 
226 unsigned char
227 M68kSubtarget::classifyGlobalReference(const GlobalValue *GV) const {
228   return classifyGlobalReference(GV, *GV->getParent());
229 }
230 
231 unsigned char M68kSubtarget::classifyGlobalReference(const GlobalValue *GV,
232                                                      const Module &M) const {
233   if (TM.shouldAssumeDSOLocal(GV))
234     return classifyLocalReference(GV);
235 
236   switch (TM.getCodeModel()) {
237   default:
238     llvm_unreachable("Unsupported code model");
239   case CodeModel::Small:
240   case CodeModel::Kernel: {
241     if (isPositionIndependent())
242       return M68kII::MO_GOTPCREL;
243     return M68kII::MO_PC_RELATIVE_ADDRESS;
244   }
245   case CodeModel::Medium: {
246     if (isPositionIndependent())
247       return M68kII::MO_GOTPCREL;
248 
249     if (atLeastM68020())
250       return M68kII::MO_PC_RELATIVE_ADDRESS;
251 
252     return M68kII::MO_ABSOLUTE_ADDRESS;
253   }
254   case CodeModel::Large: {
255     if (isPositionIndependent())
256       return M68kII::MO_GOTOFF;
257 
258     return M68kII::MO_ABSOLUTE_ADDRESS;
259   }
260   }
261 }
262 
263 unsigned M68kSubtarget::getJumpTableEncoding() const {
264   if (isPositionIndependent()) {
265     // The only time we want to use GOTOFF(used when with EK_Custom32) is when
266     // the potential delta between the jump target and table base can be larger
267     // than displacement field, which is True for older CPUs(16 bit disp)
268     // in Medium model(can have large data way beyond 16 bit).
269     if ((TM.getCodeModel() == CodeModel::Medium && !atLeastM68020()) ||
270         TM.getCodeModel() == CodeModel::Large)
271       return MachineJumpTableInfo::EK_Custom32;
272 
273     return MachineJumpTableInfo::EK_LabelDifference32;
274   }
275 
276   // In non-pic modes, just use the address of a block.
277   return MachineJumpTableInfo::EK_BlockAddress;
278 }
279 
280 unsigned char
281 M68kSubtarget::classifyGlobalFunctionReference(const GlobalValue *GV) const {
282   return classifyGlobalFunctionReference(GV, *GV->getParent());
283 }
284 
285 unsigned char
286 M68kSubtarget::classifyGlobalFunctionReference(const GlobalValue *GV,
287                                                const Module &M) const {
288   // local always use pc-rel referencing
289   if (TM.shouldAssumeDSOLocal(GV))
290     return M68kII::MO_NO_FLAG;
291 
292   // If the function is marked as non-lazy, generate an indirect call
293   // which loads from the GOT directly. This avoids run-time overhead
294   // at the cost of eager binding.
295   auto *F = dyn_cast_or_null<Function>(GV);
296   if (F && F->hasFnAttribute(Attribute::NonLazyBind)) {
297     return M68kII::MO_GOTPCREL;
298   }
299 
300   // Ensure that we don't emit PLT relocations when in non-pic modes.
301   return isPositionIndependent() ? M68kII::MO_PLT : M68kII::MO_ABSOLUTE_ADDRESS;
302 }
303