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