Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
Line
Count
Source (jump to first uncovered line)
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
16
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
17
#include "MCTargetDesc/WebAssemblyTargetStreamer.h"
18
#include "TargetInfo/WebAssemblyTargetInfo.h"
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"
24
#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
25
#include "llvm/MC/MCParser/MCTargetAsmParser.h"
26
#include "llvm/MC/MCSectionWasm.h"
27
#include "llvm/MC/MCStreamer.h"
28
#include "llvm/MC/MCSubtargetInfo.h"
29
#include "llvm/MC/MCSymbol.h"
30
#include "llvm/MC/MCSymbolWasm.h"
31
#include "llvm/Support/Endian.h"
32
#include "llvm/Support/TargetRegistry.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
440
      : Kind(K), StartLoc(Start), EndLoc(End), Tok(T) {}
77
  WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, IntOp I)
78
367
      : Kind(K), StartLoc(Start), EndLoc(End), Int(I) {}
79
  WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, FltOp F)
80
14
      : Kind(K), StartLoc(Start), EndLoc(End), Flt(F) {}
81
  WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, SymOp S)
82
27
      : Kind(K), StartLoc(Start), EndLoc(End), Sym(S) {}
83
  WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End)
84
2
      : Kind(K), StartLoc(Start), EndLoc(End), BrL() {}
85
86
850
  ~WebAssemblyOperand() {
87
850
    if (isBrList())
88
2
      BrL.~BrLOp();
89
850
  }
90
91
501
  bool isToken() const override { return Kind == Token; }
92
470
  bool isImm() const override { return Kind == Integer || 
Kind == Symbol36
; }
93
29
  bool isFPImm() const { return Kind == Float; }
94
0
  bool isMem() const override { return false; }
95
14
  bool isReg() const override { return false; }
96
852
  bool isBrList() const { return Kind == BrList; }
97
98
0
  unsigned getReg() const override {
99
0
    llvm_unreachable("Assembly inspects a register operand");
100
0
    return 0;
101
0
  }
102
103
436
  StringRef getToken() const {
104
436
    assert(isToken());
105
436
    return Tok.Tok;
106
436
  }
107
108
1
  SMLoc getStartLoc() const override { return StartLoc; }
109
0
  SMLoc getEndLoc() const override { return EndLoc; }
110
111
0
  void addRegOperands(MCInst &, unsigned) const {
112
0
    // Required by the assembly matcher.
113
0
    llvm_unreachable("Assembly matcher creates register operands");
114
0
  }
115
116
393
  void addImmOperands(MCInst &Inst, unsigned N) const {
117
393
    assert(N == 1 && "Invalid number of operands!");
118
393
    if (Kind == Integer)
119
366
      Inst.addOperand(MCOperand::createImm(Int.Val));
120
27
    else if (Kind == Symbol)
121
27
      Inst.addOperand(MCOperand::createExpr(Sym.Exp));
122
27
    else
123
27
      
llvm_unreachable0
("Should be integer immediate or symbol!");
124
393
  }
125
126
14
  void addFPImmOperands(MCInst &Inst, unsigned N) const {
127
14
    assert(N == 1 && "Invalid number of operands!");
128
14
    if (Kind == Float)
129
14
      Inst.addOperand(MCOperand::createFPImm(Flt.Val));
130
14
    else
131
14
      
llvm_unreachable0
("Should be float immediate!");
132
14
  }
133
134
2
  void addBrListOperands(MCInst &Inst, unsigned N) const {
135
2
    assert(N == 1 && isBrList() && "Invalid BrList!");
136
2
    for (auto Br : BrL.List)
137
6
      Inst.addOperand(MCOperand::createImm(Br));
138
2
  }
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
17
        Lexer(Parser.getLexer()) {
206
17
    setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
207
17
  }
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
0
                     SMLoc & /*EndLoc*/) override {
215
0
    llvm_unreachable("ParseRegister is not implemented.");
216
0
  }
217
218
0
  bool error(const Twine &Msg, const AsmToken &Tok) {
219
0
    return Parser.Error(Tok.getLoc(), Msg + Tok.getString());
220
0
  }
221
222
8
  bool error(const Twine &Msg) {
223
8
    return Parser.Error(Lexer.getTok().getLoc(), Msg);
224
8
  }
