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
isV9(const MCSubtargetInfo & STI) const370b57cec5SDimitry Andric bool SparcInstPrinter::isV9(const MCSubtargetInfo &STI) const {
3806c3fb27SDimitry Andric return (STI.hasFeature(Sparc::FeatureV9)) != 0;
390b57cec5SDimitry Andric }
400b57cec5SDimitry Andric
printRegName(raw_ostream & OS,MCRegister Reg) const41bdd1243dSDimitry Andric void SparcInstPrinter::printRegName(raw_ostream &OS, MCRegister Reg) const {
425f757f3fSDimitry Andric OS << '%' << getRegisterName(Reg);
435f757f3fSDimitry Andric }
445f757f3fSDimitry Andric
printRegName(raw_ostream & OS,MCRegister Reg,unsigned AltIdx) const455f757f3fSDimitry Andric void SparcInstPrinter::printRegName(raw_ostream &OS, MCRegister Reg,
465f757f3fSDimitry Andric unsigned AltIdx) const {
475f757f3fSDimitry Andric OS << '%' << getRegisterName(Reg, AltIdx);
480b57cec5SDimitry Andric }
490b57cec5SDimitry Andric
printInst(const MCInst * MI,uint64_t Address,StringRef Annot,const MCSubtargetInfo & STI,raw_ostream & O)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
printSparcAliasInstr(const MCInst * MI,const MCSubtargetInfo & STI,raw_ostream & O)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
printOperand(const MCInst * MI,int opNum,const MCSubtargetInfo & STI,raw_ostream & O)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
printMemOperand(const MCInst * MI,int opNum,const MCSubtargetInfo & STI,raw_ostream & O)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
printCCOperand(const MCInst * MI,int opNum,const MCSubtargetInfo & STI,raw_ostream & O)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
printGetPCX(const MCInst * MI,unsigned opNum,const MCSubtargetInfo & STI,raw_ostream & O)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
printMembarTag(const MCInst * MI,int opNum,const MCSubtargetInfo & STI,raw_ostream & O)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
printASITag(const MCInst * MI,int opNum,const MCSubtargetInfo & STI,raw_ostream & O)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
printPrefetchTag(const MCInst * MI,int opNum,const MCSubtargetInfo & STI,raw_ostream & O)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