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/MCSubtargetInfo.h" 18 #include "llvm/MC/MCSymbol.h" 19 #include "llvm/Support/raw_ostream.h" 20 using namespace llvm; 21 22 #define DEBUG_TYPE "asm-printer" 23 24 // The generated AsmMatcher SparcGenAsmWriter uses "Sparc" as the target 25 // namespace. But SPARC backend uses "SP" as its namespace. 26 namespace llvm { 27 namespace Sparc { 28 using namespace SP; 29 } 30 } 31 32 #define GET_INSTRUCTION_NAME 33 #define PRINT_ALIAS_INSTR 34 #include "SparcGenAsmWriter.inc" 35 36 bool SparcInstPrinter::isV9(const MCSubtargetInfo &STI) const { 37 return (STI.hasFeature(Sparc::FeatureV9)) != 0; 38 } 39 40 void SparcInstPrinter::printRegName(raw_ostream &OS, MCRegister Reg) { 41 OS << '%' << getRegisterName(Reg); 42 } 43 44 void SparcInstPrinter::printRegName(raw_ostream &OS, MCRegister Reg, 45 unsigned AltIdx) const { 46 OS << '%' << getRegisterName(Reg, AltIdx); 47 } 48 49 void SparcInstPrinter::printInst(const MCInst *MI, uint64_t Address, 50 StringRef Annot, const MCSubtargetInfo &STI, 51 raw_ostream &O) { 52 if (!printAliasInstr(MI, Address, STI, O) && 53 !printSparcAliasInstr(MI, STI, O)) 54 printInstruction(MI, Address, STI, O); 55 printAnnotation(O, Annot); 56 } 57 58 bool SparcInstPrinter::printSparcAliasInstr(const MCInst *MI, 59 const MCSubtargetInfo &STI, 60 raw_ostream &O) { 61 switch (MI->getOpcode()) { 62 default: return false; 63 case SP::JMPLrr: 64 case SP::JMPLri: { 65 if (MI->getNumOperands() != 3) 66 return false; 67 if (!MI->getOperand(0).isReg()) 68 return false; 69 switch (MI->getOperand(0).getReg()) { 70 default: return false; 71 case SP::G0: // jmp $addr | ret | retl 72 if (MI->getOperand(2).isImm() && 73 MI->getOperand(2).getImm() == 8) { 74 switch(MI->getOperand(1).getReg()) { 75 default: break; 76 case SP::I7: O << "\tret"; return true; 77 case SP::O7: O << "\tretl"; return true; 78 } 79 } 80 O << "\tjmp "; printMemOperand(MI, 1, STI, O); 81 return true; 82 case SP::O7: // call $addr 83 O << "\tcall "; printMemOperand(MI, 1, STI, O); 84 return true; 85 } 86 } 87 case SP::V9FCMPS: case SP::V9FCMPD: case SP::V9FCMPQ: 88 case SP::V9FCMPES: case SP::V9FCMPED: case SP::V9FCMPEQ: { 89 if (isV9(STI) 90 || (MI->getNumOperands() != 3) 91 || (!MI->getOperand(0).isReg()) 92 || (MI->getOperand(0).getReg() != SP::FCC0)) 93 return false; 94 // if V8, skip printing %fcc0. 95 switch(MI->getOpcode()) { 96 default: 97 case SP::V9FCMPS: O << "\tfcmps "; break; 98 case SP::V9FCMPD: O << "\tfcmpd "; break; 99 case SP::V9FCMPQ: O << "\tfcmpq "; break; 100 case SP::V9FCMPES: O << "\tfcmpes "; break; 101 case SP::V9FCMPED: O << "\tfcmped "; break; 102 case SP::V9FCMPEQ: O << "\tfcmpeq "; break; 103 } 104 printOperand(MI, 1, STI, O); 105 O << ", "; 106 printOperand(MI, 2, STI, O); 107 return true; 108 } 109 } 110 } 111 112 void SparcInstPrinter::printOperand(const MCInst *MI, int opNum, 113 const MCSubtargetInfo &STI, 114 raw_ostream &O) { 115 const MCOperand &MO = MI->getOperand (opNum); 116 117 if (MO.isReg()) { 118 unsigned Reg = MO.getReg(); 119 if (isV9(STI)) 120 printRegName(O, Reg, SP::RegNamesStateReg); 121 else 122 printRegName(O, Reg); 123 return ; 124 } 125 126 if (MO.isImm()) { 127 switch (MI->getOpcode()) { 128 default: 129 O << (int)MO.getImm(); 130 return; 131 132 case SP::TICCri: // Fall through 133 case SP::TICCrr: // Fall through 134 case SP::TRAPri: // Fall through 135 case SP::TRAPrr: // Fall through 136 case SP::TXCCri: // Fall through 137 case SP::TXCCrr: // Fall through 138 // Only seven-bit values up to 127. 139 O << ((int) MO.getImm() & 0x7f); 140 return; 141 } 142 } 143 144 assert(MO.isExpr() && "Unknown operand kind in printOperand"); 145 MO.getExpr()->print(O, &MAI); 146 } 147 148 void SparcInstPrinter::printMemOperand(const MCInst *MI, int opNum, 149 const MCSubtargetInfo &STI, 150 raw_ostream &O) { 151 const MCOperand &Op1 = MI->getOperand(opNum); 152 const MCOperand &Op2 = MI->getOperand(opNum + 1); 153 154 bool PrintedFirstOperand = false; 155 if (Op1.isReg() && Op1.getReg() != SP::G0) { 156 printOperand(MI, opNum, STI, O); 157 PrintedFirstOperand = true; 158 } 159 160 // Skip the second operand iff it adds nothing (literal 0 or %g0) and we've 161 // already printed the first one 162 const bool SkipSecondOperand = 163 PrintedFirstOperand && ((Op2.isReg() && Op2.getReg() == SP::G0) || 164 (Op2.isImm() && Op2.getImm() == 0)); 165 166 if (!SkipSecondOperand) { 167 if (PrintedFirstOperand) 168 O << '+'; 169 printOperand(MI, opNum + 1, STI, O); 170 } 171 } 172 173 void SparcInstPrinter::printCCOperand(const MCInst *MI, int opNum, 174 const MCSubtargetInfo &STI, 175 raw_ostream &O) { 176 int CC = (int)MI->getOperand(opNum).getImm(); 177 switch (MI->getOpcode()) { 178 default: break; 179 case SP::FBCOND: 180 case SP::FBCONDA: 181 case SP::FBCOND_V9: 182 case SP::FBCONDA_V9: 183 case SP::BPFCC: 184 case SP::BPFCCA: 185 case SP::BPFCCNT: 186 case SP::BPFCCANT: 187 case SP::MOVFCCrr: case SP::V9MOVFCCrr: 188 case SP::MOVFCCri: case SP::V9MOVFCCri: 189 case SP::FMOVS_FCC: case SP::V9FMOVS_FCC: 190 case SP::FMOVD_FCC: case SP::V9FMOVD_FCC: 191 case SP::FMOVQ_FCC: case SP::V9FMOVQ_FCC: 192 // Make sure CC is a fp conditional flag. 193 CC = (CC < SPCC::FCC_BEGIN) ? (CC + SPCC::FCC_BEGIN) : CC; 194 break; 195 case SP::CBCOND: 196 case SP::CBCONDA: 197 // Make sure CC is a cp conditional flag. 198 CC = (CC < SPCC::CPCC_BEGIN) ? (CC + SPCC::CPCC_BEGIN) : CC; 199 break; 200 case SP::BPR: 201 case SP::BPRA: 202 case SP::BPRNT: 203 case SP::BPRANT: 204 case SP::MOVRri: 205 case SP::MOVRrr: 206 case SP::FMOVRS: 207 case SP::FMOVRD: 208 case SP::FMOVRQ: 209 // Make sure CC is a register conditional flag. 210 CC = (CC < SPCC::REG_BEGIN) ? (CC + SPCC::REG_BEGIN) : CC; 211 break; 212 } 213 O << SPARCCondCodeToString((SPCC::CondCodes)CC); 214 } 215 216 bool SparcInstPrinter::printGetPCX(const MCInst *MI, unsigned opNum, 217 const MCSubtargetInfo &STI, 218 raw_ostream &O) { 219 llvm_unreachable("FIXME: Implement SparcInstPrinter::printGetPCX."); 220 return true; 221 } 222 223 void SparcInstPrinter::printMembarTag(const MCInst *MI, int opNum, 224 const MCSubtargetInfo &STI, 225 raw_ostream &O) { 226 static const char *const TagNames[] = { 227 "#LoadLoad", "#StoreLoad", "#LoadStore", "#StoreStore", 228 "#Lookaside", "#MemIssue", "#Sync"}; 229 230 unsigned Imm = MI->getOperand(opNum).getImm(); 231 232 if (Imm > 127) { 233 O << Imm; 234 return; 235 } 236 237 bool First = true; 238 for (unsigned i = 0; i < std::size(TagNames); i++) { 239 if (Imm & (1 << i)) { 240 O << (First ? "" : " | ") << TagNames[i]; 241 First = false; 242 } 243 } 244 } 245 246 void SparcInstPrinter::printASITag(const MCInst *MI, int opNum, 247 const MCSubtargetInfo &STI, raw_ostream &O) { 248 unsigned Imm = MI->getOperand(opNum).getImm(); 249 auto ASITag = SparcASITag::lookupASITagByEncoding(Imm); 250 if (isV9(STI) && ASITag) 251 O << '#' << ASITag->Name; 252 else 253 O << Imm; 254 } 255 256 void SparcInstPrinter::printPrefetchTag(const MCInst *MI, int opNum, 257 const MCSubtargetInfo &STI, 258 raw_ostream &O) { 259 unsigned Imm = MI->getOperand(opNum).getImm(); 260 auto PrefetchTag = SparcPrefetchTag::lookupPrefetchTagByEncoding(Imm); 261 if (PrefetchTag) 262 O << '#' << PrefetchTag->Name; 263 else 264 O << Imm; 265 } 266