225
226
30
  void addSignature(std::unique_ptr<wasm::WasmSignature> &&Sig) {
227
30
    Signatures.push_back(std::move(Sig));
228
30
  }
229
230
7
  std::pair<StringRef, StringRef> nestingString(NestingType NT) {
231
7
    switch (NT) {
232
7
    case Function:
233
2
      return {"function", "end_function"};
234
7
    case Block:
235
2
      return {"block", "end_block"};
236
7
    case Loop:
237
2
      return {"loop", "end_loop"};
238
7
    case Try:
239
1
      return {"try", "end_try"};
240
7
    case If:
241
0
      return {"if", "end_if"};
242
7
    case Else:
243
0
      return {"else", "end_if"};
244
7
    default:
245
0
      llvm_unreachable("unknown NestingType");
246
7
    }
247
7
  }
248
249
61
  void push(NestingType NT) { NestingStack.push_back(NT); }
250
251
61
  bool pop(StringRef Ins, NestingType NT1, NestingType NT2 = Undefined) {
252
61
    if (NestingStack.empty())
253
1
      return error(Twine("End of block construct with no start: ") + Ins);
254
60
    auto Top = NestingStack.back();
255
60
    if (Top != NT1 && 
Top != NT25
)
256
3
      return error(Twine("Block construct type mismatch, expected: ") +
257
3
                   nestingString(Top).second + ", instead got: " + Ins);
258
57
    NestingStack.pop_back();
259
57
    return false;
260
57
  }
261
262
64
  bool ensureEmptyNestingStack() {
263
64
    auto Err = !NestingStack.empty();
264
68
    while (!NestingStack.empty()) {
265
4
      error(Twine("Unmatched block construct(s) at function end: ") +
266
4
            nestingString(NestingStack.back()).first);
267
4
      NestingStack.pop_back();
268
4
    }
269
64
    return Err;
270
64
  }
271
272
374
  bool isNext(AsmToken::TokenKind Kind) {
273
374
    auto Ok = Lexer.is(Kind);
274
374
    if (Ok)
275
317
      Parser.Lex();
276
374
    return Ok;
277
374
  }
278
279
292
  bool expect(AsmToken::TokenKind Kind, const char *KindName) {
280
292
    if (!isNext(Kind))
281
0
      return error(std::string("Expected ") + KindName + ", instead got: ",
282
0
                   Lexer.getTok());
283
292
    return false;
284
292
  }
285
286
38
  StringRef expectIdent() {
287
38
    if (!Lexer.is(AsmToken::Identifier)) {
288
0
      error("Expected identifier, got: ", Lexer.getTok());
289
0
      return StringRef();
290
0
    }
291
38
    auto Name = Lexer.getTok().getString();
292
38
    Parser.Lex();
293
38
    return Name;
294
38
  }
295
296
50
  Optional<wasm::ValType> parseType(const StringRef &Type) {
297
50
    // FIXME: can't use StringSwitch because wasm::ValType doesn't have a
298
50
    // "invalid" value.
299
50
    if (Type == "i32")
300
32
      return wasm::ValType::I32;
301
18
    if (Type == "i64")
302
5
      return wasm::ValType::I64;
303
13
    if (Type == "f32")
304
3
      return wasm::ValType::F32;
305
10
    if (Type == "f64")
306
3
      return wasm::ValType::F64;
307
7
    if (Type == "v128" || 
Type == "i8x16"1
||
Type == "i16x8"1
||
308
7
        
Type == "i32x4"1
||
Type == "i64x2"1
||
Type == "f32x4"1
||
309
7
        
Type == "f64x2"1
)
310
6
      return wasm::ValType::V128;
311
1
    if (Type == "exnref")
312
1
      return wasm::ValType::EXNREF;
313
0
    return Optional<wasm::ValType>();
314
0
  }
