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 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 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 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 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 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 * 1170b57cec5SDimitry 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 149bdd1243dSDimitry 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: 1600b57cec5SDimitry Andric SparcPassConfig(SparcTargetMachine &TM, PassManagerBase &PM) 1610b57cec5SDimitry Andric : TargetPassConfig(TM, PM) {} 1620b57cec5SDimitry Andric 1630b57cec5SDimitry 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 1730b57cec5SDimitry Andric TargetPassConfig *SparcTargetMachine::createPassConfig(PassManagerBase &PM) { 1740b57cec5SDimitry Andric return new SparcPassConfig(*this, PM); 1750b57cec5SDimitry Andric } 1760b57cec5SDimitry Andric 1770b57cec5SDimitry Andric void SparcPassConfig::addIRPasses() { 178*0fca6ea1SDimitry Andric addPass(createAtomicExpandLegacyPass()); 1790b57cec5SDimitry Andric 1800b57cec5SDimitry Andric TargetPassConfig::addIRPasses(); 1810b57cec5SDimitry Andric } 1820b57cec5SDimitry Andric 1830b57cec5SDimitry Andric bool SparcPassConfig::addInstSelector() { 1840b57cec5SDimitry Andric addPass(createSparcISelDag(getSparcTargetMachine())); 1850b57cec5SDimitry Andric return false; 1860b57cec5SDimitry Andric } 1870b57cec5SDimitry Andric 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 1980b57cec5SDimitry Andric void SparcV8TargetMachine::anchor() { } 1990b57cec5SDimitry Andric 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 2080b57cec5SDimitry Andric void SparcV9TargetMachine::anchor() { } 2090b57cec5SDimitry Andric 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 2180b57cec5SDimitry Andric void SparcelTargetMachine::anchor() {} 2190b57cec5SDimitry Andric 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