1//=- SystemZInstPrinterCommon.cpp - Common SystemZ MCInst to assembly funcs -=//
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 "SystemZInstPrinterCommon.h"
10#include "MCTargetDesc/SystemZMCAsmInfo.h"
11#include "llvm/MC/MCExpr.h"
12#include "llvm/MC/MCInst.h"
13#include "llvm/MC/MCRegister.h"
14#include "llvm/MC/MCSymbol.h"
15#include "llvm/Support/Casting.h"
16#include "llvm/Support/ErrorHandling.h"
17#include "llvm/Support/MathExtras.h"
18#include "llvm/Support/raw_ostream.h"
19#include <cassert>
20#include <cstdint>
21
22using namespace llvm;
23
24#define DEBUG_TYPE "asm-printer"
25
26void SystemZInstPrinterCommon::printAddress(const MCAsmInfo *MAI,
27 MCRegister Base,
28 const MCOperand &DispMO,
29 MCRegister Index, raw_ostream &O) {
30 printOperand(MO: DispMO, MAI, O);
31 if (Base || Index) {
32 O << '(';
33 if (Index) {
34 printRegName(O, Reg: Index);
35 O << ',';
36 }
37 if (Base)
38 printRegName(O, Reg: Base);
39 else
40 O << '0';
41 O << ')';
42 }
43}
44
45void SystemZInstPrinterCommon::printOperand(const MCOperand &MO,
46 const MCAsmInfo *MAI,
47 raw_ostream &O) {
48 if (MO.isReg()) {
49 if (!MO.getReg())
50 O << '0';
51 else
52 printRegName(O, Reg: MO.getReg());
53 } else if (MO.isImm())
54 markup(OS&: O, M: Markup::Immediate) << MO.getImm();
55 else if (MO.isExpr())
56 MAI->printExpr(O, *MO.getExpr());
57 else
58 llvm_unreachable("Invalid operand");
59}
60
61void SystemZInstPrinterCommon::printRegName(raw_ostream &O, MCRegister Reg) {
62 printFormattedRegName(MAI: &MAI, Reg, O);
63}
64
65template <unsigned N>
66void SystemZInstPrinterCommon::printUImmOperand(const MCInst *MI, int OpNum,
67 raw_ostream &O) {
68 const MCOperand &MO = MI->getOperand(i: OpNum);
69 if (MO.isExpr()) {
70 MAI.printExpr(O, *MO.getExpr());
71 return;
72 }
73 uint64_t Value = static_cast<uint64_t>(MO.getImm());
74 assert(isUInt<N>(Value) && "Invalid uimm argument");
75 markup(OS&: O, M: Markup::Immediate) << Value;
76}
77
78template <unsigned N>
79void SystemZInstPrinterCommon::printSImmOperand(const MCInst *MI, int OpNum,
80 raw_ostream &O) {
81 const MCOperand &MO = MI->getOperand(i: OpNum);
82 if (MO.isExpr()) {
83 MAI.printExpr(O, *MO.getExpr());
84 return;
85 }
86 int64_t Value = MI->getOperand(i: OpNum).getImm();
87 assert(isInt<N>(Value) && "Invalid simm argument");
88 markup(OS&: O, M: Markup::Immediate) << Value;
89}
90
91void SystemZInstPrinterCommon::printU1ImmOperand(const MCInst *MI, int OpNum,
92 raw_ostream &O) {
93 printUImmOperand<1>(MI, OpNum, O);
94}
95
96void SystemZInstPrinterCommon::printU2ImmOperand(const MCInst *MI, int OpNum,
97 raw_ostream &O) {
98 printUImmOperand<2>(MI, OpNum, O);
99}
100
101void SystemZInstPrinterCommon::printU3ImmOperand(const MCInst *MI, int OpNum,
102 raw_ostream &O) {
103 printUImmOperand<3>(MI, OpNum, O);
104}
105
106void SystemZInstPrinterCommon::printU4ImmOperand(const MCInst *MI, int OpNum,
107 raw_ostream &O) {
108 printUImmOperand<4>(MI, OpNum, O);
109}
110
111void SystemZInstPrinterCommon::printS8ImmOperand(const MCInst *MI, int OpNum,
112 raw_ostream &O) {
113 printSImmOperand<8>(MI, OpNum, O);
114}
115
116void SystemZInstPrinterCommon::printU8ImmOperand(const MCInst *MI, int OpNum,
117 raw_ostream &O) {
118 printUImmOperand<8>(MI, OpNum, O);
119}
120
121void SystemZInstPrinterCommon::printX8ImmOperand(const MCInst *MI, int OpNum,
122 raw_ostream &O) {
123 int64_t Value = MI->getOperand(i: OpNum).getImm();
124 if (Value >= 0)
125 printUImmOperand<8>(MI, OpNum, O);
126 else
127 printSImmOperand<8>(MI, OpNum, O);
128}
129
130void SystemZInstPrinterCommon::printU12ImmOperand(const MCInst *MI, int OpNum,
131 raw_ostream &O) {
132 printUImmOperand<12>(MI, OpNum, O);
133}
134
135void SystemZInstPrinterCommon::printS16ImmOperand(const MCInst *MI, int OpNum,
136 raw_ostream &O) {
137 printSImmOperand<16>(MI, OpNum, O);
138}
139
140void SystemZInstPrinterCommon::printU16ImmOperand(const MCInst *MI, int OpNum,
141 raw_ostream &O) {
142 printUImmOperand<16>(MI, OpNum, O);
143}
144
145void SystemZInstPrinterCommon::printX16ImmOperand(const MCInst *MI, int OpNum,
146 raw_ostream &O) {
147 int64_t Value = MI->getOperand(i: OpNum).getImm();
148 if (Value >= 0)
149 printUImmOperand<16>(MI, OpNum, O);
150 else
151 printSImmOperand<16>(MI, OpNum, O);
152}
153
154void SystemZInstPrinterCommon::printS32ImmOperand(const MCInst *MI, int OpNum,
155 raw_ostream &O) {
156 printSImmOperand<32>(MI, OpNum, O);
157}
158
159void SystemZInstPrinterCommon::printU32ImmOperand(const MCInst *MI, int OpNum,
160 raw_ostream &O) {
161 printUImmOperand<32>(MI, OpNum, O);
162}
163
164void SystemZInstPrinterCommon::printX32ImmOperand(const MCInst *MI, int OpNum,
165 raw_ostream &O) {
166 int64_t Value = MI->getOperand(i: OpNum).getImm();
167 if (Value >= 0)
168 printUImmOperand<32>(MI, OpNum, O);
169 else
170 printSImmOperand<32>(MI, OpNum, O);
171}
172
173void SystemZInstPrinterCommon::printU48ImmOperand(const MCInst *MI, int OpNum,
174 raw_ostream &O) {
175 printUImmOperand<48>(MI, OpNum, O);
176}
177
178void SystemZInstPrinterCommon::printPCRelOperand(const MCInst *MI,
179 uint64_t Address, int OpNum,
180 raw_ostream &O) {
181 const MCOperand &MO = MI->getOperand(i: OpNum);
182
183 // If the label has already been resolved to an immediate offset (say, when
184 // we're running the disassembler), just print the immediate.
185 if (MO.isImm()) {
186 int64_t Offset = MO.getImm();
187 if (PrintBranchImmAsAddress)
188 markup(OS&: O, M: Markup::Target) << formatHex(Value: Address + Offset);
189 else
190 markup(OS&: O, M: Markup::Immediate) << formatImm(Value: Offset);
191 return;
192 }
193
194 // If the branch target is simply an address then print it in hex.
195 const MCConstantExpr *BranchTarget = dyn_cast<MCConstantExpr>(Val: MO.getExpr());
196 int64_t TargetAddress;
197 if (BranchTarget && BranchTarget->evaluateAsAbsolute(Res&: TargetAddress)) {
198 markup(OS&: O, M: Markup::Target) << formatHex(Value: (uint64_t)TargetAddress);
199 } else {
200 // Otherwise, just print the expression.
201 MAI.printExpr(O, *MO.getExpr());
202 }
203}
204
205void SystemZInstPrinterCommon::printPCRelTLSOperand(const MCInst *MI,
206 uint64_t Address, int OpNum,
207 raw_ostream &O) {
208 // Output the PC-relative operand.
209 printPCRelOperand(MI, Address, OpNum, O);
210
211 // Output the TLS marker if present.
212 if ((unsigned)OpNum + 1 < MI->getNumOperands()) {
213 const MCOperand &MO = MI->getOperand(i: OpNum + 1);
214 const MCSymbolRefExpr &RefExp = cast<MCSymbolRefExpr>(Val: *MO.getExpr());
215 switch (RefExp.getSpecifier()) {
216 case SystemZ::S_TLSGD:
217 O << ":tls_gdcall:";
218 break;
219 case SystemZ::S_TLSLDM:
220 O << ":tls_ldcall:";
221 break;
222 default:
223 llvm_unreachable("Unexpected symbol kind");
224 }
225 O << RefExp.getSymbol().getName();
226 }
227}
228
229void SystemZInstPrinterCommon::printOperand(const MCInst *MI, int OpNum,
230 raw_ostream &O) {
231 printOperand(MO: MI->getOperand(i: OpNum), MAI: &MAI, O);
232}
233
234void SystemZInstPrinterCommon::printBDAddrOperand(const MCInst *MI, int OpNum,
235 raw_ostream &O) {
236 printAddress(MAI: &MAI, Base: MI->getOperand(i: OpNum).getReg(), DispMO: MI->getOperand(i: OpNum + 1),
237 Index: 0, O);
238}
239
240void SystemZInstPrinterCommon::printBDXAddrOperand(const MCInst *MI, int OpNum,
241 raw_ostream &O) {
242 printAddress(MAI: &MAI, Base: MI->getOperand(i: OpNum).getReg(), DispMO: MI->getOperand(i: OpNum + 1),
243 Index: MI->getOperand(i: OpNum + 2).getReg(), O);
244}
245
246void SystemZInstPrinterCommon::printBDLAddrOperand(const MCInst *MI, int OpNum,
247 raw_ostream &O) {
248 MCRegister Base = MI->getOperand(i: OpNum).getReg();
249 const MCOperand &DispMO = MI->getOperand(i: OpNum + 1);
250 uint64_t Length = MI->getOperand(i: OpNum + 2).getImm();
251 printOperand(MO: DispMO, MAI: &MAI, O);
252 O << '(' << Length;
253 if (Base) {
254 O << ",";
255 printRegName(O, Reg: Base);
256 }
257 O << ')';
258}
259
260void SystemZInstPrinterCommon::printBDRAddrOperand(const MCInst *MI, int OpNum,
261 raw_ostream &O) {
262 MCRegister Base = MI->getOperand(i: OpNum).getReg();
263 const MCOperand &DispMO = MI->getOperand(i: OpNum + 1);
264 MCRegister Length = MI->getOperand(i: OpNum + 2).getReg();
265 printOperand(MO: DispMO, MAI: &MAI, O);
266 O << "(";
267 printRegName(O, Reg: Length);
268 if (Base) {
269 O << ",";
270 printRegName(O, Reg: Base);
271 }
272 O << ')';
273}
274
275void SystemZInstPrinterCommon::printBDVAddrOperand(const MCInst *MI, int OpNum,
276 raw_ostream &O) {
277 printAddress(MAI: &MAI, Base: MI->getOperand(i: OpNum).getReg(), DispMO: MI->getOperand(i: OpNum + 1),
278 Index: MI->getOperand(i: OpNum + 2).getReg(), O);
279}
280
281void SystemZInstPrinterCommon::printLXAAddrOperand(const MCInst *MI, int OpNum,
282 raw_ostream &O) {
283 printAddress(MAI: &MAI, Base: MI->getOperand(i: OpNum).getReg(), DispMO: MI->getOperand(i: OpNum + 1),
284 Index: MI->getOperand(i: OpNum + 2).getReg(), O);
285}
286
287void SystemZInstPrinterCommon::printCond4Operand(const MCInst *MI, int OpNum,
288 raw_ostream &O) {
289 static const char *const CondNames[] = {"o", "h", "nle", "l", "nhe",
290 "lh", "ne", "e", "nlh", "he",
291 "nl", "le", "nh", "no"};
292 uint64_t Imm = MI->getOperand(i: OpNum).getImm();
293 assert(Imm > 0 && Imm < 15 && "Invalid condition");
294 O << CondNames[Imm - 1];
295}
296