xref: /freebsd-src/contrib/llvm-project/llvm/lib/MC/MCInstPrinter.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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