xref: /freebsd/contrib/llvm-project/llvm/lib/Target/Sparc/SparcTargetMachine.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
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"
150b57cec5SDimitry Andric #include "SparcTargetObjectFile.h"
160b57cec5SDimitry Andric #include "TargetInfo/SparcTargetInfo.h"
170b57cec5SDimitry Andric #include "llvm/CodeGen/Passes.h"
180b57cec5SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h"
190b57cec5SDimitry Andric #include "llvm/IR/LegacyPassManager.h"
200b57cec5SDimitry Andric #include "llvm/Support/TargetRegistry.h"
210b57cec5SDimitry Andric using namespace llvm;
220b57cec5SDimitry Andric 
23480093f4SDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSparcTarget() {
240b57cec5SDimitry Andric   // Register the target.
250b57cec5SDimitry Andric   RegisterTargetMachine<SparcV8TargetMachine> X(getTheSparcTarget());
260b57cec5SDimitry Andric   RegisterTargetMachine<SparcV9TargetMachine> Y(getTheSparcV9Target());
270b57cec5SDimitry Andric   RegisterTargetMachine<SparcelTargetMachine> Z(getTheSparcelTarget());
280b57cec5SDimitry Andric }
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric static std::string computeDataLayout(const Triple &T, bool is64Bit) {
310b57cec5SDimitry Andric   // Sparc is typically big endian, but some are little.
320b57cec5SDimitry Andric   std::string Ret = T.getArch() == Triple::sparcel ? "e" : "E";
330b57cec5SDimitry Andric   Ret += "-m:e";
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric   // Some ABIs have 32bit pointers.
360b57cec5SDimitry Andric   if (!is64Bit)
370b57cec5SDimitry Andric     Ret += "-p:32:32";
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric   // Alignments for 64 bit integers.
400b57cec5SDimitry Andric   Ret += "-i64:64";
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric   // On SparcV9 128 floats are aligned to 128 bits, on others only to 64.
430b57cec5SDimitry Andric   // On SparcV9 registers can hold 64 or 32 bits, on others only 32.
440b57cec5SDimitry Andric   if (is64Bit)
450b57cec5SDimitry Andric     Ret += "-n32:64";
460b57cec5SDimitry Andric   else
470b57cec5SDimitry Andric     Ret += "-f128:64-n32";
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric   if (is64Bit)
500b57cec5SDimitry Andric     Ret += "-S128";
510b57cec5SDimitry Andric   else
520b57cec5SDimitry Andric     Ret += "-S64";
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric   return Ret;
550b57cec5SDimitry Andric }
560b57cec5SDimitry Andric 
570b57cec5SDimitry Andric static Reloc::Model getEffectiveRelocModel(Optional<Reloc::Model> RM) {
580b57cec5SDimitry Andric   if (!RM.hasValue())
590b57cec5SDimitry Andric     return Reloc::Static;
600b57cec5SDimitry Andric   return *RM;
610b57cec5SDimitry Andric }
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric // Code models. Some only make sense for 64-bit code.
640b57cec5SDimitry Andric //
650b57cec5SDimitry Andric // SunCC  Reloc   CodeModel  Constraints
660b57cec5SDimitry Andric // abs32  Static  Small      text+data+bss linked below 2^32 bytes
670b57cec5SDimitry Andric // abs44  Static  Medium     text+data+bss linked below 2^44 bytes
680b57cec5SDimitry Andric // abs64  Static  Large      text smaller than 2^31 bytes
690b57cec5SDimitry Andric // pic13  PIC_    Small      GOT < 2^13 bytes
700b57cec5SDimitry Andric // pic32  PIC_    Medium     GOT < 2^32 bytes
710b57cec5SDimitry Andric //
720b57cec5SDimitry Andric // All code models require that the text segment is smaller than 2GB.
730b57cec5SDimitry Andric static CodeModel::Model
740b57cec5SDimitry Andric getEffectiveSparcCodeModel(Optional<CodeModel::Model> CM, Reloc::Model RM,
750b57cec5SDimitry Andric                            bool Is64Bit, bool JIT) {
760b57cec5SDimitry Andric   if (CM) {
770b57cec5SDimitry Andric     if (*CM == CodeModel::Tiny)
780b57cec5SDimitry Andric       report_fatal_error("Target does not support the tiny CodeModel", false);
790b57cec5SDimitry Andric     if (*CM == CodeModel::Kernel)
800b57cec5SDimitry Andric       report_fatal_error("Target does not support the kernel CodeModel", false);
810b57cec5SDimitry Andric     return *CM;
820b57cec5SDimitry Andric   }
830b57cec5SDimitry Andric   if (Is64Bit) {
840b57cec5SDimitry Andric     if (JIT)
850b57cec5SDimitry Andric       return CodeModel::Large;
860b57cec5SDimitry Andric     return RM == Reloc::PIC_ ? CodeModel::Small : CodeModel::Medium;
870b57cec5SDimitry Andric   }
880b57cec5SDimitry Andric   return CodeModel::Small;
890b57cec5SDimitry Andric }
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric /// Create an ILP32 architecture model
920b57cec5SDimitry Andric SparcTargetMachine::SparcTargetMachine(
930b57cec5SDimitry Andric     const Target &T, const Triple &TT, StringRef CPU, StringRef FS,
940b57cec5SDimitry Andric     const TargetOptions &Options, Optional<Reloc::Model> RM,
950b57cec5SDimitry Andric     Optional<CodeModel::Model> CM, CodeGenOpt::Level OL, bool JIT, bool is64bit)
960b57cec5SDimitry Andric     : LLVMTargetMachine(T, computeDataLayout(TT, is64bit), TT, CPU, FS, Options,
970b57cec5SDimitry Andric                         getEffectiveRelocModel(RM),
980b57cec5SDimitry Andric                         getEffectiveSparcCodeModel(
990b57cec5SDimitry Andric                             CM, getEffectiveRelocModel(RM), is64bit, JIT),
1000b57cec5SDimitry Andric                         OL),
1018bcb0991SDimitry Andric       TLOF(std::make_unique<SparcELFTargetObjectFile>()),
102*5ffd83dbSDimitry Andric       Subtarget(TT, std::string(CPU), std::string(FS), *this, is64bit),
103*5ffd83dbSDimitry Andric       is64Bit(is64bit) {
1040b57cec5SDimitry Andric   initAsmInfo();
1050b57cec5SDimitry Andric }
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric SparcTargetMachine::~SparcTargetMachine() {}
1080b57cec5SDimitry Andric 
1090b57cec5SDimitry Andric const SparcSubtarget *
1100b57cec5SDimitry Andric SparcTargetMachine::getSubtargetImpl(const Function &F) const {
1110b57cec5SDimitry Andric   Attribute CPUAttr = F.getFnAttribute("target-cpu");
1120b57cec5SDimitry Andric   Attribute FSAttr = F.getFnAttribute("target-features");
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric   std::string CPU = !CPUAttr.hasAttribute(Attribute::None)
1150b57cec5SDimitry Andric                         ? CPUAttr.getValueAsString().str()
1160b57cec5SDimitry Andric                         : TargetCPU;
1170b57cec5SDimitry Andric   std::string FS = !FSAttr.hasAttribute(Attribute::None)
1180b57cec5SDimitry Andric                        ? FSAttr.getValueAsString().str()
1190b57cec5SDimitry Andric                        : TargetFS;
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric   // FIXME: This is related to the code below to reset the target options,
1220b57cec5SDimitry Andric   // we need to know whether or not the soft float flag is set on the
1230b57cec5SDimitry Andric   // function, so we can enable it as a subtarget feature.
1240b57cec5SDimitry Andric   bool softFloat =
1250b57cec5SDimitry Andric       F.hasFnAttribute("use-soft-float") &&
1260b57cec5SDimitry Andric       F.getFnAttribute("use-soft-float").getValueAsString() == "true";
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric   if (softFloat)
1290b57cec5SDimitry Andric     FS += FS.empty() ? "+soft-float" : ",+soft-float";
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric   auto &I = SubtargetMap[CPU + FS];
1320b57cec5SDimitry Andric   if (!I) {
1330b57cec5SDimitry Andric     // This needs to be done before we create a new subtarget since any
1340b57cec5SDimitry Andric     // creation will depend on the TM and the code generation flags on the
1350b57cec5SDimitry Andric     // function that reside in TargetOptions.
1360b57cec5SDimitry Andric     resetTargetOptions(F);
1378bcb0991SDimitry Andric     I = std::make_unique<SparcSubtarget>(TargetTriple, CPU, FS, *this,
1380b57cec5SDimitry Andric                                           this->is64Bit);
1390b57cec5SDimitry Andric   }
1400b57cec5SDimitry Andric   return I.get();
1410b57cec5SDimitry Andric }
1420b57cec5SDimitry Andric 
1430b57cec5SDimitry Andric namespace {
1440b57cec5SDimitry Andric /// Sparc Code Generator Pass Configuration Options.
1450b57cec5SDimitry Andric class SparcPassConfig : public TargetPassConfig {
1460b57cec5SDimitry Andric public:
1470b57cec5SDimitry Andric   SparcPassConfig(SparcTargetMachine &TM, PassManagerBase &PM)
1480b57cec5SDimitry Andric     : TargetPassConfig(TM, PM) {}
1490b57cec5SDimitry Andric 
1500b57cec5SDimitry Andric   SparcTargetMachine &getSparcTargetMachine() const {
1510b57cec5SDimitry Andric     return getTM<SparcTargetMachine>();
1520b57cec5SDimitry Andric   }
1530b57cec5SDimitry Andric 
1540b57cec5SDimitry Andric   void addIRPasses() override;
1550b57cec5SDimitry Andric   bool addInstSelector() override;
1560b57cec5SDimitry Andric   void addPreEmitPass() override;
1570b57cec5SDimitry Andric };
1580b57cec5SDimitry Andric } // namespace
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric TargetPassConfig *SparcTargetMachine::createPassConfig(PassManagerBase &PM) {
1610b57cec5SDimitry Andric   return new SparcPassConfig(*this, PM);
1620b57cec5SDimitry Andric }
1630b57cec5SDimitry Andric 
1640b57cec5SDimitry Andric void SparcPassConfig::addIRPasses() {
1650b57cec5SDimitry Andric   addPass(createAtomicExpandPass());
1660b57cec5SDimitry Andric 
1670b57cec5SDimitry Andric   TargetPassConfig::addIRPasses();
1680b57cec5SDimitry Andric }
1690b57cec5SDimitry Andric 
1700b57cec5SDimitry Andric bool SparcPassConfig::addInstSelector() {
1710b57cec5SDimitry Andric   addPass(createSparcISelDag(getSparcTargetMachine()));
1720b57cec5SDimitry Andric   return false;
1730b57cec5SDimitry Andric }
1740b57cec5SDimitry Andric 
1750b57cec5SDimitry Andric void SparcPassConfig::addPreEmitPass(){
1760b57cec5SDimitry Andric   addPass(createSparcDelaySlotFillerPass());
1770b57cec5SDimitry Andric 
1780b57cec5SDimitry Andric   if (this->getSparcTargetMachine().getSubtargetImpl()->insertNOPLoad())
1790b57cec5SDimitry Andric   {
1800b57cec5SDimitry Andric     addPass(new InsertNOPLoad());
1810b57cec5SDimitry Andric   }
1820b57cec5SDimitry Andric   if (this->getSparcTargetMachine().getSubtargetImpl()->detectRoundChange()) {
1830b57cec5SDimitry Andric     addPass(new DetectRoundChange());
1840b57cec5SDimitry Andric   }
1850b57cec5SDimitry Andric   if (this->getSparcTargetMachine().getSubtargetImpl()->fixAllFDIVSQRT())
1860b57cec5SDimitry Andric   {
1870b57cec5SDimitry Andric     addPass(new FixAllFDIVSQRT());
1880b57cec5SDimitry Andric   }
1890b57cec5SDimitry Andric }
1900b57cec5SDimitry Andric 
1910b57cec5SDimitry Andric void SparcV8TargetMachine::anchor() { }
1920b57cec5SDimitry Andric 
1930b57cec5SDimitry Andric SparcV8TargetMachine::SparcV8TargetMachine(const Target &T, const Triple &TT,
1940b57cec5SDimitry Andric                                            StringRef CPU, StringRef FS,
1950b57cec5SDimitry Andric                                            const TargetOptions &Options,
1960b57cec5SDimitry Andric                                            Optional<Reloc::Model> RM,
1970b57cec5SDimitry Andric                                            Optional<CodeModel::Model> CM,
1980b57cec5SDimitry Andric                                            CodeGenOpt::Level OL, bool JIT)
1990b57cec5SDimitry Andric     : SparcTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, JIT, false) {}
2000b57cec5SDimitry Andric 
2010b57cec5SDimitry Andric void SparcV9TargetMachine::anchor() { }
2020b57cec5SDimitry Andric 
2030b57cec5SDimitry Andric SparcV9TargetMachine::SparcV9TargetMachine(const Target &T, const Triple &TT,
2040b57cec5SDimitry Andric                                            StringRef CPU, StringRef FS,
2050b57cec5SDimitry Andric                                            const TargetOptions &Options,
2060b57cec5SDimitry Andric                                            Optional<Reloc::Model> RM,
2070b57cec5SDimitry Andric                                            Optional<CodeModel::Model> CM,
2080b57cec5SDimitry Andric                                            CodeGenOpt::Level OL, bool JIT)
2090b57cec5SDimitry Andric     : SparcTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, JIT, true) {}
2100b57cec5SDimitry Andric 
2110b57cec5SDimitry Andric void SparcelTargetMachine::anchor() {}
2120b57cec5SDimitry Andric 
2130b57cec5SDimitry Andric SparcelTargetMachine::SparcelTargetMachine(const Target &T, const Triple &TT,
2140b57cec5SDimitry Andric                                            StringRef CPU, StringRef FS,
2150b57cec5SDimitry Andric                                            const TargetOptions &Options,
2160b57cec5SDimitry Andric                                            Optional<Reloc::Model> RM,
2170b57cec5SDimitry Andric                                            Optional<CodeModel::Model> CM,
2180b57cec5SDimitry Andric                                            CodeGenOpt::Level OL, bool JIT)
2190b57cec5SDimitry Andric     : SparcTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, JIT, false) {}
220