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