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