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