10b57cec5SDimitry Andric //===-- SparcInstPrinter.cpp - Convert Sparc 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 // This class prints an Sparc MCInst to a .s file. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "SparcInstPrinter.h" 140b57cec5SDimitry Andric #include "Sparc.h" 150b57cec5SDimitry Andric #include "llvm/MC/MCExpr.h" 160b57cec5SDimitry Andric #include "llvm/MC/MCInst.h" 170b57cec5SDimitry Andric #include "llvm/MC/MCRegisterInfo.h" 180b57cec5SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h" 190b57cec5SDimitry Andric #include "llvm/MC/MCSymbol.h" 200b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 210b57cec5SDimitry Andric using namespace llvm; 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric #define DEBUG_TYPE "asm-printer" 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric // The generated AsmMatcher SparcGenAsmWriter uses "Sparc" as the target 260b57cec5SDimitry Andric // namespace. But SPARC backend uses "SP" as its namespace. 270b57cec5SDimitry Andric namespace llvm { 280b57cec5SDimitry Andric namespace Sparc { 290b57cec5SDimitry Andric using namespace SP; 300b57cec5SDimitry Andric } 310b57cec5SDimitry Andric } 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric #define GET_INSTRUCTION_NAME 340b57cec5SDimitry Andric #define PRINT_ALIAS_INSTR 350b57cec5SDimitry Andric #include "SparcGenAsmWriter.inc" 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric bool SparcInstPrinter::isV9(const MCSubtargetInfo &STI) const { 3806c3fb27SDimitry Andric return (STI.hasFeature(Sparc::FeatureV9)) != 0; 390b57cec5SDimitry Andric } 400b57cec5SDimitry Andric 41bdd1243dSDimitry Andric void SparcInstPrinter::printRegName(raw_ostream &OS, MCRegister Reg) const { 425f757f3fSDimitry Andric OS << '%' << getRegisterName(Reg); 435f757f3fSDimitry Andric } 445f757f3fSDimitry Andric 455f757f3fSDimitry Andric void SparcInstPrinter::printRegName(raw_ostream &OS, MCRegister Reg, 465f757f3fSDimitry Andric unsigned AltIdx) const { 475f757f3fSDimitry Andric OS << '%' << getRegisterName(Reg, AltIdx); 480b57cec5SDimitry Andric } 490b57cec5SDimitry Andric 50480093f4SDimitry Andric void SparcInstPrinter::printInst(const MCInst *MI, uint64_t Address, 51480093f4SDimitry Andric StringRef Annot, const MCSubtargetInfo &STI, 52480093f4SDimitry Andric raw_ostream &O) { 535ffd83dbSDimitry Andric if (!printAliasInstr(MI, Address, STI, O) && 545ffd83dbSDimitry Andric !printSparcAliasInstr(MI, STI, O)) 55480093f4SDimitry Andric printInstruction(MI, Address, STI, O); 560b57cec5SDimitry Andric printAnnotation(O, Annot); 570b57cec5SDimitry Andric } 580b57cec5SDimitry Andric 590b57cec5SDimitry Andric bool SparcInstPrinter::printSparcAliasInstr(const MCInst *MI, 600b57cec5SDimitry Andric const MCSubtargetInfo &STI, 610b57cec5SDimitry Andric raw_ostream &O) { 620b57cec5SDimitry Andric switch (MI->getOpcode()) { 630b57cec5SDimitry Andric default: return false; 640b57cec5SDimitry Andric case SP::JMPLrr: 650b57cec5SDimitry Andric case SP::JMPLri: { 660b57cec5SDimitry Andric if (MI->getNumOperands() != 3) 670b57cec5SDimitry Andric return false; 680b57cec5SDimitry Andric if (!MI->getOperand(0).isReg()) 690b57cec5SDimitry Andric return false; 700b57cec5SDimitry Andric switch (MI->getOperand(0).getReg()) { 710b57cec5SDimitry Andric default: return false; 720b57cec5SDimitry Andric case SP::G0: // jmp $addr | ret | retl 730b57cec5SDimitry Andric if (MI->getOperand(2).isImm() && 740b57cec5SDimitry Andric MI->getOperand(2).getImm() == 8) { 750b57cec5SDimitry Andric switch(MI->getOperand(1).getReg()) { 760b57cec5SDimitry Andric default: break; 770b57cec5SDimitry Andric case SP::I7: O << "\tret"; return true; 780b57cec5SDimitry Andric case SP::O7: O << "\tretl"; return true; 790b57cec5SDimitry Andric } 800b57cec5SDimitry Andric } 810b57cec5SDimitry Andric O << "\tjmp "; printMemOperand(MI, 1, STI, O); 820b57cec5SDimitry Andric return true; 830b57cec5SDimitry Andric case SP::O7: // call $addr 840b57cec5SDimitry Andric O << "\tcall "; printMemOperand(MI, 1, STI, O); 850b57cec5SDimitry Andric return true; 860b57cec5SDimitry Andric } 870b57cec5SDimitry Andric } 880b57cec5SDimitry Andric case SP::V9FCMPS: case SP::V9FCMPD: case SP::V9FCMPQ: 890b57cec5SDimitry Andric case SP::V9FCMPES: case SP::V9FCMPED: case SP::V9FCMPEQ: { 900b57cec5SDimitry Andric if (isV9(STI) 910b57cec5SDimitry Andric || (MI->getNumOperands() != 3) 920b57cec5SDimitry Andric || (!MI->getOperand(0).isReg()) 930b57cec5SDimitry Andric || (MI->getOperand(0).getReg() != SP::FCC0)) 940b57cec5SDimitry Andric return false; 950b57cec5SDimitry Andric // if V8, skip printing %fcc0. 960b57cec5SDimitry Andric switch(MI->getOpcode()) { 970b57cec5SDimitry Andric default: 980b57cec5SDimitry Andric case SP::V9FCMPS: O << "\tfcmps "; break; 990b57cec5SDimitry Andric case SP::V9FCMPD: O << "\tfcmpd "; break; 1000b57cec5SDimitry Andric case SP::V9FCMPQ: O << "\tfcmpq "; break; 1010b57cec5SDimitry Andric case SP::V9FCMPES: O << "\tfcmpes "; break; 1020b57cec5SDimitry Andric case SP::V9FCMPED: O << "\tfcmped "; break; 1030b57cec5SDimitry Andric case SP::V9FCMPEQ: O << "\tfcmpeq "; break; 1040b57cec5SDimitry Andric } 1050b57cec5SDimitry Andric printOperand(MI, 1, STI, O); 1060b57cec5SDimitry Andric O << ", "; 1070b57cec5SDimitry Andric printOperand(MI, 2, STI, O); 1080b57cec5SDimitry Andric return true; 1090b57cec5SDimitry Andric } 1100b57cec5SDimitry Andric } 1110b57cec5SDimitry Andric } 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric void SparcInstPrinter::printOperand(const MCInst *MI, int opNum, 1140b57cec5SDimitry Andric const MCSubtargetInfo &STI, 1150b57cec5SDimitry Andric raw_ostream &O) { 1160b57cec5SDimitry Andric const MCOperand &MO = MI->getOperand (opNum); 1170b57cec5SDimitry Andric 1180b57cec5SDimitry Andric if (MO.isReg()) { 1195f757f3fSDimitry Andric unsigned Reg = MO.getReg(); 1205f757f3fSDimitry Andric if (isV9(STI)) 1215f757f3fSDimitry Andric printRegName(O, Reg, SP::RegNamesStateReg); 1225f757f3fSDimitry Andric else 1235f757f3fSDimitry Andric printRegName(O, Reg); 1240b57cec5SDimitry Andric return ; 1250b57cec5SDimitry Andric } 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric if (MO.isImm()) { 1280b57cec5SDimitry Andric switch (MI->getOpcode()) { 1290b57cec5SDimitry Andric default: 1300b57cec5SDimitry Andric O << (int)MO.getImm(); 1310b57cec5SDimitry Andric return; 1320b57cec5SDimitry Andric 1330b57cec5SDimitry Andric case SP::TICCri: // Fall through 1340b57cec5SDimitry Andric case SP::TICCrr: // Fall through 1350b57cec5SDimitry Andric case SP::TRAPri: // Fall through 1360b57cec5SDimitry Andric case SP::TRAPrr: // Fall through 1370b57cec5SDimitry Andric case SP::TXCCri: // Fall through 1380b57cec5SDimitry Andric case SP::TXCCrr: // Fall through 1390b57cec5SDimitry Andric // Only seven-bit values up to 127. 1400b57cec5SDimitry Andric O << ((int) MO.getImm() & 0x7f); 1410b57cec5SDimitry Andric return; 1420b57cec5SDimitry Andric } 1430b57cec5SDimitry Andric } 1440b57cec5SDimitry Andric 1450b57cec5SDimitry Andric assert(MO.isExpr() && "Unknown operand kind in printOperand"); 1460b57cec5SDimitry Andric MO.getExpr()->print(O, &MAI); 1470b57cec5SDimitry Andric } 1480b57cec5SDimitry Andric 1490b57cec5SDimitry Andric void SparcInstPrinter::printMemOperand(const MCInst *MI, int opNum, 1500b57cec5SDimitry Andric const MCSubtargetInfo &STI, 1515f757f3fSDimitry Andric raw_ostream &O) { 152e8d8bef9SDimitry Andric const MCOperand &Op1 = MI->getOperand(opNum); 153e8d8bef9SDimitry Andric const MCOperand &Op2 = MI->getOperand(opNum + 1); 1540b57cec5SDimitry Andric 155e8d8bef9SDimitry Andric bool PrintedFirstOperand = false; 156e8d8bef9SDimitry Andric if (Op1.isReg() && Op1.getReg() != SP::G0) { 157e8d8bef9SDimitry Andric printOperand(MI, opNum, STI, O); 158e8d8bef9SDimitry Andric PrintedFirstOperand = true; 159e8d8bef9SDimitry Andric } 1600b57cec5SDimitry Andric 161e8d8bef9SDimitry Andric // Skip the second operand iff it adds nothing (literal 0 or %g0) and we've 162e8d8bef9SDimitry Andric // already printed the first one 163e8d8bef9SDimitry Andric const bool SkipSecondOperand = 164e8d8bef9SDimitry Andric PrintedFirstOperand && ((Op2.isReg() && Op2.getReg() == SP::G0) || 165e8d8bef9SDimitry Andric (Op2.isImm() && Op2.getImm() == 0)); 166e8d8bef9SDimitry Andric 167e8d8bef9SDimitry Andric if (!SkipSecondOperand) { 168e8d8bef9SDimitry Andric if (PrintedFirstOperand) 169e8d8bef9SDimitry Andric O << '+'; 1700b57cec5SDimitry Andric printOperand(MI, opNum + 1, STI, O); 1710b57cec5SDimitry Andric } 172e8d8bef9SDimitry Andric } 1730b57cec5SDimitry Andric 1740b57cec5SDimitry Andric void SparcInstPrinter::printCCOperand(const MCInst *MI, int opNum, 1750b57cec5SDimitry Andric const MCSubtargetInfo &STI, 1760b57cec5SDimitry Andric raw_ostream &O) { 1770b57cec5SDimitry Andric int CC = (int)MI->getOperand(opNum).getImm(); 1780b57cec5SDimitry Andric switch (MI->getOpcode()) { 1790b57cec5SDimitry Andric default: break; 1800b57cec5SDimitry Andric case SP::FBCOND: 1810b57cec5SDimitry Andric case SP::FBCONDA: 1821ac55f4cSDimitry Andric case SP::FBCOND_V9: 1831ac55f4cSDimitry Andric case SP::FBCONDA_V9: 1840b57cec5SDimitry Andric case SP::BPFCC: 1850b57cec5SDimitry Andric case SP::BPFCCA: 1860b57cec5SDimitry Andric case SP::BPFCCNT: 1870b57cec5SDimitry Andric case SP::BPFCCANT: 1880b57cec5SDimitry Andric case SP::MOVFCCrr: case SP::V9MOVFCCrr: 1890b57cec5SDimitry Andric case SP::MOVFCCri: case SP::V9MOVFCCri: 1900b57cec5SDimitry Andric case SP::FMOVS_FCC: case SP::V9FMOVS_FCC: 1910b57cec5SDimitry Andric case SP::FMOVD_FCC: case SP::V9FMOVD_FCC: 1920b57cec5SDimitry Andric case SP::FMOVQ_FCC: case SP::V9FMOVQ_FCC: 1930b57cec5SDimitry Andric // Make sure CC is a fp conditional flag. 194bdd1243dSDimitry Andric CC = (CC < SPCC::FCC_BEGIN) ? (CC + SPCC::FCC_BEGIN) : CC; 1950b57cec5SDimitry Andric break; 1960b57cec5SDimitry Andric case SP::CBCOND: 1970b57cec5SDimitry Andric case SP::CBCONDA: 1980b57cec5SDimitry Andric // Make sure CC is a cp conditional flag. 199bdd1243dSDimitry Andric CC = (CC < SPCC::CPCC_BEGIN) ? (CC + SPCC::CPCC_BEGIN) : CC; 200bdd1243dSDimitry Andric break; 20106c3fb27SDimitry Andric case SP::BPR: 20206c3fb27SDimitry Andric case SP::BPRA: 20306c3fb27SDimitry Andric case SP::BPRNT: 20406c3fb27SDimitry Andric case SP::BPRANT: 205bdd1243dSDimitry Andric case SP::MOVRri: 206bdd1243dSDimitry Andric case SP::MOVRrr: 207bdd1243dSDimitry Andric case SP::FMOVRS: 208bdd1243dSDimitry Andric case SP::FMOVRD: 209bdd1243dSDimitry Andric case SP::FMOVRQ: 210bdd1243dSDimitry Andric // Make sure CC is a register conditional flag. 211bdd1243dSDimitry Andric CC = (CC < SPCC::REG_BEGIN) ? (CC + SPCC::REG_BEGIN) : CC; 2120b57cec5SDimitry Andric break; 2130b57cec5SDimitry Andric } 2140b57cec5SDimitry Andric O << SPARCCondCodeToString((SPCC::CondCodes)CC); 2150b57cec5SDimitry Andric } 2160b57cec5SDimitry Andric 2170b57cec5SDimitry Andric bool SparcInstPrinter::printGetPCX(const MCInst *MI, unsigned opNum, 2180b57cec5SDimitry Andric const MCSubtargetInfo &STI, 2190b57cec5SDimitry Andric raw_ostream &O) { 2200b57cec5SDimitry Andric llvm_unreachable("FIXME: Implement SparcInstPrinter::printGetPCX."); 2210b57cec5SDimitry Andric return true; 2220b57cec5SDimitry Andric } 2230b57cec5SDimitry Andric 2240b57cec5SDimitry Andric void SparcInstPrinter::printMembarTag(const MCInst *MI, int opNum, 2250b57cec5SDimitry Andric const MCSubtargetInfo &STI, 2260b57cec5SDimitry Andric raw_ostream &O) { 2270b57cec5SDimitry Andric static const char *const TagNames[] = { 2280b57cec5SDimitry Andric "#LoadLoad", "#StoreLoad", "#LoadStore", "#StoreStore", 2290b57cec5SDimitry Andric "#Lookaside", "#MemIssue", "#Sync"}; 2300b57cec5SDimitry Andric 2310b57cec5SDimitry Andric unsigned Imm = MI->getOperand(opNum).getImm(); 2320b57cec5SDimitry Andric 2330b57cec5SDimitry Andric if (Imm > 127) { 2340b57cec5SDimitry Andric O << Imm; 2350b57cec5SDimitry Andric return; 2360b57cec5SDimitry Andric } 2370b57cec5SDimitry Andric 2380b57cec5SDimitry Andric bool First = true; 239bdd1243dSDimitry Andric for (unsigned i = 0; i < std::size(TagNames); i++) { 2400b57cec5SDimitry Andric if (Imm & (1 << i)) { 2410b57cec5SDimitry Andric O << (First ? "" : " | ") << TagNames[i]; 2420b57cec5SDimitry Andric First = false; 2430b57cec5SDimitry Andric } 2440b57cec5SDimitry Andric } 2450b57cec5SDimitry Andric } 2465f757f3fSDimitry Andric 2475f757f3fSDimitry Andric void SparcInstPrinter::printASITag(const MCInst *MI, int opNum, 2485f757f3fSDimitry Andric const MCSubtargetInfo &STI, raw_ostream &O) { 2495f757f3fSDimitry Andric unsigned Imm = MI->getOperand(opNum).getImm(); 2505f757f3fSDimitry Andric auto ASITag = SparcASITag::lookupASITagByEncoding(Imm); 2515f757f3fSDimitry Andric if (isV9(STI) && ASITag) 2525f757f3fSDimitry Andric O << '#' << ASITag->Name; 2535f757f3fSDimitry Andric else 2545f757f3fSDimitry Andric O << Imm; 2555f757f3fSDimitry Andric } 256*0fca6ea1SDimitry Andric 257*0fca6ea1SDimitry Andric void SparcInstPrinter::printPrefetchTag(const MCInst *MI, int opNum, 258*0fca6ea1SDimitry Andric const MCSubtargetInfo &STI, 259*0fca6ea1SDimitry Andric raw_ostream &O) { 260*0fca6ea1SDimitry Andric unsigned Imm = MI->getOperand(opNum).getImm(); 261*0fca6ea1SDimitry Andric auto PrefetchTag = SparcPrefetchTag::lookupPrefetchTagByEncoding(Imm); 262*0fca6ea1SDimitry Andric if (PrefetchTag) 263*0fca6ea1SDimitry Andric O << '#' << PrefetchTag->Name; 264*0fca6ea1SDimitry Andric else 265*0fca6ea1SDimitry Andric O << Imm; 266*0fca6ea1SDimitry Andric } 267