AArch64MCInstLower.cpp 13 KB

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