#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/MCSymbolWasm.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/TargetRegistry.h"
class WebAssemblyAsmParser final : public MCTargetAsmParser {
MCAsmParser &Parser;
MCAsmLexer &Lexer;
- MCSymbol *LastLabel;
+ MCSymbolWasm *LastSymbol;
public:
- WebAssemblyAsmParser(const MCSubtargetInfo &sti, MCAsmParser &Parser,
- const MCInstrInfo &mii, const MCTargetOptions &Options)
- : MCTargetAsmParser(Options, sti, mii), Parser(Parser),
- Lexer(Parser.getLexer()), LastLabel(nullptr) {
- setAvailableFeatures(ComputeAvailableFeatures(sti.getFeatureBits()));
+ WebAssemblyAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
+ const MCInstrInfo &MII, const MCTargetOptions &Options)
+ : MCTargetAsmParser(Options, STI, MII), Parser(Parser),
+ Lexer(Parser.getLexer()), LastSymbol(nullptr) {
+ setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
}
#define GET_ASSEMBLER_HEADER
return false;
}
- MVT::SimpleValueType ParseRegType(const StringRef &RegType) {
+
+ std::pair<MVT::SimpleValueType, unsigned>
+ ParseRegType(const StringRef &RegType) {
// Derive type from .param .local decls, or the instruction itself.
- return StringSwitch<MVT::SimpleValueType>(RegType)
- .Case("i32", MVT::i32)
- .Case("i64", MVT::i64)
- .Case("f32", MVT::f32)
- .Case("f64", MVT::f64)
- .Case("i8x16", MVT::v16i8)
- .Case("i16x8", MVT::v8i16)
- .Case("i32x4", MVT::v4i32)
- .Case("i64x2", MVT::v2i64)
- .Case("f32x4", MVT::v4f32)
- .Case("f64x2", MVT::v2f64)
+ return StringSwitch<std::pair<MVT::SimpleValueType, unsigned>>(RegType)
+ .Case("i32", {MVT::i32, wasm::WASM_TYPE_I32})
+ .Case("i64", {MVT::i64, wasm::WASM_TYPE_I64})
+ .Case("f32", {MVT::f32, wasm::WASM_TYPE_F32})
+ .Case("f64", {MVT::f64, wasm::WASM_TYPE_F64})
+ .Case("i8x16", {MVT::v16i8, wasm::WASM_TYPE_V128})
+ .Case("i16x8", {MVT::v8i16, wasm::WASM_TYPE_V128})
+ .Case("i32x4", {MVT::v4i32, wasm::WASM_TYPE_V128})
+ .Case("i64x2", {MVT::v2i64, wasm::WASM_TYPE_V128})
+ .Case("f32x4", {MVT::v4f32, wasm::WASM_TYPE_V128})
+ .Case("f64x2", {MVT::v2f64, wasm::WASM_TYPE_V128})
// arbitrarily chosen vector type to associate with "v128"
// FIXME: should these be EVTs to avoid this arbitrary hack? Do we want
// to accept more specific SIMD register types?
- .Case("v128", MVT::v16i8)
- .Default(MVT::INVALID_SIMPLE_VALUE_TYPE);
+ .Case("v128", {MVT::v16i8, wasm::WASM_TYPE_V128})
+ .Default({MVT::INVALID_SIMPLE_VALUE_TYPE, wasm::WASM_TYPE_NORESULT});
}
void ParseSingleInteger(bool IsNegative, OperandVector &Operands) {
return false;
}
- void onLabelParsed(MCSymbol *Symbol) override { LastLabel = Symbol; }
+ void onLabelParsed(MCSymbol *Symbol) override {
+ LastSymbol = cast<MCSymbolWasm>(Symbol);
+ }
bool ParseDirective(AsmToken DirectiveID) override {
+ // This function has a really weird return value behavior that is different
+ // from all the other parsing functions:
+ // - return true && no tokens consumed -> don't know this directive / let
+ // the generic parser handle it.
+ // - return true && tokens consumed -> a parsing error occurred.
+ // - return false -> processed this directive successfully.
assert(DirectiveID.getKind() == AsmToken::Identifier);
auto &Out = getStreamer();
auto &TOut =
reinterpret_cast<WebAssemblyTargetStreamer &>(*Out.getTargetStreamer());
- // TODO: we're just parsing the subset of directives we're interested in,
- // and ignoring ones we don't recognise. We should ideally verify
- // all directives here.
+ // TODO: any time we return an error, at least one token must have been
+ // consumed, otherwise this will not signal an error to the caller.
if (DirectiveID.getString() == ".type") {
// This could be the start of a function, check if followed by
// "label,@function"
- if (!(IsNext(AsmToken::Identifier) && IsNext(AsmToken::Comma) &&
- IsNext(AsmToken::At) && Lexer.is(AsmToken::Identifier)))
+ if (!Lexer.is(AsmToken::Identifier))
+ return Error("Expected label after .type directive, got: ",
+ Lexer.getTok());
+ auto WasmSym = cast<MCSymbolWasm>(
+ TOut.getStreamer().getContext().getOrCreateSymbol(
+ Lexer.getTok().getString()));
+ Parser.Lex();
+ if (!(IsNext(AsmToken::Comma) && IsNext(AsmToken::At) &&
+ Lexer.is(AsmToken::Identifier)))
return Error("Expected label,@type declaration, got: ", Lexer.getTok());
+ auto TypeName = Lexer.getTok().getString();
+ if (TypeName == "function")
+ WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
+ else if (TypeName == "global")
+ WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);
+ else
+ return Error("Unknown WASM symbol type: ", Lexer.getTok());
+ Parser.Lex();
+ return Expect(AsmToken::EndOfStatement, "EOL");
+ } else if (DirectiveID.getString() == ".size") {
+ if (!Lexer.is(AsmToken::Identifier))
+ return Error("Expected label after .size directive, got: ",
+ Lexer.getTok());
+ auto WasmSym = cast<MCSymbolWasm>(
+ TOut.getStreamer().getContext().getOrCreateSymbol(
+ Lexer.getTok().getString()));
Parser.Lex();
- // Out.EmitSymbolAttribute(??, MCSA_ELF_TypeFunction);
+ if (!IsNext(AsmToken::Comma))
+ return Error("Expected `,`, got: ", Lexer.getTok());
+ const MCExpr *Exp;
+ if (Parser.parseExpression(Exp))
+ return Error("Cannot parse .size expression: ", Lexer.getTok());
+ WasmSym->setSize(Exp);
+ return Expect(AsmToken::EndOfStatement, "EOL");
+ } else if (DirectiveID.getString() == ".globaltype") {
+ if (!Lexer.is(AsmToken::Identifier))
+ return Error("Expected symbol name after .globaltype directive, got: ",
+ Lexer.getTok());
+ auto Name = Lexer.getTok().getString();
+ Parser.Lex();
+ if (!IsNext(AsmToken::Comma))
+ return Error("Expected `,`, got: ", Lexer.getTok());
+ if (!Lexer.is(AsmToken::Identifier))
+ return Error("Expected type in .globaltype directive, got: ",
+ Lexer.getTok());
+ auto Type = ParseRegType(Lexer.getTok().getString()).second;
+ if (Type == wasm::WASM_TYPE_NORESULT)
+ return Error("Unknown type in .globaltype directive: ",
+ Lexer.getTok());
+ Parser.Lex();
+ // Now set this symbol with the correct type.
+ auto WasmSym = cast<MCSymbolWasm>(
+ TOut.getStreamer().getContext().getOrCreateSymbol(Name));
+ WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);
+ WasmSym->setGlobalType(wasm::WasmGlobalType{uint8_t(Type), true});
+ // And emit the directive again.
+ TOut.emitGlobalType(WasmSym);
+ return Expect(AsmToken::EndOfStatement, "EOL");
} else if (DirectiveID.getString() == ".param" ||
DirectiveID.getString() == ".local") {
// Track the number of locals, needed for correct virtual register
std::vector<MVT> Params;
std::vector<MVT> Locals;
while (Lexer.is(AsmToken::Identifier)) {
- auto RegType = ParseRegType(Lexer.getTok().getString());
+ auto RegType = ParseRegType(Lexer.getTok().getString()).first;
if (RegType == MVT::INVALID_SIMPLE_VALUE_TYPE)
return true;
if (DirectiveID.getString() == ".param") {
if (!IsNext(AsmToken::Comma))
break;
}
- assert(LastLabel);
- TOut.emitParam(LastLabel, Params);
+ assert(LastSymbol);
+ // TODO: LastSymbol isn't even used by emitParam, so could be removed.
+ TOut.emitParam(LastSymbol, Params);
TOut.emitLocal(Locals);
+ return Expect(AsmToken::EndOfStatement, "EOL");
} else {
- // For now, ignore anydirective we don't recognize:
+ // TODO: remove.
while (Lexer.isNot(AsmToken::EndOfStatement))
Parser.Lex();
+ return Expect(AsmToken::EndOfStatement, "EOL");
}
- return Expect(AsmToken::EndOfStatement, "EOL");
+ // TODO: current ELF directive parsing is broken, fix this is a followup.
+ //return true; // We didn't process this directive.
+ return false;
}
bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned & /*Opcode*/,