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)
191e66a7ccfSAlex Lorenz       .Case("def", MIToken::kw_def)
192cbbfd0b1SAlex Lorenz       .Case("dead", MIToken::kw_dead)
193495ad879SAlex Lorenz       .Case("killed", MIToken::kw_killed)
1944d026b89SAlex Lorenz       .Case("undef", MIToken::kw_undef)
1951039fd1aSAlex Lorenz       .Case("internal", MIToken::kw_internal)
19601c1a5eeSAlex Lorenz       .Case("early-clobber", MIToken::kw_early_clobber)
1979075258bSAlex Lorenz       .Case("debug-use", MIToken::kw_debug_use)
1985ef93b0cSAlex Lorenz       .Case("tied-def", MIToken::kw_tied_def)
199e5a44660SAlex Lorenz       .Case("frame-setup", MIToken::kw_frame_setup)
20046d760d1SAlex Lorenz       .Case("debug-location", MIToken::kw_debug_location)
201577d271aSAlex Lorenz       .Case(".cfi_same_value", MIToken::kw_cfi_same_value)
2028cfc6867SAlex Lorenz       .Case(".cfi_offset", MIToken::kw_cfi_offset)
2035b0d5f6fSAlex Lorenz       .Case(".cfi_def_cfa_register", MIToken::kw_cfi_def_cfa_register)
204f4baeb51SAlex Lorenz       .Case(".cfi_def_cfa_offset", MIToken::kw_cfi_def_cfa_offset)
205b139323fSAlex Lorenz       .Case(".cfi_def_cfa", MIToken::kw_cfi_def_cfa)
206deb53490SAlex Lorenz       .Case("blockaddress", MIToken::kw_blockaddress)
207ef5c196fSAlex Lorenz       .Case("target-index", MIToken::kw_target_index)
208ad156fb6SAlex Lorenz       .Case("half", MIToken::kw_half)
209ad156fb6SAlex Lorenz       .Case("float", MIToken::kw_float)
210ad156fb6SAlex Lorenz       .Case("double", MIToken::kw_double)
211ad156fb6SAlex Lorenz       .Case("x86_fp80", MIToken::kw_x86_fp80)
212ad156fb6SAlex Lorenz       .Case("fp128", MIToken::kw_fp128)
213ad156fb6SAlex Lorenz       .Case("ppc_fp128", MIToken::kw_ppc_fp128)
21449873a83SAlex Lorenz       .Case("target-flags", MIToken::kw_target_flags)
215a518b796SAlex Lorenz       .Case("volatile", MIToken::kw_volatile)
21610fd0385SAlex Lorenz       .Case("non-temporal", MIToken::kw_non_temporal)
217dc8de2a6SAlex Lorenz       .Case("invariant", MIToken::kw_invariant)
21861420f79SAlex Lorenz       .Case("align", MIToken::kw_align)
21946e9558aSAlex Lorenz       .Case("stack", MIToken::kw_stack)
220d858f874SAlex Lorenz       .Case("got", MIToken::kw_got)
2214be56e93SAlex Lorenz       .Case("jump-table", MIToken::kw_jump_table)
22291097a3fSAlex Lorenz       .Case("constant-pool", MIToken::kw_constant_pool)
2230d009645SAlex Lorenz       .Case("call-entry", MIToken::kw_call_entry)
224b97c9ef4SAlex Lorenz       .Case("liveout", MIToken::kw_liveout)
2255022f6bbSAlex Lorenz       .Case("address-taken", MIToken::kw_address_taken)
2265022f6bbSAlex Lorenz       .Case("landing-pad", MIToken::kw_landing_pad)
2275022f6bbSAlex Lorenz       .Case("liveins", MIToken::kw_liveins)
2285022f6bbSAlex Lorenz       .Case("successors", MIToken::kw_successors)
229cb268d46SAlex Lorenz       .Default(MIToken::Identifier);
230cb268d46SAlex Lorenz }
231cb268d46SAlex Lorenz 
2326c6c46e4SAlex Lorenz static Cursor maybeLexIdentifier(Cursor C, MIToken &Token) {
233f4baeb51SAlex Lorenz   if (!isalpha(C.peek()) && C.peek() != '_' && C.peek() != '.')
2346c6c46e4SAlex Lorenz     return None;
23591370c5dSAlex Lorenz   auto Range = C;
23691370c5dSAlex Lorenz   while (isIdentifierChar(C.peek()))
23791370c5dSAlex Lorenz     C.advance();
23812b554e6SAlex Lorenz   auto Identifier = Range.upto(C);
2393fb77686SAlex Lorenz   Token.reset(getIdentifierKind(Identifier), Identifier)
2403fb77686SAlex Lorenz       .setStringValue(Identifier);
24191370c5dSAlex Lorenz   return C;
24291370c5dSAlex Lorenz }
24391370c5dSAlex Lorenz 
2446c6c46e4SAlex Lorenz static Cursor maybeLexMachineBasicBlock(
24533f0aef3SAlex Lorenz     Cursor C, MIToken &Token,
24633f0aef3SAlex Lorenz     function_ref<void(StringRef::iterator Loc, const Twine &)> ErrorCallback) {
2475022f6bbSAlex Lorenz   bool IsReference = C.remaining().startswith("%bb.");
2485022f6bbSAlex Lorenz   if (!IsReference && !C.remaining().startswith("bb."))
2496c6c46e4SAlex Lorenz     return None;
25033f0aef3SAlex Lorenz   auto Range = C;
2515022f6bbSAlex Lorenz   unsigned PrefixLength = IsReference ? 4 : 3;
2525022f6bbSAlex Lorenz   C.advance(PrefixLength); // Skip '%bb.' or 'bb.'
25333f0aef3SAlex Lorenz   if (!isdigit(C.peek())) {
2543fb77686SAlex Lorenz     Token.reset(MIToken::Error, C.remaining());
25533f0aef3SAlex Lorenz     ErrorCallback(C.location(), "expected a number after '%bb.'");
25633f0aef3SAlex Lorenz     return C;
25733f0aef3SAlex Lorenz   }
25833f0aef3SAlex Lorenz   auto NumberRange = C;
25933f0aef3SAlex Lorenz   while (isdigit(C.peek()))
26033f0aef3SAlex Lorenz     C.advance();
26133f0aef3SAlex Lorenz   StringRef Number = NumberRange.upto(C);
2625022f6bbSAlex Lorenz   unsigned StringOffset = PrefixLength + Number.size(); // Drop '%bb.<id>'
26333f0aef3SAlex Lorenz   if (C.peek() == '.') {
26433f0aef3SAlex Lorenz     C.advance(); // Skip '.'
26533f0aef3SAlex Lorenz     ++StringOffset;
26633f0aef3SAlex Lorenz     while (isIdentifierChar(C.peek()))
26733f0aef3SAlex Lorenz       C.advance();
26833f0aef3SAlex Lorenz   }
2695022f6bbSAlex Lorenz   Token.reset(IsReference ? MIToken::MachineBasicBlock
2705022f6bbSAlex Lorenz                           : MIToken::MachineBasicBlockLabel,
2715022f6bbSAlex Lorenz               Range.upto(C))
2723fb77686SAlex Lorenz       .setIntegerValue(APSInt(Number))
2733fb77686SAlex Lorenz       .setStringValue(Range.upto(C).drop_front(StringOffset));
27433f0aef3SAlex Lorenz   return C;
27533f0aef3SAlex Lorenz }
27633f0aef3SAlex Lorenz 
27731d70683SAlex Lorenz static Cursor maybeLexIndex(Cursor C, MIToken &Token, StringRef Rule,
27831d70683SAlex Lorenz                             MIToken::TokenKind Kind) {
27931d70683SAlex Lorenz   if (!C.remaining().startswith(Rule) || !isdigit(C.peek(Rule.size())))
28031d70683SAlex Lorenz     return None;
28131d70683SAlex Lorenz   auto Range = C;
28231d70683SAlex Lorenz   C.advance(Rule.size());
28331d70683SAlex Lorenz   auto NumberRange = C;
28431d70683SAlex Lorenz   while (isdigit(C.peek()))
28531d70683SAlex Lorenz     C.advance();
2863fb77686SAlex Lorenz   Token.reset(Kind, Range.upto(C)).setIntegerValue(APSInt(NumberRange.upto(C)));
28731d70683SAlex Lorenz   return C;
28831d70683SAlex Lorenz }
28931d70683SAlex Lorenz 
2907feaf7c6SAlex Lorenz static Cursor maybeLexIndexAndName(Cursor C, MIToken &Token, StringRef Rule,
2917feaf7c6SAlex Lorenz                                    MIToken::TokenKind Kind) {
2927feaf7c6SAlex Lorenz   if (!C.remaining().startswith(Rule) || !isdigit(C.peek(Rule.size())))
2937feaf7c6SAlex Lorenz     return None;
2947feaf7c6SAlex Lorenz   auto Range = C;
2957feaf7c6SAlex Lorenz   C.advance(Rule.size());
2967feaf7c6SAlex Lorenz   auto NumberRange = C;
2977feaf7c6SAlex Lorenz   while (isdigit(C.peek()))
2987feaf7c6SAlex Lorenz     C.advance();
2997feaf7c6SAlex Lorenz   StringRef Number = NumberRange.upto(C);
3007feaf7c6SAlex Lorenz   unsigned StringOffset = Rule.size() + Number.size();
3017feaf7c6SAlex Lorenz   if (C.peek() == '.') {
3027feaf7c6SAlex Lorenz     C.advance();
3037feaf7c6SAlex Lorenz     ++StringOffset;
3047feaf7c6SAlex Lorenz     while (isIdentifierChar(C.peek()))
3057feaf7c6SAlex Lorenz       C.advance();
3067feaf7c6SAlex Lorenz   }
3073fb77686SAlex Lorenz   Token.reset(Kind, Range.upto(C))
3083fb77686SAlex Lorenz       .setIntegerValue(APSInt(Number))
3093fb77686SAlex Lorenz       .setStringValue(Range.upto(C).drop_front(StringOffset));
3107feaf7c6SAlex Lorenz   return C;
3117feaf7c6SAlex Lorenz }
3127feaf7c6SAlex Lorenz 
31331d70683SAlex Lorenz static Cursor maybeLexJumpTableIndex(Cursor C, MIToken &Token) {
31431d70683SAlex Lorenz   return maybeLexIndex(C, Token, "%jump-table.", MIToken::JumpTableIndex);
31531d70683SAlex Lorenz }
31631d70683SAlex Lorenz 
3177feaf7c6SAlex Lorenz static Cursor maybeLexStackObject(Cursor C, MIToken &Token) {
3187feaf7c6SAlex Lorenz   return maybeLexIndexAndName(C, Token, "%stack.", MIToken::StackObject);
3197feaf7c6SAlex Lorenz }
3207feaf7c6SAlex Lorenz 
3217feaf7c6SAlex Lorenz static Cursor maybeLexFixedStackObject(Cursor C, MIToken &Token) {
3227feaf7c6SAlex Lorenz   return maybeLexIndex(C, Token, "%fixed-stack.", MIToken::FixedStackObject);
3237feaf7c6SAlex Lorenz }
3247feaf7c6SAlex Lorenz 
325ab980499SAlex Lorenz static Cursor maybeLexConstantPoolItem(Cursor C, MIToken &Token) {
326ab980499SAlex Lorenz   return maybeLexIndex(C, Token, "%const.", MIToken::ConstantPoolItem);
327ab980499SAlex Lorenz }
328ab980499SAlex Lorenz 
329deb53490SAlex Lorenz static Cursor maybeLexIRBlock(
330deb53490SAlex Lorenz     Cursor C, MIToken &Token,
331deb53490SAlex Lorenz     function_ref<void(StringRef::iterator Loc, const Twine &)> ErrorCallback) {
332deb53490SAlex Lorenz   const StringRef Rule = "%ir-block.";
333deb53490SAlex Lorenz   if (!C.remaining().startswith(Rule))
334deb53490SAlex Lorenz     return None;
335deb53490SAlex Lorenz   if (isdigit(C.peek(Rule.size())))
336deb53490SAlex Lorenz     return maybeLexIndex(C, Token, Rule, MIToken::IRBlock);
337970c12eaSAlex Lorenz   return lexName(C, Token, MIToken::NamedIRBlock, Rule.size(), ErrorCallback);
3388a1915b0SAlex Lorenz }
3398a1915b0SAlex Lorenz 
3404af7e610SAlex Lorenz static Cursor maybeLexIRValue(
3414af7e610SAlex Lorenz     Cursor C, MIToken &Token,
3424af7e610SAlex Lorenz     function_ref<void(StringRef::iterator Loc, const Twine &)> ErrorCallback) {
3434af7e610SAlex Lorenz   const StringRef Rule = "%ir.";
3444af7e610SAlex Lorenz   if (!C.remaining().startswith(Rule))
3454af7e610SAlex Lorenz     return None;
346dd13be0bSAlex Lorenz   if (isdigit(C.peek(Rule.size())))
347dd13be0bSAlex Lorenz     return maybeLexIndex(C, Token, Rule, MIToken::IRValue);
348970c12eaSAlex Lorenz   return lexName(C, Token, MIToken::NamedIRValue, Rule.size(), ErrorCallback);
3494af7e610SAlex Lorenz }
3504af7e610SAlex Lorenz 
35153464510SAlex Lorenz static Cursor lexVirtualRegister(Cursor C, MIToken &Token) {
35253464510SAlex Lorenz   auto Range = C;
35353464510SAlex Lorenz   C.advance(); // Skip '%'
35453464510SAlex Lorenz   auto NumberRange = C;
35553464510SAlex Lorenz   while (isdigit(C.peek()))
35653464510SAlex Lorenz     C.advance();
3573fb77686SAlex Lorenz   Token.reset(MIToken::VirtualRegister, Range.upto(C))
3583fb77686SAlex Lorenz       .setIntegerValue(APSInt(NumberRange.upto(C)));
35953464510SAlex Lorenz   return C;
36053464510SAlex Lorenz }
36153464510SAlex Lorenz 
3626c6c46e4SAlex Lorenz static Cursor maybeLexRegister(Cursor C, MIToken &Token) {
3636c6c46e4SAlex Lorenz   if (C.peek() != '%')
3646c6c46e4SAlex Lorenz     return None;
36553464510SAlex Lorenz   if (isdigit(C.peek(1)))
36653464510SAlex Lorenz     return lexVirtualRegister(C, Token);
367f3db51deSAlex Lorenz   auto Range = C;
368f3db51deSAlex Lorenz   C.advance(); // Skip '%'
369f3db51deSAlex Lorenz   while (isIdentifierChar(C.peek()))
370f3db51deSAlex Lorenz     C.advance();
3713fb77686SAlex Lorenz   Token.reset(MIToken::NamedRegister, Range.upto(C))
3723fb77686SAlex Lorenz       .setStringValue(Range.upto(C).drop_front(1)); // Drop the '%'
373f3db51deSAlex Lorenz   return C;
374f3db51deSAlex Lorenz }
375f3db51deSAlex Lorenz 
376c1fbb354SAlex Lorenz static Cursor maybeLexGlobalValue(
377c1fbb354SAlex Lorenz     Cursor C, MIToken &Token,
378c1fbb354SAlex Lorenz     function_ref<void(StringRef::iterator Loc, const Twine &)> ErrorCallback) {
379c1fbb354SAlex Lorenz   if (C.peek() != '@')
380c1fbb354SAlex Lorenz     return None;
381c1fbb354SAlex Lorenz   if (!isdigit(C.peek(1)))
382970c12eaSAlex Lorenz     return lexName(C, Token, MIToken::NamedGlobalValue, /*PrefixLength=*/1,
383c1fbb354SAlex Lorenz                    ErrorCallback);
384c1fbb354SAlex Lorenz   auto Range = C;
385c1fbb354SAlex Lorenz   C.advance(1); // Skip the '@'
386c1fbb354SAlex Lorenz   auto NumberRange = C;
387c1fbb354SAlex Lorenz   while (isdigit(C.peek()))
388c1fbb354SAlex Lorenz     C.advance();
3893fb77686SAlex Lorenz   Token.reset(MIToken::GlobalValue, Range.upto(C))
3903fb77686SAlex Lorenz       .setIntegerValue(APSInt(NumberRange.upto(C)));
391c1fbb354SAlex Lorenz   return C;
392c1fbb354SAlex Lorenz }
393c1fbb354SAlex Lorenz 
3946ede3744SAlex Lorenz static Cursor maybeLexExternalSymbol(
3956ede3744SAlex Lorenz     Cursor C, MIToken &Token,
3966ede3744SAlex Lorenz     function_ref<void(StringRef::iterator Loc, const Twine &)> ErrorCallback) {
3976ede3744SAlex Lorenz   if (C.peek() != '$')
3986ede3744SAlex Lorenz     return None;
399970c12eaSAlex Lorenz   return lexName(C, Token, MIToken::ExternalSymbol, /*PrefixLength=*/1,
400970c12eaSAlex Lorenz                  ErrorCallback);
4016ede3744SAlex Lorenz }
4026ede3744SAlex Lorenz 
403ad156fb6SAlex Lorenz static bool isValidHexFloatingPointPrefix(char C) {
404ad156fb6SAlex Lorenz   return C == 'H' || C == 'K' || C == 'L' || C == 'M';
405ad156fb6SAlex Lorenz }
406ad156fb6SAlex Lorenz 
407ad156fb6SAlex Lorenz static Cursor maybeLexHexFloatingPointLiteral(Cursor C, MIToken &Token) {
408ad156fb6SAlex Lorenz   if (C.peek() != '0' || C.peek(1) != 'x')
409ad156fb6SAlex Lorenz     return None;
410ad156fb6SAlex Lorenz   Cursor Range = C;
411ad156fb6SAlex Lorenz   C.advance(2); // Skip '0x'
412ad156fb6SAlex Lorenz   if (isValidHexFloatingPointPrefix(C.peek()))
413ad156fb6SAlex Lorenz     C.advance();
414ad156fb6SAlex Lorenz   while (isxdigit(C.peek()))
415ad156fb6SAlex Lorenz     C.advance();
4163fb77686SAlex Lorenz   Token.reset(MIToken::FloatingPointLiteral, Range.upto(C));
417ad156fb6SAlex Lorenz   return C;
418ad156fb6SAlex Lorenz }
419ad156fb6SAlex Lorenz 
420ad156fb6SAlex Lorenz static Cursor lexFloatingPointLiteral(Cursor Range, Cursor C, MIToken &Token) {
421ad156fb6SAlex Lorenz   C.advance();
422ad156fb6SAlex Lorenz   // Skip over [0-9]*([eE][-+]?[0-9]+)?
423ad156fb6SAlex Lorenz   while (isdigit(C.peek()))
424ad156fb6SAlex Lorenz     C.advance();
425ad156fb6SAlex Lorenz   if ((C.peek() == 'e' || C.peek() == 'E') &&
426ad156fb6SAlex Lorenz       (isdigit(C.peek(1)) ||
427ad156fb6SAlex Lorenz        ((C.peek(1) == '-' || C.peek(1) == '+') && isdigit(C.peek(2))))) {
428ad156fb6SAlex Lorenz     C.advance(2);
429ad156fb6SAlex Lorenz     while (isdigit(C.peek()))
430ad156fb6SAlex Lorenz       C.advance();
431ad156fb6SAlex Lorenz   }
4323fb77686SAlex Lorenz   Token.reset(MIToken::FloatingPointLiteral, Range.upto(C));
433ad156fb6SAlex Lorenz   return C;
434ad156fb6SAlex Lorenz }
435ad156fb6SAlex Lorenz 
436ad156fb6SAlex Lorenz static Cursor maybeLexNumericalLiteral(Cursor C, MIToken &Token) {
4376c6c46e4SAlex Lorenz   if (!isdigit(C.peek()) && (C.peek() != '-' || !isdigit(C.peek(1))))
4386c6c46e4SAlex Lorenz     return None;
439240fc1e0SAlex Lorenz   auto Range = C;
440240fc1e0SAlex Lorenz   C.advance();
441240fc1e0SAlex Lorenz   while (isdigit(C.peek()))
442240fc1e0SAlex Lorenz     C.advance();
443ad156fb6SAlex Lorenz   if (C.peek() == '.')
444ad156fb6SAlex Lorenz     return lexFloatingPointLiteral(Range, C, Token);
445240fc1e0SAlex Lorenz   StringRef StrVal = Range.upto(C);
4463fb77686SAlex Lorenz   Token.reset(MIToken::IntegerLiteral, StrVal).setIntegerValue(APSInt(StrVal));
447240fc1e0SAlex Lorenz   return C;
448240fc1e0SAlex Lorenz }
449240fc1e0SAlex Lorenz 
450a617c916SAlex Lorenz static MIToken::TokenKind getMetadataKeywordKind(StringRef Identifier) {
451a617c916SAlex Lorenz   return StringSwitch<MIToken::TokenKind>(Identifier)
452a617c916SAlex Lorenz       .Case("!tbaa", MIToken::md_tbaa)
453a16f624dSAlex Lorenz       .Case("!alias.scope", MIToken::md_alias_scope)
45403e940d1SAlex Lorenz       .Case("!noalias", MIToken::md_noalias)
455eb625686SAlex Lorenz       .Case("!range", MIToken::md_range)
456a617c916SAlex Lorenz       .Default(MIToken::Error);
457a617c916SAlex Lorenz }
458a617c916SAlex Lorenz 
459a617c916SAlex Lorenz static Cursor maybeLexExlaim(
460a617c916SAlex Lorenz     Cursor C, MIToken &Token,
461a617c916SAlex Lorenz     function_ref<void(StringRef::iterator Loc, const Twine &)> ErrorCallback) {
462a617c916SAlex Lorenz   if (C.peek() != '!')
463a617c916SAlex Lorenz     return None;
464a617c916SAlex Lorenz   auto Range = C;
465a617c916SAlex Lorenz   C.advance(1);
466a617c916SAlex Lorenz   if (isdigit(C.peek()) || !isIdentifierChar(C.peek())) {
467a617c916SAlex Lorenz     Token.reset(MIToken::exclaim, Range.upto(C));
468a617c916SAlex Lorenz     return C;
469a617c916SAlex Lorenz   }
470a617c916SAlex Lorenz   while (isIdentifierChar(C.peek()))
471a617c916SAlex Lorenz     C.advance();
472a617c916SAlex Lorenz   StringRef StrVal = Range.upto(C);
473a617c916SAlex Lorenz   Token.reset(getMetadataKeywordKind(StrVal), StrVal);
474a617c916SAlex Lorenz   if (Token.isError())
475a617c916SAlex Lorenz     ErrorCallback(Token.location(),
476a617c916SAlex Lorenz                   "use of unknown metadata keyword '" + StrVal + "'");
477a617c916SAlex Lorenz   return C;
478a617c916SAlex Lorenz }
479a617c916SAlex Lorenz 
480f3db51deSAlex Lorenz static MIToken::TokenKind symbolToken(char C) {
481f3db51deSAlex Lorenz   switch (C) {
482f3db51deSAlex Lorenz   case ',':
483f3db51deSAlex Lorenz     return MIToken::comma;
484f3db51deSAlex Lorenz   case '=':
485f3db51deSAlex Lorenz     return MIToken::equal;
4862eacca86SAlex Lorenz   case ':':
4872eacca86SAlex Lorenz     return MIToken::colon;
488deb53490SAlex Lorenz   case '(':
489deb53490SAlex Lorenz     return MIToken::lparen;
490deb53490SAlex Lorenz   case ')':
491deb53490SAlex Lorenz     return MIToken::rparen;
492f9a2b123SAlex Lorenz   case '{':
493f9a2b123SAlex Lorenz     return MIToken::lbrace;
494f9a2b123SAlex Lorenz   case '}':
495f9a2b123SAlex Lorenz     return MIToken::rbrace;
4965672a893SAlex Lorenz   case '+':
4975672a893SAlex Lorenz     return MIToken::plus;
4985672a893SAlex Lorenz   case '-':
4995672a893SAlex Lorenz     return MIToken::minus;
500*287c6bb5SQuentin Colombet   case '<':
501*287c6bb5SQuentin Colombet     return MIToken::lt;
502*287c6bb5SQuentin Colombet   case '>':
503*287c6bb5SQuentin Colombet     return MIToken::gt;
504f3db51deSAlex Lorenz   default:
505f3db51deSAlex Lorenz     return MIToken::Error;
506f3db51deSAlex Lorenz   }
507f3db51deSAlex Lorenz }
508f3db51deSAlex Lorenz 
5096c6c46e4SAlex Lorenz static Cursor maybeLexSymbol(Cursor C, MIToken &Token) {
5104af7e610SAlex Lorenz   MIToken::TokenKind Kind;
5114af7e610SAlex Lorenz   unsigned Length = 1;
5124af7e610SAlex Lorenz   if (C.peek() == ':' && C.peek(1) == ':') {
5134af7e610SAlex Lorenz     Kind = MIToken::coloncolon;
5144af7e610SAlex Lorenz     Length = 2;
5154af7e610SAlex Lorenz   } else
5164af7e610SAlex Lorenz     Kind = symbolToken(C.peek());
5176c6c46e4SAlex Lorenz   if (Kind == MIToken::Error)
5186c6c46e4SAlex Lorenz     return None;
519f3db51deSAlex Lorenz   auto Range = C;
5204af7e610SAlex Lorenz   C.advance(Length);
5213fb77686SAlex Lorenz   Token.reset(Kind, Range.upto(C));
522f3db51deSAlex Lorenz   return C;
523f3db51deSAlex Lorenz }
524f3db51deSAlex Lorenz 
5255022f6bbSAlex Lorenz static Cursor maybeLexNewline(Cursor C, MIToken &Token) {
5265022f6bbSAlex Lorenz   if (!isNewlineChar(C.peek()))
5275022f6bbSAlex Lorenz     return None;
5285022f6bbSAlex Lorenz   auto Range = C;
5295022f6bbSAlex Lorenz   C.advance();
5305022f6bbSAlex Lorenz   Token.reset(MIToken::Newline, Range.upto(C));
5315022f6bbSAlex Lorenz   return C;
5325022f6bbSAlex Lorenz }
5335022f6bbSAlex Lorenz 
534c1136ef3SAlex Lorenz static Cursor maybeLexEscapedIRValue(
535c1136ef3SAlex Lorenz     Cursor C, MIToken &Token,
536c1136ef3SAlex Lorenz     function_ref<void(StringRef::iterator Loc, const Twine &)> ErrorCallback) {
537c1136ef3SAlex Lorenz   if (C.peek() != '`')
538c1136ef3SAlex Lorenz     return None;
539c1136ef3SAlex Lorenz   auto Range = C;
540c1136ef3SAlex Lorenz   C.advance();
541c1136ef3SAlex Lorenz   auto StrRange = C;
542c1136ef3SAlex Lorenz   while (C.peek() != '`') {
543c1136ef3SAlex Lorenz     if (C.isEOF() || isNewlineChar(C.peek())) {
544c1136ef3SAlex Lorenz       ErrorCallback(
545c1136ef3SAlex Lorenz           C.location(),
546c1136ef3SAlex Lorenz           "end of machine instruction reached before the closing '`'");
547c1136ef3SAlex Lorenz       Token.reset(MIToken::Error, Range.remaining());
548c1136ef3SAlex Lorenz       return C;
549c1136ef3SAlex Lorenz     }
550c1136ef3SAlex Lorenz     C.advance();
551c1136ef3SAlex Lorenz   }
552c1136ef3SAlex Lorenz   StringRef Value = StrRange.upto(C);
553c1136ef3SAlex Lorenz   C.advance();
554c1136ef3SAlex Lorenz   Token.reset(MIToken::QuotedIRValue, Range.upto(C)).setStringValue(Value);
555c1136ef3SAlex Lorenz   return C;
556c1136ef3SAlex Lorenz }
557c1136ef3SAlex Lorenz 
55891370c5dSAlex Lorenz StringRef llvm::lexMIToken(
55991370c5dSAlex Lorenz     StringRef Source, MIToken &Token,
56091370c5dSAlex Lorenz     function_ref<void(StringRef::iterator Loc, const Twine &)> ErrorCallback) {
5615022f6bbSAlex Lorenz   auto C = skipComment(skipWhitespace(Cursor(Source)));
56291370c5dSAlex Lorenz   if (C.isEOF()) {
5633fb77686SAlex Lorenz     Token.reset(MIToken::Eof, C.remaining());
56491370c5dSAlex Lorenz     return C.remaining();
56591370c5dSAlex Lorenz   }
56691370c5dSAlex Lorenz 
56705e3882eSAlex Lorenz   if (Cursor R = maybeLexIntegerType(C, Token))
56805e3882eSAlex Lorenz     return R.remaining();
5696c6c46e4SAlex Lorenz   if (Cursor R = maybeLexMachineBasicBlock(C, Token, ErrorCallback))
5706c6c46e4SAlex Lorenz     return R.remaining();
5715022f6bbSAlex Lorenz   if (Cursor R = maybeLexIdentifier(C, Token))
5725022f6bbSAlex Lorenz     return R.remaining();
57331d70683SAlex Lorenz   if (Cursor R = maybeLexJumpTableIndex(C, Token))
57431d70683SAlex Lorenz     return R.remaining();
5757feaf7c6SAlex Lorenz   if (Cursor R = maybeLexStackObject(C, Token))
5767feaf7c6SAlex Lorenz     return R.remaining();
5777feaf7c6SAlex Lorenz   if (Cursor R = maybeLexFixedStackObject(C, Token))
5787feaf7c6SAlex Lorenz     return R.remaining();
579ab980499SAlex Lorenz   if (Cursor R = maybeLexConstantPoolItem(C, Token))
580ab980499SAlex Lorenz     return R.remaining();
581deb53490SAlex Lorenz   if (Cursor R = maybeLexIRBlock(C, Token, ErrorCallback))
5828a1915b0SAlex Lorenz     return R.remaining();
5834af7e610SAlex Lorenz   if (Cursor R = maybeLexIRValue(C, Token, ErrorCallback))
5844af7e610SAlex Lorenz     return R.remaining();
5856c6c46e4SAlex Lorenz   if (Cursor R = maybeLexRegister(C, Token))
5866c6c46e4SAlex Lorenz     return R.remaining();
587b29554daSAlex Lorenz   if (Cursor R = maybeLexGlobalValue(C, Token, ErrorCallback))
5886c6c46e4SAlex Lorenz     return R.remaining();
5896ede3744SAlex Lorenz   if (Cursor R = maybeLexExternalSymbol(C, Token, ErrorCallback))
5906ede3744SAlex Lorenz     return R.remaining();
591ad156fb6SAlex Lorenz   if (Cursor R = maybeLexHexFloatingPointLiteral(C, Token))
592ad156fb6SAlex Lorenz     return R.remaining();
593ad156fb6SAlex Lorenz   if (Cursor R = maybeLexNumericalLiteral(C, Token))
5946c6c46e4SAlex Lorenz     return R.remaining();
595a617c916SAlex Lorenz   if (Cursor R = maybeLexExlaim(C, Token, ErrorCallback))
596a617c916SAlex Lorenz     return R.remaining();
5976c6c46e4SAlex Lorenz   if (Cursor R = maybeLexSymbol(C, Token))
5986c6c46e4SAlex Lorenz     return R.remaining();
5995022f6bbSAlex Lorenz   if (Cursor R = maybeLexNewline(C, Token))
6005022f6bbSAlex Lorenz     return R.remaining();
601c1136ef3SAlex Lorenz   if (Cursor R = maybeLexEscapedIRValue(C, Token, ErrorCallback))
602c1136ef3SAlex Lorenz     return R.remaining();
6036c6c46e4SAlex Lorenz 
6043fb77686SAlex Lorenz   Token.reset(MIToken::Error, C.remaining());
60591370c5dSAlex Lorenz   ErrorCallback(C.location(),
6066c6c46e4SAlex Lorenz                 Twine("unexpected character '") + Twine(C.peek()) + "'");
60791370c5dSAlex Lorenz   return C.remaining();
60891370c5dSAlex Lorenz }
609