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