315
316
19
  WebAssembly::ExprType parseBlockType(StringRef ID) {
317
19
    return StringSwitch<WebAssembly::ExprType>(ID)
318
19
        .Case("i32", WebAssembly::ExprType::I32)
319
19
        .Case("i64", WebAssembly::ExprType::I64)
320
19
        .Case("f32", WebAssembly::ExprType::F32)
321
19
        .Case("f64", WebAssembly::ExprType::F64)
322
19
        .Case("v128", WebAssembly::ExprType::V128)
323
19
        .Case("exnref", WebAssembly::ExprType::Exnref)
324
19
        .Case("void", WebAssembly::ExprType::Void)
325
19
        .Default(WebAssembly::ExprType::Invalid);
326
19
  }
327
328
62
  bool parseRegTypeList(SmallVectorImpl<wasm::ValType> &Types) {
329
79
    while (Lexer.is(AsmToken::Identifier)) {
330
48
      auto Type = parseType(Lexer.getTok().getString());
331
48
      if (!Type)
332
0
        return error("unknown type: ", Lexer.getTok());
333
48
      Types.push_back(Type.getValue());
334
48
      Parser.Lex();
335
48
      if (!isNext(AsmToken::Comma))
336
31
        break;
337
48
    }
338
62
    return false;
339
62
  }
340
341
259
  void parseSingleInteger(bool IsNegative, OperandVector &Operands) {
342
259
    auto &Int = Lexer.getTok();
343
259
    int64_t Val = Int.getIntVal();
344
259
    if (IsNegative)
345
2
      Val = -Val;
346
259
    Operands.push_back(make_unique<WebAssemblyOperand>(
347
259
        WebAssemblyOperand::Integer, Int.getLoc(), Int.getEndLoc(),
348
259
        WebAssemblyOperand::IntOp{Val}));
349
259
    Parser.Lex();
350
259
  }
351
352
10
  bool parseSingleFloat(bool IsNegative, OperandVector &Operands) {
353
10
    auto &Flt = Lexer.getTok();
354
10
    double Val;
355
10
    if (Flt.getString().getAsDouble(Val, false))
356
0
      return error("Cannot parse real: ", Flt);
357
10
    if (IsNegative)
358
2
      Val = -Val;
359
10
    Operands.push_back(make_unique<WebAssemblyOperand>(
360
10
        WebAssemblyOperand::Float, Flt.getLoc(), Flt.getEndLoc(),
361
10
        WebAssemblyOperand::FltOp{Val}));
362
10
    Parser.Lex();
363
10
    return false;
364
10
  }
365
366
50
  bool parseSpecialFloatMaybe(bool IsNegative, OperandVector &Operands) {
367
50
    if (Lexer.isNot(AsmToken::Identifier))
368
0
      return true;
369
50
    auto &Flt = Lexer.getTok();
370
50
    auto S = Flt.getString();
371
50
    double Val;
372
50
    if (S.compare_lower("infinity") == 0) {
373
2
      Val = std::numeric_limits<double>::infinity();
374
48
    } else if (S.compare_lower("nan") == 0) {
375
2
      Val = std::numeric_limits<double>::quiet_NaN();
376
46
    } else {
377
46
      return true;
378
46
    }
379
4
    if (IsNegative)
380
2
      Val = -Val;
381
4
    Operands.push_back(make_unique<WebAssemblyOperand>(
382
4
        WebAssemblyOperand::Float, Flt.getLoc(), Flt.getEndLoc(),
383
4
        WebAssemblyOperand::FltOp{Val}));
384
4
    Parser.Lex();
385
4
    return false;
386
4
  }
387
388
282
  bool checkForP2AlignIfLoadStore(OperandVector &Operands, StringRef InstName) {
389
282
    // FIXME: there is probably a cleaner way to do this.
390
282
    auto IsLoadStore = InstName.find(".load") != StringRef::npos ||
391
282
                       
InstName.find(".store") != StringRef::npos266
;
392
282
    auto IsAtomic = InstName.find("atomic.") != StringRef::npos;
393
282
    if (IsLoadStore || 
IsAtomic254
) {
394
82
      // Parse load/store operands of the form: offset:p2align=align
395
82
      if (IsLoadStore && 
isNext(AsmToken::Colon)28
) {
396
4
        auto Id = expectIdent();
397
4
        if (Id != "p2align")
398
0
          return error("Expected p2align, instead got: " + Id);
399
4
        if (expect(AsmToken::Equal, "="))
400
0
          return true;
401
4
        if (!Lexer.is(AsmToken::Integer))
402
0
          return error("Expected integer constant");
403
4
        parseSingleInteger(false, Operands);
404
78
      } else {
405
78
        // Alignment not specified (or atomics, must use default alignment).
406
78
        // We can't just call WebAssembly::GetDefaultP2Align since we don't have
407
78
        // an opcode until after the assembly matcher, so set a default to fix
408
78
        // up later.
409
78
        auto Tok = Lexer.getTok();
410
78
        Operands.push_back(make_unique<WebAssemblyOperand>(
411
78
            WebAssemblyOperand::Integer, Tok.getLoc(), Tok.getEndLoc(),
412
78
            WebAssemblyOperand::IntOp{-1}));
413
78
      }
414
82
    }
415
282
    return false;
416
282
  }
