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