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(DispMO, MAI, O);
31   if (Base || Index) {
32     O << '(';
33     if (Index) {
34       printFormattedRegName(MAI, Index, O);
35       O << ',';
36     }
37     if (Base)
38       printFormattedRegName(MAI, 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, MO.getReg(), O);
52   }
53   else if (MO.isImm())
54     markup(O, Markup::Immediate) << MO.getImm();
55   else if (MO.isExpr())
56     MO.getExpr()->print(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(O, Markup::Register) << (RegName + 1);
69   } else
70     markup(O, Markup::Register) << '%' << RegName;
71 }
72 
73 void SystemZInstPrinter::printRegName(raw_ostream &O, MCRegister Reg) const {
74   printFormattedRegName(&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(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(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(O, 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(OpNum);
101   if (MO.isExpr()) {
102     O << *MO.getExpr();
103     return;
104   }
105   int64_t Value = MI->getOperand(OpNum).getImm();
106   assert(isInt<N>(Value) && "Invalid simm argument");
107   markup(O, 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(OpNum);
173   if (MO.isImm()) {
174     WithMarkup M = markup(O, Markup::Immediate);
175     O << "0x";
176     O.write_hex(MO.getImm());
177   } else
178     MO.getExpr()->print(O, &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(OpNum + 1);
190     const MCSymbolRefExpr &refExp = cast<MCSymbolRefExpr>(*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(MI->getOperand(OpNum), &MAI, O);
208 }
209 
210 void SystemZInstPrinter::printBDAddrOperand(const MCInst *MI, int OpNum,
211                                             raw_ostream &O) {
212   printAddress(&MAI, MI->getOperand(OpNum).getReg(), MI->getOperand(OpNum + 1),
213                0, O);
214 }
215 
216 void SystemZInstPrinter::printBDXAddrOperand(const MCInst *MI, int OpNum,
217                                              raw_ostream &O) {
218   printAddress(&MAI, MI->getOperand(OpNum).getReg(), MI->getOperand(OpNum + 1),
219                MI->getOperand(OpNum + 2).getReg(), O);
220 }
221 
222 void SystemZInstPrinter::printBDLAddrOperand(const MCInst *MI, int OpNum,
223                                              raw_ostream &O) {
224   unsigned Base = MI->getOperand(OpNum).getReg();
225   const MCOperand &DispMO = MI->getOperand(OpNum + 1);
226   uint64_t Length = MI->getOperand(OpNum + 2).getImm();
227   printOperand(DispMO, &MAI, O);
228   O << '(' << Length;
229   if (Base) {
230     O << ",";
231     printRegName(O, Base);
232   }
233   O << ')';
234 }
235 
236 void SystemZInstPrinter::printBDRAddrOperand(const MCInst *MI, int OpNum,
237                                              raw_ostream &O) {
238   unsigned Base = MI->getOperand(OpNum).getReg();
239   const MCOperand &DispMO = MI->getOperand(OpNum + 1);
240   unsigned Length = MI->getOperand(OpNum + 2).getReg();
241   printOperand(DispMO, &MAI, O);
242   O << "(";
243   printRegName(O, Length);
244   if (Base) {
245     O << ",";
246     printRegName(O, Base);
247   }
248   O << ')';
249 }
250 
251 void SystemZInstPrinter::printBDVAddrOperand(const MCInst *MI, int OpNum,
252                                              raw_ostream &O) {
253   printAddress(&MAI, MI->getOperand(OpNum).getReg(), MI->getOperand(OpNum + 1),
254                MI->getOperand(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(OpNum).getImm();
264   assert(Imm > 0 && Imm < 15 && "Invalid condition");
265   O << CondNames[Imm - 1];
266 }
267