xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/LoongArch/LoongArchTargetMachine.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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"
15*bdd1243dSDimitry Andric #include "LoongArchMachineFunctionInfo.h"
1681ad6265SDimitry Andric #include "MCTargetDesc/LoongArchBaseInfo.h"
1781ad6265SDimitry Andric #include "TargetInfo/LoongArchTargetInfo.h"
1881ad6265SDimitry Andric #include "llvm/CodeGen/Passes.h"
1981ad6265SDimitry Andric #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
2081ad6265SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h"
2181ad6265SDimitry Andric #include "llvm/MC/TargetRegistry.h"
22*bdd1243dSDimitry Andric #include <optional>
2381ad6265SDimitry Andric 
2481ad6265SDimitry Andric using namespace llvm;
2581ad6265SDimitry Andric 
2681ad6265SDimitry Andric #define DEBUG_TYPE "loongarch"
2781ad6265SDimitry Andric 
2881ad6265SDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeLoongArchTarget() {
2981ad6265SDimitry Andric   // Register the target.
3081ad6265SDimitry Andric   RegisterTargetMachine<LoongArchTargetMachine> X(getTheLoongArch32Target());
3181ad6265SDimitry Andric   RegisterTargetMachine<LoongArchTargetMachine> Y(getTheLoongArch64Target());
32*bdd1243dSDimitry Andric   auto *PR = PassRegistry::getPassRegistry();
33*bdd1243dSDimitry Andric   initializeLoongArchPreRAExpandPseudoPass(*PR);
34*bdd1243dSDimitry Andric   initializeLoongArchDAGToDAGISelPass(*PR);
3581ad6265SDimitry Andric }
3681ad6265SDimitry Andric 
3781ad6265SDimitry Andric static std::string computeDataLayout(const Triple &TT) {
3881ad6265SDimitry Andric   if (TT.isArch64Bit())
3981ad6265SDimitry Andric     return "e-m:e-p:64:64-i64:64-i128:128-n64-S128";
4081ad6265SDimitry Andric   assert(TT.isArch32Bit() && "only LA32 and LA64 are currently supported");
4181ad6265SDimitry Andric   return "e-m:e-p:32:32-i64:64-n32-S128";
4281ad6265SDimitry Andric }
4381ad6265SDimitry Andric 
4481ad6265SDimitry Andric static Reloc::Model getEffectiveRelocModel(const Triple &TT,
45*bdd1243dSDimitry Andric                                            std::optional<Reloc::Model> RM) {
46fcaf7f86SDimitry Andric   return RM.value_or(Reloc::Static);
4781ad6265SDimitry Andric }
4881ad6265SDimitry Andric 
4981ad6265SDimitry Andric LoongArchTargetMachine::LoongArchTargetMachine(
5081ad6265SDimitry Andric     const Target &T, const Triple &TT, StringRef CPU, StringRef FS,
51*bdd1243dSDimitry Andric     const TargetOptions &Options, std::optional<Reloc::Model> RM,
52*bdd1243dSDimitry Andric     std::optional<CodeModel::Model> CM, CodeGenOpt::Level OL, bool JIT)
5381ad6265SDimitry Andric     : LLVMTargetMachine(T, computeDataLayout(TT), TT, CPU, FS, Options,
5481ad6265SDimitry Andric                         getEffectiveRelocModel(TT, RM),
5581ad6265SDimitry Andric                         getEffectiveCodeModel(CM, CodeModel::Small), OL),
5681ad6265SDimitry Andric       TLOF(std::make_unique<TargetLoweringObjectFileELF>()) {
5781ad6265SDimitry Andric   initAsmInfo();
5881ad6265SDimitry Andric }
5981ad6265SDimitry Andric 
6081ad6265SDimitry Andric LoongArchTargetMachine::~LoongArchTargetMachine() = default;
6181ad6265SDimitry Andric 
6281ad6265SDimitry Andric const LoongArchSubtarget *
6381ad6265SDimitry Andric LoongArchTargetMachine::getSubtargetImpl(const Function &F) const {
6481ad6265SDimitry Andric   Attribute CPUAttr = F.getFnAttribute("target-cpu");
6581ad6265SDimitry Andric   Attribute TuneAttr = F.getFnAttribute("tune-cpu");
6681ad6265SDimitry Andric   Attribute FSAttr = F.getFnAttribute("target-features");
6781ad6265SDimitry Andric 
6881ad6265SDimitry Andric   std::string CPU =
6981ad6265SDimitry Andric       CPUAttr.isValid() ? CPUAttr.getValueAsString().str() : TargetCPU;
7081ad6265SDimitry Andric   std::string TuneCPU =
7181ad6265SDimitry Andric       TuneAttr.isValid() ? TuneAttr.getValueAsString().str() : CPU;
7281ad6265SDimitry Andric   std::string FS =
7381ad6265SDimitry Andric       FSAttr.isValid() ? FSAttr.getValueAsString().str() : TargetFS;
7481ad6265SDimitry Andric 
7581ad6265SDimitry Andric   std::string Key = CPU + TuneCPU + FS;
7681ad6265SDimitry Andric   auto &I = SubtargetMap[Key];
7781ad6265SDimitry Andric   if (!I) {
7881ad6265SDimitry Andric     // This needs to be done before we create a new subtarget since any
7981ad6265SDimitry Andric     // creation will depend on the TM and the code generation flags on the
8081ad6265SDimitry Andric     // function that reside in TargetOptions.
8181ad6265SDimitry Andric     resetTargetOptions(F);
8281ad6265SDimitry Andric     auto ABIName = Options.MCOptions.getABIName();
8381ad6265SDimitry Andric     if (const MDString *ModuleTargetABI = dyn_cast_or_null<MDString>(
8481ad6265SDimitry Andric             F.getParent()->getModuleFlag("target-abi"))) {
8581ad6265SDimitry Andric       auto TargetABI = LoongArchABI::getTargetABI(ABIName);
8681ad6265SDimitry Andric       if (TargetABI != LoongArchABI::ABI_Unknown &&
8781ad6265SDimitry Andric           ModuleTargetABI->getString() != ABIName) {
8881ad6265SDimitry Andric         report_fatal_error("-target-abi option != target-abi module flag");
8981ad6265SDimitry Andric       }
9081ad6265SDimitry Andric       ABIName = ModuleTargetABI->getString();
9181ad6265SDimitry Andric     }
9281ad6265SDimitry Andric     I = std::make_unique<LoongArchSubtarget>(TargetTriple, CPU, TuneCPU, FS,
9381ad6265SDimitry Andric                                              ABIName, *this);
9481ad6265SDimitry Andric   }
9581ad6265SDimitry Andric   return I.get();
9681ad6265SDimitry Andric }
9781ad6265SDimitry Andric 
98*bdd1243dSDimitry Andric MachineFunctionInfo *LoongArchTargetMachine::createMachineFunctionInfo(
99*bdd1243dSDimitry Andric     BumpPtrAllocator &Allocator, const Function &F,
100*bdd1243dSDimitry Andric     const TargetSubtargetInfo *STI) const {
101*bdd1243dSDimitry Andric   return LoongArchMachineFunctionInfo::create<LoongArchMachineFunctionInfo>(
102*bdd1243dSDimitry Andric       Allocator, F, STI);
103*bdd1243dSDimitry Andric }
104*bdd1243dSDimitry Andric 
10581ad6265SDimitry Andric namespace {
10681ad6265SDimitry Andric class LoongArchPassConfig : public TargetPassConfig {
10781ad6265SDimitry Andric public:
10881ad6265SDimitry Andric   LoongArchPassConfig(LoongArchTargetMachine &TM, PassManagerBase &PM)
10981ad6265SDimitry Andric       : TargetPassConfig(TM, PM) {}
11081ad6265SDimitry Andric 
11181ad6265SDimitry Andric   LoongArchTargetMachine &getLoongArchTargetMachine() const {
11281ad6265SDimitry Andric     return getTM<LoongArchTargetMachine>();
11381ad6265SDimitry Andric   }
11481ad6265SDimitry Andric 
115753f127fSDimitry Andric   void addIRPasses() override;
11681ad6265SDimitry Andric   bool addInstSelector() override;
117*bdd1243dSDimitry Andric   void addPreEmitPass() override;
118*bdd1243dSDimitry Andric   void addPreEmitPass2() override;
119*bdd1243dSDimitry Andric   void addPreRegAlloc() override;
12081ad6265SDimitry Andric };
121972a253aSDimitry Andric } // end namespace
12281ad6265SDimitry Andric 
12381ad6265SDimitry Andric TargetPassConfig *
12481ad6265SDimitry Andric LoongArchTargetMachine::createPassConfig(PassManagerBase &PM) {
12581ad6265SDimitry Andric   return new LoongArchPassConfig(*this, PM);
12681ad6265SDimitry Andric }
12781ad6265SDimitry Andric 
128753f127fSDimitry Andric void LoongArchPassConfig::addIRPasses() {
129753f127fSDimitry Andric   addPass(createAtomicExpandPass());
130753f127fSDimitry Andric 
131753f127fSDimitry Andric   TargetPassConfig::addIRPasses();
132753f127fSDimitry Andric }
133753f127fSDimitry Andric 
13481ad6265SDimitry Andric bool LoongArchPassConfig::addInstSelector() {
13581ad6265SDimitry Andric   addPass(createLoongArchISelDag(getLoongArchTargetMachine()));
13681ad6265SDimitry Andric 
13781ad6265SDimitry Andric   return false;
13881ad6265SDimitry Andric }
139*bdd1243dSDimitry Andric 
140*bdd1243dSDimitry Andric void LoongArchPassConfig::addPreEmitPass() { addPass(&BranchRelaxationPassID); }
141*bdd1243dSDimitry Andric 
142*bdd1243dSDimitry Andric void LoongArchPassConfig::addPreEmitPass2() {
143*bdd1243dSDimitry Andric   // Schedule the expansion of AtomicPseudos at the last possible moment,
144*bdd1243dSDimitry Andric   // avoiding the possibility for other passes to break the requirements for
145*bdd1243dSDimitry Andric   // forward progress in the LL/SC block.
146*bdd1243dSDimitry Andric   addPass(createLoongArchExpandAtomicPseudoPass());
147*bdd1243dSDimitry Andric }
148*bdd1243dSDimitry Andric 
149*bdd1243dSDimitry Andric void LoongArchPassConfig::addPreRegAlloc() {
150*bdd1243dSDimitry Andric   addPass(createLoongArchPreRAExpandPseudoPass());
151*bdd1243dSDimitry Andric }
152