1 | //===- SystemZInstPrinter.cpp - Convert SystemZ 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 | #include "SystemZInstPrinter.h" |
10 | #include "llvm/MC/MCExpr.h" |
11 | #include "llvm/MC/MCInst.h" |
12 | #include "llvm/MC/MCRegister.h" |
13 | #include "llvm/MC/MCSymbol.h" |
14 | #include "llvm/Support/Casting.h" |
15 | #include "llvm/Support/ErrorHandling.h" |
16 | #include "llvm/Support/MathExtras.h" |
17 | #include "llvm/Support/raw_ostream.h" |
18 | #include <cassert> |
19 | #include <cstdint> |
20 | |
21 | using namespace llvm; |
22 | |
23 | #define DEBUG_TYPE "asm-printer" |
24 | |
25 | #include "SystemZGenAsmWriter.inc" |
26 | |
27 | void SystemZInstPrinter::printAddress(const MCAsmInfo *MAI, MCRegister Base, |
28 | const MCOperand &DispMO, MCRegister Index, |
29 | raw_ostream &O) { |
30 | printOperand(MO: DispMO, MAI, O); |
31 | if (Base || Index) { |
32 | O << '('; |
33 | if (Index) { |
34 | printFormattedRegName(MAI, Reg: Index, O); |
35 | O << ','; |
36 | } |
37 | if (Base) |
38 | printFormattedRegName(MAI, Reg: Base, O); |
39 | else |
40 | O << '0'; |
41 | O << ')'; |
42 | } |
43 | } |
44 | |
45 | void SystemZInstPrinter::printOperand(const MCOperand &MO, const MCAsmInfo *MAI, |
46 | raw_ostream &O) { |
47 | if (MO.isReg()) { |
48 | if (!MO.getReg()) |
49 | O << '0'; |
50 | else |
51 | printFormattedRegName(MAI, Reg: MO.getReg(), O); |
52 | } |
53 | else if (MO.isImm()) |
54 | markup(OS&: O, M: Markup::Immediate) << MO.getImm(); |
55 | else if (MO.isExpr()) |
56 | MO.getExpr()->print(OS&: O, MAI); |
57 | else |
58 | llvm_unreachable("Invalid operand" ); |
59 | } |
60 | |
61 | void SystemZInstPrinter::printFormattedRegName(const MCAsmInfo *MAI, |
62 | MCRegister Reg, |
63 | raw_ostream &O) const { |
64 | const char *RegName = getRegisterName(Reg); |
65 | if (MAI->getAssemblerDialect() == AD_HLASM) { |
66 | // Skip register prefix so that only register number is left |
67 | assert(isalpha(RegName[0]) && isdigit(RegName[1])); |
68 | markup(OS&: O, M: Markup::Register) << (RegName + 1); |
69 | } else |
70 | markup(OS&: O, M: Markup::Register) << '%' << RegName; |
71 | } |
72 | |
73 | void SystemZInstPrinter::printRegName(raw_ostream &O, MCRegister Reg) const { |
74 | printFormattedRegName(MAI: &MAI, Reg, O); |
75 | } |
76 | |
77 | void SystemZInstPrinter::printInst(const MCInst *MI, uint64_t Address, |
78 | StringRef Annot, const MCSubtargetInfo &STI, |
79 | raw_ostream &O) { |
80 | printInstruction(MI, Address, O); |
81 | printAnnotation(OS&: O, Annot); |
82 | } |
83 | |
84 | template <unsigned N> |
85 | void SystemZInstPrinter::printUImmOperand(const MCInst *MI, int OpNum, |
86 | raw_ostream &O) { |
87 | const MCOperand &MO = MI->getOperand(i: OpNum); |
88 | if (MO.isExpr()) { |
89 | O << *MO.getExpr(); |
90 | return; |
91 | } |
92 | uint64_t Value = static_cast<uint64_t>(MO.getImm()); |
93 | assert(isUInt<N>(Value) && "Invalid uimm argument" ); |
94 | markup(OS&: O, M: Markup::Immediate) << Value; |
95 | } |
96 | |
97 | template <unsigned N> |
98 | void SystemZInstPrinter::printSImmOperand(const MCInst *MI, int OpNum, |
99 | raw_ostream &O) { |
100 | const MCOperand &MO = MI->getOperand(i: OpNum); |
101 | if (MO.isExpr()) { |
102 | O << *MO.getExpr(); |
103 | return; |
104 | } |
105 | int64_t Value = MI->getOperand(i: OpNum).getImm(); |
106 | assert(isInt<N>(Value) && "Invalid simm argument" ); |
107 | markup(OS&: O, M: Markup::Immediate) << Value; |
108 | } |
109 | |
110 | void SystemZInstPrinter::printU1ImmOperand(const MCInst *MI, int OpNum, |
111 | raw_ostream &O) { |
112 | printUImmOperand<1>(MI, OpNum, O); |
113 | } |
114 | |
115 | void SystemZInstPrinter::printU2ImmOperand(const MCInst *MI, int OpNum, |
116 | raw_ostream &O) { |
117 | printUImmOperand<2>(MI, OpNum, O); |
118 | } |
119 | |
120 | void SystemZInstPrinter::printU3ImmOperand(const MCInst *MI, int OpNum, |
121 | raw_ostream &O) { |
122 | printUImmOperand<3>(MI, OpNum, O); |
123 | } |
124 | |
125 | void SystemZInstPrinter::printU4ImmOperand(const MCInst *MI, int OpNum, |
126 | raw_ostream &O) { |
127 | printUImmOperand<4>(MI, OpNum, O); |
128 | } |
129 | |
130 | void SystemZInstPrinter::printS8ImmOperand(const MCInst *MI, int OpNum, |
131 | raw_ostream &O) { |
132 | printSImmOperand<8>(MI, OpNum, O); |
133 | } |
134 | |
135 | void SystemZInstPrinter::printU8ImmOperand(const MCInst *MI, int OpNum, |
136 | raw_ostream &O) { |
137 | printUImmOperand<8>(MI, OpNum, O); |
138 | } |
139 | |
140 | void SystemZInstPrinter::printU12ImmOperand(const MCInst *MI, int OpNum, |
141 | raw_ostream &O) { |
142 | printUImmOperand<12>(MI, OpNum, O); |
143 | } |
144 | |
145 | void SystemZInstPrinter::printS16ImmOperand(const MCInst *MI, int OpNum, |
146 | raw_ostream &O) { |
147 | printSImmOperand<16>(MI, OpNum, O); |
148 | } |
149 | |
150 | void SystemZInstPrinter::printU16ImmOperand(const MCInst *MI, int OpNum, |
151 | raw_ostream &O) { |
152 | printUImmOperand<16>(MI, OpNum, O); |
153 | } |
154 | |
155 | void SystemZInstPrinter::printS32ImmOperand(const MCInst *MI, int OpNum, |
156 | raw_ostream &O) { |
157 | printSImmOperand<32>(MI, OpNum, O); |
158 | } |
159 | |
160 | void SystemZInstPrinter::printU32ImmOperand(const MCInst *MI, int OpNum, |
161 | raw_ostream &O) { |
162 | printUImmOperand<32>(MI, OpNum, O); |
163 | } |
164 | |
165 | void SystemZInstPrinter::printU48ImmOperand(const MCInst *MI, int OpNum, |
166 | raw_ostream &O) { |
167 | printUImmOperand<48>(MI, OpNum, O); |
168 | } |
169 | |
170 | void SystemZInstPrinter::printPCRelOperand(const MCInst *MI, int OpNum, |
171 | raw_ostream &O) { |
172 | const MCOperand &MO = MI->getOperand(i: OpNum); |
173 | if (MO.isImm()) { |
174 | WithMarkup M = markup(OS&: O, M: Markup::Immediate); |
175 | O << "0x" ; |
176 | O.write_hex(N: MO.getImm()); |
177 | } else |
178 | MO.getExpr()->print(OS&: O, MAI: &MAI); |
179 | } |
180 | |
181 | void SystemZInstPrinter::printPCRelTLSOperand(const MCInst *MI, |
182 | uint64_t Address, int OpNum, |
183 | raw_ostream &O) { |
184 | // Output the PC-relative operand. |
185 | printPCRelOperand(MI, OpNum, O); |
186 | |
187 | // Output the TLS marker if present. |
188 | if ((unsigned)OpNum + 1 < MI->getNumOperands()) { |
189 | const MCOperand &MO = MI->getOperand(i: OpNum + 1); |
190 | const MCSymbolRefExpr &refExp = cast<MCSymbolRefExpr>(Val: *MO.getExpr()); |
191 | switch (refExp.getKind()) { |
192 | case MCSymbolRefExpr::VK_TLSGD: |
193 | O << ":tls_gdcall:" ; |
194 | break; |
195 | case MCSymbolRefExpr::VK_TLSLDM: |
196 | O << ":tls_ldcall:" ; |
197 | break; |
198 | default: |
199 | llvm_unreachable("Unexpected symbol kind" ); |
200 | } |
201 | O << refExp.getSymbol().getName(); |
202 | } |
203 | } |
204 | |
205 | void SystemZInstPrinter::printOperand(const MCInst *MI, int OpNum, |
206 | raw_ostream &O) { |
207 | printOperand(MO: MI->getOperand(i: OpNum), MAI: &MAI, O); |
208 | } |
209 | |
210 | void SystemZInstPrinter::printBDAddrOperand(const MCInst *MI, int OpNum, |
211 | raw_ostream &O) { |
212 | printAddress(MAI: &MAI, Base: MI->getOperand(i: OpNum).getReg(), DispMO: MI->getOperand(i: OpNum + 1), |
213 | Index: 0, O); |
214 | } |
215 | |
216 | void SystemZInstPrinter::printBDXAddrOperand(const MCInst *MI, int OpNum, |
217 | raw_ostream &O) { |
218 | printAddress(MAI: &MAI, Base: MI->getOperand(i: OpNum).getReg(), DispMO: MI->getOperand(i: OpNum + 1), |
219 | Index: MI->getOperand(i: OpNum + 2).getReg(), O); |
220 | } |
221 | |
222 | void SystemZInstPrinter::printBDLAddrOperand(const MCInst *MI, int OpNum, |
223 | raw_ostream &O) { |
224 | unsigned Base = MI->getOperand(i: OpNum).getReg(); |
225 | const MCOperand &DispMO = MI->getOperand(i: OpNum + 1); |
226 | uint64_t Length = MI->getOperand(i: OpNum + 2).getImm(); |
227 | printOperand(MO: DispMO, MAI: &MAI, O); |
228 | O << '(' << Length; |
229 | if (Base) { |
230 | O << "," ; |
231 | printRegName(O, Reg: Base); |
232 | } |
233 | O << ')'; |
234 | } |
235 | |
236 | void SystemZInstPrinter::printBDRAddrOperand(const MCInst *MI, int OpNum, |
237 | raw_ostream &O) { |
238 | unsigned Base = MI->getOperand(i: OpNum).getReg(); |
239 | const MCOperand &DispMO = MI->getOperand(i: OpNum + 1); |
240 | unsigned Length = MI->getOperand(i: OpNum + 2).getReg(); |
241 | printOperand(MO: DispMO, MAI: &MAI, O); |
242 | O << "(" ; |
243 | printRegName(O, Reg: Length); |
244 | if (Base) { |
245 | O << "," ; |
246 | printRegName(O, Reg: Base); |
247 | } |
248 | O << ')'; |
249 | } |
250 | |
251 | void SystemZInstPrinter::printBDVAddrOperand(const MCInst *MI, int OpNum, |
252 | raw_ostream &O) { |
253 | printAddress(MAI: &MAI, Base: MI->getOperand(i: OpNum).getReg(), DispMO: MI->getOperand(i: OpNum + 1), |
254 | Index: MI->getOperand(i: OpNum + 2).getReg(), O); |
255 | } |
256 | |
257 | void SystemZInstPrinter::printCond4Operand(const MCInst *MI, int OpNum, |
258 | raw_ostream &O) { |
259 | static const char *const CondNames[] = { |
260 | "o" , "h" , "nle" , "l" , "nhe" , "lh" , "ne" , |
261 | "e" , "nlh" , "he" , "nl" , "le" , "nh" , "no" |
262 | }; |
263 | uint64_t Imm = MI->getOperand(i: OpNum).getImm(); |
264 | assert(Imm > 0 && Imm < 15 && "Invalid condition" ); |
265 | O << CondNames[Imm - 1]; |
266 | } |
267 | |