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" 16*06c3fb27SDimitry Andric #include "LoongArchTargetTransformInfo.h" 1781ad6265SDimitry Andric #include "MCTargetDesc/LoongArchBaseInfo.h" 1881ad6265SDimitry Andric #include "TargetInfo/LoongArchTargetInfo.h" 19*06c3fb27SDimitry 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" 24*06c3fb27SDimitry Andric #include "llvm/Support/CodeGen.h" 25*06c3fb27SDimitry 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 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(); 37bdd1243dSDimitry Andric initializeLoongArchPreRAExpandPseudoPass(*PR); 38bdd1243dSDimitry Andric initializeLoongArchDAGToDAGISelPass(*PR); 3981ad6265SDimitry Andric } 4081ad6265SDimitry Andric 41*06c3fb27SDimitry Andric static cl::opt<bool> 42*06c3fb27SDimitry Andric EnableLoopDataPrefetch("loongarch-enable-loop-data-prefetch", cl::Hidden, 43*06c3fb27SDimitry Andric cl::desc("Enable the loop data prefetch pass"), 44*06c3fb27SDimitry Andric cl::init(false)); 45*06c3fb27SDimitry Andric 4681ad6265SDimitry Andric static std::string computeDataLayout(const Triple &TT) { 4781ad6265SDimitry Andric if (TT.isArch64Bit()) 4881ad6265SDimitry Andric return "e-m:e-p:64:64-i64:64-i128:128-n64-S128"; 4981ad6265SDimitry Andric assert(TT.isArch32Bit() && "only LA32 and LA64 are currently supported"); 5081ad6265SDimitry Andric return "e-m:e-p:32:32-i64:64-n32-S128"; 5181ad6265SDimitry Andric } 5281ad6265SDimitry Andric 5381ad6265SDimitry Andric static Reloc::Model getEffectiveRelocModel(const Triple &TT, 54bdd1243dSDimitry Andric std::optional<Reloc::Model> RM) { 55fcaf7f86SDimitry Andric return RM.value_or(Reloc::Static); 5681ad6265SDimitry Andric } 5781ad6265SDimitry Andric 58*06c3fb27SDimitry Andric static CodeModel::Model 59*06c3fb27SDimitry Andric getEffectiveLoongArchCodeModel(const Triple &TT, 60*06c3fb27SDimitry Andric std::optional<CodeModel::Model> CM) { 61*06c3fb27SDimitry Andric if (!CM) 62*06c3fb27SDimitry Andric return CodeModel::Small; 63*06c3fb27SDimitry Andric 64*06c3fb27SDimitry Andric switch (*CM) { 65*06c3fb27SDimitry Andric case CodeModel::Small: 66*06c3fb27SDimitry Andric case CodeModel::Medium: 67*06c3fb27SDimitry Andric return *CM; 68*06c3fb27SDimitry Andric case CodeModel::Large: 69*06c3fb27SDimitry Andric if (!TT.isArch64Bit()) 70*06c3fb27SDimitry Andric report_fatal_error("Large code model requires LA64"); 71*06c3fb27SDimitry Andric return *CM; 72*06c3fb27SDimitry Andric default: 73*06c3fb27SDimitry Andric report_fatal_error( 74*06c3fb27SDimitry Andric "Only small, medium and large code models are allowed on LoongArch"); 75*06c3fb27SDimitry Andric } 76*06c3fb27SDimitry Andric } 77*06c3fb27SDimitry Andric 7881ad6265SDimitry Andric LoongArchTargetMachine::LoongArchTargetMachine( 7981ad6265SDimitry Andric const Target &T, const Triple &TT, StringRef CPU, StringRef FS, 80bdd1243dSDimitry Andric const TargetOptions &Options, std::optional<Reloc::Model> RM, 81bdd1243dSDimitry Andric std::optional<CodeModel::Model> CM, CodeGenOpt::Level OL, bool JIT) 8281ad6265SDimitry Andric : LLVMTargetMachine(T, computeDataLayout(TT), TT, CPU, FS, Options, 8381ad6265SDimitry Andric getEffectiveRelocModel(TT, RM), 84*06c3fb27SDimitry Andric getEffectiveLoongArchCodeModel(TT, CM), OL), 8581ad6265SDimitry Andric TLOF(std::make_unique<TargetLoweringObjectFileELF>()) { 8681ad6265SDimitry Andric initAsmInfo(); 8781ad6265SDimitry Andric } 8881ad6265SDimitry Andric 8981ad6265SDimitry Andric LoongArchTargetMachine::~LoongArchTargetMachine() = default; 9081ad6265SDimitry Andric 9181ad6265SDimitry Andric const LoongArchSubtarget * 9281ad6265SDimitry Andric LoongArchTargetMachine::getSubtargetImpl(const Function &F) const { 9381ad6265SDimitry Andric Attribute CPUAttr = F.getFnAttribute("target-cpu"); 9481ad6265SDimitry Andric Attribute TuneAttr = F.getFnAttribute("tune-cpu"); 9581ad6265SDimitry Andric Attribute FSAttr = F.getFnAttribute("target-features"); 9681ad6265SDimitry Andric 9781ad6265SDimitry Andric std::string CPU = 9881ad6265SDimitry Andric CPUAttr.isValid() ? CPUAttr.getValueAsString().str() : TargetCPU; 9981ad6265SDimitry Andric std::string TuneCPU = 10081ad6265SDimitry Andric TuneAttr.isValid() ? TuneAttr.getValueAsString().str() : CPU; 10181ad6265SDimitry Andric std::string FS = 10281ad6265SDimitry Andric FSAttr.isValid() ? FSAttr.getValueAsString().str() : TargetFS; 10381ad6265SDimitry Andric 10481ad6265SDimitry Andric std::string Key = CPU + TuneCPU + FS; 10581ad6265SDimitry Andric auto &I = SubtargetMap[Key]; 10681ad6265SDimitry Andric if (!I) { 10781ad6265SDimitry Andric // This needs to be done before we create a new subtarget since any 10881ad6265SDimitry Andric // creation will depend on the TM and the code generation flags on the 10981ad6265SDimitry Andric // function that reside in TargetOptions. 11081ad6265SDimitry Andric resetTargetOptions(F); 11181ad6265SDimitry Andric auto ABIName = Options.MCOptions.getABIName(); 11281ad6265SDimitry Andric if (const MDString *ModuleTargetABI = dyn_cast_or_null<MDString>( 11381ad6265SDimitry Andric F.getParent()->getModuleFlag("target-abi"))) { 11481ad6265SDimitry Andric auto TargetABI = LoongArchABI::getTargetABI(ABIName); 11581ad6265SDimitry Andric if (TargetABI != LoongArchABI::ABI_Unknown && 11681ad6265SDimitry Andric ModuleTargetABI->getString() != ABIName) { 11781ad6265SDimitry Andric report_fatal_error("-target-abi option != target-abi module flag"); 11881ad6265SDimitry Andric } 11981ad6265SDimitry Andric ABIName = ModuleTargetABI->getString(); 12081ad6265SDimitry Andric } 12181ad6265SDimitry Andric I = std::make_unique<LoongArchSubtarget>(TargetTriple, CPU, TuneCPU, FS, 12281ad6265SDimitry Andric ABIName, *this); 12381ad6265SDimitry Andric } 12481ad6265SDimitry Andric return I.get(); 12581ad6265SDimitry Andric } 12681ad6265SDimitry Andric 127bdd1243dSDimitry Andric MachineFunctionInfo *LoongArchTargetMachine::createMachineFunctionInfo( 128bdd1243dSDimitry Andric BumpPtrAllocator &Allocator, const Function &F, 129bdd1243dSDimitry Andric const TargetSubtargetInfo *STI) const { 130bdd1243dSDimitry Andric return LoongArchMachineFunctionInfo::create<LoongArchMachineFunctionInfo>( 131bdd1243dSDimitry Andric Allocator, F, STI); 132bdd1243dSDimitry Andric } 133bdd1243dSDimitry Andric 13481ad6265SDimitry Andric namespace { 13581ad6265SDimitry Andric class LoongArchPassConfig : public TargetPassConfig { 13681ad6265SDimitry Andric public: 13781ad6265SDimitry Andric LoongArchPassConfig(LoongArchTargetMachine &TM, PassManagerBase &PM) 13881ad6265SDimitry Andric : TargetPassConfig(TM, PM) {} 13981ad6265SDimitry Andric 14081ad6265SDimitry Andric LoongArchTargetMachine &getLoongArchTargetMachine() const { 14181ad6265SDimitry Andric return getTM<LoongArchTargetMachine>(); 14281ad6265SDimitry Andric } 14381ad6265SDimitry Andric 144753f127fSDimitry Andric void addIRPasses() override; 14581ad6265SDimitry Andric bool addInstSelector() override; 146bdd1243dSDimitry Andric void addPreEmitPass() override; 147bdd1243dSDimitry Andric void addPreEmitPass2() override; 148bdd1243dSDimitry Andric void addPreRegAlloc() override; 14981ad6265SDimitry Andric }; 150972a253aSDimitry Andric } // end namespace 15181ad6265SDimitry Andric 15281ad6265SDimitry Andric TargetPassConfig * 15381ad6265SDimitry Andric LoongArchTargetMachine::createPassConfig(PassManagerBase &PM) { 15481ad6265SDimitry Andric return new LoongArchPassConfig(*this, PM); 15581ad6265SDimitry Andric } 15681ad6265SDimitry Andric 157753f127fSDimitry Andric void LoongArchPassConfig::addIRPasses() { 158*06c3fb27SDimitry Andric // Run LoopDataPrefetch 159*06c3fb27SDimitry Andric // 160*06c3fb27SDimitry Andric // Run this before LSR to remove the multiplies involved in computing the 161*06c3fb27SDimitry Andric // pointer values N iterations ahead. 162*06c3fb27SDimitry Andric if (TM->getOptLevel() != CodeGenOpt::None && EnableLoopDataPrefetch) 163*06c3fb27SDimitry Andric addPass(createLoopDataPrefetchPass()); 164753f127fSDimitry Andric addPass(createAtomicExpandPass()); 165753f127fSDimitry Andric 166753f127fSDimitry Andric TargetPassConfig::addIRPasses(); 167753f127fSDimitry Andric } 168753f127fSDimitry Andric 16981ad6265SDimitry Andric bool LoongArchPassConfig::addInstSelector() { 17081ad6265SDimitry Andric addPass(createLoongArchISelDag(getLoongArchTargetMachine())); 17181ad6265SDimitry Andric 17281ad6265SDimitry Andric return false; 17381ad6265SDimitry Andric } 174bdd1243dSDimitry Andric 175*06c3fb27SDimitry Andric TargetTransformInfo 176*06c3fb27SDimitry Andric LoongArchTargetMachine::getTargetTransformInfo(const Function &F) const { 177*06c3fb27SDimitry Andric return TargetTransformInfo(LoongArchTTIImpl(this, F)); 178*06c3fb27SDimitry Andric } 179*06c3fb27SDimitry Andric 180bdd1243dSDimitry Andric void LoongArchPassConfig::addPreEmitPass() { addPass(&BranchRelaxationPassID); } 181bdd1243dSDimitry Andric 182bdd1243dSDimitry Andric void LoongArchPassConfig::addPreEmitPass2() { 183bdd1243dSDimitry Andric // Schedule the expansion of AtomicPseudos at the last possible moment, 184bdd1243dSDimitry Andric // avoiding the possibility for other passes to break the requirements for 185bdd1243dSDimitry Andric // forward progress in the LL/SC block. 186bdd1243dSDimitry Andric addPass(createLoongArchExpandAtomicPseudoPass()); 187bdd1243dSDimitry Andric } 188bdd1243dSDimitry Andric 189bdd1243dSDimitry Andric void LoongArchPassConfig::addPreRegAlloc() { 190bdd1243dSDimitry Andric addPass(createLoongArchPreRAExpandPseudoPass()); 191bdd1243dSDimitry Andric } 192