
Integrate the BranchRelaxation pass to help with relaxing out-of-range conditional branches. This is mostly of concern for SPARCv9, which uses conditional branches with much smaller range than its v8 counterparts. (Some large autogenerated code, such as the ones generated by TableGen, already hits this limitation when building in Release) Reviewed By: arsenm Differential Revision: https://reviews.llvm.org/D142458
235 lines
8.5 KiB
C++
235 lines
8.5 KiB
C++
//===-- SparcTargetMachine.cpp - Define TargetMachine for Sparc -----------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "SparcTargetMachine.h"
|
|
#include "LeonPasses.h"
|
|
#include "Sparc.h"
|
|
#include "SparcMachineFunctionInfo.h"
|
|
#include "SparcTargetObjectFile.h"
|
|
#include "TargetInfo/SparcTargetInfo.h"
|
|
#include "llvm/CodeGen/Passes.h"
|
|
#include "llvm/CodeGen/TargetPassConfig.h"
|
|
#include "llvm/MC/TargetRegistry.h"
|
|
#include <optional>
|
|
using namespace llvm;
|
|
|
|
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSparcTarget() {
|
|
// Register the target.
|
|
RegisterTargetMachine<SparcV8TargetMachine> X(getTheSparcTarget());
|
|
RegisterTargetMachine<SparcV9TargetMachine> Y(getTheSparcV9Target());
|
|
RegisterTargetMachine<SparcelTargetMachine> Z(getTheSparcelTarget());
|
|
|
|
PassRegistry &PR = *PassRegistry::getPassRegistry();
|
|
initializeSparcDAGToDAGISelPass(PR);
|
|
}
|
|
|
|
static cl::opt<bool>
|
|
BranchRelaxation("sparc-enable-branch-relax", cl::Hidden, cl::init(true),
|
|
cl::desc("Relax out of range conditional branches"));
|
|
|
|
static std::string computeDataLayout(const Triple &T, bool is64Bit) {
|
|
// Sparc is typically big endian, but some are little.
|
|
std::string Ret = T.getArch() == Triple::sparcel ? "e" : "E";
|
|
Ret += "-m:e";
|
|
|
|
// Some ABIs have 32bit pointers.
|
|
if (!is64Bit)
|
|
Ret += "-p:32:32";
|
|
|
|
// Alignments for 64 bit integers.
|
|
Ret += "-i64:64";
|
|
|
|
// On SparcV9 128 floats are aligned to 128 bits, on others only to 64.
|
|
// On SparcV9 registers can hold 64 or 32 bits, on others only 32.
|
|
if (is64Bit)
|
|
Ret += "-n32:64";
|
|
else
|
|
Ret += "-f128:64-n32";
|
|
|
|
if (is64Bit)
|
|
Ret += "-S128";
|
|
else
|
|
Ret += "-S64";
|
|
|
|
return Ret;
|
|
}
|
|
|
|
static Reloc::Model getEffectiveRelocModel(std::optional<Reloc::Model> RM) {
|
|
return RM.value_or(Reloc::Static);
|
|
}
|
|
|
|
// Code models. Some only make sense for 64-bit code.
|
|
//
|
|
// SunCC Reloc CodeModel Constraints
|
|
// abs32 Static Small text+data+bss linked below 2^32 bytes
|
|
// abs44 Static Medium text+data+bss linked below 2^44 bytes
|
|
// abs64 Static Large text smaller than 2^31 bytes
|
|
// pic13 PIC_ Small GOT < 2^13 bytes
|
|
// pic32 PIC_ Medium GOT < 2^32 bytes
|
|
//
|
|
// All code models require that the text segment is smaller than 2GB.
|
|
static CodeModel::Model
|
|
getEffectiveSparcCodeModel(std::optional<CodeModel::Model> CM, Reloc::Model RM,
|
|
bool Is64Bit, bool JIT) {
|
|
if (CM) {
|
|
if (*CM == CodeModel::Tiny)
|
|
report_fatal_error("Target does not support the tiny CodeModel", false);
|
|
if (*CM == CodeModel::Kernel)
|
|
report_fatal_error("Target does not support the kernel CodeModel", false);
|
|
return *CM;
|
|
}
|
|
if (Is64Bit) {
|
|
if (JIT)
|
|
return CodeModel::Large;
|
|
return RM == Reloc::PIC_ ? CodeModel::Small : CodeModel::Medium;
|
|
}
|
|
return CodeModel::Small;
|
|
}
|
|
|
|
/// Create an ILP32 architecture model
|
|
SparcTargetMachine::SparcTargetMachine(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,
|
|
bool is64bit)
|
|
: LLVMTargetMachine(T, computeDataLayout(TT, is64bit), TT, CPU, FS, Options,
|
|
getEffectiveRelocModel(RM),
|
|
getEffectiveSparcCodeModel(
|
|
CM, getEffectiveRelocModel(RM), is64bit, JIT),
|
|
OL),
|
|
TLOF(std::make_unique<SparcELFTargetObjectFile>()),
|
|
Subtarget(TT, std::string(CPU), std::string(FS), *this, is64bit),
|
|
is64Bit(is64bit) {
|
|
initAsmInfo();
|
|
}
|
|
|
|
SparcTargetMachine::~SparcTargetMachine() = default;
|
|
|
|
const SparcSubtarget *
|
|
SparcTargetMachine::getSubtargetImpl(const Function &F) const {
|
|
Attribute CPUAttr = F.getFnAttribute("target-cpu");
|
|
Attribute FSAttr = F.getFnAttribute("target-features");
|
|
|
|
std::string CPU =
|
|
CPUAttr.isValid() ? CPUAttr.getValueAsString().str() : TargetCPU;
|
|
std::string FS =
|
|
FSAttr.isValid() ? FSAttr.getValueAsString().str() : TargetFS;
|
|
|
|
// FIXME: This is related to the code below to reset the target options,
|
|
// we need to know whether or not the soft float flag is set on the
|
|
// function, so we can enable it as a subtarget feature.
|
|
bool softFloat = F.getFnAttribute("use-soft-float").getValueAsBool();
|
|
|
|
if (softFloat)
|
|
FS += FS.empty() ? "+soft-float" : ",+soft-float";
|
|
|
|
auto &I = SubtargetMap[CPU + FS];
|
|
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);
|
|
I = std::make_unique<SparcSubtarget>(TargetTriple, CPU, FS, *this,
|
|
this->is64Bit);
|
|
}
|
|
return I.get();
|
|
}
|
|
|
|
MachineFunctionInfo *SparcTargetMachine::createMachineFunctionInfo(
|
|
BumpPtrAllocator &Allocator, const Function &F,
|
|
const TargetSubtargetInfo *STI) const {
|
|
return SparcMachineFunctionInfo::create<SparcMachineFunctionInfo>(Allocator,
|
|
F, STI);
|
|
}
|
|
|
|
namespace {
|
|
/// Sparc Code Generator Pass Configuration Options.
|
|
class SparcPassConfig : public TargetPassConfig {
|
|
public:
|
|
SparcPassConfig(SparcTargetMachine &TM, PassManagerBase &PM)
|
|
: TargetPassConfig(TM, PM) {}
|
|
|
|
SparcTargetMachine &getSparcTargetMachine() const {
|
|
return getTM<SparcTargetMachine>();
|
|
}
|
|
|
|
void addIRPasses() override;
|
|
bool addInstSelector() override;
|
|
void addPreEmitPass() override;
|
|
};
|
|
} // namespace
|
|
|
|
TargetPassConfig *SparcTargetMachine::createPassConfig(PassManagerBase &PM) {
|
|
return new SparcPassConfig(*this, PM);
|
|
}
|
|
|
|
void SparcPassConfig::addIRPasses() {
|
|
addPass(createAtomicExpandPass());
|
|
|
|
TargetPassConfig::addIRPasses();
|
|
}
|
|
|
|
bool SparcPassConfig::addInstSelector() {
|
|
addPass(createSparcISelDag(getSparcTargetMachine()));
|
|
return false;
|
|
}
|
|
|
|
void SparcPassConfig::addPreEmitPass(){
|
|
if (BranchRelaxation)
|
|
addPass(&BranchRelaxationPassID);
|
|
|
|
addPass(createSparcDelaySlotFillerPass());
|
|
|
|
if (this->getSparcTargetMachine().getSubtargetImpl()->insertNOPLoad())
|
|
{
|
|
addPass(new InsertNOPLoad());
|
|
}
|
|
if (this->getSparcTargetMachine().getSubtargetImpl()->detectRoundChange()) {
|
|
addPass(new DetectRoundChange());
|
|
}
|
|
if (this->getSparcTargetMachine().getSubtargetImpl()->fixAllFDIVSQRT())
|
|
{
|
|
addPass(new FixAllFDIVSQRT());
|
|
}
|
|
}
|
|
|
|
void SparcV8TargetMachine::anchor() { }
|
|
|
|
SparcV8TargetMachine::SparcV8TargetMachine(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)
|
|
: SparcTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, JIT, false) {}
|
|
|
|
void SparcV9TargetMachine::anchor() { }
|
|
|
|
SparcV9TargetMachine::SparcV9TargetMachine(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)
|
|
: SparcTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, JIT, true) {}
|
|
|
|
void SparcelTargetMachine::anchor() {}
|
|
|
|
SparcelTargetMachine::SparcelTargetMachine(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)
|
|
: SparcTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, JIT, false) {}
|