brintos

brintos / llvm-project-archived public Read only

0
0
Text · 20.1 KiB · e6af32d Raw
560 lines · cpp
1//===-- ARMSubtarget.cpp - ARM Subtarget Information ----------------------===//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-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the ARM specific subclass of TargetSubtargetInfo.10//11//===----------------------------------------------------------------------===//12 13#include "ARM.h"14 15#include "ARMCallLowering.h"16#include "ARMFrameLowering.h"17#include "ARMInstrInfo.h"18#include "ARMLegalizerInfo.h"19#include "ARMRegisterBankInfo.h"20#include "ARMSubtarget.h"21#include "ARMTargetMachine.h"22#include "MCTargetDesc/ARMMCTargetDesc.h"23#include "Thumb1FrameLowering.h"24#include "Thumb1InstrInfo.h"25#include "Thumb2InstrInfo.h"26#include "llvm/ADT/StringRef.h"27#include "llvm/ADT/Twine.h"28#include "llvm/CodeGen/GlobalISel/InstructionSelect.h"29#include "llvm/CodeGen/MachineFrameInfo.h"30#include "llvm/CodeGen/MachineFunction.h"31#include "llvm/IR/Function.h"32#include "llvm/IR/GlobalValue.h"33#include "llvm/MC/MCAsmInfo.h"34#include "llvm/MC/MCTargetOptions.h"35#include "llvm/Support/CodeGen.h"36#include "llvm/Support/CommandLine.h"37#include "llvm/Target/TargetOptions.h"38#include "llvm/TargetParser/ARMTargetParser.h"39#include "llvm/TargetParser/Triple.h"40 41using namespace llvm;42 43#define DEBUG_TYPE "arm-subtarget"44 45#define GET_SUBTARGETINFO_TARGET_DESC46#define GET_SUBTARGETINFO_CTOR47#include "ARMGenSubtargetInfo.inc"48 49static cl::opt<bool>50UseFusedMulOps("arm-use-mulops",51               cl::init(true), cl::Hidden);52 53enum ITMode {54  DefaultIT,55  RestrictedIT56};57 58static cl::opt<ITMode>59    IT(cl::desc("IT block support"), cl::Hidden, cl::init(DefaultIT),60       cl::values(clEnumValN(DefaultIT, "arm-default-it",61                             "Generate any type of IT block"),62                  clEnumValN(RestrictedIT, "arm-restrict-it",63                             "Disallow complex IT blocks")));64 65/// ForceFastISel - Use the fast-isel, even for subtargets where it is not66/// currently supported (for testing only).67static cl::opt<bool>68ForceFastISel("arm-force-fast-isel",69               cl::init(false), cl::Hidden);70 71/// initializeSubtargetDependencies - Initializes using a CPU and feature string72/// so that we can use initializer lists for subtarget initialization.73ARMSubtarget &ARMSubtarget::initializeSubtargetDependencies(StringRef CPU,74                                                            StringRef FS) {75  initSubtargetFeatures(CPU, FS);76  return *this;77}78 79ARMFrameLowering *ARMSubtarget::initializeFrameLowering(StringRef CPU,80                                                        StringRef FS) {81  ARMSubtarget &STI = initializeSubtargetDependencies(CPU, FS);82  if (STI.isThumb1Only())83    return (ARMFrameLowering *)new Thumb1FrameLowering(STI);84 85  return new ARMFrameLowering(STI);86}87 88ARMSubtarget::ARMSubtarget(const Triple &TT, const std::string &CPU,89                           const std::string &FS,90                           const ARMBaseTargetMachine &TM, bool IsLittle,91                           bool MinSize, DenormalMode DM)92    : ARMGenSubtargetInfo(TT, CPU, /*TuneCPU*/ CPU, FS),93      UseMulOps(UseFusedMulOps), CPUString(CPU), OptMinSize(MinSize),94      IsLittle(IsLittle), DM(DM), TargetTriple(TT), Options(TM.Options), TM(TM),95      FrameLowering(initializeFrameLowering(CPU, FS)),96      // At this point initializeSubtargetDependencies has been called so97      // we can query directly.98      InstrInfo(isThumb1Only() ? (ARMBaseInstrInfo *)new Thumb1InstrInfo(*this)99                : !isThumb()   ? (ARMBaseInstrInfo *)new ARMInstrInfo(*this)100                             : (ARMBaseInstrInfo *)new Thumb2InstrInfo(*this)),101      TLInfo(TM, *this) {102 103  CallLoweringInfo.reset(new ARMCallLowering(*getTargetLowering()));104  Legalizer.reset(new ARMLegalizerInfo(*this));105 106  auto *RBI = new ARMRegisterBankInfo(*getRegisterInfo());107 108  // FIXME: At this point, we can't rely on Subtarget having RBI.109  // It's awkward to mix passing RBI and the Subtarget; should we pass110  // TII/TRI as well?111  InstSelector.reset(createARMInstructionSelector(TM, *this, *RBI));112 113  RegBankInfo.reset(RBI);114}115 116const CallLowering *ARMSubtarget::getCallLowering() const {117  return CallLoweringInfo.get();118}119 120InstructionSelector *ARMSubtarget::getInstructionSelector() const {121  return InstSelector.get();122}123 124const LegalizerInfo *ARMSubtarget::getLegalizerInfo() const {125  return Legalizer.get();126}127 128const RegisterBankInfo *ARMSubtarget::getRegBankInfo() const {129  return RegBankInfo.get();130}131 132void ARMSubtarget::initLibcallLoweringInfo(LibcallLoweringInfo &Info) const {133  const Triple &TT = getTargetTriple();134  if (TT.isOSBinFormatMachO()) {135    // Uses VFP for Thumb libfuncs if available.136    if (isThumb() && hasVFP2Base() && hasARMOps() && !useSoftFloat()) {137      // clang-format off138      static const struct {139        const RTLIB::Libcall Op;140        const RTLIB::LibcallImpl Impl;141      } LibraryCalls[] = {142        // Single-precision floating-point arithmetic.143        { RTLIB::ADD_F32, RTLIB::impl___addsf3vfp },144        { RTLIB::SUB_F32, RTLIB::impl___subsf3vfp },145        { RTLIB::MUL_F32, RTLIB::impl___mulsf3vfp },146        { RTLIB::DIV_F32, RTLIB::impl___divsf3vfp },147 148        // Double-precision floating-point arithmetic.149        { RTLIB::ADD_F64, RTLIB::impl___adddf3vfp },150        { RTLIB::SUB_F64, RTLIB::impl___subdf3vfp },151        { RTLIB::MUL_F64, RTLIB::impl___muldf3vfp },152        { RTLIB::DIV_F64, RTLIB::impl___divdf3vfp },153 154        // Single-precision comparisons.155        { RTLIB::OEQ_F32, RTLIB::impl___eqsf2vfp },156        { RTLIB::UNE_F32, RTLIB::impl___nesf2vfp },157        { RTLIB::OLT_F32, RTLIB::impl___ltsf2vfp },158        { RTLIB::OLE_F32, RTLIB::impl___lesf2vfp },159        { RTLIB::OGE_F32, RTLIB::impl___gesf2vfp },160        { RTLIB::OGT_F32, RTLIB::impl___gtsf2vfp },161        { RTLIB::UO_F32,  RTLIB::impl___unordsf2vfp },162 163        // Double-precision comparisons.164        { RTLIB::OEQ_F64, RTLIB::impl___eqdf2vfp },165        { RTLIB::UNE_F64, RTLIB::impl___nedf2vfp },166        { RTLIB::OLT_F64, RTLIB::impl___ltdf2vfp },167        { RTLIB::OLE_F64, RTLIB::impl___ledf2vfp },168        { RTLIB::OGE_F64, RTLIB::impl___gedf2vfp },169        { RTLIB::OGT_F64, RTLIB::impl___gtdf2vfp },170        { RTLIB::UO_F64,  RTLIB::impl___unorddf2vfp },171 172        // Floating-point to integer conversions.173        // i64 conversions are done via library routines even when generating VFP174        // instructions, so use the same ones.175        { RTLIB::FPTOSINT_F64_I32, RTLIB::impl___fixdfsivfp },176        { RTLIB::FPTOUINT_F64_I32, RTLIB::impl___fixunsdfsivfp },177        { RTLIB::FPTOSINT_F32_I32, RTLIB::impl___fixsfsivfp },178        { RTLIB::FPTOUINT_F32_I32, RTLIB::impl___fixunssfsivfp },179 180        // Conversions between floating types.181        { RTLIB::FPROUND_F64_F32, RTLIB::impl___truncdfsf2vfp },182        { RTLIB::FPEXT_F32_F64,   RTLIB::impl___extendsfdf2vfp },183 184        // Integer to floating-point conversions.185        // i64 conversions are done via library routines even when generating VFP186        // instructions, so use the same ones.187        // FIXME: There appears to be some naming inconsistency in ARM libgcc:188        // e.g., __floatunsidf vs. __floatunssidfvfp.189        { RTLIB::SINTTOFP_I32_F64, RTLIB::impl___floatsidfvfp },190        { RTLIB::UINTTOFP_I32_F64, RTLIB::impl___floatunssidfvfp },191        { RTLIB::SINTTOFP_I32_F32, RTLIB::impl___floatsisfvfp },192        { RTLIB::UINTTOFP_I32_F32, RTLIB::impl___floatunssisfvfp },193      };194      // clang-format on195 196      for (const auto &LC : LibraryCalls)197        Info.setLibcallImpl(LC.Op, LC.Impl);198    }199  }200}201 202bool ARMSubtarget::isXRaySupported() const {203  // We don't currently suppport Thumb, but Windows requires Thumb.204  return hasV6Ops() && hasARMOps() && !isTargetWindows();205}206 207void ARMSubtarget::initSubtargetFeatures(StringRef CPU, StringRef FS) {208  if (CPUString.empty()) {209    CPUString = "generic";210 211    if (isTargetDarwin()) {212      StringRef ArchName = TargetTriple.getArchName();213      ARM::ArchKind AK = ARM::parseArch(ArchName);214      if (AK == ARM::ArchKind::ARMV7S)215        // Default to the Swift CPU when targeting armv7s/thumbv7s.216        CPUString = "swift";217      else if (AK == ARM::ArchKind::ARMV7K)218        // Default to the Cortex-a7 CPU when targeting armv7k/thumbv7k.219        // ARMv7k does not use SjLj exception handling.220        CPUString = "cortex-a7";221    }222  }223 224  // Insert the architecture feature derived from the target triple into the225  // feature string. This is important for setting features that are implied226  // based on the architecture version.227  std::string ArchFS = ARM_MC::ParseARMTriple(TargetTriple, CPUString);228  if (!FS.empty()) {229    if (!ArchFS.empty())230      ArchFS = (Twine(ArchFS) + "," + FS).str();231    else232      ArchFS = std::string(FS);233  }234  ParseSubtargetFeatures(CPUString, /*TuneCPU*/ CPUString, ArchFS);235 236  // FIXME: This used enable V6T2 support implicitly for Thumb2 mode.237  // Assert this for now to make the change obvious.238  assert(hasV6T2Ops() || !hasThumb2());239 240  if (genExecuteOnly()) {241    // Execute only support for >= v8-M Baseline requires movt support242    if (hasV8MBaselineOps())243      NoMovt = false;244    if (!hasV6MOps())245      report_fatal_error("Cannot generate execute-only code for this target");246  }247 248  // Keep a pointer to static instruction cost data for the specified CPU.249  SchedModel = getSchedModelForCPU(CPUString);250 251  // Initialize scheduling itinerary for the specified CPU.252  InstrItins = getInstrItineraryForCPU(CPUString);253 254  // FIXME: this is invalid for WindowsCE255  if (isTargetWindows())256    NoARM = true;257 258  if (TM.isAAPCS_ABI())259    stackAlignment = Align(8);260  if (TM.isAAPCS16_ABI())261    stackAlignment = Align(16);262 263  // FIXME: Completely disable sibcall for Thumb1 since ThumbRegisterInfo::264  // emitEpilogue is not ready for them. Thumb tail calls also use t2B, as265  // the Thumb1 16-bit unconditional branch doesn't have sufficient relocation266  // support in the assembler and linker to be used. This would need to be267  // fixed to fully support tail calls in Thumb1.268  //269  // For ARMv8-M, we /do/ implement tail calls.  Doing this is tricky for v8-M270  // baseline, since the LDM/POP instruction on Thumb doesn't take LR.  This271  // means if we need to reload LR, it takes extra instructions, which outweighs272  // the value of the tail call; but here we don't know yet whether LR is going273  // to be used. We take the optimistic approach of generating the tail call and274  // perhaps taking a hit if we need to restore the LR.275 276  // Thumb1 PIC calls to external symbols use BX, so they can be tail calls,277  // but we need to make sure there are enough registers; the only valid278  // registers are the 4 used for parameters.  We don't currently do this279  // case.280 281  SupportsTailCall = !isThumb1Only() || hasV8MBaselineOps();282 283  switch (IT) {284  case DefaultIT:285    RestrictIT = false;286    break;287  case RestrictedIT:288    RestrictIT = true;289    break;290  }291 292  // NEON f32 ops are non-IEEE 754 compliant. Darwin is ok with it by default.293  const FeatureBitset &Bits = getFeatureBits();294  if ((Bits[ARM::ProcA5] || Bits[ARM::ProcA8]) && // Where this matters295      (isTargetDarwin() || DM == DenormalMode::getPreserveSign()))296    HasNEONForFP = true;297 298  const ARM::ArchKind Arch = ARM::parseArch(TargetTriple.getArchName());299  if (isRWPI() ||300      (isTargetIOS() &&301       (Arch == ARM::ArchKind::ARMV6K || Arch == ARM::ArchKind::ARMV6) &&302       TargetTriple.isOSVersionLT(3, 0)))303    ReserveR9 = true;304 305  // If MVEVectorCostFactor is still 0 (has not been set to anything else), default it to 2306  if (MVEVectorCostFactor == 0)307    MVEVectorCostFactor = 2;308 309  // FIXME: Teach TableGen to deal with these instead of doing it manually here.310  switch (ARMProcFamily) {311  case Others:312  case CortexA5:313    break;314  case CortexA7:315    LdStMultipleTiming = DoubleIssue;316    break;317  case CortexA8:318    LdStMultipleTiming = DoubleIssue;319    break;320  case CortexA9:321    LdStMultipleTiming = DoubleIssueCheckUnalignedAccess;322    PreISelOperandLatencyAdjustment = 1;323    break;324  case CortexA12:325    break;326  case CortexA15:327    MaxInterleaveFactor = 2;328    PreISelOperandLatencyAdjustment = 1;329    PartialUpdateClearance = 12;330    break;331  case CortexA17:332  case CortexA32:333  case CortexA35:334  case CortexA53:335  case CortexA55:336  case CortexA57:337  case CortexA72:338  case CortexA73:339  case CortexA75:340  case CortexA76:341  case CortexA77:342  case CortexA78:343  case CortexA78AE:344  case CortexA78C:345  case CortexA510:346  case CortexA710:347  case CortexR4:348  case CortexR5:349  case CortexR7:350  case CortexM3:351  case CortexM55:352  case CortexM7:353  case CortexM85:354  case CortexR52:355  case CortexR52plus:356  case CortexX1:357  case CortexX1C:358    break;359  case Exynos:360    LdStMultipleTiming = SingleIssuePlusExtras;361    MaxInterleaveFactor = 4;362    if (!isThumb())363      PreferBranchLogAlignment = 3;364    break;365  case Kryo:366    break;367  case Krait:368    PreISelOperandLatencyAdjustment = 1;369    break;370  case NeoverseV1:371    break;372  case Swift:373    MaxInterleaveFactor = 2;374    LdStMultipleTiming = SingleIssuePlusExtras;375    PreISelOperandLatencyAdjustment = 1;376    PartialUpdateClearance = 12;377    break;378  }379}380 381bool ARMSubtarget::isROPI() const {382  // FIXME: This should ideally come from a function attribute, to work383  // correctly with LTO.384  return TM.getRelocationModel() == Reloc::ROPI ||385         TM.getRelocationModel() == Reloc::ROPI_RWPI;386}387 388bool ARMSubtarget::isRWPI() const {389  // FIXME: This should ideally come from a function attribute, to work390  // correctly with LTO.391  return TM.getRelocationModel() == Reloc::RWPI ||392         TM.getRelocationModel() == Reloc::ROPI_RWPI;393}394 395bool ARMSubtarget::isGVIndirectSymbol(const GlobalValue *GV) const {396  return TM.isGVIndirectSymbol(GV);397}398 399bool ARMSubtarget::isGVInGOT(const GlobalValue *GV) const {400  return isTargetELF() && TM.isPositionIndependent() && !GV->isDSOLocal();401}402 403unsigned ARMSubtarget::getMispredictionPenalty() const {404  return SchedModel.MispredictPenalty;405}406 407bool ARMSubtarget::enableMachineScheduler() const {408  // The MachineScheduler can increase register usage, so we use more high409  // registers and end up with more T2 instructions that cannot be converted to410  // T1 instructions. At least until we do better at converting to thumb1411  // instructions, on cortex-m at Oz where we are size-paranoid, don't use the412  // Machine scheduler, relying on the DAG register pressure scheduler instead.413  if (isMClass() && hasMinSize())414    return false;415  // Enable the MachineScheduler before register allocation for subtargets416  // with the use-misched feature.417  return useMachineScheduler();418}419 420bool ARMSubtarget::enableSubRegLiveness() const {421  // Enable SubRegLiveness for MVE to better optimize s subregs for mqpr regs422  // and q subregs for qqqqpr regs.423  return hasMVEIntegerOps();424}425 426bool ARMSubtarget::enableMachinePipeliner() const {427  // Enable the MachinePipeliner before register allocation for subtargets428  // with the use-mipipeliner feature.429  return getSchedModel().hasInstrSchedModel() && useMachinePipeliner();430}431 432bool ARMSubtarget::useDFAforSMS() const { return false; }433 434// This overrides the PostRAScheduler bit in the SchedModel for any CPU.435bool ARMSubtarget::enablePostRAScheduler() const {436  if (enableMachineScheduler())437    return false;438  if (disablePostRAScheduler())439    return false;440  // Thumb1 cores will generally not benefit from post-ra scheduling441  return !isThumb1Only();442}443 444bool ARMSubtarget::enablePostRAMachineScheduler() const {445  if (!enableMachineScheduler())446    return false;447  if (disablePostRAScheduler())448    return false;449  return !isThumb1Only();450}451 452bool ARMSubtarget::useStride4VFPs() const {453  // For general targets, the prologue can grow when VFPs are allocated with454  // stride 4 (more vpush instructions). But WatchOS uses a compact unwind455  // format which it's more important to get right.456  return isTargetWatchABI() ||457         (useWideStrideVFP() && !OptMinSize);458}459 460bool ARMSubtarget::useMovt() const {461  // NOTE Windows on ARM needs to use mov.w/mov.t pairs to materialise 32-bit462  // immediates as it is inherently position independent, and may be out of463  // range otherwise.464  return !NoMovt && hasV8MBaselineOps() &&465         (isTargetWindows() || !OptMinSize || genExecuteOnly());466}467 468bool ARMSubtarget::useFastISel() const {469  // Enable fast-isel for any target, for testing only.470  if (ForceFastISel)471    return true;472 473  // Limit fast-isel to the targets that are or have been tested.474  if (!hasV6Ops())475    return false;476 477  // Thumb2 support on iOS; ARM support on iOS and Linux.478  return TM.Options.EnableFastISel && ((isTargetMachO() && !isThumb1Only()) ||479                                       (isTargetLinux() && !isThumb()));480}481 482unsigned ARMSubtarget::getGPRAllocationOrder(const MachineFunction &MF) const {483  // The GPR register class has multiple possible allocation orders, with484  // tradeoffs preferred by different sub-architectures and optimisation goals.485  // The allocation orders are:486  // 0: (the default tablegen order, not used)487  // 1: r14, r0-r13488  // 2: r0-r7489  // 3: r0-r7, r12, lr, r8-r11490  // Note that the register allocator will change this order so that491  // callee-saved registers are used later, as they require extra work in the492  // prologue/epilogue (though we sometimes override that).493 494  // For thumb1-only targets, only the low registers are allocatable.495  if (isThumb1Only())496    return 2;497 498  // Allocate low registers first, so we can select more 16-bit instructions.499  // We also (in ignoreCSRForAllocationOrder) override  the default behaviour500  // with regards to callee-saved registers, because pushing extra registers is501  // much cheaper (in terms of code size) than using high registers. After502  // that, we allocate r12 (doesn't need to be saved), lr (saving it means we503  // can return with the pop, don't need an extra "bx lr") and then the rest of504  // the high registers.505  if (isThumb2() && MF.getFunction().hasMinSize())506    return 3;507 508  // Otherwise, allocate in the default order, using LR first because saving it509  // allows a shorter epilogue sequence.510  return 1;511}512 513bool ARMSubtarget::ignoreCSRForAllocationOrder(const MachineFunction &MF,514                                               MCRegister PhysReg) const {515  // To minimize code size in Thumb2, we prefer the usage of low regs (lower516  // cost per use) so we can  use narrow encoding. By default, caller-saved517  // registers (e.g. lr, r12) are always  allocated first, regardless of518  // their cost per use. When optForMinSize, we prefer the low regs even if519  // they are CSR because usually push/pop can be folded into existing ones.520  return isThumb2() && MF.getFunction().hasMinSize() &&521         ARM::GPRRegClass.contains(PhysReg);522}523 524ARMSubtarget::PushPopSplitVariation525ARMSubtarget::getPushPopSplitVariation(const MachineFunction &MF) const {526  const Function &F = MF.getFunction();527  const MachineFrameInfo &MFI = MF.getFrameInfo();528 529  // Thumb1 always splits the pushes at R7, because the Thumb1 push instruction530  // cannot use high registers except for lr.531  if (isThumb1Only())532    return SplitR7;533 534  // If R7 is the frame pointer, we must split at R7 to ensure that the535  // previous frame pointer (R7) and return address (LR) are adjacent on the536  // stack, to form a valid frame record.537  if (getFramePointerReg() == ARM::R7 &&538      MF.getTarget().Options.FramePointerIsReserved(MF))539    return SplitR7;540 541  // Returns SplitR11WindowsSEH when the stack pointer needs to be542  // restored from the frame pointer r11 + an offset and Windows CFI is enabled.543  // This stack unwinding cannot be expressed with SEH unwind opcodes when done544  // with a single push, making it necessary to split the push into r4-r10, and545  // another containing r11+lr.546  if (MF.getTarget().getMCAsmInfo()->usesWindowsCFI() &&547      F.needsUnwindTableEntry() &&548      (MFI.hasVarSizedObjects() || getRegisterInfo()->hasStackRealignment(MF)))549    return SplitR11WindowsSEH;550 551  // Returns SplitR11AAPCSSignRA when the frame pointer is R11, requiring R11552  // and LR to be adjacent on the stack, and branch signing is enabled,553  // requiring R12 to be on the stack.554  if (MF.getInfo<ARMFunctionInfo>()->shouldSignReturnAddress() &&555      getFramePointerReg() == ARM::R11 &&556      MF.getTarget().Options.FramePointerIsReserved(MF))557    return SplitR11AAPCSSignRA;558  return NoSplit;559}560