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