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 31 using 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 39 extern bool FixGlobalBaseReg; 40 41 /// Select the M68k CPU for the given triple and cpu name. 42 static StringRef selectM68kCPU(Triple TT, StringRef CPU) { 43 if (CPU.empty() || CPU == "generic") { 44 CPU = "M68000"; 45 } 46 return CPU; 47 } 48 49 void M68kSubtarget::anchor() {} 50 51 M68kSubtarget::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 65 const CallLowering *M68kSubtarget::getCallLowering() const { 66 return CallLoweringInfo.get(); 67 } 68 69 InstructionSelector *M68kSubtarget::getInstructionSelector() const { 70 return InstSelector.get(); 71 } 72 73 const LegalizerInfo *M68kSubtarget::getLegalizerInfo() const { 74 return Legalizer.get(); 75 } 76 77 const RegisterBankInfo *M68kSubtarget::getRegBankInfo() const { 78 return RegBankInfo.get(); 79 } 80 81 bool M68kSubtarget::isPositionIndependent() const { 82 return TM.isPositionIndependent(); 83 } 84 85 bool M68kSubtarget::isLegalToCallImmediateAddr() const { return true; } 86 87 M68kSubtarget &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 | absolute | @PLT | absolute | @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 // | Large | 131 // +-------------------------+ 132 // | Static | PIC | 133 // ---------------------+------------+------------+ 134 // branch | absolute | pc-rel | 135 // ---------------------+------------+------------+ 136 // call global | absolute | @PLT | 137 // ---------------------+------------+------------+ 138 // call internal | absolute | pc-rel | 139 // ---------------------+------------+------------+ 140 // data local | absolute | @GOTOFF | 141 // ---------------------+------------+------------+ 142 // data local big* | absolute | @GOTOFF | 143 // ---------------------+------------+------------+ 144 // data global | absolute | @GOTOFF | 145 // ---------------------+------------+------------+ 146 // data global big* | absolute | @GOTOFF | 147 // ---------------------+------------+------------+ 148 // 149 // * Big data potentially cannot be reached within 16 bit offset and requires 150 // special handling for old(x00 and x10) CPUs. Normally these symbols go into 151 // separate .ldata section which mapped after normal .data and .text, but I 152 // don't really know how this must be done for M68k atm... will try to dig 153 // this info out from GCC. For now CPUs prior to M68020 will use static ref 154 // for Static Model and @GOT based references for PIC. 155 // 156 // ~ These are absolute for older CPUs for now. 157 // ^ These are @GOTOFF for older CPUs for now. 158 //===----------------------------------------------------------------------===// 159 160 /// Classify a blockaddress reference for the current subtarget according to how 161 /// we should reference it in a non-pcrel context. 162 unsigned char M68kSubtarget::classifyBlockAddressReference() const { 163 switch (TM.getCodeModel()) { 164 default: 165 llvm_unreachable("Unsupported code model"); 166 case CodeModel::Small: 167 case CodeModel::Kernel: 168 case CodeModel::Medium: { 169 return M68kII::MO_PC_RELATIVE_ADDRESS; 170 } 171 case CodeModel::Large: { 172 if (isPositionIndependent()) { 173 return M68kII::MO_PC_RELATIVE_ADDRESS; 174 } else { 175 return M68kII::MO_ABSOLUTE_ADDRESS; 176 } 177 } 178 } 179 } 180 181 unsigned char 182 M68kSubtarget::classifyLocalReference(const GlobalValue *GV) const { 183 switch (TM.getCodeModel()) { 184 default: 185 llvm_unreachable("Unsupported code model"); 186 case CodeModel::Small: 187 case CodeModel::Kernel: { 188 return M68kII::MO_PC_RELATIVE_ADDRESS; 189 } 190 case CodeModel::Medium: { 191 if (isPositionIndependent()) { 192 // On M68020 and better we can fit big any data offset into dips field. 193 if (atLeastM68020()) { 194 return M68kII::MO_PC_RELATIVE_ADDRESS; 195 } 196 // Otherwise we could check the data size and make sure it will fit into 197 // 16 bit offset. For now we will be conservative and go with @GOTOFF 198 return M68kII::MO_GOTOFF; 199 } else { 200 if (atLeastM68020()) { 201 return M68kII::MO_PC_RELATIVE_ADDRESS; 202 } 203 return M68kII::MO_ABSOLUTE_ADDRESS; 204 } 205 } 206 case CodeModel::Large: { 207 if (isPositionIndependent()) { 208 return M68kII::MO_GOTOFF; 209 } else { 210 return M68kII::MO_ABSOLUTE_ADDRESS; 211 } 212 } 213 } 214 } 215 216 unsigned char M68kSubtarget::classifyExternalReference(const Module &M) const { 217 if (TM.shouldAssumeDSOLocal(nullptr)) 218 return classifyLocalReference(nullptr); 219 220 if (isPositionIndependent()) 221 return M68kII::MO_GOTPCREL; 222 223 return M68kII::MO_GOT; 224 } 225 226 unsigned char 227 M68kSubtarget::classifyGlobalReference(const GlobalValue *GV) const { 228 return classifyGlobalReference(GV, *GV->getParent()); 229 } 230 231 unsigned char M68kSubtarget::classifyGlobalReference(const GlobalValue *GV, 232 const Module &M) const { 233 if (TM.shouldAssumeDSOLocal(GV)) 234 return classifyLocalReference(GV); 235 236 switch (TM.getCodeModel()) { 237 default: 238 llvm_unreachable("Unsupported code model"); 239 case CodeModel::Small: 240 case CodeModel::Kernel: { 241 if (isPositionIndependent()) 242 return M68kII::MO_GOTPCREL; 243 return M68kII::MO_PC_RELATIVE_ADDRESS; 244 } 245 case CodeModel::Medium: { 246 if (isPositionIndependent()) 247 return M68kII::MO_GOTPCREL; 248 249 if (atLeastM68020()) 250 return M68kII::MO_PC_RELATIVE_ADDRESS; 251 252 return M68kII::MO_ABSOLUTE_ADDRESS; 253 } 254 case CodeModel::Large: { 255 if (isPositionIndependent()) 256 return M68kII::MO_GOTOFF; 257 258 return M68kII::MO_ABSOLUTE_ADDRESS; 259 } 260 } 261 } 262 263 unsigned M68kSubtarget::getJumpTableEncoding() const { 264 if (isPositionIndependent()) { 265 // The only time we want to use GOTOFF(used when with EK_Custom32) is when 266 // the potential delta between the jump target and table base can be larger 267 // than displacement field, which is True for older CPUs(16 bit disp) 268 // in Medium model(can have large data way beyond 16 bit). 269 if ((TM.getCodeModel() == CodeModel::Medium && !atLeastM68020()) || 270 TM.getCodeModel() == CodeModel::Large) 271 return MachineJumpTableInfo::EK_Custom32; 272 273 return MachineJumpTableInfo::EK_LabelDifference32; 274 } 275 276 // In non-pic modes, just use the address of a block. 277 return MachineJumpTableInfo::EK_BlockAddress; 278 } 279 280 unsigned char 281 M68kSubtarget::classifyGlobalFunctionReference(const GlobalValue *GV) const { 282 return classifyGlobalFunctionReference(GV, *GV->getParent()); 283 } 284 285 unsigned char 286 M68kSubtarget::classifyGlobalFunctionReference(const GlobalValue *GV, 287 const Module &M) const { 288 // local always use pc-rel referencing 289 if (TM.shouldAssumeDSOLocal(GV)) 290 return M68kII::MO_NO_FLAG; 291 292 // If the function is marked as non-lazy, generate an indirect call 293 // which loads from the GOT directly. This avoids run-time overhead 294 // at the cost of eager binding. 295 auto *F = dyn_cast_or_null<Function>(GV); 296 if (F && F->hasFnAttribute(Attribute::NonLazyBind)) { 297 return M68kII::MO_GOTPCREL; 298 } 299 300 // Ensure that we don't emit PLT relocations when in non-pic modes. 301 return isPositionIndependent() ? M68kII::MO_PLT : M68kII::MO_ABSOLUTE_ADDRESS; 302 } 303