1 //===-- SparcInstPrinter.cpp - Convert Sparc MCInst to assembly syntax -----==// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This class prints an Sparc MCInst to a .s file. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "SparcInstPrinter.h" 14 #include "Sparc.h" 15 #include "llvm/MC/MCExpr.h" 16 #include "llvm/MC/MCInst.h" 17 #include "llvm/MC/MCRegisterInfo.h" 18 #include "llvm/MC/MCSubtargetInfo.h" 19 #include "llvm/MC/MCSymbol.h" 20 #include "llvm/Support/raw_ostream.h" 21 using namespace llvm; 22 23 #define DEBUG_TYPE "asm-printer" 24 25 // The generated AsmMatcher SparcGenAsmWriter uses "Sparc" as the target 26 // namespace. But SPARC backend uses "SP" as its namespace. 27 namespace llvm { 28 namespace Sparc { 29 using namespace SP; 30 } 31 } 32 33 #define GET_INSTRUCTION_NAME 34 #define PRINT_ALIAS_INSTR 35 #include "SparcGenAsmWriter.inc" 36 37 bool SparcInstPrinter::isV9(const MCSubtargetInfo &STI) const { 38 return (STI.getFeatureBits()[Sparc::FeatureV9]) != 0; 39 } 40 41 void SparcInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const 42 { 43 OS << '%' << StringRef(getRegisterName(RegNo)).lower(); 44 } 45 46 void SparcInstPrinter::printInst(const MCInst *MI, uint64_t Address, 47 StringRef Annot, const MCSubtargetInfo &STI, 48 raw_ostream &O) { 49 if (!printAliasInstr(MI, Address, STI, O) && 50 !printSparcAliasInstr(MI, STI, O)) 51 printInstruction(MI, Address, STI, O); 52 printAnnotation(O, Annot); 53 } 54 55 bool SparcInstPrinter::printSparcAliasInstr(const MCInst *MI, 56 const MCSubtargetInfo &STI, 57 raw_ostream &O) { 58 switch (MI->getOpcode()) { 59 default: return false; 60 case SP::JMPLrr: 61 case SP::JMPLri: { 62 if (MI->getNumOperands() != 3) 63 return false; 64 if (!MI->getOperand(0).isReg()) 65 return false; 66 switch (MI->getOperand(0).getReg()) { 67 default: return false; 68 case SP::G0: // jmp $addr | ret | retl 69 if (MI->getOperand(2).isImm() && 70 MI->getOperand(2).getImm() == 8) { 71 switch(MI->getOperand(1).getReg()) { 72 default: break; 73 case SP::I7: O << "\tret"; return true; 74 case SP::O7: O << "\tretl"; return true; 75 } 76 } 77 O << "\tjmp "; printMemOperand(MI, 1, STI, O); 78 return true; 79 case SP::O7: // call $addr 80 O << "\tcall "; printMemOperand(MI, 1, STI, O); 81 return true; 82 } 83 } 84 case SP::V9FCMPS: case SP::V9FCMPD: case SP::V9FCMPQ: 85 case SP::V9FCMPES: case SP::V9FCMPED: case SP::V9FCMPEQ: { 86 if (isV9(STI) 87 || (MI->getNumOperands() != 3) 88 || (!MI->getOperand(0).isReg()) 89 || (MI->getOperand(0).getReg() != SP::FCC0)) 90 return false; 91 // if V8, skip printing %fcc0. 92 switch(MI->getOpcode()) { 93 default: 94 case SP::V9FCMPS: O << "\tfcmps "; break; 95 case SP::V9FCMPD: O << "\tfcmpd "; break; 96 case SP::V9FCMPQ: O << "\tfcmpq "; break; 97 case SP::V9FCMPES: O << "\tfcmpes "; break; 98 case SP::V9FCMPED: O << "\tfcmped "; break; 99 case SP::V9FCMPEQ: O << "\tfcmpeq "; break; 100 } 101 printOperand(MI, 1, STI, O); 102 O << ", "; 103 printOperand(MI, 2, STI, O); 104 return true; 105 } 106 } 107 } 108 109 void SparcInstPrinter::printOperand(const MCInst *MI, int opNum, 110 const MCSubtargetInfo &STI, 111 raw_ostream &O) { 112 const MCOperand &MO = MI->getOperand (opNum); 113 114 if (MO.isReg()) { 115 printRegName(O, MO.getReg()); 116 return ; 117 } 118 119 if (MO.isImm()) { 120 switch (MI->getOpcode()) { 121 default: 122 O << (int)MO.getImm(); 123 return; 124 125 case SP::TICCri: // Fall through 126 case SP::TICCrr: // Fall through 127 case SP::TRAPri: // Fall through 128 case SP::TRAPrr: // Fall through 129 case SP::TXCCri: // Fall through 130 case SP::TXCCrr: // Fall through 131 // Only seven-bit values up to 127. 132 O << ((int) MO.getImm() & 0x7f); 133 return; 134 } 135 } 136 137 assert(MO.isExpr() && "Unknown operand kind in printOperand"); 138 MO.getExpr()->print(O, &MAI); 139 } 140 141 void SparcInstPrinter::printMemOperand(const MCInst *MI, int opNum, 142 const MCSubtargetInfo &STI, 143 raw_ostream &O, const char *Modifier) { 144 // If this is an ADD operand, emit it like normal operands. 145 if (Modifier && !strcmp(Modifier, "arith")) { 146 printOperand(MI, opNum, STI, O); 147 O << ", "; 148 printOperand(MI, opNum + 1, STI, O); 149 return; 150 } 151 152 const MCOperand &Op1 = MI->getOperand(opNum); 153 const MCOperand &Op2 = MI->getOperand(opNum + 1); 154 155 bool PrintedFirstOperand = false; 156 if (Op1.isReg() && Op1.getReg() != SP::G0) { 157 printOperand(MI, opNum, STI, O); 158 PrintedFirstOperand = true; 159 } 160 161 // Skip the second operand iff it adds nothing (literal 0 or %g0) and we've 162 // already printed the first one 163 const bool SkipSecondOperand = 164 PrintedFirstOperand && ((Op2.isReg() && Op2.getReg() == SP::G0) || 165 (Op2.isImm() && Op2.getImm() == 0)); 166 167 if (!SkipSecondOperand) { 168 if (PrintedFirstOperand) 169 O << '+'; 170 printOperand(MI, opNum + 1, STI, O); 171 } 172 } 173 174 void SparcInstPrinter::printCCOperand(const MCInst *MI, int opNum, 175 const MCSubtargetInfo &STI, 176 raw_ostream &O) { 177 int CC = (int)MI->getOperand(opNum).getImm(); 178 switch (MI->getOpcode()) { 179 default: break; 180 case SP::FBCOND: 181 case SP::FBCONDA: 182 case SP::BPFCC: 183 case SP::BPFCCA: 184 case SP::BPFCCNT: 185 case SP::BPFCCANT: 186 case SP::MOVFCCrr: case SP::V9MOVFCCrr: 187 case SP::MOVFCCri: case SP::V9MOVFCCri: 188 case SP::FMOVS_FCC: case SP::V9FMOVS_FCC: 189 case SP::FMOVD_FCC: case SP::V9FMOVD_FCC: 190 case SP::FMOVQ_FCC: case SP::V9FMOVQ_FCC: 191 // Make sure CC is a fp conditional flag. 192 CC = (CC < 16) ? (CC + 16) : CC; 193 break; 194 case SP::CBCOND: 195 case SP::CBCONDA: 196 // Make sure CC is a cp conditional flag. 197 CC = (CC < 32) ? (CC + 32) : CC; 198 break; 199 } 200 O << SPARCCondCodeToString((SPCC::CondCodes)CC); 201 } 202 203 bool SparcInstPrinter::printGetPCX(const MCInst *MI, unsigned opNum, 204 const MCSubtargetInfo &STI, 205 raw_ostream &O) { 206 llvm_unreachable("FIXME: Implement SparcInstPrinter::printGetPCX."); 207 return true; 208 } 209 210 void SparcInstPrinter::printMembarTag(const MCInst *MI, int opNum, 211 const MCSubtargetInfo &STI, 212 raw_ostream &O) { 213 static const char *const TagNames[] = { 214 "#LoadLoad", "#StoreLoad", "#LoadStore", "#StoreStore", 215 "#Lookaside", "#MemIssue", "#Sync"}; 216 217 unsigned Imm = MI->getOperand(opNum).getImm(); 218 219 if (Imm > 127) { 220 O << Imm; 221 return; 222 } 223 224 bool First = true; 225 for (unsigned i = 0; i < sizeof(TagNames) / sizeof(char *); i++) { 226 if (Imm & (1 << i)) { 227 O << (First ? "" : " | ") << TagNames[i]; 228 First = false; 229 } 230 } 231 } 232