| //===-- M68kTargetMachine.cpp - M68k Target Machine -------------*- C++ -*-===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| /// | |
| /// \file | |
| /// This file contains implementation for M68k target machine. | |
| /// | |
| //===----------------------------------------------------------------------===// | |
| #include "M68kTargetMachine.h" | |
| #include "M68k.h" | |
| #include "M68kMachineFunction.h" | |
| #include "M68kSubtarget.h" | |
| #include "M68kTargetObjectFile.h" | |
| #include "TargetInfo/M68kTargetInfo.h" | |
| #include "llvm/CodeGen/GlobalISel/IRTranslator.h" | |
| #include "llvm/CodeGen/GlobalISel/InstructionSelect.h" | |
| #include "llvm/CodeGen/GlobalISel/Legalizer.h" | |
| #include "llvm/CodeGen/GlobalISel/RegBankSelect.h" | |
| #include "llvm/CodeGen/Passes.h" | |
| #include "llvm/CodeGen/TargetPassConfig.h" | |
| #include "llvm/IR/LegacyPassManager.h" | |
| #include "llvm/InitializePasses.h" | |
| #include "llvm/MC/TargetRegistry.h" | |
| #include "llvm/PassRegistry.h" | |
| #include <memory> | |
| #include <optional> | |
| using namespace llvm; | |
| #define DEBUG_TYPE "m68k" | |
| extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeM68kTarget() { | |
| RegisterTargetMachine<M68kTargetMachine> X(getTheM68kTarget()); | |
| auto *PR = PassRegistry::getPassRegistry(); | |
| initializeGlobalISel(*PR); | |
| initializeM68kDAGToDAGISelPass(*PR); | |
| } | |
| namespace { | |
| std::string computeDataLayout(const Triple &TT, StringRef CPU, | |
| const TargetOptions &Options) { | |
| std::string Ret = ""; | |
| // M68k is Big Endian | |
| Ret += "E"; | |
| // FIXME how to wire it with the used object format? | |
| Ret += "-m:e"; | |
| // M68k pointers are always 32 bit wide even for 16-bit CPUs. | |
| // The ABI only specifies 16-bit alignment. | |
| // On at least the 68020+ with a 32-bit bus, there is a performance benefit | |
| // to having 32-bit alignment. | |
| Ret += "-p:32:16:32"; | |
| // Bytes do not require special alignment, words are word aligned and | |
| // long words are word aligned at minimum. | |
| Ret += "-i8:8:8-i16:16:16-i32:16:32"; | |
| // FIXME no floats at the moment | |
| // The registers can hold 8, 16, 32 bits | |
| Ret += "-n8:16:32"; | |
| Ret += "-a:0:16-S16"; | |
| return Ret; | |
| } | |
| Reloc::Model getEffectiveRelocModel(const Triple &TT, | |
| std::optional<Reloc::Model> RM) { | |
| // If not defined we default to static | |
| if (!RM.has_value()) | |
| return Reloc::Static; | |
| return *RM; | |
| } | |
| CodeModel::Model getEffectiveCodeModel(std::optional<CodeModel::Model> CM, | |
| bool JIT) { | |
| if (!CM) { | |
| return CodeModel::Small; | |
| } else if (CM == CodeModel::Large) { | |
| llvm_unreachable("Large code model is not supported"); | |
| } else if (CM == CodeModel::Kernel) { | |
| llvm_unreachable("Kernel code model is not implemented yet"); | |
| } | |
| return CM.value(); | |
| } | |
| } // end anonymous namespace | |
| M68kTargetMachine::M68kTargetMachine(const Target &T, const Triple &TT, | |
| StringRef CPU, StringRef FS, | |
| const TargetOptions &Options, | |
| std::optional<Reloc::Model> RM, | |
| std::optional<CodeModel::Model> CM, | |
| CodeGenOpt::Level OL, bool JIT) | |
| : LLVMTargetMachine(T, computeDataLayout(TT, CPU, Options), TT, CPU, FS, | |
| Options, getEffectiveRelocModel(TT, RM), | |
| ::getEffectiveCodeModel(CM, JIT), OL), | |
| TLOF(std::make_unique<M68kELFTargetObjectFile>()), | |
| Subtarget(TT, CPU, FS, *this) { | |
| initAsmInfo(); | |
| } | |
| M68kTargetMachine::~M68kTargetMachine() {} | |
| const M68kSubtarget * | |
| M68kTargetMachine::getSubtargetImpl(const Function &F) const { | |
| Attribute CPUAttr = F.getFnAttribute("target-cpu"); | |
| Attribute FSAttr = F.getFnAttribute("target-features"); | |
| auto CPU = CPUAttr.isValid() ? CPUAttr.getValueAsString().str() : TargetCPU; | |
| auto FS = FSAttr.isValid() ? FSAttr.getValueAsString().str() : TargetFS; | |
| auto &I = SubtargetMap[CPU + FS]; | |
| if (!I) { | |
| // This needs to be done before we create a new subtarget since any | |
| // creation will depend on the TM and the code generation flags on the | |
| // function that reside in TargetOptions. | |
| resetTargetOptions(F); | |
| I = std::make_unique<M68kSubtarget>(TargetTriple, CPU, FS, *this); | |
| } | |
| return I.get(); | |
| } | |
| MachineFunctionInfo *M68kTargetMachine::createMachineFunctionInfo( | |
| BumpPtrAllocator &Allocator, const Function &F, | |
| const TargetSubtargetInfo *STI) const { | |
| return M68kMachineFunctionInfo::create<M68kMachineFunctionInfo>(Allocator, F, | |
| STI); | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // Pass Pipeline Configuration | |
| //===----------------------------------------------------------------------===// | |
| namespace { | |
| class M68kPassConfig : public TargetPassConfig { | |
| public: | |
| M68kPassConfig(M68kTargetMachine &TM, PassManagerBase &PM) | |
| : TargetPassConfig(TM, PM) {} | |
| M68kTargetMachine &getM68kTargetMachine() const { | |
| return getTM<M68kTargetMachine>(); | |
| } | |
| const M68kSubtarget &getM68kSubtarget() const { | |
| return *getM68kTargetMachine().getSubtargetImpl(); | |
| } | |
| void addIRPasses() override; | |
| bool addIRTranslator() override; | |
| bool addLegalizeMachineIR() override; | |
| bool addRegBankSelect() override; | |
| bool addGlobalInstructionSelect() override; | |
| bool addInstSelector() override; | |
| void addPreSched2() override; | |
| void addPreEmitPass() override; | |
| }; | |
| } // namespace | |
| TargetPassConfig *M68kTargetMachine::createPassConfig(PassManagerBase &PM) { | |
| return new M68kPassConfig(*this, PM); | |
| } | |
| void M68kPassConfig::addIRPasses() { | |
| addPass(createAtomicExpandPass()); | |
| TargetPassConfig::addIRPasses(); | |
| } | |
| bool M68kPassConfig::addInstSelector() { | |
| // Install an instruction selector. | |
| addPass(createM68kISelDag(getM68kTargetMachine())); | |
| addPass(createM68kGlobalBaseRegPass()); | |
| return false; | |
| } | |
| bool M68kPassConfig::addIRTranslator() { | |
| addPass(new IRTranslator()); | |
| return false; | |
| } | |
| bool M68kPassConfig::addLegalizeMachineIR() { | |
| addPass(new Legalizer()); | |
| return false; | |
| } | |
| bool M68kPassConfig::addRegBankSelect() { | |
| addPass(new RegBankSelect()); | |
| return false; | |
| } | |
| bool M68kPassConfig::addGlobalInstructionSelect() { | |
| addPass(new InstructionSelect()); | |
| return false; | |
| } | |
| void M68kPassConfig::addPreSched2() { addPass(createM68kExpandPseudoPass()); } | |
| void M68kPassConfig::addPreEmitPass() { | |
| addPass(createM68kCollapseMOVEMPass()); | |
| } |