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
LLVMInitializeLoongArchTarget()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
computeDataLayout(const Triple & TT)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
getEffectiveRelocModel(const Triple & TT,std::optional<Reloc::Model> RM)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
getEffectiveLoongArchCodeModel(const Triple & TT,std::optional<CodeModel::Model> CM)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
LoongArchTargetMachine(const Target & T,const Triple & TT,StringRef CPU,StringRef FS,const TargetOptions & Options,std::optional<Reloc::Model> RM,std::optional<CodeModel::Model> CM,CodeGenOptLevel OL,bool JIT)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 *
getSubtargetImpl(const Function & F) const10181ad6265SDimitry 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
createMachineFunctionInfo(BumpPtrAllocator & Allocator,const Function & F,const TargetSubtargetInfo * STI) const136bdd1243dSDimitry 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:
LoongArchPassConfig(LoongArchTargetMachine & TM,PassManagerBase & PM)14681ad6265SDimitry Andric LoongArchPassConfig(LoongArchTargetMachine &TM, PassManagerBase &PM)
14781ad6265SDimitry Andric : TargetPassConfig(TM, PM) {}
14881ad6265SDimitry Andric
getLoongArchTargetMachine() const14981ad6265SDimitry 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 *
createPassConfig(PassManagerBase & PM)16681ad6265SDimitry Andric LoongArchTargetMachine::createPassConfig(PassManagerBase &PM) {
16781ad6265SDimitry Andric return new LoongArchPassConfig(*this, PM);
16881ad6265SDimitry Andric }
16981ad6265SDimitry Andric
addIRPasses()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
addCodeGenPrepare()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
addInstSelector()18881ad6265SDimitry Andric bool LoongArchPassConfig::addInstSelector() {
18981ad6265SDimitry Andric addPass(createLoongArchISelDag(getLoongArchTargetMachine()));
19081ad6265SDimitry Andric
19181ad6265SDimitry Andric return false;
19281ad6265SDimitry Andric }
193bdd1243dSDimitry Andric
19406c3fb27SDimitry Andric TargetTransformInfo
getTargetTransformInfo(const Function & F) const19506c3fb27SDimitry Andric LoongArchTargetMachine::getTargetTransformInfo(const Function &F) const {
19606c3fb27SDimitry Andric return TargetTransformInfo(LoongArchTTIImpl(this, F));
19706c3fb27SDimitry Andric }
19806c3fb27SDimitry Andric
addPreEmitPass()199bdd1243dSDimitry Andric void LoongArchPassConfig::addPreEmitPass() { addPass(&BranchRelaxationPassID); }
200bdd1243dSDimitry Andric
addPreEmitPass2()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
addMachineSSAOptimization()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
addPreRegAlloc()217bdd1243dSDimitry Andric void LoongArchPassConfig::addPreRegAlloc() {
218bdd1243dSDimitry Andric addPass(createLoongArchPreRAExpandPseudoPass());
219bdd1243dSDimitry Andric }
220*0fca6ea1SDimitry Andric
addRegAssignAndRewriteFast()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
addRegAssignAndRewriteOptimized()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