xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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