1 //===-- ARMMCInstLower.cpp - Convert ARM 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 ARM MachineInstrs to their corresponding
13 //===----------------------------------------------------------------------===//
16 #include "ARMAsmPrinter.h"
17 #include "MCTargetDesc/ARMBaseInfo.h"
18 #include "MCTargetDesc/ARMMCExpr.h"
19 #include "llvm/CodeGen/MachineBasicBlock.h"
20 #include "llvm/IR/Constants.h"
21 #include "llvm/IR/Mangler.h"
22 #include "llvm/MC/MCExpr.h"
23 #include "llvm/MC/MCInst.h"
24 #include "llvm/MC/MCContext.h"
25 #include "llvm/MC/MCSymbolELF.h"
26 #include "llvm/MC/MCSectionELF.h"
27 #include "llvm/MC/MCSectionMachO.h"
28 #include "llvm/MC/MCInstBuilder.h"
29 #include "llvm/MC/MCStreamer.h"
33 MCOperand ARMAsmPrinter::GetSymbolRef(const MachineOperand &MO,
34 const MCSymbol *Symbol) {
36 MCSymbolRefExpr::create(Symbol, MCSymbolRefExpr::VK_None, OutContext);
37 switch (MO.getTargetFlags() & ARMII::MO_OPTION_MASK) {
39 llvm_unreachable("Unknown target flag on symbol operand");
40 case ARMII::MO_NO_FLAG:
44 MCSymbolRefExpr::create(Symbol, MCSymbolRefExpr::VK_None, OutContext);
45 Expr = ARMMCExpr::createLower16(Expr, OutContext);
49 MCSymbolRefExpr::create(Symbol, MCSymbolRefExpr::VK_None, OutContext);
50 Expr = ARMMCExpr::createUpper16(Expr, OutContext);
54 if (!MO.isJTI() && MO.getOffset())
55 Expr = MCBinaryExpr::createAdd(Expr,
56 MCConstantExpr::create(MO.getOffset(),
59 return MCOperand::createExpr(Expr);
63 bool ARMAsmPrinter::lowerOperand(const MachineOperand &MO,
65 switch (MO.getType()) {
66 default: llvm_unreachable("unknown operand type");
67 case MachineOperand::MO_Register:
68 // Ignore all non-CPSR implicit register operands.
69 if (MO.isImplicit() && MO.getReg() != ARM::CPSR)
71 assert(!MO.getSubReg() && "Subregs should be eliminated!");
72 MCOp = MCOperand::createReg(MO.getReg());
74 case MachineOperand::MO_Immediate:
75 MCOp = MCOperand::createImm(MO.getImm());
77 case MachineOperand::MO_MachineBasicBlock:
78 MCOp = MCOperand::createExpr(MCSymbolRefExpr::create(
79 MO.getMBB()->getSymbol(), OutContext));
81 case MachineOperand::MO_GlobalAddress: {
82 MCOp = GetSymbolRef(MO,
83 GetARMGVSymbol(MO.getGlobal(), MO.getTargetFlags()));
86 case MachineOperand::MO_ExternalSymbol:
87 MCOp = GetSymbolRef(MO,
88 GetExternalSymbolSymbol(MO.getSymbolName()));
90 case MachineOperand::MO_JumpTableIndex:
91 MCOp = GetSymbolRef(MO, GetJTISymbol(MO.getIndex()));
93 case MachineOperand::MO_ConstantPoolIndex:
94 if (Subtarget->genExecuteOnly())
95 llvm_unreachable("execute-only should not generate constant pools");
96 MCOp = GetSymbolRef(MO, GetCPISymbol(MO.getIndex()));
98 case MachineOperand::MO_BlockAddress:
99 MCOp = GetSymbolRef(MO, GetBlockAddressSymbol(MO.getBlockAddress()));
101 case MachineOperand::MO_FPImmediate: {
102 APFloat Val = MO.getFPImm()->getValueAPF();
104 Val.convert(APFloat::IEEEdouble(), APFloat::rmTowardZero, &ignored);
105 MCOp = MCOperand::createFPImm(Val.convertToDouble());
108 case MachineOperand::MO_RegisterMask:
109 // Ignore call clobbers.
115 void llvm::LowerARMMachineInstrToMCInst(const MachineInstr *MI, MCInst &OutMI,
117 OutMI.setOpcode(MI->getOpcode());
119 // In the MC layer, we keep modified immediates in their encoded form
120 bool EncodeImms = false;
121 switch (MI->getOpcode()) {
147 for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
148 const MachineOperand &MO = MI->getOperand(i);
151 if (AP.lowerOperand(MO, MCOp)) {
152 if (MCOp.isImm() && EncodeImms) {
153 int32_t Enc = ARM_AM::getSOImmVal(MCOp.getImm());
157 OutMI.addOperand(MCOp);
162 void ARMAsmPrinter::EmitSled(const MachineInstr &MI, SledKind Kind)
164 if (MI.getParent()->getParent()->getInfo<ARMFunctionInfo>()
167 MI.emitError("An attempt to perform XRay instrumentation for a"
168 " Thumb function (not supported). Detected when emitting a sled.");
171 static const int8_t NoopsInSledCount = 6;
172 // We want to emit the following pattern:
177 // ; 6 NOP instructions (24 bytes)
180 // We need the 24 bytes (6 instructions) because at runtime, we'd be patching
181 // over the full 28 bytes (7 instructions) with the following pattern:
184 // MOVW r0, #<lower 16 bits of function ID>
185 // MOVT r0, #<higher 16 bits of function ID>
186 // MOVW ip, #<lower 16 bits of address of __xray_FunctionEntry/Exit>
187 // MOVT ip, #<higher 16 bits of address of __xray_FunctionEntry/Exit>
191 OutStreamer->EmitCodeAlignment(4);
192 auto CurSled = OutContext.createTempSymbol("xray_sled_", true);
193 OutStreamer->EmitLabel(CurSled);
194 auto Target = OutContext.createTempSymbol();
196 // Emit "B #20" instruction, which jumps over the next 24 bytes (because
197 // register pc is 8 bytes ahead of the jump instruction by the moment CPU
199 // By analogy to ARMAsmPrinter::emitPseudoExpansionLowering() |case ARM::B|.
200 // It is not clear why |addReg(0)| is needed (the last operand).
201 EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::Bcc).addImm(20)
202 .addImm(ARMCC::AL).addReg(0));
205 Subtarget->getInstrInfo()->getNoopForElfTarget(Noop);
206 for (int8_t I = 0; I < NoopsInSledCount; I++)
208 OutStreamer->EmitInstruction(Noop, getSubtargetInfo());
211 OutStreamer->EmitLabel(Target);
212 recordSled(CurSled, MI, Kind);
215 void ARMAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI)
217 EmitSled(MI, SledKind::FUNCTION_ENTER);
220 void ARMAsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI)
222 EmitSled(MI, SledKind::FUNCTION_EXIT);
225 void ARMAsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI)
227 EmitSled(MI, SledKind::TAIL_CALL);
230 void ARMAsmPrinter::EmitXRayTable()
235 MCSection *Section = nullptr;
236 if (Subtarget->isTargetELF()) {
237 Section = OutContext.getELFSection("xray_instr_map", ELF::SHT_PROGBITS,
238 ELF::SHF_ALLOC | ELF::SHF_GROUP |
240 0, CurrentFnSym->getName());
241 } else if (Subtarget->isTargetMachO()) {
242 Section = OutContext.getMachOSection("__DATA", "xray_instr_map", 0,
243 SectionKind::getReadOnlyWithRel());
245 llvm_unreachable("Unsupported target");
248 auto PrevSection = OutStreamer->getCurrentSectionOnly();
249 OutStreamer->SwitchSection(Section);
250 for (const auto &Sled : Sleds) {
251 OutStreamer->EmitSymbolValue(Sled.Sled, 4);
252 OutStreamer->EmitSymbolValue(CurrentFnSym, 4);
253 auto Kind = static_cast<uint8_t>(Sled.Kind);
254 OutStreamer->EmitBytes(
255 StringRef(reinterpret_cast<const char *>(&Kind), 1));
256 OutStreamer->EmitBytes(
257 StringRef(reinterpret_cast<const char *>(&Sled.AlwaysInstrument), 1));
258 OutStreamer->EmitZeros(6);
260 OutStreamer->SwitchSection(PrevSection);