xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/LoongArch/LoongArchTargetMachine.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
181ad6265SDimitry Andric //===-- LoongArchTargetMachine.cpp - Define TargetMachine for LoongArch ---===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric //
981ad6265SDimitry Andric // Implements the info about LoongArch target spec.
1081ad6265SDimitry Andric //
1181ad6265SDimitry Andric //===----------------------------------------------------------------------===//
1281ad6265SDimitry Andric 
1381ad6265SDimitry Andric #include "LoongArchTargetMachine.h"
1481ad6265SDimitry Andric #include "LoongArch.h"
15bdd1243dSDimitry Andric #include "LoongArchMachineFunctionInfo.h"
1606c3fb27SDimitry Andric #include "LoongArchTargetTransformInfo.h"
1781ad6265SDimitry Andric #include "MCTargetDesc/LoongArchBaseInfo.h"
1881ad6265SDimitry Andric #include "TargetInfo/LoongArchTargetInfo.h"
1906c3fb27SDimitry Andric #include "llvm/Analysis/TargetTransformInfo.h"
2081ad6265SDimitry Andric #include "llvm/CodeGen/Passes.h"
2181ad6265SDimitry Andric #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
2281ad6265SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h"
2381ad6265SDimitry Andric #include "llvm/MC/TargetRegistry.h"
2406c3fb27SDimitry Andric #include "llvm/Support/CodeGen.h"
2506c3fb27SDimitry Andric #include "llvm/Transforms/Scalar.h"
26bdd1243dSDimitry Andric #include <optional>
2781ad6265SDimitry Andric 
2881ad6265SDimitry Andric using namespace llvm;
2981ad6265SDimitry Andric 
3081ad6265SDimitry Andric #define DEBUG_TYPE "loongarch"
3181ad6265SDimitry Andric 
3281ad6265SDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeLoongArchTarget() {
3381ad6265SDimitry Andric   // Register the target.
3481ad6265SDimitry Andric   RegisterTargetMachine<LoongArchTargetMachine> X(getTheLoongArch32Target());
3581ad6265SDimitry Andric   RegisterTargetMachine<LoongArchTargetMachine> Y(getTheLoongArch64Target());
36bdd1243dSDimitry Andric   auto *PR = PassRegistry::getPassRegistry();
37*0fca6ea1SDimitry Andric   initializeLoongArchDeadRegisterDefinitionsPass(*PR);
38*0fca6ea1SDimitry Andric   initializeLoongArchOptWInstrsPass(*PR);
39bdd1243dSDimitry Andric   initializeLoongArchPreRAExpandPseudoPass(*PR);
40*0fca6ea1SDimitry Andric   initializeLoongArchDAGToDAGISelLegacyPass(*PR);
4181ad6265SDimitry Andric }
4281ad6265SDimitry Andric 
43*0fca6ea1SDimitry Andric static cl::opt<bool> EnableLoongArchDeadRegisterElimination(
44*0fca6ea1SDimitry Andric     "loongarch-enable-dead-defs", cl::Hidden,
45*0fca6ea1SDimitry Andric     cl::desc("Enable the pass that removes dead"
46*0fca6ea1SDimitry Andric              " definitons and replaces stores to"
47*0fca6ea1SDimitry Andric              " them with stores to r0"),
48*0fca6ea1SDimitry Andric     cl::init(true));
49*0fca6ea1SDimitry Andric 
5006c3fb27SDimitry Andric static cl::opt<bool>
5106c3fb27SDimitry Andric     EnableLoopDataPrefetch("loongarch-enable-loop-data-prefetch", cl::Hidden,
5206c3fb27SDimitry Andric                            cl::desc("Enable the loop data prefetch pass"),
5306c3fb27SDimitry Andric                            cl::init(false));
5406c3fb27SDimitry Andric 
5581ad6265SDimitry Andric static std::string computeDataLayout(const Triple &TT) {
5681ad6265SDimitry Andric   if (TT.isArch64Bit())
57*0fca6ea1SDimitry Andric     return "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128";
5881ad6265SDimitry Andric   assert(TT.isArch32Bit() && "only LA32 and LA64 are currently supported");
5981ad6265SDimitry Andric   return "e-m:e-p:32:32-i64:64-n32-S128";
6081ad6265SDimitry Andric }
6181ad6265SDimitry Andric 
6281ad6265SDimitry Andric static Reloc::Model getEffectiveRelocModel(const Triple &TT,
63bdd1243dSDimitry Andric                                            std::optional<Reloc::Model> RM) {
64fcaf7f86SDimitry Andric   return RM.value_or(Reloc::Static);
6581ad6265SDimitry Andric }
6681ad6265SDimitry Andric 
6706c3fb27SDimitry Andric static CodeModel::Model
6806c3fb27SDimitry Andric getEffectiveLoongArchCodeModel(const Triple &TT,
6906c3fb27SDimitry Andric                                std::optional<CodeModel::Model> CM) {
7006c3fb27SDimitry Andric   if (!CM)
7106c3fb27SDimitry Andric     return CodeModel::Small;
7206c3fb27SDimitry Andric 
7306c3fb27SDimitry Andric   switch (*CM) {
7406c3fb27SDimitry Andric   case CodeModel::Small:
7506c3fb27SDimitry Andric     return *CM;
761db9f3b2SDimitry Andric   case CodeModel::Medium:
7706c3fb27SDimitry Andric   case CodeModel::Large:
7806c3fb27SDimitry Andric     if (!TT.isArch64Bit())
791db9f3b2SDimitry Andric       report_fatal_error("Medium/Large code model requires LA64");
8006c3fb27SDimitry Andric     return *CM;
8106c3fb27SDimitry Andric   default:
8206c3fb27SDimitry Andric     report_fatal_error(
8306c3fb27SDimitry Andric         "Only small, medium and large code models are allowed on LoongArch");
8406c3fb27SDimitry Andric   }
8506c3fb27SDimitry Andric }
8606c3fb27SDimitry Andric 
8781ad6265SDimitry Andric LoongArchTargetMachine::LoongArchTargetMachine(
8881ad6265SDimitry Andric     const Target &T, const Triple &TT, StringRef CPU, StringRef FS,
89bdd1243dSDimitry Andric     const TargetOptions &Options, std::optional<Reloc::Model> RM,
905f757f3fSDimitry Andric     std::optional<CodeModel::Model> CM, CodeGenOptLevel OL, bool JIT)
9181ad6265SDimitry Andric     : LLVMTargetMachine(T, computeDataLayout(TT), TT, CPU, FS, Options,
9281ad6265SDimitry Andric                         getEffectiveRelocModel(TT, RM),
9306c3fb27SDimitry Andric                         getEffectiveLoongArchCodeModel(TT, CM), OL),
9481ad6265SDimitry Andric       TLOF(std::make_unique<TargetLoweringObjectFileELF>()) {
9581ad6265SDimitry Andric   initAsmInfo();
9681ad6265SDimitry Andric }
9781ad6265SDimitry Andric 
9881ad6265SDimitry Andric LoongArchTargetMachine::~LoongArchTargetMachine() = default;
9981ad6265SDimitry Andric 
10081ad6265SDimitry Andric const LoongArchSubtarget *
10181ad6265SDimitry Andric LoongArchTargetMachine::getSubtargetImpl(const Function &F) const {
10281ad6265SDimitry Andric   Attribute CPUAttr = F.getFnAttribute("target-cpu");
10381ad6265SDimitry Andric   Attribute TuneAttr = F.getFnAttribute("tune-cpu");
10481ad6265SDimitry Andric   Attribute FSAttr = F.getFnAttribute("target-features");
10581ad6265SDimitry Andric 
10681ad6265SDimitry Andric   std::string CPU =
10781ad6265SDimitry Andric       CPUAttr.isValid() ? CPUAttr.getValueAsString().str() : TargetCPU;
10881ad6265SDimitry Andric   std::string TuneCPU =
10981ad6265SDimitry Andric       TuneAttr.isValid() ? TuneAttr.getValueAsString().str() : CPU;
11081ad6265SDimitry Andric   std::string FS =
11181ad6265SDimitry Andric       FSAttr.isValid() ? FSAttr.getValueAsString().str() : TargetFS;
11281ad6265SDimitry Andric 
11381ad6265SDimitry Andric   std::string Key = CPU + TuneCPU + FS;
11481ad6265SDimitry Andric   auto &I = SubtargetMap[Key];
11581ad6265SDimitry Andric   if (!I) {
11681ad6265SDimitry Andric     // This needs to be done before we create a new subtarget since any
11781ad6265SDimitry Andric     // creation will depend on the TM and the code generation flags on the
11881ad6265SDimitry Andric     // function that reside in TargetOptions.
11981ad6265SDimitry Andric     resetTargetOptions(F);
12081ad6265SDimitry Andric     auto ABIName = Options.MCOptions.getABIName();
12181ad6265SDimitry Andric     if (const MDString *ModuleTargetABI = dyn_cast_or_null<MDString>(
12281ad6265SDimitry Andric             F.getParent()->getModuleFlag("target-abi"))) {
12381ad6265SDimitry Andric       auto TargetABI = LoongArchABI::getTargetABI(ABIName);
12481ad6265SDimitry Andric       if (TargetABI != LoongArchABI::ABI_Unknown &&
12581ad6265SDimitry Andric           ModuleTargetABI->getString() != ABIName) {
12681ad6265SDimitry Andric         report_fatal_error("-target-abi option != target-abi module flag");
12781ad6265SDimitry Andric       }
12881ad6265SDimitry Andric       ABIName = ModuleTargetABI->getString();
12981ad6265SDimitry Andric     }
13081ad6265SDimitry Andric     I = std::make_unique<LoongArchSubtarget>(TargetTriple, CPU, TuneCPU, FS,
13181ad6265SDimitry Andric                                              ABIName, *this);
13281ad6265SDimitry Andric   }
13381ad6265SDimitry Andric   return I.get();
13481ad6265SDimitry Andric }
13581ad6265SDimitry Andric 
136bdd1243dSDimitry Andric MachineFunctionInfo *LoongArchTargetMachine::createMachineFunctionInfo(
137bdd1243dSDimitry Andric     BumpPtrAllocator &Allocator, const Function &F,
138bdd1243dSDimitry Andric     const TargetSubtargetInfo *STI) const {
139bdd1243dSDimitry Andric   return LoongArchMachineFunctionInfo::create<LoongArchMachineFunctionInfo>(
140bdd1243dSDimitry Andric       Allocator, F, STI);
141bdd1243dSDimitry Andric }
142bdd1243dSDimitry Andric 
14381ad6265SDimitry Andric namespace {
14481ad6265SDimitry Andric class LoongArchPassConfig : public TargetPassConfig {
14581ad6265SDimitry Andric public:
14681ad6265SDimitry Andric   LoongArchPassConfig(LoongArchTargetMachine &TM, PassManagerBase &PM)
14781ad6265SDimitry Andric       : TargetPassConfig(TM, PM) {}
14881ad6265SDimitry Andric 
14981ad6265SDimitry Andric   LoongArchTargetMachine &getLoongArchTargetMachine() const {
15081ad6265SDimitry Andric     return getTM<LoongArchTargetMachine>();
15181ad6265SDimitry Andric   }
15281ad6265SDimitry Andric 
153753f127fSDimitry Andric   void addIRPasses() override;
154*0fca6ea1SDimitry Andric   void addCodeGenPrepare() override;
15581ad6265SDimitry Andric   bool addInstSelector() override;
156bdd1243dSDimitry Andric   void addPreEmitPass() override;
157bdd1243dSDimitry Andric   void addPreEmitPass2() override;
158*0fca6ea1SDimitry Andric   void addMachineSSAOptimization() override;
159bdd1243dSDimitry Andric   void addPreRegAlloc() override;
160*0fca6ea1SDimitry Andric   bool addRegAssignAndRewriteFast() override;
161*0fca6ea1SDimitry Andric   bool addRegAssignAndRewriteOptimized() override;
16281ad6265SDimitry Andric };
163972a253aSDimitry Andric } // end namespace
16481ad6265SDimitry Andric 
16581ad6265SDimitry Andric TargetPassConfig *
16681ad6265SDimitry Andric LoongArchTargetMachine::createPassConfig(PassManagerBase &PM) {
16781ad6265SDimitry Andric   return new LoongArchPassConfig(*this, PM);
16881ad6265SDimitry Andric }
16981ad6265SDimitry Andric 
170753f127fSDimitry Andric void LoongArchPassConfig::addIRPasses() {
17106c3fb27SDimitry Andric   // Run LoopDataPrefetch
17206c3fb27SDimitry Andric   //
17306c3fb27SDimitry Andric   // Run this before LSR to remove the multiplies involved in computing the
17406c3fb27SDimitry Andric   // pointer values N iterations ahead.
1755f757f3fSDimitry Andric   if (TM->getOptLevel() != CodeGenOptLevel::None && EnableLoopDataPrefetch)
17606c3fb27SDimitry Andric     addPass(createLoopDataPrefetchPass());
177*0fca6ea1SDimitry Andric   addPass(createAtomicExpandLegacyPass());
178753f127fSDimitry Andric 
179753f127fSDimitry Andric   TargetPassConfig::addIRPasses();
180753f127fSDimitry Andric }
181753f127fSDimitry Andric 
182*0fca6ea1SDimitry Andric void LoongArchPassConfig::addCodeGenPrepare() {
183*0fca6ea1SDimitry Andric   if (getOptLevel() != CodeGenOptLevel::None)
184*0fca6ea1SDimitry Andric     addPass(createTypePromotionLegacyPass());
185*0fca6ea1SDimitry Andric   TargetPassConfig::addCodeGenPrepare();
186*0fca6ea1SDimitry Andric }
187*0fca6ea1SDimitry Andric 
18881ad6265SDimitry Andric bool LoongArchPassConfig::addInstSelector() {
18981ad6265SDimitry Andric   addPass(createLoongArchISelDag(getLoongArchTargetMachine()));
19081ad6265SDimitry Andric 
19181ad6265SDimitry Andric   return false;
19281ad6265SDimitry Andric }
193bdd1243dSDimitry Andric 
19406c3fb27SDimitry Andric TargetTransformInfo
19506c3fb27SDimitry Andric LoongArchTargetMachine::getTargetTransformInfo(const Function &F) const {
19606c3fb27SDimitry Andric   return TargetTransformInfo(LoongArchTTIImpl(this, F));
19706c3fb27SDimitry Andric }
19806c3fb27SDimitry Andric 
199bdd1243dSDimitry Andric void LoongArchPassConfig::addPreEmitPass() { addPass(&BranchRelaxationPassID); }
200bdd1243dSDimitry Andric 
201bdd1243dSDimitry Andric void LoongArchPassConfig::addPreEmitPass2() {
202b121cb00SDimitry Andric   addPass(createLoongArchExpandPseudoPass());
203bdd1243dSDimitry Andric   // Schedule the expansion of AtomicPseudos at the last possible moment,
204bdd1243dSDimitry Andric   // avoiding the possibility for other passes to break the requirements for
205bdd1243dSDimitry Andric   // forward progress in the LL/SC block.
206bdd1243dSDimitry Andric   addPass(createLoongArchExpandAtomicPseudoPass());
207bdd1243dSDimitry Andric }
208bdd1243dSDimitry Andric 
209*0fca6ea1SDimitry Andric void LoongArchPassConfig::addMachineSSAOptimization() {
210*0fca6ea1SDimitry Andric   TargetPassConfig::addMachineSSAOptimization();
211*0fca6ea1SDimitry Andric 
212*0fca6ea1SDimitry Andric   if (TM->getTargetTriple().isLoongArch64()) {
213*0fca6ea1SDimitry Andric     addPass(createLoongArchOptWInstrsPass());
214*0fca6ea1SDimitry Andric   }
215*0fca6ea1SDimitry Andric }
216*0fca6ea1SDimitry Andric 
217bdd1243dSDimitry Andric void LoongArchPassConfig::addPreRegAlloc() {
218bdd1243dSDimitry Andric   addPass(createLoongArchPreRAExpandPseudoPass());
219bdd1243dSDimitry Andric }
220*0fca6ea1SDimitry Andric 
221*0fca6ea1SDimitry Andric bool LoongArchPassConfig::addRegAssignAndRewriteFast() {
222*0fca6ea1SDimitry Andric   if (TM->getOptLevel() != CodeGenOptLevel::None &&
223*0fca6ea1SDimitry Andric       EnableLoongArchDeadRegisterElimination)
224*0fca6ea1SDimitry Andric     addPass(createLoongArchDeadRegisterDefinitionsPass());
225*0fca6ea1SDimitry Andric   return TargetPassConfig::addRegAssignAndRewriteFast();
226*0fca6ea1SDimitry Andric }
227*0fca6ea1SDimitry Andric 
228*0fca6ea1SDimitry Andric bool LoongArchPassConfig::addRegAssignAndRewriteOptimized() {
229*0fca6ea1SDimitry Andric   if (TM->getOptLevel() != CodeGenOptLevel::None &&
230*0fca6ea1SDimitry Andric       EnableLoongArchDeadRegisterElimination)
231*0fca6ea1SDimitry Andric     addPass(createLoongArchDeadRegisterDefinitionsPass());
232*0fca6ea1SDimitry Andric   return TargetPassConfig::addRegAssignAndRewriteOptimized();
233*0fca6ea1SDimitry Andric }
234