]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/llvm/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.cpp
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / llvm / lib / Target / AArch64 / InstPrinter / AArch64InstPrinter.cpp
1 //==-- AArch64InstPrinter.cpp - Convert AArch64 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 AArch64 MCInst to a .s file.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #define DEBUG_TYPE "asm-printer"
15 #include "AArch64InstPrinter.h"
16 #include "MCTargetDesc/AArch64MCTargetDesc.h"
17 #include "Utils/AArch64BaseInfo.h"
18 #include "llvm/MC/MCInst.h"
19 #include "llvm/MC/MCExpr.h"
20 #include "llvm/MC/MCRegisterInfo.h"
21 #include "llvm/Support/ErrorHandling.h"
22 #include "llvm/Support/Format.h"
23 #include "llvm/Support/raw_ostream.h"
24
25 using namespace llvm;
26
27 #define GET_INSTRUCTION_NAME
28 #define PRINT_ALIAS_INSTR
29 #include "AArch64GenAsmWriter.inc"
30
31 static int64_t unpackSignedImm(int BitWidth, uint64_t Value) {
32   assert(!(Value & ~((1ULL << BitWidth)-1)) && "immediate not n-bit");
33   if (Value & (1ULL <<  (BitWidth - 1)))
34     return static_cast<int64_t>(Value) - (1LL << BitWidth);
35   else
36     return Value;
37 }
38
39 AArch64InstPrinter::AArch64InstPrinter(const MCAsmInfo &MAI,
40                                        const MCInstrInfo &MII,
41                                        const MCRegisterInfo &MRI,
42                                        const MCSubtargetInfo &STI) :
43   MCInstPrinter(MAI, MII, MRI) {
44   // Initialize the set of available features.
45   setAvailableFeatures(STI.getFeatureBits());
46 }
47
48 void AArch64InstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const {
49   OS << getRegisterName(RegNo);
50 }
51
52 void
53 AArch64InstPrinter::printOffsetSImm9Operand(const MCInst *MI,
54                                               unsigned OpNum, raw_ostream &O) {
55   const MCOperand &MOImm = MI->getOperand(OpNum);
56   int32_t Imm = unpackSignedImm(9, MOImm.getImm());
57
58   O << '#' << Imm;
59 }
60
61 void
62 AArch64InstPrinter::printAddrRegExtendOperand(const MCInst *MI, unsigned OpNum,
63                                           raw_ostream &O, unsigned MemSize,
64                                           unsigned RmSize) {
65   unsigned ExtImm = MI->getOperand(OpNum).getImm();
66   unsigned OptionHi = ExtImm >> 1;
67   unsigned S = ExtImm & 1;
68   bool IsLSL = OptionHi == 1 && RmSize == 64;
69
70   const char *Ext;
71   switch (OptionHi) {
72   case 1:
73     Ext = (RmSize == 32) ? "uxtw" : "lsl";
74     break;
75   case 3:
76     Ext = (RmSize == 32) ? "sxtw" : "sxtx";
77     break;
78   default:
79     llvm_unreachable("Incorrect Option on load/store (reg offset)");
80   }
81   O << Ext;
82
83   if (S) {
84     unsigned ShiftAmt = Log2_32(MemSize);
85     O << " #" << ShiftAmt;
86   } else if (IsLSL) {
87     O << " #0";
88   }
89 }
90
91 void
92 AArch64InstPrinter::printAddSubImmLSL0Operand(const MCInst *MI,
93                                               unsigned OpNum, raw_ostream &O) {
94   const MCOperand &Imm12Op = MI->getOperand(OpNum);
95
96   if (Imm12Op.isImm()) {
97     int64_t Imm12 = Imm12Op.getImm();
98     assert(Imm12 >= 0 && "Invalid immediate for add/sub imm");
99     O << "#" << Imm12;
100   } else {
101     assert(Imm12Op.isExpr() && "Unexpected shift operand type");
102     O << "#" << *Imm12Op.getExpr();
103   }
104 }
105
106 void
107 AArch64InstPrinter::printAddSubImmLSL12Operand(const MCInst *MI, unsigned OpNum,
108                                                raw_ostream &O) {
109
110   printAddSubImmLSL0Operand(MI, OpNum, O);
111
112   O << ", lsl #12";
113 }
114
115 void
116 AArch64InstPrinter::printBareImmOperand(const MCInst *MI, unsigned OpNum,
117                                         raw_ostream &O) {
118   const MCOperand &MO = MI->getOperand(OpNum);
119   O << MO.getImm();
120 }
121
122 template<unsigned RegWidth> void
123 AArch64InstPrinter::printBFILSBOperand(const MCInst *MI, unsigned OpNum,
124                                        raw_ostream &O) {
125   const MCOperand &ImmROp = MI->getOperand(OpNum);
126   unsigned LSB = ImmROp.getImm() == 0 ? 0 : RegWidth - ImmROp.getImm();
127
128   O << '#' << LSB;
129 }
130
131 void AArch64InstPrinter::printBFIWidthOperand(const MCInst *MI, unsigned OpNum,
132                                               raw_ostream &O) {
133   const MCOperand &ImmSOp = MI->getOperand(OpNum);
134   unsigned Width = ImmSOp.getImm() + 1;
135
136   O << '#' << Width;
137 }
138
139 void
140 AArch64InstPrinter::printBFXWidthOperand(const MCInst *MI, unsigned OpNum,
141                                          raw_ostream &O) {
142   const MCOperand &ImmSOp = MI->getOperand(OpNum);
143   const MCOperand &ImmROp = MI->getOperand(OpNum - 1);
144
145   unsigned ImmR = ImmROp.getImm();
146   unsigned ImmS = ImmSOp.getImm();
147
148   assert(ImmS >= ImmR && "Invalid ImmR, ImmS combination for bitfield extract");
149
150   O << '#' << (ImmS - ImmR + 1);
151 }
152
153 void
154 AArch64InstPrinter::printCRxOperand(const MCInst *MI, unsigned OpNum,
155                                     raw_ostream &O) {
156     const MCOperand &CRx = MI->getOperand(OpNum);
157
158     O << 'c' << CRx.getImm();
159 }
160
161
162 void
163 AArch64InstPrinter::printCVTFixedPosOperand(const MCInst *MI, unsigned OpNum,
164                                             raw_ostream &O) {
165     const MCOperand &ScaleOp = MI->getOperand(OpNum);
166
167     O << '#' << (64 - ScaleOp.getImm());
168 }
169
170
171 void AArch64InstPrinter::printFPImmOperand(const MCInst *MI, unsigned OpNum,
172                                            raw_ostream &o) {
173   const MCOperand &MOImm8 = MI->getOperand(OpNum);
174
175   assert(MOImm8.isImm()
176          && "Immediate operand required for floating-point immediate inst");
177
178   uint32_t Imm8 = MOImm8.getImm();
179   uint32_t Fraction = Imm8 & 0xf;
180   uint32_t Exponent = (Imm8 >> 4) & 0x7;
181   uint32_t Negative = (Imm8 >> 7) & 0x1;
182
183   float Val = 1.0f + Fraction / 16.0f;
184
185   // That is:
186   // 000 -> 2^1,  001 -> 2^2,  010 -> 2^3,  011 -> 2^4,
187   // 100 -> 2^-3, 101 -> 2^-2, 110 -> 2^-1, 111 -> 2^0
188   if (Exponent & 0x4) {
189     Val /= 1 << (7 - Exponent);
190   } else {
191     Val *= 1 << (Exponent + 1);
192   }
193
194   Val = Negative ? -Val : Val;
195
196   o << '#' << format("%.8f", Val);
197 }
198
199 void AArch64InstPrinter::printFPZeroOperand(const MCInst *MI, unsigned OpNum,
200                                             raw_ostream &o) {
201   o << "#0.0";
202 }
203
204 void
205 AArch64InstPrinter::printCondCodeOperand(const MCInst *MI, unsigned OpNum,
206                                          raw_ostream &O) {
207   const MCOperand &MO = MI->getOperand(OpNum);
208
209   O << A64CondCodeToString(static_cast<A64CC::CondCodes>(MO.getImm()));
210 }
211
212 template <unsigned field_width, unsigned scale> void
213 AArch64InstPrinter::printLabelOperand(const MCInst *MI, unsigned OpNum,
214                                             raw_ostream &O) {
215   const MCOperand &MO = MI->getOperand(OpNum);
216
217   if (!MO.isImm()) {
218     printOperand(MI, OpNum, O);
219     return;
220   }
221
222   // The immediate of LDR (lit) instructions is a signed 19-bit immediate, which
223   // is multiplied by 4 (because all A64 instructions are 32-bits wide).
224   uint64_t UImm = MO.getImm();
225   uint64_t Sign = UImm & (1LL << (field_width - 1));
226   int64_t SImm = scale * ((UImm & ~Sign) - Sign);
227
228   O << "#" << SImm;
229 }
230
231 template<unsigned RegWidth> void
232 AArch64InstPrinter::printLogicalImmOperand(const MCInst *MI, unsigned OpNum,
233                                            raw_ostream &O) {
234   const MCOperand &MO = MI->getOperand(OpNum);
235   uint64_t Val;
236   A64Imms::isLogicalImmBits(RegWidth, MO.getImm(), Val);
237   O << "#0x";
238   O.write_hex(Val);
239 }
240
241 void
242 AArch64InstPrinter::printOffsetUImm12Operand(const MCInst *MI, unsigned OpNum,
243                                                raw_ostream &O, int MemSize) {
244   const MCOperand &MOImm = MI->getOperand(OpNum);
245
246   if (MOImm.isImm()) {
247     uint32_t Imm = MOImm.getImm() * MemSize;
248
249     O << "#" << Imm;
250   } else {
251     O << "#" << *MOImm.getExpr();
252   }
253 }
254
255 void
256 AArch64InstPrinter::printShiftOperand(const MCInst *MI,  unsigned OpNum,
257                                       raw_ostream &O,
258                                       A64SE::ShiftExtSpecifiers Shift) {
259     const MCOperand &MO = MI->getOperand(OpNum);
260
261     // LSL #0 is not printed
262     if (Shift == A64SE::LSL && MO.isImm() && MO.getImm() == 0)
263         return;
264
265     switch (Shift) {
266     case A64SE::LSL: O << "lsl"; break;
267     case A64SE::LSR: O << "lsr"; break;
268     case A64SE::ASR: O << "asr"; break;
269     case A64SE::ROR: O << "ror"; break;
270     default: llvm_unreachable("Invalid shift specifier in logical instruction");
271     }
272
273   O << " #" << MO.getImm();
274 }
275
276 void
277 AArch64InstPrinter::printMoveWideImmOperand(const MCInst *MI,  unsigned OpNum,
278                                             raw_ostream &O) {
279   const MCOperand &UImm16MO = MI->getOperand(OpNum);
280   const MCOperand &ShiftMO = MI->getOperand(OpNum + 1);
281
282   if (UImm16MO.isImm()) {
283     O << '#' << UImm16MO.getImm();
284
285     if (ShiftMO.getImm() != 0)
286       O << ", lsl #" << (ShiftMO.getImm() * 16);
287
288     return;
289   }
290
291   O << "#" << *UImm16MO.getExpr();
292 }
293
294 void AArch64InstPrinter::printNamedImmOperand(const NamedImmMapper &Mapper,
295                                               const MCInst *MI, unsigned OpNum,
296                                               raw_ostream &O) {
297   bool ValidName;
298   const MCOperand &MO = MI->getOperand(OpNum);
299   StringRef Name = Mapper.toString(MO.getImm(), ValidName);
300
301   if (ValidName)
302     O << Name;
303   else
304     O << '#' << MO.getImm();
305 }
306
307 void
308 AArch64InstPrinter::printSysRegOperand(const A64SysReg::SysRegMapper &Mapper,
309                                        const MCInst *MI, unsigned OpNum,
310                                        raw_ostream &O) {
311   const MCOperand &MO = MI->getOperand(OpNum);
312
313   bool ValidName;
314   std::string Name = Mapper.toString(MO.getImm(), ValidName);
315   if (ValidName) {
316     O << Name;
317     return;
318   }
319 }
320
321
322 void AArch64InstPrinter::printRegExtendOperand(const MCInst *MI,
323                                                unsigned OpNum,
324                                                raw_ostream &O,
325                                                A64SE::ShiftExtSpecifiers Ext) {
326   // FIXME: In principle TableGen should be able to detect this itself far more
327   // easily. We will only accumulate more of these hacks.
328   unsigned Reg0 = MI->getOperand(0).getReg();
329   unsigned Reg1 = MI->getOperand(1).getReg();
330
331   if (isStackReg(Reg0) || isStackReg(Reg1)) {
332     A64SE::ShiftExtSpecifiers LSLEquiv;
333
334     if (Reg0 == AArch64::XSP || Reg1 == AArch64::XSP)
335       LSLEquiv = A64SE::UXTX;
336     else
337       LSLEquiv = A64SE::UXTW;
338
339     if (Ext == LSLEquiv) {
340       O << "lsl #" << MI->getOperand(OpNum).getImm();
341       return;
342     }
343   }
344
345   switch (Ext) {
346   case A64SE::UXTB: O << "uxtb"; break;
347   case A64SE::UXTH: O << "uxth"; break;
348   case A64SE::UXTW: O << "uxtw"; break;
349   case A64SE::UXTX: O << "uxtx"; break;
350   case A64SE::SXTB: O << "sxtb"; break;
351   case A64SE::SXTH: O << "sxth"; break;
352   case A64SE::SXTW: O << "sxtw"; break;
353   case A64SE::SXTX: O << "sxtx"; break;
354   default: llvm_unreachable("Unexpected shift type for printing");
355   }
356
357   const MCOperand &MO = MI->getOperand(OpNum);
358   if (MO.getImm() != 0)
359     O << " #" << MO.getImm();
360 }
361
362 template<int MemScale> void
363 AArch64InstPrinter::printSImm7ScaledOperand(const MCInst *MI, unsigned OpNum,
364                                       raw_ostream &O) {
365   const MCOperand &MOImm = MI->getOperand(OpNum);
366   int32_t Imm = unpackSignedImm(7, MOImm.getImm());
367
368   O << "#" << (Imm * MemScale);
369 }
370
371 void AArch64InstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
372                                       raw_ostream &O) {
373   const MCOperand &Op = MI->getOperand(OpNo);
374   if (Op.isReg()) {
375     unsigned Reg = Op.getReg();
376     O << getRegisterName(Reg);
377   } else if (Op.isImm()) {
378     O << '#' << Op.getImm();
379   } else {
380     assert(Op.isExpr() && "unknown operand kind in printOperand");
381     // If a symbolic branch target was added as a constant expression then print
382     // that address in hex.
383     const MCConstantExpr *BranchTarget = dyn_cast<MCConstantExpr>(Op.getExpr());
384     int64_t Address;
385     if (BranchTarget && BranchTarget->EvaluateAsAbsolute(Address)) {
386       O << "0x";
387       O.write_hex(Address);
388     }
389     else {
390       // Otherwise, just print the expression.
391       O << *Op.getExpr();
392     }
393   }
394 }
395
396
397 void AArch64InstPrinter::printInst(const MCInst *MI, raw_ostream &O,
398                                    StringRef Annot) {
399   if (MI->getOpcode() == AArch64::TLSDESCCALL) {
400     // This is a special assembler directive which applies an
401     // R_AARCH64_TLSDESC_CALL to the following (BLR) instruction. It has a fixed
402     // form outside the normal TableGenerated scheme.
403     O << "\t.tlsdesccall " << *MI->getOperand(0).getExpr();
404   } else if (!printAliasInstr(MI, O))
405     printInstruction(MI, O);
406
407   printAnnotation(O, Annot);
408 }