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::BlockType
parseBlockType(StringRef ID
) {
317 // Multivalue block types are handled separately in parseSignature
318 return StringSwitch
<WebAssembly::BlockType
>(ID
)
319 .Case("i32", WebAssembly::BlockType::I32
)
320 .Case("i64", WebAssembly::BlockType::I64
)
321 .Case("f32", WebAssembly::BlockType::F32
)
322 .Case("f64", WebAssembly::BlockType::F64
)
323 .Case("v128", WebAssembly::BlockType::V128
)
324 .Case("exnref", WebAssembly::BlockType::Exnref
)
325 .Case("void", WebAssembly::BlockType::Void
)
326 .Default(WebAssembly::BlockType::Invalid
);
329 bool parseRegTypeList(SmallVectorImpl
<wasm::ValType
> &Types
) {
330 while (Lexer
.is(AsmToken::Identifier
)) {
331 auto Type
= parseType(Lexer
.getTok().getString());
333 return error("unknown type: ", Lexer
.getTok());
334 Types
.push_back(Type
.getValue());
336 if (!isNext(AsmToken::Comma
))
342 void parseSingleInteger(bool IsNegative
, OperandVector
&Operands
) {
343 auto &Int
= Lexer
.getTok();
344 int64_t Val
= Int
.getIntVal();
347 Operands
.push_back(std::make_unique
<WebAssemblyOperand
>(
348 WebAssemblyOperand::Integer
, Int
.getLoc(), Int
.getEndLoc(),
349 WebAssemblyOperand::IntOp
{Val
}));
353 bool parseSingleFloat(bool IsNegative
, OperandVector
&Operands
) {
354 auto &Flt
= Lexer
.getTok();
356 if (Flt
.getString().getAsDouble(Val
, false))
357 return error("Cannot parse real: ", Flt
);
360 Operands
.push_back(std::make_unique
<WebAssemblyOperand
>(
361 WebAssemblyOperand::Float
, Flt
.getLoc(), Flt
.getEndLoc(),
362 WebAssemblyOperand::FltOp
{Val
}));
367 bool parseSpecialFloatMaybe(bool IsNegative
, OperandVector
&Operands
) {
368 if (Lexer
.isNot(AsmToken::Identifier
))
370 auto &Flt
= Lexer
.getTok();
371 auto S
= Flt
.getString();
373 if (S
.compare_lower("infinity") == 0) {
374 Val
= std::numeric_limits
<double>::infinity();
375 } else if (S
.compare_lower("nan") == 0) {
376 Val
= std::numeric_limits
<double>::quiet_NaN();
382 Operands
.push_back(std::make_unique
<WebAssemblyOperand
>(
383 WebAssemblyOperand::Float
, Flt
.getLoc(), Flt
.getEndLoc(),
384 WebAssemblyOperand::FltOp
{Val
}));
389 bool checkForP2AlignIfLoadStore(OperandVector
&Operands
, StringRef InstName
) {
390 // FIXME: there is probably a cleaner way to do this.
391 auto IsLoadStore
= InstName
.find(".load") != StringRef::npos
||
392 InstName
.find(".store") != StringRef::npos
;
393 auto IsAtomic
= InstName
.find("atomic.") != StringRef::npos
;
394 if (IsLoadStore
|| IsAtomic
) {
395 // Parse load/store operands of the form: offset:p2align=align
396 if (IsLoadStore
&& isNext(AsmToken::Colon
)) {
397 auto Id
= expectIdent();
399 return error("Expected p2align, instead got: " + Id
);
400 if (expect(AsmToken::Equal
, "="))
402 if (!Lexer
.is(AsmToken::Integer
))
403 return error("Expected integer constant");
404 parseSingleInteger(false, Operands
);
406 // Alignment not specified (or atomics, must use default alignment).
407 // We can't just call WebAssembly::GetDefaultP2Align since we don't have
408 // an opcode until after the assembly matcher, so set a default to fix
410 auto Tok
= Lexer
.getTok();
411 Operands
.push_back(std::make_unique
<WebAssemblyOperand
>(
412 WebAssemblyOperand::Integer
, Tok
.getLoc(), Tok
.getEndLoc(),
413 WebAssemblyOperand::IntOp
{-1}));
419 void addBlockTypeOperand(OperandVector
&Operands
, SMLoc NameLoc
,
420 WebAssembly::BlockType BT
) {
421 Operands
.push_back(std::make_unique
<WebAssemblyOperand
>(
422 WebAssemblyOperand::Integer
, NameLoc
, NameLoc
,
423 WebAssemblyOperand::IntOp
{static_cast<int64_t>(BT
)}));
426 bool ParseInstruction(ParseInstructionInfo
& /*Info*/, StringRef Name
,
427 SMLoc NameLoc
, OperandVector
&Operands
) override
{
428 // Note: Name does NOT point into the sourcecode, but to a local, so
429 // use NameLoc instead.
430 Name
= StringRef(NameLoc
.getPointer(), Name
.size());
432 // WebAssembly has instructions with / in them, which AsmLexer parses
433 // as seperate tokens, so if we find such tokens immediately adjacent (no
434 // whitespace), expand the name to include them:
436 auto &Sep
= Lexer
.getTok();
437 if (Sep
.getLoc().getPointer() != Name
.end() ||
438 Sep
.getKind() != AsmToken::Slash
)
440 // Extend name with /
441 Name
= StringRef(Name
.begin(), Name
.size() + Sep
.getString().size());
443 // We must now find another identifier, or error.
444 auto &Id
= Lexer
.getTok();
445 if (Id
.getKind() != AsmToken::Identifier
||
446 Id
.getLoc().getPointer() != Name
.end())
447 return error("Incomplete instruction name: ", Id
);
448 Name
= StringRef(Name
.begin(), Name
.size() + Id
.getString().size());
452 // Now construct the name as first operand.
453 Operands
.push_back(std::make_unique
<WebAssemblyOperand
>(
454 WebAssemblyOperand::Token
, NameLoc
, SMLoc::getFromPointer(Name
.end()),
455 WebAssemblyOperand::TokOp
{Name
}));
457 // If this instruction is part of a control flow structure, ensure
459 bool ExpectBlockType
= false;
460 bool ExpectFuncType
= false;
461 if (Name
== "block") {
463 ExpectBlockType
= true;
464 } else if (Name
== "loop") {
466 ExpectBlockType
= true;
467 } else if (Name
== "try") {
469 ExpectBlockType
= true;
470 } else if (Name
== "if") {
472 ExpectBlockType
= true;
473 } else if (Name
== "else") {
477 } else if (Name
== "catch") {
481 } else if (Name
== "end_if") {
482 if (pop(Name
, If
, Else
))
484 } else if (Name
== "end_try") {
487 } else if (Name
== "end_loop") {
490 } else if (Name
== "end_block") {
491 if (pop(Name
, Block
))
493 } else if (Name
== "end_function") {
494 ensureLocals(getStreamer());
495 CurrentState
= EndFunction
;
496 if (pop(Name
, Function
) || ensureEmptyNestingStack())
498 } else if (Name
== "call_indirect" || Name
== "return_call_indirect") {
499 ExpectFuncType
= true;
502 if (ExpectFuncType
|| (ExpectBlockType
&& Lexer
.is(AsmToken::LParen
))) {
503 // This has a special TYPEINDEX operand which in text we
504 // represent as a signature, such that we can re-build this signature,
505 // attach it to an anonymous symbol, which is what WasmObjectWriter
506 // expects to be able to recreate the actual unique-ified type indices.
507 auto Loc
= Parser
.getTok();
508 auto Signature
= std::make_unique
<wasm::WasmSignature
>();
509 if (parseSignature(Signature
.get()))
511 // Got signature as block type, don't need more
512 ExpectBlockType
= false;
513 auto &Ctx
= getStreamer().getContext();
514 // The "true" here will cause this to be a nameless symbol.
515 MCSymbol
*Sym
= Ctx
.createTempSymbol("typeindex", true);
516 auto *WasmSym
= cast
<MCSymbolWasm
>(Sym
);
517 WasmSym
->setSignature(Signature
.get());
518 addSignature(std::move(Signature
));
519 WasmSym
->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION
);
520 const MCExpr
*Expr
= MCSymbolRefExpr::create(
521 WasmSym
, MCSymbolRefExpr::VK_WASM_TYPEINDEX
, Ctx
);
522 Operands
.push_back(std::make_unique
<WebAssemblyOperand
>(
523 WebAssemblyOperand::Symbol
, Loc
.getLoc(), Loc
.getEndLoc(),
524 WebAssemblyOperand::SymOp
{Expr
}));
527 while (Lexer
.isNot(AsmToken::EndOfStatement
)) {
528 auto &Tok
= Lexer
.getTok();
529 switch (Tok
.getKind()) {
530 case AsmToken::Identifier
: {
531 if (!parseSpecialFloatMaybe(false, Operands
))
533 auto &Id
= Lexer
.getTok();
534 if (ExpectBlockType
) {
535 // Assume this identifier is a block_type.
536 auto BT
= parseBlockType(Id
.getString());
537 if (BT
== WebAssembly::BlockType::Invalid
)
538 return error("Unknown block type: ", Id
);
539 addBlockTypeOperand(Operands
, NameLoc
, BT
);
542 // Assume this identifier is a label.
545 if (Parser
.parseExpression(Val
, End
))
546 return error("Cannot parse symbol: ", Lexer
.getTok());
547 Operands
.push_back(std::make_unique
<WebAssemblyOperand
>(
548 WebAssemblyOperand::Symbol
, Id
.getLoc(), Id
.getEndLoc(),
549 WebAssemblyOperand::SymOp
{Val
}));
550 if (checkForP2AlignIfLoadStore(Operands
, Name
))
555 case AsmToken::Minus
:
557 if (Lexer
.is(AsmToken::Integer
)) {
558 parseSingleInteger(true, Operands
);
559 if (checkForP2AlignIfLoadStore(Operands
, Name
))
561 } else if(Lexer
.is(AsmToken::Real
)) {
562 if (parseSingleFloat(true, Operands
))
564 } else if (!parseSpecialFloatMaybe(true, Operands
)) {
566 return error("Expected numeric constant instead got: ",
570 case AsmToken::Integer
:
571 parseSingleInteger(false, Operands
);
572 if (checkForP2AlignIfLoadStore(Operands
, Name
))
575 case AsmToken::Real
: {
576 if (parseSingleFloat(false, Operands
))
580 case AsmToken::LCurly
: {
582 auto Op
= std::make_unique
<WebAssemblyOperand
>(
583 WebAssemblyOperand::BrList
, Tok
.getLoc(), Tok
.getEndLoc());
584 if (!Lexer
.is(AsmToken::RCurly
))
586 Op
->BrL
.List
.push_back(Lexer
.getTok().getIntVal());
587 expect(AsmToken::Integer
, "integer");
588 if (!isNext(AsmToken::Comma
))
591 expect(AsmToken::RCurly
, "}");
592 Operands
.push_back(std::move(Op
));
596 return error("Unexpected token in operand: ", Tok
);
598 if (Lexer
.isNot(AsmToken::EndOfStatement
)) {
599 if (expect(AsmToken::Comma
, ","))
603 if (ExpectBlockType
&& Operands
.size() == 1) {
604 // Support blocks with no operands as default to void.
605 addBlockTypeOperand(Operands
, NameLoc
, WebAssembly::BlockType::Void
);
611 void onLabelParsed(MCSymbol
*Symbol
) override
{
613 CurrentState
= Label
;
616 bool parseSignature(wasm::WasmSignature
*Signature
) {
617 if (expect(AsmToken::LParen
, "("))
619 if (parseRegTypeList(Signature
->Params
))
621 if (expect(AsmToken::RParen
, ")"))
623 if (expect(AsmToken::MinusGreater
, "->"))
625 if (expect(AsmToken::LParen
, "("))
627 if (parseRegTypeList(Signature
->Returns
))
629 if (expect(AsmToken::RParen
, ")"))
634 bool CheckDataSection() {
635 if (CurrentState
!= DataSection
) {
636 auto WS
= cast
<MCSectionWasm
>(getStreamer().getCurrentSection().first
);
637 if (WS
&& WS
->getKind().isText())
638 return error("data directive must occur in a data segment: ",
641 CurrentState
= DataSection
;
645 // This function processes wasm-specific directives streamed to
646 // WebAssemblyTargetStreamer, all others go to the generic parser
647 // (see WasmAsmParser).
648 bool ParseDirective(AsmToken DirectiveID
) override
{
649 // This function has a really weird return value behavior that is different
650 // from all the other parsing functions:
651 // - return true && no tokens consumed -> don't know this directive / let
652 // the generic parser handle it.
653 // - return true && tokens consumed -> a parsing error occurred.
654 // - return false -> processed this directive successfully.
655 assert(DirectiveID
.getKind() == AsmToken::Identifier
);
656 auto &Out
= getStreamer();
658 reinterpret_cast<WebAssemblyTargetStreamer
&>(*Out
.getTargetStreamer());
659 auto &Ctx
= Out
.getContext();
661 // TODO: any time we return an error, at least one token must have been
662 // consumed, otherwise this will not signal an error to the caller.
663 if (DirectiveID
.getString() == ".globaltype") {
664 auto SymName
= expectIdent();
667 if (expect(AsmToken::Comma
, ","))
669 auto TypeTok
= Lexer
.getTok();
670 auto TypeName
= expectIdent();
671 if (TypeName
.empty())
673 auto Type
= parseType(TypeName
);
675 return error("Unknown type in .globaltype directive: ", TypeTok
);
676 // Now set this symbol with the correct type.
677 auto WasmSym
= cast
<MCSymbolWasm
>(Ctx
.getOrCreateSymbol(SymName
));
678 WasmSym
->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL
);
679 WasmSym
->setGlobalType(
680 wasm::WasmGlobalType
{uint8_t(Type
.getValue()), true});
681 // And emit the directive again.
682 TOut
.emitGlobalType(WasmSym
);
683 return expect(AsmToken::EndOfStatement
, "EOL");
686 if (DirectiveID
.getString() == ".functype") {
687 // This code has to send things to the streamer similar to
688 // WebAssemblyAsmPrinter::EmitFunctionBodyStart.
689 // TODO: would be good to factor this into a common function, but the
690 // assembler and backend really don't share any common code, and this code
691 // parses the locals seperately.
692 auto SymName
= expectIdent();
695 auto WasmSym
= cast
<MCSymbolWasm
>(Ctx
.getOrCreateSymbol(SymName
));
696 if (CurrentState
== Label
&& WasmSym
== LastLabel
) {
697 // This .functype indicates a start of a function.
698 if (ensureEmptyNestingStack())
700 CurrentState
= FunctionStart
;
701 LastFunctionLabel
= LastLabel
;
704 auto Signature
= std::make_unique
<wasm::WasmSignature
>();
705 if (parseSignature(Signature
.get()))
707 WasmSym
->setSignature(Signature
.get());
708 addSignature(std::move(Signature
));
709 WasmSym
->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION
);
710 TOut
.emitFunctionType(WasmSym
);
711 // TODO: backend also calls TOut.emitIndIdx, but that is not implemented.
712 return expect(AsmToken::EndOfStatement
, "EOL");
715 if (DirectiveID
.getString() == ".eventtype") {
716 auto SymName
= expectIdent();
719 auto WasmSym
= cast
<MCSymbolWasm
>(Ctx
.getOrCreateSymbol(SymName
));
720 auto Signature
= std::make_unique
<wasm::WasmSignature
>();
721 if (parseRegTypeList(Signature
->Params
))
723 WasmSym
->setSignature(Signature
.get());
724 addSignature(std::move(Signature
));
725 WasmSym
->setType(wasm::WASM_SYMBOL_TYPE_EVENT
);
726 TOut
.emitEventType(WasmSym
);
727 // TODO: backend also calls TOut.emitIndIdx, but that is not implemented.
728 return expect(AsmToken::EndOfStatement
, "EOL");
731 if (DirectiveID
.getString() == ".local") {
732 if (CurrentState
!= FunctionStart
)
733 return error(".local directive should follow the start of a function",
735 SmallVector
<wasm::ValType
, 4> Locals
;
736 if (parseRegTypeList(Locals
))
738 TOut
.emitLocal(Locals
);
739 CurrentState
= FunctionLocals
;
740 return expect(AsmToken::EndOfStatement
, "EOL");
743 if (DirectiveID
.getString() == ".int8" ||
744 DirectiveID
.getString() == ".int16" ||
745 DirectiveID
.getString() == ".int32" ||
746 DirectiveID
.getString() == ".int64") {
747 if (CheckDataSection()) return true;
750 if (Parser
.parseExpression(Val
, End
))
751 return error("Cannot parse .int expression: ", Lexer
.getTok());
753 DirectiveID
.getString().drop_front(4).getAsInteger(10, NumBits
);
754 Out
.EmitValue(Val
, NumBits
/ 8, End
);
755 return expect(AsmToken::EndOfStatement
, "EOL");
758 if (DirectiveID
.getString() == ".asciz") {
759 if (CheckDataSection()) return true;
761 if (Parser
.parseEscapedString(S
))
762 return error("Cannot parse string constant: ", Lexer
.getTok());
763 Out
.EmitBytes(StringRef(S
.c_str(), S
.length() + 1));
764 return expect(AsmToken::EndOfStatement
, "EOL");
767 return true; // We didn't process this directive.
770 // Called either when the first instruction is parsed of the function ends.
771 void ensureLocals(MCStreamer
&Out
) {
772 if (CurrentState
== FunctionStart
) {
773 // We haven't seen a .local directive yet. The streamer requires locals to
774 // be encoded as a prelude to the instructions, so emit an empty list of
776 auto &TOut
= reinterpret_cast<WebAssemblyTargetStreamer
&>(
777 *Out
.getTargetStreamer());
778 TOut
.emitLocal(SmallVector
<wasm::ValType
, 0>());
779 CurrentState
= FunctionLocals
;
783 bool MatchAndEmitInstruction(SMLoc IDLoc
, unsigned & /*Opcode*/,
784 OperandVector
&Operands
, MCStreamer
&Out
,
786 bool MatchingInlineAsm
) override
{
789 unsigned MatchResult
=
790 MatchInstructionImpl(Operands
, Inst
, ErrorInfo
, MatchingInlineAsm
);
791 switch (MatchResult
) {
792 case Match_Success
: {
794 // Fix unknown p2align operands.
795 auto Align
= WebAssembly::GetDefaultP2AlignAny(Inst
.getOpcode());
797 auto &Op0
= Inst
.getOperand(0);
798 if (Op0
.getImm() == -1)
801 Out
.EmitInstruction(Inst
, getSTI());
802 if (CurrentState
== EndFunction
) {
805 CurrentState
= Instructions
;
809 case Match_MissingFeature
:
811 IDLoc
, "instruction requires a WASM feature not currently enabled");
812 case Match_MnemonicFail
:
813 return Parser
.Error(IDLoc
, "invalid instruction");
814 case Match_NearMisses
:
815 return Parser
.Error(IDLoc
, "ambiguous instruction");
816 case Match_InvalidTiedOperand
:
817 case Match_InvalidOperand
: {
818 SMLoc ErrorLoc
= IDLoc
;
819 if (ErrorInfo
!= ~0ULL) {
820 if (ErrorInfo
>= Operands
.size())
821 return Parser
.Error(IDLoc
, "too few operands for instruction");
822 ErrorLoc
= Operands
[ErrorInfo
]->getStartLoc();
823 if (ErrorLoc
== SMLoc())
826 return Parser
.Error(ErrorLoc
, "invalid operand for instruction");
829 llvm_unreachable("Implement any new match types added!");
832 void doBeforeLabelEmit(MCSymbol
*Symbol
) override
{
833 // Start a new section for the next function automatically, since our
834 // object writer expects each function to have its own section. This way
835 // The user can't forget this "convention".
836 auto SymName
= Symbol
->getName();
837 if (SymName
.startswith(".L"))
838 return; // Local Symbol.
839 // Only create a new text section if we're already in one.
840 auto CWS
= cast
<MCSectionWasm
>(getStreamer().getCurrentSection().first
);
841 if (!CWS
|| !CWS
->getKind().isText())
843 auto SecName
= ".text." + SymName
;
844 auto WS
= getContext().getWasmSection(SecName
, SectionKind::getText());
845 getStreamer().SwitchSection(WS
);
848 void onEndOfFunction() {
849 // Automatically output a .size directive, so it becomes optional for the
851 if (!LastFunctionLabel
) return;
852 auto TempSym
= getContext().createLinkerPrivateTempSymbol();
853 getStreamer().EmitLabel(TempSym
);
854 auto Start
= MCSymbolRefExpr::create(LastFunctionLabel
, getContext());
855 auto End
= MCSymbolRefExpr::create(TempSym
, getContext());
857 MCBinaryExpr::create(MCBinaryExpr::Sub
, End
, Start
, getContext());
858 getStreamer().emitELFSize(LastFunctionLabel
, Expr
);
861 void onEndOfFile() override
{ ensureEmptyNestingStack(); }
863 } // end anonymous namespace
865 // Force static initialization.
866 extern "C" void LLVMInitializeWebAssemblyAsmParser() {
867 RegisterMCAsmParser
<WebAssemblyAsmParser
> X(getTheWebAssemblyTarget32());
868 RegisterMCAsmParser
<WebAssemblyAsmParser
> Y(getTheWebAssemblyTarget64());
871 #define GET_REGISTER_MATCHER
872 #define GET_MATCHER_IMPLEMENTATION
873 #include "WebAssemblyGenAsmMatcher.inc"