xref: /freebsd/contrib/llvm-project/llvm/lib/Target/LoongArch/LoongArchTargetMachine.cpp (revision 1342eb5a832fa10e689a29faab3acb6054e4778c)
1 //===-- LoongArchTargetMachine.cpp - Define TargetMachine for LoongArch ---===//
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 // Implements the info about LoongArch target spec.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "LoongArchTargetMachine.h"
14 #include "LoongArch.h"
15 #include "LoongArchMachineFunctionInfo.h"
16 #include "LoongArchTargetTransformInfo.h"
17 #include "MCTargetDesc/LoongArchBaseInfo.h"
18 #include "TargetInfo/LoongArchTargetInfo.h"
19 #include "llvm/Analysis/TargetTransformInfo.h"
20 #include "llvm/CodeGen/Passes.h"
21 #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
22 #include "llvm/CodeGen/TargetPassConfig.h"
23 #include "llvm/MC/TargetRegistry.h"
24 #include "llvm/Support/CodeGen.h"
25 #include "llvm/Support/Compiler.h"
26 #include "llvm/Transforms/Scalar.h"
27 #include <optional>
28 
29 using namespace llvm;
30 
31 #define DEBUG_TYPE "loongarch"
32 
33 extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void
34 LLVMInitializeLoongArchTarget() {
35   // Register the target.
36   RegisterTargetMachine<LoongArchTargetMachine> X(getTheLoongArch32Target());
37   RegisterTargetMachine<LoongArchTargetMachine> Y(getTheLoongArch64Target());
38   auto *PR = PassRegistry::getPassRegistry();
39   initializeLoongArchDeadRegisterDefinitionsPass(*PR);
40   initializeLoongArchMergeBaseOffsetOptPass(*PR);
41   initializeLoongArchOptWInstrsPass(*PR);
42   initializeLoongArchPreRAExpandPseudoPass(*PR);
43   initializeLoongArchExpandPseudoPass(*PR);
44   initializeLoongArchDAGToDAGISelLegacyPass(*PR);
45   initializeLoongArchExpandAtomicPseudoPass(*PR);
46 }
47 
48 static cl::opt<bool> EnableLoongArchDeadRegisterElimination(
49     "loongarch-enable-dead-defs", cl::Hidden,
50     cl::desc("Enable the pass that removes dead"
51              " definitons and replaces stores to"
52              " them with stores to r0"),
53     cl::init(true));
54 
55 static cl::opt<bool>
56     EnableLoopDataPrefetch("loongarch-enable-loop-data-prefetch", cl::Hidden,
57                            cl::desc("Enable the loop data prefetch pass"),
58                            cl::init(false));
59 
60 static std::string computeDataLayout(const Triple &TT) {
61   if (TT.isArch64Bit())
62     return "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128";
63   assert(TT.isArch32Bit() && "only LA32 and LA64 are currently supported");
64   return "e-m:e-p:32:32-i64:64-n32-S128";
65 }
66 
67 static Reloc::Model getEffectiveRelocModel(const Triple &TT,
68                                            std::optional<Reloc::Model> RM) {
69   return RM.value_or(Reloc::Static);
70 }
71 
72 static CodeModel::Model
73 getEffectiveLoongArchCodeModel(const Triple &TT,
74                                std::optional<CodeModel::Model> CM) {
75   if (!CM)
76     return TT.isArch64Bit() ? CodeModel::Medium : CodeModel::Small;
77 
78   switch (*CM) {
79   case CodeModel::Small:
80     return *CM;
81   case CodeModel::Medium:
82   case CodeModel::Large:
83     if (!TT.isArch64Bit())
84       report_fatal_error("Medium/Large code model requires LA64");
85     return *CM;
86   default:
87     report_fatal_error(
88         "Only small, medium and large code models are allowed on LoongArch");
89   }
90 }
91 
92 LoongArchTargetMachine::LoongArchTargetMachine(
93     const Target &T, const Triple &TT, StringRef CPU, StringRef FS,
94     const TargetOptions &Options, std::optional<Reloc::Model> RM,
95     std::optional<CodeModel::Model> CM, CodeGenOptLevel OL, bool JIT)
96     : CodeGenTargetMachineImpl(T, computeDataLayout(TT), TT, CPU, FS, Options,
97                                getEffectiveRelocModel(TT, RM),
98                                getEffectiveLoongArchCodeModel(TT, CM), OL),
99       TLOF(std::make_unique<TargetLoweringObjectFileELF>()) {
100   initAsmInfo();
101 }
102 
103 LoongArchTargetMachine::~LoongArchTargetMachine() = default;
104 
105 const LoongArchSubtarget *
106 LoongArchTargetMachine::getSubtargetImpl(const Function &F) const {
107   Attribute CPUAttr = F.getFnAttribute("target-cpu");
108   Attribute TuneAttr = F.getFnAttribute("tune-cpu");
109   Attribute FSAttr = F.getFnAttribute("target-features");
110 
111   std::string CPU =
112       CPUAttr.isValid() ? CPUAttr.getValueAsString().str() : TargetCPU;
113   std::string TuneCPU =
114       TuneAttr.isValid() ? TuneAttr.getValueAsString().str() : CPU;
115   std::string FS =
116       FSAttr.isValid() ? FSAttr.getValueAsString().str() : TargetFS;
117 
118   std::string Key = CPU + TuneCPU + FS;
119   auto &I = SubtargetMap[Key];
120   if (!I) {
121     // This needs to be done before we create a new subtarget since any
122     // creation will depend on the TM and the code generation flags on the
123     // function that reside in TargetOptions.
124     resetTargetOptions(F);
125     auto ABIName = Options.MCOptions.getABIName();
126     if (const MDString *ModuleTargetABI = dyn_cast_or_null<MDString>(
127             F.getParent()->getModuleFlag("target-abi"))) {
128       auto TargetABI = LoongArchABI::getTargetABI(ABIName);
129       if (TargetABI != LoongArchABI::ABI_Unknown &&
130           ModuleTargetABI->getString() != ABIName) {
131         report_fatal_error("-target-abi option != target-abi module flag");
132       }
133       ABIName = ModuleTargetABI->getString();
134     }
135     I = std::make_unique<LoongArchSubtarget>(TargetTriple, CPU, TuneCPU, FS,
136                                              ABIName, *this);
137   }
138   return I.get();
139 }
140 
141 MachineFunctionInfo *LoongArchTargetMachine::createMachineFunctionInfo(
142     BumpPtrAllocator &Allocator, const Function &F,
143     const TargetSubtargetInfo *STI) const {
144   return LoongArchMachineFunctionInfo::create<LoongArchMachineFunctionInfo>(
145       Allocator, F, STI);
146 }
147 
148 namespace {
149 class LoongArchPassConfig : public TargetPassConfig {
150 public:
151   LoongArchPassConfig(LoongArchTargetMachine &TM, PassManagerBase &PM)
152       : TargetPassConfig(TM, PM) {}
153 
154   LoongArchTargetMachine &getLoongArchTargetMachine() const {
155     return getTM<LoongArchTargetMachine>();
156   }
157 
158   void addIRPasses() override;
159   void addCodeGenPrepare() override;
160   bool addInstSelector() override;
161   void addPreEmitPass() override;
162   void addPreEmitPass2() override;
163   void addMachineSSAOptimization() override;
164   void addPreRegAlloc() override;
165   bool addRegAssignAndRewriteFast() override;
166   bool addRegAssignAndRewriteOptimized() override;
167 };
168 } // end namespace
169 
170 TargetPassConfig *
171 LoongArchTargetMachine::createPassConfig(PassManagerBase &PM) {
172   return new LoongArchPassConfig(*this, PM);
173 }
174 
175 void LoongArchPassConfig::addIRPasses() {
176   // Run LoopDataPrefetch
177   //
178   // Run this before LSR to remove the multiplies involved in computing the
179   // pointer values N iterations ahead.
180   if (TM->getOptLevel() != CodeGenOptLevel::None && EnableLoopDataPrefetch)
181     addPass(createLoopDataPrefetchPass());
182   addPass(createAtomicExpandLegacyPass());
183 
184   TargetPassConfig::addIRPasses();
185 }
186 
187 void LoongArchPassConfig::addCodeGenPrepare() {
188   if (getOptLevel() != CodeGenOptLevel::None)
189     addPass(createTypePromotionLegacyPass());
190   TargetPassConfig::addCodeGenPrepare();
191 }
192 
193 bool LoongArchPassConfig::addInstSelector() {
194   addPass(createLoongArchISelDag(getLoongArchTargetMachine(), getOptLevel()));
195 
196   return false;
197 }
198 
199 TargetTransformInfo
200 LoongArchTargetMachine::getTargetTransformInfo(const Function &F) const {
201   return TargetTransformInfo(std::make_unique<LoongArchTTIImpl>(this, F));
202 }
203 
204 void LoongArchPassConfig::addPreEmitPass() { addPass(&BranchRelaxationPassID); }
205 
206 void LoongArchPassConfig::addPreEmitPass2() {
207   addPass(createLoongArchExpandPseudoPass());
208   // Schedule the expansion of AtomicPseudos at the last possible moment,
209   // avoiding the possibility for other passes to break the requirements for
210   // forward progress in the LL/SC block.
211   addPass(createLoongArchExpandAtomicPseudoPass());
212 }
213 
214 void LoongArchPassConfig::addMachineSSAOptimization() {
215   TargetPassConfig::addMachineSSAOptimization();
216 
217   if (TM->getTargetTriple().isLoongArch64()) {
218     addPass(createLoongArchOptWInstrsPass());
219   }
220 }
221 
222 void LoongArchPassConfig::addPreRegAlloc() {
223   addPass(createLoongArchPreRAExpandPseudoPass());
224   if (TM->getOptLevel() != CodeGenOptLevel::None)
225     addPass(createLoongArchMergeBaseOffsetOptPass());
226 }
227 
228 bool LoongArchPassConfig::addRegAssignAndRewriteFast() {
229   if (TM->getOptLevel() != CodeGenOptLevel::None &&
230       EnableLoongArchDeadRegisterElimination)
231     addPass(createLoongArchDeadRegisterDefinitionsPass());
232   return TargetPassConfig::addRegAssignAndRewriteFast();
233 }
234 
235 bool LoongArchPassConfig::addRegAssignAndRewriteOptimized() {
236   if (TM->getOptLevel() != CodeGenOptLevel::None &&
237       EnableLoongArchDeadRegisterElimination)
238     addPass(createLoongArchDeadRegisterDefinitionsPass());
239   return TargetPassConfig::addRegAssignAndRewriteOptimized();
240 }
241