Skip to content

Commit cc75e77

Browse files
committed
[WebAssembly] Added WasmAsmParser.
Summary: This is to replace the ELFAsmParser that WebAssembly was using, which so far was a stub that didn't do anything, and couldn't work correctly with wasm. This new class is there to implement generic directives related to wasm as a binary format. Wasm target specific directives are still parsed in WebAssemblyAsmParser as before. The two classes now cooperate more correctly too. Also implemented .result which was missing. Any unknown directives will now result in errors. Reviewers: dschuff, sbc100 Subscribers: mgorny, jgravelle-google, eraman, aheejin, sunfish, llvm-commits Differential Revision: https://reviews.llvm.org/D54360 llvm-svn: 346700
1 parent bd844e0 commit cc75e77

File tree

6 files changed

+184
-79
lines changed

6 files changed

+184
-79
lines changed

llvm/lib/MC/MCParser/AsmParser.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,7 @@ namespace llvm {
675675
extern MCAsmParserExtension *createDarwinAsmParser();
676676
extern MCAsmParserExtension *createELFAsmParser();
677677
extern MCAsmParserExtension *createCOFFAsmParser();
678+
extern MCAsmParserExtension *createWasmAsmParser();
678679

679680
} // end namespace llvm
680681

@@ -705,10 +706,7 @@ AsmParser::AsmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out,
705706
PlatformParser.reset(createELFAsmParser());
706707
break;
707708
case MCObjectFileInfo::IsWasm:
708-
// TODO: WASM will need its own MCAsmParserExtension implementation, but
709-
// for now we can re-use the ELF one, since the directives can be the
710-
// same for now.
711-
PlatformParser.reset(createELFAsmParser());
709+
PlatformParser.reset(createWasmAsmParser());
712710
break;
713711
}
714712

@@ -3921,7 +3919,7 @@ bool AsmParser::parseDirectiveCFIStartProc() {
39213919
parseToken(AsmToken::EndOfStatement))
39223920
return addErrorSuffix(" in '.cfi_startproc' directive");
39233921
}
3924-
3922+
39253923
// TODO(kristina): Deal with a corner case of incorrect diagnostic context
39263924
// being produced if this directive is emitted as part of preprocessor macro
39273925
// expansion which can *ONLY* happen if Clang's cc1as is the API consumer.

llvm/lib/MC/MCParser/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ add_llvm_library(LLVMMCParser
88
MCAsmParser.cpp
99
MCAsmParserExtension.cpp
1010
MCTargetAsmParser.cpp
11+
WasmAsmParser.cpp
1112

1213
ADDITIONAL_HEADER_DIRS
1314
${LLVM_MAIN_INCLUDE_DIR}/llvm/MC/MCParser
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
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)>
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:
47+
WasmAsmParser() : Parser(nullptr), Lexer(nullptr) {
48+
BracketExpressionsSupported = true;
49+
}
50+
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+
63+
bool Error(const StringRef &msg, const AsmToken &tok) {
64+
return Parser->Error(tok.getLoc(), msg + tok.getString());
65+
}
66+
67+
bool IsNext(AsmToken::TokenKind Kind) {
68+
auto ok = Lexer->is(Kind);
69+
if (ok) Lex();
70+
return ok;
71+
}
72+
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+
80+
bool parseSectionDirectiveText(StringRef, SMLoc) {
81+
// FIXME: .text currently no-op.
82+
return false;
83+
}
84+
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.
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+
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+
141+
MCAsmParserExtension *createWasmAsmParser() {
142+
return new WasmAsmParser;
143+
}
144+
145+
} // end namespace llvm

llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp

