1 //==-- AArch64MCInstLower.cpp - Convert AArch64 MachineInstr to an MCInst --==//
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
7 //===----------------------------------------------------------------------===//
9 // This file contains code to lower AArch64 MachineInstrs to their corresponding
12 //===----------------------------------------------------------------------===//
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"
31 extern cl::opt
<bool> EnableAArch64ELFLocalDynamicTLSGeneration
;
33 AArch64MCInstLower::AArch64MCInstLower(MCContext
&ctx
, AsmPrinter
&printer
)
34 : Ctx(ctx
), Printer(printer
) {}
37 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
);
44 assert(TheTriple
.isOSWindows() &&
45 "Windows is the only supported COFF target");
47 bool IsIndirect
= (TargetFlags
& (AArch64II::MO_DLLIMPORT
| AArch64II::MO_COFFSTUB
));
49 return Printer
.getSymbol(GV
);
51 SmallString
<128> Name
;
52 if (TargetFlags
& AArch64II::MO_DLLIMPORT
)
54 else if (TargetFlags
& AArch64II::MO_COFFSTUB
)
56 Printer
.TM
.getNameWithPrefix(Name
, GV
,
57 Printer
.getObjFileLowering().getMangler());
59 MCSymbol
*MCSym
= Ctx
.getOrCreateSymbol(Name
);
61 if (TargetFlags
& AArch64II::MO_COFFSTUB
) {
62 MachineModuleInfoCOFF
&MMICOFF
=
63 Printer
.MMI
->getObjFileInfo
<MachineModuleInfoCOFF
>();
64 MachineModuleInfoImpl::StubValueTy
&StubSym
=
65 MMICOFF
.getGVStubEntry(MCSym
);
67 if (!StubSym
.getPointer())
68 StubSym
= MachineModuleInfoImpl::StubValueTy(Printer
.getSymbol(GV
), true);
75 AArch64MCInstLower::GetExternalSymbolSymbol(const MachineOperand
&MO
) const {
76 return Printer
.GetExternalSymbolSymbol(MO
.getSymbolName());
79 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
;
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
;
99 llvm_unreachable("Unexpected target flags with MO_TLS on GV operand");
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
;
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
);
114 MCOperand
AArch64MCInstLower::lowerSymbolOperandELF(const MachineOperand
&MO
,
115 MCSymbol
*Sym
) const {
116 uint32_t RefFlags
= 0;
118 if (MO
.getTargetFlags() & AArch64II::MO_GOT
)
119 RefFlags
|= AArch64MCExpr::VK_GOT
;
120 else if (MO
.getTargetFlags() & AArch64II::MO_TLS
) {
121 TLSModel::Model Model
;
123 const GlobalValue
*GV
= MO
.getGlobal();
124 Model
= Printer
.TM
.getTLSModel(GV
);
125 if (!EnableAArch64ELFLocalDynamicTLSGeneration
&&
126 Model
== TLSModel::LocalDynamic
)
127 Model
= TLSModel::GeneralDynamic
;
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
;
138 case TLSModel::InitialExec
:
139 RefFlags
|= AArch64MCExpr::VK_GOTTPREL
;
141 case TLSModel::LocalExec
:
142 RefFlags
|= AArch64MCExpr::VK_TPREL
;
144 case TLSModel::LocalDynamic
:
145 RefFlags
|= AArch64MCExpr::VK_DTPREL
;
147 case TLSModel::GeneralDynamic
:
148 RefFlags
|= AArch64MCExpr::VK_TLSDESC
;
152 // No modifier means this is a generic reference, classified as absolute for
153 // the cases where it matters (:abs_g0: etc).
154 RefFlags
|= AArch64MCExpr::VK_ABS
;
157 if ((MO
.getTargetFlags() & AArch64II::MO_FRAGMENT
) == AArch64II::MO_PAGE
)
158 RefFlags
|= AArch64MCExpr::VK_PAGE
;
159 else if ((MO
.getTargetFlags() & AArch64II::MO_FRAGMENT
) ==
160 AArch64II::MO_PAGEOFF
)
161 RefFlags
|= AArch64MCExpr::VK_PAGEOFF
;
162 else if ((MO
.getTargetFlags() & AArch64II::MO_FRAGMENT
) == AArch64II::MO_G3
)
163 RefFlags
|= AArch64MCExpr::VK_G3
;
164 else if ((MO
.getTargetFlags() & AArch64II::MO_FRAGMENT
) == AArch64II::MO_G2
)
165 RefFlags
|= AArch64MCExpr::VK_G2
;
166 else if ((MO
.getTargetFlags() & AArch64II::MO_FRAGMENT
) == AArch64II::MO_G1
)
167 RefFlags
|= AArch64MCExpr::VK_G1
;
168 else if ((MO
.getTargetFlags() & AArch64II::MO_FRAGMENT
) == AArch64II::MO_G0
)
169 RefFlags
|= AArch64MCExpr::VK_G0
;
170 else if ((MO
.getTargetFlags() & AArch64II::MO_FRAGMENT
) == AArch64II::MO_HI12
)
171 RefFlags
|= AArch64MCExpr::VK_HI12
;
173 if (MO
.getTargetFlags() & AArch64II::MO_NC
)
174 RefFlags
|= AArch64MCExpr::VK_NC
;
177 MCSymbolRefExpr::create(Sym
, MCSymbolRefExpr::VK_None
, Ctx
);
178 if (!MO
.isJTI() && MO
.getOffset())
179 Expr
= MCBinaryExpr::createAdd(
180 Expr
, MCConstantExpr::create(MO
.getOffset(), Ctx
), Ctx
);
182 AArch64MCExpr::VariantKind RefKind
;
183 RefKind
= static_cast<AArch64MCExpr::VariantKind
>(RefFlags
);
184 Expr
= AArch64MCExpr::create(Expr
, RefKind
, Ctx
);
186 return MCOperand::createExpr(Expr
);
189 MCOperand
AArch64MCInstLower::lowerSymbolOperandCOFF(const MachineOperand
&MO
,
190 MCSymbol
*Sym
) const {
191 uint32_t RefFlags
= 0;
193 if (MO
.getTargetFlags() & AArch64II::MO_TLS
) {
194 if ((MO
.getTargetFlags() & AArch64II::MO_FRAGMENT
) == AArch64II::MO_PAGEOFF
)
195 RefFlags
|= AArch64MCExpr::VK_SECREL_LO12
;
196 else if ((MO
.getTargetFlags() & AArch64II::MO_FRAGMENT
) ==
198 RefFlags
|= AArch64MCExpr::VK_SECREL_HI12
;
200 } else if (MO
.getTargetFlags() & AArch64II::MO_S
) {
201 RefFlags
|= AArch64MCExpr::VK_SABS
;
203 RefFlags
|= AArch64MCExpr::VK_ABS
;
206 if ((MO
.getTargetFlags() & AArch64II::MO_FRAGMENT
) == AArch64II::MO_G3
)
207 RefFlags
|= AArch64MCExpr::VK_G3
;
208 else if ((MO
.getTargetFlags() & AArch64II::MO_FRAGMENT
) == AArch64II::MO_G2
)
209 RefFlags
|= AArch64MCExpr::VK_G2
;
210 else if ((MO
.getTargetFlags() & AArch64II::MO_FRAGMENT
) == AArch64II::MO_G1
)
211 RefFlags
|= AArch64MCExpr::VK_G1
;
212 else if ((MO
.getTargetFlags() & AArch64II::MO_FRAGMENT
) == AArch64II::MO_G0
)
213 RefFlags
|= AArch64MCExpr::VK_G0
;
215 // FIXME: Currently we only set VK_NC for MO_G3/MO_G2/MO_G1/MO_G0. This is
216 // because setting VK_NC for others would mean setting their respective
217 // RefFlags correctly. We should do this in a separate patch.
218 if (MO
.getTargetFlags() & AArch64II::MO_NC
) {
219 auto MOFrag
= (MO
.getTargetFlags() & AArch64II::MO_FRAGMENT
);
220 if (MOFrag
== AArch64II::MO_G3
|| MOFrag
== AArch64II::MO_G2
||
221 MOFrag
== AArch64II::MO_G1
|| MOFrag
== AArch64II::MO_G0
)
222 RefFlags
|= AArch64MCExpr::VK_NC
;
226 MCSymbolRefExpr::create(Sym
, MCSymbolRefExpr::VK_None
, Ctx
);
227 if (!MO
.isJTI() && MO
.getOffset())
228 Expr
= MCBinaryExpr::createAdd(
229 Expr
, MCConstantExpr::create(MO
.getOffset(), Ctx
), Ctx
);
231 auto RefKind
= static_cast<AArch64MCExpr::VariantKind
>(RefFlags
);
232 assert(RefKind
!= AArch64MCExpr::VK_INVALID
&&
233 "Invalid relocation requested");
234 Expr
= AArch64MCExpr::create(Expr
, RefKind
, Ctx
);
236 return MCOperand::createExpr(Expr
);
239 MCOperand
AArch64MCInstLower::LowerSymbolOperand(const MachineOperand
&MO
,
240 MCSymbol
*Sym
) const {
241 if (Printer
.TM
.getTargetTriple().isOSDarwin())
242 return lowerSymbolOperandDarwin(MO
, Sym
);
243 if (Printer
.TM
.getTargetTriple().isOSBinFormatCOFF())
244 return lowerSymbolOperandCOFF(MO
, Sym
);
246 assert(Printer
.TM
.getTargetTriple().isOSBinFormatELF() && "Invalid target");
247 return lowerSymbolOperandELF(MO
, Sym
);
250 bool AArch64MCInstLower::lowerOperand(const MachineOperand
&MO
,
251 MCOperand
&MCOp
) const {
252 switch (MO
.getType()) {
254 llvm_unreachable("unknown operand type");
255 case MachineOperand::MO_Register
:
256 // Ignore all implicit register operands.
259 MCOp
= MCOperand::createReg(MO
.getReg());
261 case MachineOperand::MO_RegisterMask
:
262 // Regmasks are like implicit defs.
264 case MachineOperand::MO_Immediate
:
265 MCOp
= MCOperand::createImm(MO
.getImm());
267 case MachineOperand::MO_MachineBasicBlock
:
268 MCOp
= MCOperand::createExpr(
269 MCSymbolRefExpr::create(MO
.getMBB()->getSymbol(), Ctx
));
271 case MachineOperand::MO_GlobalAddress
:
272 MCOp
= LowerSymbolOperand(MO
, GetGlobalAddressSymbol(MO
));
274 case MachineOperand::MO_ExternalSymbol
:
275 MCOp
= LowerSymbolOperand(MO
, GetExternalSymbolSymbol(MO
));
277 case MachineOperand::MO_MCSymbol
:
278 MCOp
= LowerSymbolOperand(MO
, MO
.getMCSymbol());
280 case MachineOperand::MO_JumpTableIndex
:
281 MCOp
= LowerSymbolOperand(MO
, Printer
.GetJTISymbol(MO
.getIndex()));
283 case MachineOperand::MO_ConstantPoolIndex
:
284 MCOp
= LowerSymbolOperand(MO
, Printer
.GetCPISymbol(MO
.getIndex()));
286 case MachineOperand::MO_BlockAddress
:
287 MCOp
= LowerSymbolOperand(
288 MO
, Printer
.GetBlockAddressSymbol(MO
.getBlockAddress()));
294 void AArch64MCInstLower::Lower(const MachineInstr
*MI
, MCInst
&OutMI
) const {
295 OutMI
.setOpcode(MI
->getOpcode());
297 for (const MachineOperand
&MO
: MI
->operands()) {
299 if (lowerOperand(MO
, MCOp
))
300 OutMI
.addOperand(MCOp
);
303 switch (OutMI
.getOpcode()) {
304 case AArch64::CATCHRET
:
306 OutMI
.setOpcode(AArch64::RET
);
307 OutMI
.addOperand(MCOperand::createReg(AArch64::LR
));
309 case AArch64::CLEANUPRET
:
311 OutMI
.setOpcode(AArch64::RET
);
312 OutMI
.addOperand(MCOperand::createReg(AArch64::LR
));