1//===-- AVRInstPrinter.cpp - Convert AVR MCInst to assembly syntax --------===//
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 AVR MCInst to a .s file.
10//
11//===----------------------------------------------------------------------===//
12
13#include "AVRInstPrinter.h"
14
15#include "MCTargetDesc/AVRMCTargetDesc.h"
16
17#include "llvm/MC/MCExpr.h"
18#include "llvm/MC/MCInst.h"
19#include "llvm/MC/MCInstrDesc.h"
20#include "llvm/MC/MCInstrInfo.h"
21#include "llvm/MC/MCRegisterInfo.h"
22#include "llvm/Support/ErrorHandling.h"
23#include "llvm/Support/FormattedStream.h"
24
25#include <cstring>
26
27#define DEBUG_TYPE "asm-printer"
28
29namespace llvm {
30
31// Include the auto-generated portion of the assembly writer.
32#define PRINT_ALIAS_INSTR
33#include "AVRGenAsmWriter.inc"
34
35void AVRInstPrinter::printInst(const MCInst *MI, uint64_t Address,
36                               StringRef Annot, const MCSubtargetInfo &STI,
37                               raw_ostream &O) {
38  unsigned Opcode = MI->getOpcode();
39
40  // First handle load and store instructions with postinc or predec
41  // of the form "ld reg, X+".
42  // TODO: We should be able to rewrite this using TableGen data.
43  switch (Opcode) {
44  case AVR::LDRdPtr:
45  case AVR::LDRdPtrPi:
46  case AVR::LDRdPtrPd:
47    O << "\tld\t";
48    printOperand(MI, 0, O);
49    O << ", ";
50
51    if (Opcode == AVR::LDRdPtrPd)
52      O << '-';
53
54    printOperand(MI, 1, O);
55
56    if (Opcode == AVR::LDRdPtrPi)
57      O << '+';
58    break;
59  case AVR::STPtrRr:
60    O << "\tst\t";
61    printOperand(MI, 0, O);
62    O << ", ";
63    printOperand(MI, 1, O);
64    break;
65  case AVR::STPtrPiRr:
66  case AVR::STPtrPdRr:
67    O << "\tst\t";
68
69    if (Opcode == AVR::STPtrPdRr)
70      O << '-';
71
72    printOperand(MI, 1, O);
73
74    if (Opcode == AVR::STPtrPiRr)
75      O << '+';
76
77    O << ", ";
78    printOperand(MI, 2, O);
79    break;
80  default:
81    if (!printAliasInstr(MI, Address, O))
82      printInstruction(MI, Address, O);
83
84    printAnnotation(O, Annot);
85    break;
86  }
87}
88
89const char *AVRInstPrinter::getPrettyRegisterName(unsigned RegNum,
90                                                  MCRegisterInfo const &MRI) {
91  // GCC prints register pairs by just printing the lower register
92  // If the register contains a subregister, print it instead
93  if (MRI.getNumSubRegIndices() > 0) {
94    unsigned RegLoNum = MRI.getSubReg(RegNum, AVR::sub_lo);
95    RegNum = (RegLoNum != AVR::NoRegister) ? RegLoNum : RegNum;
96  }
97
98  return getRegisterName(RegNum);
99}
100
101void AVRInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
102                                  raw_ostream &O) {
103  const MCOperandInfo &MOI = this->MII.get(MI->getOpcode()).OpInfo[OpNo];
104  if (MOI.RegClass == AVR::ZREGRegClassID) {
105    // Special case for the Z register, which sometimes doesn't have an operand
106    // in the MCInst.
107    O << "Z";
108    return;
109  }
110
111  if (OpNo >= MI->size()) {
112    // Not all operands are correctly disassembled at the moment. This means
113    // that some machine instructions won't have all the necessary operands
114    // set.
115    // To avoid asserting, print <unknown> instead until the necessary support
116    // has been implemented.
117    O << "<unknown>";
118    return;
119  }
120
121  const MCOperand &Op = MI->getOperand(OpNo);
122
123  if (Op.isReg()) {
124    bool isPtrReg = (MOI.RegClass == AVR::PTRREGSRegClassID) ||
125                    (MOI.RegClass == AVR::PTRDISPREGSRegClassID) ||
126                    (MOI.RegClass == AVR::ZREGRegClassID);
127
128    if (isPtrReg) {
129      O << getRegisterName(Op.getReg(), AVR::ptr);
130    } else {
131      O << getPrettyRegisterName(Op.getReg(), MRI);
132    }
133  } else if (Op.isImm()) {
134    O << formatImm(Op.getImm());
135  } else {
136    assert(Op.isExpr() && "Unknown operand kind in printOperand");
137    O << *Op.getExpr();
138  }
139}
140
141/// This is used to print an immediate value that ends up
142/// being encoded as a pc-relative value.
143void AVRInstPrinter::printPCRelImm(const MCInst *MI, unsigned OpNo,
144                                   raw_ostream &O) {
145  if (OpNo >= MI->size()) {
146    // Not all operands are correctly disassembled at the moment. This means
147    // that some machine instructions won't have all the necessary operands
148    // set.
149    // To avoid asserting, print <unknown> instead until the necessary support
150    // has been implemented.
151    O << "<unknown>";
152    return;
153  }
154
155  const MCOperand &Op = MI->getOperand(OpNo);
156
157  if (Op.isImm()) {
158    int64_t Imm = Op.getImm();
159    O << '.';
160
161    // Print a position sign if needed.
162    // Negative values have their sign printed automatically.
163    if (Imm >= 0)
164      O << '+';
165
166    O << Imm;
167  } else {
168    assert(Op.isExpr() && "Unknown pcrel immediate operand");
169    O << *Op.getExpr();
170  }
171}
172
173void AVRInstPrinter::printMemri(const MCInst *MI, unsigned OpNo,
174                                raw_ostream &O) {
175  assert(MI->getOperand(OpNo).isReg() && "Expected a register for the first operand");
176
177  const MCOperand &OffsetOp = MI->getOperand(OpNo + 1);
178
179  // Print the register.
180  printOperand(MI, OpNo, O);
181
182  // Print the {+,-}offset.
183  if (OffsetOp.isImm()) {
184    int64_t Offset = OffsetOp.getImm();
185
186    if (Offset >= 0)
187      O << '+';
188
189    O << Offset;
190  } else if (OffsetOp.isExpr()) {
191    O << *OffsetOp.getExpr();
192  } else {
193    llvm_unreachable("unknown type for offset");
194  }
195}
196
197} // end of namespace llvm
198
199