1 //===-- ARMMCInstLower.cpp - Convert ARM 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 ARM MachineInstrs to their corresponding
11 // MCInst records.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "ARM.h"
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"
30 using namespace llvm;
31 
32 
33 MCOperand ARMAsmPrinter::GetSymbolRef(const MachineOperand &MO,
34                                       const MCSymbol *Symbol) {
35   const MCExpr *Expr =
36       MCSymbolRefExpr::create(Symbol, MCSymbolRefExpr::VK_None, OutContext);
37   switch (MO.getTargetFlags() & ARMII::MO_OPTION_MASK) {
38   default:
39     llvm_unreachable("Unknown target flag on symbol operand");
40   case ARMII::MO_NO_FLAG:
41     break;
42   case ARMII::MO_LO16:
43     Expr =
44         MCSymbolRefExpr::create(Symbol, MCSymbolRefExpr::VK_None, OutContext);
45     Expr = ARMMCExpr::createLower16(Expr, OutContext);
46     break;
47   case ARMII::MO_HI16:
48     Expr =
49         MCSymbolRefExpr::create(Symbol, MCSymbolRefExpr::VK_None, OutContext);
50     Expr = ARMMCExpr::createUpper16(Expr, OutContext);
51     break;
52   }
53 
54   if (!MO.isJTI() && MO.getOffset())
55     Expr = MCBinaryExpr::createAdd(Expr,
56                                    MCConstantExpr::create(MO.getOffset(),
57                                                           OutContext),
58                                    OutContext);
59   return MCOperand::createExpr(Expr);
60 
61 }
62 
63 bool ARMAsmPrinter::lowerOperand(const MachineOperand &MO,
64                                  MCOperand &MCOp) {
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)
70       return false;
71     assert(!MO.getSubReg() && "Subregs should be eliminated!");
72     MCOp = MCOperand::createReg(MO.getReg());
73     break;
74   case MachineOperand::MO_Immediate:
75     MCOp = MCOperand::createImm(MO.getImm());
76     break;
77   case MachineOperand::MO_MachineBasicBlock:
78     MCOp = MCOperand::createExpr(MCSymbolRefExpr::create(
79         MO.getMBB()->getSymbol(), OutContext));
80     break;
81   case MachineOperand::MO_GlobalAddress: {
82     MCOp = GetSymbolRef(MO,
83                         GetARMGVSymbol(MO.getGlobal(), MO.getTargetFlags()));
84     break;
85   }
86   case MachineOperand::MO_ExternalSymbol:
87     MCOp = GetSymbolRef(MO,
88                         GetExternalSymbolSymbol(MO.getSymbolName()));
89     break;
90   case MachineOperand::MO_JumpTableIndex:
91     MCOp = GetSymbolRef(MO, GetJTISymbol(MO.getIndex()));
92     break;
93   case MachineOperand::MO_ConstantPoolIndex:
94     MCOp = GetSymbolRef(MO, GetCPISymbol(MO.getIndex()));
95     break;
96   case MachineOperand::MO_BlockAddress:
97     MCOp = GetSymbolRef(MO, GetBlockAddressSymbol(MO.getBlockAddress()));
98     break;
99   case MachineOperand::MO_FPImmediate: {
100     APFloat Val = MO.getFPImm()->getValueAPF();
101     bool ignored;
102     Val.convert(APFloat::IEEEdouble, APFloat::rmTowardZero, &ignored);
103     MCOp = MCOperand::createFPImm(Val.convertToDouble());
104     break;
105   }
106   case MachineOperand::MO_RegisterMask:
107     // Ignore call clobbers.
108     return false;
109   }
110   return true;
111 }
112 
113 void llvm::LowerARMMachineInstrToMCInst(const MachineInstr *MI, MCInst &OutMI,
114                                         ARMAsmPrinter &AP) {
115   OutMI.setOpcode(MI->getOpcode());
116 
117   // In the MC layer, we keep modified immediates in their encoded form
118   bool EncodeImms = false;
119   switch (MI->getOpcode()) {
120   default: break;
121   case ARM::MOVi:
122   case ARM::MVNi:
123   case ARM::CMPri:
124   case ARM::CMNri:
125   case ARM::TSTri:
126   case ARM::TEQri:
127   case ARM::MSRi:
128   case ARM::ADCri:
129   case ARM::ADDri:
130   case ARM::ADDSri:
131   case ARM::SBCri:
132   case ARM::SUBri:
133   case ARM::SUBSri:
134   case ARM::ANDri:
135   case ARM::ORRri:
136   case ARM::EORri:
137   case ARM::BICri:
138   case ARM::RSBri:
139   case ARM::RSBSri:
140   case ARM::RSCri:
141     EncodeImms = true;
142     break;
143   }
144 
145   for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
146     const MachineOperand &MO = MI->getOperand(i);
147 
148     MCOperand MCOp;
149     if (AP.lowerOperand(MO, MCOp)) {
150       if (MCOp.isImm() && EncodeImms) {
151         int32_t Enc = ARM_AM::getSOImmVal(MCOp.getImm());
152         if (Enc != -1)
153           MCOp.setImm(Enc);
154       }
155       OutMI.addOperand(MCOp);
156     }
157   }
158 }
159 
160 void ARMAsmPrinter::EmitSled(const MachineInstr &MI, SledKind Kind)
161 {
162   if (MI.getParent()->getParent()->getInfo<ARMFunctionInfo>()
163     ->isThumbFunction())
164   {
165     MI.emitError("An attempt to perform XRay instrumentation for a"
166       " Thumb function (not supported). Detected when emitting a sled.");
167     return;
168   }
169   static const int8_t NoopsInSledCount = 6;
170   // We want to emit the following pattern:
171   //
172   // .Lxray_sled_N:
173   //   ALIGN
174   //   B #20
175   //   ; 6 NOP instructions (24 bytes)
176   // .tmpN
177   //
178   // We need the 24 bytes (6 instructions) because at runtime, we'd be patching
179   // over the full 28 bytes (7 instructions) with the following pattern:
180   //
181   //   PUSH{ r0, lr }
182   //   MOVW r0, #<lower 16 bits of function ID>
183   //   MOVT r0, #<higher 16 bits of function ID>
184   //   MOVW ip, #<lower 16 bits of address of __xray_FunctionEntry/Exit>
185   //   MOVT ip, #<higher 16 bits of address of __xray_FunctionEntry/Exit>
186   //   BLX ip
187   //   POP{ r0, lr }
188   //
189   OutStreamer->EmitCodeAlignment(4);
190   auto CurSled = OutContext.createTempSymbol("xray_sled_", true);
191   OutStreamer->EmitLabel(CurSled);
192   auto Target = OutContext.createTempSymbol();
193 
194   // Emit "B #20" instruction, which jumps over the next 24 bytes (because
195   // register pc is 8 bytes ahead of the jump instruction by the moment CPU
196   // is executing it).
197   // By analogy to ARMAsmPrinter::emitPseudoExpansionLowering() |case ARM::B|.
198   // It is not clear why |addReg(0)| is needed (the last operand).
199   EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::Bcc).addImm(20)
200     .addImm(ARMCC::AL).addReg(0));
201 
202   MCInst Noop;
203   Subtarget->getInstrInfo()->getNoopForElfTarget(Noop);
204   for (int8_t I = 0; I < NoopsInSledCount; I++)
205   {
206     OutStreamer->EmitInstruction(Noop, getSubtargetInfo());
207   }
208 
209   OutStreamer->EmitLabel(Target);
210   recordSled(CurSled, MI, Kind);
211 }
212 
213 void ARMAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI)
214 {
215   EmitSled(MI, SledKind::FUNCTION_ENTER);
216 }
217 
218 void ARMAsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI)
219 {
220   EmitSled(MI, SledKind::FUNCTION_EXIT);
221 }
222 
223 void ARMAsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI)
224 {
225   EmitSled(MI, SledKind::TAIL_CALL);
226 }
227 
228 void ARMAsmPrinter::EmitXRayTable()
229 {
230   if (Sleds.empty())
231     return;
232 
233   MCSection *Section = nullptr;
234   if (Subtarget->isTargetELF()) {
235     Section = OutContext.getELFSection("xray_instr_map", ELF::SHT_PROGBITS,
236                                        ELF::SHF_ALLOC | ELF::SHF_GROUP |
237                                            ELF::SHF_MERGE,
238                                        0, CurrentFnSym->getName());
239   } else if (Subtarget->isTargetMachO()) {
240     Section = OutContext.getMachOSection("__DATA", "xray_instr_map", 0,
241                                          SectionKind::getReadOnlyWithRel());
242   } else {
243     llvm_unreachable("Unsupported target");
244   }
245 
246   auto PrevSection = OutStreamer->getCurrentSectionOnly();
247   OutStreamer->SwitchSection(Section);
248   for (const auto &Sled : Sleds) {
249     OutStreamer->EmitSymbolValue(Sled.Sled, 4);
250     OutStreamer->EmitSymbolValue(CurrentFnSym, 4);
251     auto Kind = static_cast<uint8_t>(Sled.Kind);
252     OutStreamer->EmitBytes(
253       StringRef(reinterpret_cast<const char *>(&Kind), 1));
254     OutStreamer->EmitBytes(
255       StringRef(reinterpret_cast<const char *>(&Sled.AlwaysInstrument), 1));
256     OutStreamer->EmitZeros(6);
257   }
258   OutStreamer->SwitchSection(PrevSection);
259 
260   Sleds.clear();
261 }
262