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