191370c5dSAlex Lorenz //===- MILexer.cpp - Machine instructions lexer implementation ----------===//
291370c5dSAlex Lorenz //
391370c5dSAlex Lorenz //                     The LLVM Compiler Infrastructure
491370c5dSAlex Lorenz //
591370c5dSAlex Lorenz // This file is distributed under the University of Illinois Open Source
691370c5dSAlex Lorenz // License. See LICENSE.TXT for details.
791370c5dSAlex Lorenz //
891370c5dSAlex Lorenz //===----------------------------------------------------------------------===//
991370c5dSAlex Lorenz //
1091370c5dSAlex Lorenz // This file implements the lexing of machine instructions.
1191370c5dSAlex Lorenz //
1291370c5dSAlex Lorenz //===----------------------------------------------------------------------===//
1391370c5dSAlex Lorenz 
1491370c5dSAlex Lorenz #include "MILexer.h"
15b29554daSAlex Lorenz #include "llvm/ADT/StringExtras.h"
16cb268d46SAlex Lorenz #include "llvm/ADT/StringSwitch.h"
1791370c5dSAlex Lorenz #include "llvm/ADT/Twine.h"
1891370c5dSAlex Lorenz #include <cctype>
1991370c5dSAlex Lorenz 
2091370c5dSAlex Lorenz using namespace llvm;
2191370c5dSAlex Lorenz 
2291370c5dSAlex Lorenz namespace {
2391370c5dSAlex Lorenz 
2491370c5dSAlex Lorenz /// This class provides a way to iterate and get characters from the source
2591370c5dSAlex Lorenz /// string.
2691370c5dSAlex Lorenz class Cursor {
2791370c5dSAlex Lorenz   const char *Ptr;
2891370c5dSAlex Lorenz   const char *End;
2991370c5dSAlex Lorenz 
3091370c5dSAlex Lorenz public:
316c6c46e4SAlex Lorenz   Cursor(NoneType) : Ptr(nullptr), End(nullptr) {}
326c6c46e4SAlex Lorenz 
3391370c5dSAlex Lorenz   explicit Cursor(StringRef Str) {
3491370c5dSAlex Lorenz     Ptr = Str.data();
3591370c5dSAlex Lorenz     End = Ptr + Str.size();
3691370c5dSAlex Lorenz   }
3791370c5dSAlex Lorenz 
3891370c5dSAlex Lorenz   bool isEOF() const { return Ptr == End; }
3991370c5dSAlex Lorenz 
40c267b5f5SNAKAMURA Takumi   char peek(int I = 0) const { return End - Ptr <= I ? 0 : Ptr[I]; }
4191370c5dSAlex Lorenz 
4233f0aef3SAlex Lorenz   void advance(unsigned I = 1) { Ptr += I; }
4391370c5dSAlex Lorenz 
4491370c5dSAlex Lorenz   StringRef remaining() const { return StringRef(Ptr, End - Ptr); }
4591370c5dSAlex Lorenz 
4691370c5dSAlex Lorenz   StringRef upto(Cursor C) const {
4791370c5dSAlex Lorenz     assert(C.Ptr >= Ptr && C.Ptr <= End);
4891370c5dSAlex Lorenz     return StringRef(Ptr, C.Ptr - Ptr);
4991370c5dSAlex Lorenz   }
5091370c5dSAlex Lorenz 
5191370c5dSAlex Lorenz   StringRef::iterator location() const { return Ptr; }
526c6c46e4SAlex Lorenz 
536c6c46e4SAlex Lorenz   operator bool() const { return Ptr != nullptr; }
5491370c5dSAlex Lorenz };
5591370c5dSAlex Lorenz 
5691370c5dSAlex Lorenz } // end anonymous namespace
5791370c5dSAlex Lorenz 
583fb77686SAlex Lorenz MIToken &MIToken::reset(TokenKind Kind, StringRef Range) {
593fb77686SAlex Lorenz   this->Kind = Kind;
603fb77686SAlex Lorenz   this->Range = Range;
613fb77686SAlex Lorenz   return *this;
623fb77686SAlex Lorenz }
633fb77686SAlex Lorenz 
643fb77686SAlex Lorenz MIToken &MIToken::setStringValue(StringRef StrVal) {
653fb77686SAlex Lorenz   StringValue = StrVal;
663fb77686SAlex Lorenz   return *this;
673fb77686SAlex Lorenz }
683fb77686SAlex Lorenz 
693fb77686SAlex Lorenz MIToken &MIToken::setOwnedStringValue(std::string StrVal) {
703fb77686SAlex Lorenz   StringValueStorage = std::move(StrVal);
713fb77686SAlex Lorenz   StringValue = StringValueStorage;
723fb77686SAlex Lorenz   return *this;
733fb77686SAlex Lorenz }
743fb77686SAlex Lorenz 
753fb77686SAlex Lorenz MIToken &MIToken::setIntegerValue(APSInt IntVal) {
763fb77686SAlex Lorenz   this->IntVal = std::move(IntVal);
773fb77686SAlex Lorenz   return *this;
783fb77686SAlex Lorenz }
793fb77686SAlex Lorenz 
8091370c5dSAlex Lorenz /// Skip the leading whitespace characters and return the updated cursor.
8191370c5dSAlex Lorenz static Cursor skipWhitespace(Cursor C) {
825022f6bbSAlex Lorenz   while (isblank(C.peek()))
835022f6bbSAlex Lorenz     C.advance();
845022f6bbSAlex Lorenz   return C;
855022f6bbSAlex Lorenz }
865022f6bbSAlex Lorenz 
875022f6bbSAlex Lorenz static bool isNewlineChar(char C) { return C == '\n' || C == '\r'; }
885022f6bbSAlex Lorenz 
895022f6bbSAlex Lorenz /// Skip a line comment and return the updated cursor.
905022f6bbSAlex Lorenz static Cursor skipComment(Cursor C) {
915022f6bbSAlex Lorenz   if (C.peek() != ';')
925022f6bbSAlex Lorenz     return C;
935022f6bbSAlex Lorenz   while (!isNewlineChar(C.peek()) && !C.isEOF())
9491370c5dSAlex Lorenz     C.advance();
9591370c5dSAlex Lorenz   return C;
9691370c5dSAlex Lorenz }
9791370c5dSAlex Lorenz 
98484903ecSAlex Lorenz /// Return true if the given character satisfies the following regular
99484903ecSAlex Lorenz /// expression: [-a-zA-Z$._0-9]
10091370c5dSAlex Lorenz static bool isIdentifierChar(char C) {
101484903ecSAlex Lorenz   return isalpha(C) || isdigit(C) || C == '_' || C == '-' || C == '.' ||
102484903ecSAlex Lorenz          C == '$';
10391370c5dSAlex Lorenz }
10491370c5dSAlex Lorenz 
105970c12eaSAlex Lorenz /// Unescapes the given string value.
106970c12eaSAlex Lorenz ///
107970c12eaSAlex Lorenz /// Expects the string value to be quoted.
108970c12eaSAlex Lorenz static std::string unescapeQuotedString(StringRef Value) {
109b29554daSAlex Lorenz   assert(Value.front() == '"' && Value.back() == '"');
110b29554daSAlex Lorenz   Cursor C = Cursor(Value.substr(1, Value.size() - 2));
111b29554daSAlex Lorenz 
112970c12eaSAlex Lorenz   std::string Str;
113b29554daSAlex Lorenz   Str.reserve(C.remaining().size());
114b29554daSAlex Lorenz   while (!C.isEOF()) {
115b29554daSAlex Lorenz     char Char = C.peek();
116b29554daSAlex Lorenz     if (Char == '\\') {
117b29554daSAlex Lorenz       if (C.peek(1) == '\\') {
118b29554daSAlex Lorenz         // Two '\' become one
119b29554daSAlex Lorenz         Str += '\\';
120b29554daSAlex Lorenz         C.advance(2);
121b29554daSAlex Lorenz         continue;
122b29554daSAlex Lorenz       }
123b29554daSAlex Lorenz       if (isxdigit(C.peek(1)) && isxdigit(C.peek(2))) {
124b29554daSAlex Lorenz         Str += hexDigitValue(C.peek(1)) * 16 + hexDigitValue(C.peek(2));
125b29554daSAlex Lorenz         C.advance(3);
126b29554daSAlex Lorenz         continue;
127b29554daSAlex Lorenz       }
128b29554daSAlex Lorenz     }
129b29554daSAlex Lorenz     Str += Char;
130b29554daSAlex Lorenz     C.advance();
131b29554daSAlex Lorenz   }
132970c12eaSAlex Lorenz   return Str;
133b29554daSAlex Lorenz }
134b29554daSAlex Lorenz 
135b29554daSAlex Lorenz /// Lex a string constant using the following regular expression: \"[^\"]*\"
136b29554daSAlex Lorenz static Cursor lexStringConstant(
137b29554daSAlex Lorenz     Cursor C,
138b29554daSAlex Lorenz     function_ref<void(StringRef::iterator Loc, const Twine &)> ErrorCallback) {
139b29554daSAlex Lorenz   assert(C.peek() == '"');
140b29554daSAlex Lorenz   for (C.advance(); C.peek() != '"'; C.advance()) {
1415022f6bbSAlex Lorenz     if (C.isEOF() || isNewlineChar(C.peek())) {
142b29554daSAlex Lorenz       ErrorCallback(
143b29554daSAlex Lorenz           C.location(),
144b29554daSAlex Lorenz           "end of machine instruction reached before the closing '\"'");
145b29554daSAlex Lorenz       return None;
146b29554daSAlex Lorenz     }
147b29554daSAlex Lorenz   }
148b29554daSAlex Lorenz   C.advance();
149b29554daSAlex Lorenz   return C;
150b29554daSAlex Lorenz }
151b29554daSAlex Lorenz 
15282a1cfdcSAlex Lorenz static Cursor lexName(
153970c12eaSAlex Lorenz     Cursor C, MIToken &Token, MIToken::TokenKind Type, unsigned PrefixLength,
15482a1cfdcSAlex Lorenz     function_ref<void(StringRef::iterator Loc, const Twine &)> ErrorCallback) {
15582a1cfdcSAlex Lorenz   auto Range = C;
15682a1cfdcSAlex Lorenz   C.advance(PrefixLength);
15782a1cfdcSAlex Lorenz   if (C.peek() == '"') {
15882a1cfdcSAlex Lorenz     if (Cursor R = lexStringConstant(C, ErrorCallback)) {
159970c12eaSAlex Lorenz       StringRef String = Range.upto(R);
1603fb77686SAlex Lorenz       Token.reset(Type, String)
1613fb77686SAlex Lorenz           .setOwnedStringValue(
1623fb77686SAlex Lorenz               unescapeQuotedString(String.drop_front(PrefixLength)));
16382a1cfdcSAlex Lorenz       return R;
16482a1cfdcSAlex Lorenz     }
1653fb77686SAlex Lorenz     Token.reset(MIToken::Error, Range.remaining());
16682a1cfdcSAlex Lorenz     return Range;
16782a1cfdcSAlex Lorenz   }
16882a1cfdcSAlex Lorenz   while (isIdentifierChar(C.peek()))
16982a1cfdcSAlex Lorenz     C.advance();
1703fb77686SAlex Lorenz   Token.reset(Type, Range.upto(C))
1713fb77686SAlex Lorenz       .setStringValue(Range.upto(C).drop_front(PrefixLength));
17282a1cfdcSAlex Lorenz   return C;
17382a1cfdcSAlex Lorenz }
17482a1cfdcSAlex Lorenz 
17505e3882eSAlex Lorenz static Cursor maybeLexIntegerType(Cursor C, MIToken &Token) {
17605e3882eSAlex Lorenz   if (C.peek() != 'i' || !isdigit(C.peek(1)))
17705e3882eSAlex Lorenz     return None;
17805e3882eSAlex Lorenz   auto Range = C;
17905e3882eSAlex Lorenz   C.advance(); // Skip 'i'
18005e3882eSAlex Lorenz   while (isdigit(C.peek()))
18105e3882eSAlex Lorenz     C.advance();
1823fb77686SAlex Lorenz   Token.reset(MIToken::IntegerType, Range.upto(C));
18305e3882eSAlex Lorenz   return C;
18405e3882eSAlex Lorenz }
18505e3882eSAlex Lorenz 
186cb268d46SAlex Lorenz static MIToken::TokenKind getIdentifierKind(StringRef Identifier) {
187cb268d46SAlex Lorenz   return StringSwitch<MIToken::TokenKind>(Identifier)
188cb268d46SAlex Lorenz       .Case("_", MIToken::underscore)
189cb268d46SAlex Lorenz       .Case("implicit", MIToken::kw_implicit)
190cb268d46SAlex Lorenz       .Case("implicit-def", MIToken::kw_implicit_define)
191cbbfd0b1SAlex Lorenz       .Case("dead", MIToken::kw_dead)
192495ad879SAlex Lorenz       .Case("killed", MIToken::kw_killed)
1934d026b89SAlex Lorenz       .Case("undef", MIToken::kw_undef)
1941039fd1aSAlex Lorenz       .Case("internal", MIToken::kw_internal)
19501c1a5eeSAlex Lorenz       .Case("early-clobber", MIToken::kw_early_clobber)
1969075258bSAlex Lorenz       .Case("debug-use", MIToken::kw_debug_use)
197e5a44660SAlex Lorenz       .Case("frame-setup", MIToken::kw_frame_setup)
19846d760d1SAlex Lorenz       .Case("debug-location", MIToken::kw_debug_location)
199*577d271aSAlex Lorenz       .Case(".cfi_same_value", MIToken::kw_cfi_same_value)
2008cfc6867SAlex Lorenz       .Case(".cfi_offset", MIToken::kw_cfi_offset)
2015b0d5f6fSAlex Lorenz       .Case(".cfi_def_cfa_register", MIToken::kw_cfi_def_cfa_register)
202f4baeb51SAlex Lorenz       .Case(".cfi_def_cfa_offset", MIToken::kw_cfi_def_cfa_offset)
203b139323fSAlex Lorenz       .Case(".cfi_def_cfa", MIToken::kw_cfi_def_cfa)
204deb53490SAlex Lorenz       .Case("blockaddress", MIToken::kw_blockaddress)
205ef5c196fSAlex Lorenz       .Case("target-index", MIToken::kw_target_index)
206ad156fb6SAlex Lorenz       .Case("half", MIToken::kw_half)
207ad156fb6SAlex Lorenz       .Case("float", MIToken::kw_float)
208ad156fb6SAlex Lorenz       .Case("double", MIToken::kw_double)
209ad156fb6SAlex Lorenz       .Case("x86_fp80", MIToken::kw_x86_fp80)
210ad156fb6SAlex Lorenz       .Case("fp128", MIToken::kw_fp128)
211ad156fb6SAlex Lorenz       .Case("ppc_fp128", MIToken::kw_ppc_fp128)
21249873a83SAlex Lorenz       .Case("target-flags", MIToken::kw_target_flags)
213a518b796SAlex Lorenz       .Case("volatile", MIToken::kw_volatile)
21410fd0385SAlex Lorenz       .Case("non-temporal", MIToken::kw_non_temporal)
215dc8de2a6SAlex Lorenz       .Case("invariant", MIToken::kw_invariant)
21661420f79SAlex Lorenz       .Case("align", MIToken::kw_align)
21746e9558aSAlex Lorenz       .Case("stack", MIToken::kw_stack)
218d858f874SAlex Lorenz       .Case("got", MIToken::kw_got)
2194be56e93SAlex Lorenz       .Case("jump-table", MIToken::kw_jump_table)
22091097a3fSAlex Lorenz       .Case("constant-pool", MIToken::kw_constant_pool)
221b97c9ef4SAlex Lorenz       .Case("liveout", MIToken::kw_liveout)
2225022f6bbSAlex Lorenz       .Case("address-taken", MIToken::kw_address_taken)
2235022f6bbSAlex Lorenz       .Case("landing-pad", MIToken::kw_landing_pad)
2245022f6bbSAlex Lorenz       .Case("liveins", MIToken::kw_liveins)
2255022f6bbSAlex Lorenz       .Case("successors", MIToken::kw_successors)
226cb268d46SAlex Lorenz       .Default(MIToken::Identifier);
227cb268d46SAlex Lorenz }
228cb268d46SAlex Lorenz 
2296c6c46e4SAlex Lorenz static Cursor maybeLexIdentifier(Cursor C, MIToken &Token) {
230f4baeb51SAlex Lorenz   if (!isalpha(C.peek()) && C.peek() != '_' && C.peek() != '.')
2316c6c46e4SAlex Lorenz     return None;
23291370c5dSAlex Lorenz   auto Range = C;
23391370c5dSAlex Lorenz   while (isIdentifierChar(C.peek()))
23491370c5dSAlex Lorenz     C.advance();
23512b554e6SAlex Lorenz   auto Identifier = Range.upto(C);
2363fb77686SAlex Lorenz   Token.reset(getIdentifierKind(Identifier), Identifier)
2373fb77686SAlex Lorenz       .setStringValue(Identifier);
23891370c5dSAlex Lorenz   return C;
23991370c5dSAlex Lorenz }
24091370c5dSAlex Lorenz 
2416c6c46e4SAlex Lorenz static Cursor maybeLexMachineBasicBlock(
24233f0aef3SAlex Lorenz     Cursor C, MIToken &Token,
24333f0aef3SAlex Lorenz     function_ref<void(StringRef::iterator Loc, const Twine &)> ErrorCallback) {
2445022f6bbSAlex Lorenz   bool IsReference = C.remaining().startswith("%bb.");
2455022f6bbSAlex Lorenz   if (!IsReference && !C.remaining().startswith("bb."))
2466c6c46e4SAlex Lorenz     return None;
24733f0aef3SAlex Lorenz   auto Range = C;
2485022f6bbSAlex Lorenz   unsigned PrefixLength = IsReference ? 4 : 3;
2495022f6bbSAlex Lorenz   C.advance(PrefixLength); // Skip '%bb.' or 'bb.'
25033f0aef3SAlex Lorenz   if (!isdigit(C.peek())) {
2513fb77686SAlex Lorenz     Token.reset(MIToken::Error, C.remaining());
25233f0aef3SAlex Lorenz     ErrorCallback(C.location(), "expected a number after '%bb.'");
25333f0aef3SAlex Lorenz     return C;
25433f0aef3SAlex Lorenz   }
25533f0aef3SAlex Lorenz   auto NumberRange = C;
25633f0aef3SAlex Lorenz   while (isdigit(C.peek()))
25733f0aef3SAlex Lorenz     C.advance();
25833f0aef3SAlex Lorenz   StringRef Number = NumberRange.upto(C);
2595022f6bbSAlex Lorenz   unsigned StringOffset = PrefixLength + Number.size(); // Drop '%bb.<id>'
26033f0aef3SAlex Lorenz   if (C.peek() == '.') {
26133f0aef3SAlex Lorenz     C.advance(); // Skip '.'
26233f0aef3SAlex Lorenz     ++StringOffset;
26333f0aef3SAlex Lorenz     while (isIdentifierChar(C.peek()))
26433f0aef3SAlex Lorenz       C.advance();
26533f0aef3SAlex Lorenz   }
2665022f6bbSAlex Lorenz   Token.reset(IsReference ? MIToken::MachineBasicBlock
2675022f6bbSAlex Lorenz                           : MIToken::MachineBasicBlockLabel,
2685022f6bbSAlex Lorenz               Range.upto(C))
2693fb77686SAlex Lorenz       .setIntegerValue(APSInt(Number))
2703fb77686SAlex Lorenz       .setStringValue(Range.upto(C).drop_front(StringOffset));
27133f0aef3SAlex Lorenz   return C;
27233f0aef3SAlex Lorenz }
27333f0aef3SAlex Lorenz 
27431d70683SAlex Lorenz static Cursor maybeLexIndex(Cursor C, MIToken &Token, StringRef Rule,
27531d70683SAlex Lorenz                             MIToken::TokenKind Kind) {
27631d70683SAlex Lorenz   if (!C.remaining().startswith(Rule) || !isdigit(C.peek(Rule.size())))
27731d70683SAlex Lorenz     return None;
27831d70683SAlex Lorenz   auto Range = C;
27931d70683SAlex Lorenz   C.advance(Rule.size());
28031d70683SAlex Lorenz   auto NumberRange = C;
28131d70683SAlex Lorenz   while (isdigit(C.peek()))
28231d70683SAlex Lorenz     C.advance();
2833fb77686SAlex Lorenz   Token.reset(Kind, Range.upto(C)).setIntegerValue(APSInt(NumberRange.upto(C)));
28431d70683SAlex Lorenz   return C;
28531d70683SAlex Lorenz }
28631d70683SAlex Lorenz 
2877feaf7c6SAlex Lorenz static Cursor maybeLexIndexAndName(Cursor C, MIToken &Token, StringRef Rule,
2887feaf7c6SAlex Lorenz                                    MIToken::TokenKind Kind) {
2897feaf7c6SAlex Lorenz   if (!C.remaining().startswith(Rule) || !isdigit(C.peek(Rule.size())))
2907feaf7c6SAlex Lorenz     return None;
2917feaf7c6SAlex Lorenz   auto Range = C;
2927feaf7c6SAlex Lorenz   C.advance(Rule.size());
2937feaf7c6SAlex Lorenz   auto NumberRange = C;
2947feaf7c6SAlex Lorenz   while (isdigit(C.peek()))
2957feaf7c6SAlex Lorenz     C.advance();
2967feaf7c6SAlex Lorenz   StringRef Number = NumberRange.upto(C);
2977feaf7c6SAlex Lorenz   unsigned StringOffset = Rule.size() + Number.size();
2987feaf7c6SAlex Lorenz   if (C.peek() == '.') {
2997feaf7c6SAlex Lorenz     C.advance();
3007feaf7c6SAlex Lorenz     ++StringOffset;
3017feaf7c6SAlex Lorenz     while (isIdentifierChar(C.peek()))
3027feaf7c6SAlex Lorenz       C.advance();
3037feaf7c6SAlex Lorenz   }
3043fb77686SAlex Lorenz   Token.reset(Kind, Range.upto(C))
3053fb77686SAlex Lorenz       .setIntegerValue(APSInt(Number))
3063fb77686SAlex Lorenz       .setStringValue(Range.upto(C).drop_front(StringOffset));
3077feaf7c6SAlex Lorenz   return C;
3087feaf7c6SAlex Lorenz }
3097feaf7c6SAlex Lorenz 
31031d70683SAlex Lorenz static Cursor maybeLexJumpTableIndex(Cursor C, MIToken &Token) {
31131d70683SAlex Lorenz   return maybeLexIndex(C, Token, "%jump-table.", MIToken::JumpTableIndex);
31231d70683SAlex Lorenz }
31331d70683SAlex Lorenz 
3147feaf7c6SAlex Lorenz static Cursor maybeLexStackObject(Cursor C, MIToken &Token) {
3157feaf7c6SAlex Lorenz   return maybeLexIndexAndName(C, Token, "%stack.", MIToken::StackObject);
3167feaf7c6SAlex Lorenz }
3177feaf7c6SAlex Lorenz 
3187feaf7c6SAlex Lorenz static Cursor maybeLexFixedStackObject(Cursor C, MIToken &Token) {
3197feaf7c6SAlex Lorenz   return maybeLexIndex(C, Token, "%fixed-stack.", MIToken::FixedStackObject);
3207feaf7c6SAlex Lorenz }
3217feaf7c6SAlex Lorenz 
322ab980499SAlex Lorenz static Cursor maybeLexConstantPoolItem(Cursor C, MIToken &Token) {
323ab980499SAlex Lorenz   return maybeLexIndex(C, Token, "%const.", MIToken::ConstantPoolItem);
324ab980499SAlex Lorenz }
325ab980499SAlex Lorenz 
326deb53490SAlex Lorenz static Cursor maybeLexIRBlock(
327deb53490SAlex Lorenz     Cursor C, MIToken &Token,
328deb53490SAlex Lorenz     function_ref<void(StringRef::iterator Loc, const Twine &)> ErrorCallback) {
329deb53490SAlex Lorenz   const StringRef Rule = "%ir-block.";
330deb53490SAlex Lorenz   if (!C.remaining().startswith(Rule))
331deb53490SAlex Lorenz     return None;
332deb53490SAlex Lorenz   if (isdigit(C.peek(Rule.size())))
333deb53490SAlex Lorenz     return maybeLexIndex(C, Token, Rule, MIToken::IRBlock);
334970c12eaSAlex Lorenz   return lexName(C, Token, MIToken::NamedIRBlock, Rule.size(), ErrorCallback);
3358a1915b0SAlex Lorenz }
3368a1915b0SAlex Lorenz 
3374af7e610SAlex Lorenz static Cursor maybeLexIRValue(
3384af7e610SAlex Lorenz     Cursor C, MIToken &Token,
3394af7e610SAlex Lorenz     function_ref<void(StringRef::iterator Loc, const Twine &)> ErrorCallback) {
3404af7e610SAlex Lorenz   const StringRef Rule = "%ir.";
3414af7e610SAlex Lorenz   if (!C.remaining().startswith(Rule))
3424af7e610SAlex Lorenz     return None;
343970c12eaSAlex Lorenz   return lexName(C, Token, MIToken::NamedIRValue, Rule.size(), ErrorCallback);
3444af7e610SAlex Lorenz }
3454af7e610SAlex Lorenz 
34653464510SAlex Lorenz static Cursor lexVirtualRegister(Cursor C, MIToken &Token) {
34753464510SAlex Lorenz   auto Range = C;
34853464510SAlex Lorenz   C.advance(); // Skip '%'
34953464510SAlex Lorenz   auto NumberRange = C;
35053464510SAlex Lorenz   while (isdigit(C.peek()))
35153464510SAlex Lorenz     C.advance();
3523fb77686SAlex Lorenz   Token.reset(MIToken::VirtualRegister, Range.upto(C))
3533fb77686SAlex Lorenz       .setIntegerValue(APSInt(NumberRange.upto(C)));
35453464510SAlex Lorenz   return C;
35553464510SAlex Lorenz }
35653464510SAlex Lorenz 
3576c6c46e4SAlex Lorenz static Cursor maybeLexRegister(Cursor C, MIToken &Token) {
3586c6c46e4SAlex Lorenz   if (C.peek() != '%')
3596c6c46e4SAlex Lorenz     return None;
36053464510SAlex Lorenz   if (isdigit(C.peek(1)))
36153464510SAlex Lorenz     return lexVirtualRegister(C, Token);
362f3db51deSAlex Lorenz   auto Range = C;
363f3db51deSAlex Lorenz   C.advance(); // Skip '%'
364f3db51deSAlex Lorenz   while (isIdentifierChar(C.peek()))
365f3db51deSAlex Lorenz     C.advance();
3663fb77686SAlex Lorenz   Token.reset(MIToken::NamedRegister, Range.upto(C))
3673fb77686SAlex Lorenz       .setStringValue(Range.upto(C).drop_front(1)); // Drop the '%'
368f3db51deSAlex Lorenz   return C;
369f3db51deSAlex Lorenz }
370f3db51deSAlex Lorenz 
371c1fbb354SAlex Lorenz static Cursor maybeLexGlobalValue(
372c1fbb354SAlex Lorenz     Cursor C, MIToken &Token,
373c1fbb354SAlex Lorenz     function_ref<void(StringRef::iterator Loc, const Twine &)> ErrorCallback) {
374c1fbb354SAlex Lorenz   if (C.peek() != '@')
375c1fbb354SAlex Lorenz     return None;
376c1fbb354SAlex Lorenz   if (!isdigit(C.peek(1)))
377970c12eaSAlex Lorenz     return lexName(C, Token, MIToken::NamedGlobalValue, /*PrefixLength=*/1,
378c1fbb354SAlex Lorenz                    ErrorCallback);
379c1fbb354SAlex Lorenz   auto Range = C;
380c1fbb354SAlex Lorenz   C.advance(1); // Skip the '@'
381c1fbb354SAlex Lorenz   auto NumberRange = C;
382c1fbb354SAlex Lorenz   while (isdigit(C.peek()))
383c1fbb354SAlex Lorenz     C.advance();
3843fb77686SAlex Lorenz   Token.reset(MIToken::GlobalValue, Range.upto(C))
3853fb77686SAlex Lorenz       .setIntegerValue(APSInt(NumberRange.upto(C)));
386c1fbb354SAlex Lorenz   return C;
387c1fbb354SAlex Lorenz }
388c1fbb354SAlex Lorenz 
3896ede3744SAlex Lorenz static Cursor maybeLexExternalSymbol(
3906ede3744SAlex Lorenz     Cursor C, MIToken &Token,
3916ede3744SAlex Lorenz     function_ref<void(StringRef::iterator Loc, const Twine &)> ErrorCallback) {
3926ede3744SAlex Lorenz   if (C.peek() != '$')
3936ede3744SAlex Lorenz     return None;
394970c12eaSAlex Lorenz   return lexName(C, Token, MIToken::ExternalSymbol, /*PrefixLength=*/1,
395970c12eaSAlex Lorenz                  ErrorCallback);
3966ede3744SAlex Lorenz }
3976ede3744SAlex Lorenz 
398ad156fb6SAlex Lorenz static bool isValidHexFloatingPointPrefix(char C) {
399ad156fb6SAlex Lorenz   return C == 'H' || C == 'K' || C == 'L' || C == 'M';
400ad156fb6SAlex Lorenz }
401ad156fb6SAlex Lorenz 
402ad156fb6SAlex Lorenz static Cursor maybeLexHexFloatingPointLiteral(Cursor C, MIToken &Token) {
403ad156fb6SAlex Lorenz   if (C.peek() != '0' || C.peek(1) != 'x')
404ad156fb6SAlex Lorenz     return None;
405ad156fb6SAlex Lorenz   Cursor Range = C;
406ad156fb6SAlex Lorenz   C.advance(2); // Skip '0x'
407ad156fb6SAlex Lorenz   if (isValidHexFloatingPointPrefix(C.peek()))
408ad156fb6SAlex Lorenz     C.advance();
409ad156fb6SAlex Lorenz   while (isxdigit(C.peek()))
410ad156fb6SAlex Lorenz     C.advance();
4113fb77686SAlex Lorenz   Token.reset(MIToken::FloatingPointLiteral, Range.upto(C));
412ad156fb6SAlex Lorenz   return C;
413ad156fb6SAlex Lorenz }
414ad156fb6SAlex Lorenz 
415ad156fb6SAlex Lorenz static Cursor lexFloatingPointLiteral(Cursor Range, Cursor C, MIToken &Token) {
416ad156fb6SAlex Lorenz   C.advance();
417ad156fb6SAlex Lorenz   // Skip over [0-9]*([eE][-+]?[0-9]+)?
418ad156fb6SAlex Lorenz   while (isdigit(C.peek()))
419ad156fb6SAlex Lorenz     C.advance();
420ad156fb6SAlex Lorenz   if ((C.peek() == 'e' || C.peek() == 'E') &&
421ad156fb6SAlex Lorenz       (isdigit(C.peek(1)) ||
422ad156fb6SAlex Lorenz        ((C.peek(1) == '-' || C.peek(1) == '+') && isdigit(C.peek(2))))) {
423ad156fb6SAlex Lorenz     C.advance(2);
424ad156fb6SAlex Lorenz     while (isdigit(C.peek()))
425ad156fb6SAlex Lorenz       C.advance();
426ad156fb6SAlex Lorenz   }
4273fb77686SAlex Lorenz   Token.reset(MIToken::FloatingPointLiteral, Range.upto(C));
428ad156fb6SAlex Lorenz   return C;
429ad156fb6SAlex Lorenz }
430ad156fb6SAlex Lorenz 
431ad156fb6SAlex Lorenz static Cursor maybeLexNumericalLiteral(Cursor C, MIToken &Token) {
4326c6c46e4SAlex Lorenz   if (!isdigit(C.peek()) && (C.peek() != '-' || !isdigit(C.peek(1))))
4336c6c46e4SAlex Lorenz     return None;
434240fc1e0SAlex Lorenz   auto Range = C;
435240fc1e0SAlex Lorenz   C.advance();
436240fc1e0SAlex Lorenz   while (isdigit(C.peek()))
437240fc1e0SAlex Lorenz     C.advance();
438ad156fb6SAlex Lorenz   if (C.peek() == '.')
439ad156fb6SAlex Lorenz     return lexFloatingPointLiteral(Range, C, Token);
440240fc1e0SAlex Lorenz   StringRef StrVal = Range.upto(C);
4413fb77686SAlex Lorenz   Token.reset(MIToken::IntegerLiteral, StrVal).setIntegerValue(APSInt(StrVal));
442240fc1e0SAlex Lorenz   return C;
443240fc1e0SAlex Lorenz }
444240fc1e0SAlex Lorenz 
445f3db51deSAlex Lorenz static MIToken::TokenKind symbolToken(char C) {
446f3db51deSAlex Lorenz   switch (C) {
447f3db51deSAlex Lorenz   case ',':
448f3db51deSAlex Lorenz     return MIToken::comma;
449f3db51deSAlex Lorenz   case '=':
450f3db51deSAlex Lorenz     return MIToken::equal;
4512eacca86SAlex Lorenz   case ':':
4522eacca86SAlex Lorenz     return MIToken::colon;
45335e44469SAlex Lorenz   case '!':
45435e44469SAlex Lorenz     return MIToken::exclaim;
455deb53490SAlex Lorenz   case '(':
456deb53490SAlex Lorenz     return MIToken::lparen;
457deb53490SAlex Lorenz   case ')':
458deb53490SAlex Lorenz     return MIToken::rparen;
459f9a2b123SAlex Lorenz   case '{':
460f9a2b123SAlex Lorenz     return MIToken::lbrace;
461f9a2b123SAlex Lorenz   case '}':
462f9a2b123SAlex Lorenz     return MIToken::rbrace;
4635672a893SAlex Lorenz   case '+':
4645672a893SAlex Lorenz     return MIToken::plus;
4655672a893SAlex Lorenz   case '-':
4665672a893SAlex Lorenz     return MIToken::minus;
467f3db51deSAlex Lorenz   default:
468f3db51deSAlex Lorenz     return MIToken::Error;
469f3db51deSAlex Lorenz   }
470f3db51deSAlex Lorenz }
471f3db51deSAlex Lorenz 
4726c6c46e4SAlex Lorenz static Cursor maybeLexSymbol(Cursor C, MIToken &Token) {
4734af7e610SAlex Lorenz   MIToken::TokenKind Kind;
4744af7e610SAlex Lorenz   unsigned Length = 1;
4754af7e610SAlex Lorenz   if (C.peek() == ':' && C.peek(1) == ':') {
4764af7e610SAlex Lorenz     Kind = MIToken::coloncolon;
4774af7e610SAlex Lorenz     Length = 2;
4784af7e610SAlex Lorenz   } else
4794af7e610SAlex Lorenz     Kind = symbolToken(C.peek());
4806c6c46e4SAlex Lorenz   if (Kind == MIToken::Error)
4816c6c46e4SAlex Lorenz     return None;
482f3db51deSAlex Lorenz   auto Range = C;
4834af7e610SAlex Lorenz   C.advance(Length);
4843fb77686SAlex Lorenz   Token.reset(Kind, Range.upto(C));
485f3db51deSAlex Lorenz   return C;
486f3db51deSAlex Lorenz }
487f3db51deSAlex Lorenz 
4885022f6bbSAlex Lorenz static Cursor maybeLexNewline(Cursor C, MIToken &Token) {
4895022f6bbSAlex Lorenz   if (!isNewlineChar(C.peek()))
4905022f6bbSAlex Lorenz     return None;
4915022f6bbSAlex Lorenz   auto Range = C;
4925022f6bbSAlex Lorenz   C.advance();
4935022f6bbSAlex Lorenz   Token.reset(MIToken::Newline, Range.upto(C));
4945022f6bbSAlex Lorenz   return C;
4955022f6bbSAlex Lorenz }
4965022f6bbSAlex Lorenz 
49791370c5dSAlex Lorenz StringRef llvm::lexMIToken(
49891370c5dSAlex Lorenz     StringRef Source, MIToken &Token,
49991370c5dSAlex Lorenz     function_ref<void(StringRef::iterator Loc, const Twine &)> ErrorCallback) {
5005022f6bbSAlex Lorenz   auto C = skipComment(skipWhitespace(Cursor(Source)));
50191370c5dSAlex Lorenz   if (C.isEOF()) {
5023fb77686SAlex Lorenz     Token.reset(MIToken::Eof, C.remaining());
50391370c5dSAlex Lorenz     return C.remaining();
50491370c5dSAlex Lorenz   }
50591370c5dSAlex Lorenz 
50605e3882eSAlex Lorenz   if (Cursor R = maybeLexIntegerType(C, Token))
50705e3882eSAlex Lorenz     return R.remaining();
5086c6c46e4SAlex Lorenz   if (Cursor R = maybeLexMachineBasicBlock(C, Token, ErrorCallback))
5096c6c46e4SAlex Lorenz     return R.remaining();
5105022f6bbSAlex Lorenz   if (Cursor R = maybeLexIdentifier(C, Token))
5115022f6bbSAlex Lorenz     return R.remaining();
51231d70683SAlex Lorenz   if (Cursor R = maybeLexJumpTableIndex(C, Token))
51331d70683SAlex Lorenz     return R.remaining();
5147feaf7c6SAlex Lorenz   if (Cursor R = maybeLexStackObject(C, Token))
5157feaf7c6SAlex Lorenz     return R.remaining();
5167feaf7c6SAlex Lorenz   if (Cursor R = maybeLexFixedStackObject(C, Token))
5177feaf7c6SAlex Lorenz     return R.remaining();
518ab980499SAlex Lorenz   if (Cursor R = maybeLexConstantPoolItem(C, Token))
519ab980499SAlex Lorenz     return R.remaining();
520deb53490SAlex Lorenz   if (Cursor R = maybeLexIRBlock(C, Token, ErrorCallback))
5218a1915b0SAlex Lorenz     return R.remaining();
5224af7e610SAlex Lorenz   if (Cursor R = maybeLexIRValue(C, Token, ErrorCallback))
5234af7e610SAlex Lorenz     return R.remaining();
5246c6c46e4SAlex Lorenz   if (Cursor R = maybeLexRegister(C, Token))
5256c6c46e4SAlex Lorenz     return R.remaining();
526b29554daSAlex Lorenz   if (Cursor R = maybeLexGlobalValue(C, Token, ErrorCallback))
5276c6c46e4SAlex Lorenz     return R.remaining();
5286ede3744SAlex Lorenz   if (Cursor R = maybeLexExternalSymbol(C, Token, ErrorCallback))
5296ede3744SAlex Lorenz     return R.remaining();
530ad156fb6SAlex Lorenz   if (Cursor R = maybeLexHexFloatingPointLiteral(C, Token))
531ad156fb6SAlex Lorenz     return R.remaining();
532ad156fb6SAlex Lorenz   if (Cursor R = maybeLexNumericalLiteral(C, Token))
5336c6c46e4SAlex Lorenz     return R.remaining();
5346c6c46e4SAlex Lorenz   if (Cursor R = maybeLexSymbol(C, Token))
5356c6c46e4SAlex Lorenz     return R.remaining();
5365022f6bbSAlex Lorenz   if (Cursor R = maybeLexNewline(C, Token))
5375022f6bbSAlex Lorenz     return R.remaining();
5386c6c46e4SAlex Lorenz 
5393fb77686SAlex Lorenz   Token.reset(MIToken::Error, C.remaining());
54091370c5dSAlex Lorenz   ErrorCallback(C.location(),
5416c6c46e4SAlex Lorenz                 Twine("unexpected character '") + Twine(C.peek()) + "'");
54291370c5dSAlex Lorenz   return C.remaining();
54391370c5dSAlex Lorenz }
544