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