417
418
  void addBlockTypeOperand(OperandVector &Operands, SMLoc NameLoc,
419
30
                           WebAssembly::ExprType BT) {
420
30
    Operands.push_back(make_unique<WebAssemblyOperand>(
421
30
        WebAssemblyOperand::Integer, NameLoc, NameLoc,
422
30
        WebAssemblyOperand::IntOp{static_cast<int64_t>(BT)}));
423
30
  }
424
425
  bool ParseInstruction(ParseInstructionInfo & /*Info*/, StringRef Name,
426
440
                        SMLoc NameLoc, OperandVector &Operands) override {
427
440
    // Note: Name does NOT point into the sourcecode, but to a local, so
428
440
    // use NameLoc instead.
429
440
    Name = StringRef(NameLoc.getPointer(), Name.size());
430
440
431
440
    // WebAssembly has instructions with / in them, which AsmLexer parses
432
440
    // as seperate tokens, so if we find such tokens immediately adjacent (no
433
440
    // whitespace), expand the name to include them:
434
440
    for (;;) {
435
440
      auto &Sep = Lexer.getTok();
436
440
      if (Sep.getLoc().getPointer() != Name.end() ||
437
440
          
Sep.getKind() != AsmToken::Slash200
)
438
440
        break;
439
0
      // Extend name with /
440
0
      Name = StringRef(Name.begin(), Name.size() + Sep.getString().size());
441
0
      Parser.Lex();
442
0
      // We must now find another identifier, or error.
443
0
      auto &Id = Lexer.getTok();
444
0
      if (Id.getKind() != AsmToken::Identifier ||
445
0
          Id.getLoc().getPointer() != Name.end())
446
0
        return error("Incomplete instruction name: ", Id);
447
0
      Name = StringRef(Name.begin(), Name.size() + Id.getString().size());
448
0
      Parser.Lex();
449
0
    }
450
440
451
440
    // Now construct the name as first operand.
452
440
    Operands.push_back(make_unique<WebAssemblyOperand>(
453
440
        WebAssemblyOperand::Token, NameLoc, SMLoc::getFromPointer(Name.end()),
454
440
        WebAssemblyOperand::TokOp{Name}));
455
440
456
440
    // If this instruction is part of a control flow structure, ensure
457
440
    // proper nesting.
458
440
    bool ExpectBlockType = false;
459
440
    if (Name == "block") {
460
16
      push(Block);
461
16
      ExpectBlockType = true;
462
424
    } else if (Name == "loop") {
463
4
      push(Loop);
464
4
      ExpectBlockType = true;
465
420
    } else if (Name == "try") {
466
6
      push(Try);
467
6
      ExpectBlockType = true;
468
414
    } else if (Name == "if") {
469
4
      push(If);
470
4
      ExpectBlockType = true;
471
410
    } else if (Name == "else") {
472
2
      if (pop(Name, If))
473
0
        return true;
474
2
      push(Else);
475
408
    } else if (Name == "catch") {
476
5
      if (pop(Name, Try))
477
0
        return true;
478
5
      push(Try);
479
403
    } else if (Name == "end_if") {
480
5
      if (pop(Name, If, Else))
481
1
        return true;
482
398
    } else if (Name == "end_try") {
483
6
      if (pop(Name, Try))
484
1
        return true;
485
392
    } else if (Name == "end_loop") {
486
4
      if (pop(Name, Loop))
487
1
        return true;
488
388
    } else if (Name == "end_block") {
489
15
      if (pop(Name, Block))
490
0
        return true;
491
373
    } else if (Name == "end_function") {
492
24
      CurrentState = EndFunction;
493
24
      if (pop(Name, Function) || 
ensureEmptyNestingStack()23
)
494
1
        return true;
495
436
    }
496
436
497
753
    
while (436
Lexer.isNot(AsmToken::EndOfStatement)) {
498
317
      auto &Tok = Lexer.getTok();
499
317
      switch (Tok.getKind()) {
500
317
      case AsmToken::Identifier: {
501
48
        if (!parseSpecialFloatMaybe(false, Operands))
502
2
          break;
503
46
        auto &Id = Lexer.getTok();
504
46
        if (ExpectBlockType) {
505
19
          // Assume this identifier is a block_type.
506
19
          auto BT = parseBlockType(Id.getString());
507
19
          if (BT == WebAssembly::ExprType::Invalid)
508
0
            return error("Unknown block type: ", Id);
509
19
          addBlockTypeOperand(Operands, NameLoc, BT);
510
19
          Parser.Lex();
511
27
        } else {
512
27
          // Assume this identifier is a label.
513
27
          const MCExpr *Val;
514
27
          SMLoc End;
515
27
          if (Parser.parseExpression(Val, End))
516
0
            return error("Cannot parse symbol: ", Lexer.getTok());
517
27
          Operands.push_back(make_unique<WebAssemblyOperand>(
518
27
              WebAssemblyOperand::Symbol, Id.getLoc(), Id.getEndLoc(),
519
27
              WebAssemblyOperand::SymOp{Val}));
520
27
          if (checkForP2AlignIfLoadStore(Operands, Name))
521
0
            return true;
522
46
        }
523
46
        break;
524
46
      }
525
46
      case AsmToken::Minus:
526
6
        Parser.Lex();
527
6
        if (Lexer.is(AsmToken::Integer)) {
528
2
          parseSingleInteger(true, Operands);
529
2
          if (checkForP2AlignIfLoadStore(Operands, Name))
530
0
            return true;
531
4
        } else if(Lexer.is(AsmToken::Real)) {
532
2
          if (parseSingleFloat(true, Operands))
533
0
            return true;
534
2
        } else if (!parseSpecialFloatMaybe(true, Operands)) {
535
2
        } else {
536
0
          return error("Expected numeric constant instead got: ",
537
0
                       Lexer.getTok());
538
0
        }
539
6
        break;
540
253
      case AsmToken::Integer:
541
253
        parseSingleInteger(false, Operands);
542
253
        if (checkForP2AlignIfLoadStore(Operands, Name))
543
0
          return true;
544
253
        break;
545
253
      case AsmToken::Real: {
546
8
        if (parseSingleFloat(false, Operands))
547
0
          return true;
548
8
        break;
549
8
      }
550
8
      case AsmToken::LCurly: {
551
2
        Parser.Lex();
552
2
        auto Op = make_unique<WebAssemblyOperand>(
553
2
            WebAssemblyOperand::BrList, Tok.getLoc(), Tok.getEndLoc());
554
2
        if (!Lexer.is(AsmToken::RCurly))
555
6
          
for (;;)2
{
556
6
            Op->BrL.List.push_back(Lexer.getTok().getIntVal());
557
6
            expect(AsmToken::Integer, "integer");
558
6
            if (!isNext(AsmToken::Comma))
559
2
              break;
560
6
          }
561
2
        expect(AsmToken::RCurly, "}");
562
2
        Operands.push_back(std::move(Op));
563
2
        break;
564
8
      }
565
8
      default:
566
0
        return error("Unexpected token in operand: ", Tok);
567
317
      }
568
317
      if (Lexer.isNot(AsmToken::EndOfStatement)) {
569
90
        if (expect(AsmToken::Comma, ","))
570
0
          return true;
571
90
      }
572
317
    }
573
436
    if (ExpectBlockType && 
Operands.size() == 130
) {
574
11
      // Support blocks with no operands as default to void.
575
11
      addBlockTypeOperand(Operands, NameLoc, WebAssembly::ExprType::Void);
576
11
    }
577
436
    Parser.Lex();
578
436
    return false;
579
436
  }
