]> granicus.if.org Git - llvm/commitdiff
[WebAssembly] Make segment/size/type directives optional in asm
authorWouter van Oortmerssen <aardappel@gmail.com>
Mon, 4 Feb 2019 18:03:11 +0000 (18:03 +0000)
committerWouter van Oortmerssen <aardappel@gmail.com>
Mon, 4 Feb 2019 18:03:11 +0000 (18:03 +0000)
Summary:
These were "boilerplate" that repeated information already present
in .functype and end_function, that needed to be repeated to Please
the particular way our object writing works, and missing them would
generate errors.

Instead, we generate the information for these automatically so the
user can concern itself with writing more canonical wasm functions
that always work as expected.

Reviewers: dschuff, sbc100

Subscribers: jgravelle-google, aheejin, sunfish, llvm-commits

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

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

lib/MC/MCParser/WasmAsmParser.cpp
lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
test/MC/WebAssembly/assembler-binary.ll
test/MC/WebAssembly/basic-assembly-errors.s
test/MC/WebAssembly/basic-assembly.s
test/MC/WebAssembly/objdump.s

index d2099be9c8c753c67318c810df5bdcac1276f77a..485be2285b0a9369d11f5c8dad45db2ba56a26dc 100644 (file)
@@ -91,8 +91,11 @@ public:
         Expect(AsmToken::Comma, ",") || Expect(AsmToken::At, "@") ||
         Expect(AsmToken::EndOfStatement, "eol"))
       return true;
-    auto WS = getContext().getWasmSection(Name, SectionKind::getText());
-    getStreamer().SwitchSection(WS);
+    // 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);
     return false;
   }
 
@@ -110,8 +113,10 @@ public:
       return true;
     if (Expect(AsmToken::EndOfStatement, "eol"))
       return true;
-    // MCWasmStreamer implements this.
-    getStreamer().emitELFSize(Sym, Expr);
+    // 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);
     return false;
   }
 
index 48af89f24aa2eb0334fba9bf1f78426fead6d6e3..a0455cb98d5f1751ff54682f6acf9733e2b46e15 100644 (file)
 #include "MCTargetDesc/WebAssemblyTargetStreamer.h"
 #include "WebAssembly.h"
 #include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCExpr.h"
 #include "llvm/MC/MCInst.h"
 #include "llvm/MC/MCInstrInfo.h"
 #include "llvm/MC/MCParser/MCParsedAsmOperand.h"
 #include "llvm/MC/MCParser/MCTargetAsmParser.h"
+#include "llvm/MC/MCSectionWasm.h"
 #include "llvm/MC/MCStreamer.h"
 #include "llvm/MC/MCSubtargetInfo.h"
 #include "llvm/MC/MCSymbol.h"
@@ -169,6 +171,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
     FunctionStart,
     FunctionLocals,
     Instructions,
+    EndFunction,
   } CurrentState = FileStart;
 
   // For ensuring blocks are properly nested.
@@ -186,6 +189,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
   // We track this to see if a .functype following a label is the same,
   // as this is how we recognize the start of a function.
   MCSymbol *LastLabel = nullptr;
+  MCSymbol *LastFunctionLabel = nullptr;
 
 public:
   WebAssemblyAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
@@ -445,6 +449,7 @@ public:
       if (pop(BaseName, Block))
         return true;
     } else if (BaseName == "end_function") {
+      CurrentState = EndFunction;
       if (pop(BaseName, Function) || ensureEmptyNestingStack())
         return true;
     }
@@ -604,6 +609,7 @@ public:
         if (ensureEmptyNestingStack())
           return true;
         CurrentState = FunctionStart;
+        LastFunctionLabel = LastLabel;
         push(Function);
       }
       auto Signature = make_unique<wasm::WasmSignature>();
@@ -666,8 +672,12 @@ public:
             *Out.getTargetStreamer());
         TOut.emitLocal(SmallVector<wasm::ValType, 0>());
       }
-      CurrentState = Instructions;
       Out.EmitInstruction(Inst, getSTI());
+      if (CurrentState == EndFunction) {
+        onEndOfFunction();
+      } else {
+        CurrentState = Instructions;
+      }
       return false;
     }
     case Match_MissingFeature:
@@ -693,6 +703,30 @@ public:
     llvm_unreachable("Implement any new match types added!");
   }
 
