364 lines · cpp
1//===-- MipsInstPrinter.cpp - Convert Mips 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-exception6//7//===----------------------------------------------------------------------===//8//9// This class prints an Mips MCInst to a .s file.10//11//===----------------------------------------------------------------------===//12 13#include "MipsInstPrinter.h"14#include "Mips.h"15#include "llvm/ADT/StringExtras.h"16#include "llvm/MC/MCAsmInfo.h"17#include "llvm/MC/MCExpr.h"18#include "llvm/MC/MCInst.h"19#include "llvm/MC/MCInstrInfo.h"20#include "llvm/MC/MCSubtargetInfo.h"21#include "llvm/MC/MCSymbol.h"22#include "llvm/Support/ErrorHandling.h"23#include "llvm/Support/raw_ostream.h"24using namespace llvm;25 26#define DEBUG_TYPE "asm-printer"27 28#define PRINT_ALIAS_INSTR29#include "MipsGenAsmWriter.inc"30 31template<unsigned R>32static bool isReg(const MCInst &MI, unsigned OpNo) {33 assert(MI.getOperand(OpNo).isReg() && "Register operand expected.");34 return MI.getOperand(OpNo).getReg() == R;35}36 37const char* Mips::MipsFCCToString(Mips::CondCode CC) {38 switch (CC) {39 case FCOND_F:40 case FCOND_T: return "f";41 case FCOND_UN:42 case FCOND_OR: return "un";43 case FCOND_OEQ:44 case FCOND_UNE: return "eq";45 case FCOND_UEQ:46 case FCOND_ONE: return "ueq";47 case FCOND_OLT:48 case FCOND_UGE: return "olt";49 case FCOND_ULT:50 case FCOND_OGE: return "ult";51 case FCOND_OLE:52 case FCOND_UGT: return "ole";53 case FCOND_ULE:54 case FCOND_OGT: return "ule";55 case FCOND_SF:56 case FCOND_ST: return "sf";57 case FCOND_NGLE:58 case FCOND_GLE: return "ngle";59 case FCOND_SEQ:60 case FCOND_SNE: return "seq";61 case FCOND_NGL:62 case FCOND_GL: return "ngl";63 case FCOND_LT:64 case FCOND_NLT: return "lt";65 case FCOND_NGE:66 case FCOND_GE: return "nge";67 case FCOND_LE:68 case FCOND_NLE: return "le";69 case FCOND_NGT:70 case FCOND_GT: return "ngt";71 }72 llvm_unreachable("Impossible condition code!");73}74 75void MipsInstPrinter::printRegName(raw_ostream &OS, MCRegister Reg) {76 markup(OS, Markup::Register)77 << '$' << StringRef(getRegisterName(Reg)).lower();78}79 80void MipsInstPrinter::printInst(const MCInst *MI, uint64_t Address,81 StringRef Annot, const MCSubtargetInfo &STI,82 raw_ostream &O) {83 switch (MI->getOpcode()) {84 default:85 break;86 case Mips::RDHWR:87 case Mips::RDHWR64:88 O << "\t.set\tpush\n";89 O << "\t.set\tmips32r2\n";90 break;91 case Mips::Save16:92 O << "\tsave\t";93 printSaveRestore(MI, STI, O);94 O << " # 16 bit inst\n";95 return;96 case Mips::SaveX16:97 O << "\tsave\t";98 printSaveRestore(MI, STI, O);99 O << "\n";100 return;101 case Mips::Restore16:102 O << "\trestore\t";103 printSaveRestore(MI, STI, O);104 O << " # 16 bit inst\n";105 return;106 case Mips::RestoreX16:107 O << "\trestore\t";108 printSaveRestore(MI, STI, O);109 O << "\n";110 return;111 }112 113 // Try to print any aliases first.114 if (!printAliasInstr(MI, Address, STI, O) &&115 !printAlias(*MI, Address, STI, O))116 printInstruction(MI, Address, STI, O);117 printAnnotation(O, Annot);118 119 switch (MI->getOpcode()) {120 default:121 break;122 case Mips::RDHWR:123 case Mips::RDHWR64:124 O << "\n\t.set\tpop";125 }126}127 128void MipsInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,129 const MCSubtargetInfo &STI, raw_ostream &O) {130 const MCOperand &Op = MI->getOperand(OpNo);131 if (Op.isReg()) {132 printRegName(O, Op.getReg());133 return;134 }135 136 if (Op.isImm()) {137 markup(O, Markup::Immediate) << formatImm(Op.getImm());138 return;139 }140 141 assert(Op.isExpr() && "unknown operand kind in printOperand");142 MAI.printExpr(O, *Op.getExpr());143}144 145void MipsInstPrinter::printJumpOperand(const MCInst *MI, unsigned OpNo,146 const MCSubtargetInfo &STI,147 raw_ostream &O) {148 const MCOperand &Op = MI->getOperand(OpNo);149 if (!Op.isImm())150 return printOperand(MI, OpNo, STI, O);151 152 if (PrintBranchImmAsAddress)153 markup(O, Markup::Immediate) << formatHex(Op.getImm());154 else155 markup(O, Markup::Immediate) << formatImm(Op.getImm());156}157 158void MipsInstPrinter::printBranchOperand(const MCInst *MI, uint64_t Address,159 unsigned OpNo,160 const MCSubtargetInfo &STI,161 raw_ostream &O) {162 const MCOperand &Op = MI->getOperand(OpNo);163 if (!Op.isImm())164 return printOperand(MI, OpNo, STI, O);165 166 if (PrintBranchImmAsAddress) {167 uint64_t Target = Address + Op.getImm();168 if (STI.hasFeature(Mips::FeatureMips32))169 Target &= 0xffffffff;170 else if (STI.hasFeature(Mips::FeatureMips16))171 Target &= 0xffff;172 markup(O, Markup::Immediate) << formatHex(Target);173 } else {174 markup(O, Markup::Immediate) << formatImm(Op.getImm());175 }176}177 178template <unsigned Bits, unsigned Offset>179void MipsInstPrinter::printUImm(const MCInst *MI, int opNum,180 const MCSubtargetInfo &STI, raw_ostream &O) {181 const MCOperand &MO = MI->getOperand(opNum);182 if (MO.isImm()) {183 uint64_t Imm = MO.getImm();184 Imm -= Offset;185 Imm &= (1 << Bits) - 1;186 Imm += Offset;187 markup(O, Markup::Immediate) << formatImm(Imm);188 return;189 }190 191 printOperand(MI, opNum, STI, O);192}193 194void MipsInstPrinter::printMemOperand(const MCInst *MI, int opNum,195 const MCSubtargetInfo &STI,196 raw_ostream &O) {197 // Load/Store memory operands -- imm($reg)198 // If PIC target the target is loaded as the199 // pattern lw $25,%call16($28)200 201 // opNum can be invalid if instruction had reglist as operand.202 // MemOperand is always last operand of instruction (base + offset).203 switch (MI->getOpcode()) {204 default:205 break;206 case Mips::SWM32_MM:207 case Mips::LWM32_MM:208 case Mips::SWM16_MM:209 case Mips::SWM16_MMR6:210 case Mips::LWM16_MM:211 case Mips::LWM16_MMR6:212 opNum = MI->getNumOperands() - 2;213 break;214 }215 216 WithMarkup M = markup(O, Markup::Memory);217 printOperand(MI, opNum + 1, STI, O);218 O << "(";219 printOperand(MI, opNum, STI, O);220 O << ")";221}222 223void MipsInstPrinter::printMemOperandEA(const MCInst *MI, int opNum,224 const MCSubtargetInfo &STI,225 raw_ostream &O) {226 // when using stack locations for not load/store instructions227 // print the same way as all normal 3 operand instructions.228 printOperand(MI, opNum, STI, O);229 O << ", ";230 printOperand(MI, opNum + 1, STI, O);231}232 233void MipsInstPrinter::printFCCOperand(const MCInst *MI, int opNum,234 const MCSubtargetInfo & /* STI */,235 raw_ostream &O) {236 const MCOperand &MO = MI->getOperand(opNum);237 O << MipsFCCToString((Mips::CondCode)MO.getImm());238}239 240void MipsInstPrinter::241printSHFMask(const MCInst *MI, int opNum, raw_ostream &O) {242 llvm_unreachable("TODO");243}244 245bool MipsInstPrinter::printAlias(const char *Str, const MCInst &MI,246 uint64_t Address, unsigned OpNo,247 const MCSubtargetInfo &STI, raw_ostream &OS,248 bool IsBranch) {249 OS << "\t" << Str << "\t";250 if (IsBranch)251 printBranchOperand(&MI, Address, OpNo, STI, OS);252 else253 printOperand(&MI, OpNo, STI, OS);254 return true;255}256 257bool MipsInstPrinter::printAlias(const char *Str, const MCInst &MI,258 uint64_t Address, unsigned OpNo0,259 unsigned OpNo1, const MCSubtargetInfo &STI,260 raw_ostream &OS, bool IsBranch) {261 printAlias(Str, MI, Address, OpNo0, STI, OS, IsBranch);262 OS << ", ";263 if (IsBranch)264 printBranchOperand(&MI, Address, OpNo1, STI, OS);265 else266 printOperand(&MI, OpNo1, STI, OS);267 return true;268}269 270bool MipsInstPrinter::printAlias(const MCInst &MI, uint64_t Address,271 const MCSubtargetInfo &STI, raw_ostream &OS) {272 switch (MI.getOpcode()) {273 case Mips::BEQ:274 case Mips::BEQ_MM:275 // beq $zero, $zero, $L2 => b $L2276 // beq $r0, $zero, $L2 => beqz $r0, $L2277 return (isReg<Mips::ZERO>(MI, 0) && isReg<Mips::ZERO>(MI, 1) &&278 printAlias("b", MI, Address, 2, STI, OS, true)) ||279 (isReg<Mips::ZERO>(MI, 1) &&280 printAlias("beqz", MI, Address, 0, 2, STI, OS, true));281 case Mips::BEQ64:282 // beq $r0, $zero, $L2 => beqz $r0, $L2283 return isReg<Mips::ZERO_64>(MI, 1) &&284 printAlias("beqz", MI, Address, 0, 2, STI, OS, true);285 case Mips::BNE:286 case Mips::BNE_MM:287 // bne $r0, $zero, $L2 => bnez $r0, $L2288 return isReg<Mips::ZERO>(MI, 1) &&289 printAlias("bnez", MI, Address, 0, 2, STI, OS, true);290 case Mips::BNE64:291 // bne $r0, $zero, $L2 => bnez $r0, $L2292 return isReg<Mips::ZERO_64>(MI, 1) &&293 printAlias("bnez", MI, Address, 0, 2, STI, OS, true);294 case Mips::BGEZAL:295 // bgezal $zero, $L1 => bal $L1296 return isReg<Mips::ZERO>(MI, 0) &&297 printAlias("bal", MI, Address, 1, STI, OS, true);298 case Mips::BC1T:299 // bc1t $fcc0, $L1 => bc1t $L1300 return isReg<Mips::FCC0>(MI, 0) &&301 printAlias("bc1t", MI, Address, 1, STI, OS, true);302 case Mips::BC1F:303 // bc1f $fcc0, $L1 => bc1f $L1304 return isReg<Mips::FCC0>(MI, 0) &&305 printAlias("bc1f", MI, Address, 1, STI, OS, true);306 case Mips::JALR:307 // jalr $zero, $r1 => jr $r1308 // jalr $ra, $r1 => jalr $r1309 return (isReg<Mips::ZERO>(MI, 0) &&310 printAlias("jr", MI, Address, 1, STI, OS)) ||311 (isReg<Mips::RA>(MI, 0) &&312 printAlias("jalr", MI, Address, 1, STI, OS));313 case Mips::JALR64:314 // jalr $zero, $r1 => jr $r1315 // jalr $ra, $r1 => jalr $r1316 return (isReg<Mips::ZERO_64>(MI, 0) &&317 printAlias("jr", MI, Address, 1, STI, OS)) ||318 (isReg<Mips::RA_64>(MI, 0) &&319 printAlias("jalr", MI, Address, 1, STI, OS));320 case Mips::NOR:321 case Mips::NOR_MM:322 case Mips::NOR_MMR6:323 // nor $r0, $r1, $zero => not $r0, $r1324 return isReg<Mips::ZERO>(MI, 2) &&325 printAlias("not", MI, Address, 0, 1, STI, OS);326 case Mips::NOR64:327 // nor $r0, $r1, $zero => not $r0, $r1328 return isReg<Mips::ZERO_64>(MI, 2) &&329 printAlias("not", MI, Address, 0, 1, STI, OS);330 case Mips::OR:331 case Mips::ADDu:332 // or $r0, $r1, $zero => move $r0, $r1333 // addu $r0, $r1, $zero => move $r0, $r1334 return isReg<Mips::ZERO>(MI, 2) &&335 printAlias("move", MI, Address, 0, 1, STI, OS);336 default:337 return false;338 }339}340 341void MipsInstPrinter::printSaveRestore(const MCInst *MI,342 const MCSubtargetInfo &STI,343 raw_ostream &O) {344 for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {345 if (i != 0) O << ", ";346 if (MI->getOperand(i).isReg())347 printRegName(O, MI->getOperand(i).getReg());348 else349 printUImm<16>(MI, i, STI, O);350 }351}352 353void MipsInstPrinter::printRegisterList(const MCInst *MI, int opNum,354 const MCSubtargetInfo & /* STI */,355 raw_ostream &O) {356 // - 2 because register List is always first operand of instruction and it is357 // always followed by memory operand (base + offset).358 for (int i = opNum, e = MI->getNumOperands() - 2; i != e; ++i) {359 if (i != opNum)360 O << ", ";361 printRegName(O, MI->getOperand(i).getReg());362 }363}364