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