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-exception |
6 | // |
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 | |
23 | using namespace llvm; |
24 | |
25 | void 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 | else |
32 | OS << ' '; |
33 | OS << hex_rep[(i & 0xF0) >> 4]; |
34 | OS << hex_rep[i & 0xF]; |
35 | } |
36 | } |
37 | |
38 | MCInstPrinter::~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. |
42 | StringRef MCInstPrinter::getOpcodeName(unsigned Opcode) const { |
43 | return MII.getName(Opcode); |
44 | } |
45 | |
46 | void MCInstPrinter::printRegName(raw_ostream &OS, MCRegister Reg) const { |
47 | llvm_unreachable("Target should implement this" ); |
48 | } |
49 | |
50 | void 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 with |
55 | // a newline after each comment. |
56 | if (Annot.back() != '\n') |
57 | (*CommentStream) << '\n'; |
58 | } else |
59 | OS << " " << MAI.getCommentString() << " " << Annot; |
60 | } |
61 | } |
62 | |
63 | static 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(I: C.Value); |
71 | if (C.Kind == AliasPatternCond::K_NegFeature) |
72 | return !STI->getFeatureBits().test(I: C.Value); |
73 | // For feature tests where just one feature is required in a list, set the |
74 | // predicate result bit to whether the expression will return true, and only |
75 | // return the real result at the end of list marker. |
76 | if (C.Kind == AliasPatternCond::K_OrFeature) { |
77 | OrPredicateResult |= STI->getFeatureBits().test(I: C.Value); |
78 | return true; |
79 | } |
80 | if (C.Kind == AliasPatternCond::K_OrNegFeature) { |
81 | OrPredicateResult |= !(STI->getFeatureBits().test(I: 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(i: 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(i: 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(i: C.Value).contains(Reg: 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 | |
124 | const 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 this |
128 | // opcode. |
129 | auto It = lower_bound(Range: M.OpToPatterns, Value: MI->getOpcode(), |
130 | C: [](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(N: It->PatternStart, M: 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(N: P.AliasCondStart, M: P.NumConds); |
148 | unsigned OpIdx = 0; |
149 | bool OrPredicateResult = false; |
150 | if (llvm::all_of(Range&: Conds, P: [&](const AliasPatternCond &C) { |
151 | return matchAliasCondition(MI: *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. The |
165 | // offset should point to the beginning of an alias string, so it should |
166 | // 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. |
174 | static 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 | |
186 | format_object<int64_t> MCInstPrinter::formatDec(int64_t Value) const { |
187 | return format(Fmt: "%" PRId64, Vals: Value); |
188 | } |
189 | |
190 | format_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>(Fmt: "-0x8000000000000000" , Vals: Value); |
196 | return format(Fmt: "-0x%" PRIx64, Vals: -Value); |
197 | } |
198 | return format(Fmt: "0x%" PRIx64, Vals: Value); |
199 | case HexStyle::Asm: |
200 | if (Value < 0) { |
201 | if (Value == std::numeric_limits<int64_t>::min()) |
202 | return format<int64_t>(Fmt: "-8000000000000000h" , Vals: Value); |
203 | if (needsLeadingZero(Value: -(uint64_t)(Value))) |
204 | return format(Fmt: "-0%" PRIx64 "h" , Vals: -Value); |
205 | return format(Fmt: "-%" PRIx64 "h" , Vals: -Value); |
206 | } |
207 | if (needsLeadingZero(Value: (uint64_t)(Value))) |
208 | return format(Fmt: "0%" PRIx64 "h" , Vals: Value); |
209 | return format(Fmt: "%" PRIx64 "h" , Vals: Value); |
210 | } |
211 | llvm_unreachable("unsupported print style" ); |
212 | } |
213 | |
214 | format_object<uint64_t> MCInstPrinter::formatHex(uint64_t Value) const { |
215 | switch(PrintHexStyle) { |
216 | case HexStyle::C: |
217 | return format(Fmt: "0x%" PRIx64, Vals: Value); |
218 | case HexStyle::Asm: |
219 | if (needsLeadingZero(Value)) |
220 | return format(Fmt: "0%" PRIx64 "h" , Vals: Value); |
221 | else |
222 | return format(Fmt: "%" PRIx64 "h" , Vals: Value); |
223 | } |
224 | llvm_unreachable("unsupported print style" ); |
225 | } |
226 | |
227 | MCInstPrinter::WithMarkup MCInstPrinter::markup(raw_ostream &OS, |
228 | Markup S) const { |
229 | return WithMarkup(OS, S, getUseMarkup(), getUseColor()); |
230 | } |
231 | |
232 | MCInstPrinter::WithMarkup::WithMarkup(raw_ostream &OS, Markup M, |
233 | bool EnableMarkup, bool EnableColor) |
234 | : OS(OS), EnableMarkup(EnableMarkup), EnableColor(EnableColor) { |
235 | if (EnableColor) { |
236 | switch (M) { |
237 | case Markup::Immediate: |
238 | OS.changeColor(Color: raw_ostream::RED); |
239 | break; |
240 | case Markup::Register: |
241 | OS.changeColor(Color: raw_ostream::CYAN); |
242 | break; |
243 | case Markup::Target: |
244 | OS.changeColor(Color: raw_ostream::YELLOW); |
245 | break; |
246 | case Markup::Memory: |
247 | OS.changeColor(Color: raw_ostream::GREEN); |
248 | break; |
249 | } |
250 | } |
251 | |
252 | if (EnableMarkup) { |
253 | switch (M) { |
254 | case Markup::Immediate: |
255 | OS << "<imm:" ; |
256 | break; |
257 | case Markup::Register: |
258 | OS << "<reg:" ; |
259 | break; |
260 | case Markup::Target: |
261 | OS << "<target:" ; |
262 | break; |
263 | case Markup::Memory: |
264 | OS << "<mem:" ; |
265 | break; |
266 | } |
267 | } |
268 | } |
269 | |
270 | MCInstPrinter::WithMarkup::~WithMarkup() { |
271 | if (EnableMarkup) |
272 | OS << '>'; |
273 | if (EnableColor) |
274 | OS.resetColor(); |
275 | } |
276 | |