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