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::BlockType parseBlockType(StringRef ID) {
317  // Multivalue block types are handled separately in parseSignature
319  .Case("i32", WebAssembly::BlockType::I32)
327  }
328 
329  bool parseRegTypeList(SmallVectorImpl<wasm::ValType> &Types) {
330  while (Lexer.is(AsmToken::Identifier)) {
331  auto Type = parseType(Lexer.getTok().getString());
332  if (!Type)
333  return error("unknown type: ", Lexer.getTok());
334  Types.push_back(Type.getValue());
335  Parser.Lex();
336  if (!isNext(AsmToken::Comma))
337  break;
338  }
339  return false;
340  }
341 
342  void parseSingleInteger(bool IsNegative, OperandVector &Operands) {
343  auto &Int = Lexer.getTok();
344  int64_t Val = Int.getIntVal();
345  if (IsNegative)
346  Val = -Val;
347  Operands.push_back(std::make_unique<WebAssemblyOperand>(
348  WebAssemblyOperand::Integer, Int.getLoc(), Int.getEndLoc(),
349  WebAssemblyOperand::IntOp{Val}));
350  Parser.Lex();
351  }
352 
353  bool parseSingleFloat(bool IsNegative, OperandVector &Operands) {
354  auto &Flt = Lexer.getTok();
355  double Val;
356  if (Flt.getString().getAsDouble(Val, false))
357  return error("Cannot parse real: ", Flt);
358  if (IsNegative)
359  Val = -Val;
360  Operands.push_back(std::make_unique<WebAssemblyOperand>(
361  WebAssemblyOperand::Float, Flt.getLoc(), Flt.getEndLoc(),
362  WebAssemblyOperand::FltOp{Val}));
363  Parser.Lex();
364  return false;
365  }
366 
367  bool parseSpecialFloatMaybe(bool IsNegative, OperandVector &Operands) {
368  if (Lexer.isNot(AsmToken::Identifier))
369  return true;
370  auto &Flt = Lexer.getTok();
371  auto S = Flt.getString();
372  double Val;
373  if (S.compare_lower("infinity") == 0) {
374  Val = std::numeric_limits<double>::infinity();
375  } else if (S.compare_lower("nan") == 0) {
376  Val = std::numeric_limits<double>::quiet_NaN();
377  } else {
378  return true;
379  }
380  if (IsNegative)
381  Val = -Val;
382  Operands.push_back(std::make_unique<WebAssemblyOperand>(
383  WebAssemblyOperand::Float, Flt.getLoc(), Flt.getEndLoc(),
384  WebAssemblyOperand::FltOp{Val}));
385  Parser.Lex();
386  return false;
387  }
388 
389  bool checkForP2AlignIfLoadStore(OperandVector &Operands, StringRef InstName) {
390  // FIXME: there is probably a cleaner way to do this.
391  auto IsLoadStore = InstName.find(".load") != StringRef::npos ||
392  InstName.find(".store") != StringRef::npos;
393  auto IsAtomic = InstName.find("atomic.") != StringRef::npos;
394  if (IsLoadStore || IsAtomic) {
395  // Parse load/store operands of the form: offset:p2align=align
396  if (IsLoadStore && isNext(AsmToken::Colon)) {
397  auto Id = expectIdent();
398  if (Id != "p2align")
399  return error("Expected p2align, instead got: " + Id);
400  if (expect(AsmToken::Equal, "="))
401  return true;
402  if (!Lexer.is(AsmToken::Integer))
403  return error("Expected integer constant");
404  parseSingleInteger(false, Operands);
405  } else {
406  // Alignment not specified (or atomics, must use default alignment).
407  // We can't just call WebAssembly::GetDefaultP2Align since we don't have
408  // an opcode until after the assembly matcher, so set a default to fix
409  // up later.
410  auto Tok = Lexer.getTok();
411  Operands.push_back(std::make_unique<WebAssemblyOperand>(
413  WebAssemblyOperand::IntOp{-1}));
414  }
415  }
416  return false;
417  }
418 
419  void addBlockTypeOperand(OperandVector &Operands, SMLoc NameLoc,
421  Operands.push_back(std::make_unique<WebAssemblyOperand>(
422  WebAssemblyOperand::Integer, NameLoc, NameLoc,
423  WebAssemblyOperand::IntOp{static_cast<int64_t>(BT)}));
424  }
425 
426  bool ParseInstruction(ParseInstructionInfo & /*Info*/, StringRef Name,
427  SMLoc NameLoc, OperandVector &Operands) override {
428  // Note: Name does NOT point into the sourcecode, but to a local, so
429  // use NameLoc instead.
430  Name = StringRef(NameLoc.getPointer(), Name.size());
431 
432  // WebAssembly has instructions with / in them, which AsmLexer parses
433  // as seperate tokens, so if we find such tokens immediately adjacent (no
434  // whitespace), expand the name to include them:
435  for (;;) {
436  auto &Sep = Lexer.getTok();
437  if (Sep.getLoc().getPointer() != Name.end() ||
438  Sep.getKind() != AsmToken::Slash)
439  break;
440  // Extend name with /
441  Name = StringRef(Name.begin(), Name.size() + Sep.getString().size());
442  Parser.Lex();
443  // We must now find another identifier, or error.
444  auto &Id = Lexer.getTok();
445  if (Id.getKind() != AsmToken::Identifier ||
446  Id.getLoc().getPointer() != Name.end())
447  return error("Incomplete instruction name: ", Id);
448  Name = StringRef(Name.begin(), Name.size() + Id.getString().size());
449  Parser.Lex();
450  }
451 
452  // Now construct the name as first operand.
453  Operands.push_back(std::make_unique<WebAssemblyOperand>(
454  WebAssemblyOperand::Token, NameLoc, SMLoc::getFromPointer(Name.end()),
455  WebAssemblyOperand::TokOp{Name}));
456 
457  // If this instruction is part of a control flow structure, ensure
458  // proper nesting.
459  bool ExpectBlockType = false;
460  bool ExpectFuncType = false;
461  if (Name == "block") {
462  push(Block);
463  ExpectBlockType = true;
464  } else if (Name == "loop") {
465  push(Loop);
466  ExpectBlockType = true;
467  } else if (Name == "try") {
468  push(Try);
469  ExpectBlockType = true;
470  } else if (Name == "if") {
471  push(If);
472  ExpectBlockType = true;
473  } else if (Name == "else") {
474  if (pop(Name, If))
475  return true;
476  push(Else);
477  } else if (Name == "catch") {
478  if (pop(Name, Try))
479  return true;
480  push(Try);
481  } else if (Name == "end_if") {
482  if (pop(Name, If, Else))
483  return true;
484  } else if (Name == "end_try") {
485  if (pop(Name, Try))
486  return true;
487  } else if (Name == "end_loop") {
488  if (pop(Name, Loop))
489  return true;
490  } else if (Name == "end_block") {
491  if (pop(Name, Block))
492  return true;
493  } else if (Name == "end_function") {
494  ensureLocals(getStreamer());
495  CurrentState = EndFunction;
496  if (pop(Name, Function) || ensureEmptyNestingStack())
497  return true;
498  } else if (Name == "call_indirect" || Name == "return_call_indirect") {
499  ExpectFuncType = true;
500  }
501 
502  if (ExpectFuncType || (ExpectBlockType && Lexer.is(AsmToken::LParen))) {
503  // This has a special TYPEINDEX operand which in text we
504  // represent as a signature, such that we can re-build this signature,
505  // attach it to an anonymous symbol, which is what WasmObjectWriter
506  // expects to be able to recreate the actual unique-ified type indices.
507  auto Loc = Parser.getTok();
508  auto Signature = std::make_unique<wasm::WasmSignature>();
509  if (parseSignature(Signature.get()))
510  return true;
511  // Got signature as block type, don't need more
512  ExpectBlockType = false;
513  auto &Ctx = getStreamer().getContext();
514  // The "true" here will cause this to be a nameless symbol.
515  MCSymbol *Sym = Ctx.createTempSymbol("typeindex", true);
516  auto *WasmSym = cast<MCSymbolWasm>(Sym);
517  WasmSym->setSignature(Signature.get());
518  addSignature(std::move(Signature));
519  WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
520  const MCExpr *Expr = MCSymbolRefExpr::create(
521  WasmSym, MCSymbolRefExpr::VK_WASM_TYPEINDEX, Ctx);
522  Operands.push_back(std::make_unique<WebAssemblyOperand>(
523  WebAssemblyOperand::Symbol, Loc.getLoc(), Loc.getEndLoc(),
524  WebAssemblyOperand::SymOp{Expr}));
525  }
526 
527  while (Lexer.isNot(AsmToken::EndOfStatement)) {
528  auto &Tok = Lexer.getTok();
529  switch (Tok.getKind()) {
530  case AsmToken::Identifier: {
531  if (!parseSpecialFloatMaybe(false, Operands))
532  break;
533  auto &Id = Lexer.getTok();
534  if (ExpectBlockType) {
535  // Assume this identifier is a block_type.
536  auto BT = parseBlockType(Id.getString());
538  return error("Unknown block type: ", Id);
539  addBlockTypeOperand(Operands, NameLoc, BT);
540  Parser.Lex();
541  } else {
542  // Assume this identifier is a label.
543  const MCExpr *Val;
544  SMLoc End;
545  if (Parser.parseExpression(Val, End))
546  return error("Cannot parse symbol: ", Lexer.getTok());
547  Operands.push_back(std::make_unique<WebAssemblyOperand>(
548  WebAssemblyOperand::Symbol, Id.getLoc(), Id.getEndLoc(),
549  WebAssemblyOperand::SymOp{Val}));
550  if (checkForP2AlignIfLoadStore(Operands, Name))
551  return true;
552  }
553  break;
554  }
555  case AsmToken::Minus:
556  Parser.Lex();
557  if (Lexer.is(AsmToken::Integer)) {
558  parseSingleInteger(true, Operands);
559  if (checkForP2AlignIfLoadStore(Operands, Name))
560  return true;
561  } else if(Lexer.is(AsmToken::Real)) {
562  if (parseSingleFloat(true, Operands))
563  return true;
564  } else if (!parseSpecialFloatMaybe(true, Operands)) {
565  } else {
566  return error("Expected numeric constant instead got: ",
567  Lexer.getTok());
568  }
569  break;
570  case AsmToken::Integer:
571  parseSingleInteger(false, Operands);
572  if (checkForP2AlignIfLoadStore(Operands, Name))
573  return true;
574  break;
575  case AsmToken::Real: {
576  if (parseSingleFloat(false, Operands))
577  return true;
578  break;
579  }
580  case AsmToken::LCurly: {
581  Parser.Lex();
582  auto Op = std::make_unique<WebAssemblyOperand>(
583  WebAssemblyOperand::BrList, Tok.getLoc(), Tok.getEndLoc());
584  if (!Lexer.is(AsmToken::RCurly))
585  for (;;) {
586  Op->BrL.List.push_back(Lexer.getTok().getIntVal());
587  expect(AsmToken::Integer, "integer");
588  if (!isNext(AsmToken::Comma))
589  break;
590  }
591  expect(AsmToken::RCurly, "}");
592  Operands.push_back(std::move(Op));
593  break;
594  }
595  default:
596  return error("Unexpected token in operand: ", Tok);
597  }
598  if (Lexer.isNot(AsmToken::EndOfStatement)) {
599  if (expect(AsmToken::Comma, ","))
600  return true;
601  }
602  }
603  if (ExpectBlockType && Operands.size() == 1) {
604  // Support blocks with no operands as default to void.
605  addBlockTypeOperand(Operands, NameLoc, WebAssembly::BlockType::Void);
606  }
607  Parser.Lex();
608  return false;
609  }
610 
611  void onLabelParsed(MCSymbol *Symbol) override {
612  LastLabel = Symbol;
613  CurrentState = Label;
614  }
615 
616  bool parseSignature(wasm::WasmSignature *Signature) {
617  if (expect(AsmToken::LParen, "("))
618  return true;
619  if (parseRegTypeList(Signature->Params))
620  return true;
621  if (expect(AsmToken::RParen, ")"))
622  return true;
623  if (expect(AsmToken::MinusGreater, "->"))
624  return true;
625  if (expect(AsmToken::LParen, "("))
626  return true;
627  if (parseRegTypeList(Signature->Returns))
628  return true;
629  if (expect(AsmToken::RParen, ")"))
630  return true;
631  return false;
632  }
633 
634  bool CheckDataSection() {
635  if (CurrentState != DataSection) {
636  auto WS = cast<MCSectionWasm>(getStreamer().getCurrentSection().first);
637  if (WS && WS->getKind().isText())
638  return error("data directive must occur in a data segment: ",
639  Lexer.getTok());
640  }
641  CurrentState = DataSection;
642  return false;
643  }
644 
645  // This function processes wasm-specific directives streamed to
646  // WebAssemblyTargetStreamer, all others go to the generic parser
647  // (see WasmAsmParser).
648  bool ParseDirective(AsmToken DirectiveID) override {
649  // This function has a really weird return value behavior that is different
650  // from all the other parsing functions:
651  // - return true && no tokens consumed -> don't know this directive / let
652  // the generic parser handle it.
653  // - return true && tokens consumed -> a parsing error occurred.
654  // - return false -> processed this directive successfully.
655  assert(DirectiveID.getKind() == AsmToken::Identifier);
656  auto &Out = getStreamer();
657  auto &TOut =
658  reinterpret_cast<WebAssemblyTargetStreamer &>(*Out.getTargetStreamer());
659  auto &Ctx = Out.getContext();
660 
661  // TODO: any time we return an error, at least one token must have been
662  // consumed, otherwise this will not signal an error to the caller.
663  if (DirectiveID.getString() == ".globaltype") {
664  auto SymName = expectIdent();
665  if (SymName.empty())
666  return true;
667  if (expect(AsmToken::Comma, ","))
668  return true;
669  auto TypeTok = Lexer.getTok();
670  auto TypeName = expectIdent();
671  if (TypeName.empty())
672  return true;
673  auto Type = parseType(TypeName);
674  if (!Type)
675  return error("Unknown type in .globaltype directive: ", TypeTok);
676  // Now set this symbol with the correct type.
677  auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
678  WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);
679  WasmSym->setGlobalType(
680  wasm::WasmGlobalType{uint8_t(Type.getValue()), true});
681  // And emit the directive again.
682  TOut.emitGlobalType(WasmSym);
683  return expect(AsmToken::EndOfStatement, "EOL");
684  }
685 
686  if (DirectiveID.getString() == ".functype") {
687  // This code has to send things to the streamer similar to
688  // WebAssemblyAsmPrinter::EmitFunctionBodyStart.
689  // TODO: would be good to factor this into a common function, but the
690  // assembler and backend really don't share any common code, and this code
691  // parses the locals seperately.
692  auto SymName = expectIdent();
693  if (SymName.empty())
694  return true;
695  auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
696  if (CurrentState == Label && WasmSym == LastLabel) {
697  // This .functype indicates a start of a function.
698  if (ensureEmptyNestingStack())
699  return true;
700  CurrentState = FunctionStart;
701  LastFunctionLabel = LastLabel;
702  push(Function);
703  }
704  auto Signature = std::make_unique<wasm::WasmSignature>();
705  if (parseSignature(Signature.get()))
706  return true;
707  WasmSym->setSignature(Signature.get());
708  addSignature(std::move(Signature));
709  WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
710  TOut.emitFunctionType(WasmSym);
711  // TODO: backend also calls TOut.emitIndIdx, but that is not implemented.
712  return expect(AsmToken::EndOfStatement, "EOL");
713  }
714 
715  if (DirectiveID.getString() == ".eventtype") {
716  auto SymName = expectIdent();
717  if (SymName.empty())
718  return true;
719  auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
720  auto Signature = std::make_unique<wasm::WasmSignature>();
721  if (parseRegTypeList(Signature->Params))
722  return true;
723  WasmSym->setSignature(Signature.get());
724  addSignature(std::move(Signature));
725  WasmSym->setType(wasm::WASM_SYMBOL_TYPE_EVENT);
726  TOut.emitEventType(WasmSym);
727  // TODO: backend also calls TOut.emitIndIdx, but that is not implemented.
728  return expect(AsmToken::EndOfStatement, "EOL");
729  }
730 
731  if (DirectiveID.getString() == ".local") {
732  if (CurrentState != FunctionStart)
733  return error(".local directive should follow the start of a function",
734  Lexer.getTok());
736  if (parseRegTypeList(Locals))
737  return true;
738  TOut.emitLocal(Locals);
739  CurrentState = FunctionLocals;
740  return expect(AsmToken::EndOfStatement, "EOL");
741  }
742 
743  if (DirectiveID.getString() == ".int8" ||
744  DirectiveID.getString() == ".int16" ||
745  DirectiveID.getString() == ".int32" ||
746  DirectiveID.getString() == ".int64") {
747  if (CheckDataSection()) return true;
748  const MCExpr *Val;
749  SMLoc End;
750  if (Parser.parseExpression(Val, End))
751  return error("Cannot parse .int expression: ", Lexer.getTok());
752  size_t NumBits = 0;
753  DirectiveID.getString().drop_front(4).getAsInteger(10, NumBits);
754  Out.EmitValue(Val, NumBits / 8, End);
755  return expect(AsmToken::EndOfStatement, "EOL");
756  }
757 
758  if (DirectiveID.getString() == ".asciz") {
759  if (CheckDataSection()) return true;
760  std::string S;
761  if (Parser.parseEscapedString(S))
762  return error("Cannot parse string constant: ", Lexer.getTok());
763  Out.EmitBytes(StringRef(S.c_str(), S.length() + 1));
764  return expect(AsmToken::EndOfStatement, "EOL");
765  }
766 
767  return true; // We didn't process this directive.
768  }
769 
770  // Called either when the first instruction is parsed of the function ends.
771  void ensureLocals(MCStreamer &Out) {
772  if (CurrentState == FunctionStart) {
773  // We haven't seen a .local directive yet. The streamer requires locals to
774  // be encoded as a prelude to the instructions, so emit an empty list of
775  // locals here.
776  auto &TOut = reinterpret_cast<WebAssemblyTargetStreamer &>(
777  *Out.getTargetStreamer());
779  CurrentState = FunctionLocals;
780  }
781  }
782 
783  bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned & /*Opcode*/,
784  OperandVector &Operands, MCStreamer &Out,
785  uint64_t &ErrorInfo,
786  bool MatchingInlineAsm) override {
787  MCInst Inst;
788  Inst.setLoc(IDLoc);
789  unsigned MatchResult =
790  MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm);
791  switch (MatchResult) {
792  case Match_Success: {
793  ensureLocals(Out);
794  // Fix unknown p2align operands.
796  if (Align != -1U) {
797  auto &Op0 = Inst.getOperand(0);
798  if (Op0.getImm() == -1)
799  Op0.setImm(Align);
800  }
801  Out.EmitInstruction(Inst, getSTI());
802  if (CurrentState == EndFunction) {
803  onEndOfFunction();
804  } else {
805  CurrentState = Instructions;
806  }
807  return false;
808  }
809  case Match_MissingFeature:
810  return Parser.Error(
811  IDLoc, "instruction requires a WASM feature not currently enabled");
812  case Match_MnemonicFail:
813  return Parser.Error(IDLoc, "invalid instruction");
814  case Match_NearMisses:
815  return Parser.Error(IDLoc, "ambiguous instruction");
816  case Match_InvalidTiedOperand:
817  case Match_InvalidOperand: {
818  SMLoc ErrorLoc = IDLoc;
819  if (ErrorInfo != ~0ULL) {
820  if (ErrorInfo >= Operands.size())
821  return Parser.Error(IDLoc, "too few operands for instruction");
822  ErrorLoc = Operands[ErrorInfo]->getStartLoc();
823  if (ErrorLoc == SMLoc())
824  ErrorLoc = IDLoc;
825  }
826  return Parser.Error(ErrorLoc, "invalid operand for instruction");
827  }
828  }
829  llvm_unreachable("Implement any new match types added!");
830  }
831 
832  void doBeforeLabelEmit(MCSymbol *Symbol) override {
833  // Start a new section for the next function automatically, since our
834  // object writer expects each function to have its own section. This way
835  // The user can't forget this "convention".
836  auto SymName = Symbol->getName();
837  if (SymName.startswith(".L"))
838  return; // Local Symbol.
839  // Only create a new text section if we're already in one.
840  auto CWS = cast<MCSectionWasm>(getStreamer().getCurrentSection().first);
841  if (!CWS || !CWS->getKind().isText())
842  return;
843  auto SecName = ".text." + SymName;
844  auto WS = getContext().getWasmSection(SecName, SectionKind::getText());
845  getStreamer().SwitchSection(WS);
846  }
847 
848  void onEndOfFunction() {
849  // Automatically output a .size directive, so it becomes optional for the
850  // user.
851  if (!LastFunctionLabel) return;
852  auto TempSym = getContext().createLinkerPrivateTempSymbol();
853  getStreamer().EmitLabel(TempSym);
854  auto Start = MCSymbolRefExpr::create(LastFunctionLabel, getContext());
855  auto End = MCSymbolRefExpr::create(TempSym, getContext());
856  auto Expr =
857  MCBinaryExpr::create(MCBinaryExpr::Sub, End, Start, getContext());
858  getStreamer().emitELFSize(LastFunctionLabel, Expr);
859  }
860 
861  void onEndOfFile() override { ensureEmptyNestingStack(); }
862 };
863 } // end anonymous namespace
864 
865 // Force static initialization.
869 }
870 
871 #define GET_REGISTER_MATCHER
872 #define GET_MATCHER_IMPLEMENTATION
873 #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:329
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
amdgpu Simplify well known AMD library false FunctionCallee Value const Twine & Name
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:634
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:355
LLVM_NODISCARD R Default(T Value)
Definition: StringSwitch.h:181
Target independent representation for an assembler token.
Definition: MCAsmMacro.h:21
mir Rename Register Operands
static bool isMem(const MachineInstr &MI, unsigned Op)
Definition: X86InstrInfo.h:125
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:356
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:144
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:196
MCTargetStreamer * getTargetStreamer()
Definition: MCStreamer.h:265
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:46
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:299
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:492
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
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:115
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
BlockType
Used as immediate MachineOperands for block signatures.
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:447
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:117
static MCOperand createImm(int64_t Val)
Definition: MCInst.h:122
TokenKind getKind() const
Definition: MCAsmMacro.h:81
static SectionKind getText()
Definition: SectionKind.h:179