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();
31bdd1243dSDimitry Andric   initializeSparcDAGToDAGISelPass(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() {
1780b57cec5SDimitry Andric   addPass(createAtomicExpandPass());
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