Index: include/llvm/ADT/StringSwitch.h =================================================================== --- include/llvm/ADT/StringSwitch.h +++ include/llvm/ADT/StringSwitch.h @@ -206,6 +206,13 @@ return Value; } + // Useful if the target enum has no "undefined" value. + LLVM_NODISCARD + LLVM_ATTRIBUTE_ALWAYS_INLINE + Optional NoDefault() { + return std::move(Result); + } + LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE operator R() { Index: include/llvm/MC/MCSymbolWasm.h =================================================================== --- include/llvm/MC/MCSymbolWasm.h +++ include/llvm/MC/MCSymbolWasm.h @@ -69,6 +69,23 @@ GlobalTypeSet = true; GlobalType = GT; } + + // TODO(wvo): not great to have this code in a header, but currently not a + // a lot of other places shared by Codegen and Assembler. + bool checkKnownSymbol(StringRef Name, bool HasAddr64) { + // __stack_pointer is a global variable; all other external symbols used by + // CodeGen are functions. It's OK to hardcode knowledge of specific symbols + // here; this method is precisely there for fetching the signatures of known + // Clang-provided symbols. + if (Name == "__stack_pointer") { + setType(wasm::WASM_SYMBOL_TYPE_GLOBAL); + setGlobalType(wasm::WasmGlobalType{ + uint8_t(HasAddr64 ? wasm::WASM_TYPE_I64 : wasm::WASM_TYPE_I32), + true}); + return true; + } + return false; + } }; } // end namespace llvm Index: lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp =================================================================== --- lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp +++ lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp @@ -25,6 +25,7 @@ #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" @@ -131,14 +132,19 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser { MCAsmParser &Parser; MCAsmLexer &Lexer; - MCSymbol *LastLabel; + MCSymbolWasm *LastSymbol; + MCSymbolWasm *LastFunction; + std::string LastTypedSymbolName; + wasm::WasmSymbolType LastTypeOfSymbol; + const MCSubtargetInfo &STI; 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), LastFunction(nullptr), + LastTypeOfSymbol(wasm::WASM_SYMBOL_TYPE_FUNCTION), STI(STI) { + setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); } #define GET_ASSEMBLER_HEADER @@ -264,6 +270,29 @@ SMLoc End; if (Parser.parsePrimaryExpr(Val, End)) return Error("Cannot parse symbol: ", Lexer.getTok()); + if (Val->getKind() == MCExpr::SymbolRef) { + auto SymRef = cast(Val); + // TODO: there has to be a more elegant way? + auto &WasmSymbol = cast( + const_cast(SymRef->getSymbol())); + // See if this is "__stack_pointer" or some other symbol we treat + // specially. + WasmSymbol.checkKnownSymbol(WasmSymbol.getName(), STI.getTargetTriple().getArch() == + Triple::wasm64); + // TODO: do we ideally want more generic handling like this code + // below instead of checkKnownSymbol? + /* + switch (SymRef->getKind()) { + case MCSymbolRefExpr::VK_WebAssembly_FUNCTION: + WasmSymbol.setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); + break; + case MCSymbolRefExpr::VK_WebAssembly_GLOBAL: + WasmSymbol.setType(wasm::WASM_SYMBOL_TYPE_GLOBAL); + break; + default:; + } + */ + } Operands.push_back(make_unique( WebAssemblyOperand::Symbol, Id.getLoc(), Id.getEndLoc(), WebAssemblyOperand::SymOp{Val})); @@ -311,7 +340,15 @@ return false; } - void onLabelParsed(MCSymbol *Symbol) override { LastLabel = Symbol; } + void onLabelParsed(MCSymbol *Symbol) override { + auto WasmSymbol = cast(Symbol); + LastSymbol = WasmSymbol; + if (LastTypedSymbolName == WasmSymbol->getName()) { + WasmSymbol->setType(LastTypeOfSymbol); + if (LastTypeOfSymbol == wasm::WASM_SYMBOL_TYPE_FUNCTION) + LastFunction = WasmSymbol; + } + } bool ParseDirective(AsmToken DirectiveID) override { assert(DirectiveID.getKind() == AsmToken::Identifier); @@ -324,11 +361,39 @@ 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()); + LastTypedSymbolName = 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 Type = StringSwitch(Lexer.getTok().getString()) + .Case("function", wasm::WASM_SYMBOL_TYPE_FUNCTION) + .Case("data", wasm::WASM_SYMBOL_TYPE_DATA) + .Case("global", wasm::WASM_SYMBOL_TYPE_GLOBAL) + .Case("section", wasm::WASM_SYMBOL_TYPE_SECTION) + .NoDefault(); + if (!Type) + return Error("Unknown WASM symbol type: ", Lexer.getTok()); + Parser.Lex(); + LastTypeOfSymbol = *Type; + } else if (DirectiveID.getString() == ".size") { + if (!Lexer.is(AsmToken::Identifier)) + return Error("Expected label after .size directive, got: ", + Lexer.getTok()); + if (!LastFunction || + LastFunction->getName() != Lexer.getTok().getString()) + return Error(".size directive without corresponding function start with" + " .type for: ", Lexer.getTok()); 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()); + LastFunction->setSize(Exp); } else if (DirectiveID.getString() == ".param" || DirectiveID.getString() == ".local") { // Track the number of locals, needed for correct virtual register @@ -349,8 +414,8 @@ if (!IsNext(AsmToken::Comma)) break; } - assert(LastLabel); - TOut.emitParam(LastLabel, Params); + assert(LastSymbol); + TOut.emitParam(LastSymbol, Params); TOut.emitLocal(Locals); } else { // For now, ignore anydirective we don't recognize: Index: lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp +++ lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp @@ -75,18 +75,8 @@ cast(Printer.GetExternalSymbolSymbol(Name)); const WebAssemblySubtarget &Subtarget = Printer.getSubtarget(); - // __stack_pointer is a global variable; all other external symbols used by - // CodeGen are functions. It's OK to hardcode knowledge of specific symbols - // here; this method is precisely there for fetching the signatures of known - // Clang-provided symbols. - if (strcmp(Name, "__stack_pointer") == 0) { - WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL); - WasmSym->setGlobalType(wasm::WasmGlobalType{ - uint8_t(Subtarget.hasAddr64() ? wasm::WASM_TYPE_I64 - : wasm::WASM_TYPE_I32), - true}); - return WasmSym; - } + // See if this is "__stack_pointer" or some other symbol we treat specially. + if (WasmSym->checkKnownSymbol(Name, Subtarget.hasAddr64())) return WasmSym; SmallVector Returns; SmallVector Params; Index: test/MC/WebAssembly/basic-assembly.s =================================================================== --- test/MC/WebAssembly/basic-assembly.s +++ test/MC/WebAssembly/basic-assembly.s @@ -1,4 +1,6 @@ # RUN: llvm-mc -triple=wasm32-unknown-unknown -mattr=+simd128,+nontrapping-fptoint < %s | FileCheck %s +# this one is just here to see if it converts to .o without errors, but doesn't check any output: +# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj -mattr=+simd128,+nontrapping-fptoint < %s .text .type test0,@function @@ -49,7 +51,8 @@ #i32.trunc_s:sat/f32 get_global __stack_pointer@GLOBAL end_function - +.Lfunc_end0: + .size test0, .Lfunc_end0-test0 # CHECK: .text # CHECK-LABEL: test0: