LLVM 22.0.0git
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
22#include "llvm/MC/MCContext.h"
23#include "llvm/MC/MCExpr.h"
24#include "llvm/MC/MCInst.h"
25#include "llvm/MC/MCInstrInfo.h"
30#include "llvm/MC/MCStreamer.h"
32#include "llvm/MC/MCSymbol.h"
37
38using namespace llvm;
39
40#define DEBUG_TYPE "wasm-asm-parser"
41
42static const char *getSubtargetFeatureName(uint64_t Val);
43
44namespace {
45
46/// WebAssemblyOperand - Instances of this class represent the operands in a
47/// parsed Wasm machine instruction.
48struct WebAssemblyOperand : public MCParsedAsmOperand {
49 enum KindTy { Token, Integer, Float, Symbol, BrList, CatchList } Kind;
50
51 SMLoc StartLoc, EndLoc;
52
53 struct TokOp {
54 StringRef Tok;
55 };
56
57 struct IntOp {
58 int64_t Val;
59 };
60
61 struct FltOp {
62 double Val;
63 };
64
65 struct SymOp {
66 const MCExpr *Exp;
67 };
68
69 struct BrLOp {
70 std::vector<unsigned> List;
71 };
72
73 struct CaLOpElem {
74 uint8_t Opcode;
75 const MCExpr *Tag;
76 unsigned Dest;
77 };
78
79 struct CaLOp {
80 std::vector<CaLOpElem> List;
81 };
82
83 union {
84 struct TokOp Tok;
85 struct IntOp Int;
86 struct FltOp Flt;
87 struct SymOp Sym;
88 struct BrLOp BrL;
89 struct CaLOp CaL;
90 };
91
92 WebAssemblyOperand(SMLoc Start, SMLoc End, TokOp T)
93 : Kind(Token), StartLoc(Start), EndLoc(End), Tok(T) {}
94 WebAssemblyOperand(SMLoc Start, SMLoc End, IntOp I)
95 : Kind(Integer), StartLoc(Start), EndLoc(End), Int(I) {}
96 WebAssemblyOperand(SMLoc Start, SMLoc End, FltOp F)
97 : Kind(Float), StartLoc(Start), EndLoc(End), Flt(F) {}
98 WebAssemblyOperand(SMLoc Start, SMLoc End, SymOp S)
99 : Kind(Symbol), StartLoc(Start), EndLoc(End), Sym(S) {}
100 WebAssemblyOperand(SMLoc Start, SMLoc End, BrLOp B)
101 : Kind(BrList), StartLoc(Start), EndLoc(End), BrL(B) {}
102 WebAssemblyOperand(SMLoc Start, SMLoc End, CaLOp C)
103 : Kind(CatchList), StartLoc(Start), EndLoc(End), CaL(C) {}
104
105 ~WebAssemblyOperand() {
106 if (isBrList())
107 BrL.~BrLOp();
108 if (isCatchList())
109 CaL.~CaLOp();
110 }
111
112 bool isToken() const override { return Kind == Token; }
113 bool isImm() const override { return Kind == Integer || Kind == Symbol; }
114 bool isFPImm() const { return Kind == Float; }
115 bool isMem() const override { return false; }
116 bool isReg() const override { return false; }
117 bool isBrList() const { return Kind == BrList; }
118 bool isCatchList() const { return Kind == CatchList; }
119
120 MCRegister getReg() const override {
121 llvm_unreachable("Assembly inspects a register operand");
122 return 0;
123 }
124
125 StringRef getToken() const {
126 assert(isToken());
127 return Tok.Tok;
128 }
129
130 SMLoc getStartLoc() const override { return StartLoc; }
131 SMLoc getEndLoc() const override { return EndLoc; }
132
133 void addRegOperands(MCInst &, unsigned) const {
134 // Required by the assembly matcher.
135 llvm_unreachable("Assembly matcher creates register operands");
136 }
137
138 void addImmOperands(MCInst &Inst, unsigned N) const {
139 assert(N == 1 && "Invalid number of operands!");
140 if (Kind == Integer)
142 else if (Kind == Symbol)
144 else
145 llvm_unreachable("Should be integer immediate or symbol!");
146 }
147
148 void addFPImmf32Operands(MCInst &Inst, unsigned N) const {
149 assert(N == 1 && "Invalid number of operands!");
150 if (Kind == Float)
151 Inst.addOperand(
152 MCOperand::createSFPImm(bit_cast<uint32_t>(float(Flt.Val))));
153 else
154 llvm_unreachable("Should be float immediate!");
155 }
156
157 void addFPImmf64Operands(MCInst &Inst, unsigned N) const {
158 assert(N == 1 && "Invalid number of operands!");
159 if (Kind == Float)
160 Inst.addOperand(MCOperand::createDFPImm(bit_cast<uint64_t>(Flt.Val)));
161 else
162 llvm_unreachable("Should be float immediate!");
163 }
164
165 void addBrListOperands(MCInst &Inst, unsigned N) const {
166 assert(N == 1 && isBrList() && "Invalid BrList!");
167 for (auto Br : BrL.List)
169 }
170
171 void addCatchListOperands(MCInst &Inst, unsigned N) const {
172 assert(N == 1 && isCatchList() && "Invalid CatchList!");
173 Inst.addOperand(MCOperand::createImm(CaL.List.size()));
174 for (auto Ca : CaL.List) {
175 Inst.addOperand(MCOperand::createImm(Ca.Opcode));
176 if (Ca.Opcode == wasm::WASM_OPCODE_CATCH ||
177 Ca.Opcode == wasm::WASM_OPCODE_CATCH_REF)
178 Inst.addOperand(MCOperand::createExpr(Ca.Tag));
179 Inst.addOperand(MCOperand::createImm(Ca.Dest));
180 }
181 }
182
183 void print(raw_ostream &OS, const MCAsmInfo &MAI) const override {
184 switch (Kind) {
185 case Token:
186 OS << "Tok:" << Tok.Tok;
187 break;
188 case Integer:
189 OS << "Int:" << Int.Val;
190 break;
191 case Float:
192 OS << "Flt:" << Flt.Val;
193 break;
194 case Symbol:
195 OS << "Sym:" << Sym.Exp;
196 break;
197 case BrList:
198 OS << "BrList:" << BrL.List.size();
199 break;
200 case CatchList:
201 OS << "CaList:" << CaL.List.size();
202 break;
203 }
204 }
205};
206
207// Perhaps this should go somewhere common.
208static wasm::WasmLimits defaultLimits() {
209 return {wasm::WASM_LIMITS_FLAG_NONE, 0, 0, 0};
210}
211
213 const StringRef &Name,
214 bool Is64) {
215 auto *Sym = static_cast<MCSymbolWasm *>(Ctx.lookupSymbol(Name));
216 if (Sym) {
217 if (!Sym->isFunctionTable())
218 Ctx.reportError(SMLoc(), "symbol is not a wasm funcref table");
219 } else {
220 Sym = static_cast<MCSymbolWasm *>(Ctx.getOrCreateSymbol(Name));
221 Sym->setFunctionTable(Is64);
222 // The default function table is synthesized by the linker.
223 }
224 return Sym;
225}
226
227class WebAssemblyAsmParser final : public MCTargetAsmParser {
228 MCAsmParser &Parser;
229 AsmLexer &Lexer;
230
231 // Order of labels, directives and instructions in a .s file have no
232 // syntactical enforcement. This class is a callback from the actual parser,
233 // and yet we have to be feeding data to the streamer in a very particular
234 // order to ensure a correct binary encoding that matches the regular backend
235 // (the streamer does not enforce this). This "state machine" enum helps
236 // guarantee that correct order.
237 enum ParserState {
238 FileStart,
239 FunctionLabel,
240 FunctionStart,
241 FunctionLocals,
243 EndFunction,
244 DataSection,
245 } CurrentState = FileStart;
246
247 // For ensuring blocks are properly nested.
248 enum NestingType {
249 Function,
250 Block,
251 Loop,
252 Try,
253 CatchAll,
254 TryTable,
255 If,
256 Else,
257 Undefined,
258 };
259 struct Nested {
260 NestingType NT;
262 };
263 std::vector<Nested> NestingStack;
264
265 MCSymbolWasm *DefaultFunctionTable = nullptr;
266 MCSymbol *LastFunctionLabel = nullptr;
267
268 bool Is64;
269
271 // Don't type check if -no-type-check was set.
272 bool SkipTypeCheck;
273
274public:
275 WebAssemblyAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
276 const MCInstrInfo &MII, const MCTargetOptions &Options)
277 : MCTargetAsmParser(Options, STI, MII), Parser(Parser),
278 Lexer(Parser.getLexer()), Is64(STI.getTargetTriple().isArch64Bit()),
279 TC(Parser, MII, Is64), SkipTypeCheck(Options.MCNoTypeCheck) {
280 FeatureBitset FBS = ComputeAvailableFeatures(STI.getFeatureBits());
281
282 // bulk-memory implies bulk-memory-opt
283 if (FBS.test(WebAssembly::FeatureBulkMemory)) {
284 FBS.set(WebAssembly::FeatureBulkMemoryOpt);
285 }
286 // reference-types implies call-indirect-overlong
287 if (FBS.test(WebAssembly::FeatureReferenceTypes)) {
288 FBS.set(WebAssembly::FeatureCallIndirectOverlong);
289 }
290
292 // Don't type check if this is inline asm, since that is a naked sequence of
293 // instructions without a function/locals decl.
294 auto &SM = Parser.getSourceManager();
295 auto BufferName =
296 SM.getBufferInfo(SM.getMainFileID()).Buffer->getBufferIdentifier();
297 if (BufferName == "<inline asm>")
298 SkipTypeCheck = true;
299 }
300
301 void Initialize(MCAsmParser &Parser) override {
303
304 DefaultFunctionTable = getOrCreateFunctionTableSymbol(
305 getContext(), "__indirect_function_table", Is64);
306 if (!STI->checkFeatures("+call-indirect-overlong") &&
307 !STI->checkFeatures("+reference-types"))
308 DefaultFunctionTable->setOmitFromLinkingSection();
309 }
310
311#define GET_ASSEMBLER_HEADER
312#include "WebAssemblyGenAsmMatcher.inc"
313
314 // TODO: This is required to be implemented, but appears unused.
315 bool parseRegister(MCRegister &Reg, SMLoc &StartLoc, SMLoc &EndLoc) override {
316 llvm_unreachable("parseRegister is not implemented.");
317 }
319 SMLoc &EndLoc) override {
320 llvm_unreachable("tryParseRegister is not implemented.");
321 }
322
323 bool error(const Twine &Msg, const AsmToken &Tok) {
324 return Parser.Error(Tok.getLoc(), Msg + Tok.getString());
325 }
326
327 bool error(const Twine &Msg, SMLoc Loc = SMLoc()) {
328 return Parser.Error(Loc.isValid() ? Loc : Lexer.getTok().getLoc(), Msg);
329 }
330
331 std::pair<StringRef, StringRef> nestingString(NestingType NT) {
332 switch (NT) {
333 case Function:
334 return {"function", "end_function"};
335 case Block:
336 return {"block", "end_block"};
337 case Loop:
338 return {"loop", "end_loop"};
339 case Try:
340 return {"try", "end_try/delegate"};
341 case CatchAll:
342 return {"catch_all", "end_try"};
343 case TryTable:
344 return {"try_table", "end_try_table"};
345 case If:
346 return {"if", "end_if"};
347 case Else:
348 return {"else", "end_if"};
349 default:
350 llvm_unreachable("unknown NestingType");
351 }
352 }
353
354 void push(NestingType NT, wasm::WasmSignature Sig = wasm::WasmSignature()) {
355 NestingStack.push_back({NT, Sig});
356 }
357
358 bool pop(StringRef Ins, NestingType NT1, NestingType NT2 = Undefined) {
359 if (NestingStack.empty())
360 return error(Twine("End of block construct with no start: ") + Ins);
361 auto Top = NestingStack.back();
362 if (Top.NT != NT1 && Top.NT != NT2)
363 return error(Twine("Block construct type mismatch, expected: ") +
364 nestingString(Top.NT).second + ", instead got: " + Ins);
365 TC.setLastSig(Top.Sig);
366 NestingStack.pop_back();
367 return false;
368 }
369
370 // Pop a NestingType and push a new NestingType with the same signature. Used
371 // for if-else and try-catch(_all).
372 bool popAndPushWithSameSignature(StringRef Ins, NestingType PopNT,
373 NestingType PushNT) {
374 if (NestingStack.empty())
375 return error(Twine("End of block construct with no start: ") + Ins);
376 auto Sig = NestingStack.back().Sig;
377 if (pop(Ins, PopNT))
378 return true;
379 push(PushNT, Sig);
380 return false;
381 }
382
383 bool ensureEmptyNestingStack(SMLoc Loc = SMLoc()) {
384 auto Err = !NestingStack.empty();
385 while (!NestingStack.empty()) {
386 error(Twine("Unmatched block construct(s) at function end: ") +
387 nestingString(NestingStack.back().NT).first,
388 Loc);
389 NestingStack.pop_back();
390 }
391 return Err;
392 }
393
394 bool isNext(AsmToken::TokenKind Kind) {
395 auto Ok = Lexer.is(Kind);
396 if (Ok)
397 Parser.Lex();
398 return Ok;
399 }
400
401 bool expect(AsmToken::TokenKind Kind, const char *KindName) {
402 if (!isNext(Kind))
403 return error(std::string("Expected ") + KindName + ", instead got: ",
404 Lexer.getTok());
405 return false;
406 }
407
408 StringRef expectIdent() {
409 if (!Lexer.is(AsmToken::Identifier)) {
410 error("Expected identifier, got: ", Lexer.getTok());
411 return StringRef();
412 }
413 auto Name = Lexer.getTok().getString();
414 Parser.Lex();
415 return Name;
416 }
417
418 bool parseRegTypeList(SmallVectorImpl<wasm::ValType> &Types) {
419 while (Lexer.is(AsmToken::Identifier)) {
421 if (!Type)
422 return error("unknown type: ", Lexer.getTok());
423 Types.push_back(*Type);
424 Parser.Lex();
425 if (!isNext(AsmToken::Comma))
426 break;
427 }
428 return false;
429 }
430
431 void parseSingleInteger(bool IsNegative, OperandVector &Operands) {
432 auto &Int = Lexer.getTok();
433 int64_t Val = Int.getIntVal();
434 if (IsNegative)
435 Val = -Val;
436 Operands.push_back(std::make_unique<WebAssemblyOperand>(
437 Int.getLoc(), Int.getEndLoc(), WebAssemblyOperand::IntOp{Val}));
438 Parser.Lex();
439 }
440
441 bool parseSingleFloat(bool IsNegative, OperandVector &Operands) {
442 auto &Flt = Lexer.getTok();
443 double Val;
444 if (Flt.getString().getAsDouble(Val, false))
445 return error("Cannot parse real: ", Flt);
446 if (IsNegative)
447 Val = -Val;
448 Operands.push_back(std::make_unique<WebAssemblyOperand>(
449 Flt.getLoc(), Flt.getEndLoc(), WebAssemblyOperand::FltOp{Val}));
450 Parser.Lex();
451 return false;
452 }
453
454 bool parseSpecialFloatMaybe(bool IsNegative, OperandVector &Operands) {
455 if (Lexer.isNot(AsmToken::Identifier))
456 return true;
457 auto &Flt = Lexer.getTok();
458 auto S = Flt.getString();
459 double Val;
460 if (S.compare_insensitive("infinity") == 0) {
461 Val = std::numeric_limits<double>::infinity();
462 } else if (S.compare_insensitive("nan") == 0) {
463 Val = std::numeric_limits<double>::quiet_NaN();
464 } else {
465 return true;
466 }
467 if (IsNegative)
468 Val = -Val;
469 Operands.push_back(std::make_unique<WebAssemblyOperand>(
470 Flt.getLoc(), Flt.getEndLoc(), WebAssemblyOperand::FltOp{Val}));
471 Parser.Lex();
472 return false;
473 }
474
475 bool checkForP2AlignIfLoadStore(OperandVector &Operands, StringRef InstName) {
476 // FIXME: there is probably a cleaner way to do this.
477 auto IsLoadStore = InstName.contains(".load") ||
478 InstName.contains(".store") ||
479 InstName.contains("prefetch");
480 auto IsAtomic = InstName.contains("atomic.");
481 if (IsLoadStore || IsAtomic) {
482 // Parse load/store operands of the form: offset:p2align=align
483 if (IsLoadStore && isNext(AsmToken::Colon)) {
484 auto Id = expectIdent();
485 if (Id != "p2align")
486 return error("Expected p2align, instead got: " + Id);
487 if (expect(AsmToken::Equal, "="))
488 return true;
489 if (!Lexer.is(AsmToken::Integer))
490 return error("Expected integer constant");
491 parseSingleInteger(false, Operands);
492 } else {
493 // v128.{load,store}{8,16,32,64}_lane has both a memarg and a lane
494 // index. We need to avoid parsing an extra alignment operand for the
495 // lane index.
496 auto IsLoadStoreLane = InstName.contains("_lane");
497 if (IsLoadStoreLane && Operands.size() == 4)
498 return false;
499 // Alignment not specified (or atomics, must use default alignment).
500 // We can't just call WebAssembly::GetDefaultP2Align since we don't have
501 // an opcode until after the assembly matcher, so set a default to fix
502 // up later.
503 auto Tok = Lexer.getTok();
504 Operands.push_back(std::make_unique<WebAssemblyOperand>(
505 Tok.getLoc(), Tok.getEndLoc(), WebAssemblyOperand::IntOp{-1}));
506 }
507 }
508 return false;
509 }
510
511 void addBlockTypeOperand(OperandVector &Operands, SMLoc NameLoc,
513 if (BT == WebAssembly::BlockType::Void) {
515 } else {
516 wasm::WasmSignature Sig({static_cast<wasm::ValType>(BT)}, {});
517 TC.setLastSig(Sig);
518 NestingStack.back().Sig = Sig;
519 }
520 Operands.push_back(std::make_unique<WebAssemblyOperand>(
521 NameLoc, NameLoc, WebAssemblyOperand::IntOp{static_cast<int64_t>(BT)}));
522 }
523
524 bool parseLimits(wasm::WasmLimits *Limits) {
525 auto Tok = Lexer.getTok();
526 if (!Tok.is(AsmToken::Integer))
527 return error("Expected integer constant, instead got: ", Tok);
528 int64_t Val = Tok.getIntVal();
529 assert(Val >= 0);
530 Limits->Minimum = Val;
531 Parser.Lex();
532
533 if (isNext(AsmToken::Comma)) {
535 auto Tok = Lexer.getTok();
536 if (!Tok.is(AsmToken::Integer))
537 return error("Expected integer constant, instead got: ", Tok);
538 int64_t Val = Tok.getIntVal();
539 assert(Val >= 0);
540 Limits->Maximum = Val;
541 Parser.Lex();
542 }
543 return false;
544 }
545
546 bool parseFunctionTableOperand(std::unique_ptr<WebAssemblyOperand> *Op) {
547 if (STI->checkFeatures("+call-indirect-overlong") ||
548 STI->checkFeatures("+reference-types")) {
549 // If the call-indirect-overlong feature is enabled, or implied by the
550 // reference-types feature, there is an explicit table operand. To allow
551 // the same assembly to be compiled with or without
552 // call-indirect-overlong, we allow the operand to be omitted, in which
553 // case we default to __indirect_function_table.
554 auto &Tok = Lexer.getTok();
555 if (Tok.is(AsmToken::Identifier)) {
556 auto *Sym =
558 const auto *Val = MCSymbolRefExpr::create(Sym, getContext());
559 *Op = std::make_unique<WebAssemblyOperand>(
560 Tok.getLoc(), Tok.getEndLoc(), WebAssemblyOperand::SymOp{Val});
561 Parser.Lex();
562 return expect(AsmToken::Comma, ",");
563 }
564 const auto *Val =
565 MCSymbolRefExpr::create(DefaultFunctionTable, getContext());
566 *Op = std::make_unique<WebAssemblyOperand>(
567 SMLoc(), SMLoc(), WebAssemblyOperand::SymOp{Val});
568 return false;
569 }
570 // For the MVP there is at most one table whose number is 0, but we can't
571 // write a table symbol or issue relocations. Instead we just ensure the
572 // table is live and write a zero.
573 getStreamer().emitSymbolAttribute(DefaultFunctionTable, MCSA_NoDeadStrip);
574 *Op = std::make_unique<WebAssemblyOperand>(SMLoc(), SMLoc(),
575 WebAssemblyOperand::IntOp{0});
576 return false;
577 }
578
580 SMLoc NameLoc, OperandVector &Operands) override {
581 // Note: Name does NOT point into the sourcecode, but to a local, so
582 // use NameLoc instead.
583 Name = StringRef(NameLoc.getPointer(), Name.size());
584
585 // WebAssembly has instructions with / in them, which AsmLexer parses
586 // as separate tokens, so if we find such tokens immediately adjacent (no
587 // whitespace), expand the name to include them:
588 for (;;) {
589 auto &Sep = Lexer.getTok();
590 if (Sep.getLoc().getPointer() != Name.end() ||
591 Sep.getKind() != AsmToken::Slash)
592 break;
593 // Extend name with /
594 Name = StringRef(Name.begin(), Name.size() + Sep.getString().size());
595 Parser.Lex();
596 // We must now find another identifier, or error.
597 auto &Id = Lexer.getTok();
598 if (Id.getKind() != AsmToken::Identifier ||
599 Id.getLoc().getPointer() != Name.end())
600 return error("Incomplete instruction name: ", Id);
601 Name = StringRef(Name.begin(), Name.size() + Id.getString().size());
602 Parser.Lex();
603 }
604
605 // Now construct the name as first operand.
606 Operands.push_back(std::make_unique<WebAssemblyOperand>(
607 NameLoc, SMLoc::getFromPointer(Name.end()),
608 WebAssemblyOperand::TokOp{Name}));
609
610 // If this instruction is part of a control flow structure, ensure
611 // proper nesting.
612 bool ExpectBlockType = false;
613 bool ExpectFuncType = false;
614 bool ExpectCatchList = false;
615 std::unique_ptr<WebAssemblyOperand> FunctionTable;
616 if (Name == "block") {
617 push(Block);
618 ExpectBlockType = true;
619 } else if (Name == "loop") {
620 push(Loop);
621 ExpectBlockType = true;
622 } else if (Name == "try") {
623 push(Try);
624 ExpectBlockType = true;
625 } else if (Name == "if") {
626 push(If);
627 ExpectBlockType = true;
628 } else if (Name == "else") {
629 if (popAndPushWithSameSignature(Name, If, Else))
630 return true;
631 } else if (Name == "catch") {
632 if (popAndPushWithSameSignature(Name, Try, Try))
633 return true;
634 } else if (Name == "catch_all") {
635 if (popAndPushWithSameSignature(Name, Try, CatchAll))
636 return true;
637 } else if (Name == "try_table") {
638 push(TryTable);
639 ExpectBlockType = true;
640 ExpectCatchList = true;
641 } else if (Name == "end_if") {
642 if (pop(Name, If, Else))
643 return true;
644 } else if (Name == "end_try") {
645 if (pop(Name, Try, CatchAll))
646 return true;
647 } else if (Name == "end_try_table") {
648 if (pop(Name, TryTable))
649 return true;
650 } else if (Name == "delegate") {
651 if (pop(Name, Try))
652 return true;
653 } else if (Name == "end_loop") {
654 if (pop(Name, Loop))
655 return true;
656 } else if (Name == "end_block") {
657 if (pop(Name, Block))
658 return true;
659 } else if (Name == "end_function") {
660 ensureLocals(getStreamer());
661 CurrentState = EndFunction;
662 if (pop(Name, Function) || ensureEmptyNestingStack())
663 return true;
664 } else if (Name == "call_indirect" || Name == "return_call_indirect") {
665 // These instructions have differing operand orders in the text format vs
666 // the binary formats. The MC instructions follow the binary format, so
667 // here we stash away the operand and append it later.
668 if (parseFunctionTableOperand(&FunctionTable))
669 return true;
670 ExpectFuncType = true;
671 } else if (Name == "ref.test") {
672 // When we get support for wasm-gc types, this should become
673 // ExpectRefType.
674 ExpectFuncType = true;
675 }
676
677 // Returns true if the next tokens are a catch clause
678 auto PeekCatchList = [&]() {
679 if (Lexer.isNot(AsmToken::LParen))
680 return false;
681 AsmToken NextTok = Lexer.peekTok();
682 return NextTok.getKind() == AsmToken::Identifier &&
683 NextTok.getIdentifier().starts_with("catch");
684 };
685
686 // Parse a multivalue block type
687 if (ExpectFuncType ||
688 (Lexer.is(AsmToken::LParen) && ExpectBlockType && !PeekCatchList())) {
689 // This has a special TYPEINDEX operand which in text we
690 // represent as a signature, such that we can re-build this signature,
691 // attach it to an anonymous symbol, which is what WasmObjectWriter
692 // expects to be able to recreate the actual unique-ified type indices.
693 auto &Ctx = getContext();
694 auto Loc = Parser.getTok();
695 auto *Signature = Ctx.createWasmSignature();
696 if (parseSignature(Signature))
697 return true;
698 // Got signature as block type, don't need more
699 TC.setLastSig(*Signature);
700 if (ExpectBlockType)
701 NestingStack.back().Sig = *Signature;
702 ExpectBlockType = false;
703 // The "true" here will cause this to be a nameless symbol.
704 MCSymbol *Sym = Ctx.createTempSymbol("typeindex", true);
705 auto *WasmSym = static_cast<MCSymbolWasm *>(Sym);
706 WasmSym->setSignature(Signature);
707 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
708 const MCExpr *Expr =
710 Operands.push_back(std::make_unique<WebAssemblyOperand>(
711 Loc.getLoc(), Loc.getEndLoc(), WebAssemblyOperand::SymOp{Expr}));
712 }
713
714 // If we are expecting a catch clause list, try to parse it here.
715 //
716 // If there is a multivalue block return type before this catch list, it
717 // should have been parsed above. If there is no return type before
718 // encountering this catch list, this means the type is void.
719 // The case when there is a single block return value and then a catch list
720 // will be handled below in the 'while' loop.
721 if (ExpectCatchList && PeekCatchList()) {
722 if (ExpectBlockType) {
723 ExpectBlockType = false;
724 addBlockTypeOperand(Operands, NameLoc, WebAssembly::BlockType::Void);
725 }
726 if (parseCatchList(Operands))
727 return true;
728 ExpectCatchList = false;
729 }
730
731 while (Lexer.isNot(AsmToken::EndOfStatement)) {
732 auto &Tok = Lexer.getTok();
733 switch (Tok.getKind()) {
735 if (!parseSpecialFloatMaybe(false, Operands))
736 break;
737 auto &Id = Lexer.getTok();
738 if (ExpectBlockType) {
739 // Assume this identifier is a block_type.
740 auto BT = WebAssembly::parseBlockType(Id.getString());
741 if (BT == WebAssembly::BlockType::Invalid)
742 return error("Unknown block type: ", Id);
743 addBlockTypeOperand(Operands, NameLoc, BT);
744 ExpectBlockType = false;
745 Parser.Lex();
746 // Now that we've parsed a single block return type, if we are
747 // expecting a catch clause list, try to parse it.
748 if (ExpectCatchList && PeekCatchList()) {
749 if (parseCatchList(Operands))
750 return true;
751 ExpectCatchList = false;
752 }
753 } else {
754 // Assume this identifier is a label.
755 const MCExpr *Val;
756 SMLoc Start = Id.getLoc();
757 SMLoc End;
758 if (Parser.parseExpression(Val, End))
759 return error("Cannot parse symbol: ", Lexer.getTok());
760 Operands.push_back(std::make_unique<WebAssemblyOperand>(
761 Start, End, WebAssemblyOperand::SymOp{Val}));
762 if (checkForP2AlignIfLoadStore(Operands, Name))
763 return true;
764 }
765 break;
766 }
767 case AsmToken::Minus:
768 Parser.Lex();
769 if (Lexer.is(AsmToken::Integer)) {
770 parseSingleInteger(true, Operands);
771 if (checkForP2AlignIfLoadStore(Operands, Name))
772 return true;
773 } else if (Lexer.is(AsmToken::Real)) {
774 if (parseSingleFloat(true, Operands))
775 return true;
776 } else if (!parseSpecialFloatMaybe(true, Operands)) {
777 } else {
778 return error("Expected numeric constant instead got: ",
779 Lexer.getTok());
780 }
781 break;
783 parseSingleInteger(false, Operands);
784 if (checkForP2AlignIfLoadStore(Operands, Name))
785 return true;
786 break;
787 case AsmToken::Real: {
788 if (parseSingleFloat(false, Operands))
789 return true;
790 break;
791 }
792 case AsmToken::LCurly: {
793 Parser.Lex();
794 auto Op = std::make_unique<WebAssemblyOperand>(
795 Tok.getLoc(), Tok.getEndLoc(), WebAssemblyOperand::BrLOp{});
796 if (!Lexer.is(AsmToken::RCurly))
797 for (;;) {
798 Op->BrL.List.push_back(Lexer.getTok().getIntVal());
799 expect(AsmToken::Integer, "integer");
800 if (!isNext(AsmToken::Comma))
801 break;
802 }
803 expect(AsmToken::RCurly, "}");
804 Operands.push_back(std::move(Op));
805 break;
806 }
807 default:
808 return error("Unexpected token in operand: ", Tok);
809 }
810 if (Lexer.isNot(AsmToken::EndOfStatement)) {
811 if (expect(AsmToken::Comma, ","))
812 return true;
813 }
814 }
815
816 // If we are still expecting to parse a block type or a catch list at this
817 // point, we set them to the default/empty state.
818
819 // Support blocks with no operands as default to void.
820 if (ExpectBlockType)
821 addBlockTypeOperand(Operands, NameLoc, WebAssembly::BlockType::Void);
822 // If no catch list has been parsed, add an empty catch list operand.
823 if (ExpectCatchList)
824 Operands.push_back(std::make_unique<WebAssemblyOperand>(
825 NameLoc, NameLoc, WebAssemblyOperand::CaLOp{}));
826
827 if (FunctionTable)
828 Operands.push_back(std::move(FunctionTable));
829 Parser.Lex();
830 return false;
831 }
832
833 bool parseSignature(wasm::WasmSignature *Signature) {
834 if (expect(AsmToken::LParen, "("))
835 return true;
836 if (parseRegTypeList(Signature->Params))
837 return true;
838 if (expect(AsmToken::RParen, ")"))
839 return true;
840 if (expect(AsmToken::MinusGreater, "->"))
841 return true;
842 if (expect(AsmToken::LParen, "("))
843 return true;
844 if (parseRegTypeList(Signature->Returns))
845 return true;
846 if (expect(AsmToken::RParen, ")"))
847 return true;
848 return false;
849 }
850
851 bool parseCatchList(OperandVector &Operands) {
852 auto Op = std::make_unique<WebAssemblyOperand>(
853 Lexer.getTok().getLoc(), SMLoc(), WebAssemblyOperand::CaLOp{});
854 SMLoc EndLoc;
855
856 while (Lexer.is(AsmToken::LParen)) {
857 if (expect(AsmToken::LParen, "("))
858 return true;
859
860 auto CatchStr = expectIdent();
861 if (CatchStr.empty())
862 return true;
863 uint8_t CatchOpcode =
864 StringSwitch<uint8_t>(CatchStr)
866 .Case("catch_ref", wasm::WASM_OPCODE_CATCH_REF)
867 .Case("catch_all", wasm::WASM_OPCODE_CATCH_ALL)
868 .Case("catch_all_ref", wasm::WASM_OPCODE_CATCH_ALL_REF)
869 .Default(0xff);
870 if (CatchOpcode == 0xff)
871 return error(
872 "Expected catch/catch_ref/catch_all/catch_all_ref, instead got: " +
873 CatchStr);
874
875 const MCExpr *Tag = nullptr;
876 if (CatchOpcode == wasm::WASM_OPCODE_CATCH ||
877 CatchOpcode == wasm::WASM_OPCODE_CATCH_REF) {
878 if (Parser.parseExpression(Tag))
879 return error("Cannot parse symbol: ", Lexer.getTok());
880 }
881
882 auto &DestTok = Lexer.getTok();
883 if (DestTok.isNot(AsmToken::Integer))
884 return error("Expected integer constant, instead got: ", DestTok);
885 unsigned Dest = DestTok.getIntVal();
886 Parser.Lex();
887
888 EndLoc = Lexer.getTok().getEndLoc();
889 if (expect(AsmToken::RParen, ")"))
890 return true;
891
892 Op->CaL.List.push_back({CatchOpcode, Tag, Dest});
893 }
894
895 Op->EndLoc = EndLoc;
896 Operands.push_back(std::move(Op));
897 return false;
898 }
899
900 bool checkDataSection() {
901 if (CurrentState != DataSection) {
902 auto *WS = static_cast<const MCSectionWasm *>(
904 if (WS && WS->isText())
905 return error("data directive must occur in a data segment: ",
906 Lexer.getTok());
907 }
908 CurrentState = DataSection;
909 return false;
910 }
911
912 // This function processes wasm-specific directives streamed to
913 // WebAssemblyTargetStreamer, all others go to the generic parser
914 // (see WasmAsmParser).
915 ParseStatus parseDirective(AsmToken DirectiveID) override {
916 assert(DirectiveID.getKind() == AsmToken::Identifier);
917 auto &Out = getStreamer();
918 auto &TOut =
919 reinterpret_cast<WebAssemblyTargetStreamer &>(*Out.getTargetStreamer());
920 auto &Ctx = Out.getContext();
921
922 if (DirectiveID.getString() == ".globaltype") {
923 auto SymName = expectIdent();
924 if (SymName.empty())
926 if (expect(AsmToken::Comma, ","))
928 auto TypeTok = Lexer.getTok();
929 auto TypeName = expectIdent();
930 if (TypeName.empty())
932 auto Type = WebAssembly::parseType(TypeName);
933 if (!Type)
934 return error("Unknown type in .globaltype directive: ", TypeTok);
935 // Optional mutable modifier. Default to mutable for historical reasons.
936 // Ideally we would have gone with immutable as the default and used `mut`
937 // as the modifier to match the `.wat` format.
938 bool Mutable = true;
939 if (isNext(AsmToken::Comma)) {
940 TypeTok = Lexer.getTok();
941 auto Id = expectIdent();
942 if (Id.empty())
944 if (Id == "immutable")
945 Mutable = false;
946 else
947 // Should we also allow `mutable` and `mut` here for clarity?
948 return error("Unknown type in .globaltype modifier: ", TypeTok);
949 }
950 // Now set this symbol with the correct type.
951 auto *WasmSym =
952 static_cast<MCSymbolWasm *>(Ctx.getOrCreateSymbol(SymName));
954 WasmSym->setGlobalType(wasm::WasmGlobalType{uint8_t(*Type), Mutable});
955 // And emit the directive again.
956 TOut.emitGlobalType(WasmSym);
957 return expect(AsmToken::EndOfStatement, "EOL");
958 }
959
960 if (DirectiveID.getString() == ".tabletype") {
961 // .tabletype SYM, ELEMTYPE[, MINSIZE[, MAXSIZE]]
962 auto SymName = expectIdent();
963 if (SymName.empty())
965 if (expect(AsmToken::Comma, ","))
967
968 auto ElemTypeTok = Lexer.getTok();
969 auto ElemTypeName = expectIdent();
970 if (ElemTypeName.empty())
972 std::optional<wasm::ValType> ElemType =
973 WebAssembly::parseType(ElemTypeName);
974 if (!ElemType)
975 return error("Unknown type in .tabletype directive: ", ElemTypeTok);
976
977 wasm::WasmLimits Limits = defaultLimits();
978 if (isNext(AsmToken::Comma) && parseLimits(&Limits))
980
981 // Now that we have the name and table type, we can actually create the
982 // symbol
983 auto *WasmSym =
984 static_cast<MCSymbolWasm *>(Ctx.getOrCreateSymbol(SymName));
986 if (Is64) {
988 }
989 wasm::WasmTableType Type = {*ElemType, Limits};
990 WasmSym->setTableType(Type);
991 TOut.emitTableType(WasmSym);
992 return expect(AsmToken::EndOfStatement, "EOL");
993 }
994
995 if (DirectiveID.getString() == ".functype") {
996 // This code has to send things to the streamer similar to
997 // WebAssemblyAsmPrinter::EmitFunctionBodyStart.
998 // TODO: would be good to factor this into a common function, but the
999 // assembler and backend really don't share any common code, and this code
1000 // parses the locals separately.
1001 auto SymName = expectIdent();
1002 if (SymName.empty())
1003 return ParseStatus::Failure;
1004 auto *WasmSym =
1005 static_cast<MCSymbolWasm *>(Ctx.getOrCreateSymbol(SymName));
1006 if (WasmSym->isDefined()) {
1007 // We push 'Function' either when a label is parsed or a .functype
1008 // directive is parsed. The reason it is not easy to do this uniformly
1009 // in a single place is,
1010 // 1. We can't do this at label parsing time only because there are
1011 // cases we don't have .functype directive before a function label,
1012 // in which case we don't know if the label is a function at the time
1013 // of parsing.
1014 // 2. We can't do this at .functype parsing time only because we want to
1015 // detect a function started with a label and not ended correctly
1016 // without encountering a .functype directive after the label.
1017 if (CurrentState != FunctionLabel) {
1018 // This .functype indicates a start of a function.
1019 if (ensureEmptyNestingStack())
1020 return ParseStatus::Failure;
1021 push(Function);
1022 }
1023 CurrentState = FunctionStart;
1024 LastFunctionLabel = WasmSym;
1025 }
1026 auto *Signature = Ctx.createWasmSignature();
1027 if (parseSignature(Signature))
1028 return ParseStatus::Failure;
1029 if (CurrentState == FunctionStart)
1030 TC.funcDecl(*Signature);
1031 WasmSym->setSignature(Signature);
1032 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
1033 TOut.emitFunctionType(WasmSym);
1034 // TODO: backend also calls TOut.emitIndIdx, but that is not implemented.
1035 return expect(AsmToken::EndOfStatement, "EOL");
1036 }
1037
1038 if (DirectiveID.getString() == ".export_name") {
1039 auto SymName = expectIdent();
1040 if (SymName.empty())
1041 return ParseStatus::Failure;
1042 if (expect(AsmToken::Comma, ","))
1043 return ParseStatus::Failure;
1044 auto ExportName = expectIdent();
1045 if (ExportName.empty())
1046 return ParseStatus::Failure;
1047 auto *WasmSym =
1048 static_cast<MCSymbolWasm *>(Ctx.getOrCreateSymbol(SymName));
1049 WasmSym->setExportName(Ctx.allocateString(ExportName));
1050 TOut.emitExportName(WasmSym, ExportName);
1051 return expect(AsmToken::EndOfStatement, "EOL");
1052 }
1053
1054 if (DirectiveID.getString() == ".import_module") {
1055 auto SymName = expectIdent();
1056 if (SymName.empty())
1057 return ParseStatus::Failure;
1058 if (expect(AsmToken::Comma, ","))
1059 return ParseStatus::Failure;
1060 auto ImportModule = expectIdent();
1061 if (ImportModule.empty())
1062 return ParseStatus::Failure;
1063 auto *WasmSym =
1064 static_cast<MCSymbolWasm *>(Ctx.getOrCreateSymbol(SymName));
1065 WasmSym->setImportModule(Ctx.allocateString(ImportModule));
1066 TOut.emitImportModule(WasmSym, ImportModule);
1067 return expect(AsmToken::EndOfStatement, "EOL");
1068 }
1069
1070 if (DirectiveID.getString() == ".import_name") {
1071 auto SymName = expectIdent();
1072 if (SymName.empty())
1073 return ParseStatus::Failure;
1074 if (expect(AsmToken::Comma, ","))
1075 return ParseStatus::Failure;
1076 auto ImportName = expectIdent();
1077 if (ImportName.empty())
1078 return ParseStatus::Failure;
1079 auto *WasmSym =
1080 static_cast<MCSymbolWasm *>(Ctx.getOrCreateSymbol(SymName));
1081 WasmSym->setImportName(Ctx.allocateString(ImportName));
1082 TOut.emitImportName(WasmSym, ImportName);
1083 return expect(AsmToken::EndOfStatement, "EOL");
1084 }
1085
1086 if (DirectiveID.getString() == ".tagtype") {
1087 auto SymName = expectIdent();
1088 if (SymName.empty())
1089 return ParseStatus::Failure;
1090 auto *WasmSym =
1091 static_cast<MCSymbolWasm *>(Ctx.getOrCreateSymbol(SymName));
1092 auto *Signature = Ctx.createWasmSignature();
1093 if (parseRegTypeList(Signature->Params))
1094 return ParseStatus::Failure;
1095 WasmSym->setSignature(Signature);
1096 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_TAG);
1097 TOut.emitTagType(WasmSym);
1098 // TODO: backend also calls TOut.emitIndIdx, but that is not implemented.
1099 return expect(AsmToken::EndOfStatement, "EOL");
1100 }
1101
1102 if (DirectiveID.getString() == ".local") {
1103 if (CurrentState != FunctionStart)
1104 return error(".local directive should follow the start of a function: ",
1105 Lexer.getTok());
1107 if (parseRegTypeList(Locals))
1108 return ParseStatus::Failure;
1109 TC.localDecl(Locals);
1110 TOut.emitLocal(Locals);
1111 CurrentState = FunctionLocals;
1112 return expect(AsmToken::EndOfStatement, "EOL");
1113 }
1114
1115 if (DirectiveID.getString() == ".int8" ||
1116 DirectiveID.getString() == ".int16" ||
1117 DirectiveID.getString() == ".int32" ||
1118 DirectiveID.getString() == ".int64") {
1119 if (checkDataSection())
1120 return ParseStatus::Failure;
1121 const MCExpr *Val;
1122 SMLoc End;
1123 if (Parser.parseExpression(Val, End))
1124 return error("Cannot parse .int expression: ", Lexer.getTok());
1125 size_t NumBits = 0;
1126 DirectiveID.getString().drop_front(4).getAsInteger(10, NumBits);
1127 Out.emitValue(Val, NumBits / 8, End);
1128 return expect(AsmToken::EndOfStatement, "EOL");
1129 }
1130
1131 if (DirectiveID.getString() == ".asciz") {
1132 if (checkDataSection())
1133 return ParseStatus::Failure;
1134 std::string S;
1135 if (Parser.parseEscapedString(S))
1136 return error("Cannot parse string constant: ", Lexer.getTok());
1137 Out.emitBytes(StringRef(S.c_str(), S.length() + 1));
1138 return expect(AsmToken::EndOfStatement, "EOL");
1139 }
1140
1141 return ParseStatus::NoMatch; // We didn't process this directive.
1142 }
1143
1144 // Called either when the first instruction is parsed of the function ends.
1145 void ensureLocals(MCStreamer &Out) {
1146 if (CurrentState == FunctionStart) {
1147 // We haven't seen a .local directive yet. The streamer requires locals to
1148 // be encoded as a prelude to the instructions, so emit an empty list of
1149 // locals here.
1150 auto &TOut = reinterpret_cast<WebAssemblyTargetStreamer &>(
1151 *Out.getTargetStreamer());
1153 CurrentState = FunctionLocals;
1154 }
1155 }
1156
1157 bool matchAndEmitInstruction(SMLoc IDLoc, unsigned & /*Opcode*/,
1160 bool MatchingInlineAsm) override {
1161 MCInst Inst;
1162 Inst.setLoc(IDLoc);
1163 FeatureBitset MissingFeatures;
1164 unsigned MatchResult = MatchInstructionImpl(
1165 Operands, Inst, ErrorInfo, MissingFeatures, MatchingInlineAsm);
1166 switch (MatchResult) {
1167 case Match_Success: {
1168 ensureLocals(Out);
1169 // Fix unknown p2align operands.
1171 if (Align != -1U) {
1172 auto &Op0 = Inst.getOperand(0);
1173 if (Op0.getImm() == -1)
1174 Op0.setImm(Align);
1175 }
1176 if (Is64) {
1177 // Upgrade 32-bit loads/stores to 64-bit. These mostly differ by having
1178 // an offset64 arg instead of offset32, but to the assembler matcher
1179 // they're both immediates so don't get selected for.
1180 auto Opc64 = WebAssembly::getWasm64Opcode(
1181 static_cast<uint16_t>(Inst.getOpcode()));
1182 if (Opc64 >= 0) {
1183 Inst.setOpcode(Opc64);
1184 }
1185 }
1186 if (!SkipTypeCheck)
1187 TC.typeCheck(IDLoc, Inst, Operands);
1188 Out.emitInstruction(Inst, getSTI());
1189 if (CurrentState == EndFunction) {
1190 onEndOfFunction(IDLoc);
1191 } else {
1192 CurrentState = Instructions;
1193 }
1194 return false;
1195 }
1196 case Match_MissingFeature: {
1197 assert(MissingFeatures.count() > 0 && "Expected missing features");
1198 SmallString<128> Message;
1199 raw_svector_ostream OS(Message);
1200 OS << "instruction requires:";
1201 for (unsigned I = 0, E = MissingFeatures.size(); I != E; ++I)
1202 if (MissingFeatures.test(I))
1203 OS << ' ' << getSubtargetFeatureName(I);
1204 return Parser.Error(IDLoc, Message);
1205 }
1206 case Match_MnemonicFail:
1207 return Parser.Error(IDLoc, "invalid instruction");
1208 case Match_NearMisses:
1209 return Parser.Error(IDLoc, "ambiguous instruction");
1211 case Match_InvalidOperand: {
1212 SMLoc ErrorLoc = IDLoc;
1213 if (ErrorInfo != ~0ULL) {
1214 if (ErrorInfo >= Operands.size())
1215 return Parser.Error(IDLoc, "too few operands for instruction");
1216 ErrorLoc = Operands[ErrorInfo]->getStartLoc();
1217 if (ErrorLoc == SMLoc())
1218 ErrorLoc = IDLoc;
1219 }
1220 return Parser.Error(ErrorLoc, "invalid operand for instruction");
1221 }
1222 }
1223 llvm_unreachable("Implement any new match types added!");
1224 }
1225
1226 void doBeforeLabelEmit(MCSymbol *Symbol, SMLoc IDLoc) override {
1227 // Code below only applies to labels in text sections.
1228 auto *CWS = static_cast<const MCSectionWasm *>(
1230 if (!CWS->isText())
1231 return;
1232
1233 auto *WasmSym = static_cast<MCSymbolWasm *>(Symbol);
1234 // Unlike other targets, we don't allow data in text sections (labels
1235 // declared with .type @object).
1236 if (WasmSym->getType() == wasm::WASM_SYMBOL_TYPE_DATA) {
1237 Parser.Error(IDLoc,
1238 "Wasm doesn\'t support data symbols in text sections");
1239 return;
1240 }
1241
1242 // Start a new section for the next function automatically, since our
1243 // object writer expects each function to have its own section. This way
1244 // The user can't forget this "convention".
1245 auto SymName = Symbol->getName();
1246 if (SymName.starts_with(".L"))
1247 return; // Local Symbol.
1248
1249 // TODO: If the user explicitly creates a new function section, we ignore
1250 // its name when we create this one. It would be nice to honor their
1251 // choice, while still ensuring that we create one if they forget.
1252 // (that requires coordination with WasmAsmParser::parseSectionDirective)
1253 std::string SecName = (".text." + SymName).str();
1254
1255 auto *Group = CWS->getGroup();
1256 // If the current section is a COMDAT, also set the flag on the symbol.
1257 // TODO: Currently the only place that the symbols' comdat flag matters is
1258 // for importing comdat functions. But there's no way to specify that in
1259 // assembly currently.
1260 if (Group)
1261 WasmSym->setComdat(true);
1262 auto *WS = getContext().getWasmSection(SecName, SectionKind::getText(), 0,
1263 Group, MCSection::NonUniqueID);
1265 // Also generate DWARF for this section if requested.
1266 if (getContext().getGenDwarfForAssembly())
1268
1269 if (WasmSym->isFunction()) {
1270 // We give the location of the label (IDLoc) here, because otherwise the
1271 // lexer's next location will be used, which can be confusing. For
1272 // example:
1273 //
1274 // test0: ; This function does not end properly
1275 // ...
1276 //
1277 // test1: ; We would like to point to this line for error
1278 // ... . Not this line, which can contain any instruction
1279 ensureEmptyNestingStack(IDLoc);
1280 CurrentState = FunctionLabel;
1281 LastFunctionLabel = Symbol;
1282 push(Function);
1283 }
1284 }
1285
1286 void onEndOfFunction(SMLoc ErrorLoc) {
1287 if (!SkipTypeCheck)
1288 TC.endOfFunction(ErrorLoc, true);
1289 // Reset the type checker state.
1290 TC.clear();
1291 }
1292
1293 void onEndOfFile() override { ensureEmptyNestingStack(); }
1294};
1295} // end anonymous namespace
1296
1297// Force static initialization.
1298extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void
1302}
1303
1304#define GET_REGISTER_MATCHER
1305#define GET_SUBTARGET_FEATURE_NAME
1306#define GET_MATCHER_IMPLEMENTATION
1307#include "WebAssemblyGenAsmMatcher.inc"
1308
1310 // FIXME: linear search!
1311 for (auto &ME : MatchTable0) {
1312 if (ME.Opcode == Opc) {
1313 return ME.getMnemonic();
1314 }
1315 }
1316 assert(false && "mnemonic not found");
1317 return StringRef();
1318}
static const char * getSubtargetFeatureName(uint64_t Val)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
BitTracker BT
Definition: BitTracker.cpp:68
static void push(SmallVectorImpl< uint64_t > &R, StringRef Str)
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
#define LLVM_ABI
Definition: Compiler.h:213
#define LLVM_EXTERNAL_VISIBILITY
Definition: Compiler.h:132
std::string Name
bool End
Definition: ELF_riscv.cpp:480
Symbol * Sym
Definition: ELF_riscv.cpp:479
static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang", "erlang-compatible garbage collector")
static LVOptions Options
Definition: LVOptions.cpp:25
#define F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
mir Rename Register Operands
static GCMetadataPrinterRegistry::Add< OcamlGCMetadataPrinter > Y("ocaml", "ocaml 3.10-compatible collector")
const NodeList & List
Definition: RDFGraph.cpp:200
raw_pwrite_stream & OS
#define error(X)
LLVM_ABI LLVM_EXTERNAL_VISIBILITY void LLVMInitializeWebAssemblyAsmParser()
StringRef getMnemonic(unsigned Opc)
static const char * getSubtargetFeatureName(uint64_t Val)
This file is part of the WebAssembly Assembler.
This file contains the declaration of the WebAssemblyMCAsmInfo class.
This file provides WebAssembly-specific target descriptions.
This file contains the declaration of the WebAssembly-specific type parsing utility functions.
This file registers the WebAssembly target.
This file declares WebAssembly-specific target streamer classes.
const AsmToken peekTok(bool ShouldSkipSpace=true)
Look ahead at the next token to be lexed.
Definition: AsmLexer.h:121
const AsmToken & getTok() const
Get the current (last) lexed token.
Definition: AsmLexer.h:118
bool is(AsmToken::TokenKind K) const
Check if the current token has kind K.
Definition: AsmLexer.h:147
bool isNot(AsmToken::TokenKind K) const
Check if the current token has kind K.
Definition: AsmLexer.h:150
Target independent representation for an assembler token.
Definition: MCAsmMacro.h:22
LLVM_ABI SMLoc getLoc() const
Definition: AsmLexer.cpp:32
int64_t getIntVal() const
Definition: MCAsmMacro.h:108
StringRef getString() const
Get the string for the current token, this includes all characters (for example, the quotes on string...
Definition: MCAsmMacro.h:103
bool is(TokenKind K) const
Definition: MCAsmMacro.h:75
TokenKind getKind() const
Definition: MCAsmMacro.h:74
LLVM_ABI SMLoc getEndLoc() const
Definition: AsmLexer.cpp:34
StringRef getIdentifier() const
Get the identifier string for the current token, which should be an identifier or a string.
Definition: MCAsmMacro.h:92
This class represents an Operation in the Expression.
Base class for user error types.
Definition: Error.h:354
Container class for subtarget features.
constexpr bool test(unsigned I) const
FeatureBitset & set()
size_t count() const
constexpr size_t size() const
Represents a single loop in the control flow graph.
Definition: LoopInfo.h:40
This class is intended to be used as a base class for asm properties and features specific to the tar...
Definition: MCAsmInfo.h:64
virtual void Initialize(MCAsmParser &Parser)
Initialize the extension for parsing using the given Parser.
Generic assembler parser interface, for use by target specific assembly parsers.
Definition: MCAsmParser.h:124
virtual bool parseEscapedString(std::string &Data)=0
Parse the current token as a string which may include escaped characters and return the string conten...
virtual bool parseExpression(const MCExpr *&Res, SMLoc &EndLoc)=0
Parse an arbitrary expression.
const AsmToken & getTok() const
Get the current AsmToken from the stream.
Definition: MCAsmParser.cpp:43
virtual const AsmToken & Lex()=0
Get the next AsmToken in the stream, possibly handling file inclusion first.
SourceMgr & getSourceManager()
Definition: MCAsmParser.h:166
bool Error(SMLoc L, const Twine &Msg, SMRange Range=std::nullopt)
Return an error at the location L, with the message Msg.
Context object for machine code objects.
Definition: MCContext.h:83
LLVM_ABI MCSymbol * createTempSymbol()
Create a temporary symbol with a unique name.
Definition: MCContext.cpp:386
MCSectionWasm * getWasmSection(const Twine &Section, SectionKind K, unsigned Flags=0)
Definition: MCContext.h:637
LLVM_ABI wasm::WasmSignature * createWasmSignature()
Allocates and returns a new WasmSignature instance (with empty parameter and return type lists).
Definition: MCContext.cpp:473
bool addGenDwarfSection(MCSection *Sec)
Definition: MCContext.h:789
StringRef allocateString(StringRef s)
Allocates a copy of the given string on the allocator managed by this context and returns the result.
Definition: MCContext.h:835
LLVM_ABI MCSymbol * lookupSymbol(const Twine &Name) const
Get the symbol for Name, or null.
Definition: MCContext.cpp:457
LLVM_ABI void reportError(SMLoc L, const Twine &Msg)
Definition: MCContext.cpp:1115
LLVM_ABI MCSymbol * getOrCreateSymbol(const Twine &Name)
Lookup the symbol inside with the specified Name.
Definition: MCContext.cpp:203
Base class for the full range of assembler expressions which are needed for parsing.
Definition: MCExpr.h:34
Instances of this class represent a single low-level machine instruction.
Definition: MCInst.h:188
void setLoc(SMLoc loc)
Definition: MCInst.h:207
unsigned getOpcode() const
Definition: MCInst.h:202
void addOperand(const MCOperand Op)
Definition: MCInst.h:215
void setOpcode(unsigned Op)
Definition: MCInst.h:201
const MCOperand & getOperand(unsigned i) const
Definition: MCInst.h:210
Interface to description of machine instruction set.
Definition: MCInstrInfo.h:27
void setImm(int64_t Val)
Definition: MCInst.h:89
static MCOperand createExpr(const MCExpr *Val)
Definition: MCInst.h:166
static MCOperand createSFPImm(uint32_t Val)
Definition: MCInst.h:152
static MCOperand createImm(int64_t Val)
Definition: MCInst.h:145
static MCOperand createDFPImm(uint64_t Val)
Definition: MCInst.h:159
MCParsedAsmOperand - This abstract class represents a source-level assembly instruction operand.
virtual SMLoc getStartLoc() const =0
getStartLoc - Get the location of the first token of this operand.
virtual bool isReg() const =0
isReg - Is this a register operand?
virtual bool isMem() const =0
isMem - Is this a memory operand?
virtual MCRegister getReg() const =0
virtual bool isToken() const =0
isToken - Is this a token operand?
virtual bool isImm() const =0
isImm - Is this an immediate operand?
virtual void print(raw_ostream &, const MCAsmInfo &) const =0
print - Print a debug representation of the operand to the given stream.
virtual SMLoc getEndLoc() const =0
getEndLoc - Get the location of the last token of this operand.
Wrapper class representing physical registers. Should be passed by value.
Definition: MCRegister.h:33
This represents a section on wasm.
Definition: MCSectionWasm.h:26
static constexpr unsigned NonUniqueID
Definition: MCSection.h:501
Streaming machine code generation interface.
Definition: MCStreamer.h:220
virtual void emitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI)
Emit the given Instruction into the current section.
virtual bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute)=0
Add the given Attribute to Symbol.
MCTargetStreamer * getTargetStreamer()
Definition: MCStreamer.h:324
virtual void switchSection(MCSection *Section, uint32_t Subsec=0)
Set the current section where code is being emitted to Section.
MCSection * getCurrentSectionOnly() const
Definition: MCStreamer.h:421
Generic base class for all target subtargets.
bool checkFeatures(StringRef FS) const
Check whether the subtarget features are enabled/disabled as per the provided string,...
const FeatureBitset & getFeatureBits() const
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx, SMLoc Loc=SMLoc())
Definition: MCExpr.h:214
void setImportModule(StringRef Name)
Definition: MCSymbolWasm.h:101
void setSignature(wasm::WasmSignature *Sig)
Definition: MCSymbolWasm.h:133
void setImportName(StringRef Name)
Definition: MCSymbolWasm.h:109
void setType(wasm::WasmSymbolType type)
Definition: MCSymbolWasm.h:55
void setExportName(StringRef Name)
Definition: MCSymbolWasm.h:113
void setOmitFromLinkingSection()
Definition: MCSymbolWasm.h:89
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition: MCSymbol.h:42
MCTargetAsmParser - Generic interface to target specific assembly parsers.
virtual ParseStatus parseDirective(AsmToken DirectiveID)
Parses a target-specific assembler directive.
virtual bool parseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, OperandVector &Operands)=0
Parse one assembly instruction.
virtual bool parseRegister(MCRegister &Reg, SMLoc &StartLoc, SMLoc &EndLoc)=0
virtual ParseStatus tryParseRegister(MCRegister &Reg, SMLoc &StartLoc, SMLoc &EndLoc)=0
tryParseRegister - parse one register if possible
virtual bool matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, OperandVector &Operands, MCStreamer &Out, uint64_t &ErrorInfo, bool MatchingInlineAsm)=0
Recognize a series of operands of a parsed instruction as an actual MCInst and emit it to the specifi...
void setAvailableFeatures(const FeatureBitset &Value)
const MCSubtargetInfo & getSTI() const
virtual void doBeforeLabelEmit(MCSymbol *Symbol, SMLoc IDLoc)
Ternary parse status returned by various parse* methods.
static constexpr StatusTy Failure
static constexpr StatusTy NoMatch
Represents a location in source code.
Definition: SMLoc.h:23
static SMLoc getFromPointer(const char *Ptr)
Definition: SMLoc.h:36
constexpr const char * getPointer() const
Definition: SMLoc.h:34
static SectionKind getText()
Definition: SectionKind.h:190
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition: SmallString.h:26
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: SmallVector.h:574
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1197
const SrcBuffer & getBufferInfo(unsigned i) const
Definition: SourceMgr.h:121
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:55
bool getAsInteger(unsigned Radix, T &Result) const
Parse the current string as an integer of the specified radix.
Definition: StringRef.h:480
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
Definition: StringRef.h:269
constexpr bool empty() const
empty - Check if the string is empty.
Definition: StringRef.h:151
StringRef drop_front(size_t N=1) const
Return a StringRef equal to 'this' but with the first N elements dropped.
Definition: StringRef.h:619
bool contains(StringRef Other) const
Return true if the given string is a substring of *this, and false otherwise.
Definition: StringRef.h:434
A switch()-like statement whose cases are string literals.
Definition: StringSwitch.h:43
StringSwitch & Case(StringLiteral S, T Value)
Definition: StringSwitch.h:68
R Default(T Value)
Definition: StringSwitch.h:177
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:82
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
bool endOfFunction(SMLoc ErrorLoc, bool ExactMatch)
void funcDecl(const wasm::WasmSignature &Sig)
void setLastSig(const wasm::WasmSignature &Sig)
void localDecl(const SmallVectorImpl< wasm::ValType > &Locals)
bool typeCheck(SMLoc ErrorLoc, const MCInst &Inst, OperandVector &Operands)
WebAssembly-specific streamer interface, to implement support WebAssembly-specific assembly directive...
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:53
A raw_ostream that writes to an SmallVector or SmallString.
Definition: raw_ostream.h:692
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char TypeName[]
Key for Kernel::Arg::Metadata::mTypeName.
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
int getWasm64Opcode(unsigned short Opcode)
MCSymbolWasm * getOrCreateFunctionTableSymbol(MCContext &Ctx, const WebAssemblySubtarget *Subtarget)
Returns the __indirect_function_table, for use in call_indirect and in function bitcasts.
BlockType parseBlockType(StringRef Type)
BlockType
Used as immediate MachineOperands for block signatures.
unsigned GetDefaultP2AlignAny(unsigned Opc)
Return the default p2align value for a load or store with the given opcode.
std::optional< wasm::ValType > parseType(StringRef Type)
@ WASM_LIMITS_FLAG_HAS_MAX
Definition: Wasm.h:159
@ WASM_LIMITS_FLAG_IS_64
Definition: Wasm.h:161
@ WASM_LIMITS_FLAG_NONE
Definition: Wasm.h:158
@ WASM_SYMBOL_TYPE_GLOBAL
Definition: Wasm.h:222
@ WASM_SYMBOL_TYPE_DATA
Definition: Wasm.h:221
@ WASM_SYMBOL_TYPE_TAG
Definition: Wasm.h:224
@ WASM_SYMBOL_TYPE_TABLE
Definition: Wasm.h:225
@ WASM_SYMBOL_TYPE_FUNCTION
Definition: Wasm.h:220
@ WASM_OPCODE_CATCH_ALL_REF
Definition: Wasm.h:154
@ WASM_OPCODE_CATCH
Definition: Wasm.h:151
@ WASM_OPCODE_CATCH_ALL
Definition: Wasm.h:153
@ WASM_OPCODE_CATCH_REF
Definition: Wasm.h:152
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
Target & getTheWebAssemblyTarget32()
Target & getTheWebAssemblyTarget64()
@ MCSA_NoDeadStrip
.no_dead_strip (MachO)
Definition: MCDirectives.h:39
#define N
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39
RegisterMCAsmParser - Helper template for registering a target specific assembly parser,...
uint64_t Minimum
Definition: Wasm.h:323
uint64_t Maximum
Definition: Wasm.h:324
SmallVector< ValType, 1 > Returns
Definition: Wasm.h:507
SmallVector< ValType, 4 > Params
Definition: Wasm.h:508