brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.3 KiB · 3994663 Raw
398 lines · cpp
1//==-- AArch64MCInstLower.cpp - Convert AArch64 MachineInstr to an MCInst --==//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 contains code to lower AArch64 MachineInstrs to their corresponding10// MCInst records.11//12//===----------------------------------------------------------------------===//13 14#include "AArch64MCInstLower.h"15#include "AArch64MachineFunctionInfo.h"16#include "MCTargetDesc/AArch64MCAsmInfo.h"17#include "Utils/AArch64BaseInfo.h"18#include "llvm/CodeGen/AsmPrinter.h"19#include "llvm/CodeGen/MachineBasicBlock.h"20#include "llvm/CodeGen/MachineInstr.h"21#include "llvm/CodeGen/MachineModuleInfoImpls.h"22#include "llvm/IR/Function.h"23#include "llvm/IR/Mangler.h"24#include "llvm/MC/MCContext.h"25#include "llvm/MC/MCExpr.h"26#include "llvm/MC/MCInst.h"27#include "llvm/MC/MCStreamer.h"28#include "llvm/Object/COFF.h"29#include "llvm/Support/CodeGen.h"30#include "llvm/Support/CommandLine.h"31#include "llvm/Target/TargetLoweringObjectFile.h"32#include "llvm/Target/TargetMachine.h"33using namespace llvm;34using namespace llvm::object;35 36extern cl::opt<bool> EnableAArch64ELFLocalDynamicTLSGeneration;37 38AArch64MCInstLower::AArch64MCInstLower(MCContext &ctx, AsmPrinter &printer)39    : Ctx(ctx), Printer(printer) {}40 41MCSymbol *42AArch64MCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {43  return GetGlobalValueSymbol(MO.getGlobal(), MO.getTargetFlags());44}45 46MCSymbol *AArch64MCInstLower::GetGlobalValueSymbol(const GlobalValue *GV,47                                                   unsigned TargetFlags) const {48  const Triple &TheTriple = Printer.TM.getTargetTriple();49  if (!TheTriple.isOSBinFormatCOFF())50    return Printer.getSymbolPreferLocal(*GV);51 52  assert(TheTriple.isOSWindows() &&53         "Windows is the only supported COFF target");54 55  bool IsIndirect =56      (TargetFlags & (AArch64II::MO_DLLIMPORT | AArch64II::MO_COFFSTUB));57  if (!IsIndirect) {58    // For ARM64EC, symbol lookup in the MSVC linker has limited awareness59    // of ARM64EC mangling ("#"/"$$h"). So object files need to refer to both60    // the mangled and unmangled names of ARM64EC symbols, even if they aren't61    // actually used by any relocations. Emit the necessary references here.62    if (!TheTriple.isWindowsArm64EC() || !isa<Function>(GV) ||63        !GV->hasExternalLinkage())64      return Printer.getSymbol(GV);65 66    StringRef Name = Printer.getSymbol(GV)->getName();67    // Don't mangle ARM64EC runtime functions.68    static constexpr StringLiteral ExcludedFns[] = {69        "__os_arm64x_check_icall_cfg", "__os_arm64x_dispatch_call_no_redirect",70        "__os_arm64x_check_icall"};71    if (is_contained(ExcludedFns, Name))72      return Printer.getSymbol(GV);73 74    if (std::optional<std::string> MangledName =75            getArm64ECMangledFunctionName(Name.str())) {76      MCSymbol *MangledSym = Ctx.getOrCreateSymbol(MangledName.value());77      if (!cast<Function>(GV)->hasMetadata("arm64ec_hasguestexit")) {78        Printer.OutStreamer->emitSymbolAttribute(Printer.getSymbol(GV),79                                                 MCSA_WeakAntiDep);80        Printer.OutStreamer->emitAssignment(81            Printer.getSymbol(GV), MCSymbolRefExpr::create(MangledSym, Ctx));82        Printer.OutStreamer->emitSymbolAttribute(MangledSym, MCSA_WeakAntiDep);83        Printer.OutStreamer->emitAssignment(84            MangledSym, MCSymbolRefExpr::create(Printer.getSymbol(GV), Ctx));85      }86 87      if (TargetFlags & AArch64II::MO_ARM64EC_CALLMANGLE)88        return MangledSym;89    }90 91    return Printer.getSymbol(GV);92  }93 94  SmallString<128> Name;95 96  if ((TargetFlags & AArch64II::MO_DLLIMPORT) &&97      TheTriple.isWindowsArm64EC() &&98      !(TargetFlags & AArch64II::MO_ARM64EC_CALLMANGLE) &&99      isa<Function>(GV)) {100    // __imp_aux is specific to arm64EC; it represents the actual address of101    // an imported function without any thunks.102    //103    // If we see a reference to an "aux" symbol, also emit a reference to the104    // corresponding non-aux symbol.  Otherwise, the Microsoft linker behaves105    // strangely when linking against x64 import libararies.106    //107    // emitSymbolAttribute() doesn't have any real effect here; it just108    // ensures the symbol name appears in the assembly without any109    // side-effects. It might make sense to design a cleaner way to express110    // this.111    Name = "__imp_";112    Printer.TM.getNameWithPrefix(Name, GV,113                                 Printer.getObjFileLowering().getMangler());114    MCSymbol *ExtraSym = Ctx.getOrCreateSymbol(Name);115    Printer.OutStreamer->emitSymbolAttribute(ExtraSym, MCSA_Global);116 117    Name = "__imp_aux_";118  } else if (TargetFlags & AArch64II::MO_DLLIMPORT) {119    Name = "__imp_";120  } else if (TargetFlags & AArch64II::MO_COFFSTUB) {121    Name = ".refptr.";122  }123  Printer.TM.getNameWithPrefix(Name, GV,124                               Printer.getObjFileLowering().getMangler());125 126  MCSymbol *MCSym = Ctx.getOrCreateSymbol(Name);127 128  if (TargetFlags & AArch64II::MO_COFFSTUB) {129    MachineModuleInfoCOFF &MMICOFF =130        Printer.MMI->getObjFileInfo<MachineModuleInfoCOFF>();131    MachineModuleInfoImpl::StubValueTy &StubSym =132        MMICOFF.getGVStubEntry(MCSym);133 134    if (!StubSym.getPointer())135      StubSym = MachineModuleInfoImpl::StubValueTy(Printer.getSymbol(GV), true);136  }137 138  return MCSym;139}140 141MCSymbol *142AArch64MCInstLower::GetExternalSymbolSymbol(const MachineOperand &MO) const {143  return Printer.GetExternalSymbolSymbol(MO.getSymbolName());144}145 146MCOperand AArch64MCInstLower::lowerSymbolOperandMachO(const MachineOperand &MO,147                                                      MCSymbol *Sym) const {148  // FIXME: We would like an efficient form for this, so we don't have to do a149  // lot of extra uniquing.150  auto Spec = AArch64::S_None;151  if ((MO.getTargetFlags() & AArch64II::MO_GOT) != 0) {152    if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)153      Spec = AArch64::S_MACHO_GOTPAGE;154    else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==155             AArch64II::MO_PAGEOFF)156      Spec = AArch64::S_MACHO_GOTPAGEOFF;157    else158      llvm_unreachable("Unexpected target flags with MO_GOT on GV operand");159  } else if ((MO.getTargetFlags() & AArch64II::MO_TLS) != 0) {160    if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)161      Spec = AArch64::S_MACHO_TLVPPAGE;162    else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==163             AArch64II::MO_PAGEOFF)164      Spec = AArch64::S_MACHO_TLVPPAGEOFF;165    else166      llvm_unreachable("Unexpected target flags with MO_TLS on GV operand");167  } else {168    if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)169      Spec = AArch64::S_MACHO_PAGE;170    else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==171             AArch64II::MO_PAGEOFF)172      Spec = AArch64::S_MACHO_PAGEOFF;173  }174  // TODO: Migrate to MCSpecifierExpr::create like ELF.175  const MCExpr *Expr = MCSymbolRefExpr::create(Sym, Spec, Ctx);176  if (!MO.isJTI() && MO.getOffset())177    Expr = MCBinaryExpr::createAdd(178        Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);179  return MCOperand::createExpr(Expr);180}181 182MCOperand AArch64MCInstLower::lowerSymbolOperandELF(const MachineOperand &MO,183                                                    MCSymbol *Sym) const {184  uint32_t RefFlags = 0;185 186  if (MO.getTargetFlags() & AArch64II::MO_GOT) {187    const MachineFunction *MF = MO.getParent()->getParent()->getParent();188    RefFlags |= (MF->getInfo<AArch64FunctionInfo>()->hasELFSignedGOT()189                     ? AArch64::S_GOT_AUTH190                     : AArch64::S_GOT);191  } else if (MO.getTargetFlags() & AArch64II::MO_TLS) {192    TLSModel::Model Model;193    if (MO.isGlobal()) {194      const MachineFunction *MF = MO.getParent()->getParent()->getParent();195      if (MF->getInfo<AArch64FunctionInfo>()->hasELFSignedGOT()) {196        Model = TLSModel::GeneralDynamic;197      } else {198        const GlobalValue *GV = MO.getGlobal();199        Model = Printer.TM.getTLSModel(GV);200        if (!EnableAArch64ELFLocalDynamicTLSGeneration &&201            Model == TLSModel::LocalDynamic)202          Model = TLSModel::GeneralDynamic;203      }204    } else {205      assert(MO.isSymbol() &&206             StringRef(MO.getSymbolName()) == "_TLS_MODULE_BASE_" &&207             "unexpected external TLS symbol");208      // The general dynamic access sequence is used to get the209      // address of _TLS_MODULE_BASE_.210      Model = TLSModel::GeneralDynamic;211    }212    switch (Model) {213    case TLSModel::InitialExec:214      RefFlags |= AArch64::S_GOTTPREL;215      break;216    case TLSModel::LocalExec:217      RefFlags |= AArch64::S_TPREL;218      break;219    case TLSModel::LocalDynamic:220      RefFlags |= AArch64::S_DTPREL;221      break;222    case TLSModel::GeneralDynamic: {223      // TODO: it's probably better to introduce MO_TLS_AUTH or smth and avoid224      // running hasELFSignedGOT() every time, but existing flags already225      // cover all 12 bits of SubReg_TargetFlags field in MachineOperand, and226      // making the field wider breaks static assertions.227      const MachineFunction *MF = MO.getParent()->getParent()->getParent();228      RefFlags |= MF->getInfo<AArch64FunctionInfo>()->hasELFSignedGOT()229                      ? AArch64::S_TLSDESC_AUTH230                      : AArch64::S_TLSDESC;231      break;232    }233    }234  } else if (MO.getTargetFlags() & AArch64II::MO_PREL) {235    RefFlags |= AArch64::S_PREL;236  } else {237    // No modifier means this is a generic reference, classified as absolute for238    // the cases where it matters (:abs_g0: etc).239    RefFlags |= AArch64::S_ABS;240  }241 242  if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)243    RefFlags |= AArch64::S_PAGE;244  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==245           AArch64II::MO_PAGEOFF)246    RefFlags |= AArch64::S_PAGEOFF;247  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G3)248    RefFlags |= AArch64::S_G3;249  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G2)250    RefFlags |= AArch64::S_G2;251  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G1)252    RefFlags |= AArch64::S_G1;253  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G0)254    RefFlags |= AArch64::S_G0;255  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_HI12)256    RefFlags |= AArch64::S_HI12;257 258  if (MO.getTargetFlags() & AArch64II::MO_NC)259    RefFlags |= AArch64::S_NC;260 261  const MCExpr *Expr = MCSymbolRefExpr::create(Sym, Ctx);262  if (!MO.isJTI() && MO.getOffset())263    Expr = MCBinaryExpr::createAdd(264        Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);265 266  Expr = MCSpecifierExpr::create(Expr, RefFlags, Ctx);267  return MCOperand::createExpr(Expr);268}269 270MCOperand AArch64MCInstLower::lowerSymbolOperandCOFF(const MachineOperand &MO,271                                                     MCSymbol *Sym) const {272  uint32_t RefFlags = 0;273 274  if (MO.getTargetFlags() & AArch64II::MO_TLS) {275    if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGEOFF)276      RefFlags |= AArch64::S_SECREL_LO12;277    else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==278             AArch64II::MO_HI12)279      RefFlags |= AArch64::S_SECREL_HI12;280 281  } else if (MO.getTargetFlags() & AArch64II::MO_S) {282    RefFlags |= AArch64::S_SABS;283  } else {284    RefFlags |= AArch64::S_ABS;285 286    if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)287      RefFlags |= AArch64::S_PAGE;288    else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==289             AArch64II::MO_PAGEOFF)290      RefFlags |= AArch64::S_PAGEOFF | AArch64::S_NC;291  }292 293  if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G3)294    RefFlags |= AArch64::S_G3;295  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G2)296    RefFlags |= AArch64::S_G2;297  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G1)298    RefFlags |= AArch64::S_G1;299  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G0)300    RefFlags |= AArch64::S_G0;301 302  // FIXME: Currently we only set VK_NC for MO_G3/MO_G2/MO_G1/MO_G0. This is303  // because setting VK_NC for others would mean setting their respective304  // RefFlags correctly.  We should do this in a separate patch.305  if (MO.getTargetFlags() & AArch64II::MO_NC) {306    auto MOFrag = (MO.getTargetFlags() & AArch64II::MO_FRAGMENT);307    if (MOFrag == AArch64II::MO_G3 || MOFrag == AArch64II::MO_G2 ||308        MOFrag == AArch64II::MO_G1 || MOFrag == AArch64II::MO_G0)309      RefFlags |= AArch64::S_NC;310  }311 312  const MCExpr *Expr = MCSymbolRefExpr::create(Sym, Ctx);313  if (!MO.isJTI() && MO.getOffset())314    Expr = MCBinaryExpr::createAdd(315        Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);316 317  Expr = MCSpecifierExpr::create(Expr, RefFlags, Ctx);318  return MCOperand::createExpr(Expr);319}320 321MCOperand AArch64MCInstLower::LowerSymbolOperand(const MachineOperand &MO,322                                                 MCSymbol *Sym) const {323  if (Printer.TM.getTargetTriple().isOSBinFormatMachO())324    return lowerSymbolOperandMachO(MO, Sym);325  if (Printer.TM.getTargetTriple().isOSBinFormatCOFF())326    return lowerSymbolOperandCOFF(MO, Sym);327 328  assert(Printer.TM.getTargetTriple().isOSBinFormatELF() && "Invalid target");329  return lowerSymbolOperandELF(MO, Sym);330}331 332bool AArch64MCInstLower::lowerOperand(const MachineOperand &MO,333                                      MCOperand &MCOp) const {334  switch (MO.getType()) {335  default:336    llvm_unreachable("unknown operand type");337  case MachineOperand::MO_Register:338    // Ignore all implicit register operands.339    if (MO.isImplicit())340      return false;341    MCOp = MCOperand::createReg(MO.getReg());342    break;343  case MachineOperand::MO_RegisterMask:344    // Regmasks are like implicit defs.345    return false;346  case MachineOperand::MO_Immediate:347    MCOp = MCOperand::createImm(MO.getImm());348    break;349  case MachineOperand::MO_MachineBasicBlock:350    MCOp = MCOperand::createExpr(351        MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), Ctx));352    break;353  case MachineOperand::MO_GlobalAddress:354    MCOp = LowerSymbolOperand(MO, GetGlobalAddressSymbol(MO));355    break;356  case MachineOperand::MO_ExternalSymbol:357    MCOp = LowerSymbolOperand(MO, GetExternalSymbolSymbol(MO));358    break;359  case MachineOperand::MO_MCSymbol:360    MCOp = LowerSymbolOperand(MO, MO.getMCSymbol());361    break;362  case MachineOperand::MO_JumpTableIndex:363    MCOp = LowerSymbolOperand(MO, Printer.GetJTISymbol(MO.getIndex()));364    break;365  case MachineOperand::MO_ConstantPoolIndex:366    MCOp = LowerSymbolOperand(MO, Printer.GetCPISymbol(MO.getIndex()));367    break;368  case MachineOperand::MO_BlockAddress:369    MCOp = LowerSymbolOperand(370        MO, Printer.GetBlockAddressSymbol(MO.getBlockAddress()));371    break;372  }373  return true;374}375 376void AArch64MCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const {377  OutMI.setOpcode(MI->getOpcode());378 379  for (const MachineOperand &MO : MI->operands()) {380    MCOperand MCOp;381    if (lowerOperand(MO, MCOp))382      OutMI.addOperand(MCOp);383  }384 385  switch (OutMI.getOpcode()) {386  case AArch64::CATCHRET:387    OutMI = MCInst();388    OutMI.setOpcode(AArch64::RET);389    OutMI.addOperand(MCOperand::createReg(AArch64::LR));390    break;391  case AArch64::CLEANUPRET:392    OutMI = MCInst();393    OutMI.setOpcode(AArch64::RET);394    OutMI.addOperand(MCOperand::createReg(AArch64::LR));395    break;396  }397}398