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