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
16 #include "M68k.h"
17 #include "M68kMachineFunction.h"
18 #include "M68kRegisterInfo.h"
19 #include "M68kTargetMachine.h"
20
21 #include "llvm/CodeGen/MachineJumpTableInfo.h"
22 #include "llvm/IR/Attributes.h"
23 #include "llvm/IR/Function.h"
24 #include "llvm/Support/CommandLine.h"
25 #include "llvm/Support/ErrorHandling.h"
26 #include "llvm/Support/TargetRegistry.h"
27
28 using namespace llvm;
29
30 #define DEBUG_TYPE "m68k-subtarget"
31
32 #define GET_SUBTARGETINFO_TARGET_DESC
33 #define GET_SUBTARGETINFO_CTOR
34 #include "M68kGenSubtargetInfo.inc"
35
36 extern bool FixGlobalBaseReg;
37
38 /// Select the M68k CPU for the given triple and cpu name.
selectM68kCPU(Triple TT,StringRef CPU)39 static StringRef selectM68kCPU(Triple TT, StringRef CPU) {
40 if (CPU.empty() || CPU == "generic") {
41 CPU = "M68000";
42 }
43 return CPU;
44 }
45
anchor()46 void M68kSubtarget::anchor() {}
47
M68kSubtarget(const Triple & TT,StringRef CPU,StringRef FS,const M68kTargetMachine & TM)48 M68kSubtarget::M68kSubtarget(const Triple &TT, StringRef CPU, StringRef FS,
49 const M68kTargetMachine &TM)
50 : M68kGenSubtargetInfo(TT, CPU, /*TuneCPU*/ CPU, FS),
51 UserReservedRegister(M68k::NUM_TARGET_REGS), TM(TM), TSInfo(),
52 InstrInfo(initializeSubtargetDependencies(CPU, TT, FS, TM)),
53 FrameLowering(*this, this->getStackAlignment()), TLInfo(TM, *this),
54 TargetTriple(TT) {}
55
isPositionIndependent() const56 bool M68kSubtarget::isPositionIndependent() const {
57 return TM.isPositionIndependent();
58 }
59
isLegalToCallImmediateAddr() const60 bool M68kSubtarget::isLegalToCallImmediateAddr() const { return true; }
61
abiUsesSoftFloat() const62 bool M68kSubtarget::abiUsesSoftFloat() const { return true; }
63
initializeSubtargetDependencies(StringRef CPU,Triple TT,StringRef FS,const M68kTargetMachine & TM)64 M68kSubtarget &M68kSubtarget::initializeSubtargetDependencies(
65 StringRef CPU, Triple TT, StringRef FS, const M68kTargetMachine &TM) {
66 std::string CPUName = selectM68kCPU(TT, CPU).str();
67
68 // Parse features string.
69 ParseSubtargetFeatures(CPUName, CPUName, FS);
70
71 // Initialize scheduling itinerary for the specified CPU.
72 InstrItins = getInstrItineraryForCPU(CPUName);
73
74 stackAlignment = 8;
75
76 return *this;
77 }
78
79 //===----------------------------------------------------------------------===//
80 // Code Model
81 //
82 // Key assumptions:
83 // - Whenever possible we use pc-rel encoding since it is smaller(16 bit) than
84 // absolute(32 bit).
85 // - GOT is reachable within 16 bit offset for both Small and Medium models.
86 // - Code section is reachable within 16 bit offset for both models.
87 //
88 // ---------------------+-------------------------+--------------------------
89 // | Small | Medium
90 // +-------------------------+------------+-------------
91 // | Static | PIC | Static | PIC
92 // ---------------------+------------+------------+------------+-------------
93 // branch | pc-rel | pc-rel | pc-rel | pc-rel
94 // ---------------------+------------+------------+------------+-------------
95 // call global | @PLT | @PLT | @PLT | @PLT
96 // ---------------------+------------+------------+------------+-------------
97 // call internal | pc-rel | pc-rel | pc-rel | pc-rel
98 // ---------------------+------------+------------+------------+-------------
99 // data local | pc-rel | pc-rel | ~pc-rel | ^pc-rel
100 // ---------------------+------------+------------+------------+-------------
101 // data local big* | pc-rel | pc-rel | absolute | @GOTOFF
102 // ---------------------+------------+------------+------------+-------------
103 // data global | pc-rel | @GOTPCREL | ~pc-rel | @GOTPCREL
104 // ---------------------+------------+------------+------------+-------------
105 // data global big* | pc-rel | @GOTPCREL | absolute | @GOTPCREL
106 // ---------------------+------------+------------+------------+-------------
107 //
108 // * Big data potentially cannot be reached within 16 bit offset and requires
109 // special handling for old(x00 and x10) CPUs. Normally these symbols go into
110 // separate .ldata section which mapped after normal .data and .text, but I
111 // don't really know how this must be done for M68k atm... will try to dig
112 // this info out from GCC. For now CPUs prior to M68020 will use static ref
113 // for Static Model and @GOT based references for PIC.
114 //
115 // ~ These are absolute for older CPUs for now.
116 // ^ These are @GOTOFF for older CPUs for now.
117 //===----------------------------------------------------------------------===//
118
119 /// Classify a blockaddress reference for the current subtarget according to how
120 /// we should reference it in a non-pcrel context.
classifyBlockAddressReference() const121 unsigned char M68kSubtarget::classifyBlockAddressReference() const {
122 // Unless we start to support Large Code Model branching is always pc-rel
123 return M68kII::MO_PC_RELATIVE_ADDRESS;
124 }
125
126 unsigned char
classifyLocalReference(const GlobalValue * GV) const127 M68kSubtarget::classifyLocalReference(const GlobalValue *GV) const {
128 switch (TM.getCodeModel()) {
129 default:
130 llvm_unreachable("Unsupported code model");
131 case CodeModel::Small:
132 case CodeModel::Kernel: {
133 return M68kII::MO_PC_RELATIVE_ADDRESS;
134 }
135 case CodeModel::Medium: {
136 if (isPositionIndependent()) {
137 // On M68020 and better we can fit big any data offset into dips field.
138 if (atLeastM68020()) {
139 return M68kII::MO_PC_RELATIVE_ADDRESS;
140 }
141 // Otherwise we could check the data size and make sure it will fit into
142 // 16 bit offset. For now we will be conservative and go with @GOTOFF
143 return M68kII::MO_GOTOFF;
144 } else {
145 if (atLeastM68020()) {
146 return M68kII::MO_PC_RELATIVE_ADDRESS;
147 }
148 return M68kII::MO_ABSOLUTE_ADDRESS;
149 }
150 }
151 }
152 }
153
classifyExternalReference(const Module & M) const154 unsigned char M68kSubtarget::classifyExternalReference(const Module &M) const {
155 if (TM.shouldAssumeDSOLocal(M, nullptr))
156 return classifyLocalReference(nullptr);
157
158 if (isPositionIndependent())
159 return M68kII::MO_GOTPCREL;
160
161 return M68kII::MO_GOT;
162 }
163
164 unsigned char
classifyGlobalReference(const GlobalValue * GV) const165 M68kSubtarget::classifyGlobalReference(const GlobalValue *GV) const {
166 return classifyGlobalReference(GV, *GV->getParent());
167 }
168
classifyGlobalReference(const GlobalValue * GV,const Module & M) const169 unsigned char M68kSubtarget::classifyGlobalReference(const GlobalValue *GV,
170 const Module &M) const {
171 if (TM.shouldAssumeDSOLocal(M, GV))
172 return classifyLocalReference(GV);
173
174 switch (TM.getCodeModel()) {
175 default:
176 llvm_unreachable("Unsupported code model");
177 case CodeModel::Small:
178 case CodeModel::Kernel: {
179 if (isPositionIndependent())
180 return M68kII::MO_GOTPCREL;
181 return M68kII::MO_PC_RELATIVE_ADDRESS;
182 }
183 case CodeModel::Medium: {
184 if (isPositionIndependent())
185 return M68kII::MO_GOTPCREL;
186
187 if (atLeastM68020())
188 return M68kII::MO_PC_RELATIVE_ADDRESS;
189
190 return M68kII::MO_ABSOLUTE_ADDRESS;
191 }
192 }
193 }
194
getJumpTableEncoding() const195 unsigned M68kSubtarget::getJumpTableEncoding() const {
196 if (isPositionIndependent()) {
197 // The only time we want to use GOTOFF(used when with EK_Custom32) is when
198 // the potential delta between the jump target and table base can be larger
199 // than displacement field, which is True for older CPUs(16 bit disp)
200 // in Medium model(can have large data way beyond 16 bit).
201 if (TM.getCodeModel() == CodeModel::Medium && !atLeastM68020())
202 return MachineJumpTableInfo::EK_Custom32;
203
204 return MachineJumpTableInfo::EK_LabelDifference32;
205 }
206
207 // In non-pic modes, just use the address of a block.
208 return MachineJumpTableInfo::EK_BlockAddress;
209 }
210
211 unsigned char
classifyGlobalFunctionReference(const GlobalValue * GV) const212 M68kSubtarget::classifyGlobalFunctionReference(const GlobalValue *GV) const {
213 return classifyGlobalFunctionReference(GV, *GV->getParent());
214 }
215
216 unsigned char
classifyGlobalFunctionReference(const GlobalValue * GV,const Module & M) const217 M68kSubtarget::classifyGlobalFunctionReference(const GlobalValue *GV,
218 const Module &M) const {
219 // local always use pc-rel referencing
220 if (TM.shouldAssumeDSOLocal(M, GV))
221 return M68kII::MO_NO_FLAG;
222
223 // If the function is marked as non-lazy, generate an indirect call
224 // which loads from the GOT directly. This avoids run-time overhead
225 // at the cost of eager binding.
226 auto *F = dyn_cast_or_null<Function>(GV);
227 if (F && F->hasFnAttribute(Attribute::NonLazyBind)) {
228 return M68kII::MO_GOTPCREL;
229 }
230
231 // otherwise linker will figure this out
232 return M68kII::MO_PLT;
233 }
234