10b57cec5SDimitry Andric //===- SystemZInstPrinter.cpp - Convert SystemZ MCInst to assembly syntax -===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "SystemZInstPrinter.h"
100b57cec5SDimitry Andric #include "llvm/MC/MCExpr.h"
110b57cec5SDimitry Andric #include "llvm/MC/MCInst.h"
12bdd1243dSDimitry Andric #include "llvm/MC/MCRegister.h"
130b57cec5SDimitry Andric #include "llvm/MC/MCSymbol.h"
140b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
150b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
160b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h"
170b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
180b57cec5SDimitry Andric #include <cassert>
190b57cec5SDimitry Andric #include <cstdint>
200b57cec5SDimitry Andric
210b57cec5SDimitry Andric using namespace llvm;
220b57cec5SDimitry Andric
230b57cec5SDimitry Andric #define DEBUG_TYPE "asm-printer"
240b57cec5SDimitry Andric
250b57cec5SDimitry Andric #include "SystemZGenAsmWriter.inc"
260b57cec5SDimitry Andric
printAddress(const MCAsmInfo * MAI,MCRegister Base,const MCOperand & DispMO,MCRegister Index,raw_ostream & O)27bdd1243dSDimitry Andric void SystemZInstPrinter::printAddress(const MCAsmInfo *MAI, MCRegister Base,
28bdd1243dSDimitry Andric const MCOperand &DispMO, MCRegister Index,
29fe6060f1SDimitry Andric raw_ostream &O) {
30349cc55cSDimitry Andric printOperand(DispMO, MAI, O);
310b57cec5SDimitry Andric if (Base || Index) {
320b57cec5SDimitry Andric O << '(';
330b57cec5SDimitry Andric if (Index) {
34fe6060f1SDimitry Andric printFormattedRegName(MAI, Index, O);
350b57cec5SDimitry Andric O << ',';
360b57cec5SDimitry Andric }
370b57cec5SDimitry Andric if (Base)
38fe6060f1SDimitry Andric printFormattedRegName(MAI, Base, O);
39*5f757f3fSDimitry Andric else
40*5f757f3fSDimitry Andric O << '0';
410b57cec5SDimitry Andric O << ')';
420b57cec5SDimitry Andric }
430b57cec5SDimitry Andric }
440b57cec5SDimitry Andric
printOperand(const MCOperand & MO,const MCAsmInfo * MAI,raw_ostream & O)450b57cec5SDimitry Andric void SystemZInstPrinter::printOperand(const MCOperand &MO, const MCAsmInfo *MAI,
460b57cec5SDimitry Andric raw_ostream &O) {
47480093f4SDimitry Andric if (MO.isReg()) {
48480093f4SDimitry Andric if (!MO.getReg())
49480093f4SDimitry Andric O << '0';
50480093f4SDimitry Andric else
51fe6060f1SDimitry Andric printFormattedRegName(MAI, MO.getReg(), O);
52480093f4SDimitry Andric }
530b57cec5SDimitry Andric else if (MO.isImm())
54*5f757f3fSDimitry Andric markup(O, Markup::Immediate) << MO.getImm();
550b57cec5SDimitry Andric else if (MO.isExpr())
560b57cec5SDimitry Andric MO.getExpr()->print(O, MAI);
570b57cec5SDimitry Andric else
580b57cec5SDimitry Andric llvm_unreachable("Invalid operand");
590b57cec5SDimitry Andric }
600b57cec5SDimitry Andric
printFormattedRegName(const MCAsmInfo * MAI,MCRegister Reg,raw_ostream & O) const61fe6060f1SDimitry Andric void SystemZInstPrinter::printFormattedRegName(const MCAsmInfo *MAI,
62bdd1243dSDimitry Andric MCRegister Reg,
63bdd1243dSDimitry Andric raw_ostream &O) const {
64bdd1243dSDimitry Andric const char *RegName = getRegisterName(Reg);
65fe6060f1SDimitry Andric if (MAI->getAssemblerDialect() == AD_HLASM) {
66fe6060f1SDimitry Andric // Skip register prefix so that only register number is left
67fe6060f1SDimitry Andric assert(isalpha(RegName[0]) && isdigit(RegName[1]));
68*5f757f3fSDimitry Andric markup(O, Markup::Register) << (RegName + 1);
69fe6060f1SDimitry Andric } else
70*5f757f3fSDimitry Andric markup(O, Markup::Register) << '%' << RegName;
71bdd1243dSDimitry Andric }
72bdd1243dSDimitry Andric
printRegName(raw_ostream & O,MCRegister Reg) const73bdd1243dSDimitry Andric void SystemZInstPrinter::printRegName(raw_ostream &O, MCRegister Reg) const {
74bdd1243dSDimitry Andric printFormattedRegName(&MAI, Reg, O);
75fe6060f1SDimitry Andric }
76fe6060f1SDimitry Andric
printInst(const MCInst * MI,uint64_t Address,StringRef Annot,const MCSubtargetInfo & STI,raw_ostream & O)77480093f4SDimitry Andric void SystemZInstPrinter::printInst(const MCInst *MI, uint64_t Address,
78480093f4SDimitry Andric StringRef Annot, const MCSubtargetInfo &STI,
79480093f4SDimitry Andric raw_ostream &O) {
80480093f4SDimitry Andric printInstruction(MI, Address, O);
810b57cec5SDimitry Andric printAnnotation(O, Annot);
820b57cec5SDimitry Andric }
830b57cec5SDimitry Andric
840b57cec5SDimitry Andric template <unsigned N>
printUImmOperand(const MCInst * MI,int OpNum,raw_ostream & O)85bdd1243dSDimitry Andric void SystemZInstPrinter::printUImmOperand(const MCInst *MI, int OpNum,
86bdd1243dSDimitry Andric raw_ostream &O) {
8706c3fb27SDimitry Andric const MCOperand &MO = MI->getOperand(OpNum);
8806c3fb27SDimitry Andric if (MO.isExpr()) {
8906c3fb27SDimitry Andric O << *MO.getExpr();
9006c3fb27SDimitry Andric return;
9106c3fb27SDimitry Andric }
9206c3fb27SDimitry Andric uint64_t Value = static_cast<uint64_t>(MO.getImm());
930b57cec5SDimitry Andric assert(isUInt<N>(Value) && "Invalid uimm argument");
94*5f757f3fSDimitry Andric markup(O, Markup::Immediate) << Value;
950b57cec5SDimitry Andric }
960b57cec5SDimitry Andric
970b57cec5SDimitry Andric template <unsigned N>
printSImmOperand(const MCInst * MI,int OpNum,raw_ostream & O)98bdd1243dSDimitry Andric void SystemZInstPrinter::printSImmOperand(const MCInst *MI, int OpNum,
99bdd1243dSDimitry Andric raw_ostream &O) {
10006c3fb27SDimitry Andric const MCOperand &MO = MI->getOperand(OpNum);
10106c3fb27SDimitry Andric if (MO.isExpr()) {
10206c3fb27SDimitry Andric O << *MO.getExpr();
10306c3fb27SDimitry Andric return;
10406c3fb27SDimitry Andric }
1050b57cec5SDimitry Andric int64_t Value = MI->getOperand(OpNum).getImm();
1060b57cec5SDimitry Andric assert(isInt<N>(Value) && "Invalid simm argument");
107*5f757f3fSDimitry Andric markup(O, Markup::Immediate) << Value;
1080b57cec5SDimitry Andric }
1090b57cec5SDimitry Andric
printU1ImmOperand(const MCInst * MI,int OpNum,raw_ostream & O)1100b57cec5SDimitry Andric void SystemZInstPrinter::printU1ImmOperand(const MCInst *MI, int OpNum,
1110b57cec5SDimitry Andric raw_ostream &O) {
1120b57cec5SDimitry Andric printUImmOperand<1>(MI, OpNum, O);
1130b57cec5SDimitry Andric }
1140b57cec5SDimitry Andric
printU2ImmOperand(const MCInst * MI,int OpNum,raw_ostream & O)1150b57cec5SDimitry Andric void SystemZInstPrinter::printU2ImmOperand(const MCInst *MI, int OpNum,
1160b57cec5SDimitry Andric raw_ostream &O) {
1170b57cec5SDimitry Andric printUImmOperand<2>(MI, OpNum, O);
1180b57cec5SDimitry Andric }
1190b57cec5SDimitry Andric
printU3ImmOperand(const MCInst * MI,int OpNum,raw_ostream & O)1200b57cec5SDimitry Andric void SystemZInstPrinter::printU3ImmOperand(const MCInst *MI, int OpNum,
1210b57cec5SDimitry Andric raw_ostream &O) {
1220b57cec5SDimitry Andric printUImmOperand<3>(MI, OpNum, O);
1230b57cec5SDimitry Andric }
1240b57cec5SDimitry Andric
printU4ImmOperand(const MCInst * MI,int OpNum,raw_ostream & O)1250b57cec5SDimitry Andric void SystemZInstPrinter::printU4ImmOperand(const MCInst *MI, int OpNum,
1260b57cec5SDimitry Andric raw_ostream &O) {
1270b57cec5SDimitry Andric printUImmOperand<4>(MI, OpNum, O);
1280b57cec5SDimitry Andric }
1290b57cec5SDimitry Andric
printS8ImmOperand(const MCInst * MI,int OpNum,raw_ostream & O)1300b57cec5SDimitry Andric void SystemZInstPrinter::printS8ImmOperand(const MCInst *MI, int OpNum,
1310b57cec5SDimitry Andric raw_ostream &O) {
1320b57cec5SDimitry Andric printSImmOperand<8>(MI, OpNum, O);
1330b57cec5SDimitry Andric }
1340b57cec5SDimitry Andric
printU8ImmOperand(const MCInst * MI,int OpNum,raw_ostream & O)1350b57cec5SDimitry Andric void SystemZInstPrinter::printU8ImmOperand(const MCInst *MI, int OpNum,
1360b57cec5SDimitry Andric raw_ostream &O) {
1370b57cec5SDimitry Andric printUImmOperand<8>(MI, OpNum, O);
1380b57cec5SDimitry Andric }
1390b57cec5SDimitry Andric
printU12ImmOperand(const MCInst * MI,int OpNum,raw_ostream & O)1400b57cec5SDimitry Andric void SystemZInstPrinter::printU12ImmOperand(const MCInst *MI, int OpNum,
1410b57cec5SDimitry Andric raw_ostream &O) {
1420b57cec5SDimitry Andric printUImmOperand<12>(MI, OpNum, O);
1430b57cec5SDimitry Andric }
1440b57cec5SDimitry Andric
printS16ImmOperand(const MCInst * MI,int OpNum,raw_ostream & O)1450b57cec5SDimitry Andric void SystemZInstPrinter::printS16ImmOperand(const MCInst *MI, int OpNum,
1460b57cec5SDimitry Andric raw_ostream &O) {
1470b57cec5SDimitry Andric printSImmOperand<16>(MI, OpNum, O);
1480b57cec5SDimitry Andric }
1490b57cec5SDimitry Andric
printU16ImmOperand(const MCInst * MI,int OpNum,raw_ostream & O)1500b57cec5SDimitry Andric void SystemZInstPrinter::printU16ImmOperand(const MCInst *MI, int OpNum,
1510b57cec5SDimitry Andric raw_ostream &O) {
1520b57cec5SDimitry Andric printUImmOperand<16>(MI, OpNum, O);
1530b57cec5SDimitry Andric }
1540b57cec5SDimitry Andric
printS32ImmOperand(const MCInst * MI,int OpNum,raw_ostream & O)1550b57cec5SDimitry Andric void SystemZInstPrinter::printS32ImmOperand(const MCInst *MI, int OpNum,
1560b57cec5SDimitry Andric raw_ostream &O) {
1570b57cec5SDimitry Andric printSImmOperand<32>(MI, OpNum, O);
1580b57cec5SDimitry Andric }
1590b57cec5SDimitry Andric
printU32ImmOperand(const MCInst * MI,int OpNum,raw_ostream & O)1600b57cec5SDimitry Andric void SystemZInstPrinter::printU32ImmOperand(const MCInst *MI, int OpNum,
1610b57cec5SDimitry Andric raw_ostream &O) {
1620b57cec5SDimitry Andric printUImmOperand<32>(MI, OpNum, O);
1630b57cec5SDimitry Andric }
1640b57cec5SDimitry Andric
printU48ImmOperand(const MCInst * MI,int OpNum,raw_ostream & O)1650b57cec5SDimitry Andric void SystemZInstPrinter::printU48ImmOperand(const MCInst *MI, int OpNum,
1660b57cec5SDimitry Andric raw_ostream &O) {
1670b57cec5SDimitry Andric printUImmOperand<48>(MI, OpNum, O);
1680b57cec5SDimitry Andric }
1690b57cec5SDimitry Andric
printPCRelOperand(const MCInst * MI,int OpNum,raw_ostream & O)1700b57cec5SDimitry Andric void SystemZInstPrinter::printPCRelOperand(const MCInst *MI, int OpNum,
1710b57cec5SDimitry Andric raw_ostream &O) {
1720b57cec5SDimitry Andric const MCOperand &MO = MI->getOperand(OpNum);
1730b57cec5SDimitry Andric if (MO.isImm()) {
174*5f757f3fSDimitry Andric WithMarkup M = markup(O, Markup::Immediate);
175*5f757f3fSDimitry Andric O << "0x";
1760b57cec5SDimitry Andric O.write_hex(MO.getImm());
1770b57cec5SDimitry Andric } else
1780b57cec5SDimitry Andric MO.getExpr()->print(O, &MAI);
1790b57cec5SDimitry Andric }
1800b57cec5SDimitry Andric
printPCRelTLSOperand(const MCInst * MI,uint64_t Address,int OpNum,raw_ostream & O)1815ffd83dbSDimitry Andric void SystemZInstPrinter::printPCRelTLSOperand(const MCInst *MI,
1825ffd83dbSDimitry Andric uint64_t Address, int OpNum,
1830b57cec5SDimitry Andric raw_ostream &O) {
1840b57cec5SDimitry Andric // Output the PC-relative operand.
1850b57cec5SDimitry Andric printPCRelOperand(MI, OpNum, O);
1860b57cec5SDimitry Andric
1870b57cec5SDimitry Andric // Output the TLS marker if present.
1880b57cec5SDimitry Andric if ((unsigned)OpNum + 1 < MI->getNumOperands()) {
1890b57cec5SDimitry Andric const MCOperand &MO = MI->getOperand(OpNum + 1);
1900b57cec5SDimitry Andric const MCSymbolRefExpr &refExp = cast<MCSymbolRefExpr>(*MO.getExpr());
1910b57cec5SDimitry Andric switch (refExp.getKind()) {
1920b57cec5SDimitry Andric case MCSymbolRefExpr::VK_TLSGD:
1930b57cec5SDimitry Andric O << ":tls_gdcall:";
1940b57cec5SDimitry Andric break;
1950b57cec5SDimitry Andric case MCSymbolRefExpr::VK_TLSLDM:
1960b57cec5SDimitry Andric O << ":tls_ldcall:";
1970b57cec5SDimitry Andric break;
1980b57cec5SDimitry Andric default:
1990b57cec5SDimitry Andric llvm_unreachable("Unexpected symbol kind");
2000b57cec5SDimitry Andric }
2010b57cec5SDimitry Andric O << refExp.getSymbol().getName();
2020b57cec5SDimitry Andric }
2030b57cec5SDimitry Andric }
2040b57cec5SDimitry Andric
printOperand(const MCInst * MI,int OpNum,raw_ostream & O)2050b57cec5SDimitry Andric void SystemZInstPrinter::printOperand(const MCInst *MI, int OpNum,
2060b57cec5SDimitry Andric raw_ostream &O) {
2070b57cec5SDimitry Andric printOperand(MI->getOperand(OpNum), &MAI, O);
2080b57cec5SDimitry Andric }
2090b57cec5SDimitry Andric
printBDAddrOperand(const MCInst * MI,int OpNum,raw_ostream & O)2100b57cec5SDimitry Andric void SystemZInstPrinter::printBDAddrOperand(const MCInst *MI, int OpNum,
2110b57cec5SDimitry Andric raw_ostream &O) {
212349cc55cSDimitry Andric printAddress(&MAI, MI->getOperand(OpNum).getReg(), MI->getOperand(OpNum + 1),
213349cc55cSDimitry Andric 0, O);
2140b57cec5SDimitry Andric }
2150b57cec5SDimitry Andric
printBDXAddrOperand(const MCInst * MI,int OpNum,raw_ostream & O)2160b57cec5SDimitry Andric void SystemZInstPrinter::printBDXAddrOperand(const MCInst *MI, int OpNum,
2170b57cec5SDimitry Andric raw_ostream &O) {
218349cc55cSDimitry Andric printAddress(&MAI, MI->getOperand(OpNum).getReg(), MI->getOperand(OpNum + 1),
2190b57cec5SDimitry Andric MI->getOperand(OpNum + 2).getReg(), O);
2200b57cec5SDimitry Andric }
2210b57cec5SDimitry Andric
printBDLAddrOperand(const MCInst * MI,int OpNum,raw_ostream & O)2220b57cec5SDimitry Andric void SystemZInstPrinter::printBDLAddrOperand(const MCInst *MI, int OpNum,
2230b57cec5SDimitry Andric raw_ostream &O) {
2240b57cec5SDimitry Andric unsigned Base = MI->getOperand(OpNum).getReg();
225349cc55cSDimitry Andric const MCOperand &DispMO = MI->getOperand(OpNum + 1);
2260b57cec5SDimitry Andric uint64_t Length = MI->getOperand(OpNum + 2).getImm();
227349cc55cSDimitry Andric printOperand(DispMO, &MAI, O);
228349cc55cSDimitry Andric O << '(' << Length;
229fe6060f1SDimitry Andric if (Base) {
230fe6060f1SDimitry Andric O << ",";
231fe6060f1SDimitry Andric printRegName(O, Base);
232fe6060f1SDimitry Andric }
2330b57cec5SDimitry Andric O << ')';
2340b57cec5SDimitry Andric }
2350b57cec5SDimitry Andric
printBDRAddrOperand(const MCInst * MI,int OpNum,raw_ostream & O)2360b57cec5SDimitry Andric void SystemZInstPrinter::printBDRAddrOperand(const MCInst *MI, int OpNum,
2370b57cec5SDimitry Andric raw_ostream &O) {
2380b57cec5SDimitry Andric unsigned Base = MI->getOperand(OpNum).getReg();
239349cc55cSDimitry Andric const MCOperand &DispMO = MI->getOperand(OpNum + 1);
2400b57cec5SDimitry Andric unsigned Length = MI->getOperand(OpNum + 2).getReg();
241349cc55cSDimitry Andric printOperand(DispMO, &MAI, O);
242349cc55cSDimitry Andric O << "(";
243fe6060f1SDimitry Andric printRegName(O, Length);
244fe6060f1SDimitry Andric if (Base) {
245fe6060f1SDimitry Andric O << ",";
246fe6060f1SDimitry Andric printRegName(O, Base);
247fe6060f1SDimitry Andric }
2480b57cec5SDimitry Andric O << ')';
2490b57cec5SDimitry Andric }
2500b57cec5SDimitry Andric
printBDVAddrOperand(const MCInst * MI,int OpNum,raw_ostream & O)2510b57cec5SDimitry Andric void SystemZInstPrinter::printBDVAddrOperand(const MCInst *MI, int OpNum,
2520b57cec5SDimitry Andric raw_ostream &O) {
253349cc55cSDimitry Andric printAddress(&MAI, MI->getOperand(OpNum).getReg(), MI->getOperand(OpNum + 1),
2540b57cec5SDimitry Andric MI->getOperand(OpNum + 2).getReg(), O);
2550b57cec5SDimitry Andric }
2560b57cec5SDimitry Andric
printCond4Operand(const MCInst * MI,int OpNum,raw_ostream & O)2570b57cec5SDimitry Andric void SystemZInstPrinter::printCond4Operand(const MCInst *MI, int OpNum,
2580b57cec5SDimitry Andric raw_ostream &O) {
2590b57cec5SDimitry Andric static const char *const CondNames[] = {
2600b57cec5SDimitry Andric "o", "h", "nle", "l", "nhe", "lh", "ne",
2610b57cec5SDimitry Andric "e", "nlh", "he", "nl", "le", "nh", "no"
2620b57cec5SDimitry Andric };
2630b57cec5SDimitry Andric uint64_t Imm = MI->getOperand(OpNum).getImm();
2640b57cec5SDimitry Andric assert(Imm > 0 && Imm < 15 && "Invalid condition");
2650b57cec5SDimitry Andric O << CondNames[Imm - 1];
2660b57cec5SDimitry Andric }
267