xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/M68k/M68kTargetMachine.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
104eeddc0SDimitry Andric //===-- M68kTargetMachine.cpp - M68k Target Machine -------------*- 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 contains implementation for M68k target machine.
11fe6060f1SDimitry Andric ///
12fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
13fe6060f1SDimitry Andric 
14fe6060f1SDimitry Andric #include "M68kTargetMachine.h"
15fe6060f1SDimitry Andric #include "M68k.h"
16*bdd1243dSDimitry Andric #include "M68kMachineFunction.h"
17fe6060f1SDimitry Andric #include "M68kSubtarget.h"
18fe6060f1SDimitry Andric #include "M68kTargetObjectFile.h"
19fe6060f1SDimitry Andric #include "TargetInfo/M68kTargetInfo.h"
20fe6060f1SDimitry Andric #include "llvm/CodeGen/GlobalISel/IRTranslator.h"
21fe6060f1SDimitry Andric #include "llvm/CodeGen/GlobalISel/InstructionSelect.h"
22fe6060f1SDimitry Andric #include "llvm/CodeGen/GlobalISel/Legalizer.h"
23fe6060f1SDimitry Andric #include "llvm/CodeGen/GlobalISel/RegBankSelect.h"
24fe6060f1SDimitry Andric #include "llvm/CodeGen/Passes.h"
25fe6060f1SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h"
26fe6060f1SDimitry Andric #include "llvm/IR/LegacyPassManager.h"
27fe6060f1SDimitry Andric #include "llvm/InitializePasses.h"
28349cc55cSDimitry Andric #include "llvm/MC/TargetRegistry.h"
29fe6060f1SDimitry Andric #include "llvm/PassRegistry.h"
30fe6060f1SDimitry Andric #include <memory>
31*bdd1243dSDimitry Andric #include <optional>
32fe6060f1SDimitry Andric 
33fe6060f1SDimitry Andric using namespace llvm;
34fe6060f1SDimitry Andric 
35fe6060f1SDimitry Andric #define DEBUG_TYPE "m68k"
36fe6060f1SDimitry Andric 
37fe6060f1SDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeM68kTarget() {
38fe6060f1SDimitry Andric   RegisterTargetMachine<M68kTargetMachine> X(getTheM68kTarget());
39fe6060f1SDimitry Andric   auto *PR = PassRegistry::getPassRegistry();
40fe6060f1SDimitry Andric   initializeGlobalISel(*PR);
41*bdd1243dSDimitry Andric   initializeM68kDAGToDAGISelPass(*PR);
42fe6060f1SDimitry Andric }
43fe6060f1SDimitry Andric 
44fe6060f1SDimitry Andric namespace {
45fe6060f1SDimitry Andric 
46fe6060f1SDimitry Andric std::string computeDataLayout(const Triple &TT, StringRef CPU,
47fe6060f1SDimitry Andric                               const TargetOptions &Options) {
48fe6060f1SDimitry Andric   std::string Ret = "";
49fe6060f1SDimitry Andric   // M68k is Big Endian
50fe6060f1SDimitry Andric   Ret += "E";
51fe6060f1SDimitry Andric 
52fe6060f1SDimitry Andric   // FIXME how to wire it with the used object format?
53fe6060f1SDimitry Andric   Ret += "-m:e";
54fe6060f1SDimitry Andric 
5569ade1e0SDimitry Andric   // M68k pointers are always 32 bit wide even for 16-bit CPUs.
5669ade1e0SDimitry Andric   // The ABI only specifies 16-bit alignment.
5769ade1e0SDimitry Andric   // On at least the 68020+ with a 32-bit bus, there is a performance benefit
5869ade1e0SDimitry Andric   // to having 32-bit alignment.
5969ade1e0SDimitry Andric   Ret += "-p:32:16:32";
60fe6060f1SDimitry Andric 
6169ade1e0SDimitry Andric   // Bytes do not require special alignment, words are word aligned and
6269ade1e0SDimitry Andric   // long words are word aligned at minimum.
63fe6060f1SDimitry Andric   Ret += "-i8:8:8-i16:16:16-i32:16:32";
64fe6060f1SDimitry Andric 
65fe6060f1SDimitry Andric   // FIXME no floats at the moment
66fe6060f1SDimitry Andric 
67fe6060f1SDimitry Andric   // The registers can hold 8, 16, 32 bits
68fe6060f1SDimitry Andric   Ret += "-n8:16:32";
69fe6060f1SDimitry Andric 
70fe6060f1SDimitry Andric   Ret += "-a:0:16-S16";
71fe6060f1SDimitry Andric 
72fe6060f1SDimitry Andric   return Ret;
73fe6060f1SDimitry Andric }
74fe6060f1SDimitry Andric 
75fe6060f1SDimitry Andric Reloc::Model getEffectiveRelocModel(const Triple &TT,
76*bdd1243dSDimitry Andric                                     std::optional<Reloc::Model> RM) {
77fe6060f1SDimitry Andric   // If not defined we default to static
78*bdd1243dSDimitry Andric   if (!RM.has_value())
79fe6060f1SDimitry Andric     return Reloc::Static;
80fe6060f1SDimitry Andric 
81fe6060f1SDimitry Andric   return *RM;
82fe6060f1SDimitry Andric }
83fe6060f1SDimitry Andric 
84*bdd1243dSDimitry Andric CodeModel::Model getEffectiveCodeModel(std::optional<CodeModel::Model> CM,
85fe6060f1SDimitry Andric                                        bool JIT) {
86fe6060f1SDimitry Andric   if (!CM) {
87fe6060f1SDimitry Andric     return CodeModel::Small;
88fe6060f1SDimitry Andric   } else if (CM == CodeModel::Large) {
89fe6060f1SDimitry Andric     llvm_unreachable("Large code model is not supported");
90fe6060f1SDimitry Andric   } else if (CM == CodeModel::Kernel) {
91fe6060f1SDimitry Andric     llvm_unreachable("Kernel code model is not implemented yet");
92fe6060f1SDimitry Andric   }
93*bdd1243dSDimitry Andric   return CM.value();
94fe6060f1SDimitry Andric }
95fe6060f1SDimitry Andric } // end anonymous namespace
96fe6060f1SDimitry Andric 
97fe6060f1SDimitry Andric M68kTargetMachine::M68kTargetMachine(const Target &T, const Triple &TT,
98fe6060f1SDimitry Andric                                      StringRef CPU, StringRef FS,
99fe6060f1SDimitry Andric                                      const TargetOptions &Options,
100*bdd1243dSDimitry Andric                                      std::optional<Reloc::Model> RM,
101*bdd1243dSDimitry Andric                                      std::optional<CodeModel::Model> CM,
102fe6060f1SDimitry Andric                                      CodeGenOpt::Level OL, bool JIT)
103fe6060f1SDimitry Andric     : LLVMTargetMachine(T, computeDataLayout(TT, CPU, Options), TT, CPU, FS,
104fe6060f1SDimitry Andric                         Options, getEffectiveRelocModel(TT, RM),
105fe6060f1SDimitry Andric                         ::getEffectiveCodeModel(CM, JIT), OL),
106fe6060f1SDimitry Andric       TLOF(std::make_unique<M68kELFTargetObjectFile>()),
107fe6060f1SDimitry Andric       Subtarget(TT, CPU, FS, *this) {
108fe6060f1SDimitry Andric   initAsmInfo();
109fe6060f1SDimitry Andric }
110fe6060f1SDimitry Andric 
111fe6060f1SDimitry Andric M68kTargetMachine::~M68kTargetMachine() {}
112fe6060f1SDimitry Andric 
113fe6060f1SDimitry Andric const M68kSubtarget *
114fe6060f1SDimitry Andric M68kTargetMachine::getSubtargetImpl(const Function &F) const {
115fe6060f1SDimitry Andric   Attribute CPUAttr = F.getFnAttribute("target-cpu");
116fe6060f1SDimitry Andric   Attribute FSAttr = F.getFnAttribute("target-features");
117fe6060f1SDimitry Andric 
118fe6060f1SDimitry Andric   auto CPU = CPUAttr.isValid() ? CPUAttr.getValueAsString().str() : TargetCPU;
119fe6060f1SDimitry Andric   auto FS = FSAttr.isValid() ? FSAttr.getValueAsString().str() : TargetFS;
120fe6060f1SDimitry Andric 
121fe6060f1SDimitry Andric   auto &I = SubtargetMap[CPU + FS];
122fe6060f1SDimitry Andric   if (!I) {
123fe6060f1SDimitry Andric     // This needs to be done before we create a new subtarget since any
124fe6060f1SDimitry Andric     // creation will depend on the TM and the code generation flags on the
125fe6060f1SDimitry Andric     // function that reside in TargetOptions.
126fe6060f1SDimitry Andric     resetTargetOptions(F);
127fe6060f1SDimitry Andric     I = std::make_unique<M68kSubtarget>(TargetTriple, CPU, FS, *this);
128fe6060f1SDimitry Andric   }
129fe6060f1SDimitry Andric   return I.get();
130fe6060f1SDimitry Andric }
131fe6060f1SDimitry Andric 
132*bdd1243dSDimitry Andric MachineFunctionInfo *M68kTargetMachine::createMachineFunctionInfo(
133*bdd1243dSDimitry Andric     BumpPtrAllocator &Allocator, const Function &F,
134*bdd1243dSDimitry Andric     const TargetSubtargetInfo *STI) const {
135*bdd1243dSDimitry Andric   return M68kMachineFunctionInfo::create<M68kMachineFunctionInfo>(Allocator, F,
136*bdd1243dSDimitry Andric                                                                   STI);
137*bdd1243dSDimitry Andric }
138*bdd1243dSDimitry Andric 
139fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
140fe6060f1SDimitry Andric // Pass Pipeline Configuration
141fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
142fe6060f1SDimitry Andric 
143fe6060f1SDimitry Andric namespace {
144fe6060f1SDimitry Andric class M68kPassConfig : public TargetPassConfig {
145fe6060f1SDimitry Andric public:
146fe6060f1SDimitry Andric   M68kPassConfig(M68kTargetMachine &TM, PassManagerBase &PM)
147fe6060f1SDimitry Andric       : TargetPassConfig(TM, PM) {}
148fe6060f1SDimitry Andric 
149fe6060f1SDimitry Andric   M68kTargetMachine &getM68kTargetMachine() const {
150fe6060f1SDimitry Andric     return getTM<M68kTargetMachine>();
151fe6060f1SDimitry Andric   }
152fe6060f1SDimitry Andric 
153fe6060f1SDimitry Andric   const M68kSubtarget &getM68kSubtarget() const {
154fe6060f1SDimitry Andric     return *getM68kTargetMachine().getSubtargetImpl();
155fe6060f1SDimitry Andric   }
156*bdd1243dSDimitry Andric   void addIRPasses() override;
157fe6060f1SDimitry Andric   bool addIRTranslator() override;
158fe6060f1SDimitry Andric   bool addLegalizeMachineIR() override;
159fe6060f1SDimitry Andric   bool addRegBankSelect() override;
160fe6060f1SDimitry Andric   bool addGlobalInstructionSelect() override;
161fe6060f1SDimitry Andric   bool addInstSelector() override;
162fe6060f1SDimitry Andric   void addPreSched2() override;
163fe6060f1SDimitry Andric   void addPreEmitPass() override;
164fe6060f1SDimitry Andric };
165fe6060f1SDimitry Andric } // namespace
166fe6060f1SDimitry Andric 
167fe6060f1SDimitry Andric TargetPassConfig *M68kTargetMachine::createPassConfig(PassManagerBase &PM) {
168fe6060f1SDimitry Andric   return new M68kPassConfig(*this, PM);
169fe6060f1SDimitry Andric }
170fe6060f1SDimitry Andric 
171*bdd1243dSDimitry Andric void M68kPassConfig::addIRPasses() {
172*bdd1243dSDimitry Andric   addPass(createAtomicExpandPass());
173*bdd1243dSDimitry Andric   TargetPassConfig::addIRPasses();
174*bdd1243dSDimitry Andric }
175*bdd1243dSDimitry Andric 
176fe6060f1SDimitry Andric bool M68kPassConfig::addInstSelector() {
177fe6060f1SDimitry Andric   // Install an instruction selector.
178fe6060f1SDimitry Andric   addPass(createM68kISelDag(getM68kTargetMachine()));
179fe6060f1SDimitry Andric   addPass(createM68kGlobalBaseRegPass());
180fe6060f1SDimitry Andric   return false;
181fe6060f1SDimitry Andric }
182fe6060f1SDimitry Andric 
183fe6060f1SDimitry Andric bool M68kPassConfig::addIRTranslator() {
184fe6060f1SDimitry Andric   addPass(new IRTranslator());
185fe6060f1SDimitry Andric   return false;
186fe6060f1SDimitry Andric }
187fe6060f1SDimitry Andric 
188fe6060f1SDimitry Andric bool M68kPassConfig::addLegalizeMachineIR() {
189fe6060f1SDimitry Andric   addPass(new Legalizer());
190fe6060f1SDimitry Andric   return false;
191fe6060f1SDimitry Andric }
192fe6060f1SDimitry Andric 
193fe6060f1SDimitry Andric bool M68kPassConfig::addRegBankSelect() {
194fe6060f1SDimitry Andric   addPass(new RegBankSelect());
195fe6060f1SDimitry Andric   return false;
196fe6060f1SDimitry Andric }
197fe6060f1SDimitry Andric 
198fe6060f1SDimitry Andric bool M68kPassConfig::addGlobalInstructionSelect() {
199fe6060f1SDimitry Andric   addPass(new InstructionSelect());
200fe6060f1SDimitry Andric   return false;
201fe6060f1SDimitry Andric }
202fe6060f1SDimitry Andric 
203fe6060f1SDimitry Andric void M68kPassConfig::addPreSched2() { addPass(createM68kExpandPseudoPass()); }
204fe6060f1SDimitry Andric 
205fe6060f1SDimitry Andric void M68kPassConfig::addPreEmitPass() {
206fe6060f1SDimitry Andric   addPass(createM68kCollapseMOVEMPass());
207fe6060f1SDimitry Andric }
208