blob: a2084b0c4ab1cebe3acc6edb7df349e7d660d6f4 [file] [log] [blame]
Chris Lattnerfd603822009-10-19 19:56:26 +00001//===-- ARMInstPrinter.cpp - Convert ARM MCInst to assembly syntax --------===//
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 class prints an ARM MCInst to a .s file.
11//
12//===----------------------------------------------------------------------===//
13
14#define DEBUG_TYPE "asm-printer"
Chris Lattner413ae252009-10-20 00:42:49 +000015#include "ARM.h" // FIXME: FACTOR ENUMS BETTER.
Chris Lattnerfd603822009-10-19 19:56:26 +000016#include "ARMInstPrinter.h"
Chris Lattner61d35c22009-10-19 21:21:39 +000017#include "ARMAddressingModes.h"
Chris Lattnerfd603822009-10-19 19:56:26 +000018#include "llvm/MC/MCInst.h"
Chris Lattner61d35c22009-10-19 21:21:39 +000019#include "llvm/MC/MCAsmInfo.h"
Chris Lattner6f997762009-10-19 21:53:00 +000020#include "llvm/MC/MCExpr.h"
21#include "llvm/Support/raw_ostream.h"
Chris Lattnerfd603822009-10-19 19:56:26 +000022using namespace llvm;
23
24// Include the auto-generated portion of the assembly writer.
25#define MachineInstr MCInst
26#define ARMAsmPrinter ARMInstPrinter // FIXME: REMOVE.
Chris Lattnerfd603822009-10-19 19:56:26 +000027#include "ARMGenAsmWriter.inc"
28#undef MachineInstr
29#undef ARMAsmPrinter
30
31void ARMInstPrinter::printInst(const MCInst *MI) { printInstruction(MI); }
32
Chris Lattner8bc86cb2009-10-19 20:59:55 +000033void ARMInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
34 const char *Modifier) {
Chris Lattner8bc86cb2009-10-19 20:59:55 +000035 const MCOperand &Op = MI->getOperand(OpNo);
36 if (Op.isReg()) {
Chris Lattnerbf16faa2009-10-20 06:15:28 +000037 unsigned Reg = Op.getReg();
38 if (Modifier && strcmp(Modifier, "dregpair") == 0) {
39 // FIXME: Breaks e.g. ARM/vmul.ll.
40 assert(0);
41 /*
42 unsigned DRegLo = TRI->getSubReg(Reg, 5); // arm_dsubreg_0
43 unsigned DRegHi = TRI->getSubReg(Reg, 6); // arm_dsubreg_1
44 O << '{'
45 << getRegisterName(DRegLo) << ',' << getRegisterName(DRegHi)
46 << '}';*/
47 } else if (Modifier && strcmp(Modifier, "lane") == 0) {
48 assert(0);
49 /*
50 unsigned RegNum = ARMRegisterInfo::getRegisterNumbering(Reg);
51 unsigned DReg = TRI->getMatchingSuperReg(Reg, RegNum & 1 ? 2 : 1,
52 &ARM::DPR_VFP2RegClass);
53 O << getRegisterName(DReg) << '[' << (RegNum & 1) << ']';
54 */
55 } else {
56 O << getRegisterName(Reg);
57 }
Chris Lattner8bc86cb2009-10-19 20:59:55 +000058 } else if (Op.isImm()) {
Chris Lattnerbf16faa2009-10-20 06:15:28 +000059 assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported");
Chris Lattner8bc86cb2009-10-19 20:59:55 +000060 O << '#' << Op.getImm();
61 } else {
Chris Lattnerbf16faa2009-10-20 06:15:28 +000062 assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported");
Chris Lattner8bc86cb2009-10-19 20:59:55 +000063 assert(Op.isExpr() && "unknown operand kind in printOperand");
Chris Lattner8cb9a3b2010-01-18 00:37:40 +000064 O << *Op.getExpr();
Chris Lattner8bc86cb2009-10-19 20:59:55 +000065 }
66}
Chris Lattner61d35c22009-10-19 21:21:39 +000067
68static void printSOImm(raw_ostream &O, int64_t V, bool VerboseAsm,
69 const MCAsmInfo *MAI) {
70 // Break it up into two parts that make up a shifter immediate.
71 V = ARM_AM::getSOImmVal(V);
72 assert(V != -1 && "Not a valid so_imm value!");
73
74 unsigned Imm = ARM_AM::getSOImmValImm(V);
75 unsigned Rot = ARM_AM::getSOImmValRot(V);
76
77 // Print low-level immediate formation info, per
78 // A5.1.3: "Data-processing operands - Immediate".
79 if (Rot) {
80 O << "#" << Imm << ", " << Rot;
81 // Pretty printed version.
82 if (VerboseAsm)
83 O << ' ' << MAI->getCommentString()
84 << ' ' << (int)ARM_AM::rotr32(Imm, Rot);
85 } else {
86 O << "#" << Imm;
87 }
88}
89
90
91/// printSOImmOperand - SOImm is 4-bit rotate amount in bits 8-11 with 8-bit
92/// immediate in bits 0-7.
93void ARMInstPrinter::printSOImmOperand(const MCInst *MI, unsigned OpNum) {
94 const MCOperand &MO = MI->getOperand(OpNum);
95 assert(MO.isImm() && "Not a valid so_imm value!");
96 printSOImm(O, MO.getImm(), VerboseAsm, &MAI);
97}
Chris Lattner084f87d2009-10-19 21:57:05 +000098
Chris Lattner017d9472009-10-20 00:40:56 +000099/// printSOImm2PartOperand - SOImm is broken into two pieces using a 'mov'
100/// followed by an 'orr' to materialize.
101void ARMInstPrinter::printSOImm2PartOperand(const MCInst *MI, unsigned OpNum) {
102 // FIXME: REMOVE this method.
103 abort();
104}
105
106// so_reg is a 4-operand unit corresponding to register forms of the A5.1
107// "Addressing Mode 1 - Data-processing operands" forms. This includes:
108// REG 0 0 - e.g. R5
109// REG REG 0,SH_OPC - e.g. R5, ROR R3
110// REG 0 IMM,SH_OPC - e.g. R5, LSL #3
111void ARMInstPrinter::printSORegOperand(const MCInst *MI, unsigned OpNum) {
112 const MCOperand &MO1 = MI->getOperand(OpNum);
113 const MCOperand &MO2 = MI->getOperand(OpNum+1);
114 const MCOperand &MO3 = MI->getOperand(OpNum+2);
115
116 O << getRegisterName(MO1.getReg());
117
118 // Print the shift opc.
119 O << ", "
120 << ARM_AM::getShiftOpcStr(ARM_AM::getSORegShOp(MO3.getImm()))
121 << ' ';
122
123 if (MO2.getReg()) {
124 O << getRegisterName(MO2.getReg());
125 assert(ARM_AM::getSORegOffset(MO3.getImm()) == 0);
126 } else {
127 O << "#" << ARM_AM::getSORegOffset(MO3.getImm());
128 }
129}
Chris Lattner084f87d2009-10-19 21:57:05 +0000130
131
132void ARMInstPrinter::printAddrMode2Operand(const MCInst *MI, unsigned Op) {
133 const MCOperand &MO1 = MI->getOperand(Op);
134 const MCOperand &MO2 = MI->getOperand(Op+1);
135 const MCOperand &MO3 = MI->getOperand(Op+2);
136
137 if (!MO1.isReg()) { // FIXME: This is for CP entries, but isn't right.
138 printOperand(MI, Op);
139 return;
140 }
141
142 O << "[" << getRegisterName(MO1.getReg());
143
144 if (!MO2.getReg()) {
145 if (ARM_AM::getAM2Offset(MO3.getImm())) // Don't print +0.
146 O << ", #"
147 << (char)ARM_AM::getAM2Op(MO3.getImm())
148 << ARM_AM::getAM2Offset(MO3.getImm());
149 O << "]";
150 return;
151 }
152
153 O << ", "
154 << (char)ARM_AM::getAM2Op(MO3.getImm())
155 << getRegisterName(MO2.getReg());
156
157 if (unsigned ShImm = ARM_AM::getAM2Offset(MO3.getImm()))
158 O << ", "
159 << ARM_AM::getShiftOpcStr(ARM_AM::getAM2ShiftOpc(MO3.getImm()))
160 << " #" << ShImm;
161 O << "]";
162}
Chris Lattnere306d8d2009-10-19 22:09:23 +0000163
Chris Lattnerbf16faa2009-10-20 06:15:28 +0000164void ARMInstPrinter::printAddrMode2OffsetOperand(const MCInst *MI,
165 unsigned OpNum) {
166 const MCOperand &MO1 = MI->getOperand(OpNum);
167 const MCOperand &MO2 = MI->getOperand(OpNum+1);
168
169 if (!MO1.getReg()) {
170 unsigned ImmOffs = ARM_AM::getAM2Offset(MO2.getImm());
171 assert(ImmOffs && "Malformed indexed load / store!");
172 O << '#' << (char)ARM_AM::getAM2Op(MO2.getImm()) << ImmOffs;
173 return;
174 }
175
176 O << (char)ARM_AM::getAM2Op(MO2.getImm()) << getRegisterName(MO1.getReg());
177
178 if (unsigned ShImm = ARM_AM::getAM2Offset(MO2.getImm()))
179 O << ", "
180 << ARM_AM::getShiftOpcStr(ARM_AM::getAM2ShiftOpc(MO2.getImm()))
181 << " #" << ShImm;
182}
183
184void ARMInstPrinter::printAddrMode3Operand(const MCInst *MI, unsigned OpNum) {
185 const MCOperand &MO1 = MI->getOperand(OpNum);
186 const MCOperand &MO2 = MI->getOperand(OpNum+1);
187 const MCOperand &MO3 = MI->getOperand(OpNum+2);
188
189 O << '[' << getRegisterName(MO1.getReg());
190
191 if (MO2.getReg()) {
192 O << ", " << (char)ARM_AM::getAM3Op(MO3.getImm())
193 << getRegisterName(MO2.getReg()) << ']';
194 return;
195 }
196
197 if (unsigned ImmOffs = ARM_AM::getAM3Offset(MO3.getImm()))
198 O << ", #"
199 << (char)ARM_AM::getAM3Op(MO3.getImm())
200 << ImmOffs;
201 O << ']';
202}
203
204void ARMInstPrinter::printAddrMode3OffsetOperand(const MCInst *MI,
205 unsigned OpNum) {
206 const MCOperand &MO1 = MI->getOperand(OpNum);
207 const MCOperand &MO2 = MI->getOperand(OpNum+1);
208
209 if (MO1.getReg()) {
210 O << (char)ARM_AM::getAM3Op(MO2.getImm())
211 << getRegisterName(MO1.getReg());
212 return;
213 }
214
215 unsigned ImmOffs = ARM_AM::getAM3Offset(MO2.getImm());
216 assert(ImmOffs && "Malformed indexed load / store!");
217 O << "#"
218 << (char)ARM_AM::getAM3Op(MO2.getImm())
219 << ImmOffs;
220}
221
Chris Lattnere306d8d2009-10-19 22:09:23 +0000222
223void ARMInstPrinter::printAddrMode4Operand(const MCInst *MI, unsigned OpNum,
224 const char *Modifier) {
Chris Lattnere306d8d2009-10-19 22:09:23 +0000225 const MCOperand &MO1 = MI->getOperand(OpNum);
226 const MCOperand &MO2 = MI->getOperand(OpNum+1);
227 ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MO2.getImm());
Chris Lattner306d14f2009-10-19 23:31:43 +0000228 if (Modifier && strcmp(Modifier, "submode") == 0) {
Chris Lattnere306d8d2009-10-19 22:09:23 +0000229 if (MO1.getReg() == ARM::SP) {
230 // FIXME
231 bool isLDM = (MI->getOpcode() == ARM::LDM ||
232 MI->getOpcode() == ARM::LDM_RET ||
233 MI->getOpcode() == ARM::t2LDM ||
234 MI->getOpcode() == ARM::t2LDM_RET);
235 O << ARM_AM::getAMSubModeAltStr(Mode, isLDM);
236 } else
237 O << ARM_AM::getAMSubModeStr(Mode);
Chris Lattner306d14f2009-10-19 23:31:43 +0000238 } else if (Modifier && strcmp(Modifier, "wide") == 0) {
Chris Lattnere306d8d2009-10-19 22:09:23 +0000239 ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MO2.getImm());
240 if (Mode == ARM_AM::ia)
241 O << ".w";
242 } else {
243 printOperand(MI, OpNum);
244 if (ARM_AM::getAM4WBFlag(MO2.getImm()))
245 O << "!";
246 }
247}
248
Chris Lattnerbf16faa2009-10-20 06:15:28 +0000249void ARMInstPrinter::printAddrMode5Operand(const MCInst *MI, unsigned OpNum,
250 const char *Modifier) {
251 const MCOperand &MO1 = MI->getOperand(OpNum);
252 const MCOperand &MO2 = MI->getOperand(OpNum+1);
253
254 if (!MO1.isReg()) { // FIXME: This is for CP entries, but isn't right.
255 printOperand(MI, OpNum);
256 return;
257 }
258
259 if (Modifier && strcmp(Modifier, "submode") == 0) {
260 ARM_AM::AMSubMode Mode = ARM_AM::getAM5SubMode(MO2.getImm());
Jim Grosbache5165492009-11-09 00:11:35 +0000261 O << ARM_AM::getAMSubModeStr(Mode);
Chris Lattnerbf16faa2009-10-20 06:15:28 +0000262 return;
263 } else if (Modifier && strcmp(Modifier, "base") == 0) {
264 // Used for FSTM{D|S} and LSTM{D|S} operations.
265 O << getRegisterName(MO1.getReg());
266 if (ARM_AM::getAM5WBFlag(MO2.getImm()))
267 O << "!";
268 return;
269 }
270
271 O << "[" << getRegisterName(MO1.getReg());
272
273 if (unsigned ImmOffs = ARM_AM::getAM5Offset(MO2.getImm())) {
274 O << ", #"
275 << (char)ARM_AM::getAM5Op(MO2.getImm())
276 << ImmOffs*4;
277 }
278 O << "]";
279}
280
Chris Lattner235e2f62009-10-20 06:22:33 +0000281void ARMInstPrinter::printAddrMode6Operand(const MCInst *MI, unsigned OpNum) {
282 const MCOperand &MO1 = MI->getOperand(OpNum);
283 const MCOperand &MO2 = MI->getOperand(OpNum+1);
284 const MCOperand &MO3 = MI->getOperand(OpNum+2);
285
286 // FIXME: No support yet for specifying alignment.
287 O << '[' << getRegisterName(MO1.getReg()) << ']';
288
289 if (ARM_AM::getAM6WBFlag(MO3.getImm())) {
290 if (MO2.getReg() == 0)
291 O << '!';
292 else
293 O << ", " << getRegisterName(MO2.getReg());
294 }
295}
296
297void ARMInstPrinter::printAddrModePCOperand(const MCInst *MI, unsigned OpNum,
298 const char *Modifier) {
299 assert(0 && "FIXME: Implement printAddrModePCOperand");
300}
301
302void ARMInstPrinter::printBitfieldInvMaskImmOperand (const MCInst *MI,
303 unsigned OpNum) {
304 const MCOperand &MO = MI->getOperand(OpNum);
305 uint32_t v = ~MO.getImm();
306 int32_t lsb = CountTrailingZeros_32(v);
307 int32_t width = (32 - CountLeadingZeros_32 (v)) - lsb;
308 assert(MO.isImm() && "Not a valid bf_inv_mask_imm value!");
309 O << '#' << lsb << ", #" << width;
310}
Chris Lattnerbf16faa2009-10-20 06:15:28 +0000311
Chris Lattnere306d8d2009-10-19 22:09:23 +0000312void ARMInstPrinter::printRegisterList(const MCInst *MI, unsigned OpNum) {
313 O << "{";
314 // Always skip the first operand, it's the optional (and implicit writeback).
315 for (unsigned i = OpNum+1, e = MI->getNumOperands(); i != e; ++i) {
Chris Lattnere306d8d2009-10-19 22:09:23 +0000316 if (i != OpNum+1) O << ", ";
Chris Lattnere306d8d2009-10-19 22:09:23 +0000317 O << getRegisterName(MI->getOperand(i).getReg());
318 }
319 O << "}";
320}
Chris Lattner4d152222009-10-19 22:23:04 +0000321
Chris Lattner413ae252009-10-20 00:42:49 +0000322void ARMInstPrinter::printPredicateOperand(const MCInst *MI, unsigned OpNum) {
323 ARMCC::CondCodes CC = (ARMCC::CondCodes)MI->getOperand(OpNum).getImm();
324 if (CC != ARMCC::AL)
325 O << ARMCondCodeToString(CC);
326}
327
Johnny Chen9d3acaa2010-03-02 17:57:15 +0000328void ARMInstPrinter::printMandatoryPredicateOperand(const MCInst *MI,
329 unsigned OpNum) {
330 ARMCC::CondCodes CC = (ARMCC::CondCodes)MI->getOperand(OpNum).getImm();
331 O << ARMCondCodeToString(CC);
332}
333
Chris Lattner233917c2009-10-20 00:46:11 +0000334void ARMInstPrinter::printSBitModifierOperand(const MCInst *MI, unsigned OpNum){
Daniel Dunbara7cc6522009-10-20 22:10:05 +0000335 if (MI->getOperand(OpNum).getReg()) {
336 assert(MI->getOperand(OpNum).getReg() == ARM::CPSR &&
337 "Expect ARM CPSR register!");
Chris Lattner233917c2009-10-20 00:46:11 +0000338 O << 's';
339 }
340}
341
342
Chris Lattner4d152222009-10-19 22:23:04 +0000343
Chris Lattnera70e6442009-10-19 22:33:05 +0000344void ARMInstPrinter::printCPInstOperand(const MCInst *MI, unsigned OpNum,
345 const char *Modifier) {
346 // FIXME: remove this.
347 abort();
348}
Chris Lattner4d152222009-10-19 22:23:04 +0000349
Chris Lattnerbf16faa2009-10-20 06:15:28 +0000350void ARMInstPrinter::printNoHashImmediate(const MCInst *MI, unsigned OpNum) {
351 O << MI->getOperand(OpNum).getImm();
352}
353
354
Chris Lattner4d152222009-10-19 22:23:04 +0000355void ARMInstPrinter::printPCLabel(const MCInst *MI, unsigned OpNum) {
356 // FIXME: remove this.
357 abort();
358}
Evan Cheng2ef9c8a2009-11-19 06:57:41 +0000359
360void ARMInstPrinter::printThumbS4ImmOperand(const MCInst *MI, unsigned OpNum) {
Johnny Chen541ba7d2010-01-25 22:13:10 +0000361 O << "#" << MI->getOperand(OpNum).getImm() * 4;
Evan Cheng2ef9c8a2009-11-19 06:57:41 +0000362}