1 //===-- M68kSubtarget.cpp - M68k Subtarget Information ----------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
10 /// This file implements the M68k specific subclass of TargetSubtargetInfo.
12 //===----------------------------------------------------------------------===//
14 #include "M68kSubtarget.h"
15 #include "GISel/M68kCallLowering.h"
16 #include "GISel/M68kLegalizerInfo.h"
17 #include "GISel/M68kRegisterBankInfo.h"
20 #include "M68kMachineFunction.h"
21 #include "M68kRegisterInfo.h"
22 #include "M68kTargetMachine.h"
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"
33 #define DEBUG_TYPE "m68k-subtarget"
35 #define GET_SUBTARGETINFO_TARGET_DESC
36 #define GET_SUBTARGETINFO_CTOR
37 #include "M68kGenSubtargetInfo.inc"
39 extern bool FixGlobalBaseReg
;
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") {
49 void M68kSubtarget::anchor() {}
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),
57 CallLoweringInfo
.reset(new M68kCallLowering(*getTargetLowering()));
58 Legalizer
.reset(new M68kLegalizerInfo(*this));
60 auto *RBI
= new M68kRegisterBankInfo(*getRegisterInfo());
61 RegBankInfo
.reset(RBI
);
62 InstSelector
.reset(createM68kInstructionSelector(TM
, *this, *RBI
));
65 const CallLowering
*M68kSubtarget::getCallLowering() const {
66 return CallLoweringInfo
.get();
69 InstructionSelector
*M68kSubtarget::getInstructionSelector() const {
70 return InstSelector
.get();
73 const LegalizerInfo
*M68kSubtarget::getLegalizerInfo() const {
74 return Legalizer
.get();
77 const RegisterBankInfo
*M68kSubtarget::getRegBankInfo() const {
78 return RegBankInfo
.get();
81 bool M68kSubtarget::isPositionIndependent() const {
82 return TM
.isPositionIndependent();
85 bool M68kSubtarget::isLegalToCallImmediateAddr() const { return true; }
87 M68kSubtarget
&M68kSubtarget::initializeSubtargetDependencies(
88 StringRef CPU
, Triple TT
, StringRef FS
, const M68kTargetMachine
&TM
) {
89 std::string CPUName
= selectM68kCPU(TT
, CPU
).str();
91 // Parse features string.
92 ParseSubtargetFeatures(CPUName
, CPUName
, FS
);
94 // Initialize scheduling itinerary for the specified CPU.
95 InstrItins
= getInstrItineraryForCPU(CPUName
);
102 //===----------------------------------------------------------------------===//
106 // - Whenever possible we use pc-rel encoding since it is smaller(16 bit) than
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.
111 // ---------------------+-------------------------+--------------------------
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 // ---------------------+------------+------------+------------+-------------
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.
138 // ~ These are absolute for older CPUs for now.
139 // ^ These are @GOTOFF for older CPUs for now.
140 //===----------------------------------------------------------------------===//
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
;
150 M68kSubtarget::classifyLocalReference(const GlobalValue
*GV
) const {
151 switch (TM
.getCodeModel()) {
153 llvm_unreachable("Unsupported code model");
154 case CodeModel::Small
:
155 case CodeModel::Kernel
: {
156 return M68kII::MO_PC_RELATIVE_ADDRESS
;
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
;
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
;
168 if (atLeastM68020()) {
169 return M68kII::MO_PC_RELATIVE_ADDRESS
;
171 return M68kII::MO_ABSOLUTE_ADDRESS
;
177 unsigned char M68kSubtarget::classifyExternalReference(const Module
&M
) const {
178 if (TM
.shouldAssumeDSOLocal(M
, nullptr))
179 return classifyLocalReference(nullptr);
181 if (isPositionIndependent())
182 return M68kII::MO_GOTPCREL
;
184 return M68kII::MO_GOT
;
188 M68kSubtarget::classifyGlobalReference(const GlobalValue
*GV
) const {
189 return classifyGlobalReference(GV
, *GV
->getParent());
192 unsigned char M68kSubtarget::classifyGlobalReference(const GlobalValue
*GV
,
193 const Module
&M
) const {
194 if (TM
.shouldAssumeDSOLocal(M
, GV
))
195 return classifyLocalReference(GV
);
197 switch (TM
.getCodeModel()) {
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
;
206 case CodeModel::Medium
: {
207 if (isPositionIndependent())
208 return M68kII::MO_GOTPCREL
;
211 return M68kII::MO_PC_RELATIVE_ADDRESS
;
213 return M68kII::MO_ABSOLUTE_ADDRESS
;
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
;
227 return MachineJumpTableInfo::EK_LabelDifference32
;
230 // In non-pic modes, just use the address of a block.
231 return MachineJumpTableInfo::EK_BlockAddress
;
235 M68kSubtarget::classifyGlobalFunctionReference(const GlobalValue
*GV
) const {
236 return classifyGlobalFunctionReference(GV
, *GV
->getParent());
240 M68kSubtarget::classifyGlobalFunctionReference(const GlobalValue
*GV
,
241 const Module
&M
) const {
242 // local always use pc-rel referencing
243 if (TM
.shouldAssumeDSOLocal(M
, GV
))
244 return M68kII::MO_NO_FLAG
;
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
>(GV
);
250 if (F
&& F
->hasFnAttribute(Attribute::NonLazyBind
)) {
251 return M68kII::MO_GOTPCREL
;
254 // otherwise linker will figure this out
255 return M68kII::MO_PLT
;