blob: 46e4a06f6bc0134773ef9353e77ab0fc15b3c858 [file] [log] [blame]
//===-- 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/Transforms/Scalar.h"
#include <optional>
using namespace llvm;
#define DEBUG_TYPE "loongarch"
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeLoongArchTarget() {
// Register the target.
RegisterTargetMachine<LoongArchTargetMachine> X(getTheLoongArch32Target());
RegisterTargetMachine<LoongArchTargetMachine> Y(getTheLoongArch64Target());
auto *PR = PassRegistry::getPassRegistry();
initializeLoongArchPreRAExpandPseudoPass(*PR);
initializeLoongArchDAGToDAGISelPass(*PR);
}
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-n64-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 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, CodeGenOpt::Level OL, bool JIT)
: LLVMTargetMachine(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;
bool addInstSelector() override;
void addPreEmitPass() override;
void addPreEmitPass2() override;
void addPreRegAlloc() 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() != CodeGenOpt::None && EnableLoopDataPrefetch)
addPass(createLoopDataPrefetchPass());
addPass(createAtomicExpandPass());
TargetPassConfig::addIRPasses();
}
bool LoongArchPassConfig::addInstSelector() {
addPass(createLoongArchISelDag(getLoongArchTargetMachine()));
return false;
}
TargetTransformInfo
LoongArchTargetMachine::getTargetTransformInfo(const Function &F) const {
return TargetTransformInfo(LoongArchTTIImpl(this, F));
}
void LoongArchPassConfig::addPreEmitPass() { addPass(&BranchRelaxationPassID); }
void LoongArchPassConfig::addPreEmitPass2() {
// 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::addPreRegAlloc() {
addPass(createLoongArchPreRAExpandPseudoPass());
}