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