Lines changed: 31 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -132,13 +132,12 @@ struct WebAssemblyOperand : public MCParsedAsmOperand {
132132
class WebAssemblyAsmParser final : public MCTargetAsmParser {
133133
MCAsmParser &Parser;
134134
MCAsmLexer &Lexer;
135-
MCSymbolWasm *LastSymbol;
136135

137136
public:
138137
WebAssemblyAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
139138
const MCInstrInfo &MII, const MCTargetOptions &Options)
140139
: MCTargetAsmParser(Options, STI, MII), Parser(Parser),
141-
Lexer(Parser.getLexer()), LastSymbol(nullptr) {
140+
Lexer(Parser.getLexer()) {
142141
setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
143142
}
144143

@@ -191,6 +190,19 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
191190
.Default({MVT::INVALID_SIMPLE_VALUE_TYPE, wasm::WASM_TYPE_NORESULT});
192191
}
193192

193+
bool ParseRegTypeList(std::vector<MVT> &Types) {
194+
while (Lexer.is(AsmToken::Identifier)) {
195+
auto RegType = ParseRegType(Lexer.getTok().getString()).first;
196+
if (RegType == MVT::INVALID_SIMPLE_VALUE_TYPE)
197+
return true;
198+
Types.push_back(RegType);
199+
Parser.Lex();
200+
if (!IsNext(AsmToken::Comma))
201+
break;
202+
}
203+
return Expect(AsmToken::EndOfStatement, "EOL");
204+
}
205+
194206
void ParseSingleInteger(bool IsNegative, OperandVector &Operands) {
195207
auto &Int = Lexer.getTok();
196208
int64_t Val = Int.getIntVal();
@@ -314,10 +326,9 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
314326
return false;
315327
}
316328

317-
void onLabelParsed(MCSymbol *Symbol) override {
318-
LastSymbol = cast<MCSymbolWasm>(Symbol);
319-
}
320-
329+
// This function processes wasm-specific directives streamed to
330+
// WebAssemblyTargetStreamer, all others go to the generic parser
331+
// (see WasmAsmParser).
321332
bool ParseDirective(AsmToken DirectiveID) override {
322333
// This function has a really weird return value behavior that is different
323334
// from all the other parsing functions:
@@ -331,44 +342,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
331342
reinterpret_cast<WebAssemblyTargetStreamer &>(*Out.getTargetStreamer());
332343
// TODO: any time we return an error, at least one token must have been
333344
// consumed, otherwise this will not signal an error to the caller.
334-
if (DirectiveID.getString() == ".type") {
335-
// This could be the start of a function, check if followed by
336-
// "label,@function"
337-
if (!Lexer.is(AsmToken::Identifier))
338-
return Error("Expected label after .type directive, got: ",
339-
Lexer.getTok());
340-
auto WasmSym = cast<MCSymbolWasm>(
341-
TOut.getStreamer().getContext().getOrCreateSymbol(
342-
Lexer.getTok().getString()));
343-
Parser.Lex();
344-
if (!(IsNext(AsmToken::Comma) && IsNext(AsmToken::At) &&
345-
Lexer.is(AsmToken::Identifier)))
346-
return Error("Expected label,@type declaration, got: ", Lexer.getTok());
347-
auto TypeName = Lexer.getTok().getString();
348-
if (TypeName == "function")
349-
WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
350-
else if (TypeName == "global")
351-
WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);
352-
else
353-
return Error("Unknown WASM symbol type: ", Lexer.getTok());
354-
Parser.Lex();
355-
return Expect(AsmToken::EndOfStatement, "EOL");
356-
} else if (DirectiveID.getString() == ".size") {
357-
if (!Lexer.is(AsmToken::Identifier))
358-
return Error("Expected label after .size directive, got: ",
359-
Lexer.getTok());
360-
auto WasmSym = cast<MCSymbolWasm>(
361-
TOut.getStreamer().getContext().getOrCreateSymbol(
362-
Lexer.getTok().getString()));
363-
Parser.Lex();
364-
if (!IsNext(AsmToken::Comma))
365-
return Error("Expected `,`, got: ", Lexer.getTok());
366-
const MCExpr *Exp;
367-
if (Parser.parseExpression(Exp))
368-
return Error("Cannot parse .size expression: ", Lexer.getTok());
369-
WasmSym->setSize(Exp);
370-
return Expect(AsmToken::EndOfStatement, "EOL");
371-
} else if (DirectiveID.getString() == ".globaltype") {
345+
if (DirectiveID.getString() == ".globaltype") {
372346
if (!Lexer.is(AsmToken::Identifier))
373347
return Error("Expected symbol name after .globaltype directive, got: ",
374348
Lexer.getTok());
@@ -392,40 +366,23 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
392366
// And emit the directive again.
393367
TOut.emitGlobalType(WasmSym);
394368
return Expect(AsmToken::EndOfStatement, "EOL");
395-
} else if (DirectiveID.getString() == ".param" ||
396-
DirectiveID.getString() == ".local") {
397-
// Track the number of locals, needed for correct virtual register
398-
// assignment elsewhere.
399-
// Also output a directive to the streamer.
369+
} else if (DirectiveID.getString() == ".param") {
400370
std::vector<MVT> Params;
371+
if (ParseRegTypeList(Params)) return true;
372+
TOut.emitParam(nullptr /* unused */, Params);
373+
return false;
374+
} else if (DirectiveID.getString() == ".result") {
375+
std::vector<MVT> Results;
376+
if (ParseRegTypeList(Results)) return true;
377+
TOut.emitResult(nullptr /* unused */, Results);
378+
return false;
379+
} else if (DirectiveID.getString() == ".local") {
401380
std::vector<MVT> Locals;
402-
while (Lexer.is(AsmToken::Identifier)) {
403-
auto RegType = ParseRegType(Lexer.getTok().getString()).first;
404-
if (RegType == MVT::INVALID_SIMPLE_VALUE_TYPE)
405-
return true;
406-
if (DirectiveID.getString() == ".param") {
407-
Params.push_back(RegType);
408-
} else {
409-
Locals.push_back(RegType);
410-
}
411-
Parser.Lex();
412-
if (!IsNext(AsmToken::Comma))
413-
break;
414-
}
415-
assert(LastSymbol);
416-
// TODO: LastSymbol isn't even used by emitParam, so could be removed.
417-
TOut.emitParam(LastSymbol, Params);
381+
if (ParseRegTypeList(Locals)) return true;
418382
TOut.emitLocal(Locals);
419-
return Expect(AsmToken::EndOfStatement, "EOL");
420-
} else {
421-
// TODO: remove.
422-
while (Lexer.isNot(AsmToken::EndOfStatement))
423-
Parser.Lex();
424-
return Expect(AsmToken::EndOfStatement, "EOL");
383+
return false;
425384
}
426-
// TODO: current ELF directive parsing is broken, fix this is a followup.
427-
//return true; // We didn't process this directive.
428-
return false;
385+
return true; // We didn't process this directive.
429386
}
430387

431388
bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned & /*Opcode*/,

llvm/test/CodeGen/WebAssembly/inline-asm-roundtrip.ll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ target triple = "wasm32-unknown-unknown"
2222

2323
; CHECK-LABEL: main:
2424
; CHECK-NEXT: .param i32, i32
25+
; CHECK-NEXT: .result i32
2526
; CHECK-NEXT: .local i32
2627
; CHECK-NEXT: i32.const 1
2728
; CHECK-NEXT: set_local [[SRC:[0-9]+]]

llvm/test/MC/WebAssembly/basic-assembly.s

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj -mattr=+simd128,+nontrapping-fptoint,+exception-handling < %s
44

55
.text
6+
.section .text.main,"",@
67
.type test0,@function
78
test0:
89
# Test all types:
910
.param i32, i64
11+
.result i32
1012
.local f32, f64, v128, v128
1113
# Explicit getlocal/setlocal:
1214
get_local 2
@@ -65,6 +67,7 @@ test0:
6567
# CHECK: .text
6668
# CHECK-LABEL: test0:
6769
# CHECK-NEXT: .param i32, i64
70+
# CHECK-NEXT: .result i32
6871
# CHECK-NEXT: .local f32, f64
6972
# CHECK-NEXT: get_local 2
7073
# CHECK-NEXT: set_local 2

0 commit comments

Comments
 (0)