| //===-- LoongArchTargetMachine.cpp - Define TargetMachine for LoongArch ---===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // Implements the info about LoongArch target spec. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "LoongArchTargetMachine.h" | |
| #include "LoongArch.h" | |
| #include "LoongArchMachineFunctionInfo.h" | |
| #include "LoongArchTargetObjectFile.h" | |
| #include "LoongArchTargetTransformInfo.h" | |
| #include "TargetInfo/LoongArchTargetInfo.h" | |
| #include "llvm/Analysis/TargetTransformInfo.h" | |
| #include "llvm/CodeGen/Passes.h" | |
| #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" | |
| #include "llvm/CodeGen/TargetPassConfig.h" | |
| #include "llvm/MC/TargetRegistry.h" | |
| #include "llvm/Support/CodeGen.h" | |
| #include "llvm/Support/Compiler.h" | |
| #include "llvm/Transforms/Scalar.h" | |
| #include <optional> | |
| using namespace llvm; | |
| #define DEBUG_TYPE "loongarch" | |
| extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void | |
| LLVMInitializeLoongArchTarget() { | |
| // Register the target. | |
| RegisterTargetMachine<LoongArchTargetMachine> X(getTheLoongArch32Target()); | |
| RegisterTargetMachine<LoongArchTargetMachine> Y(getTheLoongArch64Target()); | |
| auto *PR = PassRegistry::getPassRegistry(); | |
| initializeLoongArchDeadRegisterDefinitionsPass(*PR); | |
| initializeLoongArchMemoryBarrierOptPass(*PR); | |
| initializeLoongArchMergeBaseOffsetOptPass(*PR); | |
| initializeLoongArchOptWInstrsPass(*PR); | |
| initializeLoongArchPreRAExpandPseudoPass(*PR); | |
| initializeLoongArchExpandPseudoPass(*PR); | |
| initializeLoongArchDAGToDAGISelLegacyPass(*PR); | |
| initializeLoongArchExpandAtomicPseudoPass(*PR); | |
| initializeLoongArchLateBranchOptPass(*PR); | |
| } | |
| static cl::opt<bool> EnableLoongArchDeadRegisterElimination( | |
| "loongarch-enable-dead-defs", cl::Hidden, | |
| cl::desc("Enable the pass that removes dead" | |
| " definitons and replaces stores to" | |
| " them with stores to r0"), | |
| cl::init(true)); | |
| static cl::opt<bool> | |
| EnableLoopDataPrefetch("loongarch-enable-loop-data-prefetch", cl::Hidden, | |
| cl::desc("Enable the loop data prefetch pass"), | |
| cl::init(false)); | |
| static cl::opt<bool> | |
| EnableMergeBaseOffset("loongarch-enable-merge-offset", | |
| cl::desc("Enable the merge base offset pass"), | |
| cl::init(true), cl::Hidden); | |
| static cl::opt<bool> | |
| EnableSinkFold("loongarch-enable-sink-fold", | |
| cl::desc("Enable sinking and folding of instruction copies"), | |
| cl::init(true), cl::Hidden); | |
| static cl::opt<bool> | |
| EnableMachineCombiner("loongarch-enable-machine-combiner", | |
| cl::desc("Enable the machine combiner pass"), | |
| cl::init(true), cl::Hidden); | |
| static Reloc::Model getEffectiveRelocModel(std::optional<Reloc::Model> RM) { | |
| return RM.value_or(Reloc::Static); | |
| } | |
| static CodeModel::Model | |
| getEffectiveLoongArchCodeModel(const Triple &TT, | |
| std::optional<CodeModel::Model> CM) { | |
| if (!CM) | |
| return TT.isArch64Bit() ? CodeModel::Medium : CodeModel::Small; | |
| switch (*CM) { | |
| case CodeModel::Small: | |
| case CodeModel::Medium: | |
| return *CM; | |
| case CodeModel::Large: | |
| if (!TT.isArch64Bit()) | |
| report_fatal_error("Large code model requires LA64"); | |
| return *CM; | |
| default: | |
| report_fatal_error( | |
| "Only small, medium and large code models are allowed on LoongArch"); | |
| } | |
| } | |
| LoongArchTargetMachine::LoongArchTargetMachine( | |
| const Target &T, const Triple &TT, StringRef CPU, StringRef FS, | |
| const TargetOptions &Options, std::optional<Reloc::Model> RM, | |
| std::optional<CodeModel::Model> CM, CodeGenOptLevel OL, bool JIT) | |
| : CodeGenTargetMachineImpl(T, TT, CPU, FS, Options, | |
| getEffectiveRelocModel(RM), | |
| getEffectiveLoongArchCodeModel(TT, CM), OL), | |
| TLOF(std::make_unique<LoongArchELFTargetObjectFile>()) { | |
| initAsmInfo(); | |
| } | |
| LoongArchTargetMachine::~LoongArchTargetMachine() = default; | |
| const LoongArchSubtarget * | |
| LoongArchTargetMachine::getSubtargetImpl(const Function &F) const { | |
| Attribute CPUAttr = F.getFnAttribute("target-cpu"); | |
| Attribute TuneAttr = F.getFnAttribute("tune-cpu"); | |
| Attribute FSAttr = F.getFnAttribute("target-features"); | |
| std::string CPU = | |
| CPUAttr.isValid() ? CPUAttr.getValueAsString().str() : TargetCPU; | |
| std::string TuneCPU = | |
| TuneAttr.isValid() ? TuneAttr.getValueAsString().str() : CPU; | |
| std::string FS = | |
| FSAttr.isValid() ? FSAttr.getValueAsString().str() : TargetFS; | |
| std::string Key = CPU + TuneCPU + FS; | |
| auto &I = SubtargetMap[Key]; | |
| if (!I) { | |
| StringRef ABIName = getTargetABIName(*F.getParent()); | |
| I = std::make_unique<LoongArchSubtarget>(TargetTriple, CPU, TuneCPU, FS, | |
| ABIName, *this); | |
| } | |
| return I.get(); | |
| } | |
| MachineFunctionInfo *LoongArchTargetMachine::createMachineFunctionInfo( | |
| BumpPtrAllocator &Allocator, const Function &F, | |
| const TargetSubtargetInfo *STI) const { | |
| return LoongArchMachineFunctionInfo::create<LoongArchMachineFunctionInfo>( | |
| Allocator, F, STI); | |
| } | |
| namespace { | |
| class LoongArchPassConfig : public TargetPassConfig { | |
| public: | |
| LoongArchPassConfig(LoongArchTargetMachine &TM, PassManagerBase &PM) | |
| : TargetPassConfig(TM, PM) { | |
| setEnableSinkAndFold(EnableSinkFold); | |
| } | |
| LoongArchTargetMachine &getLoongArchTargetMachine() const { | |
| return getTM<LoongArchTargetMachine>(); | |
| } | |
| void addIRPasses() override; | |
| void addCodeGenPrepare() override; | |
| bool addInstSelector() override; | |
| void addPreEmitPass() override; | |
| void addPreEmitPass2() override; | |
| void addMachineSSAOptimization() override; | |
| void addPreRegAlloc() override; | |
| bool addILPOpts() override; | |
| bool addRegAssignAndRewriteFast() override; | |
| bool addRegAssignAndRewriteOptimized() override; | |
| void addMachineLateOptimization() override; | |
| }; | |
| } // end namespace | |
| TargetPassConfig * | |
| LoongArchTargetMachine::createPassConfig(PassManagerBase &PM) { | |
| return new LoongArchPassConfig(*this, PM); | |
| } | |
| void LoongArchPassConfig::addIRPasses() { | |
| // Run LoopDataPrefetch | |
| // | |
| // Run this before LSR to remove the multiplies involved in computing the | |
| // pointer values N iterations ahead. | |
| if (TM->getOptLevel() != CodeGenOptLevel::None && EnableLoopDataPrefetch) | |
| addPass(createLoopDataPrefetchPass()); | |
| addPass(createAtomicExpandLegacyPass()); | |
| TargetPassConfig::addIRPasses(); | |
| } | |
| void LoongArchPassConfig::addCodeGenPrepare() { | |
| if (getOptLevel() != CodeGenOptLevel::None) | |
| addPass(createTypePromotionLegacyPass()); | |
| TargetPassConfig::addCodeGenPrepare(); | |
| } | |
| bool LoongArchPassConfig::addInstSelector() { | |
| addPass(createLoongArchISelDag(getLoongArchTargetMachine(), getOptLevel())); | |
| return false; | |
| } | |
| TargetTransformInfo | |
| LoongArchTargetMachine::getTargetTransformInfo(const Function &F) const { | |
| return TargetTransformInfo(std::make_unique<LoongArchTTIImpl>(this, F)); | |
| } | |
| void LoongArchPassConfig::addPreEmitPass() { addPass(&BranchRelaxationPassID); } | |
| void LoongArchPassConfig::addPreEmitPass2() { | |
| addPass(createLoongArchExpandPseudoPass()); | |
| // Schedule the expansion of AtomicPseudos at the last possible moment, | |
| // avoiding the possibility for other passes to break the requirements for | |
| // forward progress in the LL/SC block. | |
| addPass(createLoongArchExpandAtomicPseudoPass()); | |
| if (TM->getOptLevel() != CodeGenOptLevel::None) | |
| addPass(createLoongArchMemoryBarrierOptPass()); | |
| } | |
| void LoongArchPassConfig::addMachineSSAOptimization() { | |
| TargetPassConfig::addMachineSSAOptimization(); | |
| if (TM->getTargetTriple().isLoongArch64()) { | |
| addPass(createLoongArchOptWInstrsPass()); | |
| } | |
| } | |
| void LoongArchPassConfig::addPreRegAlloc() { | |
| addPass(createLoongArchPreRAExpandPseudoPass()); | |
| if (TM->getOptLevel() != CodeGenOptLevel::None && EnableMergeBaseOffset) | |
| addPass(createLoongArchMergeBaseOffsetOptPass()); | |
| } | |
| bool LoongArchPassConfig::addILPOpts() { | |
| if (EnableMachineCombiner) | |
| addPass(&MachineCombinerID); | |
| return true; | |
| } | |
| bool LoongArchPassConfig::addRegAssignAndRewriteFast() { | |
| if (TM->getOptLevel() != CodeGenOptLevel::None && | |
| EnableLoongArchDeadRegisterElimination) | |
| addPass(createLoongArchDeadRegisterDefinitionsPass()); | |
| return TargetPassConfig::addRegAssignAndRewriteFast(); | |
| } | |
| bool LoongArchPassConfig::addRegAssignAndRewriteOptimized() { | |
| if (TM->getOptLevel() != CodeGenOptLevel::None && | |
| EnableLoongArchDeadRegisterElimination) | |
| addPass(createLoongArchDeadRegisterDefinitionsPass()); | |
| return TargetPassConfig::addRegAssignAndRewriteOptimized(); | |
| } | |
| void LoongArchPassConfig::addMachineLateOptimization() { | |
| if (TM->getOptLevel() != CodeGenOptLevel::None) | |
| addPass(createLoongArchLateBranchOptPass()); | |
| TargetPassConfig::addMachineLateOptimization(); | |
| } |