1 //===- ARCInstPrinter.cpp - ARC MCInst to assembly syntax -------*- C++ -*-===// 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 ARC MCInst to a .s file. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "ARCInstPrinter.h" 14 #include "MCTargetDesc/ARCInfo.h" 15 #include "llvm/ADT/StringExtras.h" 16 #include "llvm/MC/MCExpr.h" 17 #include "llvm/MC/MCInst.h" 18 #include "llvm/MC/MCInstrInfo.h" 19 #include "llvm/MC/MCSymbol.h" 20 #include "llvm/Support/Casting.h" 21 #include "llvm/Support/Debug.h" 22 #include "llvm/Support/raw_ostream.h" 23 24 using namespace llvm; 25 26 #define DEBUG_TYPE "asm-printer" 27 28 #include "ARCGenAsmWriter.inc" 29 30 template <class T> 31 static const char *BadConditionCode(T cc) { 32 LLVM_DEBUG(dbgs() << "Unknown condition code passed: " << cc << "\n"); 33 return "{unknown-cc}"; 34 } 35 36 static const char *ARCBRCondCodeToString(ARCCC::BRCondCode BRCC) { 37 switch (BRCC) { 38 case ARCCC::BREQ: 39 return "eq"; 40 case ARCCC::BRNE: 41 return "ne"; 42 case ARCCC::BRLT: 43 return "lt"; 44 case ARCCC::BRGE: 45 return "ge"; 46 case ARCCC::BRLO: 47 return "lo"; 48 case ARCCC::BRHS: 49 return "hs"; 50 } 51 return BadConditionCode(BRCC); 52 } 53 54 static const char *ARCCondCodeToString(ARCCC::CondCode CC) { 55 switch (CC) { 56 case ARCCC::EQ: 57 return "eq"; 58 case ARCCC::NE: 59 return "ne"; 60 case ARCCC::P: 61 return "p"; 62 case ARCCC::N: 63 return "n"; 64 case ARCCC::HS: 65 return "hs"; 66 case ARCCC::LO: 67 return "lo"; 68 case ARCCC::GT: 69 return "gt"; 70 case ARCCC::GE: 71 return "ge"; 72 case ARCCC::VS: 73 return "vs"; 74 case ARCCC::VC: 75 return "vc"; 76 case ARCCC::LT: 77 return "lt"; 78 case ARCCC::LE: 79 return "le"; 80 case ARCCC::HI: 81 return "hi"; 82 case ARCCC::LS: 83 return "ls"; 84 case ARCCC::PNZ: 85 return "pnz"; 86 case ARCCC::AL: 87 return "al"; 88 case ARCCC::NZ: 89 return "nz"; 90 case ARCCC::Z: 91 return "z"; 92 } 93 return BadConditionCode(CC); 94 } 95 96 void ARCInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const { 97 OS << StringRef(getRegisterName(RegNo)).lower(); 98 } 99 100 void ARCInstPrinter::printInst(const MCInst *MI, uint64_t Address, 101 StringRef Annot, const MCSubtargetInfo &STI, 102 raw_ostream &O) { 103 printInstruction(MI, Address, O); 104 printAnnotation(O, Annot); 105 } 106 107 static void printExpr(const MCExpr *Expr, const MCAsmInfo *MAI, 108 raw_ostream &OS) { 109 int Offset = 0; 110 const MCSymbolRefExpr *SRE; 111 112 if (const auto *CE = dyn_cast<MCConstantExpr>(Expr)) { 113 OS << "0x"; 114 OS.write_hex(CE->getValue()); 115 return; 116 } 117 118 if (const auto *BE = dyn_cast<MCBinaryExpr>(Expr)) { 119 SRE = dyn_cast<MCSymbolRefExpr>(BE->getLHS()); 120 const auto *CE = dyn_cast<MCConstantExpr>(BE->getRHS()); 121 assert(SRE && CE && "Binary expression must be sym+const."); 122 Offset = CE->getValue(); 123 } else { 124 SRE = dyn_cast<MCSymbolRefExpr>(Expr); 125 assert(SRE && "Unexpected MCExpr type."); 126 } 127 assert(SRE->getKind() == MCSymbolRefExpr::VK_None); 128 129 // Symbols are prefixed with '@' 130 OS << '@'; 131 SRE->getSymbol().print(OS, MAI); 132 133 if (Offset) { 134 if (Offset > 0) 135 OS << '+'; 136 OS << Offset; 137 } 138 } 139 140 void ARCInstPrinter::printOperand(const MCInst *MI, unsigned OpNum, 141 raw_ostream &O) { 142 const MCOperand &Op = MI->getOperand(OpNum); 143 if (Op.isReg()) { 144 printRegName(O, Op.getReg()); 145 return; 146 } 147 148 if (Op.isImm()) { 149 O << Op.getImm(); 150 return; 151 } 152 153 assert(Op.isExpr() && "unknown operand kind in printOperand"); 154 printExpr(Op.getExpr(), &MAI, O); 155 } 156 157 void ARCInstPrinter::printMemOperandRI(const MCInst *MI, unsigned OpNum, 158 raw_ostream &O) { 159 const MCOperand &base = MI->getOperand(OpNum); 160 const MCOperand &offset = MI->getOperand(OpNum + 1); 161 assert(base.isReg() && "Base should be register."); 162 assert(offset.isImm() && "Offset should be immediate."); 163 printRegName(O, base.getReg()); 164 O << "," << offset.getImm(); 165 } 166 167 void ARCInstPrinter::printPredicateOperand(const MCInst *MI, unsigned OpNum, 168 raw_ostream &O) { 169 170 const MCOperand &Op = MI->getOperand(OpNum); 171 assert(Op.isImm() && "Predicate operand is immediate."); 172 O << ARCCondCodeToString((ARCCC::CondCode)Op.getImm()); 173 } 174 175 void ARCInstPrinter::printBRCCPredicateOperand(const MCInst *MI, unsigned OpNum, 176 raw_ostream &O) { 177 const MCOperand &Op = MI->getOperand(OpNum); 178 assert(Op.isImm() && "Predicate operand is immediate."); 179 O << ARCBRCondCodeToString((ARCCC::BRCondCode)Op.getImm()); 180 } 181 182 void ARCInstPrinter::printCCOperand(const MCInst *MI, int OpNum, 183 raw_ostream &O) { 184 O << ARCCondCodeToString((ARCCC::CondCode)MI->getOperand(OpNum).getImm()); 185 } 186 187 void ARCInstPrinter::printU6ShiftedBy(unsigned ShiftBy, const MCInst *MI, 188 int OpNum, raw_ostream &O) { 189 const MCOperand &MO = MI->getOperand(OpNum); 190 if (MO.isImm()) { 191 unsigned Value = MO.getImm(); 192 unsigned Value2 = Value >> ShiftBy; 193 if (Value2 > 0x3F || (Value2 << ShiftBy != Value)) { 194 errs() << "!!! Instruction has out-of-range U6 immediate operand:\n" 195 << " Opcode is " << MI->getOpcode() << "; operand value is " 196 << Value; 197 if (ShiftBy) 198 errs() << " scaled by " << (1 << ShiftBy) << "\n"; 199 assert(false && "instruction has wrong format"); 200 } 201 } 202 printOperand(MI, OpNum, O); 203 } 204 205 void ARCInstPrinter::printU6(const MCInst *MI, int OpNum, raw_ostream &O) { 206 printU6ShiftedBy(0, MI, OpNum, O); 207 } 208