310 lines · cpp
1//===-- M68kSubtarget.cpp - M68k Subtarget Information ----------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// This file implements the M68k specific subclass of TargetSubtargetInfo.11///12//===----------------------------------------------------------------------===//13 14#include "M68kSubtarget.h"15#include "GISel/M68kCallLowering.h"16#include "GISel/M68kLegalizerInfo.h"17#include "GISel/M68kRegisterBankInfo.h"18#include "M68k.h"19#include "M68kMachineFunction.h"20#include "M68kRegisterInfo.h"21#include "M68kSelectionDAGInfo.h"22#include "M68kTargetMachine.h"23#include "llvm/CodeGen/MachineJumpTableInfo.h"24#include "llvm/IR/Attributes.h"25#include "llvm/IR/Function.h"26#include "llvm/MC/TargetRegistry.h"27#include "llvm/Support/CommandLine.h"28#include "llvm/Support/ErrorHandling.h"29 30using namespace llvm;31 32#define DEBUG_TYPE "m68k-subtarget"33 34#define GET_SUBTARGETINFO_TARGET_DESC35#define GET_SUBTARGETINFO_CTOR36#include "M68kGenSubtargetInfo.inc"37 38extern bool FixGlobalBaseReg;39 40/// Select the M68k CPU for the given triple and cpu name.41static StringRef selectM68kCPU(Triple TT, StringRef CPU) {42 if (CPU.empty() || CPU == "generic") {43 CPU = "M68000";44 }45 return CPU;46}47 48void M68kSubtarget::anchor() {}49 50M68kSubtarget::M68kSubtarget(const Triple &TT, StringRef CPU, StringRef FS,51 const M68kTargetMachine &TM)52 : M68kGenSubtargetInfo(TT, CPU, /*TuneCPU*/ CPU, FS), TM(TM),53 InstrInfo(initializeSubtargetDependencies(CPU, TT, FS, TM)),54 FrameLowering(*this, this->getStackAlignment()), TLInfo(TM, *this),55 TargetTriple(TT) {56 TSInfo = std::make_unique<M68kSelectionDAGInfo>();57 58 CallLoweringInfo.reset(new M68kCallLowering(*getTargetLowering()));59 Legalizer.reset(new M68kLegalizerInfo(*this));60 61 auto *RBI = new M68kRegisterBankInfo(*getRegisterInfo());62 RegBankInfo.reset(RBI);63 InstSelector.reset(createM68kInstructionSelector(TM, *this, *RBI));64}65 66M68kSubtarget::~M68kSubtarget() = default;67 68const SelectionDAGTargetInfo *M68kSubtarget::getSelectionDAGInfo() const {69 return TSInfo.get();70}71 72const CallLowering *M68kSubtarget::getCallLowering() const {73 return CallLoweringInfo.get();74}75 76InstructionSelector *M68kSubtarget::getInstructionSelector() const {77 return InstSelector.get();78}79 80const LegalizerInfo *M68kSubtarget::getLegalizerInfo() const {81 return Legalizer.get();82}83 84const RegisterBankInfo *M68kSubtarget::getRegBankInfo() const {85 return RegBankInfo.get();86}87 88bool M68kSubtarget::isPositionIndependent() const {89 return TM.isPositionIndependent();90}91 92bool M68kSubtarget::isLegalToCallImmediateAddr() const { return true; }93 94M68kSubtarget &M68kSubtarget::initializeSubtargetDependencies(95 StringRef CPU, Triple TT, StringRef FS, const M68kTargetMachine &TM) {96 std::string CPUName = selectM68kCPU(TT, CPU).str();97 98 // Parse features string.99 ParseSubtargetFeatures(CPUName, CPUName, FS);100 101 // Initialize scheduling itinerary for the specified CPU.102 InstrItins = getInstrItineraryForCPU(CPUName);103 104 stackAlignment = 8;105 106 return *this;107}108 109//===----------------------------------------------------------------------===//110// Code Model111//112// Key assumptions:113// - Whenever possible we use pc-rel encoding since it is smaller(16 bit) than114// absolute(32 bit).115// - GOT is reachable within 16 bit offset for both Small and Medium models.116// - Code section is reachable within 16 bit offset for both models.117//118// ---------------------+-------------------------+--------------------------119// | Small | Medium120// +-------------------------+------------+-------------121// | Static | PIC | Static | PIC122// ---------------------+------------+------------+------------+-------------123// branch | pc-rel | pc-rel | pc-rel | pc-rel124// ---------------------+------------+------------+------------+-------------125// call global | absolute | @PLT | absolute | @PLT126// ---------------------+------------+------------+------------+-------------127// call internal | pc-rel | pc-rel | pc-rel | pc-rel128// ---------------------+------------+------------+------------+-------------129// data local | pc-rel | pc-rel | ~pc-rel | ^pc-rel130// ---------------------+------------+------------+------------+-------------131// data local big* | pc-rel | pc-rel | absolute | @GOTOFF132// ---------------------+------------+------------+------------+-------------133// data global | pc-rel | @GOTPCREL | ~pc-rel | @GOTPCREL134// ---------------------+------------+------------+------------+-------------135// data global big* | pc-rel | @GOTPCREL | absolute | @GOTPCREL136// ---------------------+------------+------------+------------+-------------137// | Large |138// +-------------------------+139// | Static | PIC |140// ---------------------+------------+------------+141// branch | absolute | pc-rel |142// ---------------------+------------+------------+143// call global | absolute | @PLT |144// ---------------------+------------+------------+145// call internal | absolute | pc-rel |146// ---------------------+------------+------------+147// data local | absolute | @GOTOFF |148// ---------------------+------------+------------+149// data local big* | absolute | @GOTOFF |150// ---------------------+------------+------------+151// data global | absolute | @GOTOFF |152// ---------------------+------------+------------+153// data global big* | absolute | @GOTOFF |154// ---------------------+------------+------------+155//156// * Big data potentially cannot be reached within 16 bit offset and requires157// special handling for old(x00 and x10) CPUs. Normally these symbols go into158// separate .ldata section which mapped after normal .data and .text, but I159// don't really know how this must be done for M68k atm... will try to dig160// this info out from GCC. For now CPUs prior to M68020 will use static ref161// for Static Model and @GOT based references for PIC.162//163// ~ These are absolute for older CPUs for now.164// ^ These are @GOTOFF for older CPUs for now.165//===----------------------------------------------------------------------===//166 167/// Classify a blockaddress reference for the current subtarget according to how168/// we should reference it in a non-pcrel context.169unsigned char M68kSubtarget::classifyBlockAddressReference() const {170 switch (TM.getCodeModel()) {171 default:172 llvm_unreachable("Unsupported code model");173 case CodeModel::Small:174 case CodeModel::Kernel:175 case CodeModel::Medium: {176 return M68kII::MO_PC_RELATIVE_ADDRESS;177 }178 case CodeModel::Large: {179 if (isPositionIndependent()) {180 return M68kII::MO_PC_RELATIVE_ADDRESS;181 } else {182 return M68kII::MO_ABSOLUTE_ADDRESS;183 }184 }185 }186}187 188unsigned char189M68kSubtarget::classifyLocalReference(const GlobalValue *GV) const {190 switch (TM.getCodeModel()) {191 default:192 llvm_unreachable("Unsupported code model");193 case CodeModel::Small:194 case CodeModel::Kernel: {195 return M68kII::MO_PC_RELATIVE_ADDRESS;196 }197 case CodeModel::Medium: {198 if (isPositionIndependent()) {199 // On M68020 and better we can fit big any data offset into dips field.200 if (atLeastM68020()) {201 return M68kII::MO_PC_RELATIVE_ADDRESS;202 }203 // Otherwise we could check the data size and make sure it will fit into204 // 16 bit offset. For now we will be conservative and go with @GOTOFF205 return M68kII::MO_GOTOFF;206 } else {207 if (atLeastM68020()) {208 return M68kII::MO_PC_RELATIVE_ADDRESS;209 }210 return M68kII::MO_ABSOLUTE_ADDRESS;211 }212 }213 case CodeModel::Large: {214 if (isPositionIndependent()) {215 return M68kII::MO_GOTOFF;216 } else {217 return M68kII::MO_ABSOLUTE_ADDRESS;218 }219 }220 }221}222 223unsigned char M68kSubtarget::classifyExternalReference(const Module &M) const {224 if (TM.shouldAssumeDSOLocal(nullptr))225 return classifyLocalReference(nullptr);226 227 if (isPositionIndependent())228 return M68kII::MO_GOTPCREL;229 230 return M68kII::MO_GOT;231}232 233unsigned char234M68kSubtarget::classifyGlobalReference(const GlobalValue *GV) const {235 return classifyGlobalReference(GV, *GV->getParent());236}237 238unsigned char M68kSubtarget::classifyGlobalReference(const GlobalValue *GV,239 const Module &M) const {240 if (TM.shouldAssumeDSOLocal(GV))241 return classifyLocalReference(GV);242 243 switch (TM.getCodeModel()) {244 default:245 llvm_unreachable("Unsupported code model");246 case CodeModel::Small:247 case CodeModel::Kernel: {248 if (isPositionIndependent())249 return M68kII::MO_GOTPCREL;250 return M68kII::MO_PC_RELATIVE_ADDRESS;251 }252 case CodeModel::Medium: {253 if (isPositionIndependent())254 return M68kII::MO_GOTPCREL;255 256 if (atLeastM68020())257 return M68kII::MO_PC_RELATIVE_ADDRESS;258 259 return M68kII::MO_ABSOLUTE_ADDRESS;260 }261 case CodeModel::Large: {262 if (isPositionIndependent())263 return M68kII::MO_GOTOFF;264 265 return M68kII::MO_ABSOLUTE_ADDRESS;266 }267 }268}269 270unsigned M68kSubtarget::getJumpTableEncoding() const {271 if (isPositionIndependent()) {272 // The only time we want to use GOTOFF(used when with EK_Custom32) is when273 // the potential delta between the jump target and table base can be larger274 // than displacement field, which is True for older CPUs(16 bit disp)275 // in Medium model(can have large data way beyond 16 bit).276 if ((TM.getCodeModel() == CodeModel::Medium && !atLeastM68020()) ||277 TM.getCodeModel() == CodeModel::Large)278 return MachineJumpTableInfo::EK_Custom32;279 280 return MachineJumpTableInfo::EK_LabelDifference32;281 }282 283 // In non-pic modes, just use the address of a block.284 return MachineJumpTableInfo::EK_BlockAddress;285}286 287unsigned char288M68kSubtarget::classifyGlobalFunctionReference(const GlobalValue *GV) const {289 return classifyGlobalFunctionReference(GV, *GV->getParent());290}291 292unsigned char293M68kSubtarget::classifyGlobalFunctionReference(const GlobalValue *GV,294 const Module &M) const {295 // local always use pc-rel referencing296 if (TM.shouldAssumeDSOLocal(GV))297 return M68kII::MO_NO_FLAG;298 299 // If the function is marked as non-lazy, generate an indirect call300 // which loads from the GOT directly. This avoids run-time overhead301 // at the cost of eager binding.302 auto *F = dyn_cast_or_null<Function>(GV);303 if (F && F->hasFnAttribute(Attribute::NonLazyBind)) {304 return M68kII::MO_GOTPCREL;305 }306 307 // Ensure that we don't emit PLT relocations when in non-pic modes.308 return isPositionIndependent() ? M68kII::MO_PLT : M68kII::MO_ABSOLUTE_ADDRESS;309}310