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"
120b57cec5SDimitry Andric #include "llvm/MC/MCSymbol.h"
130b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
140b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
150b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h"
160b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
170b57cec5SDimitry Andric #include <cassert>
180b57cec5SDimitry Andric #include <cstdint>
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric using namespace llvm;
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric #define DEBUG_TYPE "asm-printer"
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric #include "SystemZGenAsmWriter.inc"
250b57cec5SDimitry Andric 
printAddress(const MCAsmInfo * MAI,unsigned Base,int64_t Disp,unsigned Index,raw_ostream & O)26*5f7ddb14SDimitry Andric void SystemZInstPrinter::printAddress(const MCAsmInfo *MAI, unsigned Base,
27*5f7ddb14SDimitry Andric                                       int64_t Disp, unsigned Index,
28*5f7ddb14SDimitry Andric                                       raw_ostream &O) {
290b57cec5SDimitry Andric   O << Disp;
300b57cec5SDimitry Andric   if (Base || Index) {
310b57cec5SDimitry Andric     O << '(';
320b57cec5SDimitry Andric     if (Index) {
33*5f7ddb14SDimitry Andric       printFormattedRegName(MAI, Index, O);
340b57cec5SDimitry Andric       if (Base)
350b57cec5SDimitry Andric         O << ',';
360b57cec5SDimitry Andric     }
370b57cec5SDimitry Andric     if (Base)
38*5f7ddb14SDimitry Andric       printFormattedRegName(MAI, Base, O);
390b57cec5SDimitry Andric     O << ')';
400b57cec5SDimitry Andric   }
410b57cec5SDimitry Andric }
420b57cec5SDimitry Andric 
printOperand(const MCOperand & MO,const MCAsmInfo * MAI,raw_ostream & O)430b57cec5SDimitry Andric void SystemZInstPrinter::printOperand(const MCOperand &MO, const MCAsmInfo *MAI,
440b57cec5SDimitry Andric                                       raw_ostream &O) {
45480093f4SDimitry Andric   if (MO.isReg()) {
46480093f4SDimitry Andric     if (!MO.getReg())
47480093f4SDimitry Andric       O << '0';
48480093f4SDimitry Andric     else
49*5f7ddb14SDimitry Andric       printFormattedRegName(MAI, MO.getReg(), O);
50480093f4SDimitry Andric   }
510b57cec5SDimitry Andric   else if (MO.isImm())
520b57cec5SDimitry Andric     O << MO.getImm();
530b57cec5SDimitry Andric   else if (MO.isExpr())
540b57cec5SDimitry Andric     MO.getExpr()->print(O, MAI);
550b57cec5SDimitry Andric   else
560b57cec5SDimitry Andric     llvm_unreachable("Invalid operand");
570b57cec5SDimitry Andric }
580b57cec5SDimitry Andric 
printFormattedRegName(const MCAsmInfo * MAI,unsigned RegNo,raw_ostream & O)59*5f7ddb14SDimitry Andric void SystemZInstPrinter::printFormattedRegName(const MCAsmInfo *MAI,
60*5f7ddb14SDimitry Andric                                                unsigned RegNo, raw_ostream &O) {
61*5f7ddb14SDimitry Andric   const char *RegName = getRegisterName(RegNo);
62*5f7ddb14SDimitry Andric   if (MAI->getAssemblerDialect() == AD_HLASM) {
63*5f7ddb14SDimitry Andric     // Skip register prefix so that only register number is left
64*5f7ddb14SDimitry Andric     assert(isalpha(RegName[0]) && isdigit(RegName[1]));
65*5f7ddb14SDimitry Andric     O << (RegName + 1);
66*5f7ddb14SDimitry Andric   } else
67*5f7ddb14SDimitry Andric     O << '%' << RegName;
68*5f7ddb14SDimitry Andric }
69*5f7ddb14SDimitry Andric 
printInst(const MCInst * MI,uint64_t Address,StringRef Annot,const MCSubtargetInfo & STI,raw_ostream & O)70480093f4SDimitry Andric void SystemZInstPrinter::printInst(const MCInst *MI, uint64_t Address,
71480093f4SDimitry Andric                                    StringRef Annot, const MCSubtargetInfo &STI,
72480093f4SDimitry Andric                                    raw_ostream &O) {
73480093f4SDimitry Andric   printInstruction(MI, Address, O);
740b57cec5SDimitry Andric   printAnnotation(O, Annot);
750b57cec5SDimitry Andric }
760b57cec5SDimitry Andric 
770b57cec5SDimitry Andric template <unsigned N>
printUImmOperand(const MCInst * MI,int OpNum,raw_ostream & O)780b57cec5SDimitry Andric static void printUImmOperand(const MCInst *MI, int OpNum, raw_ostream &O) {
790b57cec5SDimitry Andric   int64_t Value = MI->getOperand(OpNum).getImm();
800b57cec5SDimitry Andric   assert(isUInt<N>(Value) && "Invalid uimm argument");
810b57cec5SDimitry Andric   O << Value;
820b57cec5SDimitry Andric }
830b57cec5SDimitry Andric 
840b57cec5SDimitry Andric template <unsigned N>
printSImmOperand(const MCInst * MI,int OpNum,raw_ostream & O)850b57cec5SDimitry Andric static void printSImmOperand(const MCInst *MI, int OpNum, raw_ostream &O) {
860b57cec5SDimitry Andric   int64_t Value = MI->getOperand(OpNum).getImm();
870b57cec5SDimitry Andric   assert(isInt<N>(Value) && "Invalid simm argument");
880b57cec5SDimitry Andric   O << Value;
890b57cec5SDimitry Andric }
900b57cec5SDimitry Andric 
printU1ImmOperand(const MCInst * MI,int OpNum,raw_ostream & O)910b57cec5SDimitry Andric void SystemZInstPrinter::printU1ImmOperand(const MCInst *MI, int OpNum,
920b57cec5SDimitry Andric                                            raw_ostream &O) {
930b57cec5SDimitry Andric   printUImmOperand<1>(MI, OpNum, O);
940b57cec5SDimitry Andric }
950b57cec5SDimitry Andric 
printU2ImmOperand(const MCInst * MI,int OpNum,raw_ostream & O)960b57cec5SDimitry Andric void SystemZInstPrinter::printU2ImmOperand(const MCInst *MI, int OpNum,
970b57cec5SDimitry Andric                                            raw_ostream &O) {
980b57cec5SDimitry Andric   printUImmOperand<2>(MI, OpNum, O);
990b57cec5SDimitry Andric }
1000b57cec5SDimitry Andric 
printU3ImmOperand(const MCInst * MI,int OpNum,raw_ostream & O)1010b57cec5SDimitry Andric void SystemZInstPrinter::printU3ImmOperand(const MCInst *MI, int OpNum,
1020b57cec5SDimitry Andric                                            raw_ostream &O) {
1030b57cec5SDimitry Andric   printUImmOperand<3>(MI, OpNum, O);
1040b57cec5SDimitry Andric }
1050b57cec5SDimitry Andric 
printU4ImmOperand(const MCInst * MI,int OpNum,raw_ostream & O)1060b57cec5SDimitry Andric void SystemZInstPrinter::printU4ImmOperand(const MCInst *MI, int OpNum,
1070b57cec5SDimitry Andric                                            raw_ostream &O) {
1080b57cec5SDimitry Andric   printUImmOperand<4>(MI, OpNum, O);
1090b57cec5SDimitry Andric }
1100b57cec5SDimitry Andric 
printU6ImmOperand(const MCInst * MI,int OpNum,raw_ostream & O)1110b57cec5SDimitry Andric void SystemZInstPrinter::printU6ImmOperand(const MCInst *MI, int OpNum,
1120b57cec5SDimitry Andric                                            raw_ostream &O) {
1130b57cec5SDimitry Andric   printUImmOperand<6>(MI, OpNum, O);
1140b57cec5SDimitry Andric }
1150b57cec5SDimitry Andric 
printS8ImmOperand(const MCInst * MI,int OpNum,raw_ostream & O)1160b57cec5SDimitry Andric void SystemZInstPrinter::printS8ImmOperand(const MCInst *MI, int OpNum,
1170b57cec5SDimitry Andric                                            raw_ostream &O) {
1180b57cec5SDimitry Andric   printSImmOperand<8>(MI, OpNum, O);
1190b57cec5SDimitry Andric }
1200b57cec5SDimitry Andric 
printU8ImmOperand(const MCInst * MI,int OpNum,raw_ostream & O)1210b57cec5SDimitry Andric void SystemZInstPrinter::printU8ImmOperand(const MCInst *MI, int OpNum,
1220b57cec5SDimitry Andric                                            raw_ostream &O) {
1230b57cec5SDimitry Andric   printUImmOperand<8>(MI, OpNum, O);
1240b57cec5SDimitry Andric }
1250b57cec5SDimitry Andric 
printU12ImmOperand(const MCInst * MI,int OpNum,raw_ostream & O)1260b57cec5SDimitry Andric void SystemZInstPrinter::printU12ImmOperand(const MCInst *MI, int OpNum,
1270b57cec5SDimitry Andric                                             raw_ostream &O) {
1280b57cec5SDimitry Andric   printUImmOperand<12>(MI, OpNum, O);
1290b57cec5SDimitry Andric }
1300b57cec5SDimitry Andric 
printS16ImmOperand(const MCInst * MI,int OpNum,raw_ostream & O)1310b57cec5SDimitry Andric void SystemZInstPrinter::printS16ImmOperand(const MCInst *MI, int OpNum,
1320b57cec5SDimitry Andric                                             raw_ostream &O) {
1330b57cec5SDimitry Andric   printSImmOperand<16>(MI, OpNum, O);
1340b57cec5SDimitry Andric }
1350b57cec5SDimitry Andric 
printU16ImmOperand(const MCInst * MI,int OpNum,raw_ostream & O)1360b57cec5SDimitry Andric void SystemZInstPrinter::printU16ImmOperand(const MCInst *MI, int OpNum,
1370b57cec5SDimitry Andric                                             raw_ostream &O) {
1380b57cec5SDimitry Andric   printUImmOperand<16>(MI, OpNum, O);
1390b57cec5SDimitry Andric }
1400b57cec5SDimitry Andric 
printS32ImmOperand(const MCInst * MI,int OpNum,raw_ostream & O)1410b57cec5SDimitry Andric void SystemZInstPrinter::printS32ImmOperand(const MCInst *MI, int OpNum,
1420b57cec5SDimitry Andric                                             raw_ostream &O) {
1430b57cec5SDimitry Andric   printSImmOperand<32>(MI, OpNum, O);
1440b57cec5SDimitry Andric }
1450b57cec5SDimitry Andric 
printU32ImmOperand(const MCInst * MI,int OpNum,raw_ostream & O)1460b57cec5SDimitry Andric void SystemZInstPrinter::printU32ImmOperand(const MCInst *MI, int OpNum,
1470b57cec5SDimitry Andric                                             raw_ostream &O) {
1480b57cec5SDimitry Andric   printUImmOperand<32>(MI, OpNum, O);
1490b57cec5SDimitry Andric }
1500b57cec5SDimitry Andric 
printU48ImmOperand(const MCInst * MI,int OpNum,raw_ostream & O)1510b57cec5SDimitry Andric void SystemZInstPrinter::printU48ImmOperand(const MCInst *MI, int OpNum,
1520b57cec5SDimitry Andric                                             raw_ostream &O) {
1530b57cec5SDimitry Andric   printUImmOperand<48>(MI, OpNum, O);
1540b57cec5SDimitry Andric }
1550b57cec5SDimitry Andric 
printPCRelOperand(const MCInst * MI,int OpNum,raw_ostream & O)1560b57cec5SDimitry Andric void SystemZInstPrinter::printPCRelOperand(const MCInst *MI, int OpNum,
1570b57cec5SDimitry Andric                                            raw_ostream &O) {
1580b57cec5SDimitry Andric   const MCOperand &MO = MI->getOperand(OpNum);
1590b57cec5SDimitry Andric   if (MO.isImm()) {
1600b57cec5SDimitry Andric     O << "0x";
1610b57cec5SDimitry Andric     O.write_hex(MO.getImm());
1620b57cec5SDimitry Andric   } else
1630b57cec5SDimitry Andric     MO.getExpr()->print(O, &MAI);
1640b57cec5SDimitry Andric }
1650b57cec5SDimitry Andric 
printPCRelTLSOperand(const MCInst * MI,uint64_t Address,int OpNum,raw_ostream & O)1665ffd83dbSDimitry Andric void SystemZInstPrinter::printPCRelTLSOperand(const MCInst *MI,
1675ffd83dbSDimitry Andric                                               uint64_t Address, int OpNum,
1680b57cec5SDimitry Andric                                               raw_ostream &O) {
1690b57cec5SDimitry Andric   // Output the PC-relative operand.
1700b57cec5SDimitry Andric   printPCRelOperand(MI, OpNum, O);
1710b57cec5SDimitry Andric 
1720b57cec5SDimitry Andric   // Output the TLS marker if present.
1730b57cec5SDimitry Andric   if ((unsigned)OpNum + 1 < MI->getNumOperands()) {
1740b57cec5SDimitry Andric     const MCOperand &MO = MI->getOperand(OpNum + 1);
1750b57cec5SDimitry Andric     const MCSymbolRefExpr &refExp = cast<MCSymbolRefExpr>(*MO.getExpr());
1760b57cec5SDimitry Andric     switch (refExp.getKind()) {
1770b57cec5SDimitry Andric       case MCSymbolRefExpr::VK_TLSGD:
1780b57cec5SDimitry Andric         O << ":tls_gdcall:";
1790b57cec5SDimitry Andric         break;
1800b57cec5SDimitry Andric       case MCSymbolRefExpr::VK_TLSLDM:
1810b57cec5SDimitry Andric         O << ":tls_ldcall:";
1820b57cec5SDimitry Andric         break;
1830b57cec5SDimitry Andric       default:
1840b57cec5SDimitry Andric         llvm_unreachable("Unexpected symbol kind");
1850b57cec5SDimitry Andric     }
1860b57cec5SDimitry Andric     O << refExp.getSymbol().getName();
1870b57cec5SDimitry Andric   }
1880b57cec5SDimitry Andric }
1890b57cec5SDimitry Andric 
printOperand(const MCInst * MI,int OpNum,raw_ostream & O)1900b57cec5SDimitry Andric void SystemZInstPrinter::printOperand(const MCInst *MI, int OpNum,
1910b57cec5SDimitry Andric                                       raw_ostream &O) {
1920b57cec5SDimitry Andric   printOperand(MI->getOperand(OpNum), &MAI, O);
1930b57cec5SDimitry Andric }
1940b57cec5SDimitry Andric 
printBDAddrOperand(const MCInst * MI,int OpNum,raw_ostream & O)1950b57cec5SDimitry Andric void SystemZInstPrinter::printBDAddrOperand(const MCInst *MI, int OpNum,
1960b57cec5SDimitry Andric                                             raw_ostream &O) {
197*5f7ddb14SDimitry Andric   printAddress(&MAI, MI->getOperand(OpNum).getReg(),
1980b57cec5SDimitry Andric                MI->getOperand(OpNum + 1).getImm(), 0, O);
1990b57cec5SDimitry Andric }
2000b57cec5SDimitry Andric 
printBDXAddrOperand(const MCInst * MI,int OpNum,raw_ostream & O)2010b57cec5SDimitry Andric void SystemZInstPrinter::printBDXAddrOperand(const MCInst *MI, int OpNum,
2020b57cec5SDimitry Andric                                              raw_ostream &O) {
203*5f7ddb14SDimitry Andric   printAddress(&MAI, MI->getOperand(OpNum).getReg(),
2040b57cec5SDimitry Andric                MI->getOperand(OpNum + 1).getImm(),
2050b57cec5SDimitry Andric                MI->getOperand(OpNum + 2).getReg(), O);
2060b57cec5SDimitry Andric }
2070b57cec5SDimitry Andric 
printBDLAddrOperand(const MCInst * MI,int OpNum,raw_ostream & O)2080b57cec5SDimitry Andric void SystemZInstPrinter::printBDLAddrOperand(const MCInst *MI, int OpNum,
2090b57cec5SDimitry Andric                                              raw_ostream &O) {
2100b57cec5SDimitry Andric   unsigned Base = MI->getOperand(OpNum).getReg();
2110b57cec5SDimitry Andric   uint64_t Disp = MI->getOperand(OpNum + 1).getImm();
2120b57cec5SDimitry Andric   uint64_t Length = MI->getOperand(OpNum + 2).getImm();
2130b57cec5SDimitry Andric   O << Disp << '(' << Length;
214*5f7ddb14SDimitry Andric   if (Base) {
215*5f7ddb14SDimitry Andric     O << ",";
216*5f7ddb14SDimitry Andric     printRegName(O, Base);
217*5f7ddb14SDimitry Andric   }
2180b57cec5SDimitry Andric   O << ')';
2190b57cec5SDimitry Andric }
2200b57cec5SDimitry Andric 
printBDRAddrOperand(const MCInst * MI,int OpNum,raw_ostream & O)2210b57cec5SDimitry Andric void SystemZInstPrinter::printBDRAddrOperand(const MCInst *MI, int OpNum,
2220b57cec5SDimitry Andric                                              raw_ostream &O) {
2230b57cec5SDimitry Andric   unsigned Base = MI->getOperand(OpNum).getReg();
2240b57cec5SDimitry Andric   uint64_t Disp = MI->getOperand(OpNum + 1).getImm();
2250b57cec5SDimitry Andric   unsigned Length = MI->getOperand(OpNum + 2).getReg();
226*5f7ddb14SDimitry Andric   O << Disp << "(";
227*5f7ddb14SDimitry Andric   printRegName(O, Length);
228*5f7ddb14SDimitry Andric   if (Base) {
229*5f7ddb14SDimitry Andric     O << ",";
230*5f7ddb14SDimitry Andric     printRegName(O, Base);
231*5f7ddb14SDimitry Andric   }
2320b57cec5SDimitry Andric   O << ')';
2330b57cec5SDimitry Andric }
2340b57cec5SDimitry Andric 
printBDVAddrOperand(const MCInst * MI,int OpNum,raw_ostream & O)2350b57cec5SDimitry Andric void SystemZInstPrinter::printBDVAddrOperand(const MCInst *MI, int OpNum,
2360b57cec5SDimitry Andric                                              raw_ostream &O) {
237*5f7ddb14SDimitry Andric   printAddress(&MAI, MI->getOperand(OpNum).getReg(),
2380b57cec5SDimitry Andric                MI->getOperand(OpNum + 1).getImm(),
2390b57cec5SDimitry Andric                MI->getOperand(OpNum + 2).getReg(), O);
2400b57cec5SDimitry Andric }
2410b57cec5SDimitry Andric 
printCond4Operand(const MCInst * MI,int OpNum,raw_ostream & O)2420b57cec5SDimitry Andric void SystemZInstPrinter::printCond4Operand(const MCInst *MI, int OpNum,
2430b57cec5SDimitry Andric                                            raw_ostream &O) {
2440b57cec5SDimitry Andric   static const char *const CondNames[] = {
2450b57cec5SDimitry Andric     "o", "h", "nle", "l", "nhe", "lh", "ne",
2460b57cec5SDimitry Andric     "e", "nlh", "he", "nl", "le", "nh", "no"
2470b57cec5SDimitry Andric   };
2480b57cec5SDimitry Andric   uint64_t Imm = MI->getOperand(OpNum).getImm();
2490b57cec5SDimitry Andric   assert(Imm > 0 && Imm < 15 && "Invalid condition");
2500b57cec5SDimitry Andric   O << CondNames[Imm - 1];
2510b57cec5SDimitry Andric }
252