1 //==- WebAssemblyAsmParser.cpp - Assembler for WebAssembly -*- C++ -*-==//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file
11 /// This file is part of the WebAssembly Assembler.
12 ///
13 /// It contains code to translate a parsed .s file into MCInsts.
14 ///
15 //===----------------------------------------------------------------------===//
16 
17 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
18 #include "MCTargetDesc/WebAssemblyTargetStreamer.h"
19 #include "WebAssembly.h"
20 #include "llvm/MC/MCContext.h"
21 #include "llvm/MC/MCInst.h"
22 #include "llvm/MC/MCInstrInfo.h"
23 #include "llvm/MC/MCParser/MCParsedAsmOperand.h"
24 #include "llvm/MC/MCParser/MCTargetAsmParser.h"
25 #include "llvm/MC/MCStreamer.h"
26 #include "llvm/MC/MCSubtargetInfo.h"
27 #include "llvm/MC/MCSymbol.h"
28 #include "llvm/MC/MCSymbolWasm.h"
29 #include "llvm/Support/Endian.h"
30 #include "llvm/Support/TargetRegistry.h"
31 
32 using namespace llvm;
33 
34 #define DEBUG_TYPE "wasm-asm-parser"
35 
36 namespace {
37 
38 /// WebAssemblyOperand - Instances of this class represent the operands in a
39 /// parsed WASM machine instruction.
40 struct WebAssemblyOperand : public MCParsedAsmOperand {
41   enum KindTy { Token, Integer, Float, Symbol, BrList } Kind;
42 
43   SMLoc StartLoc, EndLoc;
44 
45   struct TokOp {
46     StringRef Tok;
47   };
48 
49   struct IntOp {
50     int64_t Val;
51   };
52 
53   struct FltOp {
54     double Val;
55   };
56 
57   struct SymOp {
58     const MCExpr *Exp;
59   };
60 
61   struct BrLOp {
62     std::vector<unsigned> List;
63   };
64 
65   union {
66     struct TokOp Tok;
67     struct IntOp Int;
68     struct FltOp Flt;
69     struct SymOp Sym;
70     struct BrLOp BrL;
71   };
72 
WebAssemblyOperand__anon1565d9e10111::WebAssemblyOperand73   WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, TokOp T)
74       : Kind(K), StartLoc(Start), EndLoc(End), Tok(T) {}
WebAssemblyOperand__anon1565d9e10111::WebAssemblyOperand75   WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, IntOp I)
76       : Kind(K), StartLoc(Start), EndLoc(End), Int(I) {}
WebAssemblyOperand__anon1565d9e10111::WebAssemblyOperand77   WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, FltOp F)
78       : Kind(K), StartLoc(Start), EndLoc(End), Flt(F) {}
WebAssemblyOperand__anon1565d9e10111::WebAssemblyOperand79   WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, SymOp S)
80       : Kind(K), StartLoc(Start), EndLoc(End), Sym(S) {}
WebAssemblyOperand__anon1565d9e10111::WebAssemblyOperand81   WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End)
82       : Kind(K), StartLoc(Start), EndLoc(End), BrL() {}
83 
~WebAssemblyOperand__anon1565d9e10111::WebAssemblyOperand84   ~WebAssemblyOperand() {
85     if (isBrList())
86       BrL.~BrLOp();
87   }
88 
isToken__anon1565d9e10111::WebAssemblyOperand89   bool isToken() const override { return Kind == Token; }
isImm__anon1565d9e10111::WebAssemblyOperand90   bool isImm() const override {
91     return Kind == Integer || Kind == Float || Kind == Symbol;
92   }
isMem__anon1565d9e10111::WebAssemblyOperand93   bool isMem() const override { return false; }
isReg__anon1565d9e10111::WebAssemblyOperand94   bool isReg() const override { return false; }
isBrList__anon1565d9e10111::WebAssemblyOperand95   bool isBrList() const { return Kind == BrList; }
96 
getReg__anon1565d9e10111::WebAssemblyOperand97   unsigned getReg() const override {
98     llvm_unreachable("Assembly inspects a register operand");
99     return 0;
100   }
101 
getToken__anon1565d9e10111::WebAssemblyOperand102   StringRef getToken() const {
103     assert(isToken());
104     return Tok.Tok;
105   }
106 
getStartLoc__anon1565d9e10111::WebAssemblyOperand107   SMLoc getStartLoc() const override { return StartLoc; }
getEndLoc__anon1565d9e10111::WebAssemblyOperand108   SMLoc getEndLoc() const override { return EndLoc; }
109 
addRegOperands__anon1565d9e10111::WebAssemblyOperand110   void addRegOperands(MCInst &, unsigned) const {
111     // Required by the assembly matcher.
112     llvm_unreachable("Assembly matcher creates register operands");
113   }
114 
addImmOperands__anon1565d9e10111::WebAssemblyOperand115   void addImmOperands(MCInst &Inst, unsigned N) const {
116     assert(N == 1 && "Invalid number of operands!");
117     if (Kind == Integer)
118       Inst.addOperand(MCOperand::createImm(Int.Val));
119     else if (Kind == Float)
120       Inst.addOperand(MCOperand::createFPImm(Flt.Val));
121     else if (Kind == Symbol)
122       Inst.addOperand(MCOperand::createExpr(Sym.Exp));
123     else
124       llvm_unreachable("Should be immediate or symbol!");
125   }
126 
addBrListOperands__anon1565d9e10111::WebAssemblyOperand127   void addBrListOperands(MCInst &Inst, unsigned N) const {
128     assert(N == 1 && isBrList() && "Invalid BrList!");
129     for (auto Br : BrL.List)
130       Inst.addOperand(MCOperand::createImm(Br));
131   }
132 
print__anon1565d9e10111::WebAssemblyOperand133   void print(raw_ostream &OS) const override {
134     switch (Kind) {
135     case Token:
136       OS << "Tok:" << Tok.Tok;
137       break;
138     case Integer:
139       OS << "Int:" << Int.Val;
140       break;
141     case Float:
142       OS << "Flt:" << Flt.Val;
143       break;
144     case Symbol:
145       OS << "Sym:" << Sym.Exp;
146       break;
147     case BrList:
148       OS << "BrList:" << BrL.List.size();
149       break;
150     }
151   }
152 };
153 
154 class WebAssemblyAsmParser final : public MCTargetAsmParser {
155   MCAsmParser &Parser;
156   MCAsmLexer &Lexer;
157 
158   // Much like WebAssemblyAsmPrinter in the backend, we have to own these.
159   std::vector<std::unique_ptr<wasm::WasmSignature>> Signatures;
160 
161   // Order of labels, directives and instructions in a .s file have no
162   // syntactical enforcement. This class is a callback from the actual parser,
163   // and yet we have to be feeding data to the streamer in a very particular
164   // order to ensure a correct binary encoding that matches the regular backend
165   // (the streamer does not enforce this). This "state machine" enum helps
166   // guarantee that correct order.
167   enum ParserState {
168     FileStart,
169     Label,
170     FunctionStart,
171     FunctionLocals,
172     Instructions,
173   } CurrentState = FileStart;
174 
175   // For ensuring blocks are properly nested.
176   enum NestingType {
177     Function,
178     Block,
179     Loop,
180     Try,
181     If,
182     Else,
183     Undefined,
184   };
185   std::vector<NestingType> NestingStack;
186 
187   // We track this to see if a .functype following a label is the same,
188   // as this is how we recognize the start of a function.
189   MCSymbol *LastLabel = nullptr;
190 
191 public:
WebAssemblyAsmParser(const MCSubtargetInfo & STI,MCAsmParser & Parser,const MCInstrInfo & MII,const MCTargetOptions & Options)192   WebAssemblyAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
193                        const MCInstrInfo &MII, const MCTargetOptions &Options)
194       : MCTargetAsmParser(Options, STI, MII), Parser(Parser),
195         Lexer(Parser.getLexer()) {
196     setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
197   }
198 
199 #define GET_ASSEMBLER_HEADER
200 #include "WebAssemblyGenAsmMatcher.inc"
201 
202   // TODO: This is required to be implemented, but appears unused.
ParseRegister(unsigned &,SMLoc &,SMLoc &)203   bool ParseRegister(unsigned & /*RegNo*/, SMLoc & /*StartLoc*/,
204                      SMLoc & /*EndLoc*/) override {
205     llvm_unreachable("ParseRegister is not implemented.");
206   }
207 
error(const Twine & Msg,const AsmToken & Tok)208   bool error(const Twine &Msg, const AsmToken &Tok) {
209     return Parser.Error(Tok.getLoc(), Msg + Tok.getString());
210   }
211 
error(const Twine & Msg)212   bool error(const Twine &Msg) {
213     return Parser.Error(Lexer.getTok().getLoc(), Msg);
214   }
215 
addSignature(std::unique_ptr<wasm::WasmSignature> && Sig)216   void addSignature(std::unique_ptr<wasm::WasmSignature> &&Sig) {
217     Signatures.push_back(std::move(Sig));
218   }
219 
nestingString(NestingType NT)220   std::pair<StringRef, StringRef> nestingString(NestingType NT) {
221     switch (NT) {
222     case Function:
223       return {"function", "end_function"};
224     case Block:
225       return {"block", "end_block"};
226     case Loop:
227       return {"loop", "end_loop"};
228     case Try:
229       return {"try", "end_try"};
230     case If:
231       return {"if", "end_if"};
232     case Else:
233       return {"else", "end_if"};
234     default:
235       llvm_unreachable("unknown NestingType");
236     }
237   }
238 
push(NestingType NT)239   void push(NestingType NT) { NestingStack.push_back(NT); }
240 
pop(StringRef Ins,NestingType NT1,NestingType NT2=Undefined)241   bool pop(StringRef Ins, NestingType NT1, NestingType NT2 = Undefined) {
242     if (NestingStack.empty())
243       return error(Twine("End of block construct with no start: ") + Ins);
244     auto Top = NestingStack.back();
245     if (Top != NT1 && Top != NT2)
246       return error(Twine("Block construct type mismatch, expected: ") +
247                    nestingString(Top).second + ", instead got: " + Ins);
248     NestingStack.pop_back();
249     return false;
250   }
251 
ensureEmptyNestingStack()252   bool ensureEmptyNestingStack() {
253     auto err = !NestingStack.empty();
254     while (!NestingStack.empty()) {
255       error(Twine("Unmatched block construct(s) at function end: ") +
256             nestingString(NestingStack.back()).first);
257       NestingStack.pop_back();
258     }
259     return err;
260   }
261 
isNext(AsmToken::TokenKind Kind)262   bool isNext(AsmToken::TokenKind Kind) {
263     auto Ok = Lexer.is(Kind);
264     if (Ok)
265       Parser.Lex();
266     return Ok;
267   }
268 
expect(AsmToken::TokenKind Kind,const char * KindName)269   bool expect(AsmToken::TokenKind Kind, const char *KindName) {
270     if (!isNext(Kind))
271       return error(std::string("Expected ") + KindName + ", instead got: ",
272                    Lexer.getTok());
273     return false;
274   }
275 
expectIdent()276   StringRef expectIdent() {
277     if (!Lexer.is(AsmToken::Identifier)) {
278       error("Expected identifier, got: ", Lexer.getTok());
279       return StringRef();
280     }
281     auto Name = Lexer.getTok().getString();
282     Parser.Lex();
283     return Name;
284   }
285 
parseType(const StringRef & Type)286   Optional<wasm::ValType> parseType(const StringRef &Type) {
287     // FIXME: can't use StringSwitch because wasm::ValType doesn't have a
288     // "invalid" value.
289     if (Type == "i32")
290       return wasm::ValType::I32;
291     if (Type == "i64")
292       return wasm::ValType::I64;
293     if (Type == "f32")
294       return wasm::ValType::F32;
295     if (Type == "f64")
296       return wasm::ValType::F64;
297     if (Type == "v128" || Type == "i8x16" || Type == "i16x8" ||
298         Type == "i32x4" || Type == "i64x2" || Type == "f32x4" ||
299         Type == "f64x2")
300       return wasm::ValType::V128;
301     return Optional<wasm::ValType>();
302   }
303 
parseBlockType(StringRef ID)304   WebAssembly::ExprType parseBlockType(StringRef ID) {
305     return StringSwitch<WebAssembly::ExprType>(ID)
306         .Case("i32", WebAssembly::ExprType::I32)
307         .Case("i64", WebAssembly::ExprType::I64)
308         .Case("f32", WebAssembly::ExprType::F32)
309         .Case("f64", WebAssembly::ExprType::F64)
310         .Case("v128", WebAssembly::ExprType::V128)
311         .Case("except_ref", WebAssembly::ExprType::ExceptRef)
312         .Case("void", WebAssembly::ExprType::Void)
313         .Default(WebAssembly::ExprType::Invalid);
314   }
315 
parseRegTypeList(SmallVectorImpl<wasm::ValType> & Types)316   bool parseRegTypeList(SmallVectorImpl<wasm::ValType> &Types) {
317     while (Lexer.is(AsmToken::Identifier)) {
318       auto Type = parseType(Lexer.getTok().getString());
319       if (!Type)
320         return true;
321       Types.push_back(Type.getValue());
322       Parser.Lex();
323       if (!isNext(AsmToken::Comma))
324         break;
325     }
326     return false;
327   }
328 
parseSingleInteger(bool IsNegative,OperandVector & Operands)329   void parseSingleInteger(bool IsNegative, OperandVector &Operands) {
330     auto &Int = Lexer.getTok();
331     int64_t Val = Int.getIntVal();
332     if (IsNegative)
333       Val = -Val;
334     Operands.push_back(make_unique<WebAssemblyOperand>(
335         WebAssemblyOperand::Integer, Int.getLoc(), Int.getEndLoc(),
336         WebAssemblyOperand::IntOp{Val}));
337     Parser.Lex();
338   }
339 
parseOperandStartingWithInteger(bool IsNegative,OperandVector & Operands,StringRef InstName)340   bool parseOperandStartingWithInteger(bool IsNegative, OperandVector &Operands,
341                                        StringRef InstName) {
342     parseSingleInteger(IsNegative, Operands);
343     // FIXME: there is probably a cleaner way to do this.
344     auto IsLoadStore = InstName.startswith("load") ||
345                        InstName.startswith("store") ||
346                        InstName.startswith("atomic_load") ||
347                        InstName.startswith("atomic_store");
348     if (IsLoadStore) {
349       // Parse load/store operands of the form: offset align
350       auto &Offset = Lexer.getTok();
351       if (Offset.is(AsmToken::Integer)) {
352         parseSingleInteger(false, Operands);
353       } else {
354         // Alignment not specified.
355         // FIXME: correctly derive a default from the instruction.
356         // We can't just call WebAssembly::GetDefaultP2Align since we don't have
357         // an opcode until after the assembly matcher.
358         Operands.push_back(make_unique<WebAssemblyOperand>(
359             WebAssemblyOperand::Integer, Offset.getLoc(), Offset.getEndLoc(),
360             WebAssemblyOperand::IntOp{0}));
361       }
362     }
363     return false;
364   }
365 
addBlockTypeOperand(OperandVector & Operands,SMLoc NameLoc,WebAssembly::ExprType BT)366   void addBlockTypeOperand(OperandVector &Operands, SMLoc NameLoc,
367                            WebAssembly::ExprType BT) {
368     Operands.push_back(make_unique<WebAssemblyOperand>(
369         WebAssemblyOperand::Integer, NameLoc, NameLoc,
370         WebAssemblyOperand::IntOp{static_cast<int64_t>(BT)}));
371   }
372 
ParseInstruction(ParseInstructionInfo &,StringRef Name,SMLoc NameLoc,OperandVector & Operands)373   bool ParseInstruction(ParseInstructionInfo & /*Info*/, StringRef Name,
374                         SMLoc NameLoc, OperandVector &Operands) override {
375     // Note: Name does NOT point into the sourcecode, but to a local, so
376     // use NameLoc instead.
377     Name = StringRef(NameLoc.getPointer(), Name.size());
378 
379     // WebAssembly has instructions with / in them, which AsmLexer parses
380     // as seperate tokens, so if we find such tokens immediately adjacent (no
381     // whitespace), expand the name to include them:
382     for (;;) {
383       auto &Sep = Lexer.getTok();
384       if (Sep.getLoc().getPointer() != Name.end() ||
385           Sep.getKind() != AsmToken::Slash)
386         break;
387       // Extend name with /
388       Name = StringRef(Name.begin(), Name.size() + Sep.getString().size());
389       Parser.Lex();
390       // We must now find another identifier, or error.
391       auto &Id = Lexer.getTok();
392       if (Id.getKind() != AsmToken::Identifier ||
393           Id.getLoc().getPointer() != Name.end())
394         return error("Incomplete instruction name: ", Id);
395       Name = StringRef(Name.begin(), Name.size() + Id.getString().size());
396       Parser.Lex();
397     }
398 
399     // Now construct the name as first operand.
400     Operands.push_back(make_unique<WebAssemblyOperand>(
401         WebAssemblyOperand::Token, NameLoc, SMLoc::getFromPointer(Name.end()),
402         WebAssemblyOperand::TokOp{Name}));
403     auto NamePair = Name.split('.');
404     // If no '.', there is no type prefix.
405     auto BaseName = NamePair.second.empty() ? NamePair.first : NamePair.second;
406 
407     // If this instruction is part of a control flow structure, ensure
408     // proper nesting.
409     bool ExpectBlockType = false;
410     if (BaseName == "block") {
411       push(Block);
412       ExpectBlockType = true;
413     } else if (BaseName == "loop") {
414       push(Loop);
415       ExpectBlockType = true;
416     } else if (BaseName == "try") {
417       push(Try);
418       ExpectBlockType = true;
419     } else if (BaseName == "if") {
420       push(If);
421       ExpectBlockType = true;
422     } else if (BaseName == "else") {
423       if (pop(BaseName, If))
424         return true;
425       push(Else);
426     } else if (BaseName == "catch") {
427       if (pop(BaseName, Try))
428         return true;
429       push(Try);
430     } else if (BaseName == "catch_all") {
431       if (pop(BaseName, Try))
432         return true;
433       push(Try);
434     } else if (BaseName == "end_if") {
435       if (pop(BaseName, If, Else))
436         return true;
437     } else if (BaseName == "end_try") {
438       if (pop(BaseName, Try))
439         return true;
440     } else if (BaseName == "end_loop") {
441       if (pop(BaseName, Loop))
442         return true;
443     } else if (BaseName == "end_block") {
444       if (pop(BaseName, Block))
445         return true;
446     } else if (BaseName == "end_function") {
447       if (pop(BaseName, Function) || ensureEmptyNestingStack())
448         return true;
449     }
450 
451     while (Lexer.isNot(AsmToken::EndOfStatement)) {
452       auto &Tok = Lexer.getTok();
453       switch (Tok.getKind()) {
454       case AsmToken::Identifier: {
455         auto &Id = Lexer.getTok();
456         if (ExpectBlockType) {
457           // Assume this identifier is a block_type.
458           auto BT = parseBlockType(Id.getString());
459           if (BT == WebAssembly::ExprType::Invalid)
460             return error("Unknown block type: ", Id);
461           addBlockTypeOperand(Operands, NameLoc, BT);
462           Parser.Lex();
463         } else {
464           // Assume this identifier is a label.
465           const MCExpr *Val;
466           SMLoc End;
467           if (Parser.parsePrimaryExpr(Val, End))
468             return error("Cannot parse symbol: ", Lexer.getTok());
469           Operands.push_back(make_unique<WebAssemblyOperand>(
470               WebAssemblyOperand::Symbol, Id.getLoc(), Id.getEndLoc(),
471               WebAssemblyOperand::SymOp{Val}));
472         }
473         break;
474       }
475       case AsmToken::Minus:
476         Parser.Lex();
477         if (Lexer.isNot(AsmToken::Integer))
478           return error("Expected integer instead got: ", Lexer.getTok());
479         if (parseOperandStartingWithInteger(true, Operands, BaseName))
480           return true;
481         break;
482       case AsmToken::Integer:
483         if (parseOperandStartingWithInteger(false, Operands, BaseName))
484           return true;
485         break;
486       case AsmToken::Real: {
487         double Val;
488         if (Tok.getString().getAsDouble(Val, false))
489           return error("Cannot parse real: ", Tok);
490         Operands.push_back(make_unique<WebAssemblyOperand>(
491             WebAssemblyOperand::Float, Tok.getLoc(), Tok.getEndLoc(),
492             WebAssemblyOperand::FltOp{Val}));
493         Parser.Lex();
494         break;
495       }
496       case AsmToken::LCurly: {
497         Parser.Lex();
498         auto Op = make_unique<WebAssemblyOperand>(
499             WebAssemblyOperand::BrList, Tok.getLoc(), Tok.getEndLoc());
500         if (!Lexer.is(AsmToken::RCurly))
501           for (;;) {
502             Op->BrL.List.push_back(Lexer.getTok().getIntVal());
503             expect(AsmToken::Integer, "integer");
504             if (!isNext(AsmToken::Comma))
505               break;
506           }
507         expect(AsmToken::RCurly, "}");
508         Operands.push_back(std::move(Op));
509         break;
510       }
511       default:
512         return error("Unexpected token in operand: ", Tok);
513       }
514       if (Lexer.isNot(AsmToken::EndOfStatement)) {
515         if (expect(AsmToken::Comma, ","))
516           return true;
517       }
518     }
519     if (ExpectBlockType && Operands.size() == 1) {
520       // Support blocks with no operands as default to void.
521       addBlockTypeOperand(Operands, NameLoc, WebAssembly::ExprType::Void);
522     }
523     Parser.Lex();
524     return false;
525   }
526 
onLabelParsed(MCSymbol * Symbol)527   void onLabelParsed(MCSymbol *Symbol) override {
528     LastLabel = Symbol;
529     CurrentState = Label;
530   }
531 
parseSignature(wasm::WasmSignature * Signature)532   bool parseSignature(wasm::WasmSignature *Signature) {
533     if (expect(AsmToken::LParen, "("))
534       return true;
535     if (parseRegTypeList(Signature->Params))
536       return true;
537     if (expect(AsmToken::RParen, ")"))
538       return true;
539     if (expect(AsmToken::MinusGreater, "->"))
540       return true;
541     if (expect(AsmToken::LParen, "("))
542       return true;
543     if (parseRegTypeList(Signature->Returns))
544       return true;
545     if (expect(AsmToken::RParen, ")"))
546       return true;
547     return false;
548   }
549 
550   // This function processes wasm-specific directives streamed to
551   // WebAssemblyTargetStreamer, all others go to the generic parser
552   // (see WasmAsmParser).
ParseDirective(AsmToken DirectiveID)553   bool ParseDirective(AsmToken DirectiveID) override {
554     // This function has a really weird return value behavior that is different
555     // from all the other parsing functions:
556     // - return true && no tokens consumed -> don't know this directive / let
557     //   the generic parser handle it.
558     // - return true && tokens consumed -> a parsing error occurred.
559     // - return false -> processed this directive successfully.
560     assert(DirectiveID.getKind() == AsmToken::Identifier);
561     auto &Out = getStreamer();
562     auto &TOut =
563         reinterpret_cast<WebAssemblyTargetStreamer &>(*Out.getTargetStreamer());
564 
565     // TODO: any time we return an error, at least one token must have been
566     // consumed, otherwise this will not signal an error to the caller.
567     if (DirectiveID.getString() == ".globaltype") {
568       auto SymName = expectIdent();
569       if (SymName.empty())
570         return true;
571       if (expect(AsmToken::Comma, ","))
572         return true;
573       auto TypeTok = Lexer.getTok();
574       auto TypeName = expectIdent();
575       if (TypeName.empty())
576         return true;
577       auto Type = parseType(TypeName);
578       if (!Type)
579         return error("Unknown type in .globaltype directive: ", TypeTok);
580       // Now set this symbol with the correct type.
581       auto WasmSym = cast<MCSymbolWasm>(
582           TOut.getStreamer().getContext().getOrCreateSymbol(SymName));
583       WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);
584       WasmSym->setGlobalType(
585           wasm::WasmGlobalType{uint8_t(Type.getValue()), true});
586       // And emit the directive again.
587       TOut.emitGlobalType(WasmSym);
588       return expect(AsmToken::EndOfStatement, "EOL");
589     }
590 
591     if (DirectiveID.getString() == ".functype") {
592       // This code has to send things to the streamer similar to
593       // WebAssemblyAsmPrinter::EmitFunctionBodyStart.
594       // TODO: would be good to factor this into a common function, but the
595       // assembler and backend really don't share any common code, and this code
596       // parses the locals seperately.
597       auto SymName = expectIdent();
598       if (SymName.empty())
599         return true;
600       auto WasmSym = cast<MCSymbolWasm>(
601           TOut.getStreamer().getContext().getOrCreateSymbol(SymName));
602       if (CurrentState == Label && WasmSym == LastLabel) {
603         // This .functype indicates a start of a function.
604         if (ensureEmptyNestingStack())
605           return true;
606         CurrentState = FunctionStart;
607         push(Function);
608       }
609       auto Signature = make_unique<wasm::WasmSignature>();
610       if (parseSignature(Signature.get()))
611         return true;
612       WasmSym->setSignature(Signature.get());
613       addSignature(std::move(Signature));
614       WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
615       TOut.emitFunctionType(WasmSym);
616       // TODO: backend also calls TOut.emitIndIdx, but that is not implemented.
617       return expect(AsmToken::EndOfStatement, "EOL");
618     }
619 
620     if (DirectiveID.getString() == ".eventtype") {
621       auto SymName = expectIdent();
622       if (SymName.empty())
623         return true;
624       auto WasmSym = cast<MCSymbolWasm>(
625           TOut.getStreamer().getContext().getOrCreateSymbol(SymName));
626       auto Signature = make_unique<wasm::WasmSignature>();
627       if (parseRegTypeList(Signature->Params))
628         return true;
629       WasmSym->setSignature(Signature.get());
630       addSignature(std::move(Signature));
631       WasmSym->setType(wasm::WASM_SYMBOL_TYPE_EVENT);
632       TOut.emitEventType(WasmSym);
633       // TODO: backend also calls TOut.emitIndIdx, but that is not implemented.
634       return expect(AsmToken::EndOfStatement, "EOL");
635     }
636 
637     if (DirectiveID.getString() == ".local") {
638       if (CurrentState != FunctionStart)
639         return error(".local directive should follow the start of a function",
640                      Lexer.getTok());
641       SmallVector<wasm::ValType, 4> Locals;
642       if (parseRegTypeList(Locals))
643         return true;
644       TOut.emitLocal(Locals);
645       CurrentState = FunctionLocals;
646       return expect(AsmToken::EndOfStatement, "EOL");
647     }
648 
649     return true; // We didn't process this directive.
650   }
651 
MatchAndEmitInstruction(SMLoc IDLoc,unsigned &,OperandVector & Operands,MCStreamer & Out,uint64_t & ErrorInfo,bool MatchingInlineAsm)652   bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned & /*Opcode*/,
653                                OperandVector &Operands, MCStreamer &Out,
654                                uint64_t &ErrorInfo,
655                                bool MatchingInlineAsm) override {
656     MCInst Inst;
657     unsigned MatchResult =
658         MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm);
659     switch (MatchResult) {
660     case Match_Success: {
661       if (CurrentState == FunctionStart) {
662         // This is the first instruction in a function, but we haven't seen
663         // a .local directive yet. The streamer requires locals to be encoded
664         // as a prelude to the instructions, so emit an empty list of locals
665         // here.
666         auto &TOut = reinterpret_cast<WebAssemblyTargetStreamer &>(
667             *Out.getTargetStreamer());
668         TOut.emitLocal(SmallVector<wasm::ValType, 0>());
669       }
670       CurrentState = Instructions;
671       Out.EmitInstruction(Inst, getSTI());
672       return false;
673     }
674     case Match_MissingFeature:
675       return Parser.Error(
676           IDLoc, "instruction requires a WASM feature not currently enabled");
677     case Match_MnemonicFail:
678       return Parser.Error(IDLoc, "invalid instruction");
679     case Match_NearMisses:
680       return Parser.Error(IDLoc, "ambiguous instruction");
681     case Match_InvalidTiedOperand:
682     case Match_InvalidOperand: {
683       SMLoc ErrorLoc = IDLoc;
684       if (ErrorInfo != ~0ULL) {
685         if (ErrorInfo >= Operands.size())
686           return Parser.Error(IDLoc, "too few operands for instruction");
687         ErrorLoc = Operands[ErrorInfo]->getStartLoc();
688         if (ErrorLoc == SMLoc())
689           ErrorLoc = IDLoc;
690       }
691       return Parser.Error(ErrorLoc, "invalid operand for instruction");
692     }
693     }
694     llvm_unreachable("Implement any new match types added!");
695   }
696 
onEndOfFile()697   void onEndOfFile() override { ensureEmptyNestingStack(); }
698 };
699 } // end anonymous namespace
700 
701 // Force static initialization.
LLVMInitializeWebAssemblyAsmParser()702 extern "C" void LLVMInitializeWebAssemblyAsmParser() {
703   RegisterMCAsmParser<WebAssemblyAsmParser> X(getTheWebAssemblyTarget32());
704   RegisterMCAsmParser<WebAssemblyAsmParser> Y(getTheWebAssemblyTarget64());
705 }
706 
707 #define GET_REGISTER_MATCHER
708 #define GET_MATCHER_IMPLEMENTATION
709 #include "WebAssemblyGenAsmMatcher.inc"
710