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