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/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" 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), 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 of 101 // an imported function without any thunks. 102 // 103 // If we see a reference to an "aux" symbol, also emit a reference to the 104 // corresponding non-aux symbol. Otherwise, the Microsoft linker behaves 105 // strangely when linking against x64 import libararies. 106 // 107 // emitSymbolAttribute() doesn't have any real effect here; it just 108 // ensures the symbol name appears in the assembly without any 109 // side-effects. It might make sense to design a cleaner way to express 110 // 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 141 MCSymbol * 142 AArch64MCInstLower::GetExternalSymbolSymbol(const MachineOperand &MO) const { 143 return Printer.GetExternalSymbolSymbol(MO.getSymbolName()); 144 } 145 146 MCOperand 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 a 149 // 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 else 158 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 else 166 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 182 MCOperand 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_AUTH 190 : 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 the 209 // 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 avoid 224 // running hasELFSignedGOT() every time, but existing flags already 225 // cover all 12 bits of SubReg_TargetFlags field in MachineOperand, and 226 // 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_AUTH 230 : 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 for 238 // 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 270 MCOperand 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 is 303 // because setting VK_NC for others would mean setting their respective 304 // 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 321 MCOperand 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 332 bool 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 376 void 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