Only export functions with default visibility

As discussed in #585, this change makes s2wasm more aware of the
symbol visibility output from LLVM, and only exports global functions
with default visibility (instead of all globals as before).
diff --git a/src/s2wasm.h b/src/s2wasm.h
index bf66f44..5eae659 100644
--- a/src/s2wasm.h
+++ b/src/s2wasm.h
@@ -399,7 +399,10 @@
       s++;
       if (match("text")) parseText();
       else if (match("type")) parseType();
-      else if (match("weak") || match("hidden") || match("protected") || match("internal")) getStr(); // contents are in the content that follows
+      else if (match("weak")) getStr(); // contents are in the content that follows
+      else if (match("hidden")) parseVisibility(LinkerObject::Visibility::kHidden);
+      else if (match("internal")) parseVisibility(LinkerObject::Visibility::kInternal);
+      else if (match("protected")) parseVisibility(LinkerObject::Visibility::kProtected);
       else if (match("imports")) skipImports();
       else if (match("data")) {}
       else if (match("ident")) skipToEOL();
@@ -481,6 +484,10 @@
     WASM_UNUSED(filename); // TODO: use the filename
   }
 
+  void parseVisibility(LinkerObject::Visibility vis) {
+    linkerObj->setVisibility(getStr(), vis);
+    skipWhitespace();
+  }
   void parseGlobl() {
     linkerObj->addGlobal(getStr());
     skipWhitespace();
diff --git a/src/wasm-linker.cpp b/src/wasm-linker.cpp
index e6a0a05..fe95b97 100644
--- a/src/wasm-linker.cpp
+++ b/src/wasm-linker.cpp
@@ -115,8 +115,17 @@
   if (userMaxMemory) out.wasm.memory.max = userMaxMemory / Memory::kPageSize;
   out.wasm.memory.exportName = MEMORY;
 
-  // XXX For now, export all functions marked .globl.
-  for (Name name : out.globls) exportFunction(name, false);
+  // Export all globl functions with default visibility. Since .s files usually
+  // only output visibility information if it is not default, symbols are
+  // considered to have default visibility if they are not in the visibility table.
+  // Also export main for now because emscripten and the binaryen-shell tests use it.
+  for (Name name : out.globls) {
+    if (out.visibilities.count(name) == 0 ||
+        out.visibilities.at(name) == LinkerObject::Visibility::kDefault ||
+        name == "main") {
+      exportFunction(name, false);
+    }
+  }
   for (Name name : out.initializerFunctions) exportFunction(name, true);
 
   auto ensureFunctionIndex = [this](Name name) {
diff --git a/src/wasm-linker.h b/src/wasm-linker.h
index 97e1c9c..808b892 100644
--- a/src/wasm-linker.h
+++ b/src/wasm-linker.h
@@ -67,6 +67,7 @@
                               other.aliasedFunctions.end());
     }
   };
+  enum class Visibility { kDefault, kInternal, kHidden, kProtected };
 
   LinkerObject() {}
 
@@ -75,6 +76,9 @@
     staticObjects.emplace_back(allocSize, alignment, name);
   }
 
+  void setVisibility(Name name, Visibility vis) {
+    visibilities[name] = vis;
+  }
   void addGlobal(Name name) {
     globls.push_back(name);
   }
@@ -145,6 +149,7 @@
         allocSize(allocSize), alignment(alignment), name(name) {}
   };
 
+  std::unordered_map<cashew::IString, LinkerObject::Visibility> visibilities;
   std::vector<Name> globls;
 
   std::vector<StaticObject> staticObjects;
diff --git a/test/dot_s/alias.wast b/test/dot_s/alias.wast
index d1e08e1..0bbd414 100644
--- a/test/dot_s/alias.wast
+++ b/test/dot_s/alias.wast
@@ -2,8 +2,6 @@
   (memory 1)
   (export "memory" memory)
   (type $FUNCSIG$v (func))
