1//===-- NVPTXInstPrinter.cpp - PTX assembly instruction printing ----------===//
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// Print MCInst instructions to .ptx format.
11//
12//===----------------------------------------------------------------------===//
13
14#include "InstPrinter/NVPTXInstPrinter.h"
15#include "MCTargetDesc/NVPTXBaseInfo.h"
16#include "NVPTX.h"
17#include "llvm/MC/MCExpr.h"
18#include "llvm/MC/MCInst.h"
19#include "llvm/MC/MCInstrInfo.h"
20#include "llvm/MC/MCSubtargetInfo.h"
21#include "llvm/MC/MCSymbol.h"
22#include "llvm/Support/ErrorHandling.h"
23#include "llvm/Support/FormattedStream.h"
24#include <cctype>
25using namespace llvm;
26
27#define DEBUG_TYPE "asm-printer"
28
29#include "NVPTXGenAsmWriter.inc"
30
31
32NVPTXInstPrinter::NVPTXInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII,
33                                   const MCRegisterInfo &MRI,
34                                   const MCSubtargetInfo &STI)
35  : MCInstPrinter(MAI, MII, MRI) {
36  setAvailableFeatures(STI.getFeatureBits());
37}
38
39void NVPTXInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const {
40  // Decode the virtual register
41  // Must be kept in sync with NVPTXAsmPrinter::encodeVirtualRegister
42  unsigned RCId = (RegNo >> 28);
43  switch (RCId) {
44  default: report_fatal_error("Bad virtual register encoding");
45  case 0:
46    // This is actually a physical register, so defer to the autogenerated
47    // register printer
48    OS << getRegisterName(RegNo);
49    return;
50  case 1:
51    OS << "%p";
52    break;
53  case 2:
54    OS << "%rs";
55    break;
56  case 3:
57    OS << "%r";
58    break;
59  case 4:
60    OS << "%rl";
61    break;
62  case 5:
63    OS << "%f";
64    break;
65  case 6:
66    OS << "%fl";
67    break;
68  }
69
70  unsigned VReg = RegNo & 0x0FFFFFFF;
71  OS << VReg;
72}
73
74void NVPTXInstPrinter::printInst(const MCInst *MI, raw_ostream &OS,
75                                 StringRef Annot) {
76  printInstruction(MI, OS);
77
78  // Next always print the annotation.
79  printAnnotation(OS, Annot);
80}
81
82void NVPTXInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
83                                    raw_ostream &O) {
84  const MCOperand &Op = MI->getOperand(OpNo);
85  if (Op.isReg()) {
86    unsigned Reg = Op.getReg();
87    printRegName(O, Reg);
88  } else if (Op.isImm()) {
89    O << markup("<imm:") << formatImm(Op.getImm()) << markup(">");
90  } else {
91    assert(Op.isExpr() && "Unknown operand kind in printOperand");
92    O << *Op.getExpr();
93  }
94}
95
96void NVPTXInstPrinter::printCvtMode(const MCInst *MI, int OpNum, raw_ostream &O,
97                                    const char *Modifier) {
98  const MCOperand &MO = MI->getOperand(OpNum);
99  int64_t Imm = MO.getImm();
100
101  if (strcmp(Modifier, "ftz") == 0) {
102    // FTZ flag
103    if (Imm & NVPTX::PTXCvtMode::FTZ_FLAG)
104      O << ".ftz";
105  } else if (strcmp(Modifier, "sat") == 0) {
106    // SAT flag
107    if (Imm & NVPTX::PTXCvtMode::SAT_FLAG)
108      O << ".sat";
109  } else if (strcmp(Modifier, "base") == 0) {
110    // Default operand
111    switch (Imm & NVPTX::PTXCvtMode::BASE_MASK) {
112    default:
113      return;
114    case NVPTX::PTXCvtMode::NONE:
115      break;
116    case NVPTX::PTXCvtMode::RNI:
117      O << ".rni";
118      break;
119    case NVPTX::PTXCvtMode::RZI:
120      O << ".rzi";
121      break;
122    case NVPTX::PTXCvtMode::RMI:
123      O << ".rmi";
124      break;
125    case NVPTX::PTXCvtMode::RPI:
126      O << ".rpi";
127      break;
128    case NVPTX::PTXCvtMode::RN:
129      O << ".rn";
130      break;
131    case NVPTX::PTXCvtMode::RZ:
132      O << ".rz";
133      break;
134    case NVPTX::PTXCvtMode::RM:
135      O << ".rm";
136      break;
137    case NVPTX::PTXCvtMode::RP:
138      O << ".rp";
139      break;
140    }
141  } else {
142    llvm_unreachable("Invalid conversion modifier");
143  }
144}
145
146void NVPTXInstPrinter::printCmpMode(const MCInst *MI, int OpNum, raw_ostream &O,
147                                    const char *Modifier) {
148  const MCOperand &MO = MI->getOperand(OpNum);
149  int64_t Imm = MO.getImm();
150
151  if (strcmp(Modifier, "ftz") == 0) {
152    // FTZ flag
153    if (Imm & NVPTX::PTXCmpMode::FTZ_FLAG)
154      O << ".ftz";
155  } else if (strcmp(Modifier, "base") == 0) {
156    switch (Imm & NVPTX::PTXCmpMode::BASE_MASK) {
157    default:
158      return;
159    case NVPTX::PTXCmpMode::EQ:
160      O << ".eq";
161      break;
162    case NVPTX::PTXCmpMode::NE:
163      O << ".ne";
164      break;
165    case NVPTX::PTXCmpMode::LT:
166      O << ".lt";
167      break;
168    case NVPTX::PTXCmpMode::LE:
169      O << ".le";
170      break;
171    case NVPTX::PTXCmpMode::GT:
172      O << ".gt";
173      break;
174    case NVPTX::PTXCmpMode::GE:
175      O << ".ge";
176      break;
177    case NVPTX::PTXCmpMode::LO:
178      O << ".lo";
179      break;
180    case NVPTX::PTXCmpMode::LS:
181      O << ".ls";
182      break;
183    case NVPTX::PTXCmpMode::HI:
184      O << ".hi";
185      break;
186    case NVPTX::PTXCmpMode::HS:
187      O << ".hs";
188      break;
189    case NVPTX::PTXCmpMode::EQU:
190      O << ".equ";
191      break;
192    case NVPTX::PTXCmpMode::NEU:
193      O << ".neu";
194      break;
195    case NVPTX::PTXCmpMode::LTU:
196      O << ".ltu";
197      break;
198    case NVPTX::PTXCmpMode::LEU:
199      O << ".leu";
200      break;
201    case NVPTX::PTXCmpMode::GTU:
202      O << ".gtu";
203      break;
204    case NVPTX::PTXCmpMode::GEU:
205      O << ".geu";
206      break;
207    case NVPTX::PTXCmpMode::NUM:
208      O << ".num";
209      break;
210    case NVPTX::PTXCmpMode::NotANumber:
211      O << ".nan";
212      break;
213    }
214  } else {
215    llvm_unreachable("Empty Modifier");
216  }
217}
218
219void NVPTXInstPrinter::printLdStCode(const MCInst *MI, int OpNum,
220                                     raw_ostream &O, const char *Modifier) {
221  if (Modifier) {
222    const MCOperand &MO = MI->getOperand(OpNum);
223    int Imm = (int) MO.getImm();
224    if (!strcmp(Modifier, "volatile")) {
225      if (Imm)
226        O << ".volatile";
227    } else if (!strcmp(Modifier, "addsp")) {
228      switch (Imm) {
229      case NVPTX::PTXLdStInstCode::GLOBAL:
230        O << ".global";
231        break;
232      case NVPTX::PTXLdStInstCode::SHARED:
233        O << ".shared";
234        break;
235      case NVPTX::PTXLdStInstCode::LOCAL:
236        O << ".local";
237        break;
238      case NVPTX::PTXLdStInstCode::PARAM:
239        O << ".param";
240        break;
241      case NVPTX::PTXLdStInstCode::CONSTANT:
242        O << ".const";
243        break;
244      case NVPTX::PTXLdStInstCode::GENERIC:
245        break;
246      default:
247        llvm_unreachable("Wrong Address Space");
248      }
249    } else if (!strcmp(Modifier, "sign")) {
250      if (Imm == NVPTX::PTXLdStInstCode::Signed)
251        O << "s";
252      else if (Imm == NVPTX::PTXLdStInstCode::Unsigned)
253        O << "u";
254      else
255        O << "f";
256    } else if (!strcmp(Modifier, "vec")) {
257      if (Imm == NVPTX::PTXLdStInstCode::V2)
258        O << ".v2";
259      else if (Imm == NVPTX::PTXLdStInstCode::V4)
260        O << ".v4";
261    } else
262      llvm_unreachable("Unknown Modifier");
263  } else
264    llvm_unreachable("Empty Modifier");
265}
266
267void NVPTXInstPrinter::printMemOperand(const MCInst *MI, int OpNum,
268                                       raw_ostream &O, const char *Modifier) {
269  printOperand(MI, OpNum, O);
270
271  if (Modifier && !strcmp(Modifier, "add")) {
272    O << ", ";
273    printOperand(MI, OpNum + 1, O);
274  } else {
275    if (MI->getOperand(OpNum + 1).isImm() &&
276        MI->getOperand(OpNum + 1).getImm() == 0)
277      return; // don't print ',0' or '+0'
278    O << "+";
279    printOperand(MI, OpNum + 1, O);
280  }
281}
282
283void NVPTXInstPrinter::printProtoIdent(const MCInst *MI, int OpNum,
284                                       raw_ostream &O, const char *Modifier) {
285  const MCOperand &Op = MI->getOperand(OpNum);
286  assert(Op.isExpr() && "Call prototype is not an MCExpr?");
287  const MCExpr *Expr = Op.getExpr();
288  const MCSymbol &Sym = cast<MCSymbolRefExpr>(Expr)->getSymbol();
289  O << Sym.getName();
290}
291