10b57cec5SDimitry Andric //===-- SparcTargetMachine.cpp - Define TargetMachine for Sparc -----------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric //
100b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
110b57cec5SDimitry Andric
120b57cec5SDimitry Andric #include "SparcTargetMachine.h"
130b57cec5SDimitry Andric #include "LeonPasses.h"
140b57cec5SDimitry Andric #include "Sparc.h"
15bdd1243dSDimitry Andric #include "SparcMachineFunctionInfo.h"
160b57cec5SDimitry Andric #include "SparcTargetObjectFile.h"
170b57cec5SDimitry Andric #include "TargetInfo/SparcTargetInfo.h"
180b57cec5SDimitry Andric #include "llvm/CodeGen/Passes.h"
190b57cec5SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h"
20349cc55cSDimitry Andric #include "llvm/MC/TargetRegistry.h"
21bdd1243dSDimitry Andric #include <optional>
220b57cec5SDimitry Andric using namespace llvm;
230b57cec5SDimitry Andric
LLVMInitializeSparcTarget()24480093f4SDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSparcTarget() {
250b57cec5SDimitry Andric // Register the target.
260b57cec5SDimitry Andric RegisterTargetMachine<SparcV8TargetMachine> X(getTheSparcTarget());
270b57cec5SDimitry Andric RegisterTargetMachine<SparcV9TargetMachine> Y(getTheSparcV9Target());
280b57cec5SDimitry Andric RegisterTargetMachine<SparcelTargetMachine> Z(getTheSparcelTarget());
29bdd1243dSDimitry Andric
30bdd1243dSDimitry Andric PassRegistry &PR = *PassRegistry::getPassRegistry();
31*0fca6ea1SDimitry Andric initializeSparcDAGToDAGISelLegacyPass(PR);
320b57cec5SDimitry Andric }
330b57cec5SDimitry Andric
341ac55f4cSDimitry Andric static cl::opt<bool>
351ac55f4cSDimitry Andric BranchRelaxation("sparc-enable-branch-relax", cl::Hidden, cl::init(true),
361ac55f4cSDimitry Andric cl::desc("Relax out of range conditional branches"));
371ac55f4cSDimitry Andric
computeDataLayout(const Triple & T,bool is64Bit)380b57cec5SDimitry Andric static std::string computeDataLayout(const Triple &T, bool is64Bit) {
390b57cec5SDimitry Andric // Sparc is typically big endian, but some are little.
400b57cec5SDimitry Andric std::string Ret = T.getArch() == Triple::sparcel ? "e" : "E";
410b57cec5SDimitry Andric Ret += "-m:e";
420b57cec5SDimitry Andric
430b57cec5SDimitry Andric // Some ABIs have 32bit pointers.
440b57cec5SDimitry Andric if (!is64Bit)
450b57cec5SDimitry Andric Ret += "-p:32:32";
460b57cec5SDimitry Andric
470b57cec5SDimitry Andric // Alignments for 64 bit integers.
480b57cec5SDimitry Andric Ret += "-i64:64";
490b57cec5SDimitry Andric
500b57cec5SDimitry Andric // On SparcV9 128 floats are aligned to 128 bits, on others only to 64.
510b57cec5SDimitry Andric // On SparcV9 registers can hold 64 or 32 bits, on others only 32.
520b57cec5SDimitry Andric if (is64Bit)
530b57cec5SDimitry Andric Ret += "-n32:64";
540b57cec5SDimitry Andric else
550b57cec5SDimitry Andric Ret += "-f128:64-n32";
560b57cec5SDimitry Andric
570b57cec5SDimitry Andric if (is64Bit)
580b57cec5SDimitry Andric Ret += "-S128";
590b57cec5SDimitry Andric else
600b57cec5SDimitry Andric Ret += "-S64";
610b57cec5SDimitry Andric
620b57cec5SDimitry Andric return Ret;
630b57cec5SDimitry Andric }
640b57cec5SDimitry Andric
getEffectiveRelocModel(std::optional<Reloc::Model> RM)65bdd1243dSDimitry Andric static Reloc::Model getEffectiveRelocModel(std::optional<Reloc::Model> RM) {
6681ad6265SDimitry Andric return RM.value_or(Reloc::Static);
670b57cec5SDimitry Andric }
680b57cec5SDimitry Andric
690b57cec5SDimitry Andric // Code models. Some only make sense for 64-bit code.
700b57cec5SDimitry Andric //
710b57cec5SDimitry Andric // SunCC Reloc CodeModel Constraints
720b57cec5SDimitry Andric // abs32 Static Small text+data+bss linked below 2^32 bytes
730b57cec5SDimitry Andric // abs44 Static Medium text+data+bss linked below 2^44 bytes
740b57cec5SDimitry Andric // abs64 Static Large text smaller than 2^31 bytes
750b57cec5SDimitry Andric // pic13 PIC_ Small GOT < 2^13 bytes
760b57cec5SDimitry Andric // pic32 PIC_ Medium GOT < 2^32 bytes
770b57cec5SDimitry Andric //
780b57cec5SDimitry Andric // All code models require that the text segment is smaller than 2GB.
790b57cec5SDimitry Andric static CodeModel::Model
getEffectiveSparcCodeModel(std::optional<CodeModel::Model> CM,Reloc::Model RM,bool Is64Bit,bool JIT)80bdd1243dSDimitry Andric getEffectiveSparcCodeModel(std::optional<CodeModel::Model> CM, Reloc::Model RM,
810b57cec5SDimitry Andric bool Is64Bit, bool JIT) {
820b57cec5SDimitry Andric if (CM) {
830b57cec5SDimitry Andric if (*CM == CodeModel::Tiny)
840b57cec5SDimitry Andric report_fatal_error("Target does not support the tiny CodeModel", false);
850b57cec5SDimitry Andric if (*CM == CodeModel::Kernel)
860b57cec5SDimitry Andric report_fatal_error("Target does not support the kernel CodeModel", false);
870b57cec5SDimitry Andric return *CM;
880b57cec5SDimitry Andric }
890b57cec5SDimitry Andric if (Is64Bit) {
900b57cec5SDimitry Andric if (JIT)
910b57cec5SDimitry Andric return CodeModel::Large;
920b57cec5SDimitry Andric return RM == Reloc::PIC_ ? CodeModel::Small : CodeModel::Medium;
930b57cec5SDimitry Andric }
940b57cec5SDimitry Andric return CodeModel::Small;
950b57cec5SDimitry Andric }
960b57cec5SDimitry Andric
970b57cec5SDimitry Andric /// Create an ILP32 architecture model
SparcTargetMachine(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,bool is64bit)98bdd1243dSDimitry Andric SparcTargetMachine::SparcTargetMachine(const Target &T, const Triple &TT,
99bdd1243dSDimitry Andric StringRef CPU, StringRef FS,
100bdd1243dSDimitry Andric const TargetOptions &Options,
101bdd1243dSDimitry Andric std::optional<Reloc::Model> RM,
102bdd1243dSDimitry Andric std::optional<CodeModel::Model> CM,
1035f757f3fSDimitry Andric CodeGenOptLevel OL, bool JIT,
104bdd1243dSDimitry Andric bool is64bit)
1050b57cec5SDimitry Andric : LLVMTargetMachine(T, computeDataLayout(TT, is64bit), TT, CPU, FS, Options,
1060b57cec5SDimitry Andric getEffectiveRelocModel(RM),
1070b57cec5SDimitry Andric getEffectiveSparcCodeModel(
1080b57cec5SDimitry Andric CM, getEffectiveRelocModel(RM), is64bit, JIT),
1090b57cec5SDimitry Andric OL),
1105f757f3fSDimitry Andric TLOF(std::make_unique<SparcELFTargetObjectFile>()), is64Bit(is64bit) {
1110b57cec5SDimitry Andric initAsmInfo();
1120b57cec5SDimitry Andric }
1130b57cec5SDimitry Andric
11481ad6265SDimitry Andric SparcTargetMachine::~SparcTargetMachine() = default;
1150b57cec5SDimitry Andric
1160b57cec5SDimitry Andric const SparcSubtarget *
getSubtargetImpl(const Function & F) const1170b57cec5SDimitry Andric SparcTargetMachine::getSubtargetImpl(const Function &F) const {
1180b57cec5SDimitry Andric Attribute CPUAttr = F.getFnAttribute("target-cpu");
1197a6dacacSDimitry Andric Attribute TuneAttr = F.getFnAttribute("tune-cpu");
1200b57cec5SDimitry Andric Attribute FSAttr = F.getFnAttribute("target-features");
1210b57cec5SDimitry Andric
122e8d8bef9SDimitry Andric std::string CPU =
123e8d8bef9SDimitry Andric CPUAttr.isValid() ? CPUAttr.getValueAsString().str() : TargetCPU;
1247a6dacacSDimitry Andric std::string TuneCPU =
1257a6dacacSDimitry Andric TuneAttr.isValid() ? TuneAttr.getValueAsString().str() : CPU;
126e8d8bef9SDimitry Andric std::string FS =
127e8d8bef9SDimitry Andric FSAttr.isValid() ? FSAttr.getValueAsString().str() : TargetFS;
1280b57cec5SDimitry Andric
1290b57cec5SDimitry Andric // FIXME: This is related to the code below to reset the target options,
1300b57cec5SDimitry Andric // we need to know whether or not the soft float flag is set on the
1310b57cec5SDimitry Andric // function, so we can enable it as a subtarget feature.
132fe6060f1SDimitry Andric bool softFloat = F.getFnAttribute("use-soft-float").getValueAsBool();
1330b57cec5SDimitry Andric
1340b57cec5SDimitry Andric if (softFloat)
1350b57cec5SDimitry Andric FS += FS.empty() ? "+soft-float" : ",+soft-float";
1360b57cec5SDimitry Andric
1370b57cec5SDimitry Andric auto &I = SubtargetMap[CPU + FS];
1380b57cec5SDimitry Andric if (!I) {
1390b57cec5SDimitry Andric // This needs to be done before we create a new subtarget since any
1400b57cec5SDimitry Andric // creation will depend on the TM and the code generation flags on the
1410b57cec5SDimitry Andric // function that reside in TargetOptions.
1420b57cec5SDimitry Andric resetTargetOptions(F);
1437a6dacacSDimitry Andric I = std::make_unique<SparcSubtarget>(CPU, TuneCPU, FS, *this,
1440b57cec5SDimitry Andric this->is64Bit);
1450b57cec5SDimitry Andric }
1460b57cec5SDimitry Andric return I.get();
1470b57cec5SDimitry Andric }
1480b57cec5SDimitry Andric
createMachineFunctionInfo(BumpPtrAllocator & Allocator,const Function & F,const TargetSubtargetInfo * STI) const149bdd1243dSDimitry Andric MachineFunctionInfo *SparcTargetMachine::createMachineFunctionInfo(
150bdd1243dSDimitry Andric BumpPtrAllocator &Allocator, const Function &F,
151bdd1243dSDimitry Andric const TargetSubtargetInfo *STI) const {
152bdd1243dSDimitry Andric return SparcMachineFunctionInfo::create<SparcMachineFunctionInfo>(Allocator,
153bdd1243dSDimitry Andric F, STI);
154bdd1243dSDimitry Andric }
155bdd1243dSDimitry Andric
1560b57cec5SDimitry Andric namespace {
1570b57cec5SDimitry Andric /// Sparc Code Generator Pass Configuration Options.
1580b57cec5SDimitry Andric class SparcPassConfig : public TargetPassConfig {
1590b57cec5SDimitry Andric public:
SparcPassConfig(SparcTargetMachine & TM,PassManagerBase & PM)1600b57cec5SDimitry Andric SparcPassConfig(SparcTargetMachine &TM, PassManagerBase &PM)
1610b57cec5SDimitry Andric : TargetPassConfig(TM, PM) {}
1620b57cec5SDimitry Andric
getSparcTargetMachine() const1630b57cec5SDimitry Andric SparcTargetMachine &getSparcTargetMachine() const {
1640b57cec5SDimitry Andric return getTM<SparcTargetMachine>();
1650b57cec5SDimitry Andric }
1660b57cec5SDimitry Andric
1670b57cec5SDimitry Andric void addIRPasses() override;
1680b57cec5SDimitry Andric bool addInstSelector() override;
1690b57cec5SDimitry Andric void addPreEmitPass() override;
1700b57cec5SDimitry Andric };
1710b57cec5SDimitry Andric } // namespace
1720b57cec5SDimitry Andric
createPassConfig(PassManagerBase & PM)1730b57cec5SDimitry Andric TargetPassConfig *SparcTargetMachine::createPassConfig(PassManagerBase &PM) {
1740b57cec5SDimitry Andric return new SparcPassConfig(*this, PM);
1750b57cec5SDimitry Andric }
1760b57cec5SDimitry Andric
addIRPasses()1770b57cec5SDimitry Andric void SparcPassConfig::addIRPasses() {
178*0fca6ea1SDimitry Andric addPass(createAtomicExpandLegacyPass());
1790b57cec5SDimitry Andric
1800b57cec5SDimitry Andric TargetPassConfig::addIRPasses();
1810b57cec5SDimitry Andric }
1820b57cec5SDimitry Andric
addInstSelector()1830b57cec5SDimitry Andric bool SparcPassConfig::addInstSelector() {
1840b57cec5SDimitry Andric addPass(createSparcISelDag(getSparcTargetMachine()));
1850b57cec5SDimitry Andric return false;
1860b57cec5SDimitry Andric }
1870b57cec5SDimitry Andric
addPreEmitPass()1880b57cec5SDimitry Andric void SparcPassConfig::addPreEmitPass(){
1891ac55f4cSDimitry Andric if (BranchRelaxation)
1901ac55f4cSDimitry Andric addPass(&BranchRelaxationPassID);
1911ac55f4cSDimitry Andric
1920b57cec5SDimitry Andric addPass(createSparcDelaySlotFillerPass());
1930b57cec5SDimitry Andric addPass(new InsertNOPLoad());
1940b57cec5SDimitry Andric addPass(new DetectRoundChange());
1950b57cec5SDimitry Andric addPass(new FixAllFDIVSQRT());
1960b57cec5SDimitry Andric }
1970b57cec5SDimitry Andric
anchor()1980b57cec5SDimitry Andric void SparcV8TargetMachine::anchor() { }
1990b57cec5SDimitry Andric
SparcV8TargetMachine(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)2000b57cec5SDimitry Andric SparcV8TargetMachine::SparcV8TargetMachine(const Target &T, const Triple &TT,
2010b57cec5SDimitry Andric StringRef CPU, StringRef FS,
2020b57cec5SDimitry Andric const TargetOptions &Options,
203bdd1243dSDimitry Andric std::optional<Reloc::Model> RM,
204bdd1243dSDimitry Andric std::optional<CodeModel::Model> CM,
2055f757f3fSDimitry Andric CodeGenOptLevel OL, bool JIT)
2060b57cec5SDimitry Andric : SparcTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, JIT, false) {}
2070b57cec5SDimitry Andric
anchor()2080b57cec5SDimitry Andric void SparcV9TargetMachine::anchor() { }
2090b57cec5SDimitry Andric
SparcV9TargetMachine(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)2100b57cec5SDimitry Andric SparcV9TargetMachine::SparcV9TargetMachine(const Target &T, const Triple &TT,
2110b57cec5SDimitry Andric StringRef CPU, StringRef FS,
2120b57cec5SDimitry Andric const TargetOptions &Options,
213bdd1243dSDimitry Andric std::optional<Reloc::Model> RM,
214bdd1243dSDimitry Andric std::optional<CodeModel::Model> CM,
2155f757f3fSDimitry Andric CodeGenOptLevel OL, bool JIT)
2160b57cec5SDimitry Andric : SparcTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, JIT, true) {}
2170b57cec5SDimitry Andric
anchor()2180b57cec5SDimitry Andric void SparcelTargetMachine::anchor() {}
2190b57cec5SDimitry Andric
SparcelTargetMachine(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)2200b57cec5SDimitry Andric SparcelTargetMachine::SparcelTargetMachine(const Target &T, const Triple &TT,
2210b57cec5SDimitry Andric StringRef CPU, StringRef FS,
2220b57cec5SDimitry Andric const TargetOptions &Options,
223bdd1243dSDimitry Andric std::optional<Reloc::Model> RM,
224bdd1243dSDimitry Andric std::optional<CodeModel::Model> CM,
2255f757f3fSDimitry Andric CodeGenOptLevel OL, bool JIT)
2260b57cec5SDimitry Andric : SparcTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, JIT, false) {}
227