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