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