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(CPU: CPUName, TuneCPU: 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 | @PLT | @PLT | @PLT | @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 | // |
131 | // * Big data potentially cannot be reached within 16 bit offset and requires |
132 | // special handling for old(x00 and x10) CPUs. Normally these symbols go into |
133 | // separate .ldata section which mapped after normal .data and .text, but I |
134 | // don't really know how this must be done for M68k atm... will try to dig |
135 | // this info out from GCC. For now CPUs prior to M68020 will use static ref |
136 | // for Static Model and @GOT based references for PIC. |
137 | // |
138 | // ~ These are absolute for older CPUs for now. |
139 | // ^ These are @GOTOFF for older CPUs for now. |
140 | //===----------------------------------------------------------------------===// |
141 | |
142 | /// Classify a blockaddress reference for the current subtarget according to how |
143 | /// we should reference it in a non-pcrel context. |
144 | unsigned char M68kSubtarget::classifyBlockAddressReference() const { |
145 | // Unless we start to support Large Code Model branching is always pc-rel |
146 | return M68kII::MO_PC_RELATIVE_ADDRESS; |
147 | } |
148 | |
149 | unsigned char |
150 | M68kSubtarget::classifyLocalReference(const GlobalValue *GV) const { |
151 | switch (TM.getCodeModel()) { |
152 | default: |
153 | llvm_unreachable("Unsupported code model" ); |
154 | case CodeModel::Small: |
155 | case CodeModel::Kernel: { |
156 | return M68kII::MO_PC_RELATIVE_ADDRESS; |
157 | } |
158 | case CodeModel::Medium: { |
159 | if (isPositionIndependent()) { |
160 | // On M68020 and better we can fit big any data offset into dips field. |
161 | if (atLeastM68020()) { |
162 | return M68kII::MO_PC_RELATIVE_ADDRESS; |
163 | } |
164 | // Otherwise we could check the data size and make sure it will fit into |
165 | // 16 bit offset. For now we will be conservative and go with @GOTOFF |
166 | return M68kII::MO_GOTOFF; |
167 | } else { |
168 | if (atLeastM68020()) { |
169 | return M68kII::MO_PC_RELATIVE_ADDRESS; |
170 | } |
171 | return M68kII::MO_ABSOLUTE_ADDRESS; |
172 | } |
173 | } |
174 | } |
175 | } |
176 | |
177 | unsigned char M68kSubtarget::classifyExternalReference(const Module &M) const { |
178 | if (TM.shouldAssumeDSOLocal(nullptr)) |
179 | return classifyLocalReference(GV: nullptr); |
180 | |
181 | if (isPositionIndependent()) |
182 | return M68kII::MO_GOTPCREL; |
183 | |
184 | return M68kII::MO_GOT; |
185 | } |
186 | |
187 | unsigned char |
188 | M68kSubtarget::classifyGlobalReference(const GlobalValue *GV) const { |
189 | return classifyGlobalReference(GV, M: *GV->getParent()); |
190 | } |
191 | |
192 | unsigned char M68kSubtarget::classifyGlobalReference(const GlobalValue *GV, |
193 | const Module &M) const { |
194 | if (TM.shouldAssumeDSOLocal(GV)) |
195 | return classifyLocalReference(GV); |
196 | |
197 | switch (TM.getCodeModel()) { |
198 | default: |
199 | llvm_unreachable("Unsupported code model" ); |
200 | case CodeModel::Small: |
201 | case CodeModel::Kernel: { |
202 | if (isPositionIndependent()) |
203 | return M68kII::MO_GOTPCREL; |
204 | return M68kII::MO_PC_RELATIVE_ADDRESS; |
205 | } |
206 | case CodeModel::Medium: { |
207 | if (isPositionIndependent()) |
208 | return M68kII::MO_GOTPCREL; |
209 | |
210 | if (atLeastM68020()) |
211 | return M68kII::MO_PC_RELATIVE_ADDRESS; |
212 | |
213 | return M68kII::MO_ABSOLUTE_ADDRESS; |
214 | } |
215 | } |
216 | } |
217 | |
218 | unsigned M68kSubtarget::getJumpTableEncoding() const { |
219 | if (isPositionIndependent()) { |
220 | // The only time we want to use GOTOFF(used when with EK_Custom32) is when |
221 | // the potential delta between the jump target and table base can be larger |
222 | // than displacement field, which is True for older CPUs(16 bit disp) |
223 | // in Medium model(can have large data way beyond 16 bit). |
224 | if (TM.getCodeModel() == CodeModel::Medium && !atLeastM68020()) |
225 | return MachineJumpTableInfo::EK_Custom32; |
226 | |
227 | return MachineJumpTableInfo::EK_LabelDifference32; |
228 | } |
229 | |
230 | // In non-pic modes, just use the address of a block. |
231 | return MachineJumpTableInfo::EK_BlockAddress; |
232 | } |
233 | |
234 | unsigned char |
235 | M68kSubtarget::classifyGlobalFunctionReference(const GlobalValue *GV) const { |
236 | return classifyGlobalFunctionReference(GV, M: *GV->getParent()); |
237 | } |
238 | |
239 | unsigned char |
240 | M68kSubtarget::classifyGlobalFunctionReference(const GlobalValue *GV, |
241 | const Module &M) const { |
242 | // local always use pc-rel referencing |
243 | if (TM.shouldAssumeDSOLocal(GV)) |
244 | return M68kII::MO_NO_FLAG; |
245 | |
246 | // If the function is marked as non-lazy, generate an indirect call |
247 | // which loads from the GOT directly. This avoids run-time overhead |
248 | // at the cost of eager binding. |
249 | auto *F = dyn_cast_or_null<Function>(Val: GV); |
250 | if (F && F->hasFnAttribute(Attribute::NonLazyBind)) { |
251 | return M68kII::MO_GOTPCREL; |
252 | } |
253 | |
254 | // otherwise linker will figure this out |
255 | return M68kII::MO_PLT; |
256 | } |
257 | |