580
581
46
  void onLabelParsed(MCSymbol *Symbol) override {
582
46
    LastLabel = Symbol;
583
46
    CurrentState = Label;
584
46
  }
585
586
27
  bool parseSignature(wasm::WasmSignature *Signature) {
587
27
    if (expect(AsmToken::LParen, "("))
588
0
      return true;
589
27
    if (parseRegTypeList(Signature->Params))
590
0
      return true;
591
27
    if (expect(AsmToken::RParen, ")"))
592
0
      return true;
593
27
    if (expect(AsmToken::MinusGreater, "->"))
594
0
      return true;
595
27
    if (expect(AsmToken::LParen, "("))
596
0
      return true;
597
27
    if (parseRegTypeList(Signature->Returns))
598
0
      return true;
599
27
    if (expect(AsmToken::RParen, ")"))
600
0
      return true;
601
27
    return false;
602
27
  }
603
604
16
  bool CheckDataSection() {
605
16
    if (CurrentState != DataSection) {
606
6
      auto WS = cast<MCSectionWasm>(getStreamer().getCurrentSection().first);
607
6
      if (WS && WS->getKind().isText())
608
0
        return error("data directive must occur in a data segment: ",
609
0
                     Lexer.getTok());
610
16
    }
611
16
    CurrentState = DataSection;
612
16
    return false;
613
16
  }
