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 { 152 // No modifier means this is a generic reference, classified as absolute for 153 // the cases where it matters (:abs_g0: etc). 154 RefFlags |= AArch64MCExpr::VK_ABS; 155 } 156 157 if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE) 158 RefFlags |= AArch64MCExpr::VK_PAGE; 159 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == 160 AArch64II::MO_PAGEOFF) 161 RefFlags |= AArch64MCExpr::VK_PAGEOFF; 162 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G3) 163 RefFlags |= AArch64MCExpr::VK_G3; 164 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G2) 165 RefFlags |= AArch64MCExpr::VK_G2; 166 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G1) 167 RefFlags |= AArch64MCExpr::VK_G1; 168 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G0) 169 RefFlags |= AArch64MCExpr::VK_G0; 170 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_HI12) 171 RefFlags |= AArch64MCExpr::VK_HI12; 172 173 if (MO.getTargetFlags() & AArch64II::MO_NC) 174 RefFlags |= AArch64MCExpr::VK_NC; 175 176 const MCExpr *Expr = 177 MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Ctx); 178 if (!MO.isJTI() && MO.getOffset()) 179 Expr = MCBinaryExpr::createAdd( 180 Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx); 181 182 AArch64MCExpr::VariantKind RefKind; 183 RefKind = static_cast<AArch64MCExpr::VariantKind>(RefFlags); 184 Expr = AArch64MCExpr::create(Expr, RefKind, Ctx); 185 186 return MCOperand::createExpr(Expr); 187 } 188 189 MCOperand AArch64MCInstLower::lowerSymbolOperandCOFF(const MachineOperand &MO, 190 MCSymbol *Sym) const { 191 uint32_t RefFlags = 0; 192 193 if (MO.getTargetFlags() & AArch64II::MO_TLS) { 194 if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGEOFF) 195 RefFlags |= AArch64MCExpr::VK_SECREL_LO12; 196 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == 197 AArch64II::MO_HI12) 198 RefFlags |= AArch64MCExpr::VK_SECREL_HI12; 199 200 } else if (MO.getTargetFlags() & AArch64II::MO_S) { 201 RefFlags |= AArch64MCExpr::VK_SABS; 202 } else { 203 RefFlags |= AArch64MCExpr::VK_ABS; 204 } 205 206 if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G3) 207 RefFlags |= AArch64MCExpr::VK_G3; 208 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G2) 209 RefFlags |= AArch64MCExpr::VK_G2; 210 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G1) 211 RefFlags |= AArch64MCExpr::VK_G1; 212 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G0) 213 RefFlags |= AArch64MCExpr::VK_G0; 214 215 // FIXME: Currently we only set VK_NC for MO_G3/MO_G2/MO_G1/MO_G0. This is 216 // because setting VK_NC for others would mean setting their respective 217 // RefFlags correctly. We should do this in a separate patch. 218 if (MO.getTargetFlags() & AArch64II::MO_NC) { 219 auto MOFrag = (MO.getTargetFlags() & AArch64II::MO_FRAGMENT); 220 if (MOFrag == AArch64II::MO_G3 || MOFrag == AArch64II::MO_G2 || 221 MOFrag == AArch64II::MO_G1 || MOFrag == AArch64II::MO_G0) 222 RefFlags |= AArch64MCExpr::VK_NC; 223 } 224 225 const MCExpr *Expr = 226 MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Ctx); 227 if (!MO.isJTI() && MO.getOffset()) 228 Expr = MCBinaryExpr::createAdd( 229 Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx); 230 231 auto RefKind = static_cast<AArch64MCExpr::VariantKind>(RefFlags); 232 assert(RefKind != AArch64MCExpr::VK_INVALID && 233 "Invalid relocation requested"); 234 Expr = AArch64MCExpr::create(Expr, RefKind, Ctx); 235 236 return MCOperand::createExpr(Expr); 237 } 238 239 MCOperand AArch64MCInstLower::LowerSymbolOperand(const MachineOperand &MO, 240 MCSymbol *Sym) const { 241 if (Printer.TM.getTargetTriple().isOSDarwin()) 242 return lowerSymbolOperandDarwin(MO, Sym); 243 if (Printer.TM.getTargetTriple().isOSBinFormatCOFF()) 244 return lowerSymbolOperandCOFF(MO, Sym); 245 246 assert(Printer.TM.getTargetTriple().isOSBinFormatELF() && "Invalid target"); 247 return lowerSymbolOperandELF(MO, Sym); 248 } 249 250 bool AArch64MCInstLower::lowerOperand(const MachineOperand &MO, 251 MCOperand &MCOp) const { 252 switch (MO.getType()) { 253 default: 254 llvm_unreachable("unknown operand type"); 255 case MachineOperand::MO_Register: 256 // Ignore all implicit register operands. 257 if (MO.isImplicit()) 258 return false; 259 MCOp = MCOperand::createReg(MO.getReg()); 260 break; 261 case MachineOperand::MO_RegisterMask: 262 // Regmasks are like implicit defs. 263 return false; 264 case MachineOperand::MO_Immediate: 265 MCOp = MCOperand::createImm(MO.getImm()); 266 break; 267 case MachineOperand::MO_MachineBasicBlock: 268 MCOp = MCOperand::createExpr( 269 MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), Ctx)); 270 break; 271 case MachineOperand::MO_GlobalAddress: 272 MCOp = LowerSymbolOperand(MO, GetGlobalAddressSymbol(MO)); 273 break; 274 case MachineOperand::MO_ExternalSymbol: 275 MCOp = LowerSymbolOperand(MO, GetExternalSymbolSymbol(MO)); 276 break; 277 case MachineOperand::MO_MCSymbol: 278 MCOp = LowerSymbolOperand(MO, MO.getMCSymbol()); 279 break; 280 case MachineOperand::MO_JumpTableIndex: 281 MCOp = LowerSymbolOperand(MO, Printer.GetJTISymbol(MO.getIndex())); 282 break; 283 case MachineOperand::MO_ConstantPoolIndex: 284 MCOp = LowerSymbolOperand(MO, Printer.GetCPISymbol(MO.getIndex())); 285 break; 286 case MachineOperand::MO_BlockAddress: 287 MCOp = LowerSymbolOperand( 288 MO, Printer.GetBlockAddressSymbol(MO.getBlockAddress())); 289 break; 290 } 291 return true; 292 } 293 294 void AArch64MCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const { 295 OutMI.setOpcode(MI->getOpcode()); 296 297 for (const MachineOperand &MO : MI->operands()) { 298 MCOperand MCOp; 299 if (lowerOperand(MO, MCOp)) 300 OutMI.addOperand(MCOp); 301 } 302 303 switch (OutMI.getOpcode()) { 304 case AArch64::CATCHRET: 305 OutMI = MCInst(); 306 OutMI.setOpcode(AArch64::RET); 307 OutMI.addOperand(MCOperand::createReg(AArch64::LR)); 308 break; 309 case AArch64::CLEANUPRET: 310 OutMI = MCInst(); 311 OutMI.setOpcode(AArch64::RET); 312 OutMI.addOperand(MCOperand::createReg(AArch64::LR)); 313 break; 314 } 315 } 316