
## Purpose This patch is one in a series of code-mods that annotate LLVM’s public interface for export. This patch annotates the `llvm/Target` library. These annotations currently have no meaningful impact on the LLVM build; however, they are a prerequisite to support an LLVM Windows DLL (shared library) build. ## Background This effort is tracked in #109483. Additional context is provided in [this discourse](https://discourse.llvm.org/t/psa-annotating-llvm-public-interface/85307), and documentation for `LLVM_ABI` and related annotations is found in the LLVM repo [here](https://github.com/llvm/llvm-project/blob/main/llvm/docs/InterfaceExportAnnotations.rst). A sub-set of these changes were generated automatically using the [Interface Definition Scanner (IDS)](https://github.com/compnerd/ids) tool, followed formatting with `git clang-format`. The bulk of this change is manual additions of `LLVM_ABI` to `LLVMInitializeX` functions defined in .cpp files under llvm/lib/Target. Adding `LLVM_ABI` to the function implementation is required here because they do not `#include "llvm/Support/TargetSelect.h"`, which contains the declarations for this functions and was already updated with `LLVM_ABI` in a previous patch. I considered patching these files with `#include "llvm/Support/TargetSelect.h"` instead, but since TargetSelect.h is a large file with a bunch of preprocessor x-macro stuff in it I was concerned it would unnecessarily impact compile times. In addition, a number of unit tests under llvm/unittests/Target required additional dependencies to make them build correctly against the LLVM DLL on Windows using MSVC. ## Validation Local builds and tests to validate cross-platform compatibility. This included llvm, clang, and lldb on the following configurations: - Windows with MSVC - Windows with Clang - Linux with GCC - Linux with Clang - Darwin with Clang
241 lines
8.5 KiB
C++
241 lines
8.5 KiB
C++
//===-- 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 "LoongArchTargetTransformInfo.h"
|
|
#include "MCTargetDesc/LoongArchBaseInfo.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);
|
|
initializeLoongArchMergeBaseOffsetOptPass(*PR);
|
|
initializeLoongArchOptWInstrsPass(*PR);
|
|
initializeLoongArchPreRAExpandPseudoPass(*PR);
|
|
initializeLoongArchExpandPseudoPass(*PR);
|
|
initializeLoongArchDAGToDAGISelLegacyPass(*PR);
|
|
initializeLoongArchExpandAtomicPseudoPass(*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 std::string computeDataLayout(const Triple &TT) {
|
|
if (TT.isArch64Bit())
|
|
return "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128";
|
|
assert(TT.isArch32Bit() && "only LA32 and LA64 are currently supported");
|
|
return "e-m:e-p:32:32-i64:64-n32-S128";
|
|
}
|
|
|
|
static Reloc::Model getEffectiveRelocModel(const Triple &TT,
|
|
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:
|
|
return *CM;
|
|
case CodeModel::Medium:
|
|
case CodeModel::Large:
|
|
if (!TT.isArch64Bit())
|
|
report_fatal_error("Medium/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, computeDataLayout(TT), TT, CPU, FS, Options,
|
|
getEffectiveRelocModel(TT, RM),
|
|
getEffectiveLoongArchCodeModel(TT, CM), OL),
|
|
TLOF(std::make_unique<TargetLoweringObjectFileELF>()) {
|
|
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) {
|
|
// This needs to be done before we create a new subtarget since any
|
|
// creation will depend on the TM and the code generation flags on the
|
|
// function that reside in TargetOptions.
|
|
resetTargetOptions(F);
|
|
auto ABIName = Options.MCOptions.getABIName();
|
|
if (const MDString *ModuleTargetABI = dyn_cast_or_null<MDString>(
|
|
F.getParent()->getModuleFlag("target-abi"))) {
|
|
auto TargetABI = LoongArchABI::getTargetABI(ABIName);
|
|
if (TargetABI != LoongArchABI::ABI_Unknown &&
|
|
ModuleTargetABI->getString() != ABIName) {
|
|
report_fatal_error("-target-abi option != target-abi module flag");
|
|
}
|
|
ABIName = ModuleTargetABI->getString();
|
|
}
|
|
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) {}
|
|
|
|
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 addRegAssignAndRewriteFast() override;
|
|
bool addRegAssignAndRewriteOptimized() 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());
|
|
}
|
|
|
|
void LoongArchPassConfig::addMachineSSAOptimization() {
|
|
TargetPassConfig::addMachineSSAOptimization();
|
|
|
|
if (TM->getTargetTriple().isLoongArch64()) {
|
|
addPass(createLoongArchOptWInstrsPass());
|
|
}
|
|
}
|
|
|
|
void LoongArchPassConfig::addPreRegAlloc() {
|
|
addPass(createLoongArchPreRAExpandPseudoPass());
|
|
if (TM->getOptLevel() != CodeGenOptLevel::None)
|
|
addPass(createLoongArchMergeBaseOffsetOptPass());
|
|
}
|
|
|
|
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();
|
|
}
|