1226633Sdim//===-- MipsInstPrinter.cpp - Convert Mips MCInst to assembly syntax ------===// 2224133Sdim// 3224133Sdim// The LLVM Compiler Infrastructure 4224133Sdim// 5224133Sdim// This file is distributed under the University of Illinois Open Source 6224133Sdim// License. See LICENSE.TXT for details. 7224133Sdim// 8224133Sdim//===----------------------------------------------------------------------===// 9224133Sdim// 10224133Sdim// This class prints an Mips MCInst to a .s file. 11224133Sdim// 12224133Sdim//===----------------------------------------------------------------------===// 13224133Sdim 14224133Sdim#define DEBUG_TYPE "asm-printer" 15224133Sdim#include "MipsInstPrinter.h" 16239462Sdim#include "MipsInstrInfo.h" 17234353Sdim#include "llvm/ADT/StringExtras.h" 18224133Sdim#include "llvm/MC/MCExpr.h" 19224133Sdim#include "llvm/MC/MCInst.h" 20234353Sdim#include "llvm/MC/MCInstrInfo.h" 21234353Sdim#include "llvm/MC/MCSymbol.h" 22224133Sdim#include "llvm/Support/ErrorHandling.h" 23224133Sdim#include "llvm/Support/raw_ostream.h" 24224133Sdimusing namespace llvm; 25224133Sdim 26249423Sdim#define PRINT_ALIAS_INSTR 27224133Sdim#include "MipsGenAsmWriter.inc" 28224133Sdim 29263508Sdimtemplate<unsigned R> 30263508Sdimstatic bool isReg(const MCInst &MI, unsigned OpNo) { 31263508Sdim assert(MI.getOperand(OpNo).isReg() && "Register operand expected."); 32263508Sdim return MI.getOperand(OpNo).getReg() == R; 33263508Sdim} 34263508Sdim 35224133Sdimconst char* Mips::MipsFCCToString(Mips::CondCode CC) { 36224133Sdim switch (CC) { 37224133Sdim case FCOND_F: 38224133Sdim case FCOND_T: return "f"; 39224133Sdim case FCOND_UN: 40224133Sdim case FCOND_OR: return "un"; 41224133Sdim case FCOND_OEQ: 42224133Sdim case FCOND_UNE: return "eq"; 43224133Sdim case FCOND_UEQ: 44224133Sdim case FCOND_ONE: return "ueq"; 45224133Sdim case FCOND_OLT: 46224133Sdim case FCOND_UGE: return "olt"; 47224133Sdim case FCOND_ULT: 48224133Sdim case FCOND_OGE: return "ult"; 49224133Sdim case FCOND_OLE: 50224133Sdim case FCOND_UGT: return "ole"; 51224133Sdim case FCOND_ULE: 52224133Sdim case FCOND_OGT: return "ule"; 53224133Sdim case FCOND_SF: 54224133Sdim case FCOND_ST: return "sf"; 55224133Sdim case FCOND_NGLE: 56224133Sdim case FCOND_GLE: return "ngle"; 57224133Sdim case FCOND_SEQ: 58224133Sdim case FCOND_SNE: return "seq"; 59224133Sdim case FCOND_NGL: 60224133Sdim case FCOND_GL: return "ngl"; 61224133Sdim case FCOND_LT: 62224133Sdim case FCOND_NLT: return "lt"; 63224133Sdim case FCOND_NGE: 64224133Sdim case FCOND_GE: return "nge"; 65224133Sdim case FCOND_LE: 66224133Sdim case FCOND_NLE: return "le"; 67224133Sdim case FCOND_NGT: 68224133Sdim case FCOND_GT: return "ngt"; 69224133Sdim } 70224133Sdim llvm_unreachable("Impossible condition code!"); 71224133Sdim} 72224133Sdim 73224133Sdimvoid MipsInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const { 74234353Sdim OS << '$' << StringRef(getRegisterName(RegNo)).lower(); 75224133Sdim} 76224133Sdim 77226633Sdimvoid MipsInstPrinter::printInst(const MCInst *MI, raw_ostream &O, 78226633Sdim StringRef Annot) { 79239462Sdim switch (MI->getOpcode()) { 80239462Sdim default: 81239462Sdim break; 82239462Sdim case Mips::RDHWR: 83239462Sdim case Mips::RDHWR64: 84239462Sdim O << "\t.set\tpush\n"; 85239462Sdim O << "\t.set\tmips32r2\n"; 86239462Sdim } 87239462Sdim 88249423Sdim // Try to print any aliases first. 89263508Sdim if (!printAliasInstr(MI, O) && !printAlias(*MI, O)) 90249423Sdim printInstruction(MI, O); 91226633Sdim printAnnotation(O, Annot); 92239462Sdim 93239462Sdim switch (MI->getOpcode()) { 94239462Sdim default: 95239462Sdim break; 96239462Sdim case Mips::RDHWR: 97239462Sdim case Mips::RDHWR64: 98239462Sdim O << "\n\t.set\tpop"; 99239462Sdim } 100224133Sdim} 101224133Sdim 102234353Sdimstatic void printExpr(const MCExpr *Expr, raw_ostream &OS) { 103234353Sdim int Offset = 0; 104234353Sdim const MCSymbolRefExpr *SRE; 105234353Sdim 106234353Sdim if (const MCBinaryExpr *BE = dyn_cast<MCBinaryExpr>(Expr)) { 107234353Sdim SRE = dyn_cast<MCSymbolRefExpr>(BE->getLHS()); 108234353Sdim const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(BE->getRHS()); 109234353Sdim assert(SRE && CE && "Binary expression must be sym+const."); 110234353Sdim Offset = CE->getValue(); 111234353Sdim } 112234353Sdim else if (!(SRE = dyn_cast<MCSymbolRefExpr>(Expr))) 113234353Sdim assert(false && "Unexpected MCExpr type."); 114234353Sdim 115234353Sdim MCSymbolRefExpr::VariantKind Kind = SRE->getKind(); 116234353Sdim 117234353Sdim switch (Kind) { 118234353Sdim default: llvm_unreachable("Invalid kind!"); 119234353Sdim case MCSymbolRefExpr::VK_None: break; 120234353Sdim case MCSymbolRefExpr::VK_Mips_GPREL: OS << "%gp_rel("; break; 121234353Sdim case MCSymbolRefExpr::VK_Mips_GOT_CALL: OS << "%call16("; break; 122234353Sdim case MCSymbolRefExpr::VK_Mips_GOT16: OS << "%got("; break; 123234353Sdim case MCSymbolRefExpr::VK_Mips_GOT: OS << "%got("; break; 124234353Sdim case MCSymbolRefExpr::VK_Mips_ABS_HI: OS << "%hi("; break; 125234353Sdim case MCSymbolRefExpr::VK_Mips_ABS_LO: OS << "%lo("; break; 126234353Sdim case MCSymbolRefExpr::VK_Mips_TLSGD: OS << "%tlsgd("; break; 127234353Sdim case MCSymbolRefExpr::VK_Mips_TLSLDM: OS << "%tlsldm("; break; 128234353Sdim case MCSymbolRefExpr::VK_Mips_DTPREL_HI: OS << "%dtprel_hi("; break; 129234353Sdim case MCSymbolRefExpr::VK_Mips_DTPREL_LO: OS << "%dtprel_lo("; break; 130234353Sdim case MCSymbolRefExpr::VK_Mips_GOTTPREL: OS << "%gottprel("; break; 131234353Sdim case MCSymbolRefExpr::VK_Mips_TPREL_HI: OS << "%tprel_hi("; break; 132234353Sdim case MCSymbolRefExpr::VK_Mips_TPREL_LO: OS << "%tprel_lo("; break; 133234353Sdim case MCSymbolRefExpr::VK_Mips_GPOFF_HI: OS << "%hi(%neg(%gp_rel("; break; 134234353Sdim case MCSymbolRefExpr::VK_Mips_GPOFF_LO: OS << "%lo(%neg(%gp_rel("; break; 135234353Sdim case MCSymbolRefExpr::VK_Mips_GOT_DISP: OS << "%got_disp("; break; 136234353Sdim case MCSymbolRefExpr::VK_Mips_GOT_PAGE: OS << "%got_page("; break; 137234353Sdim case MCSymbolRefExpr::VK_Mips_GOT_OFST: OS << "%got_ofst("; break; 138239462Sdim case MCSymbolRefExpr::VK_Mips_HIGHER: OS << "%higher("; break; 139239462Sdim case MCSymbolRefExpr::VK_Mips_HIGHEST: OS << "%highest("; break; 140244628Sdim case MCSymbolRefExpr::VK_Mips_GOT_HI16: OS << "%got_hi("; break; 141244628Sdim case MCSymbolRefExpr::VK_Mips_GOT_LO16: OS << "%got_lo("; break; 142244628Sdim case MCSymbolRefExpr::VK_Mips_CALL_HI16: OS << "%call_hi("; break; 143244628Sdim case MCSymbolRefExpr::VK_Mips_CALL_LO16: OS << "%call_lo("; break; 144234353Sdim } 145234353Sdim 146234353Sdim OS << SRE->getSymbol(); 147234353Sdim 148234353Sdim if (Offset) { 149234353Sdim if (Offset > 0) 150234353Sdim OS << '+'; 151234353Sdim OS << Offset; 152234353Sdim } 153234353Sdim 154234353Sdim if ((Kind == MCSymbolRefExpr::VK_Mips_GPOFF_HI) || 155234353Sdim (Kind == MCSymbolRefExpr::VK_Mips_GPOFF_LO)) 156234353Sdim OS << ")))"; 157234353Sdim else if (Kind != MCSymbolRefExpr::VK_None) 158234353Sdim OS << ')'; 159234353Sdim} 160234353Sdim 161224133Sdimvoid MipsInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, 162224133Sdim raw_ostream &O) { 163224133Sdim const MCOperand &Op = MI->getOperand(OpNo); 164224133Sdim if (Op.isReg()) { 165224133Sdim printRegName(O, Op.getReg()); 166224133Sdim return; 167224133Sdim } 168234353Sdim 169224133Sdim if (Op.isImm()) { 170224133Sdim O << Op.getImm(); 171224133Sdim return; 172224133Sdim } 173234353Sdim 174224133Sdim assert(Op.isExpr() && "unknown operand kind in printOperand"); 175234353Sdim printExpr(Op.getExpr(), O); 176224133Sdim} 177224133Sdim 178224133Sdimvoid MipsInstPrinter::printUnsignedImm(const MCInst *MI, int opNum, 179224133Sdim raw_ostream &O) { 180224133Sdim const MCOperand &MO = MI->getOperand(opNum); 181224133Sdim if (MO.isImm()) 182224133Sdim O << (unsigned short int)MO.getImm(); 183224133Sdim else 184224133Sdim printOperand(MI, opNum, O); 185224133Sdim} 186224133Sdim 187263508Sdimvoid MipsInstPrinter::printUnsignedImm8(const MCInst *MI, int opNum, 188263508Sdim raw_ostream &O) { 189263508Sdim const MCOperand &MO = MI->getOperand(opNum); 190263508Sdim if (MO.isImm()) 191263508Sdim O << (unsigned short int)(unsigned char)MO.getImm(); 192263508Sdim else 193263508Sdim printOperand(MI, opNum, O); 194263508Sdim} 195263508Sdim 196224133Sdimvoid MipsInstPrinter:: 197224133SdimprintMemOperand(const MCInst *MI, int opNum, raw_ostream &O) { 198224133Sdim // Load/Store memory operands -- imm($reg) 199224133Sdim // If PIC target the target is loaded as the 200224133Sdim // pattern lw $25,%call16($28) 201224133Sdim printOperand(MI, opNum+1, O); 202224133Sdim O << "("; 203224133Sdim printOperand(MI, opNum, O); 204224133Sdim O << ")"; 205224133Sdim} 206224133Sdim 207224133Sdimvoid MipsInstPrinter:: 208224133SdimprintMemOperandEA(const MCInst *MI, int opNum, raw_ostream &O) { 209224133Sdim // when using stack locations for not load/store instructions 210224133Sdim // print the same way as all normal 3 operand instructions. 211224133Sdim printOperand(MI, opNum, O); 212224133Sdim O << ", "; 213224133Sdim printOperand(MI, opNum+1, O); 214224133Sdim return; 215224133Sdim} 216224133Sdim 217224133Sdimvoid MipsInstPrinter:: 218224133SdimprintFCCOperand(const MCInst *MI, int opNum, raw_ostream &O) { 219224133Sdim const MCOperand& MO = MI->getOperand(opNum); 220224133Sdim O << MipsFCCToString((Mips::CondCode)MO.getImm()); 221224133Sdim} 222263508Sdim 223263508Sdimvoid MipsInstPrinter:: 224263508SdimprintSHFMask(const MCInst *MI, int opNum, raw_ostream &O) { 225263508Sdim llvm_unreachable("TODO"); 226263508Sdim} 227263508Sdim 228263508Sdimbool MipsInstPrinter::printAlias(const char *Str, const MCInst &MI, 229263508Sdim unsigned OpNo, raw_ostream &OS) { 230263508Sdim OS << "\t" << Str << "\t"; 231263508Sdim printOperand(&MI, OpNo, OS); 232263508Sdim return true; 233263508Sdim} 234263508Sdim 235263508Sdimbool MipsInstPrinter::printAlias(const char *Str, const MCInst &MI, 236263508Sdim unsigned OpNo0, unsigned OpNo1, 237263508Sdim raw_ostream &OS) { 238263508Sdim printAlias(Str, MI, OpNo0, OS); 239263508Sdim OS << ", "; 240263508Sdim printOperand(&MI, OpNo1, OS); 241263508Sdim return true; 242263508Sdim} 243263508Sdim 244263508Sdimbool MipsInstPrinter::printAlias(const MCInst &MI, raw_ostream &OS) { 245263508Sdim switch (MI.getOpcode()) { 246263508Sdim case Mips::BEQ: 247263508Sdim // beq $zero, $zero, $L2 => b $L2 248263508Sdim // beq $r0, $zero, $L2 => beqz $r0, $L2 249263508Sdim return (isReg<Mips::ZERO>(MI, 0) && isReg<Mips::ZERO>(MI, 1) && 250263508Sdim printAlias("b", MI, 2, OS)) || 251263508Sdim (isReg<Mips::ZERO>(MI, 1) && printAlias("beqz", MI, 0, 2, OS)); 252263508Sdim case Mips::BEQ64: 253263508Sdim // beq $r0, $zero, $L2 => beqz $r0, $L2 254263508Sdim return isReg<Mips::ZERO_64>(MI, 1) && printAlias("beqz", MI, 0, 2, OS); 255263508Sdim case Mips::BNE: 256263508Sdim // bne $r0, $zero, $L2 => bnez $r0, $L2 257263508Sdim return isReg<Mips::ZERO>(MI, 1) && printAlias("bnez", MI, 0, 2, OS); 258263508Sdim case Mips::BNE64: 259263508Sdim // bne $r0, $zero, $L2 => bnez $r0, $L2 260263508Sdim return isReg<Mips::ZERO_64>(MI, 1) && printAlias("bnez", MI, 0, 2, OS); 261263508Sdim case Mips::BGEZAL: 262263508Sdim // bgezal $zero, $L1 => bal $L1 263263508Sdim return isReg<Mips::ZERO>(MI, 0) && printAlias("bal", MI, 1, OS); 264263508Sdim case Mips::BC1T: 265263508Sdim // bc1t $fcc0, $L1 => bc1t $L1 266263508Sdim return isReg<Mips::FCC0>(MI, 0) && printAlias("bc1t", MI, 1, OS); 267263508Sdim case Mips::BC1F: 268263508Sdim // bc1f $fcc0, $L1 => bc1f $L1 269263508Sdim return isReg<Mips::FCC0>(MI, 0) && printAlias("bc1f", MI, 1, OS); 270263508Sdim case Mips::JALR: 271263508Sdim // jalr $ra, $r1 => jalr $r1 272263508Sdim return isReg<Mips::RA>(MI, 0) && printAlias("jalr", MI, 1, OS); 273263508Sdim case Mips::JALR64: 274263508Sdim // jalr $ra, $r1 => jalr $r1 275263508Sdim return isReg<Mips::RA_64>(MI, 0) && printAlias("jalr", MI, 1, OS); 276263508Sdim case Mips::NOR: 277263508Sdim case Mips::NOR_MM: 278263508Sdim // nor $r0, $r1, $zero => not $r0, $r1 279263508Sdim return isReg<Mips::ZERO>(MI, 2) && printAlias("not", MI, 0, 1, OS); 280263508Sdim case Mips::NOR64: 281263508Sdim // nor $r0, $r1, $zero => not $r0, $r1 282263508Sdim return isReg<Mips::ZERO_64>(MI, 2) && printAlias("not", MI, 0, 1, OS); 283263508Sdim case Mips::OR: 284263508Sdim // or $r0, $r1, $zero => move $r0, $r1 285263508Sdim return isReg<Mips::ZERO>(MI, 2) && printAlias("move", MI, 0, 1, OS); 286263508Sdim default: return false; 287263508Sdim } 288263508Sdim} 289