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 208 if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G3) 209 RefFlags |= AArch64MCExpr::VK_G3; 210 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G2) 211 RefFlags |= AArch64MCExpr::VK_G2; 212 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G1) 213 RefFlags |= AArch64MCExpr::VK_G1; 214 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G0) 215 RefFlags |= AArch64MCExpr::VK_G0; 216 217 // FIXME: Currently we only set VK_NC for MO_G3/MO_G2/MO_G1/MO_G0. This is 218 // because setting VK_NC for others would mean setting their respective 219 // RefFlags correctly. We should do this in a separate patch. 220 if (MO.getTargetFlags() & AArch64II::MO_NC) { 221 auto MOFrag = (MO.getTargetFlags() & AArch64II::MO_FRAGMENT); 222 if (MOFrag == AArch64II::MO_G3 || MOFrag == AArch64II::MO_G2 || 223 MOFrag == AArch64II::MO_G1 || MOFrag == AArch64II::MO_G0) 224 RefFlags |= AArch64MCExpr::VK_NC; 225 } 226 227 const MCExpr *Expr = 228 MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Ctx); 229 if (!MO.isJTI() && MO.getOffset()) 230 Expr = MCBinaryExpr::createAdd( 231 Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx); 232 233 auto RefKind = static_cast<AArch64MCExpr::VariantKind>(RefFlags); 234 assert(RefKind != AArch64MCExpr::VK_INVALID && 235 "Invalid relocation requested"); 236 Expr = AArch64MCExpr::create(Expr, RefKind, Ctx); 237 238 return MCOperand::createExpr(Expr); 239 } 240 241 MCOperand AArch64MCInstLower::LowerSymbolOperand(const MachineOperand &MO, 242 MCSymbol *Sym) const { 243 if (Printer.TM.getTargetTriple().isOSDarwin()) 244 return lowerSymbolOperandDarwin(MO, Sym); 245 if (Printer.TM.getTargetTriple().isOSBinFormatCOFF()) 246 return lowerSymbolOperandCOFF(MO, Sym); 247 248 assert(Printer.TM.getTargetTriple().isOSBinFormatELF() && "Invalid target"); 249 return lowerSymbolOperandELF(MO, Sym); 250 } 251 252 bool AArch64MCInstLower::lowerOperand(const MachineOperand &MO, 253 MCOperand &MCOp) const { 254 switch (MO.getType()) { 255 default: 256 llvm_unreachable("unknown operand type"); 257 case MachineOperand::MO_Register: 258 // Ignore all implicit register operands. 259 if (MO.isImplicit()) 260 return false; 261 MCOp = MCOperand::createReg(MO.getReg()); 262 break; 263 case MachineOperand::MO_RegisterMask: 264 // Regmasks are like implicit defs. 265 return false; 266 case MachineOperand::MO_Immediate: 267 MCOp = MCOperand::createImm(MO.getImm()); 268 break; 269 case MachineOperand::MO_MachineBasicBlock: 270 MCOp = MCOperand::createExpr( 271 MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), Ctx)); 272 break; 273 case MachineOperand::MO_GlobalAddress: 274 MCOp = LowerSymbolOperand(MO, GetGlobalAddressSymbol(MO)); 275 break; 276 case MachineOperand::MO_ExternalSymbol: 277 MCOp = LowerSymbolOperand(MO, GetExternalSymbolSymbol(MO)); 278 break; 279 case MachineOperand::MO_MCSymbol: 280 MCOp = LowerSymbolOperand(MO, MO.getMCSymbol()); 281 break; 282 case MachineOperand::MO_JumpTableIndex: 283 MCOp = LowerSymbolOperand(MO, Printer.GetJTISymbol(MO.getIndex())); 284 break; 285 case MachineOperand::MO_ConstantPoolIndex: 286 MCOp = LowerSymbolOperand(MO, Printer.GetCPISymbol(MO.getIndex())); 287 break; 288 case MachineOperand::MO_BlockAddress: 289 MCOp = LowerSymbolOperand( 290 MO, Printer.GetBlockAddressSymbol(MO.getBlockAddress())); 291 break; 292 } 293 return true; 294 } 295 296 void AArch64MCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const { 297 OutMI.setOpcode(MI->getOpcode()); 298 299 for (const MachineOperand &MO : MI->operands()) { 300 MCOperand MCOp; 301 if (lowerOperand(MO, MCOp)) 302 OutMI.addOperand(MCOp); 303 } 304 305 switch (OutMI.getOpcode()) { 306 case AArch64::CATCHRET: 307 OutMI = MCInst(); 308 OutMI.setOpcode(AArch64::RET); 309 OutMI.addOperand(MCOperand::createReg(AArch64::LR)); 310 break; 311 case AArch64::CLEANUPRET: 312 OutMI = MCInst(); 313 OutMI.setOpcode(AArch64::RET); 314 OutMI.addOperand(MCOperand::createReg(AArch64::LR)); 315 break; 316 } 317 } 318