1//===- MILexer.cpp - Machine instructions lexer implementation ------------===//
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// This file implements the lexing of machine instructions.
10//
11//===----------------------------------------------------------------------===//
12
13#include "MILexer.h"
14#include "llvm/ADT/StringExtras.h"
15#include "llvm/ADT/StringSwitch.h"
16#include "llvm/ADT/Twine.h"
17#include <cassert>
18#include <cctype>
19#include <string>
20
21using namespace llvm;
22
23namespace {
24
25using ErrorCallbackType =
26    function_ref<void(StringRef::iterator Loc, const Twine &)>;
27
28/// This class provides a way to iterate and get characters from the source
29/// string.
30class Cursor {
31  const char *Ptr = nullptr;
32  const char *End = nullptr;
33
34public:
35  Cursor(std::nullopt_t) {}
36
37  explicit Cursor(StringRef Str) {
38    Ptr = Str.data();
39    End = Ptr + Str.size();
40  }
41
42  bool isEOF() const { return Ptr == End; }
43
44  char peek(int I = 0) const { return End - Ptr <= I ? 0 : Ptr[I]; }
45
46  void advance(unsigned I = 1) { Ptr += I; }
47
48  StringRef remaining() const { return StringRef(Ptr, End - Ptr); }
49
50  StringRef upto(Cursor C) const {
51    assert(C.Ptr >= Ptr && C.Ptr <= End);
52    return StringRef(Ptr, C.Ptr - Ptr);
53  }
54
55  StringRef::iterator location() const { return Ptr; }
56
57  operator bool() const { return Ptr != nullptr; }
58};
59
60} // end anonymous namespace
61
62MIToken &MIToken::reset(TokenKind Kind, StringRef Range) {
63  this->Kind = Kind;
64  this->Range = Range;
65  return *this;
66}
67
68MIToken &MIToken::setStringValue(StringRef StrVal) {
69  StringValue = StrVal;
70  return *this;
71}
72
73MIToken &MIToken::setOwnedStringValue(std::string StrVal) {
74  StringValueStorage = std::move(StrVal);
75  StringValue = StringValueStorage;
76  return *this;
77}
78
79MIToken &MIToken::setIntegerValue(APSInt IntVal) {
80  this->IntVal = std::move(IntVal);
81  return *this;
82}
83
84/// Skip the leading whitespace characters and return the updated cursor.
85static Cursor skipWhitespace(Cursor C) {
86  while (isblank(C.peek()))
87    C.advance();
88  return C;
89}
90
91static bool isNewlineChar(char C) { return C == '\n' || C == '\r'; }
92
93/// Skip a line comment and return the updated cursor.
94static Cursor skipComment(Cursor C) {
95  if (C.peek() != ';')
96    return C;
97  while (!isNewlineChar(C.peek()) && !C.isEOF())
98    C.advance();
99  return C;
100}
101
102/// Machine operands can have comments, enclosed between /* and */.
103/// This eats up all tokens, including /* and */.
104static Cursor skipMachineOperandComment(Cursor C) {
105  if (C.peek() != '/' || C.peek(1) != '*')
106    return C;
107
108  while (C.peek() != '*' || C.peek(1) != '/')
109    C.advance();
110
111  C.advance();
112  C.advance();
113  return C;
114}
115
116/// Return true if the given character satisfies the following regular
117/// expression: [-a-zA-Z$._0-9]
118static bool isIdentifierChar(char C) {
119  return isalpha(C) || isdigit(C) || C == '_' || C == '-' || C == '.' ||
120         C == '$';
121}
122
123/// Unescapes the given string value.
124///
125/// Expects the string value to be quoted.
126static std::string unescapeQuotedString(StringRef Value) {
127  assert(Value.front() == '"' && Value.back() == '"');
128  Cursor C = Cursor(Value.substr(1, Value.size() - 2));
129
130  std::string Str;
131  Str.reserve(C.remaining().size());
132  while (!C.isEOF()) {
133    char Char = C.peek();
134    if (Char == '\\') {
135      if (C.peek(1) == '\\') {
136        // Two '\' become one
137        Str += '\\';
138        C.advance(2);
139        continue;
140      }
141      if (isxdigit(C.peek(1)) && isxdigit(C.peek(2))) {
142        Str += hexDigitValue(C.peek(1)) * 16 + hexDigitValue(C.peek(2));
143        C.advance(3);
144        continue;
145      }
146    }
147    Str += Char;
148    C.advance();
149  }
150  return Str;
151}
152
153/// Lex a string constant using the following regular expression: \"[^\"]*\"
154static Cursor lexStringConstant(Cursor C, ErrorCallbackType ErrorCallback) {
155  assert(C.peek() == '"');
156  for (C.advance(); C.peek() != '"'; C.advance()) {
157    if (C.isEOF() || isNewlineChar(C.peek())) {
158      ErrorCallback(
159          C.location(),
160          "end of machine instruction reached before the closing '\"'");
161      return std::nullopt;
162    }
163  }
164  C.advance();
165  return C;
166}
167
168static Cursor lexName(Cursor C, MIToken &Token, MIToken::TokenKind Type,
169                      unsigned PrefixLength, ErrorCallbackType ErrorCallback) {
170  auto Range = C;
171  C.advance(PrefixLength);
172  if (C.peek() == '"') {
173    if (Cursor R = lexStringConstant(C, ErrorCallback)) {
174      StringRef String = Range.upto(R);
175      Token.reset(Type, String)
176          .setOwnedStringValue(
177              unescapeQuotedString(String.drop_front(PrefixLength)));
178      return R;
179    }
180    Token.reset(MIToken::Error, Range.remaining());
181    return Range;
182  }
183  while (isIdentifierChar(C.peek()))
184    C.advance();
185  Token.reset(Type, Range.upto(C))
186      .setStringValue(Range.upto(C).drop_front(PrefixLength));
187  return C;
188}
189
190static MIToken::TokenKind getIdentifierKind(StringRef Identifier) {
191  return StringSwitch<MIToken::TokenKind>(Identifier)
192      .Case("_", MIToken::underscore)
193      .Case("implicit", MIToken::kw_implicit)
194      .Case("implicit-def", MIToken::kw_implicit_define)
195      .Case("def", MIToken::kw_def)
196      .Case("dead", MIToken::kw_dead)
197      .Case("killed", MIToken::kw_killed)
198      .Case("undef", MIToken::kw_undef)
199      .Case("internal", MIToken::kw_internal)
200      .Case("early-clobber", MIToken::kw_early_clobber)
201      .Case("debug-use", MIToken::kw_debug_use)
202      .Case("renamable", MIToken::kw_renamable)
203      .Case("tied-def", MIToken::kw_tied_def)
204      .Case("frame-setup", MIToken::kw_frame_setup)
205      .Case("frame-destroy", MIToken::kw_frame_destroy)
206      .Case("nnan", MIToken::kw_nnan)
207      .Case("ninf", MIToken::kw_ninf)
208      .Case("nsz", MIToken::kw_nsz)
209      .Case("arcp", MIToken::kw_arcp)
210      .Case("contract", MIToken::kw_contract)
211      .Case("afn", MIToken::kw_afn)
212      .Case("reassoc", MIToken::kw_reassoc)
213      .Case("nuw", MIToken::kw_nuw)
214      .Case("nsw", MIToken::kw_nsw)
215      .Case("exact", MIToken::kw_exact)
216      .Case("nofpexcept", MIToken::kw_nofpexcept)
217      .Case("unpredictable", MIToken::kw_unpredictable)
218      .Case("debug-location", MIToken::kw_debug_location)
219      .Case("debug-instr-number", MIToken::kw_debug_instr_number)
220      .Case("dbg-instr-ref", MIToken::kw_dbg_instr_ref)
221      .Case("same_value", MIToken::kw_cfi_same_value)
222      .Case("offset", MIToken::kw_cfi_offset)
223      .Case("rel_offset", MIToken::kw_cfi_rel_offset)
224      .Case("def_cfa_register", MIToken::kw_cfi_def_cfa_register)
225      .Case("def_cfa_offset", MIToken::kw_cfi_def_cfa_offset)
226      .Case("adjust_cfa_offset", MIToken::kw_cfi_adjust_cfa_offset)
227      .Case("escape", MIToken::kw_cfi_escape)
228      .Case("def_cfa", MIToken::kw_cfi_def_cfa)
229      .Case("llvm_def_aspace_cfa", MIToken::kw_cfi_llvm_def_aspace_cfa)
230      .Case("remember_state", MIToken::kw_cfi_remember_state)
231      .Case("restore", MIToken::kw_cfi_restore)
232      .Case("restore_state", MIToken::kw_cfi_restore_state)
233      .Case("undefined", MIToken::kw_cfi_undefined)
234      .Case("register", MIToken::kw_cfi_register)
235      .Case("window_save", MIToken::kw_cfi_window_save)
236      .Case("negate_ra_sign_state",
237            MIToken::kw_cfi_aarch64_negate_ra_sign_state)
238      .Case("blockaddress", MIToken::kw_blockaddress)
239      .Case("intrinsic", MIToken::kw_intrinsic)
240      .Case("target-index", MIToken::kw_target_index)
241      .Case("half", MIToken::kw_half)
242      .Case("float", MIToken::kw_float)
243      .Case("double", MIToken::kw_double)
244      .Case("x86_fp80", MIToken::kw_x86_fp80)
245      .Case("fp128", MIToken::kw_fp128)
246      .Case("ppc_fp128", MIToken::kw_ppc_fp128)
247      .Case("target-flags", MIToken::kw_target_flags)
248      .Case("volatile", MIToken::kw_volatile)
249      .Case("non-temporal", MIToken::kw_non_temporal)
250      .Case("dereferenceable", MIToken::kw_dereferenceable)
251      .Case("invariant", MIToken::kw_invariant)
252      .Case("align", MIToken::kw_align)
253      .Case("basealign", MIToken::kw_basealign)
254      .Case("addrspace", MIToken::kw_addrspace)
255      .Case("stack", MIToken::kw_stack)
256      .Case("got", MIToken::kw_got)
257      .Case("jump-table", MIToken::kw_jump_table)
258      .Case("constant-pool", MIToken::kw_constant_pool)
259      .Case("call-entry", MIToken::kw_call_entry)
260      .Case("custom", MIToken::kw_custom)
261      .Case("liveout", MIToken::kw_liveout)
262      .Case("landing-pad", MIToken::kw_landing_pad)
263      .Case("inlineasm-br-indirect-target",
264            MIToken::kw_inlineasm_br_indirect_target)
265      .Case("ehfunclet-entry", MIToken::kw_ehfunclet_entry)
266      .Case("liveins", MIToken::kw_liveins)
267      .Case("successors", MIToken::kw_successors)
268      .Case("floatpred", MIToken::kw_floatpred)
269      .Case("intpred", MIToken::kw_intpred)
270      .Case("shufflemask", MIToken::kw_shufflemask)
271      .Case("pre-instr-symbol", MIToken::kw_pre_instr_symbol)
272      .Case("post-instr-symbol", MIToken::kw_post_instr_symbol)
273      .Case("heap-alloc-marker", MIToken::kw_heap_alloc_marker)
274      .Case("pcsections", MIToken::kw_pcsections)
275      .Case("cfi-type", MIToken::kw_cfi_type)
276      .Case("bbsections", MIToken::kw_bbsections)
277      .Case("bb_id", MIToken::kw_bb_id)
278      .Case("unknown-size", MIToken::kw_unknown_size)
279      .Case("unknown-address", MIToken::kw_unknown_address)
280      .Case("distinct", MIToken::kw_distinct)
281      .Case("ir-block-address-taken", MIToken::kw_ir_block_address_taken)
282      .Case("machine-block-address-taken",
283            MIToken::kw_machine_block_address_taken)
284      .Case("call-frame-size", MIToken::kw_call_frame_size)
285      .Case("noconvergent", MIToken::kw_noconvergent)
286      .Default(MIToken::Identifier);
287}
288
289static Cursor maybeLexIdentifier(Cursor C, MIToken &Token) {
290  if (!isalpha(C.peek()) && C.peek() != '_')
291    return std::nullopt;
292  auto Range = C;
293  while (isIdentifierChar(C.peek()))
294    C.advance();
295  auto Identifier = Range.upto(C);
296  Token.reset(getIdentifierKind(Identifier), Identifier)
297      .setStringValue(Identifier);
298  return C;
299}
300
301static Cursor maybeLexMachineBasicBlock(Cursor C, MIToken &Token,
302                                        ErrorCallbackType ErrorCallback) {
303  bool IsReference = C.remaining().starts_with("%bb.");
304  if (!IsReference && !C.remaining().starts_with("bb."))
305    return std::nullopt;
306  auto Range = C;
307  unsigned PrefixLength = IsReference ? 4 : 3;
308  C.advance(PrefixLength); // Skip '%bb.' or 'bb.'
309  if (!isdigit(C.peek())) {
310    Token.reset(MIToken::Error, C.remaining());
311    ErrorCallback(C.location(), "expected a number after '%bb.'");
312    return C;
313  }
314  auto NumberRange = C;
315  while (isdigit(C.peek()))
316    C.advance();
317  StringRef Number = NumberRange.upto(C);
318  unsigned StringOffset = PrefixLength + Number.size(); // Drop '%bb.<id>'
319  // TODO: The format bb.<id>.<irname> is supported only when it's not a
320  // reference. Once we deprecate the format where the irname shows up, we
321  // should only lex forward if it is a reference.
322  if (C.peek() == '.') {
323    C.advance(); // Skip '.'
324    ++StringOffset;
325    while (isIdentifierChar(C.peek()))
326      C.advance();
327  }
328  Token.reset(IsReference ? MIToken::MachineBasicBlock
329                          : MIToken::MachineBasicBlockLabel,
330              Range.upto(C))
331      .setIntegerValue(APSInt(Number))
332      .setStringValue(Range.upto(C).drop_front(StringOffset));
333  return C;
334}
335
336static Cursor maybeLexIndex(Cursor C, MIToken &Token, StringRef Rule,
337                            MIToken::TokenKind Kind) {
338  if (!C.remaining().starts_with(Rule) || !isdigit(C.peek(Rule.size())))
339    return std::nullopt;
340  auto Range = C;
341  C.advance(Rule.size());
342  auto NumberRange = C;
343  while (isdigit(C.peek()))
344    C.advance();
345  Token.reset(Kind, Range.upto(C)).setIntegerValue(APSInt(NumberRange.upto(C)));
346  return C;
347}
348
349static Cursor maybeLexIndexAndName(Cursor C, MIToken &Token, StringRef Rule,
350                                   MIToken::TokenKind Kind) {
351  if (!C.remaining().starts_with(Rule) || !isdigit(C.peek(Rule.size())))
352    return std::nullopt;
353  auto Range = C;
354  C.advance(Rule.size());
355  auto NumberRange = C;
356  while (isdigit(C.peek()))
357    C.advance();
358  StringRef Number = NumberRange.upto(C);
359  unsigned StringOffset = Rule.size() + Number.size();
360  if (C.peek() == '.') {
361    C.advance();
362    ++StringOffset;
363    while (isIdentifierChar(C.peek()))
364      C.advance();
365  }
366  Token.reset(Kind, Range.upto(C))
367      .setIntegerValue(APSInt(Number))
368      .setStringValue(Range.upto(C).drop_front(StringOffset));
369  return C;
370}
371
372static Cursor maybeLexJumpTableIndex(Cursor C, MIToken &Token) {
373  return maybeLexIndex(C, Token, "%jump-table.", MIToken::JumpTableIndex);
374}
375
376static Cursor maybeLexStackObject(Cursor C, MIToken &Token) {
377  return maybeLexIndexAndName(C, Token, "%stack.", MIToken::StackObject);
378}
379
380static Cursor maybeLexFixedStackObject(Cursor C, MIToken &Token) {
381  return maybeLexIndex(C, Token, "%fixed-stack.", MIToken::FixedStackObject);
382}
383
384static Cursor maybeLexConstantPoolItem(Cursor C, MIToken &Token) {
385  return maybeLexIndex(C, Token, "%const.", MIToken::ConstantPoolItem);
386}
387
388static Cursor maybeLexSubRegisterIndex(Cursor C, MIToken &Token,
389                                       ErrorCallbackType ErrorCallback) {
390  const StringRef Rule = "%subreg.";
391  if (!C.remaining().starts_with(Rule))
392    return std::nullopt;
393  return lexName(C, Token, MIToken::SubRegisterIndex, Rule.size(),
394                 ErrorCallback);
395}
396
397static Cursor maybeLexIRBlock(Cursor C, MIToken &Token,
398                              ErrorCallbackType ErrorCallback) {
399  const StringRef Rule = "%ir-block.";
400  if (!C.remaining().starts_with(Rule))
401    return std::nullopt;
402  if (isdigit(C.peek(Rule.size())))
403    return maybeLexIndex(C, Token, Rule, MIToken::IRBlock);
404  return lexName(C, Token, MIToken::NamedIRBlock, Rule.size(), ErrorCallback);
405}
406
407static Cursor maybeLexIRValue(Cursor C, MIToken &Token,
408                              ErrorCallbackType ErrorCallback) {
409  const StringRef Rule = "%ir.";
410  if (!C.remaining().starts_with(Rule))
411    return std::nullopt;
412  if (isdigit(C.peek(Rule.size())))
413    return maybeLexIndex(C, Token, Rule, MIToken::IRValue);
414  return lexName(C, Token, MIToken::NamedIRValue, Rule.size(), ErrorCallback);
415}
416
417static Cursor maybeLexStringConstant(Cursor C, MIToken &Token,
418                                     ErrorCallbackType ErrorCallback) {
419  if (C.peek() != '"')
420    return std::nullopt;
421  return lexName(C, Token, MIToken::StringConstant, /*PrefixLength=*/0,
422                 ErrorCallback);
423}
424
425static Cursor lexVirtualRegister(Cursor C, MIToken &Token) {
426  auto Range = C;
427  C.advance(); // Skip '%'
428  auto NumberRange = C;
429  while (isdigit(C.peek()))
430    C.advance();
431  Token.reset(MIToken::VirtualRegister, Range.upto(C))
432      .setIntegerValue(APSInt(NumberRange.upto(C)));
433  return C;
434}
435
436/// Returns true for a character allowed in a register name.
437static bool isRegisterChar(char C) {
438  return isIdentifierChar(C) && C != '.';
439}
440
441static Cursor lexNamedVirtualRegister(Cursor C, MIToken &Token) {
442  Cursor Range = C;
443  C.advance(); // Skip '%'
444  while (isRegisterChar(C.peek()))
445    C.advance();
446  Token.reset(MIToken::NamedVirtualRegister, Range.upto(C))
447      .setStringValue(Range.upto(C).drop_front(1)); // Drop the '%'
448  return C;
449}
450
451static Cursor maybeLexRegister(Cursor C, MIToken &Token,
452                               ErrorCallbackType ErrorCallback) {
453  if (C.peek() != '%' && C.peek() != '$')
454    return std::nullopt;
455
456  if (C.peek() == '%') {
457    if (isdigit(C.peek(1)))
458      return lexVirtualRegister(C, Token);
459
460    if (isRegisterChar(C.peek(1)))
461      return lexNamedVirtualRegister(C, Token);
462
463    return std::nullopt;
464  }
465
466  assert(C.peek() == '$');
467  auto Range = C;
468  C.advance(); // Skip '$'
469  while (isRegisterChar(C.peek()))
470    C.advance();
471  Token.reset(MIToken::NamedRegister, Range.upto(C))
472      .setStringValue(Range.upto(C).drop_front(1)); // Drop the '$'
473  return C;
474}
475
476static Cursor maybeLexGlobalValue(Cursor C, MIToken &Token,
477                                  ErrorCallbackType ErrorCallback) {
478  if (C.peek() != '@')
479    return std::nullopt;
480  if (!isdigit(C.peek(1)))
481    return lexName(C, Token, MIToken::NamedGlobalValue, /*PrefixLength=*/1,
482                   ErrorCallback);
483  auto Range = C;
484  C.advance(1); // Skip the '@'
485  auto NumberRange = C;
486  while (isdigit(C.peek()))
487    C.advance();
488  Token.reset(MIToken::GlobalValue, Range.upto(C))
489      .setIntegerValue(APSInt(NumberRange.upto(C)));
490  return C;
491}
492
493static Cursor maybeLexExternalSymbol(Cursor C, MIToken &Token,
494                                     ErrorCallbackType ErrorCallback) {
495  if (C.peek() != '&')
496    return std::nullopt;
497  return lexName(C, Token, MIToken::ExternalSymbol, /*PrefixLength=*/1,
498                 ErrorCallback);
499}
500
501static Cursor maybeLexMCSymbol(Cursor C, MIToken &Token,
502                               ErrorCallbackType ErrorCallback) {
503  const StringRef Rule = "<mcsymbol ";
504  if (!C.remaining().starts_with(Rule))
505    return std::nullopt;
506  auto Start = C;
507  C.advance(Rule.size());
508
509  // Try a simple unquoted name.
510  if (C.peek() != '"') {
511    while (isIdentifierChar(C.peek()))
512      C.advance();
513    StringRef String = Start.upto(C).drop_front(Rule.size());
514    if (C.peek() != '>') {
515      ErrorCallback(C.location(),
516                    "expected the '<mcsymbol ...' to be closed by a '>'");
517      Token.reset(MIToken::Error, Start.remaining());
518      return Start;
519    }
520    C.advance();
521
522    Token.reset(MIToken::MCSymbol, Start.upto(C)).setStringValue(String);
523    return C;
524  }
525
526  // Otherwise lex out a quoted name.
527  Cursor R = lexStringConstant(C, ErrorCallback);
528  if (!R) {
529    ErrorCallback(C.location(),
530                  "unable to parse quoted string from opening quote");
531    Token.reset(MIToken::Error, Start.remaining());
532    return Start;
533  }
534  StringRef String = Start.upto(R).drop_front(Rule.size());
535  if (R.peek() != '>') {
536    ErrorCallback(R.location(),
537                  "expected the '<mcsymbol ...' to be closed by a '>'");
538    Token.reset(MIToken::Error, Start.remaining());
539    return Start;
540  }
541  R.advance();
542
543  Token.reset(MIToken::MCSymbol, Start.upto(R))
544      .setOwnedStringValue(unescapeQuotedString(String));
545  return R;
546}
547
548static bool isValidHexFloatingPointPrefix(char C) {
549  return C == 'H' || C == 'K' || C == 'L' || C == 'M' || C == 'R';
550}
551
552static Cursor lexFloatingPointLiteral(Cursor Range, Cursor C, MIToken &Token) {
553  C.advance();
554  // Skip over [0-9]*([eE][-+]?[0-9]+)?
555  while (isdigit(C.peek()))
556    C.advance();
557  if ((C.peek() == 'e' || C.peek() == 'E') &&
558      (isdigit(C.peek(1)) ||
559       ((C.peek(1) == '-' || C.peek(1) == '+') && isdigit(C.peek(2))))) {
560    C.advance(2);
561    while (isdigit(C.peek()))
562      C.advance();
563  }
564  Token.reset(MIToken::FloatingPointLiteral, Range.upto(C));
565  return C;
566}
567
568static Cursor maybeLexHexadecimalLiteral(Cursor C, MIToken &Token) {
569  if (C.peek() != '0' || (C.peek(1) != 'x' && C.peek(1) != 'X'))
570    return std::nullopt;
571  Cursor Range = C;
572  C.advance(2);
573  unsigned PrefLen = 2;
574  if (isValidHexFloatingPointPrefix(C.peek())) {
575    C.advance();
576    PrefLen++;
577  }
578  while (isxdigit(C.peek()))
579    C.advance();
580  StringRef StrVal = Range.upto(C);
581  if (StrVal.size() <= PrefLen)
582    return std::nullopt;
583  if (PrefLen == 2)
584    Token.reset(MIToken::HexLiteral, Range.upto(C));
585  else // It must be 3, which means that there was a floating-point prefix.
586    Token.reset(MIToken::FloatingPointLiteral, Range.upto(C));
587  return C;
588}
589
590static Cursor maybeLexNumericalLiteral(Cursor C, MIToken &Token) {
591  if (!isdigit(C.peek()) && (C.peek() != '-' || !isdigit(C.peek(1))))
592    return std::nullopt;
593  auto Range = C;
594  C.advance();
595  while (isdigit(C.peek()))
596    C.advance();
597  if (C.peek() == '.')
598    return lexFloatingPointLiteral(Range, C, Token);
599  StringRef StrVal = Range.upto(C);
600  Token.reset(MIToken::IntegerLiteral, StrVal).setIntegerValue(APSInt(StrVal));
601  return C;
602}
603
604static MIToken::TokenKind getMetadataKeywordKind(StringRef Identifier) {
605  return StringSwitch<MIToken::TokenKind>(Identifier)
606      .Case("!tbaa", MIToken::md_tbaa)
607      .Case("!alias.scope", MIToken::md_alias_scope)
608      .Case("!noalias", MIToken::md_noalias)
609      .Case("!range", MIToken::md_range)
610      .Case("!DIExpression", MIToken::md_diexpr)
611      .Case("!DILocation", MIToken::md_dilocation)
612      .Default(MIToken::Error);
613}
614
615static Cursor maybeLexExclaim(Cursor C, MIToken &Token,
616                              ErrorCallbackType ErrorCallback) {
617  if (C.peek() != '!')
618    return std::nullopt;
619  auto Range = C;
620  C.advance(1);
621  if (isdigit(C.peek()) || !isIdentifierChar(C.peek())) {
622    Token.reset(MIToken::exclaim, Range.upto(C));
623    return C;
624  }
625  while (isIdentifierChar(C.peek()))
626    C.advance();
627  StringRef StrVal = Range.upto(C);
628  Token.reset(getMetadataKeywordKind(StrVal), StrVal);
629  if (Token.isError())
630    ErrorCallback(Token.location(),
631                  "use of unknown metadata keyword '" + StrVal + "'");
632  return C;
633}
634
635static MIToken::TokenKind symbolToken(char C) {
636  switch (C) {
637  case ',':
638    return MIToken::comma;
639  case '.':
640    return MIToken::dot;
641  case '=':
642    return MIToken::equal;
643  case ':':
644    return MIToken::colon;
645  case '(':
646    return MIToken::lparen;
647  case ')':
648    return MIToken::rparen;
649  case '{':
650    return MIToken::lbrace;
651  case '}':
652    return MIToken::rbrace;
653  case '+':
654    return MIToken::plus;
655  case '-':
656    return MIToken::minus;
657  case '<':
658    return MIToken::less;
659  case '>':
660    return MIToken::greater;
661  default:
662    return MIToken::Error;
663  }
664}
665
666static Cursor maybeLexSymbol(Cursor C, MIToken &Token) {
667  MIToken::TokenKind Kind;
668  unsigned Length = 1;
669  if (C.peek() == ':' && C.peek(1) == ':') {
670    Kind = MIToken::coloncolon;
671    Length = 2;
672  } else
673    Kind = symbolToken(C.peek());
674  if (Kind == MIToken::Error)
675    return std::nullopt;
676  auto Range = C;
677  C.advance(Length);
678  Token.reset(Kind, Range.upto(C));
679  return C;
680}
681
682static Cursor maybeLexNewline(Cursor C, MIToken &Token) {
683  if (!isNewlineChar(C.peek()))
684    return std::nullopt;
685  auto Range = C;
686  C.advance();
687  Token.reset(MIToken::Newline, Range.upto(C));
688  return C;
689}
690
691static Cursor maybeLexEscapedIRValue(Cursor C, MIToken &Token,
692                                     ErrorCallbackType ErrorCallback) {
693  if (C.peek() != '`')
694    return std::nullopt;
695  auto Range = C;
696  C.advance();
697  auto StrRange = C;
698  while (C.peek() != '`') {
699    if (C.isEOF() || isNewlineChar(C.peek())) {
700      ErrorCallback(
701          C.location(),
702          "end of machine instruction reached before the closing '`'");
703      Token.reset(MIToken::Error, Range.remaining());
704      return C;
705    }
706    C.advance();
707  }
708  StringRef Value = StrRange.upto(C);
709  C.advance();
710  Token.reset(MIToken::QuotedIRValue, Range.upto(C)).setStringValue(Value);
711  return C;
712}
713
714StringRef llvm::lexMIToken(StringRef Source, MIToken &Token,
715                           ErrorCallbackType ErrorCallback) {
716  auto C = skipComment(skipWhitespace(Cursor(Source)));
717  if (C.isEOF()) {
718    Token.reset(MIToken::Eof, C.remaining());
719    return C.remaining();
720  }
721
722  C = skipMachineOperandComment(C);
723
724  if (Cursor R = maybeLexMachineBasicBlock(C, Token, ErrorCallback))
725    return R.remaining();
726  if (Cursor R = maybeLexIdentifier(C, Token))
727    return R.remaining();
728  if (Cursor R = maybeLexJumpTableIndex(C, Token))
729    return R.remaining();
730  if (Cursor R = maybeLexStackObject(C, Token))
731    return R.remaining();
732  if (Cursor R = maybeLexFixedStackObject(C, Token))
733    return R.remaining();
734  if (Cursor R = maybeLexConstantPoolItem(C, Token))
735    return R.remaining();
736  if (Cursor R = maybeLexSubRegisterIndex(C, Token, ErrorCallback))
737    return R.remaining();
738  if (Cursor R = maybeLexIRBlock(C, Token, ErrorCallback))
739    return R.remaining();
740  if (Cursor R = maybeLexIRValue(C, Token, ErrorCallback))
741    return R.remaining();
742  if (Cursor R = maybeLexRegister(C, Token, ErrorCallback))
743    return R.remaining();
744  if (Cursor R = maybeLexGlobalValue(C, Token, ErrorCallback))
745    return R.remaining();
746  if (Cursor R = maybeLexExternalSymbol(C, Token, ErrorCallback))
747    return R.remaining();
748  if (Cursor R = maybeLexMCSymbol(C, Token, ErrorCallback))
749    return R.remaining();
750  if (Cursor R = maybeLexHexadecimalLiteral(C, Token))
751    return R.remaining();
752  if (Cursor R = maybeLexNumericalLiteral(C, Token))
753    return R.remaining();
754  if (Cursor R = maybeLexExclaim(C, Token, ErrorCallback))
755    return R.remaining();
756  if (Cursor R = maybeLexSymbol(C, Token))
757    return R.remaining();
758  if (Cursor R = maybeLexNewline(C, Token))
759    return R.remaining();
760  if (Cursor R = maybeLexEscapedIRValue(C, Token, ErrorCallback))
761    return R.remaining();
762  if (Cursor R = maybeLexStringConstant(C, Token, ErrorCallback))
763    return R.remaining();
764
765  Token.reset(MIToken::Error, C.remaining());
766  ErrorCallback(C.location(),
767                Twine("unexpected character '") + Twine(C.peek()) + "'");
768  return C.remaining();
769}
770