1//===-- AMDGPUInstPrinter.cpp - AMDGPU MC Inst -> ASM ---------------------===//
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// \file
9//===----------------------------------------------------------------------===//
10
11#include "AMDGPUInstPrinter.h"
12#include "MCTargetDesc/AMDGPUMCTargetDesc.h"
13#include "llvm/MC/MCExpr.h"
14#include "llvm/MC/MCInst.h"
15#include "llvm/MC/MCRegisterInfo.h"
16#include "llvm/Support/MathExtras.h"
17
18using namespace llvm;
19
20void AMDGPUInstPrinter::printInst(const MCInst *MI, raw_ostream &OS,
21                             StringRef Annot) {
22  OS.flush();
23  printInstruction(MI, OS);
24
25  printAnnotation(OS, Annot);
26}
27
28void AMDGPUInstPrinter::printU8ImmOperand(const MCInst *MI, unsigned OpNo,
29                                           raw_ostream &O) {
30  O << formatHex(MI->getOperand(OpNo).getImm() & 0xff);
31}
32
33void AMDGPUInstPrinter::printU16ImmOperand(const MCInst *MI, unsigned OpNo,
34                                           raw_ostream &O) {
35  O << formatHex(MI->getOperand(OpNo).getImm() & 0xffff);
36}
37
38void AMDGPUInstPrinter::printU32ImmOperand(const MCInst *MI, unsigned OpNo,
39                                           raw_ostream &O) {
40  O << formatHex(MI->getOperand(OpNo).getImm() & 0xffffffff);
41}
42
43void AMDGPUInstPrinter::printRegOperand(unsigned reg, raw_ostream &O) {
44  switch (reg) {
45  case AMDGPU::VCC:
46    O << "vcc";
47    return;
48  case AMDGPU::SCC:
49    O << "scc";
50    return;
51  case AMDGPU::EXEC:
52    O << "exec";
53    return;
54  case AMDGPU::M0:
55    O << "m0";
56    return;
57  default:
58    break;
59  }
60
61  char Type;
62  unsigned NumRegs;
63
64  if (MRI.getRegClass(AMDGPU::VGPR_32RegClassID).contains(reg)) {
65    Type = 'v';
66    NumRegs = 1;
67  } else  if (MRI.getRegClass(AMDGPU::SGPR_32RegClassID).contains(reg)) {
68    Type = 's';
69    NumRegs = 1;
70  } else if (MRI.getRegClass(AMDGPU::VReg_64RegClassID).contains(reg)) {
71    Type = 'v';
72    NumRegs = 2;
73  } else  if (MRI.getRegClass(AMDGPU::SReg_64RegClassID).contains(reg)) {
74    Type = 's';
75    NumRegs = 2;
76  } else if (MRI.getRegClass(AMDGPU::VReg_128RegClassID).contains(reg)) {
77    Type = 'v';
78    NumRegs = 4;
79  } else  if (MRI.getRegClass(AMDGPU::SReg_128RegClassID).contains(reg)) {
80    Type = 's';
81    NumRegs = 4;
82  } else if (MRI.getRegClass(AMDGPU::VReg_96RegClassID).contains(reg)) {
83    Type = 'v';
84    NumRegs = 3;
85  } else if (MRI.getRegClass(AMDGPU::VReg_256RegClassID).contains(reg)) {
86    Type = 'v';
87    NumRegs = 8;
88  } else if (MRI.getRegClass(AMDGPU::SReg_256RegClassID).contains(reg)) {
89    Type = 's';
90    NumRegs = 8;
91  } else if (MRI.getRegClass(AMDGPU::VReg_512RegClassID).contains(reg)) {
92    Type = 'v';
93    NumRegs = 16;
94  } else if (MRI.getRegClass(AMDGPU::SReg_512RegClassID).contains(reg)) {
95    Type = 's';
96    NumRegs = 16;
97  } else {
98    O << getRegisterName(reg);
99    return;
100  }
101
102  // The low 8 bits of the encoding value is the register index, for both VGPRs
103  // and SGPRs.
104  unsigned RegIdx = MRI.getEncodingValue(reg) & ((1 << 8) - 1);
105  if (NumRegs == 1) {
106    O << Type << RegIdx;
107    return;
108  }
109
110  O << Type << '[' << RegIdx << ':' << (RegIdx + NumRegs - 1) << ']';
111}
112
113void AMDGPUInstPrinter::printImmediate(uint32_t Imm, raw_ostream &O) {
114  int32_t SImm = static_cast<int32_t>(Imm);
115  if (SImm >= -16 && SImm <= 64) {
116    O << SImm;
117    return;
118  }
119
120  if (Imm == FloatToBits(1.0f) ||
121      Imm == FloatToBits(-1.0f) ||
122      Imm == FloatToBits(0.5f) ||
123      Imm == FloatToBits(-0.5f) ||
124      Imm == FloatToBits(2.0f) ||
125      Imm == FloatToBits(-2.0f) ||
126      Imm == FloatToBits(4.0f) ||
127      Imm == FloatToBits(-4.0f)) {
128    O << BitsToFloat(Imm);
129    return;
130  }
131
132  O << formatHex(static_cast<uint64_t>(Imm));
133}
134
135void AMDGPUInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
136                                     raw_ostream &O) {
137
138  const MCOperand &Op = MI->getOperand(OpNo);
139  if (Op.isReg()) {
140    switch (Op.getReg()) {
141    // This is the default predicate state, so we don't need to print it.
142    case AMDGPU::PRED_SEL_OFF:
143      break;
144
145    default:
146      printRegOperand(Op.getReg(), O);
147      break;
148    }
149  } else if (Op.isImm()) {
150    printImmediate(Op.getImm(), O);
151  } else if (Op.isFPImm()) {
152    O << Op.getFPImm();
153  } else if (Op.isExpr()) {
154    const MCExpr *Exp = Op.getExpr();
155    Exp->print(O);
156  } else {
157    assert(!"unknown operand type in printOperand");
158  }
159}
160
161void AMDGPUInstPrinter::printOperandAndMods(const MCInst *MI, unsigned OpNo,
162                                            raw_ostream &O) {
163  unsigned InputModifiers = MI->getOperand(OpNo).getImm();
164  if (InputModifiers & 0x1)
165    O << "-";
166  if (InputModifiers & 0x2)
167    O << "|";
168  printOperand(MI, OpNo + 1, O);
169  if (InputModifiers & 0x2)
170    O << "|";
171}
172
173void AMDGPUInstPrinter::printInterpSlot(const MCInst *MI, unsigned OpNum,
174                                        raw_ostream &O) {
175  unsigned Imm = MI->getOperand(OpNum).getImm();
176
177  if (Imm == 2) {
178    O << "P0";
179  } else if (Imm == 1) {
180    O << "P20";
181  } else if (Imm == 0) {
182    O << "P10";
183  } else {
184    assert(!"Invalid interpolation parameter slot");
185  }
186}
187
188void AMDGPUInstPrinter::printMemOperand(const MCInst *MI, unsigned OpNo,
189                                        raw_ostream &O) {
190  printOperand(MI, OpNo, O);
191  O  << ", ";
192  printOperand(MI, OpNo + 1, O);
193}
194
195void AMDGPUInstPrinter::printIfSet(const MCInst *MI, unsigned OpNo,
196                                   raw_ostream &O, StringRef Asm,
197                                   StringRef Default) {
198  const MCOperand &Op = MI->getOperand(OpNo);
199  assert(Op.isImm());
200  if (Op.getImm() == 1) {
201    O << Asm;
202  } else {
203    O << Default;
204  }
205}
206
207void AMDGPUInstPrinter::printAbs(const MCInst *MI, unsigned OpNo,
208                                 raw_ostream &O) {
209  printIfSet(MI, OpNo, O, "|");
210}
211
212void AMDGPUInstPrinter::printClamp(const MCInst *MI, unsigned OpNo,
213                                   raw_ostream &O) {
214  printIfSet(MI, OpNo, O, "_SAT");
215}
216
217void AMDGPUInstPrinter::printLiteral(const MCInst *MI, unsigned OpNo,
218                                     raw_ostream &O) {
219  int32_t Imm = MI->getOperand(OpNo).getImm();
220  O << Imm << '(' << BitsToFloat(Imm) << ')';
221}
222
223void AMDGPUInstPrinter::printLast(const MCInst *MI, unsigned OpNo,
224                                  raw_ostream &O) {
225  printIfSet(MI, OpNo, O.indent(25 - O.GetNumBytesInBuffer()), "*", " ");
226}
227
228void AMDGPUInstPrinter::printNeg(const MCInst *MI, unsigned OpNo,
229                                 raw_ostream &O) {
230  printIfSet(MI, OpNo, O, "-");
231}
232
233void AMDGPUInstPrinter::printOMOD(const MCInst *MI, unsigned OpNo,
234                                  raw_ostream &O) {
235  switch (MI->getOperand(OpNo).getImm()) {
236  default: break;
237  case 1:
238    O << " * 2.0";
239    break;
240  case 2:
241    O << " * 4.0";
242    break;
243  case 3:
244    O << " / 2.0";
245    break;
246  }
247}
248
249void AMDGPUInstPrinter::printRel(const MCInst *MI, unsigned OpNo,
250                                 raw_ostream &O) {
251  printIfSet(MI, OpNo, O, "+");
252}
253
254void AMDGPUInstPrinter::printUpdateExecMask(const MCInst *MI, unsigned OpNo,
255                                            raw_ostream &O) {
256  printIfSet(MI, OpNo, O, "ExecMask,");
257}
258
259void AMDGPUInstPrinter::printUpdatePred(const MCInst *MI, unsigned OpNo,
260                                        raw_ostream &O) {
261  printIfSet(MI, OpNo, O, "Pred,");
262}
263
264void AMDGPUInstPrinter::printWrite(const MCInst *MI, unsigned OpNo,
265                                       raw_ostream &O) {
266  const MCOperand &Op = MI->getOperand(OpNo);
267  if (Op.getImm() == 0) {
268    O << " (MASKED)";
269  }
270}
271
272void AMDGPUInstPrinter::printSel(const MCInst *MI, unsigned OpNo,
273                                  raw_ostream &O) {
274  const char * chans = "XYZW";
275  int sel = MI->getOperand(OpNo).getImm();
276
277  int chan = sel & 3;
278  sel >>= 2;
279
280  if (sel >= 512) {
281    sel -= 512;
282    int cb = sel >> 12;
283    sel &= 4095;
284    O << cb << "[" << sel << "]";
285  } else if (sel >= 448) {
286    sel -= 448;
287    O << sel;
288  } else if (sel >= 0){
289    O << sel;
290  }
291
292  if (sel >= 0)
293    O << "." << chans[chan];
294}
295
296void AMDGPUInstPrinter::printBankSwizzle(const MCInst *MI, unsigned OpNo,
297                                         raw_ostream &O) {
298  int BankSwizzle = MI->getOperand(OpNo).getImm();
299  switch (BankSwizzle) {
300  case 1:
301    O << "BS:VEC_021/SCL_122";
302    break;
303  case 2:
304    O << "BS:VEC_120/SCL_212";
305    break;
306  case 3:
307    O << "BS:VEC_102/SCL_221";
308    break;
309  case 4:
310    O << "BS:VEC_201";
311    break;
312  case 5:
313    O << "BS:VEC_210";
314    break;
315  default:
316    break;
317  }
318  return;
319}
320
321void AMDGPUInstPrinter::printRSel(const MCInst *MI, unsigned OpNo,
322                                  raw_ostream &O) {
323  unsigned Sel = MI->getOperand(OpNo).getImm();
324  switch (Sel) {
325  case 0:
326    O << "X";
327    break;
328  case 1:
329    O << "Y";
330    break;
331  case 2:
332    O << "Z";
333    break;
334  case 3:
335    O << "W";
336    break;
337  case 4:
338    O << "0";
339    break;
340  case 5:
341    O << "1";
342    break;
343  case 7:
344    O << "_";
345    break;
346  default:
347    break;
348  }
349}
350
351void AMDGPUInstPrinter::printCT(const MCInst *MI, unsigned OpNo,
352                                  raw_ostream &O) {
353  unsigned CT = MI->getOperand(OpNo).getImm();
354  switch (CT) {
355  case 0:
356    O << "U";
357    break;
358  case 1:
359    O << "N";
360    break;
361  default:
362    break;
363  }
364}
365
366void AMDGPUInstPrinter::printKCache(const MCInst *MI, unsigned OpNo,
367                                    raw_ostream &O) {
368  int KCacheMode = MI->getOperand(OpNo).getImm();
369  if (KCacheMode > 0) {
370    int KCacheBank = MI->getOperand(OpNo - 2).getImm();
371    O << "CB" << KCacheBank <<":";
372    int KCacheAddr = MI->getOperand(OpNo + 2).getImm();
373    int LineSize = (KCacheMode == 1)?16:32;
374    O << KCacheAddr * 16 << "-" << KCacheAddr * 16 + LineSize;
375  }
376}
377
378void AMDGPUInstPrinter::printSendMsg(const MCInst *MI, unsigned OpNo,
379                                     raw_ostream &O) {
380  unsigned SImm16 = MI->getOperand(OpNo).getImm();
381  unsigned Msg = SImm16 & 0xF;
382  if (Msg == 2 || Msg == 3) {
383    unsigned Op = (SImm16 >> 4) & 0xF;
384    if (Msg == 3)
385      O << "Gs_done(";
386    else
387      O << "Gs(";
388    if (Op == 0) {
389      O << "nop";
390    } else {
391      unsigned Stream = (SImm16 >> 8) & 0x3;
392      if (Op == 1)
393	O << "cut";
394      else if (Op == 2)
395	O << "emit";
396      else if (Op == 3)
397	O << "emit-cut";
398      O << " stream " << Stream;
399    }
400    O << "), [m0] ";
401  } else if (Msg == 1)
402    O << "interrupt ";
403  else if (Msg == 15)
404    O << "system ";
405  else
406    O << "unknown(" << Msg << ") ";
407}
408
409void AMDGPUInstPrinter::printWaitFlag(const MCInst *MI, unsigned OpNo,
410                                      raw_ostream &O) {
411  // Note: Mask values are taken from SIInsertWaits.cpp and not from ISA docs
412  // SIInsertWaits.cpp bits usage does not match ISA docs description but it
413  // works so it might be a misprint in docs.
414  unsigned SImm16 = MI->getOperand(OpNo).getImm();
415  unsigned Vmcnt = SImm16 & 0xF;
416  unsigned Expcnt = (SImm16 >> 4) & 0xF;
417  unsigned Lgkmcnt = (SImm16 >> 8) & 0xF;
418  if (Vmcnt != 0xF)
419    O << "vmcnt(" << Vmcnt << ") ";
420  if (Expcnt != 0x7)
421    O << "expcnt(" << Expcnt << ") ";
422  if (Lgkmcnt != 0x7)
423    O << "lgkmcnt(" << Lgkmcnt << ")";
424}
425
426#include "AMDGPUGenAsmWriter.inc"
427