1 //==-- AArch64MCInstLower.cpp - Convert AArch64 MachineInstr to an MCInst --==//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file contains code to lower AArch64 MachineInstrs to their corresponding
11 // MCInst records.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "AArch64MCInstLower.h"
16 #include "MCTargetDesc/AArch64MCExpr.h"
17 #include "Utils/AArch64BaseInfo.h"
18 #include "llvm/CodeGen/AsmPrinter.h"
19 #include "llvm/CodeGen/MachineBasicBlock.h"
20 #include "llvm/CodeGen/MachineInstr.h"
21 #include "llvm/CodeGen/MachineModuleInfoImpls.h"
22 #include "llvm/IR/Mangler.h"
23 #include "llvm/MC/MCContext.h"
24 #include "llvm/MC/MCExpr.h"
25 #include "llvm/MC/MCInst.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.getSymbol(GV);
44 
45   assert(TheTriple.isOSWindows() &&
46          "Windows is the only supported COFF target");
47 
48   bool IsIndirect = (TargetFlags & (AArch64II::MO_DLLIMPORT | AArch64II::MO_COFFSTUB));
49   if (!IsIndirect)
50     return Printer.getSymbol(GV);
51 
52   SmallString<128> Name;
53   if (TargetFlags & AArch64II::MO_DLLIMPORT)
54     Name = "__imp_";
55   else if (TargetFlags & AArch64II::MO_COFFSTUB)
56     Name = ".refptr.";
57   Printer.TM.getNameWithPrefix(Name, GV,
58                                Printer.getObjFileLowering().getMangler());
59 
60   MCSymbol *MCSym = Ctx.getOrCreateSymbol(Name);
61 
62   if (TargetFlags & AArch64II::MO_COFFSTUB) {
63     MachineModuleInfoCOFF &MMICOFF =
64         Printer.MMI->getObjFileInfo<MachineModuleInfoCOFF>();
65     MachineModuleInfoImpl::StubValueTy &StubSym =
66         MMICOFF.getGVStubEntry(MCSym);
67 
68     if (!StubSym.getPointer())
69       StubSym = MachineModuleInfoImpl::StubValueTy(Printer.getSymbol(GV), true);
70   }
71 
72   return MCSym;
73 }
74 
75 MCSymbol *
76 AArch64MCInstLower::GetExternalSymbolSymbol(const MachineOperand &MO) const {
77   return Printer.GetExternalSymbolSymbol(MO.getSymbolName());
78 }
79 
80 MCOperand AArch64MCInstLower::lowerSymbolOperandDarwin(const MachineOperand &MO,
81                                                        MCSymbol *Sym) const {
82   // FIXME: We would like an efficient form for this, so we don't have to do a
83   // lot of extra uniquing.
84   MCSymbolRefExpr::VariantKind RefKind = MCSymbolRefExpr::VK_None;
85   if ((MO.getTargetFlags() & AArch64II::MO_GOT) != 0) {
86     if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
87       RefKind = MCSymbolRefExpr::VK_GOTPAGE;
88     else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
89              AArch64II::MO_PAGEOFF)
90       RefKind = MCSymbolRefExpr::VK_GOTPAGEOFF;
91     else
92       llvm_unreachable("Unexpected target flags with MO_GOT on GV operand");
93   } else if ((MO.getTargetFlags() & AArch64II::MO_TLS) != 0) {
94     if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
95       RefKind = MCSymbolRefExpr::VK_TLVPPAGE;
96     else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
97              AArch64II::MO_PAGEOFF)
98       RefKind = MCSymbolRefExpr::VK_TLVPPAGEOFF;
99     else
100       llvm_unreachable("Unexpected target flags with MO_TLS on GV operand");
101   } else {
102     if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
103       RefKind = MCSymbolRefExpr::VK_PAGE;
104     else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
105              AArch64II::MO_PAGEOFF)
106       RefKind = MCSymbolRefExpr::VK_PAGEOFF;
107   }
108   const MCExpr *Expr = MCSymbolRefExpr::create(Sym, RefKind, Ctx);
109   if (!MO.isJTI() && MO.getOffset())
110     Expr = MCBinaryExpr::createAdd(
111         Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
112   return MCOperand::createExpr(Expr);
113 }
114 
115 MCOperand AArch64MCInstLower::lowerSymbolOperandELF(const MachineOperand &MO,
116                                                     MCSymbol *Sym) const {
117   uint32_t RefFlags = 0;
118 
119   if (MO.getTargetFlags() & AArch64II::MO_GOT)
120     RefFlags |= AArch64MCExpr::VK_GOT;
121   else if (MO.getTargetFlags() & AArch64II::MO_TLS) {
122     TLSModel::Model Model;
123     if (MO.isGlobal()) {
124       const GlobalValue *GV = MO.getGlobal();
125       Model = Printer.TM.getTLSModel(GV);
126       if (!EnableAArch64ELFLocalDynamicTLSGeneration &&
127           Model == TLSModel::LocalDynamic)
128         Model = TLSModel::GeneralDynamic;
129 
130     } else {
131       assert(MO.isSymbol() &&
132              StringRef(MO.getSymbolName()) == "_TLS_MODULE_BASE_" &&
133              "unexpected external TLS symbol");
134       // The general dynamic access sequence is used to get the
135       // address of _TLS_MODULE_BASE_.
136       Model = TLSModel::GeneralDynamic;
137     }
138     switch (Model) {
139     case TLSModel::InitialExec:
140       RefFlags |= AArch64MCExpr::VK_GOTTPREL;
141       break;
142     case TLSModel::LocalExec:
143       RefFlags |= AArch64MCExpr::VK_TPREL;
144       break;
145     case TLSModel::LocalDynamic:
146       RefFlags |= AArch64MCExpr::VK_DTPREL;
147       break;
148     case TLSModel::GeneralDynamic:
149       RefFlags |= AArch64MCExpr::VK_TLSDESC;
150       break;
151     }
152   } else {
153     // No modifier means this is a generic reference, classified as absolute for
154     // the cases where it matters (:abs_g0: etc).
155     RefFlags |= AArch64MCExpr::VK_ABS;
156   }
157 
158   if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
159     RefFlags |= AArch64MCExpr::VK_PAGE;
160   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
161            AArch64II::MO_PAGEOFF)
162     RefFlags |= AArch64MCExpr::VK_PAGEOFF;
163   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G3)
164     RefFlags |= AArch64MCExpr::VK_G3;
165   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G2)
166     RefFlags |= AArch64MCExpr::VK_G2;
167   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G1)
168     RefFlags |= AArch64MCExpr::VK_G1;
169   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G0)
170     RefFlags |= AArch64MCExpr::VK_G0;
171   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_HI12)
172     RefFlags |= AArch64MCExpr::VK_HI12;
173 
174   if (MO.getTargetFlags() & AArch64II::MO_NC)
175     RefFlags |= AArch64MCExpr::VK_NC;
176 
177   const MCExpr *Expr =
178       MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Ctx);
179   if (!MO.isJTI() && MO.getOffset())
180     Expr = MCBinaryExpr::createAdd(
181         Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
182 
183   AArch64MCExpr::VariantKind RefKind;
184   RefKind = static_cast<AArch64MCExpr::VariantKind>(RefFlags);
185   Expr = AArch64MCExpr::create(Expr, RefKind, Ctx);
186 
187   return MCOperand::createExpr(Expr);
188 }
189 
190 MCOperand AArch64MCInstLower::lowerSymbolOperandCOFF(const MachineOperand &MO,
191                                                      MCSymbol *Sym) const {
192   AArch64MCExpr::VariantKind RefKind = AArch64MCExpr::VK_NONE;
193   if (MO.getTargetFlags() & AArch64II::MO_TLS) {
194     if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGEOFF)
195       RefKind = AArch64MCExpr::VK_SECREL_LO12;
196     else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
197              AArch64II::MO_HI12)
198       RefKind = AArch64MCExpr::VK_SECREL_HI12;
199   }
200   const MCExpr *Expr =
201       MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Ctx);
202   if (!MO.isJTI() && MO.getOffset())
203     Expr = MCBinaryExpr::createAdd(
204         Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
205   Expr = AArch64MCExpr::create(Expr, RefKind, Ctx);
206   return MCOperand::createExpr(Expr);
207 }
208 
209 MCOperand AArch64MCInstLower::LowerSymbolOperand(const MachineOperand &MO,
210                                                  MCSymbol *Sym) const {
211   if (Printer.TM.getTargetTriple().isOSDarwin())
212     return lowerSymbolOperandDarwin(MO, Sym);
213   if (Printer.TM.getTargetTriple().isOSBinFormatCOFF())
214     return lowerSymbolOperandCOFF(MO, Sym);
215 
216   assert(Printer.TM.getTargetTriple().isOSBinFormatELF() && "Invalid target");
217   return lowerSymbolOperandELF(MO, Sym);
218 }
219 
220 bool AArch64MCInstLower::lowerOperand(const MachineOperand &MO,
221                                       MCOperand &MCOp) const {
222   switch (MO.getType()) {
223   default:
224     llvm_unreachable("unknown operand type");
225   case MachineOperand::MO_Register:
226     // Ignore all implicit register operands.
227     if (MO.isImplicit())
228       return false;
229     MCOp = MCOperand::createReg(MO.getReg());
230     break;
231   case MachineOperand::MO_RegisterMask:
232     // Regmasks are like implicit defs.
233     return false;
234   case MachineOperand::MO_Immediate:
235     MCOp = MCOperand::createImm(MO.getImm());
236     break;
237   case MachineOperand::MO_MachineBasicBlock:
238     MCOp = MCOperand::createExpr(
239         MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), Ctx));
240     break;
241   case MachineOperand::MO_GlobalAddress:
242     MCOp = LowerSymbolOperand(MO, GetGlobalAddressSymbol(MO));
243     break;
244   case MachineOperand::MO_ExternalSymbol:
245     MCOp = LowerSymbolOperand(MO, GetExternalSymbolSymbol(MO));
246     break;
247   case MachineOperand::MO_MCSymbol:
248     MCOp = LowerSymbolOperand(MO, MO.getMCSymbol());
249     break;
250   case MachineOperand::MO_JumpTableIndex:
251     MCOp = LowerSymbolOperand(MO, Printer.GetJTISymbol(MO.getIndex()));
252     break;
253   case MachineOperand::MO_ConstantPoolIndex:
254     MCOp = LowerSymbolOperand(MO, Printer.GetCPISymbol(MO.getIndex()));
255     break;
256   case MachineOperand::MO_BlockAddress:
257     MCOp = LowerSymbolOperand(
258         MO, Printer.GetBlockAddressSymbol(MO.getBlockAddress()));
259     break;
260   }
261   return true;
262 }
263 
264 void AArch64MCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const {
265   OutMI.setOpcode(MI->getOpcode());
266 
267   for (const MachineOperand &MO : MI->operands()) {
268     MCOperand MCOp;
269     if (lowerOperand(MO, MCOp))
270       OutMI.addOperand(MCOp);
271   }
272 }
273