Index: llvm/trunk/lib/MC/MCParser/WasmAsmParser.cpp =================================================================== --- llvm/trunk/lib/MC/MCParser/WasmAsmParser.cpp +++ llvm/trunk/lib/MC/MCParser/WasmAsmParser.cpp @@ -130,11 +130,27 @@ if (expect(AsmToken::Comma, ",") || expect(AsmToken::At, "@") || expect(AsmToken::EndOfStatement, "eol")) return true; - // This is done automatically by the assembler for text sections currently, - // so we don't need to emit that here. This is what it would do (and may - // be needed later for other section types): - // auto WS = getContext().getWasmSection(Name, SectionKind::getText()); - // getStreamer().SwitchSection(WS); + struct SectionType { + const char *Name; + SectionKind Kind; + }; + static SectionType SectionTypes[] = { + { ".text", SectionKind::getText() }, + { ".rodata", SectionKind::getReadOnly() }, + { ".data", SectionKind::getData() }, + // TODO: add more types. + }; + for (size_t I = 0; I < sizeof(SectionTypes) / sizeof(SectionType); I++) { + if (Name.startswith(SectionTypes[I].Name)) { + auto WS = getContext().getWasmSection(Name, SectionTypes[I].Kind); + getStreamer().SwitchSection(WS); + return false; + } + } + // Not found, just ignore this section. + // For code in a text section WebAssemblyAsmParser automatically adds + // one section per function, so they're optional to be specified with + // this directive. return false; } @@ -153,9 +169,8 @@ if (expect(AsmToken::EndOfStatement, "eol")) return true; // This is done automatically by the assembler for functions currently, - // so we don't need to emit that here. This is what it would do: - (void)Sym; - // getStreamer().emitELFSize(Sym, Expr); + // so this is only currently needed for data sections: + getStreamer().emitELFSize(Sym, Expr); return false; } Index: llvm/trunk/lib/MC/WasmObjectWriter.cpp =================================================================== --- llvm/trunk/lib/MC/WasmObjectWriter.cpp +++ llvm/trunk/lib/MC/WasmObjectWriter.cpp @@ -1348,7 +1348,7 @@ LLVM_DEBUG(dbgs() << " -> function index: " << Index << "\n"); } else if (WS.isData()) { - if (WS.isTemporary() && !WS.getSize()) + if (!isInSymtab(WS)) continue; if (!WS.isDefined()) { Index: llvm/trunk/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp =================================================================== --- llvm/trunk/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp +++ llvm/trunk/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp @@ -172,6 +172,7 @@ FunctionLocals, Instructions, EndFunction, + DataSection, } CurrentState = FileStart; // For ensuring blocks are properly nested. @@ -552,6 +553,17 @@ return false; } + bool CheckDataSection() { + if (CurrentState != DataSection) { + auto WS = cast(getStreamer().getCurrentSection().first); + if (WS && WS->getKind().isText()) + return error("data directive must occur in a data segment: ", + Lexer.getTok()); + } + CurrentState = DataSection; + return false; + } + // This function processes wasm-specific directives streamed to // WebAssemblyTargetStreamer, all others go to the generic parser // (see WasmAsmParser). @@ -650,6 +662,25 @@ return expect(AsmToken::EndOfStatement, "EOL"); } + if (DirectiveID.getString() == ".int8") { + if (CheckDataSection()) return true; + int64_t V; + if (Parser.parseAbsoluteExpression(V)) + return error("Cannot parse int8 constant: ", Lexer.getTok()); + // TODO: error if value doesn't fit? + Out.EmitIntValue(static_cast(V), 1); + return expect(AsmToken::EndOfStatement, "EOL"); + } + + if (DirectiveID.getString() == ".asciz") { + if (CheckDataSection()) return true; + std::string S; + if (Parser.parseEscapedString(S)) + return error("Cannot parse string constant: ", Lexer.getTok()); + Out.EmitBytes(StringRef(S.c_str(), S.length() + 1)); + return expect(AsmToken::EndOfStatement, "EOL"); + } + return true; // We didn't process this directive. } @@ -717,9 +748,10 @@ void onEndOfFunction() { // Automatically output a .size directive, so it becomes optional for the // user. + if (!LastFunctionLabel) return; auto TempSym = getContext().createLinkerPrivateTempSymbol(); getStreamer().EmitLabel(TempSym); - auto Start = MCSymbolRefExpr::create(LastLabel, getContext()); + auto Start = MCSymbolRefExpr::create(LastFunctionLabel, getContext()); auto End = MCSymbolRefExpr::create(TempSym, getContext()); auto Expr = MCBinaryExpr::create(MCBinaryExpr::Sub, End, Start, getContext()); Index: llvm/trunk/test/MC/WebAssembly/basic-assembly.s =================================================================== --- llvm/trunk/test/MC/WebAssembly/basic-assembly.s +++ llvm/trunk/test/MC/WebAssembly/basic-assembly.s @@ -77,12 +77,19 @@ .LBB0_4: end_block end_try - i32.const 0 + i32.const .L.str throw 0 .LBB0_5: #i32.trunc_sat_f32_s global.get __stack_pointer end_function + + .section .rodata..L.str,"",@ +.L.str: + .int8 'H' + .asciz "ello, World!" + .size .L.str, 14 + .globaltype __stack_pointer, i32 # CHECK: .text @@ -154,10 +161,15 @@ # CHECK-NEXT: .LBB0_4: # CHECK-NEXT: end_block # CHECK-NEXT: end_try -# CHECK-NEXT: i32.const 0 +# CHECK-NEXT: i32.const .L.str # CHECK-NEXT: throw 0 # CHECK-NEXT: .LBB0_5: # CHECK-NEXT: global.get __stack_pointer # CHECK-NEXT: end_function +# CHECK: .section .rodata..L.str,"",@ +# CHECK-NEXT:.L.str: +# CHECK-NEXT: .int8 72 +# CHECK-NEXT: .asciz "ello, World!" + # CHECK: .globaltype __stack_pointer, i32 Index: llvm/trunk/test/MC/WebAssembly/data-section.s =================================================================== --- llvm/trunk/test/MC/WebAssembly/data-section.s +++ llvm/trunk/test/MC/WebAssembly/data-section.s @@ -0,0 +1,94 @@ +# RUN: llvm-mc -triple=wasm32-unknown-unknown -mattr=+unimplemented-simd128,+nontrapping-fptoint,+exception-handling < %s | FileCheck %s +# Check that it converts to .o without errors: +# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj -mattr=+unimplemented-simd128,+nontrapping-fptoint,+exception-handling < %s | obj2yaml | FileCheck -check-prefix=BIN %s + +# Minimal test for data sections. + +test0: + .functype test0 () -> (i32) + i32.const .L.str +.Ltestlabel: + end_function + + .section .rodata..L.str,"",@ +.L.str: + .int8 100 + .size .L.str, 1 + + +# CHECK: .text +# CHECK-LABEL: test0: +# CHECK-NEXT: .functype test0 () -> (i32) +# CHECK-NEXT: i32.const .L.str +# CHECK-NEXT: .Ltestlabel: +# CHECK-NEXT: end_function + +# CHECK: .section .rodata..L.str,"",@ +# CHECK-NEXT:.L.str: +# CHECK-NEXT: .int8 100 + + +# BIN: --- !WASM +# BIN-NEXT: FileHeader: +# BIN-NEXT: Version: 0x00000001 +# BIN-NEXT: Sections: +# BIN-NEXT: - Type: TYPE +# BIN-NEXT: Signatures: +# BIN-NEXT: - Index: 0 +# BIN-NEXT: ReturnType: I32 +# BIN-NEXT: ParamTypes: [] +# BIN-NEXT: - Type: IMPORT +# BIN-NEXT: Imports: +# BIN-NEXT: - Module: env +# BIN-NEXT: Field: __linear_memory +# BIN-NEXT: Kind: MEMORY +# BIN-NEXT: Memory: +# BIN-NEXT: Initial: 0x00000001 +# BIN-NEXT: - Module: env +# BIN-NEXT: Field: __indirect_function_table +# BIN-NEXT: Kind: TABLE +# BIN-NEXT: Table: +# BIN-NEXT: ElemType: FUNCREF +# BIN-NEXT: Limits: +# BIN-NEXT: Initial: 0x00000000 +# BIN-NEXT: - Type: FUNCTION +# BIN-NEXT: FunctionTypes: [ 0 ] +# BIN-NEXT: - Type: CODE +# BIN-NEXT: Relocations: +# BIN-NEXT: - Type: R_WASM_MEMORY_ADDR_SLEB +# BIN-NEXT: Index: 1 +# BIN-NEXT: Offset: 0x00000004 +# BIN-NEXT: Functions: +# BIN-NEXT: - Index: 0 +# BIN-NEXT: Locals: [] +# BIN-NEXT: Body: 4180808080000B +# BIN-NEXT: - Type: DATA +# BIN-NEXT: Segments: +# BIN-NEXT: - SectionOffset: 6 +# BIN-NEXT: InitFlags: 0 +# BIN-NEXT: Offset: +# BIN-NEXT: Opcode: I32_CONST +# BIN-NEXT: Value: 0 +# BIN-NEXT: Content: '64' +# BIN-NEXT: - Type: CUSTOM +# BIN-NEXT: Name: linking +# BIN-NEXT: Version: 2 +# BIN-NEXT: SymbolTable: +# BIN-NEXT: - Index: 0 +# BIN-NEXT: Kind: FUNCTION +# BIN-NEXT: Name: test0 +# BIN-NEXT: Flags: [ BINDING_LOCAL ] +# BIN-NEXT: Function: 0 +# BIN-NEXT: - Index: 1 +# BIN-NEXT: Kind: DATA +# BIN-NEXT: Name: .L.str +# BIN-NEXT: Flags: [ BINDING_LOCAL ] +# BIN-NEXT: Segment: 0 +# BIN-NEXT: Size: 1 +# BIN-NEXT: SegmentInfo: +# BIN-NEXT: - Index: 0 +# BIN-NEXT: Name: .rodata..L.str +# BIN-NEXT: Alignment: 0 +# BIN-NEXT: Flags: [ ] +# BIN-NEXT: ... +