xref: /netbsd-src/external/apache2/llvm/dist/llvm/lib/Target/M68k/M68kSubtarget.cpp (revision 82d56013d7b633d116a93943de88e08335357a7c)
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