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