614
615
  // This function processes wasm-specific directives streamed to
616
  // WebAssemblyTargetStreamer, all others go to the generic parser
617
  // (see WasmAsmParser).
618
101
  bool ParseDirective(AsmToken DirectiveID) override {
619
101
    // This function has a really weird return value behavior that is different
620
101
    // from all the other parsing functions:
621
101
    // - return true && no tokens consumed -> don't know this directive / let
622
101
    //   the generic parser handle it.
623
101
    // - return true && tokens consumed -> a parsing error occurred.
624
101
    // - return false -> processed this directive successfully.
625
101
    assert(DirectiveID.getKind() == AsmToken::Identifier);
626
101
    auto &Out = getStreamer();
627
101
    auto &TOut =
628
101
        reinterpret_cast<WebAssemblyTargetStreamer &>(*Out.getTargetStreamer());
629
101
    auto &Ctx = Out.getContext();
630
101
631
101
    // TODO: any time we return an error, at least one token must have been
632
101
    // consumed, otherwise this will not signal an error to the caller.
633
101
    if (DirectiveID.getString() == ".globaltype") {
634
2
      auto SymName = expectIdent();
635
2
      if (SymName.empty())
636
0
        return true;
637
2
      if (expect(AsmToken::Comma, ","))
638
0
        return true;
639
2
      auto TypeTok = Lexer.getTok();
640
2
      auto TypeName = expectIdent();
641
2
      if (TypeName.empty())
642
0
        return true;
643
2
      auto Type = parseType(TypeName);
644
2
      if (!Type)
645
0
        return error("Unknown type in .globaltype directive: ", TypeTok);
646
2
      // Now set this symbol with the correct type.
647
2
      auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
648
2
      WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);
649
2
      WasmSym->setGlobalType(
650
2
          wasm::WasmGlobalType{uint8_t(Type.getValue()), true});
651
2
      // And emit the directive again.
652
2
      TOut.emitGlobalType(WasmSym);
653
2
      return expect(AsmToken::EndOfStatement, "EOL");
654
2
    }
655
99
656
99
    if (DirectiveID.getString() == ".functype") {
657
27
      // This code has to send things to the streamer similar to
658
27
      // WebAssemblyAsmPrinter::EmitFunctionBodyStart.
659
27
      // TODO: would be good to factor this into a common function, but the
660
27
      // assembler and backend really don't share any common code, and this code
661
27
      // parses the locals seperately.
662
27
      auto SymName = expectIdent();
663
27
      if (SymName.empty())
664
0
        return true;
665
27
      auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
666
27
      if (CurrentState == Label && 
WasmSym == LastLabel26
) {
667
24
        // This .functype indicates a start of a function.
668
24
        if (ensureEmptyNestingStack())
669
0
          return true;
670
24
        CurrentState = FunctionStart;
671
24
        LastFunctionLabel = LastLabel;
672
24
        push(Function);
673
24
      }
674
27
      auto Signature = make_unique<wasm::WasmSignature>();
675
27
      if (parseSignature(Signature.get()))
676
0
        return true;
677
27
      WasmSym->setSignature(Signature.get());
678
27
      addSignature(std::move(Signature));
679
27
      WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
680
27
      TOut.emitFunctionType(WasmSym);
681
27
      // TODO: backend also calls TOut.emitIndIdx, but that is not implemented.
682
27
      return expect(AsmToken::EndOfStatement, "EOL");
683
27
    }
