]> granicus.if.org Git - llvm/commitdiff
[WebAssembly] Add support for data sections in the assembler.
authorWouter van Oortmerssen <aardappel@gmail.com>
Mon, 4 Mar 2019 17:18:04 +0000 (17:18 +0000)
committerWouter van Oortmerssen <aardappel@gmail.com>
Mon, 4 Mar 2019 17:18:04 +0000 (17:18 +0000)
Summary:
This is quite minimal so far, introduce them with .section,
fill them with .int8 or .asciz, end with .size

Reviewers: dschuff, sbc100, aheejin

Subscribers: jgravelle-google, sunfish, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D58660

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@355321 91177308-0d34-0410-b5e6-96231b3b80d8

lib/MC/MCParser/WasmAsmParser.cpp
lib/MC/WasmObjectWriter.cpp
lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
test/MC/WebAssembly/basic-assembly.s
test/MC/WebAssembly/data-section.s [new file with mode: 0644]

index a8a48d1cd69a86ea97285e5aae8ae93b6d81fc51..197e90525661183044f0b0cecf1bbd9cf94b5715 100644 (file)
@@ -130,11 +130,27 @@ public:
     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 @@ public:
     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 b985d4bf4d36cb759f77d10d477a7da899131dc4..e82ed5898b49e00b7d54dec0f21c5baa9d2bf331 100644 (file)
@@ -1348,7 +1348,7 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
       LLVM_DEBUG(dbgs() << "  -> function index: " << Index << "\n");
 
     } else if (WS.isData()) {
-      if (WS.isTemporary() && !WS.getSize())
+      if (!isInSymtab(WS))
         continue;
 
       if (!WS.isDefined()) {
index eeccc3e64495faf98c049a523be255de1fd13137..9d5bb3f11e0f3da8fc5c4c986d6ec3306910e6b8 100644 (file)
@@ -172,6 +172,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
     FunctionLocals,
     Instructions,
     EndFunction,
+    DataSection,
   } CurrentState = FileStart;
 
   // For ensuring blocks are properly nested.
@@ -552,6 +553,17 @@ public:
     return false;
   }
 
+  bool CheckDataSection() {
+    if (CurrentState != DataSection) {
+      auto WS = cast<MCSectionWasm>(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 @@ public:
       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<uint64_t>(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 @@ public:
   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 85cd05a0eaf5e95330bfa40de960a739603bb3a4..ec88cf6bbdcba32b8e0aa521a94416b1439a6b82 100644 (file)
@@ -77,12 +77,19 @@ test0:
 .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 @@ test0:
 # 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
diff --git a/test/MC/WebAssembly/data-section.s b/test/MC/WebAssembly/data-section.s
new file mode 100644 (file)
index 0000000..d4ddd3d
--- /dev/null
@@ -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: ...
+