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" 1606c3fb27SDimitry Andric #include "LoongArchTargetTransformInfo.h" 1781ad6265SDimitry Andric #include "MCTargetDesc/LoongArchBaseInfo.h" 1881ad6265SDimitry Andric #include "TargetInfo/LoongArchTargetInfo.h" 1906c3fb27SDimitry 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" 2406c3fb27SDimitry Andric #include "llvm/Support/CodeGen.h" 2506c3fb27SDimitry 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(); 37*0fca6ea1SDimitry Andric initializeLoongArchDeadRegisterDefinitionsPass(*PR); 38*0fca6ea1SDimitry Andric initializeLoongArchOptWInstrsPass(*PR); 39bdd1243dSDimitry Andric initializeLoongArchPreRAExpandPseudoPass(*PR); 40*0fca6ea1SDimitry Andric initializeLoongArchDAGToDAGISelLegacyPass(*PR); 4181ad6265SDimitry Andric } 4281ad6265SDimitry Andric 43*0fca6ea1SDimitry Andric static cl::opt<bool> EnableLoongArchDeadRegisterElimination( 44*0fca6ea1SDimitry Andric "loongarch-enable-dead-defs", cl::Hidden, 45*0fca6ea1SDimitry Andric cl::desc("Enable the pass that removes dead" 46*0fca6ea1SDimitry Andric " definitons and replaces stores to" 47*0fca6ea1SDimitry Andric " them with stores to r0"), 48*0fca6ea1SDimitry Andric cl::init(true)); 49*0fca6ea1SDimitry Andric 5006c3fb27SDimitry Andric static cl::opt<bool> 5106c3fb27SDimitry Andric EnableLoopDataPrefetch("loongarch-enable-loop-data-prefetch", cl::Hidden, 5206c3fb27SDimitry Andric cl::desc("Enable the loop data prefetch pass"), 5306c3fb27SDimitry Andric cl::init(false)); 5406c3fb27SDimitry Andric 5581ad6265SDimitry Andric static std::string computeDataLayout(const Triple &TT) { 5681ad6265SDimitry Andric if (TT.isArch64Bit()) 57*0fca6ea1SDimitry Andric return "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"; 5881ad6265SDimitry Andric assert(TT.isArch32Bit() && "only LA32 and LA64 are currently supported"); 5981ad6265SDimitry Andric return "e-m:e-p:32:32-i64:64-n32-S128"; 6081ad6265SDimitry Andric } 6181ad6265SDimitry Andric 6281ad6265SDimitry Andric static Reloc::Model getEffectiveRelocModel(const Triple &TT, 63bdd1243dSDimitry Andric std::optional<Reloc::Model> RM) { 64fcaf7f86SDimitry Andric return RM.value_or(Reloc::Static); 6581ad6265SDimitry Andric } 6681ad6265SDimitry Andric 6706c3fb27SDimitry Andric static CodeModel::Model 6806c3fb27SDimitry Andric getEffectiveLoongArchCodeModel(const Triple &TT, 6906c3fb27SDimitry Andric std::optional<CodeModel::Model> CM) { 7006c3fb27SDimitry Andric if (!CM) 7106c3fb27SDimitry Andric return CodeModel::Small; 7206c3fb27SDimitry Andric 7306c3fb27SDimitry Andric switch (*CM) { 7406c3fb27SDimitry Andric case CodeModel::Small: 7506c3fb27SDimitry Andric return *CM; 761db9f3b2SDimitry Andric case CodeModel::Medium: 7706c3fb27SDimitry Andric case CodeModel::Large: 7806c3fb27SDimitry Andric if (!TT.isArch64Bit()) 791db9f3b2SDimitry Andric report_fatal_error("Medium/Large code model requires LA64"); 8006c3fb27SDimitry Andric return *CM; 8106c3fb27SDimitry Andric default: 8206c3fb27SDimitry Andric report_fatal_error( 8306c3fb27SDimitry Andric "Only small, medium and large code models are allowed on LoongArch"); 8406c3fb27SDimitry Andric } 8506c3fb27SDimitry Andric } 8606c3fb27SDimitry Andric 8781ad6265SDimitry Andric LoongArchTargetMachine::LoongArchTargetMachine( 8881ad6265SDimitry Andric const Target &T, const Triple &TT, StringRef CPU, StringRef FS, 89bdd1243dSDimitry Andric const TargetOptions &Options, std::optional<Reloc::Model> RM, 905f757f3fSDimitry Andric std::optional<CodeModel::Model> CM, CodeGenOptLevel OL, bool JIT) 9181ad6265SDimitry Andric : LLVMTargetMachine(T, computeDataLayout(TT), TT, CPU, FS, Options, 9281ad6265SDimitry Andric getEffectiveRelocModel(TT, RM), 9306c3fb27SDimitry Andric getEffectiveLoongArchCodeModel(TT, CM), OL), 9481ad6265SDimitry Andric TLOF(std::make_unique<TargetLoweringObjectFileELF>()) { 9581ad6265SDimitry Andric initAsmInfo(); 9681ad6265SDimitry Andric } 9781ad6265SDimitry Andric 9881ad6265SDimitry Andric LoongArchTargetMachine::~LoongArchTargetMachine() = default; 9981ad6265SDimitry Andric 10081ad6265SDimitry Andric const LoongArchSubtarget * 10181ad6265SDimitry Andric LoongArchTargetMachine::getSubtargetImpl(const Function &F) const { 10281ad6265SDimitry Andric Attribute CPUAttr = F.getFnAttribute("target-cpu"); 10381ad6265SDimitry Andric Attribute TuneAttr = F.getFnAttribute("tune-cpu"); 10481ad6265SDimitry Andric Attribute FSAttr = F.getFnAttribute("target-features"); 10581ad6265SDimitry Andric 10681ad6265SDimitry Andric std::string CPU = 10781ad6265SDimitry Andric CPUAttr.isValid() ? CPUAttr.getValueAsString().str() : TargetCPU; 10881ad6265SDimitry Andric std::string TuneCPU = 10981ad6265SDimitry Andric TuneAttr.isValid() ? TuneAttr.getValueAsString().str() : CPU; 11081ad6265SDimitry Andric std::string FS = 11181ad6265SDimitry Andric FSAttr.isValid() ? FSAttr.getValueAsString().str() : TargetFS; 11281ad6265SDimitry Andric 11381ad6265SDimitry Andric std::string Key = CPU + TuneCPU + FS; 11481ad6265SDimitry Andric auto &I = SubtargetMap[Key]; 11581ad6265SDimitry Andric if (!I) { 11681ad6265SDimitry Andric // This needs to be done before we create a new subtarget since any 11781ad6265SDimitry Andric // creation will depend on the TM and the code generation flags on the 11881ad6265SDimitry Andric // function that reside in TargetOptions. 11981ad6265SDimitry Andric resetTargetOptions(F); 12081ad6265SDimitry Andric auto ABIName = Options.MCOptions.getABIName(); 12181ad6265SDimitry Andric if (const MDString *ModuleTargetABI = dyn_cast_or_null<MDString>( 12281ad6265SDimitry Andric F.getParent()->getModuleFlag("target-abi"))) { 12381ad6265SDimitry Andric auto TargetABI = LoongArchABI::getTargetABI(ABIName); 12481ad6265SDimitry Andric if (TargetABI != LoongArchABI::ABI_Unknown && 12581ad6265SDimitry Andric ModuleTargetABI->getString() != ABIName) { 12681ad6265SDimitry Andric report_fatal_error("-target-abi option != target-abi module flag"); 12781ad6265SDimitry Andric } 12881ad6265SDimitry Andric ABIName = ModuleTargetABI->getString(); 12981ad6265SDimitry Andric } 13081ad6265SDimitry Andric I = std::make_unique<LoongArchSubtarget>(TargetTriple, CPU, TuneCPU, FS, 13181ad6265SDimitry Andric ABIName, *this); 13281ad6265SDimitry Andric } 13381ad6265SDimitry Andric return I.get(); 13481ad6265SDimitry Andric } 13581ad6265SDimitry Andric 136bdd1243dSDimitry Andric MachineFunctionInfo *LoongArchTargetMachine::createMachineFunctionInfo( 137bdd1243dSDimitry Andric BumpPtrAllocator &Allocator, const Function &F, 138bdd1243dSDimitry Andric const TargetSubtargetInfo *STI) const { 139bdd1243dSDimitry Andric return LoongArchMachineFunctionInfo::create<LoongArchMachineFunctionInfo>( 140bdd1243dSDimitry Andric Allocator, F, STI); 141bdd1243dSDimitry Andric } 142bdd1243dSDimitry Andric 14381ad6265SDimitry Andric namespace { 14481ad6265SDimitry Andric class LoongArchPassConfig : public TargetPassConfig { 14581ad6265SDimitry Andric public: 14681ad6265SDimitry Andric LoongArchPassConfig(LoongArchTargetMachine &TM, PassManagerBase &PM) 14781ad6265SDimitry Andric : TargetPassConfig(TM, PM) {} 14881ad6265SDimitry Andric 14981ad6265SDimitry Andric LoongArchTargetMachine &getLoongArchTargetMachine() const { 15081ad6265SDimitry Andric return getTM<LoongArchTargetMachine>(); 15181ad6265SDimitry Andric } 15281ad6265SDimitry Andric 153753f127fSDimitry Andric void addIRPasses() override; 154*0fca6ea1SDimitry Andric void addCodeGenPrepare() override; 15581ad6265SDimitry Andric bool addInstSelector() override; 156bdd1243dSDimitry Andric void addPreEmitPass() override; 157bdd1243dSDimitry Andric void addPreEmitPass2() override; 158*0fca6ea1SDimitry Andric void addMachineSSAOptimization() override; 159bdd1243dSDimitry Andric void addPreRegAlloc() override; 160*0fca6ea1SDimitry Andric bool addRegAssignAndRewriteFast() override; 161*0fca6ea1SDimitry Andric bool addRegAssignAndRewriteOptimized() override; 16281ad6265SDimitry Andric }; 163972a253aSDimitry Andric } // end namespace 16481ad6265SDimitry Andric 16581ad6265SDimitry Andric TargetPassConfig * 16681ad6265SDimitry Andric LoongArchTargetMachine::createPassConfig(PassManagerBase &PM) { 16781ad6265SDimitry Andric return new LoongArchPassConfig(*this, PM); 16881ad6265SDimitry Andric } 16981ad6265SDimitry Andric 170753f127fSDimitry Andric void LoongArchPassConfig::addIRPasses() { 17106c3fb27SDimitry Andric // Run LoopDataPrefetch 17206c3fb27SDimitry Andric // 17306c3fb27SDimitry Andric // Run this before LSR to remove the multiplies involved in computing the 17406c3fb27SDimitry Andric // pointer values N iterations ahead. 1755f757f3fSDimitry Andric if (TM->getOptLevel() != CodeGenOptLevel::None && EnableLoopDataPrefetch) 17606c3fb27SDimitry Andric addPass(createLoopDataPrefetchPass()); 177*0fca6ea1SDimitry Andric addPass(createAtomicExpandLegacyPass()); 178753f127fSDimitry Andric 179753f127fSDimitry Andric TargetPassConfig::addIRPasses(); 180753f127fSDimitry Andric } 181753f127fSDimitry Andric 182*0fca6ea1SDimitry Andric void LoongArchPassConfig::addCodeGenPrepare() { 183*0fca6ea1SDimitry Andric if (getOptLevel() != CodeGenOptLevel::None) 184*0fca6ea1SDimitry Andric addPass(createTypePromotionLegacyPass()); 185*0fca6ea1SDimitry Andric TargetPassConfig::addCodeGenPrepare(); 186*0fca6ea1SDimitry Andric } 187*0fca6ea1SDimitry Andric 18881ad6265SDimitry Andric bool LoongArchPassConfig::addInstSelector() { 18981ad6265SDimitry Andric addPass(createLoongArchISelDag(getLoongArchTargetMachine())); 19081ad6265SDimitry Andric 19181ad6265SDimitry Andric return false; 19281ad6265SDimitry Andric } 193bdd1243dSDimitry Andric 19406c3fb27SDimitry Andric TargetTransformInfo 19506c3fb27SDimitry Andric LoongArchTargetMachine::getTargetTransformInfo(const Function &F) const { 19606c3fb27SDimitry Andric return TargetTransformInfo(LoongArchTTIImpl(this, F)); 19706c3fb27SDimitry Andric } 19806c3fb27SDimitry Andric 199bdd1243dSDimitry Andric void LoongArchPassConfig::addPreEmitPass() { addPass(&BranchRelaxationPassID); } 200bdd1243dSDimitry Andric 201bdd1243dSDimitry Andric void LoongArchPassConfig::addPreEmitPass2() { 202b121cb00SDimitry Andric addPass(createLoongArchExpandPseudoPass()); 203bdd1243dSDimitry Andric // Schedule the expansion of AtomicPseudos at the last possible moment, 204bdd1243dSDimitry Andric // avoiding the possibility for other passes to break the requirements for 205bdd1243dSDimitry Andric // forward progress in the LL/SC block. 206bdd1243dSDimitry Andric addPass(createLoongArchExpandAtomicPseudoPass()); 207bdd1243dSDimitry Andric } 208bdd1243dSDimitry Andric 209*0fca6ea1SDimitry Andric void LoongArchPassConfig::addMachineSSAOptimization() { 210*0fca6ea1SDimitry Andric TargetPassConfig::addMachineSSAOptimization(); 211*0fca6ea1SDimitry Andric 212*0fca6ea1SDimitry Andric if (TM->getTargetTriple().isLoongArch64()) { 213*0fca6ea1SDimitry Andric addPass(createLoongArchOptWInstrsPass()); 214*0fca6ea1SDimitry Andric } 215*0fca6ea1SDimitry Andric } 216*0fca6ea1SDimitry Andric 217bdd1243dSDimitry Andric void LoongArchPassConfig::addPreRegAlloc() { 218bdd1243dSDimitry Andric addPass(createLoongArchPreRAExpandPseudoPass()); 219bdd1243dSDimitry Andric } 220*0fca6ea1SDimitry Andric 221*0fca6ea1SDimitry Andric bool LoongArchPassConfig::addRegAssignAndRewriteFast() { 222*0fca6ea1SDimitry Andric if (TM->getOptLevel() != CodeGenOptLevel::None && 223*0fca6ea1SDimitry Andric EnableLoongArchDeadRegisterElimination) 224*0fca6ea1SDimitry Andric addPass(createLoongArchDeadRegisterDefinitionsPass()); 225*0fca6ea1SDimitry Andric return TargetPassConfig::addRegAssignAndRewriteFast(); 226*0fca6ea1SDimitry Andric } 227*0fca6ea1SDimitry Andric 228*0fca6ea1SDimitry Andric bool LoongArchPassConfig::addRegAssignAndRewriteOptimized() { 229*0fca6ea1SDimitry Andric if (TM->getOptLevel() != CodeGenOptLevel::None && 230*0fca6ea1SDimitry Andric EnableLoongArchDeadRegisterElimination) 231*0fca6ea1SDimitry Andric addPass(createLoongArchDeadRegisterDefinitionsPass()); 232*0fca6ea1SDimitry Andric return TargetPassConfig::addRegAssignAndRewriteOptimized(); 233*0fca6ea1SDimitry Andric } 234