684
72
685
72
    if (DirectiveID.getString() == ".eventtype") {
686
3
      auto SymName = expectIdent();
687
3
      if (SymName.empty())
688
0
        return true;
689
3
      auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
690
3
      auto Signature = make_unique<wasm::WasmSignature>();
691
3
      if (parseRegTypeList(Signature->Params))
692
0
        return true;
693
3
      WasmSym->setSignature(Signature.get());
694
3
      addSignature(std::move(Signature));
695
3
      WasmSym->setType(wasm::WASM_SYMBOL_TYPE_EVENT);
696
3
      TOut.emitEventType(WasmSym);
697
3
      // TODO: backend also calls TOut.emitIndIdx, but that is not implemented.
698
3
      return expect(AsmToken::EndOfStatement, "EOL");
699
3
    }
700
69
701
69
    if (DirectiveID.getString() == ".local") {
702
5
      if (CurrentState != FunctionStart)
703
0
        return error(".local directive should follow the start of a function",
704
0
                     Lexer.getTok());
705
5
      SmallVector<wasm::ValType, 4> Locals;
706
5
      if (parseRegTypeList(Locals))
707
0
        return true;
708
5
      TOut.emitLocal(Locals);
709
5
      CurrentState = FunctionLocals;
710
5
      return expect(AsmToken::EndOfStatement, "EOL");
711
5
    }
712
64
713
64
    if (DirectiveID.getString() == ".int8" ||
714
64
        
DirectiveID.getString() == ".int16"58
||
715
64
        
DirectiveID.getString() == ".int32"56
||
716
64
        
DirectiveID.getString() == ".int64"52
) {
717
14
      if (CheckDataSection()) 
return true0
;
718
14
      const MCExpr *Val;
719
14
      SMLoc End;
720
14
      if (Parser.parseExpression(Val, End))
721
0
        return error("Cannot parse .int expression: ", Lexer.getTok());
722
14
      size_t NumBits = 0;
723
14
      DirectiveID.getString().drop_front(4).getAsInteger(10, NumBits);
724
14
      Out.EmitValue(Val, NumBits / 8, End);
725
14
      return expect(AsmToken::EndOfStatement, "EOL");
726
14
    }
727
50
728
50
    if (DirectiveID.getString() == ".asciz") {
729
2
      if (CheckDataSection()) 
return true0
;
730
2
      std::string S;
731
2
      if (Parser.parseEscapedString(S))
732
0
        return error("Cannot parse string constant: ", Lexer.getTok());
733
2
      Out.EmitBytes(StringRef(S.c_str(), S.length() + 1));
734
2
      return expect(AsmToken::EndOfStatement, "EOL");
735
2
    }
736
48
737
48
    return true; // We didn't process this directive.
738
48
  }
739
740
  bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned & /*Opcode*/,
741
                               OperandVector &Operands, MCStreamer &Out,
742
                               uint64_t &ErrorInfo,
743
436
                               bool MatchingInlineAsm) override {
744
436
    MCInst Inst;
745
436
    unsigned MatchResult =
746
436
        MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm);
