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 
AArch64MCInstLower(MCContext & ctx,AsmPrinter & printer)33 AArch64MCInstLower::AArch64MCInstLower(MCContext &ctx, AsmPrinter &printer)
34     : Ctx(ctx), Printer(printer) {}
35 
36 MCSymbol *
GetGlobalAddressSymbol(const MachineOperand & MO) const37 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 *
GetExternalSymbolSymbol(const MachineOperand & MO) const75 AArch64MCInstLower::GetExternalSymbolSymbol(const MachineOperand &MO) const {
76   return Printer.GetExternalSymbolSymbol(MO.getSymbolName());
77 }
78 
lowerSymbolOperandDarwin(const MachineOperand & MO,MCSymbol * Sym) const79 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 
lowerSymbolOperandELF(const MachineOperand & MO,MCSymbol * Sym) const114 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 
lowerSymbolOperandCOFF(const MachineOperand & MO,MCSymbol * Sym) const191 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 
LowerSymbolOperand(const MachineOperand & MO,MCSymbol * Sym) const247 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 
lowerOperand(const MachineOperand & MO,MCOperand & MCOp) const258 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 
Lower(const MachineInstr * MI,MCInst & OutMI) const302 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