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.
selectM68kCPU(Triple TT,StringRef CPU)42 static StringRef selectM68kCPU(Triple TT, StringRef CPU) {
43 if (CPU.empty() || CPU == "generic") {
44 CPU = "M68000";
45 }
46 return CPU;
47 }
48
anchor()49 void M68kSubtarget::anchor() {}
50
M68kSubtarget(const Triple & TT,StringRef CPU,StringRef FS,const M68kTargetMachine & TM)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
getCallLowering() const65 const CallLowering *M68kSubtarget::getCallLowering() const {
66 return CallLoweringInfo.get();
67 }
68
getInstructionSelector() const69 InstructionSelector *M68kSubtarget::getInstructionSelector() const {
70 return InstSelector.get();
71 }
72
getLegalizerInfo() const73 const LegalizerInfo *M68kSubtarget::getLegalizerInfo() const {
74 return Legalizer.get();
75 }
76
getRegBankInfo() const77 const RegisterBankInfo *M68kSubtarget::getRegBankInfo() const {
78 return RegBankInfo.get();
79 }
80
isPositionIndependent() const81 bool M68kSubtarget::isPositionIndependent() const {
82 return TM.isPositionIndependent();
83 }
84
isLegalToCallImmediateAddr() const85 bool M68kSubtarget::isLegalToCallImmediateAddr() const { return true; }
86
abiUsesSoftFloat() const87 bool M68kSubtarget::abiUsesSoftFloat() const { return true; }
88
initializeSubtargetDependencies(StringRef CPU,Triple TT,StringRef FS,const M68kTargetMachine & TM)89 M68kSubtarget &M68kSubtarget::initializeSubtargetDependencies(
90 StringRef CPU, Triple TT, StringRef FS, const M68kTargetMachine &TM) {
91 std::string CPUName = selectM68kCPU(TT, CPU).str();
92
93 // Parse features string.
94 ParseSubtargetFeatures(CPUName, CPUName, FS);
95
96 // Initialize scheduling itinerary for the specified CPU.
97 InstrItins = getInstrItineraryForCPU(CPUName);
98
99 stackAlignment = 8;
100
101 return *this;
102 }
103
104 //===----------------------------------------------------------------------===//
105 // Code Model
106 //
107 // Key assumptions:
108 // - Whenever possible we use pc-rel encoding since it is smaller(16 bit) than
109 // absolute(32 bit).
110 // - GOT is reachable within 16 bit offset for both Small and Medium models.
111 // - Code section is reachable within 16 bit offset for both models.
112 //
113 // ---------------------+-------------------------+--------------------------
114 // | Small | Medium
115 // +-------------------------+------------+-------------
116 // | Static | PIC | Static | PIC
117 // ---------------------+------------+------------+------------+-------------
118 // branch | pc-rel | pc-rel | pc-rel | pc-rel
119 // ---------------------+------------+------------+------------+-------------
120 // call global | @PLT | @PLT | @PLT | @PLT
121 // ---------------------+------------+------------+------------+-------------
122 // call internal | pc-rel | pc-rel | pc-rel | pc-rel
123 // ---------------------+------------+------------+------------+-------------
124 // data local | pc-rel | pc-rel | ~pc-rel | ^pc-rel
125 // ---------------------+------------+------------+------------+-------------
126 // data local big* | pc-rel | pc-rel | absolute | @GOTOFF
127 // ---------------------+------------+------------+------------+-------------
128 // data global | pc-rel | @GOTPCREL | ~pc-rel | @GOTPCREL
129 // ---------------------+------------+------------+------------+-------------
130 // data global big* | pc-rel | @GOTPCREL | absolute | @GOTPCREL
131 // ---------------------+------------+------------+------------+-------------
132 //
133 // * Big data potentially cannot be reached within 16 bit offset and requires
134 // special handling for old(x00 and x10) CPUs. Normally these symbols go into
135 // separate .ldata section which mapped after normal .data and .text, but I
136 // don't really know how this must be done for M68k atm... will try to dig
137 // this info out from GCC. For now CPUs prior to M68020 will use static ref
138 // for Static Model and @GOT based references for PIC.
139 //
140 // ~ These are absolute for older CPUs for now.
141 // ^ These are @GOTOFF for older CPUs for now.
142 //===----------------------------------------------------------------------===//
143
144 /// Classify a blockaddress reference for the current subtarget according to how
145 /// we should reference it in a non-pcrel context.
classifyBlockAddressReference() const146 unsigned char M68kSubtarget::classifyBlockAddressReference() const {
147 // Unless we start to support Large Code Model branching is always pc-rel
148 return M68kII::MO_PC_RELATIVE_ADDRESS;
149 }
150
151 unsigned char
classifyLocalReference(const GlobalValue * GV) const152 M68kSubtarget::classifyLocalReference(const GlobalValue *GV) const {
153 switch (TM.getCodeModel()) {
154 default:
155 llvm_unreachable("Unsupported code model");
156 case CodeModel::Small:
157 case CodeModel::Kernel: {
158 return M68kII::MO_PC_RELATIVE_ADDRESS;
159 }
160 case CodeModel::Medium: {
161 if (isPositionIndependent()) {
162 // On M68020 and better we can fit big any data offset into dips field.
163 if (atLeastM68020()) {
164 return M68kII::MO_PC_RELATIVE_ADDRESS;
165 }
166 // Otherwise we could check the data size and make sure it will fit into
167 // 16 bit offset. For now we will be conservative and go with @GOTOFF
168 return M68kII::MO_GOTOFF;
169 } else {
170 if (atLeastM68020()) {
171 return M68kII::MO_PC_RELATIVE_ADDRESS;
172 }
173 return M68kII::MO_ABSOLUTE_ADDRESS;
174 }
175 }
176 }
177 }
178
classifyExternalReference(const Module & M) const179 unsigned char M68kSubtarget::classifyExternalReference(const Module &M) const {
180 if (TM.shouldAssumeDSOLocal(M, nullptr))
181 return classifyLocalReference(nullptr);
182
183 if (isPositionIndependent())
184 return M68kII::MO_GOTPCREL;
185
186 return M68kII::MO_GOT;
187 }
188
189 unsigned char
classifyGlobalReference(const GlobalValue * GV) const190 M68kSubtarget::classifyGlobalReference(const GlobalValue *GV) const {
191 return classifyGlobalReference(GV, *GV->getParent());
192 }
193
classifyGlobalReference(const GlobalValue * GV,const Module & M) const194 unsigned char M68kSubtarget::classifyGlobalReference(const GlobalValue *GV,
195 const Module &M) const {
196 if (TM.shouldAssumeDSOLocal(M, GV))
197 return classifyLocalReference(GV);
198
199 switch (TM.getCodeModel()) {
200 default:
201 llvm_unreachable("Unsupported code model");
202 case CodeModel::Small:
203 case CodeModel::Kernel: {
204 if (isPositionIndependent())
205 return M68kII::MO_GOTPCREL;
206 return M68kII::MO_PC_RELATIVE_ADDRESS;
207 }
208 case CodeModel::Medium: {
209 if (isPositionIndependent())
210 return M68kII::MO_GOTPCREL;
211
212 if (atLeastM68020())
213 return M68kII::MO_PC_RELATIVE_ADDRESS;
214
215 return M68kII::MO_ABSOLUTE_ADDRESS;
216 }
217 }
218 }
219
getJumpTableEncoding() const220 unsigned M68kSubtarget::getJumpTableEncoding() const {
221 if (isPositionIndependent()) {
222 // The only time we want to use GOTOFF(used when with EK_Custom32) is when
223 // the potential delta between the jump target and table base can be larger
224 // than displacement field, which is True for older CPUs(16 bit disp)
225 // in Medium model(can have large data way beyond 16 bit).
226 if (TM.getCodeModel() == CodeModel::Medium && !atLeastM68020())
227 return MachineJumpTableInfo::EK_Custom32;
228
229 return MachineJumpTableInfo::EK_LabelDifference32;
230 }
231
232 // In non-pic modes, just use the address of a block.
233 return MachineJumpTableInfo::EK_BlockAddress;
234 }
235
236 unsigned char
classifyGlobalFunctionReference(const GlobalValue * GV) const237 M68kSubtarget::classifyGlobalFunctionReference(const GlobalValue *GV) const {
238 return classifyGlobalFunctionReference(GV, *GV->getParent());
239 }
240
241 unsigned char
classifyGlobalFunctionReference(const GlobalValue * GV,const Module & M) const242 M68kSubtarget::classifyGlobalFunctionReference(const GlobalValue *GV,
243 const Module &M) const {
244 // local always use pc-rel referencing
245 if (TM.shouldAssumeDSOLocal(M, GV))
246 return M68kII::MO_NO_FLAG;
247
248 // If the function is marked as non-lazy, generate an indirect call
249 // which loads from the GOT directly. This avoids run-time overhead
250 // at the cost of eager binding.
251 auto *F = dyn_cast_or_null<Function>(GV);
252 if (F && F->hasFnAttribute(Attribute::NonLazyBind)) {
253 return M68kII::MO_GOTPCREL;
254 }
255
256 // otherwise linker will figure this out
257 return M68kII::MO_PLT;
258 }
259