10b57cec5SDimitry Andric //===- MCInstPrinter.cpp - Convert an MCInst to target assembly syntax ----===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "llvm/MC/MCInstPrinter.h"
100b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h"
110b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
120b57cec5SDimitry Andric #include "llvm/MC/MCAsmInfo.h"
13480093f4SDimitry Andric #include "llvm/MC/MCInst.h"
140b57cec5SDimitry Andric #include "llvm/MC/MCInstrInfo.h"
1581ad6265SDimitry Andric #include "llvm/MC/MCRegisterInfo.h"
16480093f4SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h"
170b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
180b57cec5SDimitry Andric #include "llvm/Support/Format.h"
190b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
200b57cec5SDimitry Andric #include <cinttypes>
210b57cec5SDimitry Andric #include <cstdint>
220b57cec5SDimitry Andric
230b57cec5SDimitry Andric using namespace llvm;
240b57cec5SDimitry Andric
dumpBytes(ArrayRef<uint8_t> bytes,raw_ostream & OS)250b57cec5SDimitry Andric void llvm::dumpBytes(ArrayRef<uint8_t> bytes, raw_ostream &OS) {
260b57cec5SDimitry Andric static const char hex_rep[] = "0123456789abcdef";
270b57cec5SDimitry Andric bool First = true;
280b57cec5SDimitry Andric for (char i: bytes) {
290b57cec5SDimitry Andric if (First)
300b57cec5SDimitry Andric First = false;
310b57cec5SDimitry Andric else
320b57cec5SDimitry Andric OS << ' ';
330b57cec5SDimitry Andric OS << hex_rep[(i & 0xF0) >> 4];
340b57cec5SDimitry Andric OS << hex_rep[i & 0xF];
350b57cec5SDimitry Andric }
360b57cec5SDimitry Andric }
370b57cec5SDimitry Andric
380b57cec5SDimitry Andric MCInstPrinter::~MCInstPrinter() = default;
390b57cec5SDimitry Andric
400b57cec5SDimitry Andric /// getOpcodeName - Return the name of the specified opcode enum (e.g.
410b57cec5SDimitry Andric /// "MOV32ri") or empty if we can't resolve it.
getOpcodeName(unsigned Opcode) const420b57cec5SDimitry Andric StringRef MCInstPrinter::getOpcodeName(unsigned Opcode) const {
430b57cec5SDimitry Andric return MII.getName(Opcode);
440b57cec5SDimitry Andric }
450b57cec5SDimitry Andric
printRegName(raw_ostream & OS,MCRegister Reg) const46bdd1243dSDimitry Andric void MCInstPrinter::printRegName(raw_ostream &OS, MCRegister Reg) const {
470b57cec5SDimitry Andric llvm_unreachable("Target should implement this");
480b57cec5SDimitry Andric }
490b57cec5SDimitry Andric
printAnnotation(raw_ostream & OS,StringRef Annot)500b57cec5SDimitry Andric void MCInstPrinter::printAnnotation(raw_ostream &OS, StringRef Annot) {
510b57cec5SDimitry Andric if (!Annot.empty()) {
520b57cec5SDimitry Andric if (CommentStream) {
530b57cec5SDimitry Andric (*CommentStream) << Annot;
540b57cec5SDimitry Andric // By definition (see MCInstPrinter.h), CommentStream must end with
550b57cec5SDimitry Andric // a newline after each comment.
560b57cec5SDimitry Andric if (Annot.back() != '\n')
570b57cec5SDimitry Andric (*CommentStream) << '\n';
580b57cec5SDimitry Andric } else
590b57cec5SDimitry Andric OS << " " << MAI.getCommentString() << " " << Annot;
600b57cec5SDimitry Andric }
610b57cec5SDimitry Andric }
620b57cec5SDimitry Andric
matchAliasCondition(const MCInst & MI,const MCSubtargetInfo * STI,const MCRegisterInfo & MRI,unsigned & OpIdx,const AliasMatchingData & M,const AliasPatternCond & C,bool & OrPredicateResult)63480093f4SDimitry Andric static bool matchAliasCondition(const MCInst &MI, const MCSubtargetInfo *STI,
64480093f4SDimitry Andric const MCRegisterInfo &MRI, unsigned &OpIdx,
65480093f4SDimitry Andric const AliasMatchingData &M,
665ffd83dbSDimitry Andric const AliasPatternCond &C,
675ffd83dbSDimitry Andric bool &OrPredicateResult) {
68480093f4SDimitry Andric // Feature tests are special, they don't consume operands.
69480093f4SDimitry Andric if (C.Kind == AliasPatternCond::K_Feature)
70480093f4SDimitry Andric return STI->getFeatureBits().test(C.Value);
71480093f4SDimitry Andric if (C.Kind == AliasPatternCond::K_NegFeature)
72480093f4SDimitry Andric return !STI->getFeatureBits().test(C.Value);
735ffd83dbSDimitry Andric // For feature tests where just one feature is required in a list, set the
745ffd83dbSDimitry Andric // predicate result bit to whether the expression will return true, and only
755ffd83dbSDimitry Andric // return the real result at the end of list marker.
765ffd83dbSDimitry Andric if (C.Kind == AliasPatternCond::K_OrFeature) {
775ffd83dbSDimitry Andric OrPredicateResult |= STI->getFeatureBits().test(C.Value);
785ffd83dbSDimitry Andric return true;
795ffd83dbSDimitry Andric }
805ffd83dbSDimitry Andric if (C.Kind == AliasPatternCond::K_OrNegFeature) {
815ffd83dbSDimitry Andric OrPredicateResult |= !(STI->getFeatureBits().test(C.Value));
825ffd83dbSDimitry Andric return true;
835ffd83dbSDimitry Andric }
845ffd83dbSDimitry Andric if (C.Kind == AliasPatternCond::K_EndOrFeatures) {
855ffd83dbSDimitry Andric bool Res = OrPredicateResult;
865ffd83dbSDimitry Andric OrPredicateResult = false;
875ffd83dbSDimitry Andric return Res;
885ffd83dbSDimitry Andric }
89480093f4SDimitry Andric
90480093f4SDimitry Andric // Get and consume an operand.
91480093f4SDimitry Andric const MCOperand &Opnd = MI.getOperand(OpIdx);
92480093f4SDimitry Andric ++OpIdx;
93480093f4SDimitry Andric
94480093f4SDimitry Andric // Check the specific condition for the operand.
95480093f4SDimitry Andric switch (C.Kind) {
96480093f4SDimitry Andric case AliasPatternCond::K_Imm:
97480093f4SDimitry Andric // Operand must be a specific immediate.
98480093f4SDimitry Andric return Opnd.isImm() && Opnd.getImm() == int32_t(C.Value);
99480093f4SDimitry Andric case AliasPatternCond::K_Reg:
100480093f4SDimitry Andric // Operand must be a specific register.
101480093f4SDimitry Andric return Opnd.isReg() && Opnd.getReg() == C.Value;
102480093f4SDimitry Andric case AliasPatternCond::K_TiedReg:
103480093f4SDimitry Andric // Operand must match the register of another operand.
104480093f4SDimitry Andric return Opnd.isReg() && Opnd.getReg() == MI.getOperand(C.Value).getReg();
105480093f4SDimitry Andric case AliasPatternCond::K_RegClass:
106480093f4SDimitry Andric // Operand must be a register in this class. Value is a register class id.
107480093f4SDimitry Andric return Opnd.isReg() && MRI.getRegClass(C.Value).contains(Opnd.getReg());
108480093f4SDimitry Andric case AliasPatternCond::K_Custom:
109480093f4SDimitry Andric // Operand must match some custom criteria.
110480093f4SDimitry Andric return M.ValidateMCOperand(Opnd, *STI, C.Value);
111480093f4SDimitry Andric case AliasPatternCond::K_Ignore:
112480093f4SDimitry Andric // Operand can be anything.
113480093f4SDimitry Andric return true;
114480093f4SDimitry Andric case AliasPatternCond::K_Feature:
115480093f4SDimitry Andric case AliasPatternCond::K_NegFeature:
1165ffd83dbSDimitry Andric case AliasPatternCond::K_OrFeature:
1175ffd83dbSDimitry Andric case AliasPatternCond::K_OrNegFeature:
1185ffd83dbSDimitry Andric case AliasPatternCond::K_EndOrFeatures:
119480093f4SDimitry Andric llvm_unreachable("handled earlier");
120480093f4SDimitry Andric }
121480093f4SDimitry Andric llvm_unreachable("invalid kind");
122480093f4SDimitry Andric }
123480093f4SDimitry Andric
matchAliasPatterns(const MCInst * MI,const MCSubtargetInfo * STI,const AliasMatchingData & M)124480093f4SDimitry Andric const char *MCInstPrinter::matchAliasPatterns(const MCInst *MI,
125480093f4SDimitry Andric const MCSubtargetInfo *STI,
126480093f4SDimitry Andric const AliasMatchingData &M) {
127480093f4SDimitry Andric // Binary search by opcode. Return false if there are no aliases for this
128480093f4SDimitry Andric // opcode.
129480093f4SDimitry Andric auto It = lower_bound(M.OpToPatterns, MI->getOpcode(),
130480093f4SDimitry Andric [](const PatternsForOpcode &L, unsigned Opcode) {
131480093f4SDimitry Andric return L.Opcode < Opcode;
132480093f4SDimitry Andric });
133480093f4SDimitry Andric if (It == M.OpToPatterns.end() || It->Opcode != MI->getOpcode())
134480093f4SDimitry Andric return nullptr;
135480093f4SDimitry Andric
136480093f4SDimitry Andric // Try all patterns for this opcode.
137480093f4SDimitry Andric uint32_t AsmStrOffset = ~0U;
138480093f4SDimitry Andric ArrayRef<AliasPattern> Patterns =
139480093f4SDimitry Andric M.Patterns.slice(It->PatternStart, It->NumPatterns);
140480093f4SDimitry Andric for (const AliasPattern &P : Patterns) {
141480093f4SDimitry Andric // Check operand count first.
142480093f4SDimitry Andric if (MI->getNumOperands() != P.NumOperands)
143480093f4SDimitry Andric return nullptr;
144480093f4SDimitry Andric
145480093f4SDimitry Andric // Test all conditions for this pattern.
146480093f4SDimitry Andric ArrayRef<AliasPatternCond> Conds =
147480093f4SDimitry Andric M.PatternConds.slice(P.AliasCondStart, P.NumConds);
148480093f4SDimitry Andric unsigned OpIdx = 0;
1495ffd83dbSDimitry Andric bool OrPredicateResult = false;
150480093f4SDimitry Andric if (llvm::all_of(Conds, [&](const AliasPatternCond &C) {
1515ffd83dbSDimitry Andric return matchAliasCondition(*MI, STI, MRI, OpIdx, M, C,
1525ffd83dbSDimitry Andric OrPredicateResult);
153480093f4SDimitry Andric })) {
154480093f4SDimitry Andric // If all conditions matched, use this asm string.
155480093f4SDimitry Andric AsmStrOffset = P.AsmStrOffset;
156480093f4SDimitry Andric break;
157480093f4SDimitry Andric }
158480093f4SDimitry Andric }
159480093f4SDimitry Andric
160480093f4SDimitry Andric // If no alias matched, don't print an alias.
161480093f4SDimitry Andric if (AsmStrOffset == ~0U)
162480093f4SDimitry Andric return nullptr;
163480093f4SDimitry Andric
164480093f4SDimitry Andric // Go to offset AsmStrOffset and use the null terminated string there. The
165480093f4SDimitry Andric // offset should point to the beginning of an alias string, so it should
166480093f4SDimitry Andric // either be zero or be preceded by a null byte.
167480093f4SDimitry Andric assert(AsmStrOffset < M.AsmStrings.size() &&
168480093f4SDimitry Andric (AsmStrOffset == 0 || M.AsmStrings[AsmStrOffset - 1] == '\0') &&
169480093f4SDimitry Andric "bad asm string offset");
170480093f4SDimitry Andric return M.AsmStrings.data() + AsmStrOffset;
171480093f4SDimitry Andric }
172480093f4SDimitry Andric
1730b57cec5SDimitry Andric // For asm-style hex (e.g. 0ffh) the first digit always has to be a number.
needsLeadingZero(uint64_t Value)1740b57cec5SDimitry Andric static bool needsLeadingZero(uint64_t Value)
1750b57cec5SDimitry Andric {
1760b57cec5SDimitry Andric while (Value)
1770b57cec5SDimitry Andric {
1780b57cec5SDimitry Andric uint64_t digit = (Value >> 60) & 0xf;
1790b57cec5SDimitry Andric if (digit != 0)
1800b57cec5SDimitry Andric return (digit >= 0xa);
1810b57cec5SDimitry Andric Value <<= 4;
1820b57cec5SDimitry Andric }
1830b57cec5SDimitry Andric return false;
1840b57cec5SDimitry Andric }
1850b57cec5SDimitry Andric
formatDec(int64_t Value) const1860b57cec5SDimitry Andric format_object<int64_t> MCInstPrinter::formatDec(int64_t Value) const {
1870b57cec5SDimitry Andric return format("%" PRId64, Value);
1880b57cec5SDimitry Andric }
1890b57cec5SDimitry Andric
formatHex(int64_t Value) const1900b57cec5SDimitry Andric format_object<int64_t> MCInstPrinter::formatHex(int64_t Value) const {
1910b57cec5SDimitry Andric switch (PrintHexStyle) {
1920b57cec5SDimitry Andric case HexStyle::C:
1938bcb0991SDimitry Andric if (Value < 0) {
1948bcb0991SDimitry Andric if (Value == std::numeric_limits<int64_t>::min())
1958bcb0991SDimitry Andric return format<int64_t>("-0x8000000000000000", Value);
1960b57cec5SDimitry Andric return format("-0x%" PRIx64, -Value);
1978bcb0991SDimitry Andric }
1980b57cec5SDimitry Andric return format("0x%" PRIx64, Value);
1990b57cec5SDimitry Andric case HexStyle::Asm:
2000b57cec5SDimitry Andric if (Value < 0) {
2018bcb0991SDimitry Andric if (Value == std::numeric_limits<int64_t>::min())
2028bcb0991SDimitry Andric return format<int64_t>("-8000000000000000h", Value);
2038bcb0991SDimitry Andric if (needsLeadingZero(-(uint64_t)(Value)))
2040b57cec5SDimitry Andric return format("-0%" PRIx64 "h", -Value);
2050b57cec5SDimitry Andric return format("-%" PRIx64 "h", -Value);
2068bcb0991SDimitry Andric }
2070b57cec5SDimitry Andric if (needsLeadingZero((uint64_t)(Value)))
2080b57cec5SDimitry Andric return format("0%" PRIx64 "h", Value);
2090b57cec5SDimitry Andric return format("%" PRIx64 "h", Value);
2100b57cec5SDimitry Andric }
2110b57cec5SDimitry Andric llvm_unreachable("unsupported print style");
2120b57cec5SDimitry Andric }
2130b57cec5SDimitry Andric
formatHex(uint64_t Value) const2140b57cec5SDimitry Andric format_object<uint64_t> MCInstPrinter::formatHex(uint64_t Value) const {
2150b57cec5SDimitry Andric switch(PrintHexStyle) {
2160b57cec5SDimitry Andric case HexStyle::C:
2170b57cec5SDimitry Andric return format("0x%" PRIx64, Value);
2180b57cec5SDimitry Andric case HexStyle::Asm:
2190b57cec5SDimitry Andric if (needsLeadingZero(Value))
2200b57cec5SDimitry Andric return format("0%" PRIx64 "h", Value);
2210b57cec5SDimitry Andric else
2220b57cec5SDimitry Andric return format("%" PRIx64 "h", Value);
2230b57cec5SDimitry Andric }
2240b57cec5SDimitry Andric llvm_unreachable("unsupported print style");
2250b57cec5SDimitry Andric }
226*5f757f3fSDimitry Andric
markup(raw_ostream & OS,Markup S) const227*5f757f3fSDimitry Andric MCInstPrinter::WithMarkup MCInstPrinter::markup(raw_ostream &OS,
228*5f757f3fSDimitry Andric Markup S) const {
229*5f757f3fSDimitry Andric return WithMarkup(OS, S, getUseMarkup(), getUseColor());
230*5f757f3fSDimitry Andric }
231*5f757f3fSDimitry Andric
WithMarkup(raw_ostream & OS,Markup M,bool EnableMarkup,bool EnableColor)232*5f757f3fSDimitry Andric MCInstPrinter::WithMarkup::WithMarkup(raw_ostream &OS, Markup M,
233*5f757f3fSDimitry Andric bool EnableMarkup, bool EnableColor)
234*5f757f3fSDimitry Andric : OS(OS), EnableMarkup(EnableMarkup), EnableColor(EnableColor) {
235*5f757f3fSDimitry Andric if (EnableColor) {
236*5f757f3fSDimitry Andric switch (M) {
237*5f757f3fSDimitry Andric case Markup::Immediate:
238*5f757f3fSDimitry Andric OS.changeColor(raw_ostream::RED);
239*5f757f3fSDimitry Andric break;
240*5f757f3fSDimitry Andric case Markup::Register:
241*5f757f3fSDimitry Andric OS.changeColor(raw_ostream::CYAN);
242*5f757f3fSDimitry Andric break;
243*5f757f3fSDimitry Andric case Markup::Target:
244*5f757f3fSDimitry Andric OS.changeColor(raw_ostream::YELLOW);
245*5f757f3fSDimitry Andric break;
246*5f757f3fSDimitry Andric case Markup::Memory:
247*5f757f3fSDimitry Andric OS.changeColor(raw_ostream::GREEN);
248*5f757f3fSDimitry Andric break;
249*5f757f3fSDimitry Andric }
250*5f757f3fSDimitry Andric }
251*5f757f3fSDimitry Andric
252*5f757f3fSDimitry Andric if (EnableMarkup) {
253*5f757f3fSDimitry Andric switch (M) {
254*5f757f3fSDimitry Andric case Markup::Immediate:
255*5f757f3fSDimitry Andric OS << "<imm:";
256*5f757f3fSDimitry Andric break;
257*5f757f3fSDimitry Andric case Markup::Register:
258*5f757f3fSDimitry Andric OS << "<reg:";
259*5f757f3fSDimitry Andric break;
260*5f757f3fSDimitry Andric case Markup::Target:
261*5f757f3fSDimitry Andric OS << "<target:";
262*5f757f3fSDimitry Andric break;
263*5f757f3fSDimitry Andric case Markup::Memory:
264*5f757f3fSDimitry Andric OS << "<mem:";
265*5f757f3fSDimitry Andric break;
266*5f757f3fSDimitry Andric }
267*5f757f3fSDimitry Andric }
268*5f757f3fSDimitry Andric }
269*5f757f3fSDimitry Andric
~WithMarkup()270*5f757f3fSDimitry Andric MCInstPrinter::WithMarkup::~WithMarkup() {
271*5f757f3fSDimitry Andric if (EnableMarkup)
272*5f757f3fSDimitry Andric OS << '>';
273*5f757f3fSDimitry Andric if (EnableColor)
274*5f757f3fSDimitry Andric OS.resetColor();
275*5f757f3fSDimitry Andric }
276