blob: 19c91510c2595c7fdc5c792773b7758b7a50002e [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"
27#include "llvm/MC/MCInstBuilder.h"
28#include "llvm/MC/MCStreamer.h"
Chris Lattner78393d72009-10-19 20:21:05 +000029using namespace llvm;
30
Chris Lattnerc5afd122010-11-14 20:58:38 +000031
Jim Grosbach95dee402011-07-08 17:40:42 +000032MCOperand ARMAsmPrinter::GetSymbolRef(const MachineOperand &MO,
33 const MCSymbol *Symbol) {
Aaron Ballman86100fc2016-06-20 15:37:15 +000034 const MCExpr *Expr =
35 MCSymbolRefExpr::create(Symbol, MCSymbolRefExpr::VK_None, OutContext);
36 switch (MO.getTargetFlags() & ARMII::MO_OPTION_MASK) {
37 default:
38 llvm_unreachable("Unknown target flag on symbol operand");
39 case ARMII::MO_NO_FLAG:
Chris Lattner3040e8c2010-11-14 20:40:08 +000040 break;
Aaron Ballman86100fc2016-06-20 15:37:15 +000041 case ARMII::MO_LO16:
42 Expr =
43 MCSymbolRefExpr::create(Symbol, MCSymbolRefExpr::VK_None, OutContext);
44 Expr = ARMMCExpr::createLower16(Expr, OutContext);
45 break;
46 case ARMII::MO_HI16:
47 Expr =
48 MCSymbolRefExpr::create(Symbol, MCSymbolRefExpr::VK_None, OutContext);
49 Expr = ARMMCExpr::createUpper16(Expr, OutContext);
50 break;
Chris Lattner3040e8c2010-11-14 20:40:08 +000051 }
Jim Grosbach38d90de2010-11-30 23:29:24 +000052
Jim Grosbach0d35df12010-09-17 18:25:25 +000053 if (!MO.isJTI() && MO.getOffset())
Jim Grosbach13760bd2015-05-30 01:25:56 +000054 Expr = MCBinaryExpr::createAdd(Expr,
55 MCConstantExpr::create(MO.getOffset(),
Jim Grosbach95dee402011-07-08 17:40:42 +000056 OutContext),
57 OutContext);
Jim Grosbache9119e42015-05-13 18:37:00 +000058 return MCOperand::createExpr(Expr);
Jim Grosbach38d90de2010-11-30 23:29:24 +000059
Jim Grosbach0d35df12010-09-17 18:25:25 +000060}
61
Jim Grosbach95dee402011-07-08 17:40:42 +000062bool ARMAsmPrinter::lowerOperand(const MachineOperand &MO,
63 MCOperand &MCOp) {
64 switch (MO.getType()) {
Craig Toppere55c5562012-02-07 02:50:20 +000065 default: llvm_unreachable("unknown operand type");
Jim Grosbach95dee402011-07-08 17:40:42 +000066 case MachineOperand::MO_Register:
67 // Ignore all non-CPSR implicit register operands.
68 if (MO.isImplicit() && MO.getReg() != ARM::CPSR)
69 return false;
70 assert(!MO.getSubReg() && "Subregs should be eliminated!");
Jim Grosbache9119e42015-05-13 18:37:00 +000071 MCOp = MCOperand::createReg(MO.getReg());
Jim Grosbach95dee402011-07-08 17:40:42 +000072 break;
73 case MachineOperand::MO_Immediate:
Jim Grosbache9119e42015-05-13 18:37:00 +000074 MCOp = MCOperand::createImm(MO.getImm());
Jim Grosbach95dee402011-07-08 17:40:42 +000075 break;
76 case MachineOperand::MO_MachineBasicBlock:
Jim Grosbach13760bd2015-05-30 01:25:56 +000077 MCOp = MCOperand::createExpr(MCSymbolRefExpr::create(
Jim Grosbach95dee402011-07-08 17:40:42 +000078 MO.getMBB()->getSymbol(), OutContext));
79 break;
Tim Northoverdb962e2c2013-11-25 16:24:52 +000080 case MachineOperand::MO_GlobalAddress: {
81 MCOp = GetSymbolRef(MO,
82 GetARMGVSymbol(MO.getGlobal(), MO.getTargetFlags()));
Jim Grosbach95dee402011-07-08 17:40:42 +000083 break;
Tim Northoverdb962e2c2013-11-25 16:24:52 +000084 }
Jim Grosbach95dee402011-07-08 17:40:42 +000085 case MachineOperand::MO_ExternalSymbol:
Etienne Bergeron715ec092016-06-21 15:21:04 +000086 MCOp = GetSymbolRef(MO,
Jim Grosbach95dee402011-07-08 17:40:42 +000087 GetExternalSymbolSymbol(MO.getSymbolName()));
88 break;
89 case MachineOperand::MO_JumpTableIndex:
90 MCOp = GetSymbolRef(MO, GetJTISymbol(MO.getIndex()));
91 break;
92 case MachineOperand::MO_ConstantPoolIndex:
93 MCOp = GetSymbolRef(MO, GetCPISymbol(MO.getIndex()));
94 break;
95 case MachineOperand::MO_BlockAddress:
96 MCOp = GetSymbolRef(MO, GetBlockAddressSymbol(MO.getBlockAddress()));
97 break;
98 case MachineOperand::MO_FPImmediate: {
99 APFloat Val = MO.getFPImm()->getValueAPF();
100 bool ignored;
101 Val.convert(APFloat::IEEEdouble, APFloat::rmTowardZero, &ignored);
Jim Grosbache9119e42015-05-13 18:37:00 +0000102 MCOp = MCOperand::createFPImm(Val.convertToDouble());
Jim Grosbach95dee402011-07-08 17:40:42 +0000103 break;
104 }
Jakob Stoklund Olesenf1fb1d22012-01-18 23:52:19 +0000105 case MachineOperand::MO_RegisterMask:
106 // Ignore call clobbers.
107 return false;
Jim Grosbach95dee402011-07-08 17:40:42 +0000108 }
109 return true;
110}
111
Chris Lattnerde16ca82010-11-14 21:00:02 +0000112void llvm::LowerARMMachineInstrToMCInst(const MachineInstr *MI, MCInst &OutMI,
Jim Grosbachd0d13292010-12-01 03:45:07 +0000113 ARMAsmPrinter &AP) {
Chris Lattner78393d72009-10-19 20:21:05 +0000114 OutMI.setOpcode(MI->getOpcode());
Jim Grosbach7aeff132010-09-13 18:25:42 +0000115
Asiri Rathnayakea0199b92014-12-02 10:53:20 +0000116 // In the MC layer, we keep modified immediates in their encoded form
117 bool EncodeImms = false;
118 switch (MI->getOpcode()) {
119 default: break;
120 case ARM::MOVi:
121 case ARM::MVNi:
122 case ARM::CMPri:
123 case ARM::CMNri:
124 case ARM::TSTri:
125 case ARM::TEQri:
126 case ARM::MSRi:
127 case ARM::ADCri:
128 case ARM::ADDri:
129 case ARM::ADDSri:
130 case ARM::SBCri:
131 case ARM::SUBri:
132 case ARM::SUBSri:
133 case ARM::ANDri:
134 case ARM::ORRri:
135 case ARM::EORri:
136 case ARM::BICri:
137 case ARM::RSBri:
138 case ARM::RSBSri:
139 case ARM::RSCri:
140 EncodeImms = true;
141 break;
142 }
143
Chris Lattner78393d72009-10-19 20:21:05 +0000144 for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
145 const MachineOperand &MO = MI->getOperand(i);
Jim Grosbach7aeff132010-09-13 18:25:42 +0000146
Chris Lattner78393d72009-10-19 20:21:05 +0000147 MCOperand MCOp;
Asiri Rathnayakea0199b92014-12-02 10:53:20 +0000148 if (AP.lowerOperand(MO, MCOp)) {
149 if (MCOp.isImm() && EncodeImms) {
150 int32_t Enc = ARM_AM::getSOImmVal(MCOp.getImm());
151 if (Enc != -1)
152 MCOp.setImm(Enc);
153 }
Jim Grosbach95dee402011-07-08 17:40:42 +0000154 OutMI.addOperand(MCOp);
Asiri Rathnayakea0199b92014-12-02 10:53:20 +0000155 }
Chris Lattner78393d72009-10-19 20:21:05 +0000156 }
Chris Lattner78393d72009-10-19 20:21:05 +0000157}
Dean Michael Berris464015442016-09-19 00:54:35 +0000158
159void ARMAsmPrinter::EmitSled(const MachineInstr &MI, SledKind Kind)
160{
161 if (MI.getParent()->getParent()->getInfo<ARMFunctionInfo>()
162 ->isThumbFunction())
163 {
164 MI.emitError("An attempt to perform XRay instrumentation for a"
165 " Thumb function (not supported). Detected when emitting a sled.");
166 return;
167 }
168 static const int8_t NoopsInSledCount = 6;
169 // We want to emit the following pattern:
170 //
171 // .Lxray_sled_N:
172 // ALIGN
173 // B #20
174 // ; 6 NOP instructions (24 bytes)
175 // .tmpN
176 //
177 // We need the 24 bytes (6 instructions) because at runtime, we'd be patching
178 // over the full 28 bytes (7 instructions) with the following pattern:
179 //
180 // PUSH{ r0, lr }
181 // MOVW r0, #<lower 16 bits of function ID>
182 // MOVT r0, #<higher 16 bits of function ID>
183 // MOVW ip, #<lower 16 bits of address of __xray_FunctionEntry/Exit>
184 // MOVT ip, #<higher 16 bits of address of __xray_FunctionEntry/Exit>
185 // BLX ip
186 // POP{ r0, lr }
187 //
188 OutStreamer->EmitCodeAlignment(4);
189 auto CurSled = OutContext.createTempSymbol("xray_sled_", true);
190 OutStreamer->EmitLabel(CurSled);
191 auto Target = OutContext.createTempSymbol();
192
193 // Emit "B #20" instruction, which jumps over the next 24 bytes (because
194 // register pc is 8 bytes ahead of the jump instruction by the moment CPU
195 // is executing it).
196 // By analogy to ARMAsmPrinter::emitPseudoExpansionLowering() |case ARM::B|.
197 // It is not clear why |addReg(0)| is needed (the last operand).
198 EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::Bcc).addImm(20)
199 .addImm(ARMCC::AL).addReg(0));
200
201 MCInst Noop;
202 Subtarget->getInstrInfo()->getNoopForElfTarget(Noop);
203 for (int8_t I = 0; I < NoopsInSledCount; I++)
204 {
205 OutStreamer->EmitInstruction(Noop, getSubtargetInfo());
206 }
207
208 OutStreamer->EmitLabel(Target);
209 recordSled(CurSled, MI, Kind);
210}
211
212void ARMAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI)
213{
214 EmitSled(MI, SledKind::FUNCTION_ENTER);
215}
216
217void ARMAsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI)
218{
219 EmitSled(MI, SledKind::FUNCTION_EXIT);
220}
221
222void ARMAsmPrinter::EmitXRayTable()
223{
224 if (Sleds.empty())
225 return;
226 if (Subtarget->isTargetELF()) {
227 auto *Section = OutContext.getELFSection(
228 "xray_instr_map", ELF::SHT_PROGBITS,
229 ELF::SHF_ALLOC | ELF::SHF_GROUP | ELF::SHF_MERGE, 0,
230 CurrentFnSym->getName());
231 auto PrevSection = OutStreamer->getCurrentSectionOnly();
232 OutStreamer->SwitchSection(Section);
233 for (const auto &Sled : Sleds) {
234 OutStreamer->EmitSymbolValue(Sled.Sled, 4);
235 OutStreamer->EmitSymbolValue(CurrentFnSym, 4);
236 auto Kind = static_cast<uint8_t>(Sled.Kind);
237 OutStreamer->EmitBytes(
238 StringRef(reinterpret_cast<const char *>(&Kind), 1));
239 OutStreamer->EmitBytes(
240 StringRef(reinterpret_cast<const char *>(&Sled.AlwaysInstrument), 1));
241 OutStreamer->EmitZeros(6);
242 }
243 OutStreamer->SwitchSection(PrevSection);
244 }
245 Sleds.clear();
246}