xref: /freebsd/contrib/llvm-project/llvm/lib/Target/Sparc/SparcTargetMachine.cpp (revision fe6060f10f634930ff71b7c50291ddc610da2475)
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) {
58e8d8bef9SDimitry Andric   return RM.getValueOr(Reloc::Static);
590b57cec5SDimitry Andric }
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric // Code models. Some only make sense for 64-bit code.
620b57cec5SDimitry Andric //
630b57cec5SDimitry Andric // SunCC  Reloc   CodeModel  Constraints
640b57cec5SDimitry Andric // abs32  Static  Small      text+data+bss linked below 2^32 bytes
650b57cec5SDimitry Andric // abs44  Static  Medium     text+data+bss linked below 2^44 bytes
660b57cec5SDimitry Andric // abs64  Static  Large      text smaller than 2^31 bytes
670b57cec5SDimitry Andric // pic13  PIC_    Small      GOT < 2^13 bytes
680b57cec5SDimitry Andric // pic32  PIC_    Medium     GOT < 2^32 bytes
690b57cec5SDimitry Andric //
700b57cec5SDimitry Andric // All code models require that the text segment is smaller than 2GB.
710b57cec5SDimitry Andric static CodeModel::Model
720b57cec5SDimitry Andric getEffectiveSparcCodeModel(Optional<CodeModel::Model> CM, Reloc::Model RM,
730b57cec5SDimitry Andric                            bool Is64Bit, bool JIT) {
740b57cec5SDimitry Andric   if (CM) {
750b57cec5SDimitry Andric     if (*CM == CodeModel::Tiny)
760b57cec5SDimitry Andric       report_fatal_error("Target does not support the tiny CodeModel", false);
770b57cec5SDimitry Andric     if (*CM == CodeModel::Kernel)
780b57cec5SDimitry Andric       report_fatal_error("Target does not support the kernel CodeModel", false);
790b57cec5SDimitry Andric     return *CM;
800b57cec5SDimitry Andric   }
810b57cec5SDimitry Andric   if (Is64Bit) {
820b57cec5SDimitry Andric     if (JIT)
830b57cec5SDimitry Andric       return CodeModel::Large;
840b57cec5SDimitry Andric     return RM == Reloc::PIC_ ? CodeModel::Small : CodeModel::Medium;
850b57cec5SDimitry Andric   }
860b57cec5SDimitry Andric   return CodeModel::Small;
870b57cec5SDimitry Andric }
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric /// Create an ILP32 architecture model
900b57cec5SDimitry Andric SparcTargetMachine::SparcTargetMachine(
910b57cec5SDimitry Andric     const Target &T, const Triple &TT, StringRef CPU, StringRef FS,
920b57cec5SDimitry Andric     const TargetOptions &Options, Optional<Reloc::Model> RM,
930b57cec5SDimitry Andric     Optional<CodeModel::Model> CM, CodeGenOpt::Level OL, bool JIT, bool is64bit)
940b57cec5SDimitry Andric     : LLVMTargetMachine(T, computeDataLayout(TT, is64bit), TT, CPU, FS, Options,
950b57cec5SDimitry Andric                         getEffectiveRelocModel(RM),
960b57cec5SDimitry Andric                         getEffectiveSparcCodeModel(
970b57cec5SDimitry Andric                             CM, getEffectiveRelocModel(RM), is64bit, JIT),
980b57cec5SDimitry Andric                         OL),
998bcb0991SDimitry Andric       TLOF(std::make_unique<SparcELFTargetObjectFile>()),
1005ffd83dbSDimitry Andric       Subtarget(TT, std::string(CPU), std::string(FS), *this, is64bit),
1015ffd83dbSDimitry Andric       is64Bit(is64bit) {
1020b57cec5SDimitry Andric   initAsmInfo();
1030b57cec5SDimitry Andric }
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric SparcTargetMachine::~SparcTargetMachine() {}
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric const SparcSubtarget *
1080b57cec5SDimitry Andric SparcTargetMachine::getSubtargetImpl(const Function &F) const {
1090b57cec5SDimitry Andric   Attribute CPUAttr = F.getFnAttribute("target-cpu");
1100b57cec5SDimitry Andric   Attribute FSAttr = F.getFnAttribute("target-features");
1110b57cec5SDimitry Andric 
112e8d8bef9SDimitry Andric   std::string CPU =
113e8d8bef9SDimitry Andric       CPUAttr.isValid() ? CPUAttr.getValueAsString().str() : TargetCPU;
114e8d8bef9SDimitry Andric   std::string FS =
115e8d8bef9SDimitry Andric       FSAttr.isValid() ? FSAttr.getValueAsString().str() : TargetFS;
1160b57cec5SDimitry Andric 
1170b57cec5SDimitry Andric   // FIXME: This is related to the code below to reset the target options,
1180b57cec5SDimitry Andric   // we need to know whether or not the soft float flag is set on the
1190b57cec5SDimitry Andric   // function, so we can enable it as a subtarget feature.
120*fe6060f1SDimitry Andric   bool softFloat = F.getFnAttribute("use-soft-float").getValueAsBool();
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric   if (softFloat)
1230b57cec5SDimitry Andric     FS += FS.empty() ? "+soft-float" : ",+soft-float";
1240b57cec5SDimitry Andric 
1250b57cec5SDimitry Andric   auto &I = SubtargetMap[CPU + FS];
1260b57cec5SDimitry Andric   if (!I) {
1270b57cec5SDimitry Andric     // This needs to be done before we create a new subtarget since any
1280b57cec5SDimitry Andric     // creation will depend on the TM and the code generation flags on the
1290b57cec5SDimitry Andric     // function that reside in TargetOptions.
1300b57cec5SDimitry Andric     resetTargetOptions(F);
1318bcb0991SDimitry Andric     I = std::make_unique<SparcSubtarget>(TargetTriple, CPU, FS, *this,
1320b57cec5SDimitry Andric                                           this->is64Bit);
1330b57cec5SDimitry Andric   }
1340b57cec5SDimitry Andric   return I.get();
1350b57cec5SDimitry Andric }
1360b57cec5SDimitry Andric 
1370b57cec5SDimitry Andric namespace {
1380b57cec5SDimitry Andric /// Sparc Code Generator Pass Configuration Options.
1390b57cec5SDimitry Andric class SparcPassConfig : public TargetPassConfig {
1400b57cec5SDimitry Andric public:
1410b57cec5SDimitry Andric   SparcPassConfig(SparcTargetMachine &TM, PassManagerBase &PM)
1420b57cec5SDimitry Andric     : TargetPassConfig(TM, PM) {}
1430b57cec5SDimitry Andric 
1440b57cec5SDimitry Andric   SparcTargetMachine &getSparcTargetMachine() const {
1450b57cec5SDimitry Andric     return getTM<SparcTargetMachine>();
1460b57cec5SDimitry Andric   }
1470b57cec5SDimitry Andric 
1480b57cec5SDimitry Andric   void addIRPasses() override;
1490b57cec5SDimitry Andric   bool addInstSelector() override;
1500b57cec5SDimitry Andric   void addPreEmitPass() override;
1510b57cec5SDimitry Andric };
1520b57cec5SDimitry Andric } // namespace
1530b57cec5SDimitry Andric 
1540b57cec5SDimitry Andric TargetPassConfig *SparcTargetMachine::createPassConfig(PassManagerBase &PM) {
1550b57cec5SDimitry Andric   return new SparcPassConfig(*this, PM);
1560b57cec5SDimitry Andric }
1570b57cec5SDimitry Andric 
1580b57cec5SDimitry Andric void SparcPassConfig::addIRPasses() {
1590b57cec5SDimitry Andric   addPass(createAtomicExpandPass());
1600b57cec5SDimitry Andric 
1610b57cec5SDimitry Andric   TargetPassConfig::addIRPasses();
1620b57cec5SDimitry Andric }
1630b57cec5SDimitry Andric 
1640b57cec5SDimitry Andric bool SparcPassConfig::addInstSelector() {
1650b57cec5SDimitry Andric   addPass(createSparcISelDag(getSparcTargetMachine()));
1660b57cec5SDimitry Andric   return false;
1670b57cec5SDimitry Andric }
1680b57cec5SDimitry Andric 
1690b57cec5SDimitry Andric void SparcPassConfig::addPreEmitPass(){
1700b57cec5SDimitry Andric   addPass(createSparcDelaySlotFillerPass());
1710b57cec5SDimitry Andric 
1720b57cec5SDimitry Andric   if (this->getSparcTargetMachine().getSubtargetImpl()->insertNOPLoad())
1730b57cec5SDimitry Andric   {
1740b57cec5SDimitry Andric     addPass(new InsertNOPLoad());
1750b57cec5SDimitry Andric   }
1760b57cec5SDimitry Andric   if (this->getSparcTargetMachine().getSubtargetImpl()->detectRoundChange()) {
1770b57cec5SDimitry Andric     addPass(new DetectRoundChange());
1780b57cec5SDimitry Andric   }
1790b57cec5SDimitry Andric   if (this->getSparcTargetMachine().getSubtargetImpl()->fixAllFDIVSQRT())
1800b57cec5SDimitry Andric   {
1810b57cec5SDimitry Andric     addPass(new FixAllFDIVSQRT());
1820b57cec5SDimitry Andric   }
1830b57cec5SDimitry Andric }
1840b57cec5SDimitry Andric 
1850b57cec5SDimitry Andric void SparcV8TargetMachine::anchor() { }
1860b57cec5SDimitry Andric 
1870b57cec5SDimitry Andric SparcV8TargetMachine::SparcV8TargetMachine(const Target &T, const Triple &TT,
1880b57cec5SDimitry Andric                                            StringRef CPU, StringRef FS,
1890b57cec5SDimitry Andric                                            const TargetOptions &Options,
1900b57cec5SDimitry Andric                                            Optional<Reloc::Model> RM,
1910b57cec5SDimitry Andric                                            Optional<CodeModel::Model> CM,
1920b57cec5SDimitry Andric                                            CodeGenOpt::Level OL, bool JIT)
1930b57cec5SDimitry Andric     : SparcTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, JIT, false) {}
1940b57cec5SDimitry Andric 
1950b57cec5SDimitry Andric void SparcV9TargetMachine::anchor() { }
1960b57cec5SDimitry Andric 
1970b57cec5SDimitry Andric SparcV9TargetMachine::SparcV9TargetMachine(const Target &T, const Triple &TT,
1980b57cec5SDimitry Andric                                            StringRef CPU, StringRef FS,
1990b57cec5SDimitry Andric                                            const TargetOptions &Options,
2000b57cec5SDimitry Andric                                            Optional<Reloc::Model> RM,
2010b57cec5SDimitry Andric                                            Optional<CodeModel::Model> CM,
2020b57cec5SDimitry Andric                                            CodeGenOpt::Level OL, bool JIT)
2030b57cec5SDimitry Andric     : SparcTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, JIT, true) {}
2040b57cec5SDimitry Andric 
2050b57cec5SDimitry Andric void SparcelTargetMachine::anchor() {}
2060b57cec5SDimitry Andric 
2070b57cec5SDimitry Andric SparcelTargetMachine::SparcelTargetMachine(const Target &T, const Triple &TT,
2080b57cec5SDimitry Andric                                            StringRef CPU, StringRef FS,
2090b57cec5SDimitry Andric                                            const TargetOptions &Options,
2100b57cec5SDimitry Andric                                            Optional<Reloc::Model> RM,
2110b57cec5SDimitry Andric                                            Optional<CodeModel::Model> CM,
2120b57cec5SDimitry Andric                                            CodeGenOpt::Level OL, bool JIT)
2130b57cec5SDimitry Andric     : SparcTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, JIT, false) {}
214