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