Path: blob/main/contrib/llvm-project/llvm/lib/Target/AArch64/AArch64MCInstLower.cpp
35267 views
//==-- AArch64MCInstLower.cpp - Convert AArch64 MachineInstr to an MCInst --==//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file contains code to lower AArch64 MachineInstrs to their corresponding9// MCInst records.10//11//===----------------------------------------------------------------------===//1213#include "AArch64MCInstLower.h"14#include "MCTargetDesc/AArch64MCExpr.h"15#include "Utils/AArch64BaseInfo.h"16#include "llvm/CodeGen/AsmPrinter.h"17#include "llvm/CodeGen/MachineBasicBlock.h"18#include "llvm/CodeGen/MachineInstr.h"19#include "llvm/CodeGen/MachineModuleInfoImpls.h"20#include "llvm/IR/Function.h"21#include "llvm/IR/Mangler.h"22#include "llvm/MC/MCContext.h"23#include "llvm/MC/MCExpr.h"24#include "llvm/MC/MCInst.h"25#include "llvm/MC/MCStreamer.h"26#include "llvm/Object/COFF.h"27#include "llvm/Support/CodeGen.h"28#include "llvm/Support/CommandLine.h"29#include "llvm/Target/TargetLoweringObjectFile.h"30#include "llvm/Target/TargetMachine.h"31using namespace llvm;32using namespace llvm::object;3334extern cl::opt<bool> EnableAArch64ELFLocalDynamicTLSGeneration;3536AArch64MCInstLower::AArch64MCInstLower(MCContext &ctx, AsmPrinter &printer)37: Ctx(ctx), Printer(printer) {}3839MCSymbol *40AArch64MCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {41return GetGlobalValueSymbol(MO.getGlobal(), MO.getTargetFlags());42}4344MCSymbol *AArch64MCInstLower::GetGlobalValueSymbol(const GlobalValue *GV,45unsigned TargetFlags) const {46const Triple &TheTriple = Printer.TM.getTargetTriple();47if (!TheTriple.isOSBinFormatCOFF())48return Printer.getSymbolPreferLocal(*GV);4950assert(TheTriple.isOSWindows() &&51"Windows is the only supported COFF target");5253bool IsIndirect =54(TargetFlags & (AArch64II::MO_DLLIMPORT | AArch64II::MO_COFFSTUB));55if (!IsIndirect) {56// For ARM64EC, symbol lookup in the MSVC linker has limited awareness57// of ARM64EC mangling ("#"/"$$h"). So object files need to refer to both58// the mangled and unmangled names of ARM64EC symbols, even if they aren't59// actually used by any relocations. Emit the necessary references here.60if (!TheTriple.isWindowsArm64EC() || !isa<Function>(GV) ||61!GV->hasExternalLinkage())62return Printer.getSymbol(GV);6364StringRef Name = Printer.getSymbol(GV)->getName();65// Don't mangle ARM64EC runtime functions.66static constexpr StringLiteral ExcludedFns[] = {67"__os_arm64x_check_icall_cfg", "__os_arm64x_dispatch_call_no_redirect",68"__os_arm64x_check_icall"};69if (is_contained(ExcludedFns, Name))70return Printer.getSymbol(GV);7172if (std::optional<std::string> MangledName =73getArm64ECMangledFunctionName(Name.str())) {74MCSymbol *MangledSym = Ctx.getOrCreateSymbol(MangledName.value());75if (!cast<Function>(GV)->hasMetadata("arm64ec_hasguestexit")) {76Printer.OutStreamer->emitSymbolAttribute(Printer.getSymbol(GV),77MCSA_WeakAntiDep);78Printer.OutStreamer->emitAssignment(79Printer.getSymbol(GV),80MCSymbolRefExpr::create(MangledSym, MCSymbolRefExpr::VK_WEAKREF,81Ctx));82Printer.OutStreamer->emitSymbolAttribute(MangledSym, MCSA_WeakAntiDep);83Printer.OutStreamer->emitAssignment(84MangledSym,85MCSymbolRefExpr::create(Printer.getSymbol(GV),86MCSymbolRefExpr::VK_WEAKREF, Ctx));87}8889if (TargetFlags & AArch64II::MO_ARM64EC_CALLMANGLE)90return MangledSym;91}9293return Printer.getSymbol(GV);94}9596SmallString<128> Name;9798if ((TargetFlags & AArch64II::MO_DLLIMPORT) &&99TheTriple.isWindowsArm64EC() &&100!(TargetFlags & AArch64II::MO_ARM64EC_CALLMANGLE) &&101isa<Function>(GV)) {102// __imp_aux is specific to arm64EC; it represents the actual address of103// an imported function without any thunks.104//105// If we see a reference to an "aux" symbol, also emit a reference to the106// corresponding non-aux symbol. Otherwise, the Microsoft linker behaves107// strangely when linking against x64 import libararies.108//109// emitSymbolAttribute() doesn't have any real effect here; it just110// ensures the symbol name appears in the assembly without any111// side-effects. It might make sense to design a cleaner way to express112// this.113Name = "__imp_";114Printer.TM.getNameWithPrefix(Name, GV,115Printer.getObjFileLowering().getMangler());116MCSymbol *ExtraSym = Ctx.getOrCreateSymbol(Name);117Printer.OutStreamer->emitSymbolAttribute(ExtraSym, MCSA_Global);118119Name = "__imp_aux_";120} else if (TargetFlags & AArch64II::MO_DLLIMPORT) {121Name = "__imp_";122} else if (TargetFlags & AArch64II::MO_COFFSTUB) {123Name = ".refptr.";124}125Printer.TM.getNameWithPrefix(Name, GV,126Printer.getObjFileLowering().getMangler());127128MCSymbol *MCSym = Ctx.getOrCreateSymbol(Name);129130if (TargetFlags & AArch64II::MO_COFFSTUB) {131MachineModuleInfoCOFF &MMICOFF =132Printer.MMI->getObjFileInfo<MachineModuleInfoCOFF>();133MachineModuleInfoImpl::StubValueTy &StubSym =134MMICOFF.getGVStubEntry(MCSym);135136if (!StubSym.getPointer())137StubSym = MachineModuleInfoImpl::StubValueTy(Printer.getSymbol(GV), true);138}139140return MCSym;141}142143MCSymbol *144AArch64MCInstLower::GetExternalSymbolSymbol(const MachineOperand &MO) const {145return Printer.GetExternalSymbolSymbol(MO.getSymbolName());146}147148MCOperand AArch64MCInstLower::lowerSymbolOperandMachO(const MachineOperand &MO,149MCSymbol *Sym) const {150// FIXME: We would like an efficient form for this, so we don't have to do a151// lot of extra uniquing.152MCSymbolRefExpr::VariantKind RefKind = MCSymbolRefExpr::VK_None;153if ((MO.getTargetFlags() & AArch64II::MO_GOT) != 0) {154if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)155RefKind = MCSymbolRefExpr::VK_GOTPAGE;156else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==157AArch64II::MO_PAGEOFF)158RefKind = MCSymbolRefExpr::VK_GOTPAGEOFF;159else160llvm_unreachable("Unexpected target flags with MO_GOT on GV operand");161} else if ((MO.getTargetFlags() & AArch64II::MO_TLS) != 0) {162if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)163RefKind = MCSymbolRefExpr::VK_TLVPPAGE;164else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==165AArch64II::MO_PAGEOFF)166RefKind = MCSymbolRefExpr::VK_TLVPPAGEOFF;167else168llvm_unreachable("Unexpected target flags with MO_TLS on GV operand");169} else {170if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)171RefKind = MCSymbolRefExpr::VK_PAGE;172else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==173AArch64II::MO_PAGEOFF)174RefKind = MCSymbolRefExpr::VK_PAGEOFF;175}176const MCExpr *Expr = MCSymbolRefExpr::create(Sym, RefKind, Ctx);177if (!MO.isJTI() && MO.getOffset())178Expr = MCBinaryExpr::createAdd(179Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);180return MCOperand::createExpr(Expr);181}182183MCOperand AArch64MCInstLower::lowerSymbolOperandELF(const MachineOperand &MO,184MCSymbol *Sym) const {185uint32_t RefFlags = 0;186187if (MO.getTargetFlags() & AArch64II::MO_GOT)188RefFlags |= AArch64MCExpr::VK_GOT;189else if (MO.getTargetFlags() & AArch64II::MO_TLS) {190TLSModel::Model Model;191if (MO.isGlobal()) {192const GlobalValue *GV = MO.getGlobal();193Model = Printer.TM.getTLSModel(GV);194if (!EnableAArch64ELFLocalDynamicTLSGeneration &&195Model == TLSModel::LocalDynamic)196Model = TLSModel::GeneralDynamic;197198} else {199assert(MO.isSymbol() &&200StringRef(MO.getSymbolName()) == "_TLS_MODULE_BASE_" &&201"unexpected external TLS symbol");202// The general dynamic access sequence is used to get the203// address of _TLS_MODULE_BASE_.204Model = TLSModel::GeneralDynamic;205}206switch (Model) {207case TLSModel::InitialExec:208RefFlags |= AArch64MCExpr::VK_GOTTPREL;209break;210case TLSModel::LocalExec:211RefFlags |= AArch64MCExpr::VK_TPREL;212break;213case TLSModel::LocalDynamic:214RefFlags |= AArch64MCExpr::VK_DTPREL;215break;216case TLSModel::GeneralDynamic:217RefFlags |= AArch64MCExpr::VK_TLSDESC;218break;219}220} else if (MO.getTargetFlags() & AArch64II::MO_PREL) {221RefFlags |= AArch64MCExpr::VK_PREL;222} else {223// No modifier means this is a generic reference, classified as absolute for224// the cases where it matters (:abs_g0: etc).225RefFlags |= AArch64MCExpr::VK_ABS;226}227228if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)229RefFlags |= AArch64MCExpr::VK_PAGE;230else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==231AArch64II::MO_PAGEOFF)232RefFlags |= AArch64MCExpr::VK_PAGEOFF;233else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G3)234RefFlags |= AArch64MCExpr::VK_G3;235else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G2)236RefFlags |= AArch64MCExpr::VK_G2;237else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G1)238RefFlags |= AArch64MCExpr::VK_G1;239else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G0)240RefFlags |= AArch64MCExpr::VK_G0;241else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_HI12)242RefFlags |= AArch64MCExpr::VK_HI12;243244if (MO.getTargetFlags() & AArch64II::MO_NC)245RefFlags |= AArch64MCExpr::VK_NC;246247const MCExpr *Expr =248MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Ctx);249if (!MO.isJTI() && MO.getOffset())250Expr = MCBinaryExpr::createAdd(251Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);252253AArch64MCExpr::VariantKind RefKind;254RefKind = static_cast<AArch64MCExpr::VariantKind>(RefFlags);255Expr = AArch64MCExpr::create(Expr, RefKind, Ctx);256257return MCOperand::createExpr(Expr);258}259260MCOperand AArch64MCInstLower::lowerSymbolOperandCOFF(const MachineOperand &MO,261MCSymbol *Sym) const {262uint32_t RefFlags = 0;263264if (MO.getTargetFlags() & AArch64II::MO_TLS) {265if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGEOFF)266RefFlags |= AArch64MCExpr::VK_SECREL_LO12;267else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==268AArch64II::MO_HI12)269RefFlags |= AArch64MCExpr::VK_SECREL_HI12;270271} else if (MO.getTargetFlags() & AArch64II::MO_S) {272RefFlags |= AArch64MCExpr::VK_SABS;273} else {274RefFlags |= AArch64MCExpr::VK_ABS;275276if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)277RefFlags |= AArch64MCExpr::VK_PAGE;278else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==279AArch64II::MO_PAGEOFF)280RefFlags |= AArch64MCExpr::VK_PAGEOFF | AArch64MCExpr::VK_NC;281}282283if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G3)284RefFlags |= AArch64MCExpr::VK_G3;285else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G2)286RefFlags |= AArch64MCExpr::VK_G2;287else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G1)288RefFlags |= AArch64MCExpr::VK_G1;289else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G0)290RefFlags |= AArch64MCExpr::VK_G0;291292// FIXME: Currently we only set VK_NC for MO_G3/MO_G2/MO_G1/MO_G0. This is293// because setting VK_NC for others would mean setting their respective294// RefFlags correctly. We should do this in a separate patch.295if (MO.getTargetFlags() & AArch64II::MO_NC) {296auto MOFrag = (MO.getTargetFlags() & AArch64II::MO_FRAGMENT);297if (MOFrag == AArch64II::MO_G3 || MOFrag == AArch64II::MO_G2 ||298MOFrag == AArch64II::MO_G1 || MOFrag == AArch64II::MO_G0)299RefFlags |= AArch64MCExpr::VK_NC;300}301302const MCExpr *Expr =303MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Ctx);304if (!MO.isJTI() && MO.getOffset())305Expr = MCBinaryExpr::createAdd(306Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);307308auto RefKind = static_cast<AArch64MCExpr::VariantKind>(RefFlags);309assert(RefKind != AArch64MCExpr::VK_INVALID &&310"Invalid relocation requested");311Expr = AArch64MCExpr::create(Expr, RefKind, Ctx);312313return MCOperand::createExpr(Expr);314}315316MCOperand AArch64MCInstLower::LowerSymbolOperand(const MachineOperand &MO,317MCSymbol *Sym) const {318if (Printer.TM.getTargetTriple().isOSBinFormatMachO())319return lowerSymbolOperandMachO(MO, Sym);320if (Printer.TM.getTargetTriple().isOSBinFormatCOFF())321return lowerSymbolOperandCOFF(MO, Sym);322323assert(Printer.TM.getTargetTriple().isOSBinFormatELF() && "Invalid target");324return lowerSymbolOperandELF(MO, Sym);325}326327bool AArch64MCInstLower::lowerOperand(const MachineOperand &MO,328MCOperand &MCOp) const {329switch (MO.getType()) {330default:331llvm_unreachable("unknown operand type");332case MachineOperand::MO_Register:333// Ignore all implicit register operands.334if (MO.isImplicit())335return false;336MCOp = MCOperand::createReg(MO.getReg());337break;338case MachineOperand::MO_RegisterMask:339// Regmasks are like implicit defs.340return false;341case MachineOperand::MO_Immediate:342MCOp = MCOperand::createImm(MO.getImm());343break;344case MachineOperand::MO_MachineBasicBlock:345MCOp = MCOperand::createExpr(346MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), Ctx));347break;348case MachineOperand::MO_GlobalAddress:349MCOp = LowerSymbolOperand(MO, GetGlobalAddressSymbol(MO));350break;351case MachineOperand::MO_ExternalSymbol:352MCOp = LowerSymbolOperand(MO, GetExternalSymbolSymbol(MO));353break;354case MachineOperand::MO_MCSymbol:355MCOp = LowerSymbolOperand(MO, MO.getMCSymbol());356break;357case MachineOperand::MO_JumpTableIndex:358MCOp = LowerSymbolOperand(MO, Printer.GetJTISymbol(MO.getIndex()));359break;360case MachineOperand::MO_ConstantPoolIndex:361MCOp = LowerSymbolOperand(MO, Printer.GetCPISymbol(MO.getIndex()));362break;363case MachineOperand::MO_BlockAddress:364MCOp = LowerSymbolOperand(365MO, Printer.GetBlockAddressSymbol(MO.getBlockAddress()));366break;367}368return true;369}370371void AArch64MCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const {372OutMI.setOpcode(MI->getOpcode());373374for (const MachineOperand &MO : MI->operands()) {375MCOperand MCOp;376if (lowerOperand(MO, MCOp))377OutMI.addOperand(MCOp);378}379380switch (OutMI.getOpcode()) {381case AArch64::CATCHRET:382OutMI = MCInst();383OutMI.setOpcode(AArch64::RET);384OutMI.addOperand(MCOperand::createReg(AArch64::LR));385break;386case AArch64::CLEANUPRET:387OutMI = MCInst();388OutMI.setOpcode(AArch64::RET);389OutMI.addOperand(MCOperand::createReg(AArch64::LR));390break;391}392}393394395