|  | //===-- M68kSubtarget.cpp - M68k Subtarget Information ----------*- 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 implements the M68k specific subclass of TargetSubtargetInfo. | 
|  | /// | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "M68kSubtarget.h" | 
|  | #include "GISel/M68kCallLowering.h" | 
|  | #include "GISel/M68kLegalizerInfo.h" | 
|  | #include "GISel/M68kRegisterBankInfo.h" | 
|  | #include "M68k.h" | 
|  | #include "M68kMachineFunction.h" | 
|  | #include "M68kRegisterInfo.h" | 
|  | #include "M68kSelectionDAGInfo.h" | 
|  | #include "M68kTargetMachine.h" | 
|  | #include "llvm/CodeGen/MachineJumpTableInfo.h" | 
|  | #include "llvm/IR/Attributes.h" | 
|  | #include "llvm/IR/Function.h" | 
|  | #include "llvm/MC/TargetRegistry.h" | 
|  | #include "llvm/Support/CommandLine.h" | 
|  | #include "llvm/Support/ErrorHandling.h" | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | #define DEBUG_TYPE "m68k-subtarget" | 
|  |  | 
|  | #define GET_SUBTARGETINFO_TARGET_DESC | 
|  | #define GET_SUBTARGETINFO_CTOR | 
|  | #include "M68kGenSubtargetInfo.inc" | 
|  |  | 
|  | extern bool FixGlobalBaseReg; | 
|  |  | 
|  | /// Select the M68k CPU for the given triple and cpu name. | 
|  | static StringRef selectM68kCPU(Triple TT, StringRef CPU) { | 
|  | if (CPU.empty() || CPU == "generic") { | 
|  | CPU = "M68000"; | 
|  | } | 
|  | return CPU; | 
|  | } | 
|  |  | 
|  | void M68kSubtarget::anchor() {} | 
|  |  | 
|  | M68kSubtarget::M68kSubtarget(const Triple &TT, StringRef CPU, StringRef FS, | 
|  | const M68kTargetMachine &TM) | 
|  | : M68kGenSubtargetInfo(TT, CPU, /*TuneCPU*/ CPU, FS), TM(TM), | 
|  | InstrInfo(initializeSubtargetDependencies(CPU, TT, FS, TM)), | 
|  | FrameLowering(*this, this->getStackAlignment()), TLInfo(TM, *this), | 
|  | TargetTriple(TT) { | 
|  | TSInfo = std::make_unique<M68kSelectionDAGInfo>(); | 
|  |  | 
|  | CallLoweringInfo.reset(new M68kCallLowering(*getTargetLowering())); | 
|  | Legalizer.reset(new M68kLegalizerInfo(*this)); | 
|  |  | 
|  | auto *RBI = new M68kRegisterBankInfo(*getRegisterInfo()); | 
|  | RegBankInfo.reset(RBI); | 
|  | InstSelector.reset(createM68kInstructionSelector(TM, *this, *RBI)); | 
|  | } | 
|  |  | 
|  | M68kSubtarget::~M68kSubtarget() = default; | 
|  |  | 
|  | const SelectionDAGTargetInfo *M68kSubtarget::getSelectionDAGInfo() const { | 
|  | return TSInfo.get(); | 
|  | } | 
|  |  | 
|  | const CallLowering *M68kSubtarget::getCallLowering() const { | 
|  | return CallLoweringInfo.get(); | 
|  | } | 
|  |  | 
|  | InstructionSelector *M68kSubtarget::getInstructionSelector() const { | 
|  | return InstSelector.get(); | 
|  | } | 
|  |  | 
|  | const LegalizerInfo *M68kSubtarget::getLegalizerInfo() const { | 
|  | return Legalizer.get(); | 
|  | } | 
|  |  | 
|  | const RegisterBankInfo *M68kSubtarget::getRegBankInfo() const { | 
|  | return RegBankInfo.get(); | 
|  | } | 
|  |  | 
|  | bool M68kSubtarget::isPositionIndependent() const { | 
|  | return TM.isPositionIndependent(); | 
|  | } | 
|  |  | 
|  | bool M68kSubtarget::isLegalToCallImmediateAddr() const { return true; } | 
|  |  | 
|  | M68kSubtarget &M68kSubtarget::initializeSubtargetDependencies( | 
|  | StringRef CPU, Triple TT, StringRef FS, const M68kTargetMachine &TM) { | 
|  | std::string CPUName = selectM68kCPU(TT, CPU).str(); | 
|  |  | 
|  | // Parse features string. | 
|  | ParseSubtargetFeatures(CPUName, CPUName, FS); | 
|  |  | 
|  | // Initialize scheduling itinerary for the specified CPU. | 
|  | InstrItins = getInstrItineraryForCPU(CPUName); | 
|  |  | 
|  | stackAlignment = 8; | 
|  |  | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | //===----------------------------------------------------------------------===// | 
|  | // Code Model | 
|  | // | 
|  | // Key assumptions: | 
|  | //  - Whenever possible we use pc-rel encoding since it is smaller(16 bit) than | 
|  | //    absolute(32 bit). | 
|  | //  - GOT is reachable within 16 bit offset for both Small and Medium models. | 
|  | //  - Code section is reachable within 16 bit offset for both models. | 
|  | // | 
|  | //  ---------------------+-------------------------+-------------------------- | 
|  | //                       |          Small          |          Medium | 
|  | //                       +-------------------------+------------+------------- | 
|  | //                       |   Static   |    PIC     |   Static   |    PIC | 
|  | //  ---------------------+------------+------------+------------+------------- | 
|  | //                branch |   pc-rel   |   pc-rel   |   pc-rel   |   pc-rel | 
|  | //  ---------------------+------------+------------+------------+------------- | 
|  | //           call global |  absolute  |    @PLT    |  absolute  |    @PLT | 
|  | //  ---------------------+------------+------------+------------+------------- | 
|  | //         call internal |   pc-rel   |   pc-rel   |   pc-rel   |   pc-rel | 
|  | //  ---------------------+------------+------------+------------+------------- | 
|  | //            data local |   pc-rel   |   pc-rel   |  ~pc-rel   |  ^pc-rel | 
|  | //  ---------------------+------------+------------+------------+------------- | 
|  | //       data local big* |   pc-rel   |   pc-rel   |  absolute  |  @GOTOFF | 
|  | //  ---------------------+------------+------------+------------+------------- | 
|  | //           data global |   pc-rel   |  @GOTPCREL |  ~pc-rel   |  @GOTPCREL | 
|  | //  ---------------------+------------+------------+------------+------------- | 
|  | //      data global big* |   pc-rel   |  @GOTPCREL |  absolute  |  @GOTPCREL | 
|  | //  ---------------------+------------+------------+------------+------------- | 
|  | //                       |          Large          | | 
|  | //                       +-------------------------+ | 
|  | //                       |   Static   |    PIC     | | 
|  | //  ---------------------+------------+------------+ | 
|  | //                branch |  absolute  |   pc-rel   | | 
|  | //  ---------------------+------------+------------+ | 
|  | //           call global |  absolute  |    @PLT    | | 
|  | //  ---------------------+------------+------------+ | 
|  | //         call internal |  absolute  |   pc-rel   | | 
|  | //  ---------------------+------------+------------+ | 
|  | //            data local |  absolute  |  @GOTOFF   | | 
|  | //  ---------------------+------------+------------+ | 
|  | //       data local big* |  absolute  |  @GOTOFF   | | 
|  | //  ---------------------+------------+------------+ | 
|  | //           data global |  absolute  |  @GOTOFF   | | 
|  | //  ---------------------+------------+------------+ | 
|  | //      data global big* |  absolute  |  @GOTOFF   | | 
|  | //  ---------------------+------------+------------+ | 
|  | // | 
|  | // * Big data potentially cannot be reached within 16 bit offset and requires | 
|  | //   special handling for old(x00 and x10) CPUs. Normally these symbols go into | 
|  | //   separate .ldata section which mapped after normal .data and .text, but I | 
|  | //   don't really know how this must be done for M68k atm... will try to dig | 
|  | //   this info out from GCC. For now CPUs prior to M68020 will use static ref | 
|  | //   for Static Model and @GOT based references for PIC. | 
|  | // | 
|  | // ~ These are absolute for older CPUs for now. | 
|  | // ^ These are @GOTOFF for older CPUs for now. | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | /// Classify a blockaddress reference for the current subtarget according to how | 
|  | /// we should reference it in a non-pcrel context. | 
|  | unsigned char M68kSubtarget::classifyBlockAddressReference() const { | 
|  | switch (TM.getCodeModel()) { | 
|  | default: | 
|  | llvm_unreachable("Unsupported code model"); | 
|  | case CodeModel::Small: | 
|  | case CodeModel::Kernel: | 
|  | case CodeModel::Medium: { | 
|  | return M68kII::MO_PC_RELATIVE_ADDRESS; | 
|  | } | 
|  | case CodeModel::Large: { | 
|  | if (isPositionIndependent()) { | 
|  | return M68kII::MO_PC_RELATIVE_ADDRESS; | 
|  | } else { | 
|  | return M68kII::MO_ABSOLUTE_ADDRESS; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | unsigned char | 
|  | M68kSubtarget::classifyLocalReference(const GlobalValue *GV) const { | 
|  | switch (TM.getCodeModel()) { | 
|  | default: | 
|  | llvm_unreachable("Unsupported code model"); | 
|  | case CodeModel::Small: | 
|  | case CodeModel::Kernel: { | 
|  | return M68kII::MO_PC_RELATIVE_ADDRESS; | 
|  | } | 
|  | case CodeModel::Medium: { | 
|  | if (isPositionIndependent()) { | 
|  | // On M68020 and better we can fit big any data offset into dips field. | 
|  | if (atLeastM68020()) { | 
|  | return M68kII::MO_PC_RELATIVE_ADDRESS; | 
|  | } | 
|  | // Otherwise we could check the data size and make sure it will fit into | 
|  | // 16 bit offset. For now we will be conservative and go with @GOTOFF | 
|  | return M68kII::MO_GOTOFF; | 
|  | } else { | 
|  | if (atLeastM68020()) { | 
|  | return M68kII::MO_PC_RELATIVE_ADDRESS; | 
|  | } | 
|  | return M68kII::MO_ABSOLUTE_ADDRESS; | 
|  | } | 
|  | } | 
|  | case CodeModel::Large: { | 
|  | if (isPositionIndependent()) { | 
|  | return M68kII::MO_GOTOFF; | 
|  | } else { | 
|  | return M68kII::MO_ABSOLUTE_ADDRESS; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | unsigned char M68kSubtarget::classifyExternalReference(const Module &M) const { | 
|  | if (TM.shouldAssumeDSOLocal(nullptr)) | 
|  | return classifyLocalReference(nullptr); | 
|  |  | 
|  | if (isPositionIndependent()) | 
|  | return M68kII::MO_GOTPCREL; | 
|  |  | 
|  | return M68kII::MO_GOT; | 
|  | } | 
|  |  | 
|  | unsigned char | 
|  | M68kSubtarget::classifyGlobalReference(const GlobalValue *GV) const { | 
|  | return classifyGlobalReference(GV, *GV->getParent()); | 
|  | } | 
|  |  | 
|  | unsigned char M68kSubtarget::classifyGlobalReference(const GlobalValue *GV, | 
|  | const Module &M) const { | 
|  | if (TM.shouldAssumeDSOLocal(GV)) | 
|  | return classifyLocalReference(GV); | 
|  |  | 
|  | switch (TM.getCodeModel()) { | 
|  | default: | 
|  | llvm_unreachable("Unsupported code model"); | 
|  | case CodeModel::Small: | 
|  | case CodeModel::Kernel: { | 
|  | if (isPositionIndependent()) | 
|  | return M68kII::MO_GOTPCREL; | 
|  | return M68kII::MO_PC_RELATIVE_ADDRESS; | 
|  | } | 
|  | case CodeModel::Medium: { | 
|  | if (isPositionIndependent()) | 
|  | return M68kII::MO_GOTPCREL; | 
|  |  | 
|  | if (atLeastM68020()) | 
|  | return M68kII::MO_PC_RELATIVE_ADDRESS; | 
|  |  | 
|  | return M68kII::MO_ABSOLUTE_ADDRESS; | 
|  | } | 
|  | case CodeModel::Large: { | 
|  | if (isPositionIndependent()) | 
|  | return M68kII::MO_GOTOFF; | 
|  |  | 
|  | return M68kII::MO_ABSOLUTE_ADDRESS; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | unsigned M68kSubtarget::getJumpTableEncoding() const { | 
|  | if (isPositionIndependent()) { | 
|  | // The only time we want to use GOTOFF(used when with EK_Custom32) is when | 
|  | // the potential delta between the jump target and table base can be larger | 
|  | // than displacement field, which is True for older CPUs(16 bit disp) | 
|  | // in Medium model(can have large data way beyond 16 bit). | 
|  | if ((TM.getCodeModel() == CodeModel::Medium && !atLeastM68020()) || | 
|  | TM.getCodeModel() == CodeModel::Large) | 
|  | return MachineJumpTableInfo::EK_Custom32; | 
|  |  | 
|  | return MachineJumpTableInfo::EK_LabelDifference32; | 
|  | } | 
|  |  | 
|  | // In non-pic modes, just use the address of a block. | 
|  | return MachineJumpTableInfo::EK_BlockAddress; | 
|  | } | 
|  |  | 
|  | unsigned char | 
|  | M68kSubtarget::classifyGlobalFunctionReference(const GlobalValue *GV) const { | 
|  | return classifyGlobalFunctionReference(GV, *GV->getParent()); | 
|  | } | 
|  |  | 
|  | unsigned char | 
|  | M68kSubtarget::classifyGlobalFunctionReference(const GlobalValue *GV, | 
|  | const Module &M) const { | 
|  | // local always use pc-rel referencing | 
|  | if (TM.shouldAssumeDSOLocal(GV)) | 
|  | return M68kII::MO_NO_FLAG; | 
|  |  | 
|  | // If the function is marked as non-lazy, generate an indirect call | 
|  | // which loads from the GOT directly. This avoids run-time overhead | 
|  | // at the cost of eager binding. | 
|  | auto *F = dyn_cast_or_null<Function>(GV); | 
|  | if (F && F->hasFnAttribute(Attribute::NonLazyBind)) { | 
|  | return M68kII::MO_GOTPCREL; | 
|  | } | 
|  |  | 
|  | // Ensure that we don't emit PLT relocations when in non-pic modes. | 
|  | return isPositionIndependent() ? M68kII::MO_PLT : M68kII::MO_ABSOLUTE_ADDRESS; | 
|  | } |