xref: /openbsd-src/gnu/llvm/llvm/lib/Target/M68k/M68kSubtarget.cpp (revision d415bd752c734aee168c4ee86ff32e8cc249eb16)
1*d415bd75Srobert //===-- M68kSubtarget.cpp - M68k Subtarget Information ----------*- C++ -*-===//
273471bf0Spatrick //
373471bf0Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
473471bf0Spatrick // See https://llvm.org/LICENSE.txt for license information.
573471bf0Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
673471bf0Spatrick //
773471bf0Spatrick //===----------------------------------------------------------------------===//
873471bf0Spatrick ///
973471bf0Spatrick /// \file
1073471bf0Spatrick /// This file implements the M68k specific subclass of TargetSubtargetInfo.
1173471bf0Spatrick ///
1273471bf0Spatrick //===----------------------------------------------------------------------===//
1373471bf0Spatrick 
1473471bf0Spatrick #include "M68kSubtarget.h"
15*d415bd75Srobert #include "GISel/M68kCallLowering.h"
16*d415bd75Srobert #include "GISel/M68kLegalizerInfo.h"
17*d415bd75Srobert #include "GISel/M68kRegisterBankInfo.h"
1873471bf0Spatrick 
1973471bf0Spatrick #include "M68k.h"
2073471bf0Spatrick #include "M68kMachineFunction.h"
2173471bf0Spatrick #include "M68kRegisterInfo.h"
2273471bf0Spatrick #include "M68kTargetMachine.h"
2373471bf0Spatrick 
2473471bf0Spatrick #include "llvm/CodeGen/MachineJumpTableInfo.h"
2573471bf0Spatrick #include "llvm/IR/Attributes.h"
2673471bf0Spatrick #include "llvm/IR/Function.h"
27*d415bd75Srobert #include "llvm/MC/TargetRegistry.h"
2873471bf0Spatrick #include "llvm/Support/CommandLine.h"
2973471bf0Spatrick #include "llvm/Support/ErrorHandling.h"
3073471bf0Spatrick 
3173471bf0Spatrick using namespace llvm;
3273471bf0Spatrick 
3373471bf0Spatrick #define DEBUG_TYPE "m68k-subtarget"
3473471bf0Spatrick 
3573471bf0Spatrick #define GET_SUBTARGETINFO_TARGET_DESC
3673471bf0Spatrick #define GET_SUBTARGETINFO_CTOR
3773471bf0Spatrick #include "M68kGenSubtargetInfo.inc"
3873471bf0Spatrick 
3973471bf0Spatrick extern bool FixGlobalBaseReg;
4073471bf0Spatrick 
4173471bf0Spatrick /// Select the M68k CPU for the given triple and cpu name.
selectM68kCPU(Triple TT,StringRef CPU)4273471bf0Spatrick static StringRef selectM68kCPU(Triple TT, StringRef CPU) {
4373471bf0Spatrick   if (CPU.empty() || CPU == "generic") {
4473471bf0Spatrick     CPU = "M68000";
4573471bf0Spatrick   }
4673471bf0Spatrick   return CPU;
4773471bf0Spatrick }
4873471bf0Spatrick 
anchor()4973471bf0Spatrick void M68kSubtarget::anchor() {}
5073471bf0Spatrick 
M68kSubtarget(const Triple & TT,StringRef CPU,StringRef FS,const M68kTargetMachine & TM)5173471bf0Spatrick M68kSubtarget::M68kSubtarget(const Triple &TT, StringRef CPU, StringRef FS,
5273471bf0Spatrick                              const M68kTargetMachine &TM)
53*d415bd75Srobert     : M68kGenSubtargetInfo(TT, CPU, /*TuneCPU*/ CPU, FS), TM(TM), TSInfo(),
5473471bf0Spatrick       InstrInfo(initializeSubtargetDependencies(CPU, TT, FS, TM)),
5573471bf0Spatrick       FrameLowering(*this, this->getStackAlignment()), TLInfo(TM, *this),
5673471bf0Spatrick       TargetTriple(TT) {
5773471bf0Spatrick   CallLoweringInfo.reset(new M68kCallLowering(*getTargetLowering()));
5873471bf0Spatrick   Legalizer.reset(new M68kLegalizerInfo(*this));
5973471bf0Spatrick 
6073471bf0Spatrick   auto *RBI = new M68kRegisterBankInfo(*getRegisterInfo());
6173471bf0Spatrick   RegBankInfo.reset(RBI);
6273471bf0Spatrick   InstSelector.reset(createM68kInstructionSelector(TM, *this, *RBI));
6373471bf0Spatrick }
6473471bf0Spatrick 
getCallLowering() const6573471bf0Spatrick const CallLowering *M68kSubtarget::getCallLowering() const {
6673471bf0Spatrick   return CallLoweringInfo.get();
6773471bf0Spatrick }
6873471bf0Spatrick 
getInstructionSelector() const6973471bf0Spatrick InstructionSelector *M68kSubtarget::getInstructionSelector() const {
7073471bf0Spatrick   return InstSelector.get();
7173471bf0Spatrick }
7273471bf0Spatrick 
getLegalizerInfo() const7373471bf0Spatrick const LegalizerInfo *M68kSubtarget::getLegalizerInfo() const {
7473471bf0Spatrick   return Legalizer.get();
7573471bf0Spatrick }
7673471bf0Spatrick 
getRegBankInfo() const7773471bf0Spatrick const RegisterBankInfo *M68kSubtarget::getRegBankInfo() const {
7873471bf0Spatrick   return RegBankInfo.get();
7973471bf0Spatrick }
8073471bf0Spatrick 
isPositionIndependent() const8173471bf0Spatrick bool M68kSubtarget::isPositionIndependent() const {
8273471bf0Spatrick   return TM.isPositionIndependent();
8373471bf0Spatrick }
8473471bf0Spatrick 
isLegalToCallImmediateAddr() const8573471bf0Spatrick bool M68kSubtarget::isLegalToCallImmediateAddr() const { return true; }
8673471bf0Spatrick 
abiUsesSoftFloat() const8773471bf0Spatrick bool M68kSubtarget::abiUsesSoftFloat() const { return true; }
8873471bf0Spatrick 
initializeSubtargetDependencies(StringRef CPU,Triple TT,StringRef FS,const M68kTargetMachine & TM)8973471bf0Spatrick M68kSubtarget &M68kSubtarget::initializeSubtargetDependencies(
9073471bf0Spatrick     StringRef CPU, Triple TT, StringRef FS, const M68kTargetMachine &TM) {
9173471bf0Spatrick   std::string CPUName = selectM68kCPU(TT, CPU).str();
9273471bf0Spatrick 
9373471bf0Spatrick   // Parse features string.
9473471bf0Spatrick   ParseSubtargetFeatures(CPUName, CPUName, FS);
9573471bf0Spatrick 
9673471bf0Spatrick   // Initialize scheduling itinerary for the specified CPU.
9773471bf0Spatrick   InstrItins = getInstrItineraryForCPU(CPUName);
9873471bf0Spatrick 
9973471bf0Spatrick   stackAlignment = 8;
10073471bf0Spatrick 
10173471bf0Spatrick   return *this;
10273471bf0Spatrick }
10373471bf0Spatrick 
10473471bf0Spatrick //===----------------------------------------------------------------------===//
10573471bf0Spatrick // Code Model
10673471bf0Spatrick //
10773471bf0Spatrick // Key assumptions:
10873471bf0Spatrick //  - Whenever possible we use pc-rel encoding since it is smaller(16 bit) than
10973471bf0Spatrick //    absolute(32 bit).
11073471bf0Spatrick //  - GOT is reachable within 16 bit offset for both Small and Medium models.
11173471bf0Spatrick //  - Code section is reachable within 16 bit offset for both models.
11273471bf0Spatrick //
11373471bf0Spatrick //  ---------------------+-------------------------+--------------------------
11473471bf0Spatrick //                       |          Small          |          Medium
11573471bf0Spatrick //                       +-------------------------+------------+-------------
11673471bf0Spatrick //                       |   Static   |    PIC     |   Static   |    PIC
11773471bf0Spatrick //  ---------------------+------------+------------+------------+-------------
11873471bf0Spatrick //                branch |   pc-rel   |   pc-rel   |   pc-rel   |   pc-rel
11973471bf0Spatrick //  ---------------------+------------+------------+------------+-------------
12073471bf0Spatrick //           call global |    @PLT    |    @PLT    |    @PLT    |    @PLT
12173471bf0Spatrick //  ---------------------+------------+------------+------------+-------------
12273471bf0Spatrick //         call internal |   pc-rel   |   pc-rel   |   pc-rel   |   pc-rel
12373471bf0Spatrick //  ---------------------+------------+------------+------------+-------------
12473471bf0Spatrick //            data local |   pc-rel   |   pc-rel   |  ~pc-rel   |  ^pc-rel
12573471bf0Spatrick //  ---------------------+------------+------------+------------+-------------
12673471bf0Spatrick //       data local big* |   pc-rel   |   pc-rel   |  absolute  |  @GOTOFF
12773471bf0Spatrick //  ---------------------+------------+------------+------------+-------------
12873471bf0Spatrick //           data global |   pc-rel   |  @GOTPCREL |  ~pc-rel   |  @GOTPCREL
12973471bf0Spatrick //  ---------------------+------------+------------+------------+-------------
13073471bf0Spatrick //      data global big* |   pc-rel   |  @GOTPCREL |  absolute  |  @GOTPCREL
13173471bf0Spatrick //  ---------------------+------------+------------+------------+-------------
13273471bf0Spatrick //
13373471bf0Spatrick // * Big data potentially cannot be reached within 16 bit offset and requires
13473471bf0Spatrick //   special handling for old(x00 and x10) CPUs. Normally these symbols go into
13573471bf0Spatrick //   separate .ldata section which mapped after normal .data and .text, but I
13673471bf0Spatrick //   don't really know how this must be done for M68k atm... will try to dig
13773471bf0Spatrick //   this info out from GCC. For now CPUs prior to M68020 will use static ref
13873471bf0Spatrick //   for Static Model and @GOT based references for PIC.
13973471bf0Spatrick //
14073471bf0Spatrick // ~ These are absolute for older CPUs for now.
14173471bf0Spatrick // ^ These are @GOTOFF for older CPUs for now.
14273471bf0Spatrick //===----------------------------------------------------------------------===//
14373471bf0Spatrick 
14473471bf0Spatrick /// Classify a blockaddress reference for the current subtarget according to how
14573471bf0Spatrick /// we should reference it in a non-pcrel context.
classifyBlockAddressReference() const14673471bf0Spatrick unsigned char M68kSubtarget::classifyBlockAddressReference() const {
14773471bf0Spatrick   // Unless we start to support Large Code Model branching is always pc-rel
14873471bf0Spatrick   return M68kII::MO_PC_RELATIVE_ADDRESS;
14973471bf0Spatrick }
15073471bf0Spatrick 
15173471bf0Spatrick unsigned char
classifyLocalReference(const GlobalValue * GV) const15273471bf0Spatrick M68kSubtarget::classifyLocalReference(const GlobalValue *GV) const {
15373471bf0Spatrick   switch (TM.getCodeModel()) {
15473471bf0Spatrick   default:
15573471bf0Spatrick     llvm_unreachable("Unsupported code model");
15673471bf0Spatrick   case CodeModel::Small:
15773471bf0Spatrick   case CodeModel::Kernel: {
15873471bf0Spatrick     return M68kII::MO_PC_RELATIVE_ADDRESS;
15973471bf0Spatrick   }
16073471bf0Spatrick   case CodeModel::Medium: {
16173471bf0Spatrick     if (isPositionIndependent()) {
16273471bf0Spatrick       // On M68020 and better we can fit big any data offset into dips field.
16373471bf0Spatrick       if (atLeastM68020()) {
16473471bf0Spatrick         return M68kII::MO_PC_RELATIVE_ADDRESS;
16573471bf0Spatrick       }
16673471bf0Spatrick       // Otherwise we could check the data size and make sure it will fit into
16773471bf0Spatrick       // 16 bit offset. For now we will be conservative and go with @GOTOFF
16873471bf0Spatrick       return M68kII::MO_GOTOFF;
16973471bf0Spatrick     } else {
17073471bf0Spatrick       if (atLeastM68020()) {
17173471bf0Spatrick         return M68kII::MO_PC_RELATIVE_ADDRESS;
17273471bf0Spatrick       }
17373471bf0Spatrick       return M68kII::MO_ABSOLUTE_ADDRESS;
17473471bf0Spatrick     }
17573471bf0Spatrick   }
17673471bf0Spatrick   }
17773471bf0Spatrick }
17873471bf0Spatrick 
classifyExternalReference(const Module & M) const17973471bf0Spatrick unsigned char M68kSubtarget::classifyExternalReference(const Module &M) const {
18073471bf0Spatrick   if (TM.shouldAssumeDSOLocal(M, nullptr))
18173471bf0Spatrick     return classifyLocalReference(nullptr);
18273471bf0Spatrick 
18373471bf0Spatrick   if (isPositionIndependent())
18473471bf0Spatrick     return M68kII::MO_GOTPCREL;
18573471bf0Spatrick 
18673471bf0Spatrick   return M68kII::MO_GOT;
18773471bf0Spatrick }
18873471bf0Spatrick 
18973471bf0Spatrick unsigned char
classifyGlobalReference(const GlobalValue * GV) const19073471bf0Spatrick M68kSubtarget::classifyGlobalReference(const GlobalValue *GV) const {
19173471bf0Spatrick   return classifyGlobalReference(GV, *GV->getParent());
19273471bf0Spatrick }
19373471bf0Spatrick 
classifyGlobalReference(const GlobalValue * GV,const Module & M) const19473471bf0Spatrick unsigned char M68kSubtarget::classifyGlobalReference(const GlobalValue *GV,
19573471bf0Spatrick                                                      const Module &M) const {
19673471bf0Spatrick   if (TM.shouldAssumeDSOLocal(M, GV))
19773471bf0Spatrick     return classifyLocalReference(GV);
19873471bf0Spatrick 
19973471bf0Spatrick   switch (TM.getCodeModel()) {
20073471bf0Spatrick   default:
20173471bf0Spatrick     llvm_unreachable("Unsupported code model");
20273471bf0Spatrick   case CodeModel::Small:
20373471bf0Spatrick   case CodeModel::Kernel: {
20473471bf0Spatrick     if (isPositionIndependent())
20573471bf0Spatrick       return M68kII::MO_GOTPCREL;
20673471bf0Spatrick     return M68kII::MO_PC_RELATIVE_ADDRESS;
20773471bf0Spatrick   }
20873471bf0Spatrick   case CodeModel::Medium: {
20973471bf0Spatrick     if (isPositionIndependent())
21073471bf0Spatrick       return M68kII::MO_GOTPCREL;
21173471bf0Spatrick 
21273471bf0Spatrick     if (atLeastM68020())
21373471bf0Spatrick       return M68kII::MO_PC_RELATIVE_ADDRESS;
21473471bf0Spatrick 
21573471bf0Spatrick     return M68kII::MO_ABSOLUTE_ADDRESS;
21673471bf0Spatrick   }
21773471bf0Spatrick   }
21873471bf0Spatrick }
21973471bf0Spatrick 
getJumpTableEncoding() const22073471bf0Spatrick unsigned M68kSubtarget::getJumpTableEncoding() const {
22173471bf0Spatrick   if (isPositionIndependent()) {
22273471bf0Spatrick     // The only time we want to use GOTOFF(used when with EK_Custom32) is when
22373471bf0Spatrick     // the potential delta between the jump target and table base can be larger
22473471bf0Spatrick     // than displacement field, which is True for older CPUs(16 bit disp)
22573471bf0Spatrick     // in Medium model(can have large data way beyond 16 bit).
22673471bf0Spatrick     if (TM.getCodeModel() == CodeModel::Medium && !atLeastM68020())
22773471bf0Spatrick       return MachineJumpTableInfo::EK_Custom32;
22873471bf0Spatrick 
22973471bf0Spatrick     return MachineJumpTableInfo::EK_LabelDifference32;
23073471bf0Spatrick   }
23173471bf0Spatrick 
23273471bf0Spatrick   // In non-pic modes, just use the address of a block.
23373471bf0Spatrick   return MachineJumpTableInfo::EK_BlockAddress;
23473471bf0Spatrick }
23573471bf0Spatrick 
23673471bf0Spatrick unsigned char
classifyGlobalFunctionReference(const GlobalValue * GV) const23773471bf0Spatrick M68kSubtarget::classifyGlobalFunctionReference(const GlobalValue *GV) const {
23873471bf0Spatrick   return classifyGlobalFunctionReference(GV, *GV->getParent());
23973471bf0Spatrick }
24073471bf0Spatrick 
24173471bf0Spatrick unsigned char
classifyGlobalFunctionReference(const GlobalValue * GV,const Module & M) const24273471bf0Spatrick M68kSubtarget::classifyGlobalFunctionReference(const GlobalValue *GV,
24373471bf0Spatrick                                                const Module &M) const {
24473471bf0Spatrick   // local always use pc-rel referencing
24573471bf0Spatrick   if (TM.shouldAssumeDSOLocal(M, GV))
24673471bf0Spatrick     return M68kII::MO_NO_FLAG;
24773471bf0Spatrick 
24873471bf0Spatrick   // If the function is marked as non-lazy, generate an indirect call
24973471bf0Spatrick   // which loads from the GOT directly. This avoids run-time overhead
25073471bf0Spatrick   // at the cost of eager binding.
25173471bf0Spatrick   auto *F = dyn_cast_or_null<Function>(GV);
25273471bf0Spatrick   if (F && F->hasFnAttribute(Attribute::NonLazyBind)) {
25373471bf0Spatrick     return M68kII::MO_GOTPCREL;
25473471bf0Spatrick   }
25573471bf0Spatrick 
25673471bf0Spatrick   // otherwise linker will figure this out
25773471bf0Spatrick   return M68kII::MO_PLT;
25873471bf0Spatrick }
259