1//===- ARCInstPrinter.cpp - ARC MCInst to assembly syntax -------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This class prints an ARC MCInst to a .s file.
10//
11//===----------------------------------------------------------------------===//
12
13#include "ARCInstPrinter.h"
14#include "MCTargetDesc/ARCInfo.h"
15#include "llvm/ADT/StringExtras.h"
16#include "llvm/MC/MCExpr.h"
17#include "llvm/MC/MCInst.h"
18#include "llvm/MC/MCInstrInfo.h"
19#include "llvm/MC/MCSymbol.h"
20#include "llvm/Support/Casting.h"
21#include "llvm/Support/Debug.h"
22#include "llvm/Support/raw_ostream.h"
23
24using namespace llvm;
25
26#define DEBUG_TYPE "asm-printer"
27
28#include "ARCGenAsmWriter.inc"
29
30template <class T>
31static const char *BadConditionCode(T cc) {
32  LLVM_DEBUG(dbgs() << "Unknown condition code passed: " << cc << "\n");
33  return "{unknown-cc}";
34}
35
36static const char *ARCBRCondCodeToString(ARCCC::BRCondCode BRCC) {
37  switch (BRCC) {
38  case ARCCC::BREQ:
39    return "eq";
40  case ARCCC::BRNE:
41    return "ne";
42  case ARCCC::BRLT:
43    return "lt";
44  case ARCCC::BRGE:
45    return "ge";
46  case ARCCC::BRLO:
47    return "lo";
48  case ARCCC::BRHS:
49    return "hs";
50  }
51  return BadConditionCode(BRCC);
52}
53
54static const char *ARCCondCodeToString(ARCCC::CondCode CC) {
55  switch (CC) {
56  case ARCCC::EQ:
57    return "eq";
58  case ARCCC::NE:
59    return "ne";
60  case ARCCC::P:
61    return "p";
62  case ARCCC::N:
63    return "n";
64  case ARCCC::HS:
65    return "hs";
66  case ARCCC::LO:
67    return "lo";
68  case ARCCC::GT:
69    return "gt";
70  case ARCCC::GE:
71    return "ge";
72  case ARCCC::VS:
73    return "vs";
74  case ARCCC::VC:
75    return "vc";
76  case ARCCC::LT:
77    return "lt";
78  case ARCCC::LE:
79    return "le";
80  case ARCCC::HI:
81    return "hi";
82  case ARCCC::LS:
83    return "ls";
84  case ARCCC::PNZ:
85    return "pnz";
86  case ARCCC::AL:
87    return "al";
88  case ARCCC::NZ:
89    return "nz";
90  case ARCCC::Z:
91    return "z";
92  }
93  return BadConditionCode(CC);
94}
95
96void ARCInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const {
97  OS << StringRef(getRegisterName(RegNo)).lower();
98}
99
100void ARCInstPrinter::printInst(const MCInst *MI, uint64_t Address,
101                               StringRef Annot, const MCSubtargetInfo &STI,
102                               raw_ostream &O) {
103  printInstruction(MI, Address, O);
104  printAnnotation(O, Annot);
105}
106
107static void printExpr(const MCExpr *Expr, const MCAsmInfo *MAI,
108                      raw_ostream &OS) {
109  int Offset = 0;
110  const MCSymbolRefExpr *SRE;
111
112  if (const auto *CE = dyn_cast<MCConstantExpr>(Expr)) {
113    OS << "0x";
114    OS.write_hex(CE->getValue());
115    return;
116  }
117
118  if (const auto *BE = dyn_cast<MCBinaryExpr>(Expr)) {
119    SRE = dyn_cast<MCSymbolRefExpr>(BE->getLHS());
120    const auto *CE = dyn_cast<MCConstantExpr>(BE->getRHS());
121    assert(SRE && CE && "Binary expression must be sym+const.");
122    Offset = CE->getValue();
123  } else {
124    SRE = dyn_cast<MCSymbolRefExpr>(Expr);
125    assert(SRE && "Unexpected MCExpr type.");
126  }
127  assert(SRE->getKind() == MCSymbolRefExpr::VK_None);
128
129  // Symbols are prefixed with '@'
130  OS << '@';
131  SRE->getSymbol().print(OS, MAI);
132
133  if (Offset) {
134    if (Offset > 0)
135      OS << '+';
136    OS << Offset;
137  }
138}
139
140void ARCInstPrinter::printOperand(const MCInst *MI, unsigned OpNum,
141                                  raw_ostream &O) {
142  const MCOperand &Op = MI->getOperand(OpNum);
143  if (Op.isReg()) {
144    printRegName(O, Op.getReg());
145    return;
146  }
147
148  if (Op.isImm()) {
149    O << Op.getImm();
150    return;
151  }
152
153  assert(Op.isExpr() && "unknown operand kind in printOperand");
154  printExpr(Op.getExpr(), &MAI, O);
155}
156
157void ARCInstPrinter::printMemOperandRI(const MCInst *MI, unsigned OpNum,
158                                       raw_ostream &O) {
159  const MCOperand &base = MI->getOperand(OpNum);
160  const MCOperand &offset = MI->getOperand(OpNum + 1);
161  assert(base.isReg() && "Base should be register.");
162  assert(offset.isImm() && "Offset should be immediate.");
163  printRegName(O, base.getReg());
164  O << "," << offset.getImm();
165}
166
167void ARCInstPrinter::printPredicateOperand(const MCInst *MI, unsigned OpNum,
168                                           raw_ostream &O) {
169
170  const MCOperand &Op = MI->getOperand(OpNum);
171  assert(Op.isImm() && "Predicate operand is immediate.");
172  O << ARCCondCodeToString((ARCCC::CondCode)Op.getImm());
173}
174
175void ARCInstPrinter::printBRCCPredicateOperand(const MCInst *MI, unsigned OpNum,
176                                               raw_ostream &O) {
177  const MCOperand &Op = MI->getOperand(OpNum);
178  assert(Op.isImm() && "Predicate operand is immediate.");
179  O << ARCBRCondCodeToString((ARCCC::BRCondCode)Op.getImm());
180}
181