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