LLVM 23.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() override {
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)
143 Inst.addOperand(MCOperand::createExpr(Sym.Exp));
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(
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)
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,
242 Instructions,
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;
261 wasm::WasmSignature Sig;
262 };
263 std::vector<Nested> NestingStack;
264
265 MCSymbolWasm *DefaultFunctionTable = nullptr;
266 MCSymbol *LastFunctionLabel = nullptr;
267
268 bool Is64;
269
270 WebAssemblyAsmTypeCheck TC;
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
291 setAvailableFeatures(FBS);
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 }
318 ParseStatus tryParseRegister(MCRegister &Reg, SMLoc &StartLoc,
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 StringRef expectStringOrIdent() {
419 if (Lexer.is(AsmToken::String)) {
420 auto Str = Lexer.getTok().getStringContents();
421 Parser.Lex();
422 return Str;
423 }
424 if (Lexer.is(AsmToken::Identifier)) {
425 auto Name = Lexer.getTok().getString();
426 Parser.Lex();
427 return Name;
428 }
429 error("Expected string or identifier, got: ", Lexer.getTok());
430 return StringRef();
431 }
432
433 bool parseRegTypeList(SmallVectorImpl<wasm::ValType> &Types) {
434 while (Lexer.is(AsmToken::Identifier)) {
435 auto Type = WebAssembly::parseType(Lexer.getTok().getString());
436 if (!Type)
437 return error("unknown type: ", Lexer.getTok());
438 Types.push_back(*Type);
439 Parser.Lex();
440 if (!isNext(AsmToken::Comma))
441 break;
442 }
443 return false;
444 }
445
446 void parseSingleInteger(bool IsNegative, OperandVector &Operands) {
447 auto &Int = Lexer.getTok();
448 int64_t Val = Int.getIntVal();
449 if (IsNegative)
450 Val = -Val;
451 Operands.push_back(std::make_unique<WebAssemblyOperand>(
452 Int.getLoc(), Int.getEndLoc(), WebAssemblyOperand::IntOp{Val}));
453 Parser.Lex();
454 }
455
456 bool parseSingleFloat(bool IsNegative, OperandVector &Operands) {
457 auto &Flt = Lexer.getTok();
458 double Val;
459 if (Flt.getString().getAsDouble(Val, false))
460 return error("Cannot parse real: ", Flt);
461 if (IsNegative)
462 Val = -Val;
463 Operands.push_back(std::make_unique<WebAssemblyOperand>(
464 Flt.getLoc(), Flt.getEndLoc(), WebAssemblyOperand::FltOp{Val}));
465 Parser.Lex();
466 return false;
467 }
468
469 bool parseSpecialFloatMaybe(bool IsNegative, OperandVector &Operands) {
470 if (Lexer.isNot(AsmToken::Identifier))
471 return true;
472 auto &Flt = Lexer.getTok();
473 auto S = Flt.getString();
474 double Val;
475 if (S.compare_insensitive("infinity") == 0) {
476 Val = std::numeric_limits<double>::infinity();
477 } else if (S.compare_insensitive("nan") == 0) {
478 Val = std::numeric_limits<double>::quiet_NaN();
479 } else {
480 return true;
481 }
482 if (IsNegative)
483 Val = -Val;
484 Operands.push_back(std::make_unique<WebAssemblyOperand>(
485 Flt.getLoc(), Flt.getEndLoc(), WebAssemblyOperand::FltOp{Val}));
486 Parser.Lex();
487 return false;
488 }
489
490 bool addMemOrderOrDefault(OperandVector &Operands) {
491 auto &Tok = Lexer.getTok();
492 int64_t Order = wasm::WASM_MEM_ORDER_SEQ_CST;
493 if (Tok.is(AsmToken::Identifier)) {
494 StringRef S = Tok.getString();
495 Order = StringSwitch<int64_t>(S)
496 .Case("acqrel", wasm::WASM_MEM_ORDER_ACQ_REL)
497 .Case("seqcst", wasm::WASM_MEM_ORDER_SEQ_CST)
498 .Default(-1);
499 if (Order != -1) {
500 if (!STI->checkFeatures("+relaxed-atomics"))
501 return error("memory ordering requires relaxed-atomics feature: ",
502 Tok);
503 Parser.Lex();
504 } else {
506 }
507 }
508 Operands.push_back(std::make_unique<WebAssemblyOperand>(
509 Tok.getLoc(), Tok.getEndLoc(), WebAssemblyOperand::IntOp{Order}));
510 return false;
511 }
512
513 bool checkForP2AlignIfLoadStore(OperandVector &Operands, StringRef InstName) {
514 // FIXME: there is probably a cleaner way to do this.
515 auto IsLoadStore = InstName.contains(".load") ||
516 InstName.contains(".store") ||
517 InstName.contains("prefetch");
518 auto IsAtomic = InstName.contains("atomic.");
519 if (IsLoadStore || IsAtomic) {
520 // Parse load/store operands of the form: offset:p2align=align
521 if (IsLoadStore && isNext(AsmToken::Colon)) {
522 auto Id = expectIdent();
523 if (Id != "p2align")
524 return error("Expected p2align, instead got: " + Id);
525 if (expect(AsmToken::Equal, "="))
526 return true;
527 if (!Lexer.is(AsmToken::Integer))
528 return error("Expected integer constant");
529 parseSingleInteger(false, Operands);
530 } else {
531 // v128.{load,store}{8,16,32,64}_lane has both a memarg and a lane
532 // index. We need to avoid parsing an extra alignment operand for the
533 // lane index.
534 auto IsLoadStoreLane = InstName.contains("_lane");
535 if (IsLoadStoreLane && Operands.size() == 4)
536 return false;
537 // Alignment not specified (or atomics, must use default alignment).
538 // We can't just call WebAssembly::GetDefaultP2Align since we don't have
539 // an opcode until after the assembly matcher, so set a default to fix
540 // up later.
541 auto Tok = Lexer.getTok();
542 Operands.push_back(std::make_unique<WebAssemblyOperand>(
543 Tok.getLoc(), Tok.getEndLoc(), WebAssemblyOperand::IntOp{-1}));
544 }
545 }
546 return false;
547 }
548
549 void addBlockTypeOperand(OperandVector &Operands, SMLoc NameLoc,
551 if (BT == WebAssembly::BlockType::Void) {
552 TC.setLastSig(wasm::WasmSignature{});
553 } else {
554 wasm::WasmSignature Sig({static_cast<wasm::ValType>(BT)}, {});
555 TC.setLastSig(Sig);
556 NestingStack.back().Sig = Sig;
557 }
558 Operands.push_back(std::make_unique<WebAssemblyOperand>(
559 NameLoc, NameLoc, WebAssemblyOperand::IntOp{static_cast<int64_t>(BT)}));
560 }
561
562 bool parseLimits(wasm::WasmLimits *Limits) {
563 auto Tok = Lexer.getTok();
564 if (!Tok.is(AsmToken::Integer))
565 return error("Expected integer constant, instead got: ", Tok);
566 int64_t Val = Tok.getIntVal();
567 assert(Val >= 0);
568 Limits->Minimum = Val;
569 Parser.Lex();
570
571 if (isNext(AsmToken::Comma)) {
573 auto Tok = Lexer.getTok();
574 if (!Tok.is(AsmToken::Integer))
575 return error("Expected integer constant, instead got: ", Tok);
576 int64_t Val = Tok.getIntVal();
577 assert(Val >= 0);
578 Limits->Maximum = Val;
579 Parser.Lex();
580 }
581 return false;
582 }
583
584 bool parseFunctionTableOperand(std::unique_ptr<WebAssemblyOperand> *Op) {
585 if (STI->checkFeatures("+call-indirect-overlong") ||
586 STI->checkFeatures("+reference-types")) {
587 // If the call-indirect-overlong feature is enabled, or implied by the
588 // reference-types feature, there is an explicit table operand. To allow
589 // the same assembly to be compiled with or without
590 // call-indirect-overlong, we allow the operand to be omitted, in which
591 // case we default to __indirect_function_table.
592 auto &Tok = Lexer.getTok();
593 if (Tok.is(AsmToken::Identifier)) {
594 auto *Sym =
596 const auto *Val = MCSymbolRefExpr::create(Sym, getContext());
597 *Op = std::make_unique<WebAssemblyOperand>(
598 Tok.getLoc(), Tok.getEndLoc(), WebAssemblyOperand::SymOp{Val});
599 Parser.Lex();
600 return expect(AsmToken::Comma, ",");
601 }
602 const auto *Val =
603 MCSymbolRefExpr::create(DefaultFunctionTable, getContext());
604 *Op = std::make_unique<WebAssemblyOperand>(
605 SMLoc(), SMLoc(), WebAssemblyOperand::SymOp{Val});
606 return false;
607 }
608 // For the MVP there is at most one table whose number is 0, but we can't
609 // write a table symbol or issue relocations. Instead we just ensure the
610 // table is live and write a zero.
611 getStreamer().emitSymbolAttribute(DefaultFunctionTable, MCSA_NoDeadStrip);
612 *Op = std::make_unique<WebAssemblyOperand>(SMLoc(), SMLoc(),
613 WebAssemblyOperand::IntOp{0});
614 return false;
615 }
616
617 bool parseInstruction(ParseInstructionInfo & /*Info*/, StringRef Name,
618 SMLoc NameLoc, OperandVector &Operands) override {
619 // Note: Name does NOT point into the sourcecode, but to a local, so
620 // use NameLoc instead.
621 Name = StringRef(NameLoc.getPointer(), Name.size());
622
623 // WebAssembly has instructions with / in them, which AsmLexer parses
624 // as separate tokens, so if we find such tokens immediately adjacent (no
625 // whitespace), expand the name to include them:
626 for (;;) {
627 auto &Sep = Lexer.getTok();
628 if (Sep.getLoc().getPointer() != Name.end() ||
629 Sep.getKind() != AsmToken::Slash)
630 break;
631 // Extend name with /
632 Name = StringRef(Name.begin(), Name.size() + Sep.getString().size());
633 Parser.Lex();
634 // We must now find another identifier, or error.
635 auto &Id = Lexer.getTok();
636 if (Id.getKind() != AsmToken::Identifier ||
637 Id.getLoc().getPointer() != Name.end())
638 return error("Incomplete instruction name: ", Id);
639 Name = StringRef(Name.begin(), Name.size() + Id.getString().size());
640 Parser.Lex();
641 }
642
643 // Now construct the name as first operand.
644 Operands.push_back(std::make_unique<WebAssemblyOperand>(
645 NameLoc, SMLoc::getFromPointer(Name.end()),
646 WebAssemblyOperand::TokOp{Name}));
647
648 // If this instruction is part of a control flow structure, ensure
649 // proper nesting.
650 bool ExpectBlockType = false;
651 bool ExpectFuncType = false;
652 bool ExpectCatchList = false;
653 std::unique_ptr<WebAssemblyOperand> FunctionTable;
654 if (Name == "block") {
655 push(Block);
656 ExpectBlockType = true;
657 } else if (Name == "loop") {
658 push(Loop);
659 ExpectBlockType = true;
660 } else if (Name == "try") {
661 push(Try);
662 ExpectBlockType = true;
663 } else if (Name == "if") {
664 push(If);
665 ExpectBlockType = true;
666 } else if (Name == "else") {
667 if (popAndPushWithSameSignature(Name, If, Else))
668 return true;
669 } else if (Name == "catch") {
670 if (popAndPushWithSameSignature(Name, Try, Try))
671 return true;
672 } else if (Name == "catch_all") {
673 if (popAndPushWithSameSignature(Name, Try, CatchAll))
674 return true;
675 } else if (Name == "try_table") {
676 push(TryTable);
677 ExpectBlockType = true;
678 ExpectCatchList = true;
679 } else if (Name == "end_if") {
680 if (pop(Name, If, Else))
681 return true;
682 } else if (Name == "end_try") {
683 if (pop(Name, Try, CatchAll))
684 return true;
685 } else if (Name == "end_try_table") {
686 if (pop(Name, TryTable))
687 return true;
688 } else if (Name == "delegate") {
689 if (pop(Name, Try))
690 return true;
691 } else if (Name == "end_loop") {
692 if (pop(Name, Loop))
693 return true;
694 } else if (Name == "end_block") {
695 if (pop(Name, Block))
696 return true;
697 } else if (Name == "end_function") {
698 ensureLocals(getStreamer());
699 CurrentState = EndFunction;
700 if (pop(Name, Function) || ensureEmptyNestingStack())
701 return true;
702 } else if (Name == "call_indirect" || Name == "return_call_indirect") {
703 // These instructions have differing operand orders in the text format vs
704 // the binary formats. The MC instructions follow the binary format, so
705 // here we stash away the operand and append it later.
706 if (parseFunctionTableOperand(&FunctionTable))
707 return true;
708 ExpectFuncType = true;
709 } else if (Name == "ref.test") {
710 // When we get support for wasm-gc types, this should become
711 // ExpectRefType.
712 ExpectFuncType = true;
713 }
714
715 if (Name.contains("atomic.")) {
716 if (addMemOrderOrDefault(Operands))
717 return true;
718 }
719
720 // Returns true if the next tokens are a catch clause
721 auto PeekCatchList = [&]() {
722 if (Lexer.isNot(AsmToken::LParen))
723 return false;
724 AsmToken NextTok = Lexer.peekTok();
725 return NextTok.getKind() == AsmToken::Identifier &&
726 NextTok.getIdentifier().starts_with("catch");
727 };
728
729 // Parse a multivalue block type
730 if (ExpectFuncType ||
731 (Lexer.is(AsmToken::LParen) && ExpectBlockType && !PeekCatchList())) {
732 // This has a special TYPEINDEX operand which in text we
733 // represent as a signature, such that we can re-build this signature,
734 // attach it to an anonymous symbol, which is what WasmObjectWriter
735 // expects to be able to recreate the actual unique-ified type indices.
736 auto &Ctx = getContext();
737 auto Loc = Parser.getTok();
738 auto *Signature = Ctx.createWasmSignature();
739 if (parseSignature(Signature))
740 return true;
741 // Got signature as block type, don't need more
742 TC.setLastSig(*Signature);
743 if (ExpectBlockType)
744 NestingStack.back().Sig = *Signature;
745 ExpectBlockType = false;
746 // The "true" here will cause this to be a nameless symbol.
747 MCSymbol *Sym = Ctx.createTempSymbol("typeindex", true);
748 auto *WasmSym = static_cast<MCSymbolWasm *>(Sym);
749 WasmSym->setSignature(Signature);
750 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
751 const MCExpr *Expr =
753 Operands.push_back(std::make_unique<WebAssemblyOperand>(
754 Loc.getLoc(), Loc.getEndLoc(), WebAssemblyOperand::SymOp{Expr}));
755 }
756
757 // If we are expecting a catch clause list, try to parse it here.
758 //
759 // If there is a multivalue block return type before this catch list, it
760 // should have been parsed above. If there is no return type before
761 // encountering this catch list, this means the type is void.
762 // The case when there is a single block return value and then a catch list
763 // will be handled below in the 'while' loop.
764 if (ExpectCatchList && PeekCatchList()) {
765 if (ExpectBlockType) {
766 ExpectBlockType = false;
767 addBlockTypeOperand(Operands, NameLoc, WebAssembly::BlockType::Void);
768 }
769 if (parseCatchList(Operands))
770 return true;
771 ExpectCatchList = false;
772 }
773
774 while (Lexer.isNot(AsmToken::EndOfStatement)) {
775 auto &Tok = Lexer.getTok();
776 switch (Tok.getKind()) {
778 if (!parseSpecialFloatMaybe(false, Operands))
779 break;
780 auto &Id = Lexer.getTok();
781 if (ExpectBlockType) {
782 // Assume this identifier is a block_type.
783 auto BT = WebAssembly::parseBlockType(Id.getString());
784 if (BT == WebAssembly::BlockType::Invalid)
785 return error("Unknown block type: ", Id);
786 addBlockTypeOperand(Operands, NameLoc, BT);
787 ExpectBlockType = false;
788 Parser.Lex();
789 // Now that we've parsed a single block return type, if we are
790 // expecting a catch clause list, try to parse it.
791 if (ExpectCatchList && PeekCatchList()) {
792 if (parseCatchList(Operands))
793 return true;
794 ExpectCatchList = false;
795 }
796 } else {
797 // Assume this identifier is a label.
798 const MCExpr *Val;
799 SMLoc Start = Id.getLoc();
800 SMLoc End;
801 if (Parser.parseExpression(Val, End))
802 return error("Cannot parse symbol: ", Lexer.getTok());
803 Operands.push_back(std::make_unique<WebAssemblyOperand>(
804 Start, End, WebAssemblyOperand::SymOp{Val}));
805 if (checkForP2AlignIfLoadStore(Operands, Name))
806 return true;
807 }
808 break;
809 }
810 case AsmToken::Minus:
811 Parser.Lex();
812 if (Lexer.is(AsmToken::Integer)) {
813 parseSingleInteger(true, Operands);
814 if (checkForP2AlignIfLoadStore(Operands, Name))
815 return true;
816 } else if (Lexer.is(AsmToken::Real)) {
817 if (parseSingleFloat(true, Operands))
818 return true;
819 } else if (!parseSpecialFloatMaybe(true, Operands)) {
820 } else {
821 return error("Expected numeric constant instead got: ",
822 Lexer.getTok());
823 }
824 break;
826 parseSingleInteger(false, Operands);
827 if (checkForP2AlignIfLoadStore(Operands, Name))
828 return true;
829 break;
830 case AsmToken::Real: {
831 if (parseSingleFloat(false, Operands))
832 return true;
833 break;
834 }
835 case AsmToken::LCurly: {
836 Parser.Lex();
837 auto Op = std::make_unique<WebAssemblyOperand>(
838 Tok.getLoc(), Tok.getEndLoc(), WebAssemblyOperand::BrLOp{});
839 if (!Lexer.is(AsmToken::RCurly))
840 for (;;) {
841 Op->BrL.List.push_back(Lexer.getTok().getIntVal());
842 expect(AsmToken::Integer, "integer");
843 if (!isNext(AsmToken::Comma))
844 break;
845 }
846 expect(AsmToken::RCurly, "}");
847 Operands.push_back(std::move(Op));
848 break;
849 }
850 default:
851 return error("Unexpected token in operand: ", Tok);
852 }
853 if (Lexer.isNot(AsmToken::EndOfStatement)) {
854 if (expect(AsmToken::Comma, ","))
855 return true;
856 }
857 }
858
859 // If we are still expecting to parse a block type or a catch list at this
860 // point, we set them to the default/empty state.
861
862 // Support blocks with no operands as default to void.
863 if (ExpectBlockType)
864 addBlockTypeOperand(Operands, NameLoc, WebAssembly::BlockType::Void);
865 // If no catch list has been parsed, add an empty catch list operand.
866 if (ExpectCatchList)
867 Operands.push_back(std::make_unique<WebAssemblyOperand>(
868 NameLoc, NameLoc, WebAssemblyOperand::CaLOp{}));
869
870 if (FunctionTable)
871 Operands.push_back(std::move(FunctionTable));
872 Parser.Lex();
873 return false;
874 }
875
876 bool parseSignature(wasm::WasmSignature *Signature) {
877 if (expect(AsmToken::LParen, "("))
878 return true;
879 if (parseRegTypeList(Signature->Params))
880 return true;
881 if (expect(AsmToken::RParen, ")"))
882 return true;
883 if (expect(AsmToken::MinusGreater, "->"))
884 return true;
885 if (expect(AsmToken::LParen, "("))
886 return true;
887 if (parseRegTypeList(Signature->Returns))
888 return true;
889 if (expect(AsmToken::RParen, ")"))
890 return true;
891 return false;
892 }
893
894 bool parseCatchList(OperandVector &Operands) {
895 auto Op = std::make_unique<WebAssemblyOperand>(
896 Lexer.getTok().getLoc(), SMLoc(), WebAssemblyOperand::CaLOp{});
897 SMLoc EndLoc;
898
899 while (Lexer.is(AsmToken::LParen)) {
900 if (expect(AsmToken::LParen, "("))
901 return true;
902
903 auto CatchStr = expectIdent();
904 if (CatchStr.empty())
905 return true;
906 uint8_t CatchOpcode =
907 StringSwitch<uint8_t>(CatchStr)
908 .Case("catch", wasm::WASM_OPCODE_CATCH)
909 .Case("catch_ref", wasm::WASM_OPCODE_CATCH_REF)
910 .Case("catch_all", wasm::WASM_OPCODE_CATCH_ALL)
911 .Case("catch_all_ref", wasm::WASM_OPCODE_CATCH_ALL_REF)
912 .Default(0xff);
913 if (CatchOpcode == 0xff)
914 return error(
915 "Expected catch/catch_ref/catch_all/catch_all_ref, instead got: " +
916 CatchStr);
917
918 const MCExpr *Tag = nullptr;
919 if (CatchOpcode == wasm::WASM_OPCODE_CATCH ||
920 CatchOpcode == wasm::WASM_OPCODE_CATCH_REF) {
921 if (Parser.parseExpression(Tag))
922 return error("Cannot parse symbol: ", Lexer.getTok());
923 }
924
925 auto &DestTok = Lexer.getTok();
926 if (DestTok.isNot(AsmToken::Integer))
927 return error("Expected integer constant, instead got: ", DestTok);
928 unsigned Dest = DestTok.getIntVal();
929 Parser.Lex();
930
931 EndLoc = Lexer.getTok().getEndLoc();
932 if (expect(AsmToken::RParen, ")"))
933 return true;
934
935 Op->CaL.List.push_back({CatchOpcode, Tag, Dest});
936 }
937
938 Op->EndLoc = EndLoc;
939 Operands.push_back(std::move(Op));
940 return false;
941 }
942
943 bool checkDataSection() {
944 if (CurrentState != DataSection) {
945 auto *WS = static_cast<const MCSectionWasm *>(
946 getStreamer().getCurrentSectionOnly());
947 if (WS && WS->isText())
948 return error("data directive must occur in a data segment: ",
949 Lexer.getTok());
950 }
951 CurrentState = DataSection;
952 return false;
953 }
954
955 // This function processes wasm-specific directives streamed to
956 // WebAssemblyTargetStreamer, all others go to the generic parser
957 // (see WasmAsmParser).
958 ParseStatus parseDirective(AsmToken DirectiveID) override {
959 assert(DirectiveID.getKind() == AsmToken::Identifier);
960 auto &Out = getStreamer();
961 auto &TOut =
962 reinterpret_cast<WebAssemblyTargetStreamer &>(*Out.getTargetStreamer());
963 auto &Ctx = Out.getContext();
964
965 if (DirectiveID.getString() == ".globaltype") {
966 auto SymName = expectIdent();
967 if (SymName.empty())
969 if (expect(AsmToken::Comma, ","))
971 auto TypeTok = Lexer.getTok();
972 auto TypeName = expectIdent();
973 if (TypeName.empty())
975 auto Type = WebAssembly::parseType(TypeName);
976 if (!Type)
977 return error("Unknown type in .globaltype directive: ", TypeTok);
978 // Optional mutable modifier. Default to mutable for historical reasons.
979 // Ideally we would have gone with immutable as the default and used `mut`
980 // as the modifier to match the `.wat` format.
981 bool Mutable = true;
982 if (isNext(AsmToken::Comma)) {
983 TypeTok = Lexer.getTok();
984 auto Id = expectIdent();
985 if (Id.empty())
987 if (Id == "immutable")
988 Mutable = false;
989 else
990 // Should we also allow `mutable` and `mut` here for clarity?
991 return error("Unknown type in .globaltype modifier: ", TypeTok);
992 }
993 // Now set this symbol with the correct type.
994 auto *WasmSym =
995 static_cast<MCSymbolWasm *>(Ctx.getOrCreateSymbol(SymName));
996 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);
997 WasmSym->setGlobalType(wasm::WasmGlobalType{uint8_t(*Type), Mutable});
998 // And emit the directive again.
999 TOut.emitGlobalType(WasmSym);
1000 return expect(AsmToken::EndOfStatement, "EOL");
1001 }
1002
1003 if (DirectiveID.getString() == ".tabletype") {
1004 // .tabletype SYM, ELEMTYPE[, MINSIZE[, MAXSIZE]]
1005 auto SymName = expectIdent();
1006 if (SymName.empty())
1007 return ParseStatus::Failure;
1008 if (expect(AsmToken::Comma, ","))
1009 return ParseStatus::Failure;
1010
1011 auto ElemTypeTok = Lexer.getTok();
1012 auto ElemTypeName = expectIdent();
1013 if (ElemTypeName.empty())
1014 return ParseStatus::Failure;
1015 std::optional<wasm::ValType> ElemType =
1016 WebAssembly::parseType(ElemTypeName);
1017 if (!ElemType)
1018 return error("Unknown type in .tabletype directive: ", ElemTypeTok);
1019
1020 wasm::WasmLimits Limits = defaultLimits();
1021 if (isNext(AsmToken::Comma) && parseLimits(&Limits))
1022 return ParseStatus::Failure;
1023
1024 // Now that we have the name and table type, we can actually create the
1025 // symbol
1026 auto *WasmSym =
1027 static_cast<MCSymbolWasm *>(Ctx.getOrCreateSymbol(SymName));
1028 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_TABLE);
1029 if (Is64) {
1031 }
1032 wasm::WasmTableType Type = {*ElemType, Limits};
1033 WasmSym->setTableType(Type);
1034 TOut.emitTableType(WasmSym);
1035 return expect(AsmToken::EndOfStatement, "EOL");
1036 }
1037
1038 if (DirectiveID.getString() == ".functype") {
1039 // This code has to send things to the streamer similar to
1040 // WebAssemblyAsmPrinter::EmitFunctionBodyStart.
1041 // TODO: would be good to factor this into a common function, but the
1042 // assembler and backend really don't share any common code, and this code
1043 // parses the locals separately.
1044 auto SymName = expectIdent();
1045 if (SymName.empty())
1046 return ParseStatus::Failure;
1047 auto *WasmSym =
1048 static_cast<MCSymbolWasm *>(Ctx.getOrCreateSymbol(SymName));
1049 if (WasmSym->isDefined()) {
1050 // We push 'Function' either when a label is parsed or a .functype
1051 // directive is parsed. The reason it is not easy to do this uniformly
1052 // in a single place is,
1053 // 1. We can't do this at label parsing time only because there are
1054 // cases we don't have .functype directive before a function label,
1055 // in which case we don't know if the label is a function at the time
1056 // of parsing.
1057 // 2. We can't do this at .functype parsing time only because we want to
1058 // detect a function started with a label and not ended correctly
1059 // without encountering a .functype directive after the label.
1060 if (CurrentState != FunctionLabel) {
1061 // This .functype indicates a start of a function.
1062 if (ensureEmptyNestingStack())
1063 return ParseStatus::Failure;
1064 push(Function);
1065 }
1066 CurrentState = FunctionStart;
1067 LastFunctionLabel = WasmSym;
1068 }
1069 auto *Signature = Ctx.createWasmSignature();
1070 if (parseSignature(Signature))
1071 return ParseStatus::Failure;
1072 if (CurrentState == FunctionStart)
1073 TC.funcDecl(*Signature);
1074 WasmSym->setSignature(Signature);
1075 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
1076 TOut.emitFunctionType(WasmSym);
1077 // TODO: backend also calls TOut.emitIndIdx, but that is not implemented.
1078 return expect(AsmToken::EndOfStatement, "EOL");
1079 }
1080
1081 if (DirectiveID.getString() == ".export_name") {
1082 auto SymName = expectIdent();
1083 if (SymName.empty())
1084 return ParseStatus::Failure;
1085 if (expect(AsmToken::Comma, ","))
1086 return ParseStatus::Failure;
1087 auto ExportName = expectStringOrIdent();
1088 if (ExportName.empty())
1089 return ParseStatus::Failure;
1090 auto *WasmSym =
1091 static_cast<MCSymbolWasm *>(Ctx.getOrCreateSymbol(SymName));
1092 WasmSym->setExportName(Ctx.allocateString(ExportName));
1093 TOut.emitExportName(WasmSym, ExportName);
1094 return expect(AsmToken::EndOfStatement, "EOL");
1095 }
1096
1097 if (DirectiveID.getString() == ".import_module") {
1098 auto SymName = expectIdent();
1099 if (SymName.empty())
1100 return ParseStatus::Failure;
1101 if (expect(AsmToken::Comma, ","))
1102 return ParseStatus::Failure;
1103 auto ImportModule = expectStringOrIdent();
1104 if (ImportModule.empty())
1105 return ParseStatus::Failure;
1106 auto *WasmSym =
1107 static_cast<MCSymbolWasm *>(Ctx.getOrCreateSymbol(SymName));
1108 WasmSym->setImportModule(Ctx.allocateString(ImportModule));
1109 TOut.emitImportModule(WasmSym, ImportModule);
1110 return expect(AsmToken::EndOfStatement, "EOL");
1111 }
1112
1113 if (DirectiveID.getString() == ".import_name") {
1114 auto SymName = expectIdent();
1115 if (SymName.empty())
1116 return ParseStatus::Failure;
1117 if (expect(AsmToken::Comma, ","))
1118 return ParseStatus::Failure;
1119 StringRef ImportName = expectStringOrIdent();
1120 if (ImportName.empty())
1121 return ParseStatus::Failure;
1122 auto *WasmSym =
1123 static_cast<MCSymbolWasm *>(Ctx.getOrCreateSymbol(SymName));
1124 WasmSym->setImportName(Ctx.allocateString(ImportName));
1125 TOut.emitImportName(WasmSym, ImportName);
1126 return expect(AsmToken::EndOfStatement, "EOL");
1127 }
1128
1129 if (DirectiveID.getString() == ".tagtype") {
1130 auto SymName = expectIdent();
1131 if (SymName.empty())
1132 return ParseStatus::Failure;
1133 auto *WasmSym =
1134 static_cast<MCSymbolWasm *>(Ctx.getOrCreateSymbol(SymName));
1135 auto *Signature = Ctx.createWasmSignature();
1136 if (parseRegTypeList(Signature->Params))
1137 return ParseStatus::Failure;
1138 WasmSym->setSignature(Signature);
1139 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_TAG);
1140 TOut.emitTagType(WasmSym);
1141 // TODO: backend also calls TOut.emitIndIdx, but that is not implemented.
1142 return expect(AsmToken::EndOfStatement, "EOL");
1143 }
1144
1145 if (DirectiveID.getString() == ".local") {
1146 if (CurrentState != FunctionStart)
1147 return error(".local directive should follow the start of a function: ",
1148 Lexer.getTok());
1150 if (parseRegTypeList(Locals))
1151 return ParseStatus::Failure;
1152 TC.localDecl(Locals);
1153 TOut.emitLocal(Locals);
1154 CurrentState = FunctionLocals;
1155 return expect(AsmToken::EndOfStatement, "EOL");
1156 }
1157
1158 if (DirectiveID.getString() == ".int8" ||
1159 DirectiveID.getString() == ".int16" ||
1160 DirectiveID.getString() == ".int32" ||
1161 DirectiveID.getString() == ".int64") {
1162 if (checkDataSection())
1163 return ParseStatus::Failure;
1164 const MCExpr *Val;
1165 SMLoc End;
1166 if (Parser.parseExpression(Val, End))
1167 return error("Cannot parse .int expression: ", Lexer.getTok());
1168 size_t NumBits = 0;
1169 DirectiveID.getString().drop_front(4).getAsInteger(10, NumBits);
1170 Out.emitValue(Val, NumBits / 8, End);
1171 return expect(AsmToken::EndOfStatement, "EOL");
1172 }
1173
1174 if (DirectiveID.getString() == ".asciz") {
1175 if (checkDataSection())
1176 return ParseStatus::Failure;
1177 std::string S;
1178 if (Parser.parseEscapedString(S))
1179 return error("Cannot parse string constant: ", Lexer.getTok());
1180 Out.emitBytes(StringRef(S.c_str(), S.length() + 1));
1181 return expect(AsmToken::EndOfStatement, "EOL");
1182 }
1183
1184 return ParseStatus::NoMatch; // We didn't process this directive.
1185 }
1186
1187 // Called either when the first instruction is parsed of the function ends.
1188 void ensureLocals(MCStreamer &Out) {
1189 if (CurrentState == FunctionStart) {
1190 // We haven't seen a .local directive yet. The streamer requires locals to
1191 // be encoded as a prelude to the instructions, so emit an empty list of
1192 // locals here.
1193 auto &TOut = reinterpret_cast<WebAssemblyTargetStreamer &>(
1194 *Out.getTargetStreamer());
1195 TOut.emitLocal(SmallVector<wasm::ValType, 0>());
1196 CurrentState = FunctionLocals;
1197 }
1198 }
1199
1200 bool matchAndEmitInstruction(SMLoc IDLoc, unsigned & /*Opcode*/,
1201 OperandVector &Operands, MCStreamer &Out,
1202 uint64_t &ErrorInfo,
1203 bool MatchingInlineAsm) override {
1204 MCInst Inst;
1205 Inst.setLoc(IDLoc);
1206 FeatureBitset MissingFeatures;
1207 unsigned MatchResult = MatchInstructionImpl(
1208 Operands, Inst, ErrorInfo, MissingFeatures, MatchingInlineAsm);
1209 switch (MatchResult) {
1210 case Match_Success: {
1211 ensureLocals(Out);
1212 // Fix unknown p2align operands.
1213 const MCInstrDesc &Desc = MII.get(Inst.getOpcode());
1215 if (Align != -1U) {
1216 unsigned I = 0;
1217 // It's operand 0 for regular memory ops and 1 for atomics.
1218 for (unsigned E = Desc.getNumOperands(); I < E; ++I) {
1219 if (Desc.operands()[I].OperandType == WebAssembly::OPERAND_P2ALIGN) {
1220 auto &Op = Inst.getOperand(I);
1221 if (Op.getImm() == -1) {
1222 Op.setImm(Align);
1223 }
1224 break;
1225 }
1226 }
1227 assert(I < 2 && "Default p2align set but operand not found");
1228 }
1229 if (Is64) {
1230 // Upgrade 32-bit loads/stores to 64-bit. These mostly differ by having
1231 // an offset64 arg instead of offset32, but to the assembler matcher
1232 // they're both immediates so don't get selected for.
1233 auto Opc64 = WebAssembly::getWasm64Opcode(
1234 static_cast<uint16_t>(Inst.getOpcode()));
1235 if (Opc64 >= 0) {
1236 Inst.setOpcode(Opc64);
1237 }
1238 }
1239 if (!SkipTypeCheck)
1240 TC.typeCheck(IDLoc, Inst, Operands);
1241 Out.emitInstruction(Inst, getSTI());
1242 if (CurrentState == EndFunction) {
1243 onEndOfFunction(IDLoc);
1244 } else {
1245 CurrentState = Instructions;
1246 }
1247 return false;
1248 }
1249 case Match_MissingFeature: {
1250 assert(MissingFeatures.count() > 0 && "Expected missing features");
1251 SmallString<128> Message;
1252 raw_svector_ostream OS(Message);
1253 OS << "instruction requires:";
1254 for (unsigned I = 0, E = MissingFeatures.size(); I != E; ++I)
1255 if (MissingFeatures.test(I))
1256 OS << ' ' << getSubtargetFeatureName(I);
1257 return Parser.Error(IDLoc, Message);
1258 }
1259 case Match_MnemonicFail:
1260 return Parser.Error(IDLoc, "invalid instruction");
1261 case Match_NearMisses:
1262 return Parser.Error(IDLoc, "ambiguous instruction");
1263 case Match_InvalidTiedOperand:
1264 case Match_InvalidOperand: {
1265 SMLoc ErrorLoc = IDLoc;
1266 if (ErrorInfo != ~0ULL) {
1267 if (ErrorInfo >= Operands.size())
1268 return Parser.Error(IDLoc, "too few operands for instruction");
1269 ErrorLoc = Operands[ErrorInfo]->getStartLoc();
1270 if (ErrorLoc == SMLoc())
1271 ErrorLoc = IDLoc;
1272 }
1273 return Parser.Error(ErrorLoc, "invalid operand for instruction");
1274 }
1275 }
1276 llvm_unreachable("Implement any new match types added!");
1277 }
1278
1279 void doBeforeLabelEmit(MCSymbol *Symbol, SMLoc IDLoc) override {
1280 // Code below only applies to labels in text sections.
1281 auto *CWS = static_cast<const MCSectionWasm *>(
1282 getStreamer().getCurrentSectionOnly());
1283 if (!CWS->isText())
1284 return;
1285
1286 auto *WasmSym = static_cast<MCSymbolWasm *>(Symbol);
1287 // Unlike other targets, we don't allow data in text sections (labels
1288 // declared with .type @object).
1289 if (WasmSym->getType() == wasm::WASM_SYMBOL_TYPE_DATA) {
1290 Parser.Error(IDLoc,
1291 "Wasm doesn\'t support data symbols in text sections");
1292 return;
1293 }
1294
1295 // Start a new section for the next function automatically, since our
1296 // object writer expects each function to have its own section. This way
1297 // The user can't forget this "convention".
1298 auto SymName = Symbol->getName();
1299 if (SymName.starts_with(".L"))
1300 return; // Local Symbol.
1301
1302 // TODO: If the user explicitly creates a new function section, we ignore
1303 // its name when we create this one. It would be nice to honor their
1304 // choice, while still ensuring that we create one if they forget.
1305 // (that requires coordination with WasmAsmParser::parseSectionDirective)
1306 std::string SecName = (".text." + SymName).str();
1307
1308 auto *Group = CWS->getGroup();
1309 // If the current section is a COMDAT, also set the flag on the symbol.
1310 // TODO: Currently the only place that the symbols' comdat flag matters is
1311 // for importing comdat functions. But there's no way to specify that in
1312 // assembly currently.
1313 if (Group)
1314 WasmSym->setComdat(true);
1315 auto *WS = getContext().getWasmSection(SecName, SectionKind::getText(), 0,
1316 Group, MCSection::NonUniqueID);
1317 getStreamer().switchSection(WS);
1318 // Also generate DWARF for this section if requested.
1319 if (getContext().getGenDwarfForAssembly())
1320 getContext().addGenDwarfSection(WS);
1321
1322 if (WasmSym->isFunction()) {
1323 // We give the location of the label (IDLoc) here, because otherwise the
1324 // lexer's next location will be used, which can be confusing. For
1325 // example:
1326 //
1327 // test0: ; This function does not end properly
1328 // ...
1329 //
1330 // test1: ; We would like to point to this line for error
1331 // ... . Not this line, which can contain any instruction
1332 ensureEmptyNestingStack(IDLoc);
1333 CurrentState = FunctionLabel;
1334 LastFunctionLabel = Symbol;
1335 push(Function);
1336 }
1337 }
1338
1339 void onEndOfFunction(SMLoc ErrorLoc) {
1340 if (!SkipTypeCheck)
1341 TC.endOfFunction(ErrorLoc, true);
1342 // Reset the type checker state.
1343 TC.clear();
1344 }
1345
1346 void onEndOfFile() override { ensureEmptyNestingStack(); }
1347};
1348} // end anonymous namespace
1349
1350// Force static initialization.
1351extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void
1356
1357#define GET_REGISTER_MATCHER
1358#define GET_SUBTARGET_FEATURE_NAME
1359#define GET_MATCHER_IMPLEMENTATION
1360#include "WebAssemblyGenAsmMatcher.inc"
1361
1363 // FIXME: linear search!
1364 for (auto &ME : MatchTable0) {
1365 if (ME.Opcode == Opc) {
1366 return ME.getMnemonic();
1367 }
1368 }
1369 assert(false && "mnemonic not found");
1370 return StringRef();
1371}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
BitTracker BT
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
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
static LVOptions Options
Definition LVOptions.cpp:25
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Register Reg
#define T
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
static bool isReg(const MCInst &MI, unsigned OpNo)
static constexpr unsigned SM(unsigned Version)
#define error(X)
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
static TableGen::Emitter::OptClass< SkeletonEmitter > X("gen-skeleton-class", "Generate example skeleton class")
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.
LLVM_ABI SMLoc getLoc() const
Definition AsmLexer.cpp:31
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:33
StringRef getIdentifier() const
Get the identifier string for the current token, which should be an identifier or a string.
Definition MCAsmMacro.h:92
constexpr bool test(unsigned I) const
FeatureBitset & set()
constexpr size_t size() const
virtual void Initialize(MCAsmParser &Parser)
Initialize the extension for parsing using the given Parser.
Context object for machine code objects.
Definition MCContext.h:83
LLVM_ABI MCSymbol * createTempSymbol()
Create a temporary symbol with a unique name.
LLVM_ABI wasm::WasmSignature * createWasmSignature()
Allocates and returns a new WasmSignature instance (with empty parameter and return type lists).
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:839
LLVM_ABI MCSymbol * getOrCreateSymbol(const Twine &Name)
Lookup the symbol inside with the specified Name.
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
const MCInstrDesc & get(unsigned Opcode) const
Return the machine instruction descriptor that corresponds to the specified instruction opcode.
Definition MCInstrInfo.h:90
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.
Wrapper class representing physical registers. Should be passed by value.
Definition MCRegister.h:41
static constexpr unsigned NonUniqueID
Definition MCSection.h:521
virtual void emitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI)
Emit the given Instruction into the current section.
MCTargetStreamer * getTargetStreamer()
Definition MCStreamer.h:332
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 setFunctionTable(bool is64)
MCTargetAsmParser - Generic interface to target specific assembly parsers.
static constexpr StatusTy Failure
static constexpr StatusTy NoMatch
Represents a location in source code.
Definition SMLoc.h:22
static SMLoc getFromPointer(const char *Ptr)
Definition SMLoc.h:35
constexpr const char * getPointer() const
Definition SMLoc.h:33
static SectionKind getText()
void push_back(const T &Elt)
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:490
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
Definition StringRef.h:258
constexpr bool empty() const
empty - Check if the string is empty.
Definition StringRef.h:140
StringRef drop_front(size_t N=1) const
Return a StringRef equal to 'this' but with the first N elements dropped.
Definition StringRef.h:629
bool contains(StringRef Other) const
Return true if the given string is a substring of *this, and false otherwise.
Definition StringRef.h:446
LLVM_ABI void clear()
Clears function-level state.
Definition Context.cpp:642
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr char TypeName[]
Key for Kernel::Arg::Metadata::mTypeName.
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
int32_t getWasm64Opcode(uint32_t 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.
@ OPERAND_P2ALIGN
p2align immediate for load and store address alignment.
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)
Context & getContext() const
Definition BasicBlock.h:99
@ WASM_OPCODE_CATCH_ALL_REF
Definition Wasm.h:163
@ WASM_OPCODE_CATCH
Definition Wasm.h:160
@ WASM_OPCODE_CATCH_ALL
Definition Wasm.h:162
@ WASM_OPCODE_CATCH_REF
Definition Wasm.h:161
@ WASM_LIMITS_FLAG_HAS_MAX
Definition Wasm.h:168
@ WASM_LIMITS_FLAG_IS_64
Definition Wasm.h:170
@ WASM_LIMITS_FLAG_NONE
Definition Wasm.h:167
@ WASM_SYMBOL_TYPE_GLOBAL
Definition Wasm.h:231
@ WASM_SYMBOL_TYPE_DATA
Definition Wasm.h:230
@ WASM_SYMBOL_TYPE_TAG
Definition Wasm.h:233
@ WASM_SYMBOL_TYPE_TABLE
Definition Wasm.h:234
@ WASM_SYMBOL_TYPE_FUNCTION
Definition Wasm.h:229
@ WASM_MEM_ORDER_SEQ_CST
Definition Wasm.h:86
@ WASM_MEM_ORDER_ACQ_REL
Definition Wasm.h:87
This is an optimization pass for GlobalISel generic memory operations.
Definition Types.h:26
Printable print(const GCNRegPressure &RP, const GCNSubtarget *ST=nullptr, unsigned DynamicVGPRBlockSize=0)
static bool isMem(const MachineInstr &MI, unsigned Op)
LLVM_ABI std::pair< StringRef, StringRef > getToken(StringRef Source, StringRef Delimiters=" \t\n\v\f\r")
getToken - This function extracts one token from source, ignoring any leading characters that appear ...
Op::Description Desc
SmallVectorImpl< std::unique_ptr< MCParsedAsmOperand > > OperandVector
Target & getTheWebAssemblyTarget32()
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
Target & getTheWebAssemblyTarget64()
To bit_cast(const From &from) noexcept
Definition bit.h:90
DWARFExpression::Operation Op
@ MCSA_NoDeadStrip
.no_dead_strip (MachO)
#define N
RegisterMCAsmParser - Helper template for registering a target specific assembly parser,...
SmallVector< ValType, 1 > Returns
Definition Wasm.h:516
SmallVector< ValType, 4 > Params
Definition Wasm.h:517