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