xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/M68k/M68kSubtarget.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
104eeddc0SDimitry Andric //===-- M68kSubtarget.cpp - M68k Subtarget Information ----------*- C++ -*-===//
2fe6060f1SDimitry Andric //
3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fe6060f1SDimitry Andric //
7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
8fe6060f1SDimitry Andric ///
9fe6060f1SDimitry Andric /// \file
10fe6060f1SDimitry Andric /// This file implements the M68k specific subclass of TargetSubtargetInfo.
11fe6060f1SDimitry Andric ///
12fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
13fe6060f1SDimitry Andric 
14fe6060f1SDimitry Andric #include "M68kSubtarget.h"
15349cc55cSDimitry Andric #include "GISel/M68kCallLowering.h"
16349cc55cSDimitry Andric #include "GISel/M68kLegalizerInfo.h"
17349cc55cSDimitry Andric #include "GISel/M68kRegisterBankInfo.h"
18fe6060f1SDimitry Andric 
19fe6060f1SDimitry Andric #include "M68k.h"
20fe6060f1SDimitry Andric #include "M68kMachineFunction.h"
21fe6060f1SDimitry Andric #include "M68kRegisterInfo.h"
22fe6060f1SDimitry Andric #include "M68kTargetMachine.h"
23fe6060f1SDimitry Andric 
24fe6060f1SDimitry Andric #include "llvm/CodeGen/MachineJumpTableInfo.h"
25fe6060f1SDimitry Andric #include "llvm/IR/Attributes.h"
26fe6060f1SDimitry Andric #include "llvm/IR/Function.h"
27349cc55cSDimitry Andric #include "llvm/MC/TargetRegistry.h"
28fe6060f1SDimitry Andric #include "llvm/Support/CommandLine.h"
29fe6060f1SDimitry Andric #include "llvm/Support/ErrorHandling.h"
30fe6060f1SDimitry Andric 
31fe6060f1SDimitry Andric using namespace llvm;
32fe6060f1SDimitry Andric 
33fe6060f1SDimitry Andric #define DEBUG_TYPE "m68k-subtarget"
34fe6060f1SDimitry Andric 
35fe6060f1SDimitry Andric #define GET_SUBTARGETINFO_TARGET_DESC
36fe6060f1SDimitry Andric #define GET_SUBTARGETINFO_CTOR
37fe6060f1SDimitry Andric #include "M68kGenSubtargetInfo.inc"
38fe6060f1SDimitry Andric 
39fe6060f1SDimitry Andric extern bool FixGlobalBaseReg;
40fe6060f1SDimitry Andric 
41fe6060f1SDimitry Andric /// Select the M68k CPU for the given triple and cpu name.
42fe6060f1SDimitry Andric static StringRef selectM68kCPU(Triple TT, StringRef CPU) {
43fe6060f1SDimitry Andric   if (CPU.empty() || CPU == "generic") {
44fe6060f1SDimitry Andric     CPU = "M68000";
45fe6060f1SDimitry Andric   }
46fe6060f1SDimitry Andric   return CPU;
47fe6060f1SDimitry Andric }
48fe6060f1SDimitry Andric 
49fe6060f1SDimitry Andric void M68kSubtarget::anchor() {}
50fe6060f1SDimitry Andric 
51fe6060f1SDimitry Andric M68kSubtarget::M68kSubtarget(const Triple &TT, StringRef CPU, StringRef FS,
52fe6060f1SDimitry Andric                              const M68kTargetMachine &TM)
53bdd1243dSDimitry Andric     : M68kGenSubtargetInfo(TT, CPU, /*TuneCPU*/ CPU, FS), TM(TM), TSInfo(),
54fe6060f1SDimitry Andric       InstrInfo(initializeSubtargetDependencies(CPU, TT, FS, TM)),
55fe6060f1SDimitry Andric       FrameLowering(*this, this->getStackAlignment()), TLInfo(TM, *this),
56fe6060f1SDimitry Andric       TargetTriple(TT) {
57fe6060f1SDimitry Andric   CallLoweringInfo.reset(new M68kCallLowering(*getTargetLowering()));
58fe6060f1SDimitry Andric   Legalizer.reset(new M68kLegalizerInfo(*this));
59fe6060f1SDimitry Andric 
60fe6060f1SDimitry Andric   auto *RBI = new M68kRegisterBankInfo(*getRegisterInfo());
61fe6060f1SDimitry Andric   RegBankInfo.reset(RBI);
62fe6060f1SDimitry Andric   InstSelector.reset(createM68kInstructionSelector(TM, *this, *RBI));
63fe6060f1SDimitry Andric }
64fe6060f1SDimitry Andric 
65fe6060f1SDimitry Andric const CallLowering *M68kSubtarget::getCallLowering() const {
66fe6060f1SDimitry Andric   return CallLoweringInfo.get();
67fe6060f1SDimitry Andric }
68fe6060f1SDimitry Andric 
69fe6060f1SDimitry Andric InstructionSelector *M68kSubtarget::getInstructionSelector() const {
70fe6060f1SDimitry Andric   return InstSelector.get();
71fe6060f1SDimitry Andric }
72fe6060f1SDimitry Andric 
73fe6060f1SDimitry Andric const LegalizerInfo *M68kSubtarget::getLegalizerInfo() const {
74fe6060f1SDimitry Andric   return Legalizer.get();
75fe6060f1SDimitry Andric }
76fe6060f1SDimitry Andric 
77fe6060f1SDimitry Andric const RegisterBankInfo *M68kSubtarget::getRegBankInfo() const {
78fe6060f1SDimitry Andric   return RegBankInfo.get();
79fe6060f1SDimitry Andric }
80fe6060f1SDimitry Andric 
81fe6060f1SDimitry Andric bool M68kSubtarget::isPositionIndependent() const {
82fe6060f1SDimitry Andric   return TM.isPositionIndependent();
83fe6060f1SDimitry Andric }
84fe6060f1SDimitry Andric 
85fe6060f1SDimitry Andric bool M68kSubtarget::isLegalToCallImmediateAddr() const { return true; }
86fe6060f1SDimitry Andric 
87fe6060f1SDimitry Andric M68kSubtarget &M68kSubtarget::initializeSubtargetDependencies(
88fe6060f1SDimitry Andric     StringRef CPU, Triple TT, StringRef FS, const M68kTargetMachine &TM) {
89fe6060f1SDimitry Andric   std::string CPUName = selectM68kCPU(TT, CPU).str();
90fe6060f1SDimitry Andric 
91fe6060f1SDimitry Andric   // Parse features string.
92fe6060f1SDimitry Andric   ParseSubtargetFeatures(CPUName, CPUName, FS);
93fe6060f1SDimitry Andric 
94fe6060f1SDimitry Andric   // Initialize scheduling itinerary for the specified CPU.
95fe6060f1SDimitry Andric   InstrItins = getInstrItineraryForCPU(CPUName);
96fe6060f1SDimitry Andric 
97fe6060f1SDimitry Andric   stackAlignment = 8;
98fe6060f1SDimitry Andric 
99fe6060f1SDimitry Andric   return *this;
100fe6060f1SDimitry Andric }
101fe6060f1SDimitry Andric 
102fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
103fe6060f1SDimitry Andric // Code Model
104fe6060f1SDimitry Andric //
105fe6060f1SDimitry Andric // Key assumptions:
106fe6060f1SDimitry Andric //  - Whenever possible we use pc-rel encoding since it is smaller(16 bit) than
107fe6060f1SDimitry Andric //    absolute(32 bit).
108fe6060f1SDimitry Andric //  - GOT is reachable within 16 bit offset for both Small and Medium models.
109fe6060f1SDimitry Andric //  - Code section is reachable within 16 bit offset for both models.
110fe6060f1SDimitry Andric //
111fe6060f1SDimitry Andric //  ---------------------+-------------------------+--------------------------
112fe6060f1SDimitry Andric //                       |          Small          |          Medium
113fe6060f1SDimitry Andric //                       +-------------------------+------------+-------------
114fe6060f1SDimitry Andric //                       |   Static   |    PIC     |   Static   |    PIC
115fe6060f1SDimitry Andric //  ---------------------+------------+------------+------------+-------------
116fe6060f1SDimitry Andric //                branch |   pc-rel   |   pc-rel   |   pc-rel   |   pc-rel
117fe6060f1SDimitry Andric //  ---------------------+------------+------------+------------+-------------
118fe6060f1SDimitry Andric //           call global |    @PLT    |    @PLT    |    @PLT    |    @PLT
119fe6060f1SDimitry Andric //  ---------------------+------------+------------+------------+-------------
120fe6060f1SDimitry Andric //         call internal |   pc-rel   |   pc-rel   |   pc-rel   |   pc-rel
121fe6060f1SDimitry Andric //  ---------------------+------------+------------+------------+-------------
122fe6060f1SDimitry Andric //            data local |   pc-rel   |   pc-rel   |  ~pc-rel   |  ^pc-rel
123fe6060f1SDimitry Andric //  ---------------------+------------+------------+------------+-------------
124fe6060f1SDimitry Andric //       data local big* |   pc-rel   |   pc-rel   |  absolute  |  @GOTOFF
125fe6060f1SDimitry Andric //  ---------------------+------------+------------+------------+-------------
126fe6060f1SDimitry Andric //           data global |   pc-rel   |  @GOTPCREL |  ~pc-rel   |  @GOTPCREL
127fe6060f1SDimitry Andric //  ---------------------+------------+------------+------------+-------------
128fe6060f1SDimitry Andric //      data global big* |   pc-rel   |  @GOTPCREL |  absolute  |  @GOTPCREL
129fe6060f1SDimitry Andric //  ---------------------+------------+------------+------------+-------------
130fe6060f1SDimitry Andric //
131fe6060f1SDimitry Andric // * Big data potentially cannot be reached within 16 bit offset and requires
132fe6060f1SDimitry Andric //   special handling for old(x00 and x10) CPUs. Normally these symbols go into
133fe6060f1SDimitry Andric //   separate .ldata section which mapped after normal .data and .text, but I
134fe6060f1SDimitry Andric //   don't really know how this must be done for M68k atm... will try to dig
135fe6060f1SDimitry Andric //   this info out from GCC. For now CPUs prior to M68020 will use static ref
136fe6060f1SDimitry Andric //   for Static Model and @GOT based references for PIC.
137fe6060f1SDimitry Andric //
138fe6060f1SDimitry Andric // ~ These are absolute for older CPUs for now.
139fe6060f1SDimitry Andric // ^ These are @GOTOFF for older CPUs for now.
140fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
141fe6060f1SDimitry Andric 
142fe6060f1SDimitry Andric /// Classify a blockaddress reference for the current subtarget according to how
143fe6060f1SDimitry Andric /// we should reference it in a non-pcrel context.
144fe6060f1SDimitry Andric unsigned char M68kSubtarget::classifyBlockAddressReference() const {
145fe6060f1SDimitry Andric   // Unless we start to support Large Code Model branching is always pc-rel
146fe6060f1SDimitry Andric   return M68kII::MO_PC_RELATIVE_ADDRESS;
147fe6060f1SDimitry Andric }
148fe6060f1SDimitry Andric 
149fe6060f1SDimitry Andric unsigned char
150fe6060f1SDimitry Andric M68kSubtarget::classifyLocalReference(const GlobalValue *GV) const {
151fe6060f1SDimitry Andric   switch (TM.getCodeModel()) {
152fe6060f1SDimitry Andric   default:
153fe6060f1SDimitry Andric     llvm_unreachable("Unsupported code model");
154fe6060f1SDimitry Andric   case CodeModel::Small:
155fe6060f1SDimitry Andric   case CodeModel::Kernel: {
156fe6060f1SDimitry Andric     return M68kII::MO_PC_RELATIVE_ADDRESS;
157fe6060f1SDimitry Andric   }
158fe6060f1SDimitry Andric   case CodeModel::Medium: {
159fe6060f1SDimitry Andric     if (isPositionIndependent()) {
160fe6060f1SDimitry Andric       // On M68020 and better we can fit big any data offset into dips field.
161fe6060f1SDimitry Andric       if (atLeastM68020()) {
162fe6060f1SDimitry Andric         return M68kII::MO_PC_RELATIVE_ADDRESS;
163fe6060f1SDimitry Andric       }
164fe6060f1SDimitry Andric       // Otherwise we could check the data size and make sure it will fit into
165fe6060f1SDimitry Andric       // 16 bit offset. For now we will be conservative and go with @GOTOFF
166fe6060f1SDimitry Andric       return M68kII::MO_GOTOFF;
167fe6060f1SDimitry Andric     } else {
168fe6060f1SDimitry Andric       if (atLeastM68020()) {
169fe6060f1SDimitry Andric         return M68kII::MO_PC_RELATIVE_ADDRESS;
170fe6060f1SDimitry Andric       }
171fe6060f1SDimitry Andric       return M68kII::MO_ABSOLUTE_ADDRESS;
172fe6060f1SDimitry Andric     }
173fe6060f1SDimitry Andric   }
174fe6060f1SDimitry Andric   }
175fe6060f1SDimitry Andric }
176fe6060f1SDimitry Andric 
177fe6060f1SDimitry Andric unsigned char M68kSubtarget::classifyExternalReference(const Module &M) const {
178*0fca6ea1SDimitry Andric   if (TM.shouldAssumeDSOLocal(nullptr))
179fe6060f1SDimitry Andric     return classifyLocalReference(nullptr);
180fe6060f1SDimitry Andric 
181fe6060f1SDimitry Andric   if (isPositionIndependent())
182fe6060f1SDimitry Andric     return M68kII::MO_GOTPCREL;
183fe6060f1SDimitry Andric 
184fe6060f1SDimitry Andric   return M68kII::MO_GOT;
185fe6060f1SDimitry Andric }
186fe6060f1SDimitry Andric 
187fe6060f1SDimitry Andric unsigned char
188fe6060f1SDimitry Andric M68kSubtarget::classifyGlobalReference(const GlobalValue *GV) const {
189fe6060f1SDimitry Andric   return classifyGlobalReference(GV, *GV->getParent());
190fe6060f1SDimitry Andric }
191fe6060f1SDimitry Andric 
192fe6060f1SDimitry Andric unsigned char M68kSubtarget::classifyGlobalReference(const GlobalValue *GV,
193fe6060f1SDimitry Andric                                                      const Module &M) const {
194*0fca6ea1SDimitry Andric   if (TM.shouldAssumeDSOLocal(GV))
195fe6060f1SDimitry Andric     return classifyLocalReference(GV);
196fe6060f1SDimitry Andric 
197fe6060f1SDimitry Andric   switch (TM.getCodeModel()) {
198fe6060f1SDimitry Andric   default:
199fe6060f1SDimitry Andric     llvm_unreachable("Unsupported code model");
200fe6060f1SDimitry Andric   case CodeModel::Small:
201fe6060f1SDimitry Andric   case CodeModel::Kernel: {
202fe6060f1SDimitry Andric     if (isPositionIndependent())
203fe6060f1SDimitry Andric       return M68kII::MO_GOTPCREL;
204fe6060f1SDimitry Andric     return M68kII::MO_PC_RELATIVE_ADDRESS;
205fe6060f1SDimitry Andric   }
206fe6060f1SDimitry Andric   case CodeModel::Medium: {
207fe6060f1SDimitry Andric     if (isPositionIndependent())
208fe6060f1SDimitry Andric       return M68kII::MO_GOTPCREL;
209fe6060f1SDimitry Andric 
210fe6060f1SDimitry Andric     if (atLeastM68020())
211fe6060f1SDimitry Andric       return M68kII::MO_PC_RELATIVE_ADDRESS;
212fe6060f1SDimitry Andric 
213fe6060f1SDimitry Andric     return M68kII::MO_ABSOLUTE_ADDRESS;
214fe6060f1SDimitry Andric   }
215fe6060f1SDimitry Andric   }
216fe6060f1SDimitry Andric }
217fe6060f1SDimitry Andric 
218fe6060f1SDimitry Andric unsigned M68kSubtarget::getJumpTableEncoding() const {
219fe6060f1SDimitry Andric   if (isPositionIndependent()) {
220fe6060f1SDimitry Andric     // The only time we want to use GOTOFF(used when with EK_Custom32) is when
221fe6060f1SDimitry Andric     // the potential delta between the jump target and table base can be larger
222fe6060f1SDimitry Andric     // than displacement field, which is True for older CPUs(16 bit disp)
223fe6060f1SDimitry Andric     // in Medium model(can have large data way beyond 16 bit).
224fe6060f1SDimitry Andric     if (TM.getCodeModel() == CodeModel::Medium && !atLeastM68020())
225fe6060f1SDimitry Andric       return MachineJumpTableInfo::EK_Custom32;
226fe6060f1SDimitry Andric 
227fe6060f1SDimitry Andric     return MachineJumpTableInfo::EK_LabelDifference32;
228fe6060f1SDimitry Andric   }
229fe6060f1SDimitry Andric 
230fe6060f1SDimitry Andric   // In non-pic modes, just use the address of a block.
231fe6060f1SDimitry Andric   return MachineJumpTableInfo::EK_BlockAddress;
232fe6060f1SDimitry Andric }
233fe6060f1SDimitry Andric 
234fe6060f1SDimitry Andric unsigned char
235fe6060f1SDimitry Andric M68kSubtarget::classifyGlobalFunctionReference(const GlobalValue *GV) const {
236fe6060f1SDimitry Andric   return classifyGlobalFunctionReference(GV, *GV->getParent());
237fe6060f1SDimitry Andric }
238fe6060f1SDimitry Andric 
239fe6060f1SDimitry Andric unsigned char
240fe6060f1SDimitry Andric M68kSubtarget::classifyGlobalFunctionReference(const GlobalValue *GV,
241fe6060f1SDimitry Andric                                                const Module &M) const {
242fe6060f1SDimitry Andric   // local always use pc-rel referencing
243*0fca6ea1SDimitry Andric   if (TM.shouldAssumeDSOLocal(GV))
244fe6060f1SDimitry Andric     return M68kII::MO_NO_FLAG;
245fe6060f1SDimitry Andric 
246fe6060f1SDimitry Andric   // If the function is marked as non-lazy, generate an indirect call
247fe6060f1SDimitry Andric   // which loads from the GOT directly. This avoids run-time overhead
248fe6060f1SDimitry Andric   // at the cost of eager binding.
249fe6060f1SDimitry Andric   auto *F = dyn_cast_or_null<Function>(GV);
250fe6060f1SDimitry Andric   if (F && F->hasFnAttribute(Attribute::NonLazyBind)) {
251fe6060f1SDimitry Andric     return M68kII::MO_GOTPCREL;
252fe6060f1SDimitry Andric   }
253fe6060f1SDimitry Andric 
254*0fca6ea1SDimitry Andric   // Ensure that we don't emit PLT relocations when in non-pic modes.
255*0fca6ea1SDimitry Andric   return isPositionIndependent() ? M68kII::MO_PLT : M68kII::MO_ABSOLUTE_ADDRESS;
256fe6060f1SDimitry Andric }
257