xref: /netbsd-src/external/apache2/llvm/dist/llvm/lib/Target/Mips/MCTargetDesc/MipsInstPrinter.cpp (revision 82d56013d7b633d116a93943de88e08335357a7c)
17330f729Sjoerg //===-- MipsInstPrinter.cpp - Convert Mips MCInst to assembly syntax ------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This class prints an Mips MCInst to a .s file.
107330f729Sjoerg //
117330f729Sjoerg //===----------------------------------------------------------------------===//
127330f729Sjoerg 
137330f729Sjoerg #include "MipsInstPrinter.h"
147330f729Sjoerg #include "MipsInstrInfo.h"
157330f729Sjoerg #include "MipsMCExpr.h"
167330f729Sjoerg #include "llvm/ADT/StringExtras.h"
177330f729Sjoerg #include "llvm/MC/MCExpr.h"
187330f729Sjoerg #include "llvm/MC/MCInst.h"
197330f729Sjoerg #include "llvm/MC/MCInstrInfo.h"
207330f729Sjoerg #include "llvm/MC/MCSymbol.h"
217330f729Sjoerg #include "llvm/Support/ErrorHandling.h"
227330f729Sjoerg #include "llvm/Support/raw_ostream.h"
237330f729Sjoerg using namespace llvm;
247330f729Sjoerg 
257330f729Sjoerg #define DEBUG_TYPE "asm-printer"
267330f729Sjoerg 
277330f729Sjoerg #define PRINT_ALIAS_INSTR
287330f729Sjoerg #include "MipsGenAsmWriter.inc"
297330f729Sjoerg 
307330f729Sjoerg template<unsigned R>
isReg(const MCInst & MI,unsigned OpNo)317330f729Sjoerg static bool isReg(const MCInst &MI, unsigned OpNo) {
327330f729Sjoerg   assert(MI.getOperand(OpNo).isReg() && "Register operand expected.");
337330f729Sjoerg   return MI.getOperand(OpNo).getReg() == R;
347330f729Sjoerg }
357330f729Sjoerg 
MipsFCCToString(Mips::CondCode CC)367330f729Sjoerg const char* Mips::MipsFCCToString(Mips::CondCode CC) {
377330f729Sjoerg   switch (CC) {
387330f729Sjoerg   case FCOND_F:
397330f729Sjoerg   case FCOND_T:   return "f";
407330f729Sjoerg   case FCOND_UN:
417330f729Sjoerg   case FCOND_OR:  return "un";
427330f729Sjoerg   case FCOND_OEQ:
437330f729Sjoerg   case FCOND_UNE: return "eq";
447330f729Sjoerg   case FCOND_UEQ:
457330f729Sjoerg   case FCOND_ONE: return "ueq";
467330f729Sjoerg   case FCOND_OLT:
477330f729Sjoerg   case FCOND_UGE: return "olt";
487330f729Sjoerg   case FCOND_ULT:
497330f729Sjoerg   case FCOND_OGE: return "ult";
507330f729Sjoerg   case FCOND_OLE:
517330f729Sjoerg   case FCOND_UGT: return "ole";
527330f729Sjoerg   case FCOND_ULE:
537330f729Sjoerg   case FCOND_OGT: return "ule";
547330f729Sjoerg   case FCOND_SF:
557330f729Sjoerg   case FCOND_ST:  return "sf";
567330f729Sjoerg   case FCOND_NGLE:
577330f729Sjoerg   case FCOND_GLE: return "ngle";
587330f729Sjoerg   case FCOND_SEQ:
597330f729Sjoerg   case FCOND_SNE: return "seq";
607330f729Sjoerg   case FCOND_NGL:
617330f729Sjoerg   case FCOND_GL:  return "ngl";
627330f729Sjoerg   case FCOND_LT:
637330f729Sjoerg   case FCOND_NLT: return "lt";
647330f729Sjoerg   case FCOND_NGE:
657330f729Sjoerg   case FCOND_GE:  return "nge";
667330f729Sjoerg   case FCOND_LE:
677330f729Sjoerg   case FCOND_NLE: return "le";
687330f729Sjoerg   case FCOND_NGT:
697330f729Sjoerg   case FCOND_GT:  return "ngt";
707330f729Sjoerg   }
717330f729Sjoerg   llvm_unreachable("Impossible condition code!");
727330f729Sjoerg }
737330f729Sjoerg 
printRegName(raw_ostream & OS,unsigned RegNo) const747330f729Sjoerg void MipsInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const {
757330f729Sjoerg   OS << '$' << StringRef(getRegisterName(RegNo)).lower();
767330f729Sjoerg }
777330f729Sjoerg 
printInst(const MCInst * MI,uint64_t Address,StringRef Annot,const MCSubtargetInfo & STI,raw_ostream & O)78*82d56013Sjoerg void MipsInstPrinter::printInst(const MCInst *MI, uint64_t Address,
79*82d56013Sjoerg                                 StringRef Annot, const MCSubtargetInfo &STI,
80*82d56013Sjoerg                                 raw_ostream &O) {
817330f729Sjoerg   switch (MI->getOpcode()) {
827330f729Sjoerg   default:
837330f729Sjoerg     break;
847330f729Sjoerg   case Mips::RDHWR:
857330f729Sjoerg   case Mips::RDHWR64:
867330f729Sjoerg     O << "\t.set\tpush\n";
877330f729Sjoerg     O << "\t.set\tmips32r2\n";
887330f729Sjoerg     break;
897330f729Sjoerg   case Mips::Save16:
907330f729Sjoerg     O << "\tsave\t";
917330f729Sjoerg     printSaveRestore(MI, O);
927330f729Sjoerg     O << " # 16 bit inst\n";
937330f729Sjoerg     return;
947330f729Sjoerg   case Mips::SaveX16:
957330f729Sjoerg     O << "\tsave\t";
967330f729Sjoerg     printSaveRestore(MI, O);
977330f729Sjoerg     O << "\n";
987330f729Sjoerg     return;
997330f729Sjoerg   case Mips::Restore16:
1007330f729Sjoerg     O << "\trestore\t";
1017330f729Sjoerg     printSaveRestore(MI, O);
1027330f729Sjoerg     O << " # 16 bit inst\n";
1037330f729Sjoerg     return;
1047330f729Sjoerg   case Mips::RestoreX16:
1057330f729Sjoerg     O << "\trestore\t";
1067330f729Sjoerg     printSaveRestore(MI, O);
1077330f729Sjoerg     O << "\n";
1087330f729Sjoerg     return;
1097330f729Sjoerg   }
1107330f729Sjoerg 
1117330f729Sjoerg   // Try to print any aliases first.
112*82d56013Sjoerg   if (!printAliasInstr(MI, Address, O) && !printAlias(*MI, O))
113*82d56013Sjoerg     printInstruction(MI, Address, O);
1147330f729Sjoerg   printAnnotation(O, Annot);
1157330f729Sjoerg 
1167330f729Sjoerg   switch (MI->getOpcode()) {
1177330f729Sjoerg   default:
1187330f729Sjoerg     break;
1197330f729Sjoerg   case Mips::RDHWR:
1207330f729Sjoerg   case Mips::RDHWR64:
1217330f729Sjoerg     O << "\n\t.set\tpop";
1227330f729Sjoerg   }
1237330f729Sjoerg }
1247330f729Sjoerg 
printOperand(const MCInst * MI,unsigned OpNo,raw_ostream & O)1257330f729Sjoerg void MipsInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
1267330f729Sjoerg                                    raw_ostream &O) {
1277330f729Sjoerg   const MCOperand &Op = MI->getOperand(OpNo);
1287330f729Sjoerg   if (Op.isReg()) {
1297330f729Sjoerg     printRegName(O, Op.getReg());
1307330f729Sjoerg     return;
1317330f729Sjoerg   }
1327330f729Sjoerg 
1337330f729Sjoerg   if (Op.isImm()) {
1347330f729Sjoerg     O << formatImm(Op.getImm());
1357330f729Sjoerg     return;
1367330f729Sjoerg   }
1377330f729Sjoerg 
1387330f729Sjoerg   assert(Op.isExpr() && "unknown operand kind in printOperand");
1397330f729Sjoerg   Op.getExpr()->print(O, &MAI, true);
1407330f729Sjoerg }
1417330f729Sjoerg 
1427330f729Sjoerg template <unsigned Bits, unsigned Offset>
printUImm(const MCInst * MI,int opNum,raw_ostream & O)1437330f729Sjoerg void MipsInstPrinter::printUImm(const MCInst *MI, int opNum, raw_ostream &O) {
1447330f729Sjoerg   const MCOperand &MO = MI->getOperand(opNum);
1457330f729Sjoerg   if (MO.isImm()) {
1467330f729Sjoerg     uint64_t Imm = MO.getImm();
1477330f729Sjoerg     Imm -= Offset;
1487330f729Sjoerg     Imm &= (1 << Bits) - 1;
1497330f729Sjoerg     Imm += Offset;
1507330f729Sjoerg     O << formatImm(Imm);
1517330f729Sjoerg     return;
1527330f729Sjoerg   }
1537330f729Sjoerg 
1547330f729Sjoerg   printOperand(MI, opNum, O);
1557330f729Sjoerg }
1567330f729Sjoerg 
1577330f729Sjoerg void MipsInstPrinter::
printMemOperand(const MCInst * MI,int opNum,raw_ostream & O)1587330f729Sjoerg printMemOperand(const MCInst *MI, int opNum, raw_ostream &O) {
1597330f729Sjoerg   // Load/Store memory operands -- imm($reg)
1607330f729Sjoerg   // If PIC target the target is loaded as the
1617330f729Sjoerg   // pattern lw $25,%call16($28)
1627330f729Sjoerg 
1637330f729Sjoerg   // opNum can be invalid if instruction had reglist as operand.
1647330f729Sjoerg   // MemOperand is always last operand of instruction (base + offset).
1657330f729Sjoerg   switch (MI->getOpcode()) {
1667330f729Sjoerg   default:
1677330f729Sjoerg     break;
1687330f729Sjoerg   case Mips::SWM32_MM:
1697330f729Sjoerg   case Mips::LWM32_MM:
1707330f729Sjoerg   case Mips::SWM16_MM:
1717330f729Sjoerg   case Mips::SWM16_MMR6:
1727330f729Sjoerg   case Mips::LWM16_MM:
1737330f729Sjoerg   case Mips::LWM16_MMR6:
1747330f729Sjoerg     opNum = MI->getNumOperands() - 2;
1757330f729Sjoerg     break;
1767330f729Sjoerg   }
1777330f729Sjoerg 
1787330f729Sjoerg   printOperand(MI, opNum+1, O);
1797330f729Sjoerg   O << "(";
1807330f729Sjoerg   printOperand(MI, opNum, O);
1817330f729Sjoerg   O << ")";
1827330f729Sjoerg }
1837330f729Sjoerg 
1847330f729Sjoerg void MipsInstPrinter::
printMemOperandEA(const MCInst * MI,int opNum,raw_ostream & O)1857330f729Sjoerg printMemOperandEA(const MCInst *MI, int opNum, raw_ostream &O) {
1867330f729Sjoerg   // when using stack locations for not load/store instructions
1877330f729Sjoerg   // print the same way as all normal 3 operand instructions.
1887330f729Sjoerg   printOperand(MI, opNum, O);
1897330f729Sjoerg   O << ", ";
1907330f729Sjoerg   printOperand(MI, opNum+1, O);
1917330f729Sjoerg }
1927330f729Sjoerg 
1937330f729Sjoerg void MipsInstPrinter::
printFCCOperand(const MCInst * MI,int opNum,raw_ostream & O)1947330f729Sjoerg printFCCOperand(const MCInst *MI, int opNum, raw_ostream &O) {
1957330f729Sjoerg   const MCOperand& MO = MI->getOperand(opNum);
1967330f729Sjoerg   O << MipsFCCToString((Mips::CondCode)MO.getImm());
1977330f729Sjoerg }
1987330f729Sjoerg 
1997330f729Sjoerg void MipsInstPrinter::
printSHFMask(const MCInst * MI,int opNum,raw_ostream & O)2007330f729Sjoerg printSHFMask(const MCInst *MI, int opNum, raw_ostream &O) {
2017330f729Sjoerg   llvm_unreachable("TODO");
2027330f729Sjoerg }
2037330f729Sjoerg 
printAlias(const char * Str,const MCInst & MI,unsigned OpNo,raw_ostream & OS)2047330f729Sjoerg bool MipsInstPrinter::printAlias(const char *Str, const MCInst &MI,
2057330f729Sjoerg                                  unsigned OpNo, raw_ostream &OS) {
2067330f729Sjoerg   OS << "\t" << Str << "\t";
2077330f729Sjoerg   printOperand(&MI, OpNo, OS);
2087330f729Sjoerg   return true;
2097330f729Sjoerg }
2107330f729Sjoerg 
printAlias(const char * Str,const MCInst & MI,unsigned OpNo0,unsigned OpNo1,raw_ostream & OS)2117330f729Sjoerg bool MipsInstPrinter::printAlias(const char *Str, const MCInst &MI,
2127330f729Sjoerg                                  unsigned OpNo0, unsigned OpNo1,
2137330f729Sjoerg                                  raw_ostream &OS) {
2147330f729Sjoerg   printAlias(Str, MI, OpNo0, OS);
2157330f729Sjoerg   OS << ", ";
2167330f729Sjoerg   printOperand(&MI, OpNo1, OS);
2177330f729Sjoerg   return true;
2187330f729Sjoerg }
2197330f729Sjoerg 
printAlias(const MCInst & MI,raw_ostream & OS)2207330f729Sjoerg bool MipsInstPrinter::printAlias(const MCInst &MI, raw_ostream &OS) {
2217330f729Sjoerg   switch (MI.getOpcode()) {
2227330f729Sjoerg   case Mips::BEQ:
2237330f729Sjoerg   case Mips::BEQ_MM:
2247330f729Sjoerg     // beq $zero, $zero, $L2 => b $L2
2257330f729Sjoerg     // beq $r0, $zero, $L2 => beqz $r0, $L2
2267330f729Sjoerg     return (isReg<Mips::ZERO>(MI, 0) && isReg<Mips::ZERO>(MI, 1) &&
2277330f729Sjoerg             printAlias("b", MI, 2, OS)) ||
2287330f729Sjoerg            (isReg<Mips::ZERO>(MI, 1) && printAlias("beqz", MI, 0, 2, OS));
2297330f729Sjoerg   case Mips::BEQ64:
2307330f729Sjoerg     // beq $r0, $zero, $L2 => beqz $r0, $L2
2317330f729Sjoerg     return isReg<Mips::ZERO_64>(MI, 1) && printAlias("beqz", MI, 0, 2, OS);
2327330f729Sjoerg   case Mips::BNE:
2337330f729Sjoerg   case Mips::BNE_MM:
2347330f729Sjoerg     // bne $r0, $zero, $L2 => bnez $r0, $L2
2357330f729Sjoerg     return isReg<Mips::ZERO>(MI, 1) && printAlias("bnez", MI, 0, 2, OS);
2367330f729Sjoerg   case Mips::BNE64:
2377330f729Sjoerg     // bne $r0, $zero, $L2 => bnez $r0, $L2
2387330f729Sjoerg     return isReg<Mips::ZERO_64>(MI, 1) && printAlias("bnez", MI, 0, 2, OS);
2397330f729Sjoerg   case Mips::BGEZAL:
2407330f729Sjoerg     // bgezal $zero, $L1 => bal $L1
2417330f729Sjoerg     return isReg<Mips::ZERO>(MI, 0) && printAlias("bal", MI, 1, OS);
2427330f729Sjoerg   case Mips::BC1T:
2437330f729Sjoerg     // bc1t $fcc0, $L1 => bc1t $L1
2447330f729Sjoerg     return isReg<Mips::FCC0>(MI, 0) && printAlias("bc1t", MI, 1, OS);
2457330f729Sjoerg   case Mips::BC1F:
2467330f729Sjoerg     // bc1f $fcc0, $L1 => bc1f $L1
2477330f729Sjoerg     return isReg<Mips::FCC0>(MI, 0) && printAlias("bc1f", MI, 1, OS);
2487330f729Sjoerg   case Mips::JALR:
2497330f729Sjoerg     // jalr $ra, $r1 => jalr $r1
2507330f729Sjoerg     return isReg<Mips::RA>(MI, 0) && printAlias("jalr", MI, 1, OS);
2517330f729Sjoerg   case Mips::JALR64:
2527330f729Sjoerg     // jalr $ra, $r1 => jalr $r1
2537330f729Sjoerg     return isReg<Mips::RA_64>(MI, 0) && printAlias("jalr", MI, 1, OS);
2547330f729Sjoerg   case Mips::NOR:
2557330f729Sjoerg   case Mips::NOR_MM:
2567330f729Sjoerg   case Mips::NOR_MMR6:
2577330f729Sjoerg     // nor $r0, $r1, $zero => not $r0, $r1
2587330f729Sjoerg     return isReg<Mips::ZERO>(MI, 2) && printAlias("not", MI, 0, 1, OS);
2597330f729Sjoerg   case Mips::NOR64:
2607330f729Sjoerg     // nor $r0, $r1, $zero => not $r0, $r1
2617330f729Sjoerg     return isReg<Mips::ZERO_64>(MI, 2) && printAlias("not", MI, 0, 1, OS);
2627330f729Sjoerg   case Mips::OR:
2637330f729Sjoerg     // or $r0, $r1, $zero => move $r0, $r1
2647330f729Sjoerg     return isReg<Mips::ZERO>(MI, 2) && printAlias("move", MI, 0, 1, OS);
2657330f729Sjoerg   default: return false;
2667330f729Sjoerg   }
2677330f729Sjoerg }
2687330f729Sjoerg 
printSaveRestore(const MCInst * MI,raw_ostream & O)2697330f729Sjoerg void MipsInstPrinter::printSaveRestore(const MCInst *MI, raw_ostream &O) {
2707330f729Sjoerg   for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
2717330f729Sjoerg     if (i != 0) O << ", ";
2727330f729Sjoerg     if (MI->getOperand(i).isReg())
2737330f729Sjoerg       printRegName(O, MI->getOperand(i).getReg());
2747330f729Sjoerg     else
2757330f729Sjoerg       printUImm<16>(MI, i, O);
2767330f729Sjoerg   }
2777330f729Sjoerg }
2787330f729Sjoerg 
2797330f729Sjoerg void MipsInstPrinter::
printRegisterList(const MCInst * MI,int opNum,raw_ostream & O)2807330f729Sjoerg printRegisterList(const MCInst *MI, int opNum, raw_ostream &O) {
2817330f729Sjoerg   // - 2 because register List is always first operand of instruction and it is
2827330f729Sjoerg   // always followed by memory operand (base + offset).
2837330f729Sjoerg   for (int i = opNum, e = MI->getNumOperands() - 2; i != e; ++i) {
2847330f729Sjoerg     if (i != opNum)
2857330f729Sjoerg       O << ", ";
2867330f729Sjoerg     printRegName(O, MI->getOperand(i).getReg());
2877330f729Sjoerg   }
2887330f729Sjoerg }
289