1 //==-- AArch64MCInstLower.cpp - Convert AArch64 MachineInstr to an MCInst --==//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file contains code to lower AArch64 MachineInstrs to their corresponding
13 //===----------------------------------------------------------------------===//
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"
32 extern cl::opt<bool> EnableAArch64ELFLocalDynamicTLSGeneration;
34 AArch64MCInstLower::AArch64MCInstLower(MCContext &ctx, AsmPrinter &printer)
35 : Ctx(ctx), Printer(printer) {}
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);
45 assert(TheTriple.isOSWindows() &&
46 "Windows is the only supported COFF target");
48 bool IsIndirect = (TargetFlags & (AArch64II::MO_DLLIMPORT | AArch64II::MO_COFFSTUB));
50 return Printer.getSymbol(GV);
52 SmallString<128> Name;
53 if (TargetFlags & AArch64II::MO_DLLIMPORT)
55 else if (TargetFlags & AArch64II::MO_COFFSTUB)
57 Printer.TM.getNameWithPrefix(Name, GV,
58 Printer.getObjFileLowering().getMangler());
60 MCSymbol *MCSym = Ctx.getOrCreateSymbol(Name);
62 if (TargetFlags & AArch64II::MO_COFFSTUB) {
63 MachineModuleInfoCOFF &MMICOFF =
64 Printer.MMI->getObjFileInfo<MachineModuleInfoCOFF>();
65 MachineModuleInfoImpl::StubValueTy &StubSym =
66 MMICOFF.getGVStubEntry(MCSym);
68 if (!StubSym.getPointer())
69 StubSym = MachineModuleInfoImpl::StubValueTy(Printer.getSymbol(GV), true);
76 AArch64MCInstLower::GetExternalSymbolSymbol(const MachineOperand &MO) const {
77 return Printer.GetExternalSymbolSymbol(MO.getSymbolName());
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;
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;
100 llvm_unreachable("Unexpected target flags with MO_TLS on GV operand");
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;
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);
115 MCOperand AArch64MCInstLower::lowerSymbolOperandELF(const MachineOperand &MO,
116 MCSymbol *Sym) const {
117 uint32_t RefFlags = 0;
119 if (MO.getTargetFlags() & AArch64II::MO_GOT)
120 RefFlags |= AArch64MCExpr::VK_GOT;
121 else if (MO.getTargetFlags() & AArch64II::MO_TLS) {
122 TLSModel::Model Model;
124 const GlobalValue *GV = MO.getGlobal();
125 Model = Printer.TM.getTLSModel(GV);
126 if (!EnableAArch64ELFLocalDynamicTLSGeneration &&
127 Model == TLSModel::LocalDynamic)
128 Model = TLSModel::GeneralDynamic;
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;
139 case TLSModel::InitialExec:
140 RefFlags |= AArch64MCExpr::VK_GOTTPREL;
142 case TLSModel::LocalExec:
143 RefFlags |= AArch64MCExpr::VK_TPREL;
145 case TLSModel::LocalDynamic:
146 RefFlags |= AArch64MCExpr::VK_DTPREL;
148 case TLSModel::GeneralDynamic:
149 RefFlags |= AArch64MCExpr::VK_TLSDESC;
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;
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;
174 if (MO.getTargetFlags() & AArch64II::MO_NC)
175 RefFlags |= AArch64MCExpr::VK_NC;
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);
183 AArch64MCExpr::VariantKind RefKind;
184 RefKind = static_cast<AArch64MCExpr::VariantKind>(RefFlags);
185 Expr = AArch64MCExpr::create(Expr, RefKind, Ctx);
187 return MCOperand::createExpr(Expr);
190 MCOperand AArch64MCInstLower::lowerSymbolOperandCOFF(const MachineOperand &MO,
191 MCSymbol *Sym) const {
192 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) ==
199 RefFlags |= AArch64MCExpr::VK_SECREL_HI12;
201 } else if (MO.getTargetFlags() & AArch64II::MO_S) {
202 RefFlags |= AArch64MCExpr::VK_SABS;
204 RefFlags |= AArch64MCExpr::VK_ABS;
207 if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G3)
208 RefFlags |= AArch64MCExpr::VK_G3;
209 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G2)
210 RefFlags |= AArch64MCExpr::VK_G2;
211 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G1)
212 RefFlags |= AArch64MCExpr::VK_G1;
213 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G0)
214 RefFlags |= AArch64MCExpr::VK_G0;
216 // FIXME: Currently we only set VK_NC for MO_G3/MO_G2/MO_G1/MO_G0. This is
217 // because setting VK_NC for others would mean setting their respective
218 // RefFlags correctly. We should do this in a separate patch.
219 if (MO.getTargetFlags() & AArch64II::MO_NC) {
220 auto MOFrag = (MO.getTargetFlags() & AArch64II::MO_FRAGMENT);
221 if (MOFrag == AArch64II::MO_G3 || MOFrag == AArch64II::MO_G2 ||
222 MOFrag == AArch64II::MO_G1 || MOFrag == AArch64II::MO_G0)
223 RefFlags |= AArch64MCExpr::VK_NC;
227 MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Ctx);
228 if (!MO.isJTI() && MO.getOffset())
229 Expr = MCBinaryExpr::createAdd(
230 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);
237 return MCOperand::createExpr(Expr);
240 MCOperand AArch64MCInstLower::LowerSymbolOperand(const MachineOperand &MO,
241 MCSymbol *Sym) const {
242 if (Printer.TM.getTargetTriple().isOSDarwin())
243 return lowerSymbolOperandDarwin(MO, Sym);
244 if (Printer.TM.getTargetTriple().isOSBinFormatCOFF())
245 return lowerSymbolOperandCOFF(MO, Sym);
247 assert(Printer.TM.getTargetTriple().isOSBinFormatELF() && "Invalid target");
248 return lowerSymbolOperandELF(MO, Sym);
251 bool AArch64MCInstLower::lowerOperand(const MachineOperand &MO,
252 MCOperand &MCOp) const {
253 switch (MO.getType()) {
255 llvm_unreachable("unknown operand type");
256 case MachineOperand::MO_Register:
257 // Ignore all implicit register operands.
260 MCOp = MCOperand::createReg(MO.getReg());
262 case MachineOperand::MO_RegisterMask:
263 // Regmasks are like implicit defs.
265 case MachineOperand::MO_Immediate:
266 MCOp = MCOperand::createImm(MO.getImm());
268 case MachineOperand::MO_MachineBasicBlock:
269 MCOp = MCOperand::createExpr(
270 MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), Ctx));
272 case MachineOperand::MO_GlobalAddress:
273 MCOp = LowerSymbolOperand(MO, GetGlobalAddressSymbol(MO));
275 case MachineOperand::MO_ExternalSymbol:
276 MCOp = LowerSymbolOperand(MO, GetExternalSymbolSymbol(MO));
278 case MachineOperand::MO_MCSymbol:
279 MCOp = LowerSymbolOperand(MO, MO.getMCSymbol());
281 case MachineOperand::MO_JumpTableIndex:
282 MCOp = LowerSymbolOperand(MO, Printer.GetJTISymbol(MO.getIndex()));
284 case MachineOperand::MO_ConstantPoolIndex:
285 MCOp = LowerSymbolOperand(MO, Printer.GetCPISymbol(MO.getIndex()));
287 case MachineOperand::MO_BlockAddress:
288 MCOp = LowerSymbolOperand(
289 MO, Printer.GetBlockAddressSymbol(MO.getBlockAddress()));
295 void AArch64MCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const {
296 OutMI.setOpcode(MI->getOpcode());
298 for (const MachineOperand &MO : MI->operands()) {
300 if (lowerOperand(MO, MCOp))
301 OutMI.addOperand(MCOp);
304 switch (OutMI.getOpcode()) {
305 case AArch64::CATCHRET:
307 OutMI.setOpcode(AArch64::RET);
308 OutMI.addOperand(MCOperand::createReg(AArch64::LR));
310 case AArch64::CLEANUPRET:
312 OutMI.setOpcode(AArch64::RET);
313 OutMI.addOperand(MCOperand::createReg(AArch64::LR));