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