Path: blob/main/contrib/llvm-project/llvm/lib/Target/Mips/MCTargetDesc/MipsInstPrinter.cpp
35294 views
//===-- MipsInstPrinter.cpp - Convert Mips MCInst to assembly syntax ------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This class prints an Mips MCInst to a .s file.9//10//===----------------------------------------------------------------------===//1112#include "MipsInstPrinter.h"13#include "Mips.h"14#include "MipsMCExpr.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/MCSubtargetInfo.h"20#include "llvm/MC/MCSymbol.h"21#include "llvm/Support/ErrorHandling.h"22#include "llvm/Support/raw_ostream.h"23using namespace llvm;2425#define DEBUG_TYPE "asm-printer"2627#define PRINT_ALIAS_INSTR28#include "MipsGenAsmWriter.inc"2930template<unsigned R>31static bool isReg(const MCInst &MI, unsigned OpNo) {32assert(MI.getOperand(OpNo).isReg() && "Register operand expected.");33return MI.getOperand(OpNo).getReg() == R;34}3536const char* Mips::MipsFCCToString(Mips::CondCode CC) {37switch (CC) {38case FCOND_F:39case FCOND_T: return "f";40case FCOND_UN:41case FCOND_OR: return "un";42case FCOND_OEQ:43case FCOND_UNE: return "eq";44case FCOND_UEQ:45case FCOND_ONE: return "ueq";46case FCOND_OLT:47case FCOND_UGE: return "olt";48case FCOND_ULT:49case FCOND_OGE: return "ult";50case FCOND_OLE:51case FCOND_UGT: return "ole";52case FCOND_ULE:53case FCOND_OGT: return "ule";54case FCOND_SF:55case FCOND_ST: return "sf";56case FCOND_NGLE:57case FCOND_GLE: return "ngle";58case FCOND_SEQ:59case FCOND_SNE: return "seq";60case FCOND_NGL:61case FCOND_GL: return "ngl";62case FCOND_LT:63case FCOND_NLT: return "lt";64case FCOND_NGE:65case FCOND_GE: return "nge";66case FCOND_LE:67case FCOND_NLE: return "le";68case FCOND_NGT:69case FCOND_GT: return "ngt";70}71llvm_unreachable("Impossible condition code!");72}7374void MipsInstPrinter::printRegName(raw_ostream &OS, MCRegister Reg) const {75markup(OS, Markup::Register)76<< '$' << StringRef(getRegisterName(Reg)).lower();77}7879void MipsInstPrinter::printInst(const MCInst *MI, uint64_t Address,80StringRef Annot, const MCSubtargetInfo &STI,81raw_ostream &O) {82switch (MI->getOpcode()) {83default:84break;85case Mips::RDHWR:86case Mips::RDHWR64:87O << "\t.set\tpush\n";88O << "\t.set\tmips32r2\n";89break;90case Mips::Save16:91O << "\tsave\t";92printSaveRestore(MI, STI, O);93O << " # 16 bit inst\n";94return;95case Mips::SaveX16:96O << "\tsave\t";97printSaveRestore(MI, STI, O);98O << "\n";99return;100case Mips::Restore16:101O << "\trestore\t";102printSaveRestore(MI, STI, O);103O << " # 16 bit inst\n";104return;105case Mips::RestoreX16:106O << "\trestore\t";107printSaveRestore(MI, STI, O);108O << "\n";109return;110}111112// Try to print any aliases first.113if (!printAliasInstr(MI, Address, STI, O) &&114!printAlias(*MI, Address, STI, O))115printInstruction(MI, Address, STI, O);116printAnnotation(O, Annot);117118switch (MI->getOpcode()) {119default:120break;121case Mips::RDHWR:122case Mips::RDHWR64:123O << "\n\t.set\tpop";124}125}126127void MipsInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,128const MCSubtargetInfo &STI, raw_ostream &O) {129const MCOperand &Op = MI->getOperand(OpNo);130if (Op.isReg()) {131printRegName(O, Op.getReg());132return;133}134135if (Op.isImm()) {136markup(O, Markup::Immediate) << formatImm(Op.getImm());137return;138}139140assert(Op.isExpr() && "unknown operand kind in printOperand");141Op.getExpr()->print(O, &MAI, true);142}143144void MipsInstPrinter::printJumpOperand(const MCInst *MI, unsigned OpNo,145const MCSubtargetInfo &STI,146raw_ostream &O) {147const MCOperand &Op = MI->getOperand(OpNo);148if (!Op.isImm())149return printOperand(MI, OpNo, STI, O);150151if (PrintBranchImmAsAddress)152markup(O, Markup::Immediate) << formatHex(Op.getImm());153else154markup(O, Markup::Immediate) << formatImm(Op.getImm());155}156157void MipsInstPrinter::printBranchOperand(const MCInst *MI, uint64_t Address,158unsigned OpNo,159const MCSubtargetInfo &STI,160raw_ostream &O) {161const MCOperand &Op = MI->getOperand(OpNo);162if (!Op.isImm())163return printOperand(MI, OpNo, STI, O);164165if (PrintBranchImmAsAddress) {166uint64_t Target = Address + Op.getImm();167if (STI.hasFeature(Mips::FeatureMips32))168Target &= 0xffffffff;169else if (STI.hasFeature(Mips::FeatureMips16))170Target &= 0xffff;171markup(O, Markup::Immediate) << formatHex(Target);172} else {173markup(O, Markup::Immediate) << formatImm(Op.getImm());174}175}176177template <unsigned Bits, unsigned Offset>178void MipsInstPrinter::printUImm(const MCInst *MI, int opNum,179const MCSubtargetInfo &STI, raw_ostream &O) {180const MCOperand &MO = MI->getOperand(opNum);181if (MO.isImm()) {182uint64_t Imm = MO.getImm();183Imm -= Offset;184Imm &= (1 << Bits) - 1;185Imm += Offset;186markup(O, Markup::Immediate) << formatImm(Imm);187return;188}189190printOperand(MI, opNum, STI, O);191}192193void MipsInstPrinter::printMemOperand(const MCInst *MI, int opNum,194const MCSubtargetInfo &STI,195raw_ostream &O) {196// Load/Store memory operands -- imm($reg)197// If PIC target the target is loaded as the198// pattern lw $25,%call16($28)199200// opNum can be invalid if instruction had reglist as operand.201// MemOperand is always last operand of instruction (base + offset).202switch (MI->getOpcode()) {203default:204break;205case Mips::SWM32_MM:206case Mips::LWM32_MM:207case Mips::SWM16_MM:208case Mips::SWM16_MMR6:209case Mips::LWM16_MM:210case Mips::LWM16_MMR6:211opNum = MI->getNumOperands() - 2;212break;213}214215WithMarkup M = markup(O, Markup::Memory);216printOperand(MI, opNum + 1, STI, O);217O << "(";218printOperand(MI, opNum, STI, O);219O << ")";220}221222void MipsInstPrinter::printMemOperandEA(const MCInst *MI, int opNum,223const MCSubtargetInfo &STI,224raw_ostream &O) {225// when using stack locations for not load/store instructions226// print the same way as all normal 3 operand instructions.227printOperand(MI, opNum, STI, O);228O << ", ";229printOperand(MI, opNum + 1, STI, O);230}231232void MipsInstPrinter::printFCCOperand(const MCInst *MI, int opNum,233const MCSubtargetInfo & /* STI */,234raw_ostream &O) {235const MCOperand &MO = MI->getOperand(opNum);236O << MipsFCCToString((Mips::CondCode)MO.getImm());237}238239void MipsInstPrinter::240printSHFMask(const MCInst *MI, int opNum, raw_ostream &O) {241llvm_unreachable("TODO");242}243244bool MipsInstPrinter::printAlias(const char *Str, const MCInst &MI,245uint64_t Address, unsigned OpNo,246const MCSubtargetInfo &STI, raw_ostream &OS,247bool IsBranch) {248OS << "\t" << Str << "\t";249if (IsBranch)250printBranchOperand(&MI, Address, OpNo, STI, OS);251else252printOperand(&MI, OpNo, STI, OS);253return true;254}255256bool MipsInstPrinter::printAlias(const char *Str, const MCInst &MI,257uint64_t Address, unsigned OpNo0,258unsigned OpNo1, const MCSubtargetInfo &STI,259raw_ostream &OS, bool IsBranch) {260printAlias(Str, MI, Address, OpNo0, STI, OS, IsBranch);261OS << ", ";262if (IsBranch)263printBranchOperand(&MI, Address, OpNo1, STI, OS);264else265printOperand(&MI, OpNo1, STI, OS);266return true;267}268269bool MipsInstPrinter::printAlias(const MCInst &MI, uint64_t Address,270const MCSubtargetInfo &STI, raw_ostream &OS) {271switch (MI.getOpcode()) {272case Mips::BEQ:273case Mips::BEQ_MM:274// beq $zero, $zero, $L2 => b $L2275// beq $r0, $zero, $L2 => beqz $r0, $L2276return (isReg<Mips::ZERO>(MI, 0) && isReg<Mips::ZERO>(MI, 1) &&277printAlias("b", MI, Address, 2, STI, OS, true)) ||278(isReg<Mips::ZERO>(MI, 1) &&279printAlias("beqz", MI, Address, 0, 2, STI, OS, true));280case Mips::BEQ64:281// beq $r0, $zero, $L2 => beqz $r0, $L2282return isReg<Mips::ZERO_64>(MI, 1) &&283printAlias("beqz", MI, Address, 0, 2, STI, OS, true);284case Mips::BNE:285case Mips::BNE_MM:286// bne $r0, $zero, $L2 => bnez $r0, $L2287return isReg<Mips::ZERO>(MI, 1) &&288printAlias("bnez", MI, Address, 0, 2, STI, OS, true);289case Mips::BNE64:290// bne $r0, $zero, $L2 => bnez $r0, $L2291return isReg<Mips::ZERO_64>(MI, 1) &&292printAlias("bnez", MI, Address, 0, 2, STI, OS, true);293case Mips::BGEZAL:294// bgezal $zero, $L1 => bal $L1295return isReg<Mips::ZERO>(MI, 0) &&296printAlias("bal", MI, Address, 1, STI, OS, true);297case Mips::BC1T:298// bc1t $fcc0, $L1 => bc1t $L1299return isReg<Mips::FCC0>(MI, 0) &&300printAlias("bc1t", MI, Address, 1, STI, OS, true);301case Mips::BC1F:302// bc1f $fcc0, $L1 => bc1f $L1303return isReg<Mips::FCC0>(MI, 0) &&304printAlias("bc1f", MI, Address, 1, STI, OS, true);305case Mips::JALR:306// jalr $zero, $r1 => jr $r1307// jalr $ra, $r1 => jalr $r1308return (isReg<Mips::ZERO>(MI, 0) &&309printAlias("jr", MI, Address, 1, STI, OS)) ||310(isReg<Mips::RA>(MI, 0) &&311printAlias("jalr", MI, Address, 1, STI, OS));312case Mips::JALR64:313// jalr $zero, $r1 => jr $r1314// jalr $ra, $r1 => jalr $r1315return (isReg<Mips::ZERO_64>(MI, 0) &&316printAlias("jr", MI, Address, 1, STI, OS)) ||317(isReg<Mips::RA_64>(MI, 0) &&318printAlias("jalr", MI, Address, 1, STI, OS));319case Mips::NOR:320case Mips::NOR_MM:321case Mips::NOR_MMR6:322// nor $r0, $r1, $zero => not $r0, $r1323return isReg<Mips::ZERO>(MI, 2) &&324printAlias("not", MI, Address, 0, 1, STI, OS);325case Mips::NOR64:326// nor $r0, $r1, $zero => not $r0, $r1327return isReg<Mips::ZERO_64>(MI, 2) &&328printAlias("not", MI, Address, 0, 1, STI, OS);329case Mips::OR:330case Mips::ADDu:331// or $r0, $r1, $zero => move $r0, $r1332// addu $r0, $r1, $zero => move $r0, $r1333return isReg<Mips::ZERO>(MI, 2) &&334printAlias("move", MI, Address, 0, 1, STI, OS);335default:336return false;337}338}339340void MipsInstPrinter::printSaveRestore(const MCInst *MI,341const MCSubtargetInfo &STI,342raw_ostream &O) {343for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {344if (i != 0) O << ", ";345if (MI->getOperand(i).isReg())346printRegName(O, MI->getOperand(i).getReg());347else348printUImm<16>(MI, i, STI, O);349}350}351352void MipsInstPrinter::printRegisterList(const MCInst *MI, int opNum,353const MCSubtargetInfo & /* STI */,354raw_ostream &O) {355// - 2 because register List is always first operand of instruction and it is356// always followed by memory operand (base + offset).357for (int i = opNum, e = MI->getNumOperands() - 2; i != e; ++i) {358if (i != opNum)359O << ", ";360printRegName(O, MI->getOperand(i).getReg());361}362}363364365