1 //===- WasmAsmParser.cpp - Wasm Assembly Parser -----------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 // --
9 //
10 // Note, this is for wasm, the binary format (analogous to ELF), not wasm,
11 // the instruction set (analogous to x86), for which parsing code lives in
12 // WebAssemblyAsmParser.
13 //
14 // This file contains processing for generic directives implemented using
15 // MCTargetStreamer, the ones that depend on WebAssemblyTargetStreamer are in
16 // WebAssemblyAsmParser.
17 //
18 //===----------------------------------------------------------------------===//
19 
20 #include "llvm/BinaryFormat/Wasm.h"
21 #include "llvm/MC/MCContext.h"
22 #include "llvm/MC/MCParser/MCAsmLexer.h"
23 #include "llvm/MC/MCParser/MCAsmParser.h"
24 #include "llvm/MC/MCParser/MCAsmParserExtension.h"
25 #include "llvm/MC/MCStreamer.h"
26 #include "llvm/MC/MCSymbol.h"
27 #include "llvm/MC/MCSymbolWasm.h"
28 #include "llvm/Support/MachineValueType.h"
29 
30 using namespace llvm;
31 
32 namespace {
33 
34 class WasmAsmParser : public MCAsmParserExtension {
35   MCAsmParser *Parser;
36   MCAsmLexer *Lexer;
37 
38   template<bool (WasmAsmParser::*HandlerMethod)(StringRef, SMLoc)>
addDirectiveHandler(StringRef Directive)39   void addDirectiveHandler(StringRef Directive) {
40     MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair(
41         this, HandleDirective<WasmAsmParser, HandlerMethod>);
42 
43     getParser().addDirectiveHandler(Directive, Handler);
44   }
45 
46 public:
WasmAsmParser()47   WasmAsmParser() : Parser(nullptr), Lexer(nullptr) {
48     BracketExpressionsSupported = true;
49   }
50 
Initialize(MCAsmParser & P)51   void Initialize(MCAsmParser &P) override {
52     Parser = &P;
53     Lexer = &Parser->getLexer();
54     // Call the base implementation.
55     this->MCAsmParserExtension::Initialize(*Parser);
56 
57     addDirectiveHandler<&WasmAsmParser::parseSectionDirectiveText>(".text");
58     addDirectiveHandler<&WasmAsmParser::parseSectionDirective>(".section");
59     addDirectiveHandler<&WasmAsmParser::parseDirectiveSize>(".size");
60     addDirectiveHandler<&WasmAsmParser::parseDirectiveType>(".type");
61   }
62 
Error(const StringRef & msg,const AsmToken & tok)63   bool Error(const StringRef &msg, const AsmToken &tok) {
64     return Parser->Error(tok.getLoc(), msg + tok.getString());
65   }
66 
IsNext(AsmToken::TokenKind Kind)67   bool IsNext(AsmToken::TokenKind Kind) {
68     auto ok = Lexer->is(Kind);
69     if (ok) Lex();
70     return ok;
71   }
72 
Expect(AsmToken::TokenKind Kind,const char * KindName)73   bool Expect(AsmToken::TokenKind Kind, const char *KindName) {
74     if (!IsNext(Kind))
75       return Error(std::string("Expected ") + KindName + ", instead got: ",
76                    Lexer->getTok());
77     return false;
78   }
79 
parseSectionDirectiveText(StringRef,SMLoc)80   bool parseSectionDirectiveText(StringRef, SMLoc) {
81     // FIXME: .text currently no-op.
82     return false;
83   }
84 
parseSectionDirective(StringRef,SMLoc)85   bool parseSectionDirective(StringRef, SMLoc) {
86     // FIXME: .section currently no-op.
87     while (Lexer->isNot(AsmToken::EndOfStatement)) Parser->Lex();
88     return false;
89   }
90 
91   // TODO: This function is almost the same as ELFAsmParser::ParseDirectiveSize
92   // so maybe could be shared somehow.
parseDirectiveSize(StringRef,SMLoc)93   bool parseDirectiveSize(StringRef, SMLoc) {
94     StringRef Name;
95     if (Parser->parseIdentifier(Name))
96       return TokError("expected identifier in directive");
97     auto Sym = getContext().getOrCreateSymbol(Name);
98     if (Lexer->isNot(AsmToken::Comma))
99       return TokError("unexpected token in directive");
100     Lex();
101     const MCExpr *Expr;
102     if (Parser->parseExpression(Expr))
103       return true;
104     if (Lexer->isNot(AsmToken::EndOfStatement))
105       return TokError("unexpected token in directive");
106     Lex();
107     // MCWasmStreamer implements this.
108     getStreamer().emitELFSize(Sym, Expr);
109     return false;
110   }
111 
parseDirectiveType(StringRef,SMLoc)112   bool parseDirectiveType(StringRef, SMLoc) {
113     // This could be the start of a function, check if followed by
114     // "label,@function"
115     if (!Lexer->is(AsmToken::Identifier))
116       return Error("Expected label after .type directive, got: ",
117                    Lexer->getTok());
118     auto WasmSym = cast<MCSymbolWasm>(
119                      getStreamer().getContext().getOrCreateSymbol(
120                        Lexer->getTok().getString()));
121     Lex();
122     if (!(IsNext(AsmToken::Comma) && IsNext(AsmToken::At) &&
123           Lexer->is(AsmToken::Identifier)))
124       return Error("Expected label,@type declaration, got: ", Lexer->getTok());
125     auto TypeName = Lexer->getTok().getString();
126     if (TypeName == "function")
127       WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
128     else if (TypeName == "global")
129       WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);
130     else
131       return Error("Unknown WASM symbol type: ", Lexer->getTok());
132     Lex();
133     return Expect(AsmToken::EndOfStatement, "EOL");
134   }
135 };
136 
137 } // end anonymous namespace
138 
139 namespace llvm {
140 
createWasmAsmParser()141 MCAsmParserExtension *createWasmAsmParser() {
142   return new WasmAsmParser;
143 }
144 
145 } // end namespace llvm
146