34 #define DEBUG_TYPE "wasm-asm-parser" 43 SMLoc StartLoc, EndLoc;
62 std::vector<unsigned>
List;
73 WebAssemblyOperand(KindTy K,
SMLoc Start,
SMLoc End, TokOp
T)
74 :
Kind(K), StartLoc(Start), EndLoc(End), Tok(T) {}
75 WebAssemblyOperand(KindTy K,
SMLoc Start,
SMLoc End, IntOp
I)
76 :
Kind(K), StartLoc(Start), EndLoc(End),
Int(I) {}
77 WebAssemblyOperand(KindTy K,
SMLoc Start,
SMLoc End, FltOp
F)
78 :
Kind(K), StartLoc(Start), EndLoc(End), Flt(F) {}
79 WebAssemblyOperand(KindTy K,
SMLoc Start,
SMLoc End, SymOp S)
80 :
Kind(K), StartLoc(Start), EndLoc(End), Sym(S) {}
81 WebAssemblyOperand(KindTy K,
SMLoc Start,
SMLoc End)
82 :
Kind(K), StartLoc(Start), EndLoc(End), BrL() {}
84 ~WebAssemblyOperand() {
89 bool isToken()
const override {
return Kind == Token; }
90 bool isImm()
const override {
93 bool isMem()
const override {
return false; }
94 bool isReg()
const override {
return false; }
95 bool isBrList()
const {
return Kind == BrList; }
97 unsigned getReg()
const override {
107 SMLoc getStartLoc()
const override {
return StartLoc; }
108 SMLoc getEndLoc()
const override {
return EndLoc; }
110 void addRegOperands(
MCInst &,
unsigned)
const {
115 void addImmOperands(
MCInst &Inst,
unsigned N)
const {
116 assert(N == 1 &&
"Invalid number of operands!");
119 else if (Kind ==
Float)
127 void addBrListOperands(
MCInst &Inst,
unsigned N)
const {
128 assert(N == 1 && isBrList() &&
"Invalid BrList!");
129 for (
auto Br : BrL.List)
136 OS <<
"Tok:" << Tok.Tok;
139 OS <<
"Int:" <<
Int.Val;
142 OS <<
"Flt:" << Flt.Val;
145 OS <<
"Sym:" << Sym.Exp;
148 OS <<
"BrList:" << BrL.List.size();
159 std::vector<std::unique_ptr<wasm::WasmSignature>> Signatures;
173 } CurrentState = FileStart;
185 std::vector<NestingType> NestingStack;
196 setAvailableFeatures(ComputeAvailableFeatures(STI.
getFeatureBits()));
199 #define GET_ASSEMBLER_HEADER 200 #include "WebAssemblyGenAsmMatcher.inc" 203 bool ParseRegister(
unsigned & ,
SMLoc & ,
216 void addSignature(std::unique_ptr<wasm::WasmSignature> &&Sig) {
217 Signatures.push_back(std::move(Sig));
220 std::pair<StringRef, StringRef> nestingString(NestingType NT) {
223 return {
"function",
"end_function"};
225 return {
"block",
"end_block"};
227 return {
"loop",
"end_loop"};
229 return {
"try",
"end_try"};
231 return {
"if",
"end_if"};
233 return {
"else",
"end_if"};
239 void push(NestingType NT) { NestingStack.push_back(NT); }
241 bool pop(
StringRef Ins, NestingType NT1, NestingType NT2 = Undefined) {
242 if (NestingStack.empty())
243 return error(
Twine(
"End of block construct with no start: ") +
Ins);
244 auto Top = NestingStack.back();
245 if (Top != NT1 && Top != NT2)
246 return error(
Twine(
"Block construct type mismatch, expected: ") +
247 nestingString(Top).
second +
", instead got: " + Ins);
248 NestingStack.pop_back();
252 bool ensureEmptyNestingStack() {
253 auto err = !NestingStack.empty();
254 while (!NestingStack.empty()) {
255 error(
Twine(
"Unmatched block construct(s) at function end: ") +
256 nestingString(NestingStack.back()).
first);
257 NestingStack.pop_back();
263 auto Ok = Lexer.
is(Kind);
271 return error(std::string(
"Expected ") + KindName +
", instead got: ",
278 error(
"Expected identifier, got: ", Lexer.
getTok());
297 if (Type ==
"v128" || Type ==
"i8x16" || Type ==
"i16x8" ||
298 Type ==
"i32x4" || Type ==
"i64x2" || Type ==
"f32x4" ||
329 void parseSingleInteger(
bool IsNegative,
OperandVector &Operands) {
330 auto &Int = Lexer.
getTok();
331 int64_t Val = Int.getIntVal();
334 Operands.
push_back(make_unique<WebAssemblyOperand>(
336 WebAssemblyOperand::IntOp{Val}));
340 bool parseOperandStartingWithInteger(
bool IsNegative,
OperandVector &Operands,
342 parseSingleInteger(IsNegative, Operands);
344 auto IsLoadStore = InstName.
startswith(
"load") ||
352 parseSingleInteger(
false, Operands);
358 Operands.
push_back(make_unique<WebAssemblyOperand>(
360 WebAssemblyOperand::IntOp{0}));
368 Operands.
push_back(make_unique<WebAssemblyOperand>(
370 WebAssemblyOperand::IntOp{
static_cast<int64_t
>(
BT)}));
383 auto &Sep = Lexer.
getTok();
384 if (Sep.getLoc().getPointer() != Name.
end() ||
393 Id.getLoc().getPointer() != Name.
end())
394 return error(
"Incomplete instruction name: ",
Id);
400 Operands.
push_back(make_unique<WebAssemblyOperand>(
402 WebAssemblyOperand::TokOp{Name}));
403 auto NamePair = Name.
split(
'.');
405 auto BaseName = NamePair.second.empty() ? NamePair.first : NamePair.second;
409 bool ExpectBlockType =
false;
410 if (BaseName ==
"block") {
412 ExpectBlockType =
true;
413 }
else if (BaseName ==
"loop") {
415 ExpectBlockType =
true;
416 }
else if (BaseName ==
"try") {
418 ExpectBlockType =
true;
419 }
else if (BaseName ==
"if") {
421 ExpectBlockType =
true;
422 }
else if (BaseName ==
"else") {
423 if (pop(BaseName, If))
426 }
else if (BaseName ==
"catch") {
427 if (pop(BaseName, Try))
430 }
else if (BaseName ==
"catch_all") {
431 if (pop(BaseName, Try))
434 }
else if (BaseName ==
"end_if") {
435 if (pop(BaseName, If,
Else))
437 }
else if (BaseName ==
"end_try") {
438 if (pop(BaseName, Try))
440 }
else if (BaseName ==
"end_loop") {
441 if (pop(BaseName,
Loop))
443 }
else if (BaseName ==
"end_block") {
444 if (pop(BaseName, Block))
446 }
else if (BaseName ==
"end_function") {
447 if (pop(BaseName,
Function) || ensureEmptyNestingStack())
452 auto &Tok = Lexer.
getTok();
456 if (ExpectBlockType) {
458 auto BT = parseBlockType(
Id.getString());
460 return error(
"Unknown block type: ",
Id);
461 addBlockTypeOperand(Operands, NameLoc, BT);
468 return error(
"Cannot parse symbol: ", Lexer.
getTok());
469 Operands.
push_back(make_unique<WebAssemblyOperand>(
471 WebAssemblyOperand::SymOp{Val}));
478 return error(
"Expected integer instead got: ", Lexer.
getTok());
479 if (parseOperandStartingWithInteger(
true, Operands, BaseName))
483 if (parseOperandStartingWithInteger(
false, Operands, BaseName))
489 return error(
"Cannot parse real: ", Tok);
490 Operands.
push_back(make_unique<WebAssemblyOperand>(
492 WebAssemblyOperand::FltOp{Val}));
498 auto Op = make_unique<WebAssemblyOperand>(
512 return error(
"Unexpected token in operand: ", Tok);
519 if (ExpectBlockType && Operands.
size() == 1) {
529 CurrentState = Label;
535 if (parseRegTypeList(Signature->
Params))
543 if (parseRegTypeList(Signature->
Returns))
553 bool ParseDirective(
AsmToken DirectiveID)
override {
561 auto &Out = getStreamer();
567 if (DirectiveID.
getString() ==
".globaltype") {
568 auto SymName = expectIdent();
573 auto TypeTok = Lexer.
getTok();
579 return error(
"Unknown type in .globaltype directive: ", TypeTok);
581 auto WasmSym = cast<MCSymbolWasm>(
582 TOut.getStreamer().getContext().getOrCreateSymbol(SymName));
584 WasmSym->setGlobalType(
587 TOut.emitGlobalType(WasmSym);
591 if (DirectiveID.
getString() ==
".functype") {
597 auto SymName = expectIdent();
600 auto WasmSym = cast<MCSymbolWasm>(
601 TOut.getStreamer().getContext().getOrCreateSymbol(SymName));
602 if (CurrentState == Label && WasmSym == LastLabel) {
604 if (ensureEmptyNestingStack())
606 CurrentState = FunctionStart;
609 auto Signature = make_unique<wasm::WasmSignature>();
610 if (parseSignature(Signature.get()))
612 WasmSym->setSignature(Signature.get());
613 addSignature(std::move(Signature));
615 TOut.emitFunctionType(WasmSym);
620 if (DirectiveID.
getString() ==
".eventtype") {
621 auto SymName = expectIdent();
624 auto WasmSym = cast<MCSymbolWasm>(
625 TOut.getStreamer().getContext().getOrCreateSymbol(SymName));
626 auto Signature = make_unique<wasm::WasmSignature>();
627 if (parseRegTypeList(Signature->Params))
629 WasmSym->setSignature(Signature.get());
630 addSignature(std::move(Signature));
632 TOut.emitEventType(WasmSym);
637 if (DirectiveID.
getString() ==
".local") {
638 if (CurrentState != FunctionStart)
639 return error(
".local directive should follow the start of a function",
642 if (parseRegTypeList(Locals))
644 TOut.emitLocal(Locals);
645 CurrentState = FunctionLocals;
652 bool MatchAndEmitInstruction(
SMLoc IDLoc,
unsigned & ,
655 bool MatchingInlineAsm)
override {
657 unsigned MatchResult =
658 MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm);
659 switch (MatchResult) {
660 case Match_Success: {
661 if (CurrentState == FunctionStart) {
670 CurrentState = Instructions;
674 case Match_MissingFeature:
676 IDLoc,
"instruction requires a WASM feature not currently enabled");
677 case Match_MnemonicFail:
678 return Parser.
Error(IDLoc,
"invalid instruction");
679 case Match_NearMisses:
680 return Parser.
Error(IDLoc,
"ambiguous instruction");
681 case Match_InvalidTiedOperand:
682 case Match_InvalidOperand: {
683 SMLoc ErrorLoc = IDLoc;
684 if (ErrorInfo != ~0ULL) {
685 if (ErrorInfo >= Operands.
size())
686 return Parser.
Error(IDLoc,
"too few operands for instruction");
687 ErrorLoc = Operands[ErrorInfo]->getStartLoc();
688 if (ErrorLoc ==
SMLoc())
691 return Parser.
Error(ErrorLoc,
"invalid operand for instruction");
697 void onEndOfFile()
override { ensureEmptyNestingStack(); }
707 #define GET_REGISTER_MATCHER 708 #define GET_MATCHER_IMPLEMENTATION 709 #include "WebAssemblyGenAsmMatcher.inc" static bool isReg(const MCInst &MI, unsigned OpNo)
const AsmToken & getTok() const
Get the current (last) lexed token.
static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang", "erlang-compatible garbage collector")
StringRef getString() const
Get the string for the current token, this includes all characters (for example, the quotes on string...
This class represents lattice values for constants.
bool is(AsmToken::TokenKind K) const
Check if the current token has kind K.
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Generic assembler parser interface, for use by target specific assembly parsers.
static MCOperand createExpr(const MCExpr *Val)
MCTargetAsmParser - Generic interface to target specific assembly parsers.
void push_back(const T &Elt)
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE size_t size() const
size - Get the string size.
virtual const AsmToken & Lex()=0
Get the next AsmToken in the stream, possibly handling file inclusion first.
SmallVector< wasm::ValType, 1 > Returns
This file contains the entry points for global functions defined in the LLVM WebAssembly back-end...
virtual void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI, bool PrintSchedInfo=false)
Emit the given Instruction into the current section.
static GCMetadataPrinterRegistry::Add< OcamlGCMetadataPrinter > Y("ocaml", "ocaml 3.10-compatible collector")
amdgpu Simplify well known AMD library false Value Value const Twine & Name
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
const FeatureBitset & getFeatureBits() const
Generic assembler lexer interface, for use by target specific assembly lexers.
Base class for the full range of assembler expressions which are needed for parsing.
Target independent representation for an assembler token.
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE R Default(T Value)
static bool isMem(const MachineInstr &MI, unsigned Op)
MCParsedAsmOperand - This abstract class represents a source-level assembly instruction operand...
std::pair< StringRef, StringRef > getToken(StringRef Source, StringRef Delimiters=" \\\)
getToken - This function extracts one token from source, ignoring any leading characters that appear ...
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE bool startswith(StringRef Prefix) const
Check if this string starts with the given Prefix.
RegisterMCAsmParser - Helper template for registering a target specific assembly parser, for use in the target machine initialization function.
Instances of this class represent a single low-level machine instruction.
WebAssembly-specific streamer interface, to implement support WebAssembly-specific assembly directive...
const char * getPointer() const
A switch()-like statement whose cases are string literals.
Streaming machine code generation interface.
MCTargetStreamer * getTargetStreamer()
The instances of the Type class are immutable: once they are created, they are never changed...
This file provides WebAssembly-specific target descriptions.
virtual bool parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc)=0
Parse a primary expression.
Interface to description of machine instruction set.
virtual MCAsmLexer & getLexer()=0
constexpr char TypeName[]
Key for Kernel::Arg::Metadata::mTypeName.
int64_t getIntVal() const
static void print(raw_ostream &Out, object::Archive::Kind Kind, T Val)
bool Error(SMLoc L, const Twine &Msg, SMRange Range=None)
Return an error at the location L, with the message Msg.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
This file declares WebAssembly-specific target streamer classes.
LLVM_NODISCARD std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
bool getAsDouble(double &Result, bool AllowInexact=true) const
Parse the current string as an IEEE double-precision floating point value.
ExprType
This is used to indicate block signatures.
static MCOperand createFPImm(double Val)
void LLVMInitializeWebAssemblyAsmParser()
static unsigned getReg(const void *D, unsigned RC, unsigned RegNo)
Base class for user error types.
LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch & Case(StringLiteral S, T Value)
static SMLoc getFromPointer(const char *Ptr)
Represents a single loop in the control flow graph.
Generic base class for all target subtargets.
bool isNot(AsmToken::TokenKind K) const
Check if the current token has kind K.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
virtual void emitLocal(ArrayRef< wasm::ValType > Types)=0
.local
This class implements an extremely fast bulk output stream that can only output to a stream...
void addOperand(const MCOperand &Op)
StringRef - Represent a constant reference to a string, i.e.
Target & getTheWebAssemblyTarget32()
Type * parseType(StringRef Asm, SMDiagnostic &Err, const Module &M, const SlotMapping *Slots=nullptr)
Parse a type in the given string.
Represents a location in source code.
Target & getTheWebAssemblyTarget64()
SmallVector< wasm::ValType, 4 > Params
static MCOperand createImm(int64_t Val)
TokenKind getKind() const