1 //==- WebAssemblyAsmParser.cpp - Assembler for WebAssembly -*- C++ -*-==//
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
7 //===----------------------------------------------------------------------===//
10 /// This file is part of the WebAssembly Assembler.
12 /// It contains code to translate a parsed .s file into MCInsts.
14 //===----------------------------------------------------------------------===//
16 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
17 #include "MCTargetDesc/WebAssemblyTargetStreamer.h"
18 #include "TargetInfo/WebAssemblyTargetInfo.h"
19 #include "WebAssembly.h"
20 #include "llvm/MC/MCContext.h"
21 #include "llvm/MC/MCExpr.h"
22 #include "llvm/MC/MCInst.h"
23 #include "llvm/MC/MCInstrInfo.h"
24 #include "llvm/MC/MCParser/MCParsedAsmOperand.h"
25 #include "llvm/MC/MCParser/MCTargetAsmParser.h"
26 #include "llvm/MC/MCSectionWasm.h"
27 #include "llvm/MC/MCStreamer.h"
28 #include "llvm/MC/MCSubtargetInfo.h"
29 #include "llvm/MC/MCSymbol.h"
30 #include "llvm/MC/MCSymbolWasm.h"
31 #include "llvm/Support/Endian.h"
32 #include "llvm/Support/TargetRegistry.h"
36 #define DEBUG_TYPE "wasm-asm-parser"
40 /// WebAssemblyOperand - Instances of this class represent the operands in a
41 /// parsed WASM machine instruction.
42 struct WebAssemblyOperand
: public MCParsedAsmOperand
{
43 enum KindTy
{ Token
, Integer
, Float
, Symbol
, BrList
} Kind
;
45 SMLoc StartLoc
, EndLoc
;
64 std::vector
<unsigned> List
;
75 WebAssemblyOperand(KindTy K
, SMLoc Start
, SMLoc End
, TokOp T
)
76 : Kind(K
), StartLoc(Start
), EndLoc(End
), Tok(T
) {}
77 WebAssemblyOperand(KindTy K
, SMLoc Start
, SMLoc End
, IntOp I
)
78 : Kind(K
), StartLoc(Start
), EndLoc(End
), Int(I
) {}
79 WebAssemblyOperand(KindTy K
, SMLoc Start
, SMLoc End
, FltOp F
)
80 : Kind(K
), StartLoc(Start
), EndLoc(End
), Flt(F
) {}
81 WebAssemblyOperand(KindTy K
, SMLoc Start
, SMLoc End
, SymOp S
)
82 : Kind(K
), StartLoc(Start
), EndLoc(End
), Sym(S
) {}
83 WebAssemblyOperand(KindTy K
, SMLoc Start
, SMLoc End
)
84 : Kind(K
), StartLoc(Start
), EndLoc(End
), BrL() {}
86 ~WebAssemblyOperand() {
91 bool isToken() const override
{ return Kind
== Token
; }
92 bool isImm() const override
{ return Kind
== Integer
|| Kind
== Symbol
; }
93 bool isFPImm() const { return Kind
== Float
; }
94 bool isMem() const override
{ return false; }
95 bool isReg() const override
{ return false; }
96 bool isBrList() const { return Kind
== BrList
; }
98 unsigned getReg() const override
{
99 llvm_unreachable("Assembly inspects a register operand");
103 StringRef
getToken() const {
108 SMLoc
getStartLoc() const override
{ return StartLoc
; }
109 SMLoc
getEndLoc() const override
{ return EndLoc
; }
111 void addRegOperands(MCInst
&, unsigned) const {
112 // Required by the assembly matcher.
113 llvm_unreachable("Assembly matcher creates register operands");
116 void addImmOperands(MCInst
&Inst
, unsigned N
) const {
117 assert(N
== 1 && "Invalid number of operands!");
119 Inst
.addOperand(MCOperand::createImm(Int
.Val
));
120 else if (Kind
== Symbol
)
121 Inst
.addOperand(MCOperand::createExpr(Sym
.Exp
));
123 llvm_unreachable("Should be integer immediate or symbol!");
126 void addFPImmOperands(MCInst
&Inst
, unsigned N
) const {
127 assert(N
== 1 && "Invalid number of operands!");
129 Inst
.addOperand(MCOperand::createFPImm(Flt
.Val
));
131 llvm_unreachable("Should be float immediate!");
134 void addBrListOperands(MCInst
&Inst
, unsigned N
) const {
135 assert(N
== 1 && isBrList() && "Invalid BrList!");
136 for (auto Br
: BrL
.List
)
137 Inst
.addOperand(MCOperand::createImm(Br
));
140 void print(raw_ostream
&OS
) const override
{
143 OS
<< "Tok:" << Tok
.Tok
;
146 OS
<< "Int:" << Int
.Val
;
149 OS
<< "Flt:" << Flt
.Val
;
152 OS
<< "Sym:" << Sym
.Exp
;
155 OS
<< "BrList:" << BrL
.List
.size();
161 class WebAssemblyAsmParser final
: public MCTargetAsmParser
{
165 // Much like WebAssemblyAsmPrinter in the backend, we have to own these.
166 std::vector
<std::unique_ptr
<wasm::WasmSignature
>> Signatures
;
168 // Order of labels, directives and instructions in a .s file have no
169 // syntactical enforcement. This class is a callback from the actual parser,
170 // and yet we have to be feeding data to the streamer in a very particular
171 // order to ensure a correct binary encoding that matches the regular backend
172 // (the streamer does not enforce this). This "state machine" enum helps
173 // guarantee that correct order.
182 } CurrentState
= FileStart
;
184 // For ensuring blocks are properly nested.
194 std::vector
<NestingType
> NestingStack
;
196 // We track this to see if a .functype following a label is the same,
197 // as this is how we recognize the start of a function.
198 MCSymbol
*LastLabel
= nullptr;
199 MCSymbol
*LastFunctionLabel
= nullptr;
202 WebAssemblyAsmParser(const MCSubtargetInfo
&STI
, MCAsmParser
&Parser
,
203 const MCInstrInfo
&MII
, const MCTargetOptions
&Options
)
204 : MCTargetAsmParser(Options
, STI
, MII
), Parser(Parser
),
205 Lexer(Parser
.getLexer()) {
206 setAvailableFeatures(ComputeAvailableFeatures(STI
.getFeatureBits()));
209 #define GET_ASSEMBLER_HEADER
210 #include "WebAssemblyGenAsmMatcher.inc"
212 // TODO: This is required to be implemented, but appears unused.
213 bool ParseRegister(unsigned & /*RegNo*/, SMLoc
& /*StartLoc*/,
214 SMLoc
& /*EndLoc*/) override
{
215 llvm_unreachable("ParseRegister is not implemented.");
218 bool error(const Twine
&Msg
, const AsmToken
&Tok
) {
219 return Parser
.Error(Tok
.getLoc(), Msg
+ Tok
.getString());
222 bool error(const Twine
&Msg
) {
223 return Parser
.Error(Lexer
.getTok().getLoc(), Msg
);
226 void addSignature(std::unique_ptr
<wasm::WasmSignature
> &&Sig
) {
227 Signatures
.push_back(std::move(Sig
));
230 std::pair
<StringRef
, StringRef
> nestingString(NestingType NT
) {
233 return {"function", "end_function"};
235 return {"block", "end_block"};
237 return {"loop", "end_loop"};
239 return {"try", "end_try"};
241 return {"if", "end_if"};
243 return {"else", "end_if"};
245 llvm_unreachable("unknown NestingType");
249 void push(NestingType NT
) { NestingStack
.push_back(NT
); }
251 bool pop(StringRef Ins
, NestingType NT1
, NestingType NT2
= Undefined
) {
252 if (NestingStack
.empty())
253 return error(Twine("End of block construct with no start: ") + Ins
);
254 auto Top
= NestingStack
.back();
255 if (Top
!= NT1
&& Top
!= NT2
)
256 return error(Twine("Block construct type mismatch, expected: ") +
257 nestingString(Top
).second
+ ", instead got: " + Ins
);
258 NestingStack
.pop_back();
262 bool ensureEmptyNestingStack() {
263 auto Err
= !NestingStack
.empty();
264 while (!NestingStack
.empty()) {
265 error(Twine("Unmatched block construct(s) at function end: ") +
266 nestingString(NestingStack
.back()).first
);
267 NestingStack
.pop_back();
272 bool isNext(AsmToken::TokenKind Kind
) {
273 auto Ok
= Lexer
.is(Kind
);
279 bool expect(AsmToken::TokenKind Kind
, const char *KindName
) {
281 return error(std::string("Expected ") + KindName
+ ", instead got: ",
286 StringRef
expectIdent() {
287 if (!Lexer
.is(AsmToken::Identifier
)) {
288 error("Expected identifier, got: ", Lexer
.getTok());
291 auto Name
= Lexer
.getTok().getString();
296 Optional
<wasm::ValType
> parseType(const StringRef
&Type
) {
297 // FIXME: can't use StringSwitch because wasm::ValType doesn't have a
300 return wasm::ValType::I32
;
302 return wasm::ValType::I64
;
304 return wasm::ValType::F32
;
306 return wasm::ValType::F64
;
307 if (Type
== "v128" || Type
== "i8x16" || Type
== "i16x8" ||
308 Type
== "i32x4" || Type
== "i64x2" || Type
== "f32x4" ||
310 return wasm::ValType::V128
;
311 if (Type
== "exnref")
312 return wasm::ValType::EXNREF
;
313 return Optional
<wasm::ValType
>();
316 WebAssembly::ExprType
parseBlockType(StringRef ID
) {
317 return StringSwitch
<WebAssembly::ExprType
>(ID
)
318 .Case("i32", WebAssembly::ExprType::I32
)
319 .Case("i64", WebAssembly::ExprType::I64
)
320 .Case("f32", WebAssembly::ExprType::F32
)
321 .Case("f64", WebAssembly::ExprType::F64
)
322 .Case("v128", WebAssembly::ExprType::V128
)
323 .Case("exnref", WebAssembly::ExprType::Exnref
)
324 .Case("void", WebAssembly::ExprType::Void
)
325 .Default(WebAssembly::ExprType::Invalid
);
328 bool parseRegTypeList(SmallVectorImpl
<wasm::ValType
> &Types
) {
329 while (Lexer
.is(AsmToken::Identifier
)) {
330 auto Type
= parseType(Lexer
.getTok().getString());
332 return error("unknown type: ", Lexer
.getTok());
333 Types
.push_back(Type
.getValue());
335 if (!isNext(AsmToken::Comma
))
341 void parseSingleInteger(bool IsNegative
, OperandVector
&Operands
) {
342 auto &Int
= Lexer
.getTok();
343 int64_t Val
= Int
.getIntVal();
346 Operands
.push_back(std::make_unique
<WebAssemblyOperand
>(
347 WebAssemblyOperand::Integer
, Int
.getLoc(), Int
.getEndLoc(),
348 WebAssemblyOperand::IntOp
{Val
}));
352 bool parseSingleFloat(bool IsNegative
, OperandVector
&Operands
) {
353 auto &Flt
= Lexer
.getTok();
355 if (Flt
.getString().getAsDouble(Val
, false))
356 return error("Cannot parse real: ", Flt
);
359 Operands
.push_back(std::make_unique
<WebAssemblyOperand
>(
360 WebAssemblyOperand::Float
, Flt
.getLoc(), Flt
.getEndLoc(),
361 WebAssemblyOperand::FltOp
{Val
}));
366 bool parseSpecialFloatMaybe(bool IsNegative
, OperandVector
&Operands
) {
367 if (Lexer
.isNot(AsmToken::Identifier
))
369 auto &Flt
= Lexer
.getTok();
370 auto S
= Flt
.getString();
372 if (S
.compare_lower("infinity") == 0) {
373 Val
= std::numeric_limits
<double>::infinity();
374 } else if (S
.compare_lower("nan") == 0) {
375 Val
= std::numeric_limits
<double>::quiet_NaN();
381 Operands
.push_back(std::make_unique
<WebAssemblyOperand
>(
382 WebAssemblyOperand::Float
, Flt
.getLoc(), Flt
.getEndLoc(),
383 WebAssemblyOperand::FltOp
{Val
}));
388 bool checkForP2AlignIfLoadStore(OperandVector
&Operands
, StringRef InstName
) {
389 // FIXME: there is probably a cleaner way to do this.
390 auto IsLoadStore
= InstName
.find(".load") != StringRef::npos
||
391 InstName
.find(".store") != StringRef::npos
;
392 auto IsAtomic
= InstName
.find("atomic.") != StringRef::npos
;
393 if (IsLoadStore
|| IsAtomic
) {
394 // Parse load/store operands of the form: offset:p2align=align
395 if (IsLoadStore
&& isNext(AsmToken::Colon
)) {
396 auto Id
= expectIdent();
398 return error("Expected p2align, instead got: " + Id
);
399 if (expect(AsmToken::Equal
, "="))
401 if (!Lexer
.is(AsmToken::Integer
))
402 return error("Expected integer constant");
403 parseSingleInteger(false, Operands
);
405 // Alignment not specified (or atomics, must use default alignment).
406 // We can't just call WebAssembly::GetDefaultP2Align since we don't have
407 // an opcode until after the assembly matcher, so set a default to fix
409 auto Tok
= Lexer
.getTok();
410 Operands
.push_back(std::make_unique
<WebAssemblyOperand
>(
411 WebAssemblyOperand::Integer
, Tok
.getLoc(), Tok
.getEndLoc(),
412 WebAssemblyOperand::IntOp
{-1}));
418 void addBlockTypeOperand(OperandVector
&Operands
, SMLoc NameLoc
,
419 WebAssembly::ExprType BT
) {
420 Operands
.push_back(std::make_unique
<WebAssemblyOperand
>(
421 WebAssemblyOperand::Integer
, NameLoc
, NameLoc
,
422 WebAssemblyOperand::IntOp
{static_cast<int64_t>(BT
)}));
425 bool ParseInstruction(ParseInstructionInfo
& /*Info*/, StringRef Name
,
426 SMLoc NameLoc
, OperandVector
&Operands
) override
{
427 // Note: Name does NOT point into the sourcecode, but to a local, so
428 // use NameLoc instead.
429 Name
= StringRef(NameLoc
.getPointer(), Name
.size());
431 // WebAssembly has instructions with / in them, which AsmLexer parses
432 // as seperate tokens, so if we find such tokens immediately adjacent (no
433 // whitespace), expand the name to include them:
435 auto &Sep
= Lexer
.getTok();
436 if (Sep
.getLoc().getPointer() != Name
.end() ||
437 Sep
.getKind() != AsmToken::Slash
)
439 // Extend name with /
440 Name
= StringRef(Name
.begin(), Name
.size() + Sep
.getString().size());
442 // We must now find another identifier, or error.
443 auto &Id
= Lexer
.getTok();
444 if (Id
.getKind() != AsmToken::Identifier
||
445 Id
.getLoc().getPointer() != Name
.end())
446 return error("Incomplete instruction name: ", Id
);
447 Name
= StringRef(Name
.begin(), Name
.size() + Id
.getString().size());
451 // Now construct the name as first operand.
452 Operands
.push_back(std::make_unique
<WebAssemblyOperand
>(
453 WebAssemblyOperand::Token
, NameLoc
, SMLoc::getFromPointer(Name
.end()),
454 WebAssemblyOperand::TokOp
{Name
}));
456 // If this instruction is part of a control flow structure, ensure
458 bool ExpectBlockType
= false;
459 if (Name
== "block") {
461 ExpectBlockType
= true;
462 } else if (Name
== "loop") {
464 ExpectBlockType
= true;
465 } else if (Name
== "try") {
467 ExpectBlockType
= true;
468 } else if (Name
== "if") {
470 ExpectBlockType
= true;
471 } else if (Name
== "else") {
475 } else if (Name
== "catch") {
479 } else if (Name
== "end_if") {
480 if (pop(Name
, If
, Else
))
482 } else if (Name
== "end_try") {
485 } else if (Name
== "end_loop") {
488 } else if (Name
== "end_block") {
489 if (pop(Name
, Block
))
491 } else if (Name
== "end_function") {
492 ensureLocals(getStreamer());
493 CurrentState
= EndFunction
;
494 if (pop(Name
, Function
) || ensureEmptyNestingStack())
496 } else if (Name
== "call_indirect" || Name
== "return_call_indirect") {
497 // This has a special TYPEINDEX operand which in text we
498 // represent as a signature, such that we can re-build this signature,
499 // attach it to an anonymous symbol, which is what WasmObjectWriter
500 // expects to be able to recreate the actual unique-ified type indices.
501 auto Loc
= Parser
.getTok();
502 auto Signature
= std::make_unique
<wasm::WasmSignature
>();
503 if (parseSignature(Signature
.get()))
505 auto &Ctx
= getStreamer().getContext();
506 // The "true" here will cause this to be a nameless symbol.
507 MCSymbol
*Sym
= Ctx
.createTempSymbol("typeindex", true);
508 auto *WasmSym
= cast
<MCSymbolWasm
>(Sym
);
509 WasmSym
->setSignature(Signature
.get());
510 addSignature(std::move(Signature
));
511 WasmSym
->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION
);
512 const MCExpr
*Expr
= MCSymbolRefExpr::create(
513 WasmSym
, MCSymbolRefExpr::VK_WASM_TYPEINDEX
, Ctx
);
514 Operands
.push_back(std::make_unique
<WebAssemblyOperand
>(
515 WebAssemblyOperand::Symbol
, Loc
.getLoc(), Loc
.getEndLoc(),
516 WebAssemblyOperand::SymOp
{Expr
}));
519 while (Lexer
.isNot(AsmToken::EndOfStatement
)) {
520 auto &Tok
= Lexer
.getTok();
521 switch (Tok
.getKind()) {
522 case AsmToken::Identifier
: {
523 if (!parseSpecialFloatMaybe(false, Operands
))
525 auto &Id
= Lexer
.getTok();
526 if (ExpectBlockType
) {
527 // Assume this identifier is a block_type.
528 auto BT
= parseBlockType(Id
.getString());
529 if (BT
== WebAssembly::ExprType::Invalid
)
530 return error("Unknown block type: ", Id
);
531 addBlockTypeOperand(Operands
, NameLoc
, BT
);
534 // Assume this identifier is a label.
537 if (Parser
.parseExpression(Val
, End
))
538 return error("Cannot parse symbol: ", Lexer
.getTok());
539 Operands
.push_back(std::make_unique
<WebAssemblyOperand
>(
540 WebAssemblyOperand::Symbol
, Id
.getLoc(), Id
.getEndLoc(),
541 WebAssemblyOperand::SymOp
{Val
}));
542 if (checkForP2AlignIfLoadStore(Operands
, Name
))
547 case AsmToken::Minus
:
549 if (Lexer
.is(AsmToken::Integer
)) {
550 parseSingleInteger(true, Operands
);
551 if (checkForP2AlignIfLoadStore(Operands
, Name
))
553 } else if(Lexer
.is(AsmToken::Real
)) {
554 if (parseSingleFloat(true, Operands
))
556 } else if (!parseSpecialFloatMaybe(true, Operands
)) {
558 return error("Expected numeric constant instead got: ",
562 case AsmToken::Integer
:
563 parseSingleInteger(false, Operands
);
564 if (checkForP2AlignIfLoadStore(Operands
, Name
))
567 case AsmToken::Real
: {
568 if (parseSingleFloat(false, Operands
))
572 case AsmToken::LCurly
: {
574 auto Op
= std::make_unique
<WebAssemblyOperand
>(
575 WebAssemblyOperand::BrList
, Tok
.getLoc(), Tok
.getEndLoc());
576 if (!Lexer
.is(AsmToken::RCurly
))
578 Op
->BrL
.List
.push_back(Lexer
.getTok().getIntVal());
579 expect(AsmToken::Integer
, "integer");
580 if (!isNext(AsmToken::Comma
))
583 expect(AsmToken::RCurly
, "}");
584 Operands
.push_back(std::move(Op
));
588 return error("Unexpected token in operand: ", Tok
);
590 if (Lexer
.isNot(AsmToken::EndOfStatement
)) {
591 if (expect(AsmToken::Comma
, ","))
595 if (ExpectBlockType
&& Operands
.size() == 1) {
596 // Support blocks with no operands as default to void.
597 addBlockTypeOperand(Operands
, NameLoc
, WebAssembly::ExprType::Void
);
603 void onLabelParsed(MCSymbol
*Symbol
) override
{
605 CurrentState
= Label
;
608 bool parseSignature(wasm::WasmSignature
*Signature
) {
609 if (expect(AsmToken::LParen
, "("))
611 if (parseRegTypeList(Signature
->Params
))
613 if (expect(AsmToken::RParen
, ")"))
615 if (expect(AsmToken::MinusGreater
, "->"))
617 if (expect(AsmToken::LParen
, "("))
619 if (parseRegTypeList(Signature
->Returns
))
621 if (expect(AsmToken::RParen
, ")"))
626 bool CheckDataSection() {
627 if (CurrentState
!= DataSection
) {
628 auto WS
= cast
<MCSectionWasm
>(getStreamer().getCurrentSection().first
);
629 if (WS
&& WS
->getKind().isText())
630 return error("data directive must occur in a data segment: ",
633 CurrentState
= DataSection
;
637 // This function processes wasm-specific directives streamed to
638 // WebAssemblyTargetStreamer, all others go to the generic parser
639 // (see WasmAsmParser).
640 bool ParseDirective(AsmToken DirectiveID
) override
{
641 // This function has a really weird return value behavior that is different
642 // from all the other parsing functions:
643 // - return true && no tokens consumed -> don't know this directive / let
644 // the generic parser handle it.
645 // - return true && tokens consumed -> a parsing error occurred.
646 // - return false -> processed this directive successfully.
647 assert(DirectiveID
.getKind() == AsmToken::Identifier
);
648 auto &Out
= getStreamer();
650 reinterpret_cast<WebAssemblyTargetStreamer
&>(*Out
.getTargetStreamer());
651 auto &Ctx
= Out
.getContext();
653 // TODO: any time we return an error, at least one token must have been
654 // consumed, otherwise this will not signal an error to the caller.
655 if (DirectiveID
.getString() == ".globaltype") {
656 auto SymName
= expectIdent();
659 if (expect(AsmToken::Comma
, ","))
661 auto TypeTok
= Lexer
.getTok();
662 auto TypeName
= expectIdent();
663 if (TypeName
.empty())
665 auto Type
= parseType(TypeName
);
667 return error("Unknown type in .globaltype directive: ", TypeTok
);
668 // Now set this symbol with the correct type.
669 auto WasmSym
= cast
<MCSymbolWasm
>(Ctx
.getOrCreateSymbol(SymName
));
670 WasmSym
->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL
);
671 WasmSym
->setGlobalType(
672 wasm::WasmGlobalType
{uint8_t(Type
.getValue()), true});
673 // And emit the directive again.
674 TOut
.emitGlobalType(WasmSym
);
675 return expect(AsmToken::EndOfStatement
, "EOL");
678 if (DirectiveID
.getString() == ".functype") {
679 // This code has to send things to the streamer similar to
680 // WebAssemblyAsmPrinter::EmitFunctionBodyStart.
681 // TODO: would be good to factor this into a common function, but the
682 // assembler and backend really don't share any common code, and this code
683 // parses the locals seperately.
684 auto SymName
= expectIdent();
687 auto WasmSym
= cast
<MCSymbolWasm
>(Ctx
.getOrCreateSymbol(SymName
));
688 if (CurrentState
== Label
&& WasmSym
== LastLabel
) {
689 // This .functype indicates a start of a function.
690 if (ensureEmptyNestingStack())
692 CurrentState
= FunctionStart
;
693 LastFunctionLabel
= LastLabel
;
696 auto Signature
= std::make_unique
<wasm::WasmSignature
>();
697 if (parseSignature(Signature
.get()))
699 WasmSym
->setSignature(Signature
.get());
700 addSignature(std::move(Signature
));
701 WasmSym
->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION
);
702 TOut
.emitFunctionType(WasmSym
);
703 // TODO: backend also calls TOut.emitIndIdx, but that is not implemented.
704 return expect(AsmToken::EndOfStatement
, "EOL");
707 if (DirectiveID
.getString() == ".eventtype") {
708 auto SymName
= expectIdent();
711 auto WasmSym
= cast
<MCSymbolWasm
>(Ctx
.getOrCreateSymbol(SymName
));
712 auto Signature
= std::make_unique
<wasm::WasmSignature
>();
713 if (parseRegTypeList(Signature
->Params
))
715 WasmSym
->setSignature(Signature
.get());
716 addSignature(std::move(Signature
));
717 WasmSym
->setType(wasm::WASM_SYMBOL_TYPE_EVENT
);
718 TOut
.emitEventType(WasmSym
);
719 // TODO: backend also calls TOut.emitIndIdx, but that is not implemented.
720 return expect(AsmToken::EndOfStatement
, "EOL");
723 if (DirectiveID
.getString() == ".local") {
724 if (CurrentState
!= FunctionStart
)
725 return error(".local directive should follow the start of a function",
727 SmallVector
<wasm::ValType
, 4> Locals
;
728 if (parseRegTypeList(Locals
))
730 TOut
.emitLocal(Locals
);
731 CurrentState
= FunctionLocals
;
732 return expect(AsmToken::EndOfStatement
, "EOL");
735 if (DirectiveID
.getString() == ".int8" ||
736 DirectiveID
.getString() == ".int16" ||
737 DirectiveID
.getString() == ".int32" ||
738 DirectiveID
.getString() == ".int64") {
739 if (CheckDataSection()) return true;
742 if (Parser
.parseExpression(Val
, End
))
743 return error("Cannot parse .int expression: ", Lexer
.getTok());
745 DirectiveID
.getString().drop_front(4).getAsInteger(10, NumBits
);
746 Out
.EmitValue(Val
, NumBits
/ 8, End
);
747 return expect(AsmToken::EndOfStatement
, "EOL");
750 if (DirectiveID
.getString() == ".asciz") {
751 if (CheckDataSection()) return true;
753 if (Parser
.parseEscapedString(S
))
754 return error("Cannot parse string constant: ", Lexer
.getTok());
755 Out
.EmitBytes(StringRef(S
.c_str(), S
.length() + 1));
756 return expect(AsmToken::EndOfStatement
, "EOL");
759 return true; // We didn't process this directive.
762 // Called either when the first instruction is parsed of the function ends.
763 void ensureLocals(MCStreamer
&Out
) {
764 if (CurrentState
== FunctionStart
) {
765 // We haven't seen a .local directive yet. The streamer requires locals to
766 // be encoded as a prelude to the instructions, so emit an empty list of
768 auto &TOut
= reinterpret_cast<WebAssemblyTargetStreamer
&>(
769 *Out
.getTargetStreamer());
770 TOut
.emitLocal(SmallVector
<wasm::ValType
, 0>());
771 CurrentState
= FunctionLocals
;
775 bool MatchAndEmitInstruction(SMLoc IDLoc
, unsigned & /*Opcode*/,
776 OperandVector
&Operands
, MCStreamer
&Out
,
778 bool MatchingInlineAsm
) override
{
781 unsigned MatchResult
=
782 MatchInstructionImpl(Operands
, Inst
, ErrorInfo
, MatchingInlineAsm
);
783 switch (MatchResult
) {
784 case Match_Success
: {
786 // Fix unknown p2align operands.
787 auto Align
= WebAssembly::GetDefaultP2AlignAny(Inst
.getOpcode());
789 auto &Op0
= Inst
.getOperand(0);
790 if (Op0
.getImm() == -1)
793 Out
.EmitInstruction(Inst
, getSTI());
794 if (CurrentState
== EndFunction
) {
797 CurrentState
= Instructions
;
801 case Match_MissingFeature
:
803 IDLoc
, "instruction requires a WASM feature not currently enabled");
804 case Match_MnemonicFail
:
805 return Parser
.Error(IDLoc
, "invalid instruction");
806 case Match_NearMisses
:
807 return Parser
.Error(IDLoc
, "ambiguous instruction");
808 case Match_InvalidTiedOperand
:
809 case Match_InvalidOperand
: {
810 SMLoc ErrorLoc
= IDLoc
;
811 if (ErrorInfo
!= ~0ULL) {
812 if (ErrorInfo
>= Operands
.size())
813 return Parser
.Error(IDLoc
, "too few operands for instruction");
814 ErrorLoc
= Operands
[ErrorInfo
]->getStartLoc();
815 if (ErrorLoc
== SMLoc())
818 return Parser
.Error(ErrorLoc
, "invalid operand for instruction");
821 llvm_unreachable("Implement any new match types added!");
824 void doBeforeLabelEmit(MCSymbol
*Symbol
) override
{
825 // Start a new section for the next function automatically, since our
826 // object writer expects each function to have its own section. This way
827 // The user can't forget this "convention".
828 auto SymName
= Symbol
->getName();
829 if (SymName
.startswith(".L"))
830 return; // Local Symbol.
831 // Only create a new text section if we're already in one.
832 auto CWS
= cast
<MCSectionWasm
>(getStreamer().getCurrentSection().first
);
833 if (!CWS
|| !CWS
->getKind().isText())
835 auto SecName
= ".text." + SymName
;
836 auto WS
= getContext().getWasmSection(SecName
, SectionKind::getText());
837 getStreamer().SwitchSection(WS
);
840 void onEndOfFunction() {
841 // Automatically output a .size directive, so it becomes optional for the
843 if (!LastFunctionLabel
) return;
844 auto TempSym
= getContext().createLinkerPrivateTempSymbol();
845 getStreamer().EmitLabel(TempSym
);
846 auto Start
= MCSymbolRefExpr::create(LastFunctionLabel
, getContext());
847 auto End
= MCSymbolRefExpr::create(TempSym
, getContext());
849 MCBinaryExpr::create(MCBinaryExpr::Sub
, End
, Start
, getContext());
850 getStreamer().emitELFSize(LastFunctionLabel
, Expr
);
853 void onEndOfFile() override
{ ensureEmptyNestingStack(); }
855 } // end anonymous namespace
857 // Force static initialization.
858 extern "C" void LLVMInitializeWebAssemblyAsmParser() {
859 RegisterMCAsmParser
<WebAssemblyAsmParser
> X(getTheWebAssemblyTarget32());
860 RegisterMCAsmParser
<WebAssemblyAsmParser
> Y(getTheWebAssemblyTarget64());
863 #define GET_REGISTER_MATCHER
864 #define GET_MATCHER_IMPLEMENTATION
865 #include "WebAssemblyGenAsmMatcher.inc"