-  (export "__exit" $__exit)
-  (export "__needs_exit" $__needs_exit)
   (export "dynCall_v" $dynCall_v)
   (table $__exit)
   (func $__exit (type $FUNCSIG$v)
diff --git a/test/dot_s/bcp-1.wast b/test/dot_s/bcp-1.wast
index 0525be4..2e94f22 100644
--- a/test/dot_s/bcp-1.wast
+++ b/test/dot_s/bcp-1.wast
@@ -15,23 +15,6 @@
   (type $FUNCSIG$vi (func (param i32)))
   (import $abort "env" "abort")
   (import $exit "env" "exit" (param i32))
-  (export "bad0" $bad0)
-  (export "bad1" $bad1)
-  (export "bad2" $bad2)
-  (export "bad3" $bad3)
-  (export "bad4" $bad4)
-  (export "bad5" $bad5)
-  (export "bad6" $bad6)
-  (export "bad7" $bad7)
-  (export "bad8" $bad8)
-  (export "bad9" $bad9)
-  (export "bad10" $bad10)
-  (export "good0" $good0)
-  (export "good1" $good1)
-  (export "good2" $good2)
-  (export "opt0" $opt0)
-  (export "opt1" $opt1)
-  (export "opt2" $opt2)
   (export "main" $main)
   (export "dynCall_i" $dynCall_i)
   (export "dynCall_ii" $dynCall_ii)
diff --git a/test/dot_s/debug.wast b/test/dot_s/debug.wast
index 3a859fd..d17be66 100644
--- a/test/dot_s/debug.wast
+++ b/test/dot_s/debug.wast
@@ -1,7 +1,6 @@
 (module
   (memory 1)
   (export "memory" memory)
-  (export "fib" $fib)
   (func $fib (param $0 i32) (result i32)
     (local $1 i32)
     (local $2 i32)
diff --git a/test/dot_s/dyncall.wast b/test/dot_s/dyncall.wast
index b0521de..9cb81ed 100644
--- a/test/dot_s/dyncall.wast
+++ b/test/dot_s/dyncall.wast
@@ -5,11 +5,6 @@
   (type $FUNCSIG$if (func (param f32) (result i32)))
   (type $FUNCSIG$vd (func (param f64)))
   (type $FUNCSIG$ffjjdi (func (param f32 i64 i64 f64 i32) (result f32)))
-  (export "i" $i)
-  (export "i_f" $i_f)
-  (export "vd" $vd)
-  (export "ffjjdi" $ffjjdi)
-  (export "vd2" $vd2)
   (export "main" $main)
   (export "dynCall_i" $dynCall_i)
   (export "dynCall_if" $dynCall_if)
diff --git a/test/dot_s/indirect-import.wast b/test/dot_s/indirect-import.wast
index 21378ee..2eb506f 100644
--- a/test/dot_s/indirect-import.wast
+++ b/test/dot_s/indirect-import.wast
@@ -12,8 +12,6 @@
   (import $extern_fd "env" "extern_fd" (param f64) (result f32))
   (import $extern_struct "env" "extern_struct" (param i32))
   (import $extern_sret "env" "extern_sret" (param i32))
-  (export "bar" $bar)
-  (export "baz" $baz)
   (export "dynCall_fd" $dynCall_fd)
   (export "dynCall_v" $dynCall_v)
   (export "dynCall_vi" $dynCall_vi)
diff --git a/test/dot_s/visibilities.wast b/test/dot_s/visibilities.wast
index cfd5040..5879190 100644
--- a/test/dot_s/visibilities.wast
+++ b/test/dot_s/visibilities.wast
@@ -1,9 +1,6 @@
 (module
   (memory 1)
   (export "memory" memory)
-  (export "foo" $foo)
-  (export "bar" $bar)
-  (export "qux" $qux)
   (func $foo
     (return)
   )
diff --git a/test/llvm_autogenerated/reg-stackify.wast b/test/llvm_autogenerated/reg-stackify.wast
index eea7e8b..652b078 100644
--- a/test/llvm_autogenerated/reg-stackify.wast
+++ b/test/llvm_autogenerated/reg-stackify.wast
@@ -31,7 +31,6 @@
   (export "no_sink_readonly_call" $no_sink_readonly_call)
   (export "stack_uses" $stack_uses)
   (export "multiple_uses" $multiple_uses)
-  (export "stackify_store_across_side_effects" $stackify_store_across_side_effects)
   (export "div_tree" $div_tree)
   (export "simple_multiple_use" $simple_multiple_use)
   (export "multiple_uses_in_same_insn" $multiple_uses_in_same_insn)
diff --git a/test/llvm_autogenerated/store-results.wast b/test/llvm_autogenerated/store-results.wast
index dd974db..f67c4d8 100644
--- a/test/llvm_autogenerated/store-results.wast
+++ b/test/llvm_autogenerated/store-results.wast
@@ -6,7 +6,6 @@
   (export "single_block" $single_block)
   (export "foo" $foo)
   (export "bar" $bar)
-  (export "fi_ret" $fi_ret)
   (func $single_block (param $0 i32) (result i32)
     (return
       (i32.store