747
436
    switch (MatchResult) {
748
436
    case Match_Success: {
749
435
      if (CurrentState == FunctionStart) {
750
17
        // This is the first instruction in a function, but we haven't seen
751
17
        // a .local directive yet. The streamer requires locals to be encoded
752
17
        // as a prelude to the instructions, so emit an empty list of locals
753
17
        // here.
754
17
        auto &TOut = reinterpret_cast<WebAssemblyTargetStreamer &>(
755
17
            *Out.getTargetStreamer());
756
17
        TOut.emitLocal(SmallVector<wasm::ValType, 0>());
757
17
      }
758
435
      // Fix unknown p2align operands.
759
435
      auto Align = WebAssembly::GetDefaultP2AlignAny(Inst.getOpcode());
760
435
      if (Align != -1U) {
761
82
        auto &Op0 = Inst.getOperand(0);
762
82
        if (Op0.getImm() == -1)
763
78
          Op0.setImm(Align);
764
82
      }
765
435
      Out.EmitInstruction(Inst, getSTI());
766
435
      if (CurrentState == EndFunction) {
767
23
        onEndOfFunction();
768
412
      } else {
769
412
        CurrentState = Instructions;
770
412
      }
771
435
      return false;
772
436
    }
773
436
    case Match_MissingFeature:
774
0
      return Parser.Error(
775
0
          IDLoc, "instruction requires a WASM feature not currently enabled");
776
436
    case Match_MnemonicFail:
777
0
      return Parser.Error(IDLoc, "invalid instruction");
778
436
    case Match_NearMisses:
779
0
      return Parser.Error(IDLoc, "ambiguous instruction");
780
436
    case Match_InvalidTiedOperand:
781
1
    case Match_InvalidOperand: {
782
1
      SMLoc ErrorLoc = IDLoc;
783
1
      if (ErrorInfo != ~0ULL) {
784
1
        if (ErrorInfo >= Operands.size())
785
0
          return Parser.Error(IDLoc, "too few operands for instruction");
786
1
        ErrorLoc = Operands[ErrorInfo]->getStartLoc();
787
1
        if (ErrorLoc == SMLoc())
788
0
          ErrorLoc = IDLoc;
789
1
      }
790
1
      return Parser.Error(ErrorLoc, "invalid operand for instruction");
791
0
    }
792
0
    }
793
0
    llvm_unreachable("Implement any new match types added!");
794
0
  }
795
796
46
  void doBeforeLabelEmit(MCSymbol *Symbol) override {
797
46
    // Start a new section for the next function automatically, since our
798
46
    // object writer expects each function to have its own section. This way
799
46
    // The user can't forget this "convention".
800
46
    auto SymName = Symbol->getName();
801
46
    if (SymName.startswith(".L"))
802
22
      return; // Local Symbol.
803
24
    // Only create a new text section if we're already in one.
804
24
    auto CWS = cast<MCSectionWasm>(getStreamer().getCurrentSection().first);
805
24
    if (!CWS || !CWS->getKind().isText())
806
0
      return;
807
24
    auto SecName = ".text." + SymName;
808
24
    auto WS = getContext().getWasmSection(SecName, SectionKind::getText());
809
24
    getStreamer().SwitchSection(WS);
810
24
  }
811
812
23
  void onEndOfFunction() {
813
23
    // Automatically output a .size directive, so it becomes optional for the
814
23
    // user.
815
23
    if (!LastFunctionLabel) 
return0
;
816
23
    auto TempSym = getContext().createLinkerPrivateTempSymbol();
817
23
    getStreamer().EmitLabel(TempSym);
818
23
    auto Start = MCSymbolRefExpr::create(LastFunctionLabel, getContext());
819
23
    auto End = MCSymbolRefExpr::create(TempSym, getContext());
820
23
    auto Expr =
821
23
        MCBinaryExpr::create(MCBinaryExpr::Sub, End, Start, getContext());
822
23
    getStreamer().emitELFSize(LastFunctionLabel, Expr);
823
23
  }
824
825
17
  void onEndOfFile() override { ensureEmptyNestingStack(); }
826
};
827
} // end anonymous namespace
828
829
// Force static initialization.
830
91.7k
extern "C" void LLVMInitializeWebAssemblyAsmParser() {
831
91.7k
  RegisterMCAsmParser<WebAssemblyAsmParser> X(getTheWebAssemblyTarget32());
832
91.7k
  RegisterMCAsmParser<WebAssemblyAsmParser> Y(getTheWebAssemblyTarget64());
833
91.7k
}
834
835
#define GET_REGISTER_MATCHER
836
#define GET_MATCHER_IMPLEMENTATION
837
#include "WebAssemblyGenAsmMatcher.inc"