LLVM  10.0.0svn
WebAssemblyAsmParser.cpp
Go to the documentation of this file.
1 //==- WebAssemblyAsmParser.cpp - Assembler for WebAssembly -*- C++ -*-==//
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 /// \file
10 /// This file is part of the WebAssembly Assembler.
11 ///
12 /// It contains code to translate a parsed .s file into MCInsts.
13 ///
14 //===----------------------------------------------------------------------===//
15 
19 #include "WebAssembly.h"
20 #include "llvm/MC/MCContext.h"
21 #include "llvm/MC/MCExpr.h"
22 #include "llvm/MC/MCInst.h"
23 #include "llvm/MC/MCInstrInfo.h"
26 #include "llvm/MC/MCSectionWasm.h"
27 #include "llvm/MC/MCStreamer.h"
29 #include "llvm/MC/MCSymbol.h"
30 #include "llvm/MC/MCSymbolWasm.h"
31 #include "llvm/Support/Endian.h"
33 
34 using namespace llvm;
35 
36 #define DEBUG_TYPE "wasm-asm-parser"
37 
38 namespace {
39 
40 /// WebAssemblyOperand - Instances of this class represent the operands in a
41 /// parsed WASM machine instruction.
42 struct WebAssemblyOperand : public MCParsedAsmOperand {
43  enum KindTy { Token, Integer, Float, Symbol, BrList } Kind;
44 
45  SMLoc StartLoc, EndLoc;
46 
47  struct TokOp {
48  StringRef Tok;
49  };
50 
51  struct IntOp {
52  int64_t Val;
53  };
54 
55  struct FltOp {
56  double Val;
57  };
58 
59  struct SymOp {
60  const MCExpr *Exp;
61  };
62 
63  struct BrLOp {
64  std::vector<unsigned> List;
65  };
66 
67  union {
68  struct TokOp Tok;
69  struct IntOp Int;
70  struct FltOp Flt;
71  struct SymOp Sym;
72  struct BrLOp BrL;
73  };
74 
75  WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, TokOp T)
76  : Kind(K), StartLoc(Start), EndLoc(End), Tok(T) {}
77  WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, IntOp I)
78  : Kind(K), StartLoc(Start), EndLoc(End), Int(I) {}
79  WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, FltOp F)
80  : Kind(K), StartLoc(Start), EndLoc(End), Flt(F) {}
81  WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, SymOp S)
82  : Kind(K), StartLoc(Start), EndLoc(End), Sym(S) {}
83  WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End)
84  : Kind(K), StartLoc(Start), EndLoc(End), BrL() {}
85 
86  ~WebAssemblyOperand() {
87  if (isBrList())
88  BrL.~BrLOp();
89  }
90 
91  bool isToken() const override { return Kind == Token; }
92  bool isImm() const override { return Kind == Integer || Kind == Symbol; }
93  bool isFPImm() const { return Kind == Float; }
94  bool isMem() const override { return false; }
95  bool isReg() const override { return false; }
96  bool isBrList() const { return Kind == BrList; }
97 
98  unsigned getReg() const override {
99  llvm_unreachable("Assembly inspects a register operand");
100  return 0;
101  }
102 
103  StringRef getToken() const {
104  assert(isToken());
105  return Tok.Tok;
106  }
107 
108  SMLoc getStartLoc() const override { return StartLoc; }
109  SMLoc getEndLoc() const override { return EndLoc; }
110 
111  void addRegOperands(MCInst &, unsigned) const {
112  // Required by the assembly matcher.
113  llvm_unreachable("Assembly matcher creates register operands");
114  }
115 
116  void addImmOperands(MCInst &Inst, unsigned N) const {
117  assert(N == 1 && "Invalid number of operands!");
118  if (Kind == Integer)
120  else if (Kind == Symbol)
121  Inst.addOperand(MCOperand::createExpr(Sym.Exp));
122  else
123  llvm_unreachable("Should be integer immediate or symbol!");
124  }
125 
126  void addFPImmOperands(MCInst &Inst, unsigned N) const {
127  assert(N == 1 && "Invalid number of operands!");
128  if (Kind == Float)
129  Inst.addOperand(MCOperand::createFPImm(Flt.Val));
130  else
131  llvm_unreachable("Should be float immediate!");
132  }
133 
134  void addBrListOperands(MCInst &Inst, unsigned N) const {
135  assert(N == 1 && isBrList() && "Invalid BrList!");
136  for (auto Br : BrL.List)
138  }
139 
140  void print(raw_ostream &OS) const override {
141  switch (Kind) {
142  case Token:
143  OS << "Tok:" << Tok.Tok;
144  break;
145  case Integer:
146  OS << "Int:" << Int.Val;
147  break;
148  case Float:
149  OS << "Flt:" << Flt.Val;
150  break;
151  case Symbol:
152  OS << "Sym:" << Sym.Exp;
153  break;
154  case BrList:
155  OS << "BrList:" << BrL.List.size();
156  break;
157  }
158  }
159 };
160 
161 class WebAssemblyAsmParser final : public MCTargetAsmParser {
162  MCAsmParser &Parser;
163  MCAsmLexer &Lexer;
164 
165  // Much like WebAssemblyAsmPrinter in the backend, we have to own these.
166  std::vector<std::unique_ptr<wasm::WasmSignature>> Signatures;
167 
168  // Order of labels, directives and instructions in a .s file have no
169  // syntactical enforcement. This class is a callback from the actual parser,
170  // and yet we have to be feeding data to the streamer in a very particular
171  // order to ensure a correct binary encoding that matches the regular backend
172  // (the streamer does not enforce this). This "state machine" enum helps
173  // guarantee that correct order.
174  enum ParserState {
175  FileStart,
176  Label,
177  FunctionStart,
178  FunctionLocals,
179  Instructions,
180  EndFunction,
181  DataSection,
182  } CurrentState = FileStart;
183 
184  // For ensuring blocks are properly nested.
185  enum NestingType {
186  Function,
187  Block,
188  Loop,
189  Try,
190  If,
191  Else,
192  Undefined,
193  };
194  std::vector<NestingType> NestingStack;
195 
196  // We track this to see if a .functype following a label is the same,
197  // as this is how we recognize the start of a function.
198  MCSymbol *LastLabel = nullptr;
199  MCSymbol *LastFunctionLabel = nullptr;
200 
201 public:
202  WebAssemblyAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
203  const MCInstrInfo &MII, const MCTargetOptions &Options)
204  : MCTargetAsmParser(Options, STI, MII), Parser(Parser),
205  Lexer(Parser.getLexer()) {
206  setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
207  }
208 
209 #define GET_ASSEMBLER_HEADER
210 #include "WebAssemblyGenAsmMatcher.inc"
211 
212  // TODO: This is required to be implemented, but appears unused.
213  bool ParseRegister(unsigned & /*RegNo*/, SMLoc & /*StartLoc*/,
214  SMLoc & /*EndLoc*/) override {
215  llvm_unreachable("ParseRegister is not implemented.");
216  }
217 
218  bool error(const Twine &Msg, const AsmToken &Tok) {
219  return Parser.Error(Tok.getLoc(), Msg + Tok.getString());
220  }
221 
222  bool error(const Twine &Msg) {
223  return Parser.Error(Lexer.getTok().getLoc(), Msg);
224  }
225 
226  void addSignature(std::unique_ptr<wasm::WasmSignature> &&Sig) {
227  Signatures.push_back(std::move(Sig));
228  }
229 
230  std::pair<StringRef, StringRef> nestingString(NestingType NT) {
231  switch (NT) {
232  case Function:
233  return {"function", "end_function"};
234  case Block:
235  return {"block", "end_block"};
236  case Loop:
237  return {"loop", "end_loop"};
238  case Try:
239  return {"try", "end_try"};
240  case If:
241  return {"if", "end_if"};
242  case Else:
243  return {"else", "end_if"};
244  default:
245  llvm_unreachable("unknown NestingType");
246  }
247  }
248 
249  void push(NestingType NT) { NestingStack.push_back(NT); }
250 
251  bool pop(StringRef Ins, NestingType NT1, NestingType NT2 = Undefined) {
252  if (NestingStack.empty())
253  return error(Twine("End of block construct with no start: ") + Ins);
254  auto Top = NestingStack.back();
255  if (Top != NT1 && Top != NT2)
256  return error(Twine("Block construct type mismatch, expected: ") +
257  nestingString(Top).second + ", instead got: " + Ins);
258  NestingStack.pop_back();
259  return false;
260  }
261 
262  bool ensureEmptyNestingStack() {
263  auto Err = !NestingStack.empty();
264  while (!NestingStack.empty()) {
265  error(Twine("Unmatched block construct(s) at function end: ") +
266  nestingString(NestingStack.back()).first);
267  NestingStack.pop_back();
268  }
269  return Err;
270  }
271 
272  bool isNext(AsmToken::TokenKind Kind) {
273  auto Ok = Lexer.is(Kind);
274  if (Ok)
275  Parser.Lex();
276  return Ok;
277  }
278 
279  bool expect(AsmToken::TokenKind Kind, const char *KindName) {
280  if (!isNext(Kind))
281  return error(std::string("Expected ") + KindName + ", instead got: ",
282  Lexer.getTok());
283  return false;
284  }
285 
286  StringRef expectIdent() {
287  if (!Lexer.is(AsmToken::Identifier)) {
288  error("Expected identifier, got: ", Lexer.getTok());
289  return StringRef();
290  }
291  auto Name = Lexer.getTok().getString();
292  Parser.Lex();
293  return Name;
294  }
295 
297  // FIXME: can't use StringSwitch because wasm::ValType doesn't have a
298  // "invalid" value.
299  if (Type == "i32")
300  return wasm::ValType::I32;
301  if (Type == "i64")
302  return wasm::ValType::I64;
303  if (Type == "f32")
304  return wasm::ValType::F32;
305  if (Type == "f64")
306  return wasm::ValType::F64;
307  if (Type == "v128" || Type == "i8x16" || Type == "i16x8" ||
308  Type == "i32x4" || Type == "i64x2" || Type == "f32x4" ||
309  Type == "f64x2")
310  return wasm::ValType::V128;
311  if (Type == "exnref")
312  return wasm::ValType::EXNREF;
313  return Optional<wasm::ValType>();
314  }
315 
316  WebAssembly::ExprType parseBlockType(StringRef ID) {
318  .Case("i32", WebAssembly::ExprType::I32)
326  }
327 
328  bool parseRegTypeList(SmallVectorImpl<wasm::ValType> &Types) {
329  while (Lexer.is(AsmToken::Identifier)) {
330  auto Type = parseType(Lexer.getTok().getString());
331  if (!Type)
332  return error("unknown type: ", Lexer.getTok());
333  Types.push_back(Type.getValue());
334  Parser.Lex();
335  if (!isNext(AsmToken::Comma))
336  break;
337  }
338  return false;
339  }
340 
341  void parseSingleInteger(bool IsNegative, OperandVector &Operands) {
342  auto &Int = Lexer.getTok();
343  int64_t Val = Int.getIntVal();
344  if (IsNegative)
345  Val = -Val;
346  Operands.push_back(std::make_unique<WebAssemblyOperand>(
347  WebAssemblyOperand::Integer, Int.getLoc(), Int.getEndLoc(),
348  WebAssemblyOperand::IntOp{Val}));
349  Parser.Lex();
350  }
351 
352  bool parseSingleFloat(bool IsNegative, OperandVector &Operands) {
353  auto &Flt = Lexer.getTok();
354  double Val;
355  if (Flt.getString().getAsDouble(Val, false))
356  return error("Cannot parse real: ", Flt);
357  if (IsNegative)
358  Val = -Val;
359  Operands.push_back(std::make_unique<WebAssemblyOperand>(
360  WebAssemblyOperand::Float, Flt.getLoc(), Flt.getEndLoc(),
361  WebAssemblyOperand::FltOp{Val}));
362  Parser.Lex();
363  return false;
364  }
365 
366  bool parseSpecialFloatMaybe(bool IsNegative, OperandVector &Operands) {
367  if (Lexer.isNot(AsmToken::Identifier))
368  return true;
369  auto &Flt = Lexer.getTok();
370  auto S = Flt.getString();
371  double Val;
372  if (S.compare_lower("infinity") == 0) {
373  Val = std::numeric_limits<double>::infinity();
374  } else if (S.compare_lower("nan") == 0) {
375  Val = std::numeric_limits<double>::quiet_NaN();
376  } else {
377  return true;
378  }
379  if (IsNegative)
380  Val = -Val;
381  Operands.push_back(std::make_unique<WebAssemblyOperand>(
382  WebAssemblyOperand::Float, Flt.getLoc(), Flt.getEndLoc(),
383  WebAssemblyOperand::FltOp{Val}));
384  Parser.Lex();
385  return false;
386  }
387 
388  bool checkForP2AlignIfLoadStore(OperandVector &Operands, StringRef InstName) {
389  // FIXME: there is probably a cleaner way to do this.
390  auto IsLoadStore = InstName.find(".load") != StringRef::npos ||
391  InstName.find(".store") != StringRef::npos;
392  auto IsAtomic = InstName.find("atomic.") != StringRef::npos;
393  if (IsLoadStore || IsAtomic) {
394  // Parse load/store operands of the form: offset:p2align=align
395  if (IsLoadStore && isNext(AsmToken::Colon)) {
396  auto Id = expectIdent();
397  if (Id != "p2align")
398  return error("Expected p2align, instead got: " + Id);
399  if (expect(AsmToken::Equal, "="))
400  return true;
401  if (!Lexer.is(AsmToken::Integer))
402  return error("Expected integer constant");
403  parseSingleInteger(false, Operands);
404  } else {
405  // Alignment not specified (or atomics, must use default alignment).
406  // We can't just call WebAssembly::GetDefaultP2Align since we don't have
407  // an opcode until after the assembly matcher, so set a default to fix
408  // up later.
409  auto Tok = Lexer.getTok();
410  Operands.push_back(std::make_unique<WebAssemblyOperand>(
412  WebAssemblyOperand::IntOp{-1}));
413  }
414  }
415  return false;
416  }
417 
418  void addBlockTypeOperand(OperandVector &Operands, SMLoc NameLoc,
420  Operands.push_back(std::make_unique<WebAssemblyOperand>(
421  WebAssemblyOperand::Integer, NameLoc, NameLoc,
422  WebAssemblyOperand::IntOp{static_cast<int64_t>(BT)}));
423  }
424 
425  bool ParseInstruction(ParseInstructionInfo & /*Info*/, StringRef Name,
426  SMLoc NameLoc, OperandVector &Operands) override {
427  // Note: Name does NOT point into the sourcecode, but to a local, so
428  // use NameLoc instead.
429  Name = StringRef(NameLoc.getPointer(), Name.size());
430 
431  // WebAssembly has instructions with / in them, which AsmLexer parses
432  // as seperate tokens, so if we find such tokens immediately adjacent (no
433  // whitespace), expand the name to include them:
434  for (;;) {
435  auto &Sep = Lexer.getTok();
436  if (Sep.getLoc().getPointer() != Name.end() ||
437  Sep.getKind() != AsmToken::Slash)
438  break;
439  // Extend name with /
440  Name = StringRef(Name.begin(), Name.size() + Sep.getString().size());
441  Parser.Lex();
442  // We must now find another identifier, or error.
443  auto &Id = Lexer.getTok();
444  if (Id.getKind() != AsmToken::Identifier ||
445  Id.getLoc().getPointer() != Name.end())
446  return error("Incomplete instruction name: ", Id);
447  Name = StringRef(Name.begin(), Name.size() + Id.getString().size());
448  Parser.Lex();
449  }
450 
451  // Now construct the name as first operand.
452  Operands.push_back(std::make_unique<WebAssemblyOperand>(
453  WebAssemblyOperand::Token, NameLoc, SMLoc::getFromPointer(Name.end()),
454  WebAssemblyOperand::TokOp{Name}));
455 
456  // If this instruction is part of a control flow structure, ensure
457  // proper nesting.
458  bool ExpectBlockType = false;
459  if (Name == "block") {
460  push(Block);
461  ExpectBlockType = true;
462  } else if (Name == "loop") {
463  push(Loop);
464  ExpectBlockType = true;
465  } else if (Name == "try") {
466  push(Try);
467  ExpectBlockType = true;
468  } else if (Name == "if") {
469  push(If);
470  ExpectBlockType = true;
471  } else if (Name == "else") {
472  if (pop(Name, If))
473  return true;
474  push(Else);
475  } else if (Name == "catch") {
476  if (pop(Name, Try))
477  return true;
478  push(Try);
479  } else if (Name == "end_if") {
480  if (pop(Name, If, Else))
481  return true;
482  } else if (Name == "end_try") {
483  if (pop(Name, Try))
484  return true;
485  } else if (Name == "end_loop") {
486  if (pop(Name, Loop))
487  return true;
488  } else if (Name == "end_block") {
489  if (pop(Name, Block))
490  return true;
491  } else if (Name == "end_function") {
492  ensureLocals(getStreamer());
493  CurrentState = EndFunction;
494  if (pop(Name, Function) || ensureEmptyNestingStack())
495  return true;
496  } else if (Name == "call_indirect" || Name == "return_call_indirect") {
497  // This has a special TYPEINDEX operand which in text we
498  // represent as a signature, such that we can re-build this signature,
499  // attach it to an anonymous symbol, which is what WasmObjectWriter
500  // expects to be able to recreate the actual unique-ified type indices.
501  auto Loc = Parser.getTok();
502  auto Signature = std::make_unique<wasm::WasmSignature>();
503  if (parseSignature(Signature.get()))
504  return true;
505  auto &Ctx = getStreamer().getContext();
506  // The "true" here will cause this to be a nameless symbol.
507  MCSymbol *Sym = Ctx.createTempSymbol("typeindex", true);
508  auto *WasmSym = cast<MCSymbolWasm>(Sym);
509  WasmSym->setSignature(Signature.get());
510  addSignature(std::move(Signature));
511  WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
512  const MCExpr *Expr = MCSymbolRefExpr::create(
513  WasmSym, MCSymbolRefExpr::VK_WASM_TYPEINDEX, Ctx);
514  Operands.push_back(std::make_unique<WebAssemblyOperand>(
515  WebAssemblyOperand::Symbol, Loc.getLoc(), Loc.getEndLoc(),
516  WebAssemblyOperand::SymOp{Expr}));
517  }
518 
519  while (Lexer.isNot(AsmToken::EndOfStatement)) {
520  auto &Tok = Lexer.getTok();
521  switch (Tok.getKind()) {
522  case AsmToken::Identifier: {
523  if (!parseSpecialFloatMaybe(false, Operands))
524  break;
525  auto &Id = Lexer.getTok();
526  if (ExpectBlockType) {
527  // Assume this identifier is a block_type.
528  auto BT = parseBlockType(Id.getString());
530  return error("Unknown block type: ", Id);
531  addBlockTypeOperand(Operands, NameLoc, BT);
532  Parser.Lex();
533  } else {
534  // Assume this identifier is a label.
535  const MCExpr *Val;
536  SMLoc End;
537  if (Parser.parseExpression(Val, End))
538  return error("Cannot parse symbol: ", Lexer.getTok());
539  Operands.push_back(std::make_unique<WebAssemblyOperand>(
540  WebAssemblyOperand::Symbol, Id.getLoc(), Id.getEndLoc(),
541  WebAssemblyOperand::SymOp{Val}));
542  if (checkForP2AlignIfLoadStore(Operands, Name))
543  return true;
544  }
545  break;
546  }
547  case AsmToken::Minus:
548  Parser.Lex();
549  if (Lexer.is(AsmToken::Integer)) {
550  parseSingleInteger(true, Operands);
551  if (checkForP2AlignIfLoadStore(Operands, Name))
552  return true;
553  } else if(Lexer.is(AsmToken::Real)) {
554  if (parseSingleFloat(true, Operands))
555  return true;
556  } else if (!parseSpecialFloatMaybe(true, Operands)) {
557  } else {
558  return error("Expected numeric constant instead got: ",
559  Lexer.getTok());
560  }
561  break;
562  case AsmToken::Integer:
563  parseSingleInteger(false, Operands);
564  if (checkForP2AlignIfLoadStore(Operands, Name))
565  return true;
566  break;
567  case AsmToken::Real: {
568  if (parseSingleFloat(false, Operands))
569  return true;
570  break;
571  }
572  case AsmToken::LCurly: {
573  Parser.Lex();
574  auto Op = std::make_unique<WebAssemblyOperand>(
575  WebAssemblyOperand::BrList, Tok.getLoc(), Tok.getEndLoc());
576  if (!Lexer.is(AsmToken::RCurly))
577  for (;;) {
578  Op->BrL.List.push_back(Lexer.getTok().getIntVal());
579  expect(AsmToken::Integer, "integer");
580  if (!isNext(AsmToken::Comma))
581  break;
582  }
583  expect(AsmToken::RCurly, "}");
584  Operands.push_back(std::move(Op));
585  break;
586  }
587  default:
588  return error("Unexpected token in operand: ", Tok);
589  }
590  if (Lexer.isNot(AsmToken::EndOfStatement)) {
591  if (expect(AsmToken::Comma, ","))
592  return true;
593  }
594  }
595  if (ExpectBlockType && Operands.size() == 1) {
596  // Support blocks with no operands as default to void.
597  addBlockTypeOperand(Operands, NameLoc, WebAssembly::ExprType::Void);
598  }
599  Parser.Lex();
600  return false;
601  }
602 
603  void onLabelParsed(MCSymbol *Symbol) override {
604  LastLabel = Symbol;
605  CurrentState = Label;
606  }
607 
608  bool parseSignature(wasm::WasmSignature *Signature) {
609  if (expect(AsmToken::LParen, "("))
610  return true;
611  if (parseRegTypeList(Signature->Params))
612  return true;
613  if (expect(AsmToken::RParen, ")"))
614  return true;
615  if (expect(AsmToken::MinusGreater, "->"))
616  return true;
617  if (expect(AsmToken::LParen, "("))
618  return true;
619  if (parseRegTypeList(Signature->Returns))
620  return true;
621  if (expect(AsmToken::RParen, ")"))
622  return true;
623  return false;
624  }
625 
626  bool CheckDataSection() {
627  if (CurrentState != DataSection) {
628  auto WS = cast<MCSectionWasm>(getStreamer().getCurrentSection().first);
629  if (WS && WS->getKind().isText())
630  return error("data directive must occur in a data segment: ",
631  Lexer.getTok());
632  }
633  CurrentState = DataSection;
634  return false;
635  }
636 
637  // This function processes wasm-specific directives streamed to
638  // WebAssemblyTargetStreamer, all others go to the generic parser
639  // (see WasmAsmParser).
640  bool ParseDirective(AsmToken DirectiveID) override {
641  // This function has a really weird return value behavior that is different
642  // from all the other parsing functions:
643  // - return true && no tokens consumed -> don't know this directive / let
644  // the generic parser handle it.
645  // - return true && tokens consumed -> a parsing error occurred.
646  // - return false -> processed this directive successfully.
647  assert(DirectiveID.getKind() == AsmToken::Identifier);
648  auto &Out = getStreamer();
649  auto &TOut =
650  reinterpret_cast<WebAssemblyTargetStreamer &>(*Out.getTargetStreamer());
651  auto &Ctx = Out.getContext();
652 
653  // TODO: any time we return an error, at least one token must have been
654  // consumed, otherwise this will not signal an error to the caller.
655  if (DirectiveID.getString() == ".globaltype") {
656  auto SymName = expectIdent();
657  if (SymName.empty())
658  return true;
659  if (expect(AsmToken::Comma, ","))
660  return true;
661  auto TypeTok = Lexer.getTok();
662  auto TypeName = expectIdent();
663  if (TypeName.empty())
664  return true;
665  auto Type = parseType(TypeName);
666  if (!Type)
667  return error("Unknown type in .globaltype directive: ", TypeTok);
668  // Now set this symbol with the correct type.
669  auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
670  WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);
671  WasmSym->setGlobalType(
672  wasm::WasmGlobalType{uint8_t(Type.getValue()), true});
673  // And emit the directive again.
674  TOut.emitGlobalType(WasmSym);
675  return expect(AsmToken::EndOfStatement, "EOL");
676  }
677 
678  if (DirectiveID.getString() == ".functype") {
679  // This code has to send things to the streamer similar to
680  // WebAssemblyAsmPrinter::EmitFunctionBodyStart.
681  // TODO: would be good to factor this into a common function, but the
682  // assembler and backend really don't share any common code, and this code
683  // parses the locals seperately.
684  auto SymName = expectIdent();
685  if (SymName.empty())
686  return true;
687  auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
688  if (CurrentState == Label && WasmSym == LastLabel) {
689  // This .functype indicates a start of a function.
690  if (ensureEmptyNestingStack())
691  return true;
692  CurrentState = FunctionStart;
693  LastFunctionLabel = LastLabel;
694  push(Function);
695  }
696  auto Signature = std::make_unique<wasm::WasmSignature>();
697  if (parseSignature(Signature.get()))
698  return true;
699  WasmSym->setSignature(Signature.get());
700  addSignature(std::move(Signature));
701  WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
702  TOut.emitFunctionType(WasmSym);
703  // TODO: backend also calls TOut.emitIndIdx, but that is not implemented.
704  return expect(AsmToken::EndOfStatement, "EOL");
705  }
706 
707  if (DirectiveID.getString() == ".eventtype") {
708  auto SymName = expectIdent();
709  if (SymName.empty())
710  return true;
711  auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
712  auto Signature = std::make_unique<wasm::WasmSignature>();
713  if (parseRegTypeList(Signature->Params))
714  return true;
715  WasmSym->setSignature(Signature.get());
716  addSignature(std::move(Signature));
717  WasmSym->setType(wasm::WASM_SYMBOL_TYPE_EVENT);
718  TOut.emitEventType(WasmSym);
719  // TODO: backend also calls TOut.emitIndIdx, but that is not implemented.
720  return expect(AsmToken::EndOfStatement, "EOL");
721  }
722 
723  if (DirectiveID.getString() == ".local") {
724  if (CurrentState != FunctionStart)
725  return error(".local directive should follow the start of a function",
726  Lexer.getTok());
728  if (parseRegTypeList(Locals))
729  return true;
730  TOut.emitLocal(Locals);
731  CurrentState = FunctionLocals;
732  return expect(AsmToken::EndOfStatement, "EOL");
733  }
734 
735  if (DirectiveID.getString() == ".int8" ||
736  DirectiveID.getString() == ".int16" ||
737  DirectiveID.getString() == ".int32" ||
738  DirectiveID.getString() == ".int64") {
739  if (CheckDataSection()) return true;
740  const MCExpr *Val;
741  SMLoc End;
742  if (Parser.parseExpression(Val, End))
743  return error("Cannot parse .int expression: ", Lexer.getTok());
744  size_t NumBits = 0;
745  DirectiveID.getString().drop_front(4).getAsInteger(10, NumBits);
746  Out.EmitValue(Val, NumBits / 8, End);
747  return expect(AsmToken::EndOfStatement, "EOL");
748  }
749 
750  if (DirectiveID.getString() == ".asciz") {
751  if (CheckDataSection()) return true;
752  std::string S;
753  if (Parser.parseEscapedString(S))
754  return error("Cannot parse string constant: ", Lexer.getTok());
755  Out.EmitBytes(StringRef(S.c_str(), S.length() + 1));
756  return expect(AsmToken::EndOfStatement, "EOL");
757  }
758 
759  return true; // We didn't process this directive.
760  }
761 
762  // Called either when the first instruction is parsed of the function ends.
763  void ensureLocals(MCStreamer &Out) {
764  if (CurrentState == FunctionStart) {
765  // We haven't seen a .local directive yet. The streamer requires locals to
766  // be encoded as a prelude to the instructions, so emit an empty list of
767  // locals here.
768  auto &TOut = reinterpret_cast<WebAssemblyTargetStreamer &>(
769  *Out.getTargetStreamer());
771  CurrentState = FunctionLocals;
772  }
773  }
774 
775  bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned & /*Opcode*/,
776  OperandVector &Operands, MCStreamer &Out,
777  uint64_t &ErrorInfo,
778  bool MatchingInlineAsm) override {
779  MCInst Inst;
780  Inst.setLoc(IDLoc);
781  unsigned MatchResult =
782  MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm);
783  switch (MatchResult) {
784  case Match_Success: {
785  ensureLocals(Out);
786  // Fix unknown p2align operands.
788  if (Align != -1U) {
789  auto &Op0 = Inst.getOperand(0);
790  if (Op0.getImm() == -1)
791  Op0.setImm(Align);
792  }
793  Out.EmitInstruction(Inst, getSTI());
794  if (CurrentState == EndFunction) {
795  onEndOfFunction();
796  } else {
797  CurrentState = Instructions;
798  }
799  return false;
800  }
801  case Match_MissingFeature:
802  return Parser.Error(
803  IDLoc, "instruction requires a WASM feature not currently enabled");
804  case Match_MnemonicFail:
805  return Parser.Error(IDLoc, "invalid instruction");
806  case Match_NearMisses:
807  return Parser.Error(IDLoc, "ambiguous instruction");
808  case Match_InvalidTiedOperand:
809  case Match_InvalidOperand: {
810  SMLoc ErrorLoc = IDLoc;
811  if (ErrorInfo != ~0ULL) {
812  if (ErrorInfo >= Operands.size())
813  return Parser.Error(IDLoc, "too few operands for instruction");
814  ErrorLoc = Operands[ErrorInfo]->getStartLoc();
815  if (ErrorLoc == SMLoc())
816  ErrorLoc = IDLoc;
817  }
818  return Parser.Error(ErrorLoc, "invalid operand for instruction");
819  }
820  }
821  llvm_unreachable("Implement any new match types added!");
822  }
823 
824  void doBeforeLabelEmit(MCSymbol *Symbol) override {
825  // Start a new section for the next function automatically, since our
826  // object writer expects each function to have its own section. This way
827  // The user can't forget this "convention".
828  auto SymName = Symbol->getName();
829  if (SymName.startswith(".L"))
830  return; // Local Symbol.
831  // Only create a new text section if we're already in one.
832  auto CWS = cast<MCSectionWasm>(getStreamer().getCurrentSection().first);
833  if (!CWS || !CWS->getKind().isText())
834  return;
835  auto SecName = ".text." + SymName;
836  auto WS = getContext().getWasmSection(SecName, SectionKind::getText());
837  getStreamer().SwitchSection(WS);
838  }
839 
840  void onEndOfFunction() {
841  // Automatically output a .size directive, so it becomes optional for the
842  // user.
843  if (!LastFunctionLabel) return;
844  auto TempSym = getContext().createLinkerPrivateTempSymbol();
845  getStreamer().EmitLabel(TempSym);
846  auto Start = MCSymbolRefExpr::create(LastFunctionLabel, getContext());
847  auto End = MCSymbolRefExpr::create(TempSym, getContext());
848  auto Expr =
849  MCBinaryExpr::create(MCBinaryExpr::Sub, End, Start, getContext());
850  getStreamer().emitELFSize(LastFunctionLabel, Expr);
851  }
852 
853  void onEndOfFile() override { ensureEmptyNestingStack(); }
854 };
855 } // end anonymous namespace
856 
857 // Force static initialization.
861 }
862 
863 #define GET_REGISTER_MATCHER
864 #define GET_MATCHER_IMPLEMENTATION
865 #include "WebAssemblyGenAsmMatcher.inc"
static bool isReg(const MCInst &MI, unsigned OpNo)
const AsmToken & getTok() const
Get the current (last) lexed token.
Definition: MCAsmLexer.h:100
static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang", "erlang-compatible garbage collector")
StringRef getString() const
Get the string for the current token, this includes all characters (for example, the quotes on string...
Definition: MCAsmMacro.h:110
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx)
Definition: MCExpr.h:331
This class represents lattice values for constants.
Definition: AllocatorList.h:23
bool is(AsmToken::TokenKind K) const
Check if the current token has kind K.
Definition: MCAsmLexer.h:135
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition: MCSymbol.h:41
Generic assembler parser interface, for use by target specific assembly parsers.
Definition: MCAsmParser.h:109
static MCOperand createExpr(const MCExpr *Val)
Definition: MCInst.h:136
MCTargetAsmParser - Generic interface to target specific assembly parsers.
virtual const AsmToken & Lex()=0
Get the next AsmToken in the stream, possibly handling file inclusion first.
unsigned second
#define error(X)
F(f)
const AsmToken & getTok() const
Get the current AsmToken from the stream.
Definition: MCAsmParser.cpp:33
This file contains the entry points for global functions defined in the LLVM WebAssembly back-end...
virtual void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI)
Emit the given Instruction into the current section.
StringSwitch & Case(StringLiteral S, T Value)
Definition: StringSwitch.h:67
static GCMetadataPrinterRegistry::Add< OcamlGCMetadataPrinter > Y("ocaml", "ocaml 3.10-compatible collector")
This file registers the WebAssembly target.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:80
const FeatureBitset & getFeatureBits() const
Generic assembler lexer interface, for use by target specific assembly lexers.
Definition: MCAsmLexer.h:39
LLVM_NODISCARD StringRef drop_front(size_t N=1) const
Return a StringRef equal to &#39;this&#39; but with the first N elements dropped.
Definition: StringRef.h:620
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: APFloat.h:41
Base class for the full range of assembler expressions which are needed for parsing.
Definition: MCExpr.h:35
SmallVector< ValType, 1 > Returns
Definition: Wasm.h:341
LLVM_NODISCARD R Default(T Value)
Definition: StringSwitch.h:181
Target independent representation for an assembler token.
Definition: MCAsmMacro.h:21
static bool isMem(const MachineInstr &MI, unsigned Op)
Definition: X86InstrInfo.h:122
MCParsedAsmOperand - This abstract class represents a source-level assembly instruction operand...
virtual bool parseExpression(const MCExpr *&Res, SMLoc &EndLoc)=0
Parse an arbitrary expression.
SmallVector< ValType, 4 > Params
Definition: Wasm.h:342
std::pair< StringRef, StringRef > getToken(StringRef Source, StringRef Delimiters=" \\\)
getToken - This function extracts one token from source, ignoring any leading characters that appear ...
RegisterMCAsmParser - Helper template for registering a target specific assembly parser, for use in the target machine initialization function.
LLVM_NODISCARD size_t size() const
size - Get the string size.
Definition: StringRef.h:130
SMLoc getLoc() const
Definition: MCAsmLexer.cpp:27
virtual bool parseEscapedString(std::string &Data)=0
Parse the current token as a string which may include escaped characters and return the string conten...
Instances of this class represent a single low-level machine instruction.
Definition: MCInst.h:158
static const MCBinaryExpr * create(Opcode Op, const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx, SMLoc Loc=SMLoc())
Definition: MCExpr.cpp:158
WebAssembly-specific streamer interface, to implement support WebAssembly-specific assembly directive...
const char * getPointer() const
Definition: SMLoc.h:34
void setImm(int64_t Val)
Definition: MCInst.h:80
A switch()-like statement whose cases are string literals.
Definition: StringSwitch.h:42
Streaming machine code generation interface.
Definition: MCStreamer.h:189
MCTargetStreamer * getTargetStreamer()
Definition: MCStreamer.h:258
SMLoc getEndLoc() const
Definition: MCAsmLexer.cpp:31
static void push(SmallVectorImpl< uint64_t > &R, StringRef Str)
The instances of the Type class are immutable: once they are created, they are never changed...
Definition: Type.h:45
This file provides WebAssembly-specific target descriptions.
Interface to description of machine instruction set.
Definition: MCInstrInfo.h:23
LLVM_NODISCARD size_t find(char C, size_t From=0) const
Search for the first character C in the string.
Definition: StringRef.h:285
virtual MCAsmLexer & getLexer()=0
constexpr char TypeName[]
Key for Kernel::Arg::Metadata::mTypeName.
int64_t getIntVal() const
Definition: MCAsmMacro.h:115
static void print(raw_ostream &Out, object::Archive::Kind Kind, T Val)
bool Error(SMLoc L, const Twine &Msg, SMRange Range=None)
Return an error at the location L, with the message Msg.
Definition: MCAsmParser.cpp:87
size_t size() const
Definition: SmallVector.h:52
void setLoc(SMLoc loc)
Definition: MCInst.h:176
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:40
unsigned first
This file declares WebAssembly-specific target streamer classes.
std::enable_if< std::numeric_limits< T >::is_signed, bool >::type getAsInteger(unsigned Radix, T &Result) const
Parse the current string as an integer of the specified radix.
Definition: StringRef.h:478
This is a &#39;vector&#39; (really, a variable-sized array), optimized for the case when the array is small...
Definition: SmallVector.h:837
const MCOperand & getOperand(unsigned i) const
Definition: MCInst.h:179
ExprType
This is used to indicate block signatures.
static MCOperand createFPImm(double Val)
Definition: MCInst.h:129
void LLVMInitializeWebAssemblyAsmParser()
static unsigned getReg(const void *D, unsigned RC, unsigned RegNo)
Base class for user error types.
Definition: Error.h:344
iterator begin() const
Definition: StringRef.h:101
static SMLoc getFromPointer(const char *Ptr)
Definition: SMLoc.h:36
static const size_t npos
Definition: StringRef.h:50
BitTracker BT
Definition: BitTracker.cpp:73
Represents a single loop in the control flow graph.
Definition: LoopInfo.h:509
const NodeList & List
Definition: RDFGraph.cpp:201
#define I(x, y, z)
Definition: MD5.cpp:58
#define N
Generic base class for all target subtargets.
bool isNot(AsmToken::TokenKind K) const
Check if the current token has kind K.
Definition: MCAsmLexer.h:138
unsigned GetDefaultP2AlignAny(unsigned Opc)
Return the default p2align value for a load or store with the given opcode.
StringRef getName() const
getName - Get the symbol name.
Definition: MCSymbol.h:204
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
virtual void emitLocal(ArrayRef< wasm::ValType > Types)=0
.local
This class implements an extremely fast bulk output stream that can only output to a stream...
Definition: raw_ostream.h:45
Subtraction.
Definition: MCExpr.h:449
void addOperand(const MCOperand &Op)
Definition: MCInst.h:183
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:48
Target & getTheWebAssemblyTarget32()
Type * parseType(StringRef Asm, SMDiagnostic &Err, const Module &M, const SlotMapping *Slots=nullptr)
Parse a type in the given string.
Definition: Parser.cpp:159
Represents a location in source code.
Definition: SMLoc.h:23
unsigned getOpcode() const
Definition: MCInst.h:171
Target & getTheWebAssemblyTarget64()
iterator end() const
Definition: StringRef.h:103
static MCOperand createImm(int64_t Val)
Definition: MCInst.h:122
TokenKind getKind() const
Definition: MCAsmMacro.h:81
static SectionKind getText()
Definition: SectionKind.h:179