blob: 293a527b09e87cd4cc2f8cf10ff348b8fc80d1a7 [file] [log] [blame]
Chris Lattner78393d72009-10-19 20:21:05 +00001//===-- 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
Chris Lattnerb28e6912010-11-14 20:31:06 +000015#include "ARM.h"
Jim Grosbachd0d13292010-12-01 03:45:07 +000016#include "ARMAsmPrinter.h"
Craig Toppera9253262014-03-22 23:51:00 +000017#include "MCTargetDesc/ARMBaseInfo.h"
Evan Chenga20cde32011-07-20 23:34:39 +000018#include "MCTargetDesc/ARMMCExpr.h"
Chris Lattner1b06acb2009-10-20 00:52:47 +000019#include "llvm/CodeGen/MachineBasicBlock.h"
Chandler Carruth9fb823b2013-01-02 11:36:10 +000020#include "llvm/IR/Constants.h"
Rafael Espindola894843c2014-01-07 21:19:40 +000021#include "llvm/IR/Mangler.h"
Chris Lattner889a6212009-10-19 21:53:00 +000022#include "llvm/MC/MCExpr.h"
Chris Lattner78393d72009-10-19 20:21:05 +000023#include "llvm/MC/MCInst.h"
Dean Michael Berris464015442016-09-19 00:54:35 +000024#include "llvm/MC/MCContext.h"
25#include "llvm/MC/MCSymbolELF.h"
26#include "llvm/MC/MCSectionELF.h"
Kuba Mracek06995e82016-11-23 02:07:04 +000027#include "llvm/MC/MCSectionMachO.h"
Dean Michael Berris464015442016-09-19 00:54:35 +000028#include "llvm/MC/MCInstBuilder.h"
29#include "llvm/MC/MCStreamer.h"
Chris Lattner78393d72009-10-19 20:21:05 +000030using namespace llvm;
31
Chris Lattnerc5afd122010-11-14 20:58:38 +000032
Jim Grosbach95dee402011-07-08 17:40:42 +000033MCOperand ARMAsmPrinter::GetSymbolRef(const MachineOperand &MO,
34 const MCSymbol *Symbol) {
Aaron Ballman86100fc2016-06-20 15:37:15 +000035 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:
Chris Lattner3040e8c2010-11-14 20:40:08 +000041 break;
Aaron Ballman86100fc2016-06-20 15:37:15 +000042 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;
Chris Lattner3040e8c2010-11-14 20:40:08 +000052 }
Jim Grosbach38d90de2010-11-30 23:29:24 +000053
Jim Grosbach0d35df12010-09-17 18:25:25 +000054 if (!MO.isJTI() && MO.getOffset())
Jim Grosbach13760bd2015-05-30 01:25:56 +000055 Expr = MCBinaryExpr::createAdd(Expr,
56 MCConstantExpr::create(MO.getOffset(),
Jim Grosbach95dee402011-07-08 17:40:42 +000057 OutContext),
58 OutContext);
Jim Grosbache9119e42015-05-13 18:37:00 +000059 return MCOperand::createExpr(Expr);
Jim Grosbach38d90de2010-11-30 23:29:24 +000060
Jim Grosbach0d35df12010-09-17 18:25:25 +000061}
62
Jim Grosbach95dee402011-07-08 17:40:42 +000063bool ARMAsmPrinter::lowerOperand(const MachineOperand &MO,
64 MCOperand &MCOp) {
65 switch (MO.getType()) {
Craig Toppere55c5562012-02-07 02:50:20 +000066 default: llvm_unreachable("unknown operand type");
Jim Grosbach95dee402011-07-08 17:40:42 +000067 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!");
Jim Grosbache9119e42015-05-13 18:37:00 +000072 MCOp = MCOperand::createReg(MO.getReg());
Jim Grosbach95dee402011-07-08 17:40:42 +000073 break;
74 case MachineOperand::MO_Immediate:
Jim Grosbache9119e42015-05-13 18:37:00 +000075 MCOp = MCOperand::createImm(MO.getImm());
Jim Grosbach95dee402011-07-08 17:40:42 +000076 break;
77 case MachineOperand::MO_MachineBasicBlock:
Jim Grosbach13760bd2015-05-30 01:25:56 +000078 MCOp = MCOperand::createExpr(MCSymbolRefExpr::create(
Jim Grosbach95dee402011-07-08 17:40:42 +000079 MO.getMBB()->getSymbol(), OutContext));
80 break;
Tim Northoverdb962e2c2013-11-25 16:24:52 +000081 case MachineOperand::MO_GlobalAddress: {
82 MCOp = GetSymbolRef(MO,
83 GetARMGVSymbol(MO.getGlobal(), MO.getTargetFlags()));
Jim Grosbach95dee402011-07-08 17:40:42 +000084 break;
Tim Northoverdb962e2c2013-11-25 16:24:52 +000085 }
Jim Grosbach95dee402011-07-08 17:40:42 +000086 case MachineOperand::MO_ExternalSymbol:
Etienne Bergeron715ec092016-06-21 15:21:04 +000087 MCOp = GetSymbolRef(MO,
Jim Grosbach95dee402011-07-08 17:40:42 +000088 GetExternalSymbolSymbol(MO.getSymbolName()));
89 break;
90 case MachineOperand::MO_JumpTableIndex:
91 MCOp = GetSymbolRef(MO, GetJTISymbol(MO.getIndex()));
92 break;
93 case MachineOperand::MO_ConstantPoolIndex:
Prakhar Bahuguna52a7dd72016-12-15 07:59:08 +000094 if (Subtarget->genExecuteOnly())
95 llvm_unreachable("execute-only should not generate constant pools");
Jim Grosbach95dee402011-07-08 17:40:42 +000096 MCOp = GetSymbolRef(MO, GetCPISymbol(MO.getIndex()));
97 break;
98 case MachineOperand::MO_BlockAddress:
99 MCOp = GetSymbolRef(MO, GetBlockAddressSymbol(MO.getBlockAddress()));
100 break;
101 case MachineOperand::MO_FPImmediate: {
102 APFloat Val = MO.getFPImm()->getValueAPF();
103 bool ignored;
Stephan Bergmann17c7f702016-12-14 11:57:17 +0000104 Val.convert(APFloat::IEEEdouble(), APFloat::rmTowardZero, &ignored);
Jim Grosbache9119e42015-05-13 18:37:00 +0000105 MCOp = MCOperand::createFPImm(Val.convertToDouble());
Jim Grosbach95dee402011-07-08 17:40:42 +0000106 break;
107 }
Jakob Stoklund Olesenf1fb1d22012-01-18 23:52:19 +0000108 case MachineOperand::MO_RegisterMask:
109 // Ignore call clobbers.
110 return false;
Jim Grosbach95dee402011-07-08 17:40:42 +0000111 }
112 return true;
113}
114
Chris Lattnerde16ca82010-11-14 21:00:02 +0000115void llvm::LowerARMMachineInstrToMCInst(const MachineInstr *MI, MCInst &OutMI,
Jim Grosbachd0d13292010-12-01 03:45:07 +0000116 ARMAsmPrinter &AP) {
Chris Lattner78393d72009-10-19 20:21:05 +0000117 OutMI.setOpcode(MI->getOpcode());
Jim Grosbach7aeff132010-09-13 18:25:42 +0000118
Asiri Rathnayakea0199b92014-12-02 10:53:20 +0000119 // In the MC layer, we keep modified immediates in their encoded form
120 bool EncodeImms = false;
121 switch (MI->getOpcode()) {
122 default: break;
123 case ARM::MOVi:
124 case ARM::MVNi:
125 case ARM::CMPri:
126 case ARM::CMNri:
127 case ARM::TSTri:
128 case ARM::TEQri:
129 case ARM::MSRi:
130 case ARM::ADCri:
131 case ARM::ADDri:
132 case ARM::ADDSri:
133 case ARM::SBCri:
134 case ARM::SUBri:
135 case ARM::SUBSri:
136 case ARM::ANDri:
137 case ARM::ORRri:
138 case ARM::EORri:
139 case ARM::BICri:
140 case ARM::RSBri:
141 case ARM::RSBSri:
142 case ARM::RSCri:
143 EncodeImms = true;
144 break;
145 }
146
Chris Lattner78393d72009-10-19 20:21:05 +0000147 for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
148 const MachineOperand &MO = MI->getOperand(i);
Jim Grosbach7aeff132010-09-13 18:25:42 +0000149
Chris Lattner78393d72009-10-19 20:21:05 +0000150 MCOperand MCOp;
Asiri Rathnayakea0199b92014-12-02 10:53:20 +0000151 if (AP.lowerOperand(MO, MCOp)) {
152 if (MCOp.isImm() && EncodeImms) {
153 int32_t Enc = ARM_AM::getSOImmVal(MCOp.getImm());
154 if (Enc != -1)
155 MCOp.setImm(Enc);
156 }
Jim Grosbach95dee402011-07-08 17:40:42 +0000157 OutMI.addOperand(MCOp);
Asiri Rathnayakea0199b92014-12-02 10:53:20 +0000158 }
Chris Lattner78393d72009-10-19 20:21:05 +0000159 }
Chris Lattner78393d72009-10-19 20:21:05 +0000160}
Dean Michael Berris464015442016-09-19 00:54:35 +0000161
162void ARMAsmPrinter::EmitSled(const MachineInstr &MI, SledKind Kind)
163{
164 if (MI.getParent()->getParent()->getInfo<ARMFunctionInfo>()
165 ->isThumbFunction())
166 {
167 MI.emitError("An attempt to perform XRay instrumentation for a"
168 " Thumb function (not supported). Detected when emitting a sled.");
169 return;
170 }
171 static const int8_t NoopsInSledCount = 6;
172 // We want to emit the following pattern:
173 //
174 // .Lxray_sled_N:
175 // ALIGN
176 // B #20
177 // ; 6 NOP instructions (24 bytes)
178 // .tmpN
179 //
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:
182 //
183 // PUSH{ r0, lr }
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>
188 // BLX ip
189 // POP{ r0, lr }
190 //
191 OutStreamer->EmitCodeAlignment(4);
192 auto CurSled = OutContext.createTempSymbol("xray_sled_", true);
193 OutStreamer->EmitLabel(CurSled);
194 auto Target = OutContext.createTempSymbol();
195
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
198 // is executing it).
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));
203
204 MCInst Noop;
205 Subtarget->getInstrInfo()->getNoopForElfTarget(Noop);
206 for (int8_t I = 0; I < NoopsInSledCount; I++)
207 {
208 OutStreamer->EmitInstruction(Noop, getSubtargetInfo());
209 }
210
211 OutStreamer->EmitLabel(Target);
212 recordSled(CurSled, MI, Kind);
213}
214
215void ARMAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI)
216{
217 EmitSled(MI, SledKind::FUNCTION_ENTER);
218}
219
220void ARMAsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI)
221{
222 EmitSled(MI, SledKind::FUNCTION_EXIT);
223}
224
Dean Michael Berris156f6ca2016-10-18 05:54:15 +0000225void ARMAsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI)
226{
227 EmitSled(MI, SledKind::TAIL_CALL);
228}
229
Dean Michael Berris464015442016-09-19 00:54:35 +0000230void ARMAsmPrinter::EmitXRayTable()
231{
232 if (Sleds.empty())
233 return;
Kuba Mracek06995e82016-11-23 02:07:04 +0000234
235 MCSection *Section = nullptr;
Dean Michael Berris464015442016-09-19 00:54:35 +0000236 if (Subtarget->isTargetELF()) {
Kuba Mracek06995e82016-11-23 02:07:04 +0000237 Section = OutContext.getELFSection("xray_instr_map", ELF::SHT_PROGBITS,
238 ELF::SHF_ALLOC | ELF::SHF_GROUP |
239 ELF::SHF_MERGE,
240 0, CurrentFnSym->getName());
241 } else if (Subtarget->isTargetMachO()) {
242 Section = OutContext.getMachOSection("__DATA", "xray_instr_map", 0,
243 SectionKind::getReadOnlyWithRel());
244 } else {
245 llvm_unreachable("Unsupported target");
Dean Michael Berris464015442016-09-19 00:54:35 +0000246 }
Kuba Mracek06995e82016-11-23 02:07:04 +0000247
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);
259 }
260 OutStreamer->SwitchSection(PrevSection);
261
Dean Michael Berris464015442016-09-19 00:54:35 +0000262 Sleds.clear();
263}