281 lines · cpp
1//===- MCInstPrinter.cpp - Convert an MCInst to target 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#include "llvm/MC/MCInstPrinter.h"10#include "llvm/ADT/ArrayRef.h"11#include "llvm/ADT/StringRef.h"12#include "llvm/MC/MCAsmInfo.h"13#include "llvm/MC/MCInst.h"14#include "llvm/MC/MCInstrInfo.h"15#include "llvm/MC/MCRegisterInfo.h"16#include "llvm/MC/MCSubtargetInfo.h"17#include "llvm/Support/ErrorHandling.h"18#include "llvm/Support/Format.h"19#include "llvm/Support/raw_ostream.h"20#include <cinttypes>21#include <cstdint>22 23using namespace llvm;24 25void llvm::dumpBytes(ArrayRef<uint8_t> bytes, raw_ostream &OS) {26 static const char hex_rep[] = "0123456789abcdef";27 bool First = true;28 for (char i: bytes) {29 if (First)30 First = false;31 else32 OS << ' ';33 OS << hex_rep[(i & 0xF0) >> 4];34 OS << hex_rep[i & 0xF];35 }36}37 38MCInstPrinter::~MCInstPrinter() = default;39 40/// getOpcodeName - Return the name of the specified opcode enum (e.g.41/// "MOV32ri") or empty if we can't resolve it.42StringRef MCInstPrinter::getOpcodeName(unsigned Opcode) const {43 return MII.getName(Opcode);44}45 46void MCInstPrinter::printRegName(raw_ostream &OS, MCRegister Reg) {47 llvm_unreachable("Target should implement this");48}49 50void MCInstPrinter::printAnnotation(raw_ostream &OS, StringRef Annot) {51 if (!Annot.empty()) {52 if (CommentStream) {53 (*CommentStream) << Annot;54 // By definition (see MCInstPrinter.h), CommentStream must end with55 // a newline after each comment.56 if (Annot.back() != '\n')57 (*CommentStream) << '\n';58 } else59 OS << " " << MAI.getCommentString() << " " << Annot;60 }61}62 63static bool matchAliasCondition(const MCInst &MI, const MCSubtargetInfo *STI,64 const MCRegisterInfo &MRI, unsigned &OpIdx,65 const AliasMatchingData &M,66 const AliasPatternCond &C,67 bool &OrPredicateResult) {68 // Feature tests are special, they don't consume operands.69 if (C.Kind == AliasPatternCond::K_Feature)70 return STI->getFeatureBits().test(C.Value);71 if (C.Kind == AliasPatternCond::K_NegFeature)72 return !STI->getFeatureBits().test(C.Value);73 // For feature tests where just one feature is required in a list, set the74 // predicate result bit to whether the expression will return true, and only75 // return the real result at the end of list marker.76 if (C.Kind == AliasPatternCond::K_OrFeature) {77 OrPredicateResult |= STI->getFeatureBits().test(C.Value);78 return true;79 }80 if (C.Kind == AliasPatternCond::K_OrNegFeature) {81 OrPredicateResult |= !(STI->getFeatureBits().test(C.Value));82 return true;83 }84 if (C.Kind == AliasPatternCond::K_EndOrFeatures) {85 bool Res = OrPredicateResult;86 OrPredicateResult = false;87 return Res;88 }89 90 // Get and consume an operand.91 const MCOperand &Opnd = MI.getOperand(OpIdx);92 ++OpIdx;93 94 // Check the specific condition for the operand.95 switch (C.Kind) {96 case AliasPatternCond::K_Imm:97 // Operand must be a specific immediate.98 return Opnd.isImm() && Opnd.getImm() == int32_t(C.Value);99 case AliasPatternCond::K_Reg:100 // Operand must be a specific register.101 return Opnd.isReg() && Opnd.getReg() == C.Value;102 case AliasPatternCond::K_TiedReg:103 // Operand must match the register of another operand.104 return Opnd.isReg() && Opnd.getReg() == MI.getOperand(C.Value).getReg();105 case AliasPatternCond::K_RegClass:106 // Operand must be a register in this class. Value is a register class id.107 return Opnd.isReg() && MRI.getRegClass(C.Value).contains(Opnd.getReg());108 case AliasPatternCond::K_Custom:109 // Operand must match some custom criteria.110 return M.ValidateMCOperand(Opnd, *STI, C.Value);111 case AliasPatternCond::K_Ignore:112 // Operand can be anything.113 return true;114 case AliasPatternCond::K_Feature:115 case AliasPatternCond::K_NegFeature:116 case AliasPatternCond::K_OrFeature:117 case AliasPatternCond::K_OrNegFeature:118 case AliasPatternCond::K_EndOrFeatures:119 llvm_unreachable("handled earlier");120 }121 llvm_unreachable("invalid kind");122}123 124const char *MCInstPrinter::matchAliasPatterns(const MCInst *MI,125 const MCSubtargetInfo *STI,126 const AliasMatchingData &M) {127 // Binary search by opcode. Return false if there are no aliases for this128 // opcode.129 auto It = lower_bound(M.OpToPatterns, MI->getOpcode(),130 [](const PatternsForOpcode &L, unsigned Opcode) {131 return L.Opcode < Opcode;132 });133 if (It == M.OpToPatterns.end() || It->Opcode != MI->getOpcode())134 return nullptr;135 136 // Try all patterns for this opcode.137 uint32_t AsmStrOffset = ~0U;138 ArrayRef<AliasPattern> Patterns =139 M.Patterns.slice(It->PatternStart, It->NumPatterns);140 for (const AliasPattern &P : Patterns) {141 // Check operand count first.142 if (MI->getNumOperands() != P.NumOperands)143 return nullptr;144 145 // Test all conditions for this pattern.146 ArrayRef<AliasPatternCond> Conds =147 M.PatternConds.slice(P.AliasCondStart, P.NumConds);148 unsigned OpIdx = 0;149 bool OrPredicateResult = false;150 if (llvm::all_of(Conds, [&](const AliasPatternCond &C) {151 return matchAliasCondition(*MI, STI, MRI, OpIdx, M, C,152 OrPredicateResult);153 })) {154 // If all conditions matched, use this asm string.155 AsmStrOffset = P.AsmStrOffset;156 break;157 }158 }159 160 // If no alias matched, don't print an alias.161 if (AsmStrOffset == ~0U)162 return nullptr;163 164 // Go to offset AsmStrOffset and use the null terminated string there. The165 // offset should point to the beginning of an alias string, so it should166 // either be zero or be preceded by a null byte.167 assert(AsmStrOffset < M.AsmStrings.size() &&168 (AsmStrOffset == 0 || M.AsmStrings[AsmStrOffset - 1] == '\0') &&169 "bad asm string offset");170 return M.AsmStrings.data() + AsmStrOffset;171}172 173// For asm-style hex (e.g. 0ffh) the first digit always has to be a number.174static bool needsLeadingZero(uint64_t Value)175{176 while (Value)177 {178 uint64_t digit = (Value >> 60) & 0xf;179 if (digit != 0)180 return (digit >= 0xa);181 Value <<= 4;182 }183 return false;184}185 186format_object<int64_t> MCInstPrinter::formatDec(int64_t Value) const {187 return format("%" PRId64, Value);188}189 190format_object<int64_t> MCInstPrinter::formatHex(int64_t Value) const {191 switch (PrintHexStyle) {192 case HexStyle::C:193 if (Value < 0) {194 if (Value == std::numeric_limits<int64_t>::min())195 return format<int64_t>("-0x8000000000000000", Value);196 return format("-0x%" PRIx64, -Value);197 }198 return format("0x%" PRIx64, Value);199 case HexStyle::Asm:200 if (Value < 0) {201 if (Value == std::numeric_limits<int64_t>::min())202 return format<int64_t>("-8000000000000000h", Value);203 if (needsLeadingZero(-(uint64_t)(Value)))204 return format("-0%" PRIx64 "h", -Value);205 return format("-%" PRIx64 "h", -Value);206 }207 if (needsLeadingZero((uint64_t)(Value)))208 return format("0%" PRIx64 "h", Value);209 return format("%" PRIx64 "h", Value);210 }211 llvm_unreachable("unsupported print style");212}213 214format_object<uint64_t> MCInstPrinter::formatHex(uint64_t Value) const {215 switch(PrintHexStyle) {216 case HexStyle::C:217 return format("0x%" PRIx64, Value);218 case HexStyle::Asm:219 if (needsLeadingZero(Value))220 return format("0%" PRIx64 "h", Value);221 else222 return format("%" PRIx64 "h", Value);223 }224 llvm_unreachable("unsupported print style");225}226 227MCInstPrinter::WithMarkup MCInstPrinter::markup(raw_ostream &OS, Markup S) {228 return WithMarkup(*this, OS, S, getUseMarkup(), getUseColor());229}230 231MCInstPrinter::WithMarkup::WithMarkup(MCInstPrinter &IP, raw_ostream &OS,232 Markup M, bool EnableMarkup,233 bool EnableColor)234 : IP(IP), OS(OS), EnableMarkup(EnableMarkup), EnableColor(EnableColor) {235 if (EnableColor) {236 raw_ostream::Colors Color = raw_ostream::Colors::RESET;237 switch (M) {238 case Markup::Immediate:239 Color = raw_ostream::RED;240 break;241 case Markup::Register:242 Color = raw_ostream::CYAN;243 break;244 case Markup::Target:245 Color = raw_ostream::YELLOW;246 break;247 case Markup::Memory:248 Color = raw_ostream::GREEN;249 break;250 }251 IP.ColorStack.push_back(Color);252 OS.changeColor(Color);253 }254 255 if (EnableMarkup) {256 switch (M) {257 case Markup::Immediate:258 OS << "<imm:";259 break;260 case Markup::Register:261 OS << "<reg:";262 break;263 case Markup::Target:264 OS << "<target:";265 break;266 case Markup::Memory:267 OS << "<mem:";268 break;269 }270 }271}272 273MCInstPrinter::WithMarkup::~WithMarkup() {274 if (EnableMarkup)275 OS << '>';276 if (!EnableColor)277 return;278 IP.ColorStack.pop_back();279 OS << IP.ColorStack.back();280}281