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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file contains code to lower AArch64 MachineInstrs to their corresponding 10 // MCInst records. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "AArch64MCInstLower.h" 15 #include "AArch64MachineFunctionInfo.h" 16 #include "MCTargetDesc/AArch64MCExpr.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" 33 using namespace llvm; 34 using namespace llvm::object; 35 36 extern cl::opt<bool> EnableAArch64ELFLocalDynamicTLSGeneration; 37 38 AArch64MCInstLower::AArch64MCInstLower(MCContext &ctx, AsmPrinter &printer) 39 : Ctx(ctx), Printer(printer) {} 40 41 MCSymbol * 42 AArch64MCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const { 43 return GetGlobalValueSymbol(MO.getGlobal(), MO.getTargetFlags()); 44 } 45 46 MCSymbol *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 awareness 59 // of ARM64EC mangling ("#"/"$$h"). So object files need to refer to both 60 // the mangled and unmangled names of ARM64EC symbols, even if they aren't 61 // 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), 82 MCSymbolRefExpr::create(MangledSym, MCSymbolRefExpr::VK_WEAKREF, 83 Ctx)); 84 Printer.OutStreamer->emitSymbolAttribute(MangledSym, MCSA_WeakAntiDep); 85 Printer.OutStreamer->emitAssignment( 86 MangledSym, 87 MCSymbolRefExpr::create(Printer.getSymbol(GV), 88 MCSymbolRefExpr::VK_WEAKREF, Ctx)); 89 } 90 91 if (TargetFlags & AArch64II::MO_ARM64EC_CALLMANGLE) 92 return MangledSym; 93 } 94 95 return Printer.getSymbol(GV); 96 } 97 98 SmallString<128> Name; 99 100 if ((TargetFlags & AArch64II::MO_DLLIMPORT) && 101 TheTriple.isWindowsArm64EC() && 102 !(TargetFlags & AArch64II::MO_ARM64EC_CALLMANGLE) && 103 isa<Function>(GV)) { 104 // __imp_aux is specific to arm64EC; it represents the actual address of 105 // an imported function without any thunks. 106 // 107 // If we see a reference to an "aux" symbol, also emit a reference to the 108 // corresponding non-aux symbol. Otherwise, the Microsoft linker behaves 109 // strangely when linking against x64 import libararies. 110 // 111 // emitSymbolAttribute() doesn't have any real effect here; it just 112 // ensures the symbol name appears in the assembly without any 113 // side-effects. It might make sense to design a cleaner way to express 114 // this. 115 Name = "__imp_"; 116 Printer.TM.getNameWithPrefix(Name, GV, 117 Printer.getObjFileLowering().getMangler()); 118 MCSymbol *ExtraSym = Ctx.getOrCreateSymbol(Name); 119 Printer.OutStreamer->emitSymbolAttribute(ExtraSym, MCSA_Global); 120 121 Name = "__imp_aux_"; 122 } else if (TargetFlags & AArch64II::MO_DLLIMPORT) { 123 Name = "__imp_"; 124 } else if (TargetFlags & AArch64II::MO_COFFSTUB) { 125 Name = ".refptr."; 126 } 127 Printer.TM.getNameWithPrefix(Name, GV, 128 Printer.getObjFileLowering().getMangler()); 129 130 MCSymbol *MCSym = Ctx.getOrCreateSymbol(Name); 131 132 if (TargetFlags & AArch64II::MO_COFFSTUB) { 133 MachineModuleInfoCOFF &MMICOFF = 134 Printer.MMI->getObjFileInfo<MachineModuleInfoCOFF>(); 135 MachineModuleInfoImpl::StubValueTy &StubSym = 136 MMICOFF.getGVStubEntry(MCSym); 137 138 if (!StubSym.getPointer()) 139 StubSym = MachineModuleInfoImpl::StubValueTy(Printer.getSymbol(GV), true); 140 } 141 142 return MCSym; 143 } 144 145 MCSymbol * 146 AArch64MCInstLower::GetExternalSymbolSymbol(const MachineOperand &MO) const { 147 return Printer.GetExternalSymbolSymbol(MO.getSymbolName()); 148 } 149 150 MCOperand AArch64MCInstLower::lowerSymbolOperandMachO(const MachineOperand &MO, 151 MCSymbol *Sym) const { 152 // FIXME: We would like an efficient form for this, so we don't have to do a 153 // lot of extra uniquing. 154 MCSymbolRefExpr::VariantKind RefKind = MCSymbolRefExpr::VK_None; 155 if ((MO.getTargetFlags() & AArch64II::MO_GOT) != 0) { 156 if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE) 157 RefKind = MCSymbolRefExpr::VK_GOTPAGE; 158 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == 159 AArch64II::MO_PAGEOFF) 160 RefKind = MCSymbolRefExpr::VK_GOTPAGEOFF; 161 else 162 llvm_unreachable("Unexpected target flags with MO_GOT on GV operand"); 163 } else if ((MO.getTargetFlags() & AArch64II::MO_TLS) != 0) { 164 if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE) 165 RefKind = MCSymbolRefExpr::VK_TLVPPAGE; 166 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == 167 AArch64II::MO_PAGEOFF) 168 RefKind = MCSymbolRefExpr::VK_TLVPPAGEOFF; 169 else 170 llvm_unreachable("Unexpected target flags with MO_TLS on GV operand"); 171 } else { 172 if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE) 173 RefKind = MCSymbolRefExpr::VK_PAGE; 174 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == 175 AArch64II::MO_PAGEOFF) 176 RefKind = MCSymbolRefExpr::VK_PAGEOFF; 177 } 178 const MCExpr *Expr = MCSymbolRefExpr::create(Sym, RefKind, Ctx); 179 if (!MO.isJTI() && MO.getOffset()) 180 Expr = MCBinaryExpr::createAdd( 181 Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx); 182 return MCOperand::createExpr(Expr); 183 } 184 185 MCOperand AArch64MCInstLower::lowerSymbolOperandELF(const MachineOperand &MO, 186 MCSymbol *Sym) const { 187 uint32_t RefFlags = 0; 188 189 if (MO.getTargetFlags() & AArch64II::MO_GOT) { 190 const MachineFunction *MF = MO.getParent()->getParent()->getParent(); 191 RefFlags |= (MF->getInfo<AArch64FunctionInfo>()->hasELFSignedGOT() 192 ? AArch64MCExpr::VK_GOT_AUTH 193 : AArch64MCExpr::VK_GOT); 194 } else if (MO.getTargetFlags() & AArch64II::MO_TLS) { 195 TLSModel::Model Model; 196 if (MO.isGlobal()) { 197 const MachineFunction *MF = MO.getParent()->getParent()->getParent(); 198 if (MF->getInfo<AArch64FunctionInfo>()->hasELFSignedGOT()) { 199 Model = TLSModel::GeneralDynamic; 200 } else { 201 const GlobalValue *GV = MO.getGlobal(); 202 Model = Printer.TM.getTLSModel(GV); 203 if (!EnableAArch64ELFLocalDynamicTLSGeneration && 204 Model == TLSModel::LocalDynamic) 205 Model = TLSModel::GeneralDynamic; 206 } 207 } else { 208 assert(MO.isSymbol() && 209 StringRef(MO.getSymbolName()) == "_TLS_MODULE_BASE_" && 210 "unexpected external TLS symbol"); 211 // The general dynamic access sequence is used to get the 212 // address of _TLS_MODULE_BASE_. 213 Model = TLSModel::GeneralDynamic; 214 } 215 switch (Model) { 216 case TLSModel::InitialExec: 217 RefFlags |= AArch64MCExpr::VK_GOTTPREL; 218 break; 219 case TLSModel::LocalExec: 220 RefFlags |= AArch64MCExpr::VK_TPREL; 221 break; 222 case TLSModel::LocalDynamic: 223 RefFlags |= AArch64MCExpr::VK_DTPREL; 224 break; 225 case TLSModel::GeneralDynamic: { 226 // TODO: it's probably better to introduce MO_TLS_AUTH or smth and avoid 227 // running hasELFSignedGOT() every time, but existing flags already 228 // cover all 12 bits of SubReg_TargetFlags field in MachineOperand, and 229 // making the field wider breaks static assertions. 230 const MachineFunction *MF = MO.getParent()->getParent()->getParent(); 231 RefFlags |= MF->getInfo<AArch64FunctionInfo>()->hasELFSignedGOT() 232 ? AArch64MCExpr::VK_TLSDESC_AUTH 233 : AArch64MCExpr::VK_TLSDESC; 234 break; 235 } 236 } 237 } else if (MO.getTargetFlags() & AArch64II::MO_PREL) { 238 RefFlags |= AArch64MCExpr::VK_PREL; 239 } else { 240 // No modifier means this is a generic reference, classified as absolute for 241 // the cases where it matters (:abs_g0: etc). 242 RefFlags |= AArch64MCExpr::VK_ABS; 243 } 244 245 if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE) 246 RefFlags |= AArch64MCExpr::VK_PAGE; 247 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == 248 AArch64II::MO_PAGEOFF) 249 RefFlags |= AArch64MCExpr::VK_PAGEOFF; 250 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G3) 251 RefFlags |= AArch64MCExpr::VK_G3; 252 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G2) 253 RefFlags |= AArch64MCExpr::VK_G2; 254 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G1) 255 RefFlags |= AArch64MCExpr::VK_G1; 256 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G0) 257 RefFlags |= AArch64MCExpr::VK_G0; 258 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_HI12) 259 RefFlags |= AArch64MCExpr::VK_HI12; 260 261 if (MO.getTargetFlags() & AArch64II::MO_NC) 262 RefFlags |= AArch64MCExpr::VK_NC; 263 264 const MCExpr *Expr = 265 MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Ctx); 266 if (!MO.isJTI() && MO.getOffset()) 267 Expr = MCBinaryExpr::createAdd( 268 Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx); 269 270 AArch64MCExpr::VariantKind RefKind; 271 RefKind = static_cast<AArch64MCExpr::VariantKind>(RefFlags); 272 Expr = AArch64MCExpr::create(Expr, RefKind, Ctx); 273 274 return MCOperand::createExpr(Expr); 275 } 276 277 MCOperand AArch64MCInstLower::lowerSymbolOperandCOFF(const MachineOperand &MO, 278 MCSymbol *Sym) const { 279 uint32_t RefFlags = 0; 280 281 if (MO.getTargetFlags() & AArch64II::MO_TLS) { 282 if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGEOFF) 283 RefFlags |= AArch64MCExpr::VK_SECREL_LO12; 284 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == 285 AArch64II::MO_HI12) 286 RefFlags |= AArch64MCExpr::VK_SECREL_HI12; 287 288 } else if (MO.getTargetFlags() & AArch64II::MO_S) { 289 RefFlags |= AArch64MCExpr::VK_SABS; 290 } else { 291 RefFlags |= AArch64MCExpr::VK_ABS; 292 293 if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE) 294 RefFlags |= AArch64MCExpr::VK_PAGE; 295 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == 296 AArch64II::MO_PAGEOFF) 297 RefFlags |= AArch64MCExpr::VK_PAGEOFF | AArch64MCExpr::VK_NC; 298 } 299 300 if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G3) 301 RefFlags |= AArch64MCExpr::VK_G3; 302 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G2) 303 RefFlags |= AArch64MCExpr::VK_G2; 304 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G1) 305 RefFlags |= AArch64MCExpr::VK_G1; 306 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G0) 307 RefFlags |= AArch64MCExpr::VK_G0; 308 309 // FIXME: Currently we only set VK_NC for MO_G3/MO_G2/MO_G1/MO_G0. This is 310 // because setting VK_NC for others would mean setting their respective 311 // RefFlags correctly. We should do this in a separate patch. 312 if (MO.getTargetFlags() & AArch64II::MO_NC) { 313 auto MOFrag = (MO.getTargetFlags() & AArch64II::MO_FRAGMENT); 314 if (MOFrag == AArch64II::MO_G3 || MOFrag == AArch64II::MO_G2 || 315 MOFrag == AArch64II::MO_G1 || MOFrag == AArch64II::MO_G0) 316 RefFlags |= AArch64MCExpr::VK_NC; 317 } 318 319 const MCExpr *Expr = 320 MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Ctx); 321 if (!MO.isJTI() && MO.getOffset()) 322 Expr = MCBinaryExpr::createAdd( 323 Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx); 324 325 auto RefKind = static_cast<AArch64MCExpr::VariantKind>(RefFlags); 326 assert(RefKind != AArch64MCExpr::VK_INVALID && 327 "Invalid relocation requested"); 328 Expr = AArch64MCExpr::create(Expr, RefKind, Ctx); 329 330 return MCOperand::createExpr(Expr); 331 } 332 333 MCOperand AArch64MCInstLower::LowerSymbolOperand(const MachineOperand &MO, 334 MCSymbol *Sym) const { 335 if (Printer.TM.getTargetTriple().isOSBinFormatMachO()) 336 return lowerSymbolOperandMachO(MO, Sym); 337 if (Printer.TM.getTargetTriple().isOSBinFormatCOFF()) 338 return lowerSymbolOperandCOFF(MO, Sym); 339 340 assert(Printer.TM.getTargetTriple().isOSBinFormatELF() && "Invalid target"); 341 return lowerSymbolOperandELF(MO, Sym); 342 } 343 344 bool AArch64MCInstLower::lowerOperand(const MachineOperand &MO, 345 MCOperand &MCOp) const { 346 switch (MO.getType()) { 347 default: 348 llvm_unreachable("unknown operand type"); 349 case MachineOperand::MO_Register: 350 // Ignore all implicit register operands. 351 if (MO.isImplicit()) 352 return false; 353 MCOp = MCOperand::createReg(MO.getReg()); 354 break; 355 case MachineOperand::MO_RegisterMask: 356 // Regmasks are like implicit defs. 357 return false; 358 case MachineOperand::MO_Immediate: 359 MCOp = MCOperand::createImm(MO.getImm()); 360 break; 361 case MachineOperand::MO_MachineBasicBlock: 362 MCOp = MCOperand::createExpr( 363 MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), Ctx)); 364 break; 365 case MachineOperand::MO_GlobalAddress: 366 MCOp = LowerSymbolOperand(MO, GetGlobalAddressSymbol(MO)); 367 break; 368 case MachineOperand::MO_ExternalSymbol: 369 MCOp = LowerSymbolOperand(MO, GetExternalSymbolSymbol(MO)); 370 break; 371 case MachineOperand::MO_MCSymbol: 372 MCOp = LowerSymbolOperand(MO, MO.getMCSymbol()); 373 break; 374 case MachineOperand::MO_JumpTableIndex: 375 MCOp = LowerSymbolOperand(MO, Printer.GetJTISymbol(MO.getIndex())); 376 break; 377 case MachineOperand::MO_ConstantPoolIndex: 378 MCOp = LowerSymbolOperand(MO, Printer.GetCPISymbol(MO.getIndex())); 379 break; 380 case MachineOperand::MO_BlockAddress: 381 MCOp = LowerSymbolOperand( 382 MO, Printer.GetBlockAddressSymbol(MO.getBlockAddress())); 383 break; 384 } 385 return true; 386 } 387 388 void AArch64MCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const { 389 OutMI.setOpcode(MI->getOpcode()); 390 391 for (const MachineOperand &MO : MI->operands()) { 392 MCOperand MCOp; 393 if (lowerOperand(MO, MCOp)) 394 OutMI.addOperand(MCOp); 395 } 396 397 switch (OutMI.getOpcode()) { 398 case AArch64::CATCHRET: 399 OutMI = MCInst(); 400 OutMI.setOpcode(AArch64::RET); 401 OutMI.addOperand(MCOperand::createReg(AArch64::LR)); 402 break; 403 case AArch64::CLEANUPRET: 404 OutMI = MCInst(); 405 OutMI.setOpcode(AArch64::RET); 406 OutMI.addOperand(MCOperand::createReg(AArch64::LR)); 407 break; 408 } 409 } 410