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