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