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/MCAsmInfo.h"
18#include "llvm/MC/MCExpr.h"
19#include "llvm/MC/MCInst.h"
20#include "llvm/MC/MCInstrDesc.h"
21#include "llvm/MC/MCInstrInfo.h"
22#include "llvm/MC/MCRegisterInfo.h"
23#include "llvm/Support/ErrorHandling.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, OpNo: 0, O);
49 O << ", ";
50
51 if (Opcode == AVR::LDRdPtrPd)
52 O << '-';
53
54 printOperand(MI, OpNo: 1, O);
55
56 if (Opcode == AVR::LDRdPtrPi)
57 O << '+';
58 break;
59 case AVR::STPtrRr:
60 O << "\tst\t";
61 printOperand(MI, OpNo: 0, O);
62 O << ", ";
63 printOperand(MI, OpNo: 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, OpNo: 1, O);
73
74 if (Opcode == AVR::STPtrPiRr)
75 O << '+';
76
77 O << ", ";
78 printOperand(MI, OpNo: 2, O);
79 break;
80 default:
81 if (!printAliasInstr(MI, Address, OS&: O))
82 printInstruction(MI, Address, O);
83
84 printAnnotation(OS&: O, Annot);
85 break;
86 }
87}
88
89const char *AVRInstPrinter::getPrettyRegisterName(MCRegister Reg,
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 MCRegister RegLo = MRI.getSubReg(Reg, Idx: AVR::sub_lo);
95 Reg = (RegLo != AVR::NoRegister) ? RegLo : Reg;
96 }
97
98 return getRegisterName(Reg);
99}
100
101void AVRInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
102 raw_ostream &O) {
103 const MCOperandInfo &MOI = this->MII.get(Opcode: MI->getOpcode()).operands()[OpNo];
104 const MCOperand &Op = MI->getOperand(i: OpNo);
105
106 if (Op.isReg()) {
107 bool isPtrReg = (MOI.RegClass == AVR::PTRREGSRegClassID) ||
108 (MOI.RegClass == AVR::PTRDISPREGSRegClassID) ||
109 (MOI.RegClass == AVR::ZREGRegClassID);
110
111 if (isPtrReg) {
112 O << getRegisterName(Reg: Op.getReg(), AltIdx: AVR::ptr);
113 } else {
114 O << getPrettyRegisterName(Reg: Op.getReg(), MRI);
115 }
116 } else if (Op.isImm()) {
117 O << formatImm(Value: Op.getImm());
118 } else {
119 assert(Op.isExpr() && "Unknown operand kind in printOperand");
120 MAI.printExpr(O, *Op.getExpr());
121 }
122}
123
124/// This is used to print an immediate value that ends up
125/// being encoded as a pc-relative value.
126void AVRInstPrinter::printPCRelImm(const MCInst *MI, unsigned OpNo,
127 raw_ostream &O) {
128 if (OpNo >= MI->size()) {
129 // Not all operands are correctly disassembled at the moment. This means
130 // that some machine instructions won't have all the necessary operands
131 // set.
132 // To avoid asserting, print <unknown> instead until the necessary support
133 // has been implemented.
134 O << "<unknown>";
135 return;
136 }
137
138 const MCOperand &Op = MI->getOperand(i: OpNo);
139
140 if (Op.isImm()) {
141 int64_t Imm = Op.getImm();
142 O << '.';
143
144 // Print a position sign if needed.
145 // Negative values have their sign printed automatically.
146 if (Imm >= 0)
147 O << '+';
148
149 O << Imm;
150 } else {
151 assert(Op.isExpr() && "Unknown pcrel immediate operand");
152 MAI.printExpr(O, *Op.getExpr());
153 }
154}
155
156void AVRInstPrinter::printMemri(const MCInst *MI, unsigned OpNo,
157 raw_ostream &O) {
158 assert(MI->getOperand(OpNo).isReg() &&
159 "Expected a register for the first operand");
160
161 const MCOperand &OffsetOp = MI->getOperand(i: OpNo + 1);
162
163 // Print the register.
164 printOperand(MI, OpNo, O);
165
166 // Print the {+,-}offset.
167 if (OffsetOp.isImm()) {
168 int64_t Offset = OffsetOp.getImm();
169
170 if (Offset >= 0)
171 O << '+';
172
173 O << Offset;
174 } else if (OffsetOp.isExpr()) {
175 MAI.printExpr(O, *OffsetOp.getExpr());
176 } else {
177 llvm_unreachable("unknown type for offset");
178 }
179}
180
181} // end of namespace llvm
182