+  void doBeforeLabelEmit(MCSymbol *Symbol) override {
+    // Start a new section for the next function automatically, since our
+    // object writer expects each function to have its own section. This way
+    // The user can't forget this "convention".
+    auto SymName = Symbol->getName();
+    if (SymName.startswith(".L"))
+      return; // Local Symbol.
+    auto SecName = ".text." + SymName;
+    auto WS = getContext().getWasmSection(SecName, SectionKind::getText());
+    getStreamer().SwitchSection(WS);
+  }
+
+  void onEndOfFunction() {
+    // Automatically output a .size directive, so it becomes optional for the
+    // user.
+    auto TempSym = getContext().createLinkerPrivateTempSymbol();
+    getStreamer().EmitLabel(TempSym);
+    auto Start = MCSymbolRefExpr::create(LastLabel, getContext());
+    auto End = MCSymbolRefExpr::create(TempSym, getContext());
+    auto Expr =
+        MCBinaryExpr::create(MCBinaryExpr::Sub, End, Start, getContext());
+    getStreamer().emitELFSize(LastFunctionLabel, Expr);
+  }
+
   void onEndOfFile() override { ensureEmptyNestingStack(); }
 };
 } // end anonymous namespace
index d5d594a24e09dd369925509982e29a1f033238b3..35bd3a88646cbf0118fdb616bb4f842f565e4a3c 100644 (file)
@@ -28,8 +28,6 @@ entry:
 ; ASM-NEXT:    .functype       foo (i32) -> ()
 ; ASM-NEXT:    call    bar@FUNCTION
 ; ASM-NEXT:    end_function
-; ASM-NEXT: .Lfunc_end0:
-; ASM-NEXT:    .size   foo, .Lfunc_end0-foo
 ; ASM:         .functype       bar () -> ()
 
 
index 06fc4f85e7cbc7787de7e44e7cbf6322cceab031..eead082e93f7a222834e96b2a2f3959400a95d48 100644 (file)
@@ -1,8 +1,5 @@
 # RUN: not llvm-mc -triple=wasm32-unknown-unknown -mattr=+simd128,+nontrapping-fptoint,+exception-handling < %s 2>&1 | FileCheck %s
 
-    .text
-    .section    .text.main,"",@
-    .type       test0,@function
 # CHECK: End of block construct with no start: end_try
     end_try
 test0:
@@ -20,6 +17,4 @@ test0:
 # CHECK: error: Unmatched block construct(s) at function end: block
 # CHECK: error: Unmatched block construct(s) at function end: function
     end_function
-.Lfunc_end0:
-    .size       test0, .Lfunc_end0-test0
 
index e5f2f5f61b0106a6090227a500a0da30daf1cee1..85da7819f9b9078dda21ec877d36b255fa25290d 100644 (file)
@@ -2,9 +2,6 @@
 # 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=+unimplemented-simd128,+nontrapping-fptoint,+exception-handling < %s
 
-    .text
-    .section .text.main,"",@
-    .type    test0,@function
 test0:
     # Test all types:
     .functype   test0 (i32, i64) -> (i32)
@@ -86,8 +83,6 @@ test0:
     #i32.trunc_sat_f32_s
     global.get  __stack_pointer@GLOBAL
     end_function
-.Lfunc_end0:
-    .size      test0, .Lfunc_end0-test0
     .globaltype        __stack_pointer, i32
 
 # CHECK:           .text
index fc8717492201c0344e017b0643d75572e073b4bb..d156ec60eefa7562fab13531fcf4286635837b8f 100644 (file)
@@ -1,25 +1,17 @@
 # RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj -o %t.o -mattr=+simd128,+nontrapping-fptoint,+exception-handling < %s
 # RUN: llvm-objdump -triple=wasm32-unknown-unknown -disassemble %t.o | FileCheck %s
 
-    .section .text.main1,"",@
-    .type    test0,@function
 test0:
     .functype   test0 (i32, i64) -> (i32)
     .local      f32, f64, v128, v128
     local.get   2
     end_function
-.Lfunc_end0:
-    .size      test0, .Lfunc_end0-test0
 
-    .section .text.main2,"",@
-    .type    test1,@function
 test1:
     .functype   test1 (i32, i64) -> (i32)
     .local      i32, i64, except_ref
     local.get   3
     end_function
-.Lfunc_end1:
-    .size      test1, .Lfunc_end1-test1
 
 
 # CHECK-LABEL: CODE: