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-exception 6// 7//===----------------------------------------------------------------------===// 8/// 9/// \file 10/// 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 19#include "M68k.h" 20#include "M68kMachineFunction.h" 21#include "M68kRegisterInfo.h" 22#include "M68kTargetMachine.h" 23 24#include "llvm/CodeGen/MachineJumpTableInfo.h" 25#include "llvm/IR/Attributes.h" 26#include "llvm/IR/Function.h" 27#include "llvm/MC/TargetRegistry.h" 28#include "llvm/Support/CommandLine.h" 29#include "llvm/Support/ErrorHandling.h" 30 31using namespace llvm; 32 33#define DEBUG_TYPE "m68k-subtarget" 34 35#define GET_SUBTARGETINFO_TARGET_DESC 36#define GET_SUBTARGETINFO_CTOR 37#include "M68kGenSubtargetInfo.inc" 38 39extern bool FixGlobalBaseReg; 40 41/// Select the M68k CPU for the given triple and cpu name. 42static StringRef selectM68kCPU(Triple TT, StringRef CPU) { 43 if (CPU.empty() || CPU == "generic") { 44 CPU = "M68000"; 45 } 46 return CPU; 47} 48 49void M68kSubtarget::anchor() {} 50 51M68kSubtarget::M68kSubtarget(const Triple &TT, StringRef CPU, StringRef FS, 52 const M68kTargetMachine &TM) 53 : M68kGenSubtargetInfo(TT, CPU, /*TuneCPU*/ CPU, FS), TM(TM), TSInfo(), 54 InstrInfo(initializeSubtargetDependencies(CPU, TT, FS, TM)), 55 FrameLowering(*this, this->getStackAlignment()), TLInfo(TM, *this), 56 TargetTriple(TT) { 57 CallLoweringInfo.reset(new M68kCallLowering(*getTargetLowering())); 58 Legalizer.reset(new M68kLegalizerInfo(*this)); 59 60 auto *RBI = new M68kRegisterBankInfo(*getRegisterInfo()); 61 RegBankInfo.reset(RBI); 62 InstSelector.reset(createM68kInstructionSelector(TM, *this, *RBI)); 63} 64 65const CallLowering *M68kSubtarget::getCallLowering() const { 66 return CallLoweringInfo.get(); 67} 68 69InstructionSelector *M68kSubtarget::getInstructionSelector() const { 70 return InstSelector.get(); 71} 72 73const LegalizerInfo *M68kSubtarget::getLegalizerInfo() const { 74 return Legalizer.get(); 75} 76 77const RegisterBankInfo *M68kSubtarget::getRegBankInfo() const { 78 return RegBankInfo.get(); 79} 80 81bool M68kSubtarget::isPositionIndependent() const { 82 return TM.isPositionIndependent(); 83} 84 85bool M68kSubtarget::isLegalToCallImmediateAddr() const { return true; } 86 87M68kSubtarget &M68kSubtarget::initializeSubtargetDependencies( 88 StringRef CPU, Triple TT, StringRef FS, const M68kTargetMachine &TM) { 89 std::string CPUName = selectM68kCPU(TT, CPU).str(); 90 91 // Parse features string. 92 ParseSubtargetFeatures(CPUName, CPUName, FS); 93 94 // Initialize scheduling itinerary for the specified CPU. 95 InstrItins = getInstrItineraryForCPU(CPUName); 96 97 stackAlignment = 8; 98 99 return *this; 100} 101 102//===----------------------------------------------------------------------===// 103// Code Model 104// 105// Key assumptions: 106// - Whenever possible we use pc-rel encoding since it is smaller(16 bit) than 107// absolute(32 bit). 108// - GOT is reachable within 16 bit offset for both Small and Medium models. 109// - Code section is reachable within 16 bit offset for both models. 110// 111// ---------------------+-------------------------+-------------------------- 112// | Small | Medium 113// +-------------------------+------------+------------- 114// | Static | PIC | Static | PIC 115// ---------------------+------------+------------+------------+------------- 116// branch | pc-rel | pc-rel | pc-rel | pc-rel 117// ---------------------+------------+------------+------------+------------- 118// call global | @PLT | @PLT | @PLT | @PLT 119// ---------------------+------------+------------+------------+------------- 120// call internal | pc-rel | pc-rel | pc-rel | pc-rel 121// ---------------------+------------+------------+------------+------------- 122// data local | pc-rel | pc-rel | ~pc-rel | ^pc-rel 123// ---------------------+------------+------------+------------+------------- 124// data local big* | pc-rel | pc-rel | absolute | @GOTOFF 125// ---------------------+------------+------------+------------+------------- 126// data global | pc-rel | @GOTPCREL | ~pc-rel | @GOTPCREL 127// ---------------------+------------+------------+------------+------------- 128// data global big* | pc-rel | @GOTPCREL | absolute | @GOTPCREL 129// ---------------------+------------+------------+------------+------------- 130// 131// * Big data potentially cannot be reached within 16 bit offset and requires 132// special handling for old(x00 and x10) CPUs. Normally these symbols go into 133// separate .ldata section which mapped after normal .data and .text, but I 134// don't really know how this must be done for M68k atm... will try to dig 135// this info out from GCC. For now CPUs prior to M68020 will use static ref 136// for Static Model and @GOT based references for PIC. 137// 138// ~ These are absolute for older CPUs for now. 139// ^ These are @GOTOFF for older CPUs for now. 140//===----------------------------------------------------------------------===// 141 142/// Classify a blockaddress reference for the current subtarget according to how 143/// we should reference it in a non-pcrel context. 144unsigned char M68kSubtarget::classifyBlockAddressReference() const { 145 // Unless we start to support Large Code Model branching is always pc-rel 146 return M68kII::MO_PC_RELATIVE_ADDRESS; 147} 148 149unsigned char 150M68kSubtarget::classifyLocalReference(const GlobalValue *GV) const { 151 switch (TM.getCodeModel()) { 152 default: 153 llvm_unreachable("Unsupported code model"); 154 case CodeModel::Small: 155 case CodeModel::Kernel: { 156 return M68kII::MO_PC_RELATIVE_ADDRESS; 157 } 158 case CodeModel::Medium: { 159 if (isPositionIndependent()) { 160 // On M68020 and better we can fit big any data offset into dips field. 161 if (atLeastM68020()) { 162 return M68kII::MO_PC_RELATIVE_ADDRESS; 163 } 164 // Otherwise we could check the data size and make sure it will fit into 165 // 16 bit offset. For now we will be conservative and go with @GOTOFF 166 return M68kII::MO_GOTOFF; 167 } else { 168 if (atLeastM68020()) { 169 return M68kII::MO_PC_RELATIVE_ADDRESS; 170 } 171 return M68kII::MO_ABSOLUTE_ADDRESS; 172 } 173 } 174 } 175} 176 177unsigned char M68kSubtarget::classifyExternalReference(const Module &M) const { 178 if (TM.shouldAssumeDSOLocal(M, nullptr)) 179 return classifyLocalReference(nullptr); 180 181 if (isPositionIndependent()) 182 return M68kII::MO_GOTPCREL; 183 184 return M68kII::MO_GOT; 185} 186 187unsigned char 188M68kSubtarget::classifyGlobalReference(const GlobalValue *GV) const { 189 return classifyGlobalReference(GV, *GV->getParent()); 190} 191 192unsigned char M68kSubtarget::classifyGlobalReference(const GlobalValue *GV, 193 const Module &M) const { 194 if (TM.shouldAssumeDSOLocal(M, GV)) 195 return classifyLocalReference(GV); 196 197 switch (TM.getCodeModel()) { 198 default: 199 llvm_unreachable("Unsupported code model"); 200 case CodeModel::Small: 201 case CodeModel::Kernel: { 202 if (isPositionIndependent()) 203 return M68kII::MO_GOTPCREL; 204 return M68kII::MO_PC_RELATIVE_ADDRESS; 205 } 206 case CodeModel::Medium: { 207 if (isPositionIndependent()) 208 return M68kII::MO_GOTPCREL; 209 210 if (atLeastM68020()) 211 return M68kII::MO_PC_RELATIVE_ADDRESS; 212 213 return M68kII::MO_ABSOLUTE_ADDRESS; 214 } 215 } 216} 217 218unsigned M68kSubtarget::getJumpTableEncoding() const { 219 if (isPositionIndependent()) { 220 // The only time we want to use GOTOFF(used when with EK_Custom32) is when 221 // the potential delta between the jump target and table base can be larger 222 // than displacement field, which is True for older CPUs(16 bit disp) 223 // in Medium model(can have large data way beyond 16 bit). 224 if (TM.getCodeModel() == CodeModel::Medium && !atLeastM68020()) 225 return MachineJumpTableInfo::EK_Custom32; 226 227 return MachineJumpTableInfo::EK_LabelDifference32; 228 } 229 230 // In non-pic modes, just use the address of a block. 231 return MachineJumpTableInfo::EK_BlockAddress; 232} 233 234unsigned char 235M68kSubtarget::classifyGlobalFunctionReference(const GlobalValue *GV) const { 236 return classifyGlobalFunctionReference(GV, *GV->getParent()); 237} 238 239unsigned char 240M68kSubtarget::classifyGlobalFunctionReference(const GlobalValue *GV, 241 const Module &M) const { 242 // local always use pc-rel referencing 243 if (TM.shouldAssumeDSOLocal(M, GV)) 244 return M68kII::MO_NO_FLAG; 245 246 // If the function is marked as non-lazy, generate an indirect call 247 // which loads from the GOT directly. This avoids run-time overhead 248 // at the cost of eager binding. 249 auto *F = dyn_cast_or_null<Function>(GV); 250 if (F && F->hasFnAttribute(Attribute::NonLazyBind)) { 251 return M68kII::MO_GOTPCREL; 252 } 253 254 // otherwise linker will figure this out 255 return M68kII::MO_PLT; 256} 257