104eeddc0SDimitry Andric //===-- M68kTargetMachine.cpp - M68k Target Machine -------------*- C++ -*-===// 2fe6060f1SDimitry Andric // 3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6fe6060f1SDimitry Andric // 7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 8fe6060f1SDimitry Andric /// 9fe6060f1SDimitry Andric /// \file 10fe6060f1SDimitry Andric /// This file contains implementation for M68k target machine. 11fe6060f1SDimitry Andric /// 12fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 13fe6060f1SDimitry Andric 14fe6060f1SDimitry Andric #include "M68kTargetMachine.h" 15fe6060f1SDimitry Andric #include "M68k.h" 16*bdd1243dSDimitry Andric #include "M68kMachineFunction.h" 17fe6060f1SDimitry Andric #include "M68kSubtarget.h" 18fe6060f1SDimitry Andric #include "M68kTargetObjectFile.h" 19fe6060f1SDimitry Andric #include "TargetInfo/M68kTargetInfo.h" 20fe6060f1SDimitry Andric #include "llvm/CodeGen/GlobalISel/IRTranslator.h" 21fe6060f1SDimitry Andric #include "llvm/CodeGen/GlobalISel/InstructionSelect.h" 22fe6060f1SDimitry Andric #include "llvm/CodeGen/GlobalISel/Legalizer.h" 23fe6060f1SDimitry Andric #include "llvm/CodeGen/GlobalISel/RegBankSelect.h" 24fe6060f1SDimitry Andric #include "llvm/CodeGen/Passes.h" 25fe6060f1SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h" 26fe6060f1SDimitry Andric #include "llvm/IR/LegacyPassManager.h" 27fe6060f1SDimitry Andric #include "llvm/InitializePasses.h" 28349cc55cSDimitry Andric #include "llvm/MC/TargetRegistry.h" 29fe6060f1SDimitry Andric #include "llvm/PassRegistry.h" 30fe6060f1SDimitry Andric #include <memory> 31*bdd1243dSDimitry Andric #include <optional> 32fe6060f1SDimitry Andric 33fe6060f1SDimitry Andric using namespace llvm; 34fe6060f1SDimitry Andric 35fe6060f1SDimitry Andric #define DEBUG_TYPE "m68k" 36fe6060f1SDimitry Andric 37fe6060f1SDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeM68kTarget() { 38fe6060f1SDimitry Andric RegisterTargetMachine<M68kTargetMachine> X(getTheM68kTarget()); 39fe6060f1SDimitry Andric auto *PR = PassRegistry::getPassRegistry(); 40fe6060f1SDimitry Andric initializeGlobalISel(*PR); 41*bdd1243dSDimitry Andric initializeM68kDAGToDAGISelPass(*PR); 42fe6060f1SDimitry Andric } 43fe6060f1SDimitry Andric 44fe6060f1SDimitry Andric namespace { 45fe6060f1SDimitry Andric 46fe6060f1SDimitry Andric std::string computeDataLayout(const Triple &TT, StringRef CPU, 47fe6060f1SDimitry Andric const TargetOptions &Options) { 48fe6060f1SDimitry Andric std::string Ret = ""; 49fe6060f1SDimitry Andric // M68k is Big Endian 50fe6060f1SDimitry Andric Ret += "E"; 51fe6060f1SDimitry Andric 52fe6060f1SDimitry Andric // FIXME how to wire it with the used object format? 53fe6060f1SDimitry Andric Ret += "-m:e"; 54fe6060f1SDimitry Andric 5569ade1e0SDimitry Andric // M68k pointers are always 32 bit wide even for 16-bit CPUs. 5669ade1e0SDimitry Andric // The ABI only specifies 16-bit alignment. 5769ade1e0SDimitry Andric // On at least the 68020+ with a 32-bit bus, there is a performance benefit 5869ade1e0SDimitry Andric // to having 32-bit alignment. 5969ade1e0SDimitry Andric Ret += "-p:32:16:32"; 60fe6060f1SDimitry Andric 6169ade1e0SDimitry Andric // Bytes do not require special alignment, words are word aligned and 6269ade1e0SDimitry Andric // long words are word aligned at minimum. 63fe6060f1SDimitry Andric Ret += "-i8:8:8-i16:16:16-i32:16:32"; 64fe6060f1SDimitry Andric 65fe6060f1SDimitry Andric // FIXME no floats at the moment 66fe6060f1SDimitry Andric 67fe6060f1SDimitry Andric // The registers can hold 8, 16, 32 bits 68fe6060f1SDimitry Andric Ret += "-n8:16:32"; 69fe6060f1SDimitry Andric 70fe6060f1SDimitry Andric Ret += "-a:0:16-S16"; 71fe6060f1SDimitry Andric 72fe6060f1SDimitry Andric return Ret; 73fe6060f1SDimitry Andric } 74fe6060f1SDimitry Andric 75fe6060f1SDimitry Andric Reloc::Model getEffectiveRelocModel(const Triple &TT, 76*bdd1243dSDimitry Andric std::optional<Reloc::Model> RM) { 77fe6060f1SDimitry Andric // If not defined we default to static 78*bdd1243dSDimitry Andric if (!RM.has_value()) 79fe6060f1SDimitry Andric return Reloc::Static; 80fe6060f1SDimitry Andric 81fe6060f1SDimitry Andric return *RM; 82fe6060f1SDimitry Andric } 83fe6060f1SDimitry Andric 84*bdd1243dSDimitry Andric CodeModel::Model getEffectiveCodeModel(std::optional<CodeModel::Model> CM, 85fe6060f1SDimitry Andric bool JIT) { 86fe6060f1SDimitry Andric if (!CM) { 87fe6060f1SDimitry Andric return CodeModel::Small; 88fe6060f1SDimitry Andric } else if (CM == CodeModel::Large) { 89fe6060f1SDimitry Andric llvm_unreachable("Large code model is not supported"); 90fe6060f1SDimitry Andric } else if (CM == CodeModel::Kernel) { 91fe6060f1SDimitry Andric llvm_unreachable("Kernel code model is not implemented yet"); 92fe6060f1SDimitry Andric } 93*bdd1243dSDimitry Andric return CM.value(); 94fe6060f1SDimitry Andric } 95fe6060f1SDimitry Andric } // end anonymous namespace 96fe6060f1SDimitry Andric 97fe6060f1SDimitry Andric M68kTargetMachine::M68kTargetMachine(const Target &T, const Triple &TT, 98fe6060f1SDimitry Andric StringRef CPU, StringRef FS, 99fe6060f1SDimitry Andric const TargetOptions &Options, 100*bdd1243dSDimitry Andric std::optional<Reloc::Model> RM, 101*bdd1243dSDimitry Andric std::optional<CodeModel::Model> CM, 102fe6060f1SDimitry Andric CodeGenOpt::Level OL, bool JIT) 103fe6060f1SDimitry Andric : LLVMTargetMachine(T, computeDataLayout(TT, CPU, Options), TT, CPU, FS, 104fe6060f1SDimitry Andric Options, getEffectiveRelocModel(TT, RM), 105fe6060f1SDimitry Andric ::getEffectiveCodeModel(CM, JIT), OL), 106fe6060f1SDimitry Andric TLOF(std::make_unique<M68kELFTargetObjectFile>()), 107fe6060f1SDimitry Andric Subtarget(TT, CPU, FS, *this) { 108fe6060f1SDimitry Andric initAsmInfo(); 109fe6060f1SDimitry Andric } 110fe6060f1SDimitry Andric 111fe6060f1SDimitry Andric M68kTargetMachine::~M68kTargetMachine() {} 112fe6060f1SDimitry Andric 113fe6060f1SDimitry Andric const M68kSubtarget * 114fe6060f1SDimitry Andric M68kTargetMachine::getSubtargetImpl(const Function &F) const { 115fe6060f1SDimitry Andric Attribute CPUAttr = F.getFnAttribute("target-cpu"); 116fe6060f1SDimitry Andric Attribute FSAttr = F.getFnAttribute("target-features"); 117fe6060f1SDimitry Andric 118fe6060f1SDimitry Andric auto CPU = CPUAttr.isValid() ? CPUAttr.getValueAsString().str() : TargetCPU; 119fe6060f1SDimitry Andric auto FS = FSAttr.isValid() ? FSAttr.getValueAsString().str() : TargetFS; 120fe6060f1SDimitry Andric 121fe6060f1SDimitry Andric auto &I = SubtargetMap[CPU + FS]; 122fe6060f1SDimitry Andric if (!I) { 123fe6060f1SDimitry Andric // This needs to be done before we create a new subtarget since any 124fe6060f1SDimitry Andric // creation will depend on the TM and the code generation flags on the 125fe6060f1SDimitry Andric // function that reside in TargetOptions. 126fe6060f1SDimitry Andric resetTargetOptions(F); 127fe6060f1SDimitry Andric I = std::make_unique<M68kSubtarget>(TargetTriple, CPU, FS, *this); 128fe6060f1SDimitry Andric } 129fe6060f1SDimitry Andric return I.get(); 130fe6060f1SDimitry Andric } 131fe6060f1SDimitry Andric 132*bdd1243dSDimitry Andric MachineFunctionInfo *M68kTargetMachine::createMachineFunctionInfo( 133*bdd1243dSDimitry Andric BumpPtrAllocator &Allocator, const Function &F, 134*bdd1243dSDimitry Andric const TargetSubtargetInfo *STI) const { 135*bdd1243dSDimitry Andric return M68kMachineFunctionInfo::create<M68kMachineFunctionInfo>(Allocator, F, 136*bdd1243dSDimitry Andric STI); 137*bdd1243dSDimitry Andric } 138*bdd1243dSDimitry Andric 139fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 140fe6060f1SDimitry Andric // Pass Pipeline Configuration 141fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 142fe6060f1SDimitry Andric 143fe6060f1SDimitry Andric namespace { 144fe6060f1SDimitry Andric class M68kPassConfig : public TargetPassConfig { 145fe6060f1SDimitry Andric public: 146fe6060f1SDimitry Andric M68kPassConfig(M68kTargetMachine &TM, PassManagerBase &PM) 147fe6060f1SDimitry Andric : TargetPassConfig(TM, PM) {} 148fe6060f1SDimitry Andric 149fe6060f1SDimitry Andric M68kTargetMachine &getM68kTargetMachine() const { 150fe6060f1SDimitry Andric return getTM<M68kTargetMachine>(); 151fe6060f1SDimitry Andric } 152fe6060f1SDimitry Andric 153fe6060f1SDimitry Andric const M68kSubtarget &getM68kSubtarget() const { 154fe6060f1SDimitry Andric return *getM68kTargetMachine().getSubtargetImpl(); 155fe6060f1SDimitry Andric } 156*bdd1243dSDimitry Andric void addIRPasses() override; 157fe6060f1SDimitry Andric bool addIRTranslator() override; 158fe6060f1SDimitry Andric bool addLegalizeMachineIR() override; 159fe6060f1SDimitry Andric bool addRegBankSelect() override; 160fe6060f1SDimitry Andric bool addGlobalInstructionSelect() override; 161fe6060f1SDimitry Andric bool addInstSelector() override; 162fe6060f1SDimitry Andric void addPreSched2() override; 163fe6060f1SDimitry Andric void addPreEmitPass() override; 164fe6060f1SDimitry Andric }; 165fe6060f1SDimitry Andric } // namespace 166fe6060f1SDimitry Andric 167fe6060f1SDimitry Andric TargetPassConfig *M68kTargetMachine::createPassConfig(PassManagerBase &PM) { 168fe6060f1SDimitry Andric return new M68kPassConfig(*this, PM); 169fe6060f1SDimitry Andric } 170fe6060f1SDimitry Andric 171*bdd1243dSDimitry Andric void M68kPassConfig::addIRPasses() { 172*bdd1243dSDimitry Andric addPass(createAtomicExpandPass()); 173*bdd1243dSDimitry Andric TargetPassConfig::addIRPasses(); 174*bdd1243dSDimitry Andric } 175*bdd1243dSDimitry Andric 176fe6060f1SDimitry Andric bool M68kPassConfig::addInstSelector() { 177fe6060f1SDimitry Andric // Install an instruction selector. 178fe6060f1SDimitry Andric addPass(createM68kISelDag(getM68kTargetMachine())); 179fe6060f1SDimitry Andric addPass(createM68kGlobalBaseRegPass()); 180fe6060f1SDimitry Andric return false; 181fe6060f1SDimitry Andric } 182fe6060f1SDimitry Andric 183fe6060f1SDimitry Andric bool M68kPassConfig::addIRTranslator() { 184fe6060f1SDimitry Andric addPass(new IRTranslator()); 185fe6060f1SDimitry Andric return false; 186fe6060f1SDimitry Andric } 187fe6060f1SDimitry Andric 188fe6060f1SDimitry Andric bool M68kPassConfig::addLegalizeMachineIR() { 189fe6060f1SDimitry Andric addPass(new Legalizer()); 190fe6060f1SDimitry Andric return false; 191fe6060f1SDimitry Andric } 192fe6060f1SDimitry Andric 193fe6060f1SDimitry Andric bool M68kPassConfig::addRegBankSelect() { 194fe6060f1SDimitry Andric addPass(new RegBankSelect()); 195fe6060f1SDimitry Andric return false; 196fe6060f1SDimitry Andric } 197fe6060f1SDimitry Andric 198fe6060f1SDimitry Andric bool M68kPassConfig::addGlobalInstructionSelect() { 199fe6060f1SDimitry Andric addPass(new InstructionSelect()); 200fe6060f1SDimitry Andric return false; 201fe6060f1SDimitry Andric } 202fe6060f1SDimitry Andric 203fe6060f1SDimitry Andric void M68kPassConfig::addPreSched2() { addPass(createM68kExpandPseudoPass()); } 204fe6060f1SDimitry Andric 205fe6060f1SDimitry Andric void M68kPassConfig::addPreEmitPass() { 206fe6060f1SDimitry Andric addPass(createM68kCollapseMOVEMPass()); 207fe6060f1SDimitry Andric } 208