summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xcheck.py5
-rw-r--r--src/emscripten-optimizer/istring.h4
-rw-r--r--src/s2wasm-main.cpp8
-rw-r--r--src/s2wasm.h49
-rw-r--r--src/shared-constants.h1
-rw-r--r--src/wasm-s-parser.h3
-rw-r--r--src/wasm.h8
-rw-r--r--test/dot_s/start_main0.s8
-rw-r--r--test/dot_s/start_main0.wast12
-rw-r--r--test/dot_s/start_main2.s11
-rw-r--r--test/dot_s/start_main2.wast20
11 files changed, 121 insertions, 8 deletions
diff --git a/check.py b/check.py
index 22acc0228..495abfe50 100755
--- a/check.py
+++ b/check.py
@@ -408,7 +408,10 @@ for dot_s_dir in ['dot_s', 'llvm_autogenerated']:
print '..', s
wasm = s.replace('.s', '.wast')
full = os.path.join('test', dot_s_dir, s)
- actual, err = subprocess.Popen([os.path.join('bin', 's2wasm'), full], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
+ cmd = [os.path.join('bin', 's2wasm'), full]
+ if s.startswith('start_'):
+ cmd.append('--start')
+ actual, err = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
assert err == '', 'bad err:' + err
# verify output
diff --git a/src/emscripten-optimizer/istring.h b/src/emscripten-optimizer/istring.h
index d114540e2..abc1e327b 100644
--- a/src/emscripten-optimizer/istring.h
+++ b/src/emscripten-optimizer/istring.h
@@ -114,8 +114,8 @@ struct IString {
const char *c_str() const { return str; }
bool equals(const char *other) const { return !strcmp(str, other); }
- bool is() { return str != nullptr; }
- bool isNull() { return str == nullptr; }
+ bool is() const { return str != nullptr; }
+ bool isNull() const { return str == nullptr; }
};
} // namespace cashew
diff --git a/src/s2wasm-main.cpp b/src/s2wasm-main.cpp
index e75147b75..03321a608 100644
--- a/src/s2wasm-main.cpp
+++ b/src/s2wasm-main.cpp
@@ -28,6 +28,7 @@ using namespace wasm;
int main(int argc, const char *argv[]) {
bool ignoreUnknownSymbols = false;
+ std::string startFunction;
Options options("s2wasm", "Link .s file into .wast");
options
.add("--output", "-o", "Output file (stdout if not specified)",
@@ -41,6 +42,11 @@ int main(int argc, const char *argv[]) {
[&ignoreUnknownSymbols](Options *, const std::string &) {
ignoreUnknownSymbols = true;
})
+ .add("--start", "", "Generate the start method (default: main)",
+ Options::Arguments::Optional,
+ [&startFunction](Options *, const std::string &argument) {
+ startFunction = argument.size() ? argument : "main";
+ })
.add("--global-base", "-g", "Where to start to place globals",
Options::Arguments::One,
[](Options *o, const std::string &argument) {
@@ -70,7 +76,7 @@ int main(int argc, const char *argv[]) {
: 0;
if (options.debug) std::cerr << "Global base " << globalBase << '\n';
S2WasmBuilder s2wasm(wasm, input.c_str(), options.debug, globalBase,
- stackAllocation, ignoreUnknownSymbols);
+ stackAllocation, ignoreUnknownSymbols, startFunction);
if (options.debug) std::cerr << "Emscripten gluing..." << std::endl;
std::stringstream meta;
diff --git a/src/s2wasm.h b/src/s2wasm.h
index 1e0a28b43..275cf6a9c 100644
--- a/src/s2wasm.h
+++ b/src/s2wasm.h
@@ -39,15 +39,17 @@ class S2WasmBuilder {
const char* s;
bool debug;
bool ignoreUnknownSymbols;
+ Name startFunction;
public:
S2WasmBuilder(AllocatingModule& wasm, const char* input, bool debug,
size_t globalBase, size_t stackAllocation,
- bool ignoreUnknownSymbols)
+ bool ignoreUnknownSymbols, Name startFunction)
: wasm(wasm),
allocator(wasm.allocator),
debug(debug),
ignoreUnknownSymbols(ignoreUnknownSymbols),
+ startFunction(startFunction),
globalBase(globalBase),
nextStatic(globalBase) {
s = input;
@@ -722,7 +724,7 @@ class S2WasmBuilder {
Name target = cleanFunction(getCommaSeparated());
auto aliased = aliasedFunctions.find(target);
if (aliased != aliasedFunctions.end()) target = aliased->second;
- if (implementedFunctions.count(target) > 0) {
+ if (implementedFunctions.count(target) != 0) {
auto specific = allocator.alloc<Call>();
specific->target = target;
curr = specific;
@@ -1171,13 +1173,16 @@ class S2WasmBuilder {
if (functionIndexes.count(name) == 0) {
functionIndexes[name] = wasm.table.names.size();
wasm.table.names.push_back(name);
- if (debug) std::cerr << "function index: " << name << ": " << functionIndexes[name] << '\n';
+ if (debug) {
+ std::cerr << "function index: " << name << ": "
+ << functionIndexes[name] << '\n';
+ }
}
};
for (auto& relocation : relocations) {
Name name = relocation.value;
if (debug) std::cerr << "fix relocation " << name << '\n';
- const auto &symbolAddress = staticAddresses.find(name);
+ const auto& symbolAddress = staticAddresses.find(name);
if (symbolAddress != staticAddresses.end()) {
*(relocation.data) = symbolAddress->second + relocation.offset;
if (debug) std::cerr << " ==> " << *(relocation.data) << '\n';
@@ -1193,6 +1198,42 @@ class S2WasmBuilder {
}
}
}
+ if (!!startFunction) {
+ if (implementedFunctions.count(startFunction) == 0) {
+ std::cerr << "Unknown start function: `" << startFunction << "`\n";
+ abort();
+ }
+ const auto *target = wasm.functionsMap[startFunction];
+ Name start("_start");
+ if (implementedFunctions.count(start) != 0) {
+ std::cerr << "Start function already present: `" << start << "`\n";
+ abort();
+ }
+ auto* func = allocator.alloc<Function>();
+ func->name = start;
+ wasm.addFunction(func);
+ auto* exp = allocator.alloc<Export>();
+ exp->name = exp->value = start;
+ wasm.addExport(exp);
+ wasm.addStart(start);
+ auto* block = allocator.alloc<Block>();
+ func->body = block;
+ { // Create the call, matching its parameters.
+ // TODO allow calling with non-default values.
+ auto* call = allocator.alloc<Call>();
+ call->target = startFunction;
+ size_t paramNum = 0;
+ for (const NameType& nt : target->params) {
+ Name name = Name::fromInt(paramNum++);
+ func->locals.emplace_back(name, nt.type);
+ auto* param = allocator.alloc<GetLocal>();
+ param->name = name;
+ param->type = nt.type;
+ call->operands.push_back(param);
+ }
+ block->list.push_back(call);
+ }
+ }
}
template<class C>
diff --git a/src/shared-constants.h b/src/shared-constants.h
index a928756da..6662c50b2 100644
--- a/src/shared-constants.h
+++ b/src/shared-constants.h
@@ -52,6 +52,7 @@ cashew::IString GLOBAL("global"),
GROW_WASM_MEMORY("__growWasmMemory"),
NEW_SIZE("newSize"),
MODULE("module"),
+ START("start"),
FUNC("func"),
PARAM("param"),
RESULT("result"),
diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h
index 1c704ac74..e2a880e51 100644
--- a/src/wasm-s-parser.h
+++ b/src/wasm-s-parser.h
@@ -283,6 +283,7 @@ private:
void parseModuleElement(Element& curr) {
IString id = curr[0]->str();
+ if (id == START) return parseStart(curr);
if (id == FUNC) return parseFunction(curr);
if (id == MEMORY) return parseMemory(curr);
if (id == EXPORT) return parseExport(curr);
@@ -304,6 +305,8 @@ private:
return IString((prefix + std::to_string(otherIndex++)).c_str(), false);
}
+ void parseStart(Element& s) { wasm.addStart(s[1]->str()); }
+
void parseFunction(Element& s) {
auto func = currFunction = allocator.alloc<Function>();
size_t i = 1;
diff --git a/src/wasm.h b/src/wasm.h
index c030d9d60..b9d0d6822 100644
--- a/src/wasm.h
+++ b/src/wasm.h
@@ -1125,6 +1125,7 @@ public:
std::map<Name, Function*> functionsMap;
Table table;
Memory memory;
+ Name start;
Module() : functionTypeIndex(0), importIndex(0), exportIndex(0), functionIndex(0) {}
@@ -1168,6 +1169,9 @@ public:
functionsMap[numericName] = curr;
functionIndex++;
}
+ void addStart(const Name &s) {
+ start = s;
+ }
void removeImport(Name name) {
for (size_t i = 0; i < imports.size(); i++) {
@@ -1211,6 +1215,10 @@ public:
o << "\")";
}
o << (module.memory.segments.size() > 0 ? "\n " : "") << ")\n";
+ if (module.start.is()) {
+ doIndent(o, indent);
+ printOpening(o, "start") << " " << module.start << ")\n";
+ }
for (auto& curr : module.functionTypes) {
doIndent(o, indent);
curr->print(o, indent, true);
diff --git a/test/dot_s/start_main0.s b/test/dot_s/start_main0.s
new file mode 100644
index 000000000..85323ee62
--- /dev/null
+++ b/test/dot_s/start_main0.s
@@ -0,0 +1,8 @@
+ .text
+ .file "main0"
+ .globl main
+ .type main,@function
+main: # @main
+# BB#0:
+.Lfunc_end0:
+ .size main, .Lfunc_end0-main
diff --git a/test/dot_s/start_main0.wast b/test/dot_s/start_main0.wast
new file mode 100644
index 000000000..d40390aee
--- /dev/null
+++ b/test/dot_s/start_main0.wast
@@ -0,0 +1,12 @@
+(module
+ (memory 0 4294967295)
+ (start $_start)
+ (export "main" $main)
+ (export "_start" $_start)
+ (func $main
+ )
+ (func $_start
+ (call $main)
+ )
+)
+;; METADATA: { "asmConsts": {},"staticBump": 4 }
diff --git a/test/dot_s/start_main2.s b/test/dot_s/start_main2.s
new file mode 100644
index 000000000..7f77ec463
--- /dev/null
+++ b/test/dot_s/start_main2.s
@@ -0,0 +1,11 @@
+ .text
+ .file "main2"
+ .globl main
+ .type main,@function
+main: # @main
+ .param i32, i32
+ .result i32
+# BB#0:
+ return $0
+.Lfunc_end0:
+ .size main, .Lfunc_end0-main
diff --git a/test/dot_s/start_main2.wast b/test/dot_s/start_main2.wast
new file mode 100644
index 000000000..42e8b4897
--- /dev/null
+++ b/test/dot_s/start_main2.wast
@@ -0,0 +1,20 @@
+(module
+ (memory 0 4294967295)
+ (start $_start)
+ (export "main" $main)
+ (export "_start" $_start)
+ (func $main (param $$0 i32) (param $$1 i32) (result i32)
+ (return
+ (get_local $$0)
+ )
+ )
+ (func $_start
+ (local $0 i32)
+ (local $1 i32)
+ (call $main
+ (get_local $0)
+ (get_local $1)
+ )
+ )
+)
+;; METADATA: { "asmConsts": {},"staticBump": 4 }