summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/c-writer.cc134
-rw-r--r--src/prebuilt/wasm2c.include.c4
-rw-r--r--src/wasm2c.c.tmpl4
3 files changed, 115 insertions, 27 deletions
diff --git a/src/c-writer.cc b/src/c-writer.cc
index 6ed61de8..19b7f3f1 100644
--- a/src/c-writer.cc
+++ b/src/c-writer.cc
@@ -49,7 +49,7 @@ struct Label {
used(used) {}
bool HasValue() const {
- return label_type != LabelType::Loop && !sig.empty();
+ return !sig.empty();
}
LabelType label_type;
@@ -163,6 +163,7 @@ class CWriter {
static char MangleType(Type);
static std::string MangleTypes(const TypeVector&);
+ static std::string MangleMultivalueTypes(const TypeVector&);
static std::string MangleName(string_view);
static std::string MangleFuncName(string_view,
const TypeVector& param_types,
@@ -222,6 +223,7 @@ class CWriter {
void WriteInitExpr(const ExprList&);
std::string GenerateHeaderGuard() const;
void WriteSourceTop();
+ void WriteMultivalueTypes();
void WriteFuncTypes();
void WriteImports();
void WriteFuncDeclarations();
@@ -333,14 +335,12 @@ void CWriter::PushLabel(LabelType label_type,
const std::string& name,
const FuncSignature& sig,
bool used) {
- // TODO(binji): Add multi-value support.
- if ((label_type != LabelType::Func && sig.GetNumParams() != 0) ||
- sig.GetNumResults() > 1) {
- UNIMPLEMENTED("multi value support");
- }
-
- label_stack_.emplace_back(label_type, name, sig.result_types,
- type_stack_.size(), used);
+ if (label_type == LabelType::Loop)
+ label_stack_.emplace_back(label_type, name, sig.param_types,
+ type_stack_.size(), used);
+ else
+ label_stack_.emplace_back(label_type, name, sig.result_types,
+ type_stack_.size(), used);
}
const Label* CWriter::FindLabel(const Var& var) {
@@ -409,6 +409,16 @@ std::string CWriter::MangleTypes(const TypeVector& types) {
}
// static
+std::string CWriter::MangleMultivalueTypes(const TypeVector& types) {
+ assert(types.size() >= 2);
+ std::string result = "wasm_multi_";
+ for (auto type : types) {
+ result += MangleType(type);
+ }
+ return result;
+}
+
+// static
std::string CWriter::MangleName(string_view name) {
const char kPrefix = 'Z';
std::string result = "Z_";
@@ -619,11 +629,16 @@ void CWriter::Write(const Var& var) {
void CWriter::Write(const GotoLabel& goto_label) {
const Label* label = FindLabel(goto_label.var);
if (label->HasValue()) {
- assert(label->sig.size() == 1);
+ size_t amount = label->sig.size();
assert(type_stack_.size() >= label->type_stack_size);
- Index dst = type_stack_.size() - label->type_stack_size - 1;
- if (dst != 0)
- Write(StackVar(dst, label->sig[0]), " = ", StackVar(0), "; ");
+ assert(type_stack_.size() >= amount);
+ assert(type_stack_.size() - amount >= label->type_stack_size);
+ Index offset = type_stack_.size() - label->type_stack_size - amount;
+ if (offset != 0) {
+ for (Index i = 0; i < amount; ++i) {
+ Write(StackVar(amount - i - 1 + offset, label->sig[i]), " = ", StackVar(amount - i - 1), "; ");
+ }
+ }
}
if (goto_label.var.is_name()) {
@@ -696,10 +711,12 @@ void CWriter::Write(SignedType type) {
}
void CWriter::Write(const ResultType& rt) {
- if (!rt.types.empty()) {
+ if (rt.types.empty()) {
+ Write("void");
+ } else if (rt.types.size() == 1) {
Write(rt.types[0]);
} else {
- Write("void");
+ Write("struct ", MangleMultivalueTypes(rt.types));
}
}
@@ -804,6 +821,30 @@ void CWriter::WriteSourceTop() {
Write(s_source_declarations);
}
+void CWriter::WriteMultivalueTypes() {
+ for (TypeEntry* type : module_->types) {
+ FuncType* func_type = cast<FuncType>(type);
+ Index num_results = func_type->GetNumResults();
+ if (num_results <= 1) {
+ continue;
+ }
+ std::string name = MangleMultivalueTypes(func_type->sig.result_types);
+ // these ifndefs are actually to support importing multiple modules
+ // incidentally they also mean we don't have to bother with deduplication
+ Write("#ifndef ", name, Newline());
+ Write("#define ", name, " ", name, Newline());
+ Write("struct ", name, " {", Newline());
+ for (Index i = 0; i < num_results; ++i) {
+ Type type = func_type->GetResultType(i);
+ Write(" ", type);
+ Writef(" %c%d;", MangleType(type), i);
+ Write(Newline());
+ }
+ Write("};", Newline(), "#endif /* ", name, " */", Newline());
+ }
+}
+
+
void CWriter::WriteFuncTypes() {
Write(Newline());
Writef("static u32 func_types[%" PRIzd "];", module_->types.size());
@@ -1211,9 +1252,20 @@ void CWriter::Write(const Func& func) {
PushTypes(func.decl.sig.result_types);
Write("FUNC_EPILOGUE;", Newline());
- if (!func.decl.sig.result_types.empty()) {
- // Return the top of the stack implicitly.
+ // Return the top of the stack implicitly.
+ Index num_results = func.GetNumResults();
+ if (num_results == 1) {
Write("return ", StackVar(0), ";", Newline());
+ } else if (num_results >= 2) {
+ Write(OpenBrace());
+ Write(ResultType(func.decl.sig.result_types), " tmp;", Newline());
+ for (Index i = 0; i < num_results; ++i) {
+ Type type = func.GetResultType(i);
+ Writef("tmp.%c%d = ", MangleType(type), i);
+ Write(StackVar(num_results - i - 1), ";", Newline());
+ }
+ Write("return tmp;", Newline());
+ Write(CloseBrace(), Newline());
}
stream_ = c_stream_;
@@ -1323,8 +1375,10 @@ void CWriter::Write(const ExprList& exprs) {
case ExprType::Block: {
const Block& block = cast<BlockExpr>(&expr)->block;
std::string label = DefineLocalScopeName(block.label);
+ DropTypes(block.decl.GetNumParams());
size_t mark = MarkTypeStack();
PushLabel(LabelType::Block, block.label, block.decl.sig);
+ PushTypes(block.decl.sig.param_types);
Write(block.exprs, LabelDecl(label));
ResetTypeStack(mark);
PopLabel();
@@ -1364,8 +1418,11 @@ void CWriter::Write(const ExprList& exprs) {
Index num_params = func.GetNumParams();
Index num_results = func.GetNumResults();
assert(type_stack_.size() >= num_params);
- if (num_results > 0) {
- assert(num_results == 1);
+ if (num_results > 1) {
+ Write(OpenBrace());
+ Write("struct ", MangleMultivalueTypes(func.decl.sig.result_types));
+ Write(" tmp = ");
+ } else if (num_results == 1) {
Write(StackVar(num_params - 1, func.GetResultType(0)), " = ");
}
@@ -1378,7 +1435,18 @@ void CWriter::Write(const ExprList& exprs) {
}
Write(");", Newline());
DropTypes(num_params);
- PushTypes(func.decl.sig.result_types);
+ if (num_results > 1) {
+ for (Index i = 0; i < num_results; ++i) {
+ Type type = func.GetResultType(i);
+ PushType(type);
+ Write(StackVar(0));
+ Writef(" = tmp.%c%d;", MangleType(type), i);
+ Write(Newline());
+ }
+ Write(CloseBrace(), Newline());
+ } else {
+ PushTypes(func.decl.sig.result_types);
+ }
break;
}
@@ -1387,8 +1455,11 @@ void CWriter::Write(const ExprList& exprs) {
Index num_params = decl.GetNumParams();
Index num_results = decl.GetNumResults();
assert(type_stack_.size() > num_params);
- if (num_results > 0) {
- assert(num_results == 1);
+ if (num_results > 1) {
+ Write(OpenBrace());
+ Write("struct ", MangleMultivalueTypes(decl.sig.result_types));
+ Write(" tmp = ");
+ } else if (num_results == 1) {
Write(StackVar(num_params, decl.GetResultType(0)), " = ");
}
@@ -1406,7 +1477,18 @@ void CWriter::Write(const ExprList& exprs) {
}
Write(");", Newline());
DropTypes(num_params + 1);
- PushTypes(decl.sig.result_types);
+ if (num_results > 1) {
+ for (Index i = 0; i < num_results; ++i) {
+ Type type = decl.GetResultType(i);
+ PushType(type);
+ Write(StackVar(0));
+ Writef(" = tmp.%c%d;", MangleType(type), i);
+ Write(Newline());
+ }
+ Write(CloseBrace(), Newline());
+ } else {
+ PushTypes(decl.sig.result_types);
+ }
break;
}
@@ -1448,11 +1530,14 @@ void CWriter::Write(const ExprList& exprs) {
Write("if (", StackVar(0), ") ", OpenBrace());
DropTypes(1);
std::string label = DefineLocalScopeName(if_.true_.label);
+ DropTypes(if_.true_.decl.GetNumParams());
size_t mark = MarkTypeStack();
PushLabel(LabelType::If, if_.true_.label, if_.true_.decl.sig);
+ PushTypes(if_.true_.decl.sig.param_types);
Write(if_.true_.exprs, CloseBrace());
if (!if_.false_.empty()) {
ResetTypeStack(mark);
+ PushTypes(if_.true_.decl.sig.param_types);
Write(" else ", OpenBrace(), if_.false_, CloseBrace());
}
ResetTypeStack(mark);
@@ -1491,8 +1576,10 @@ void CWriter::Write(const ExprList& exprs) {
if (!block.exprs.empty()) {
Write(DefineLocalScopeName(block.label), ": ");
Indent();
+ DropTypes(block.decl.GetNumParams());
size_t mark = MarkTypeStack();
PushLabel(LabelType::Loop, block.label, block.decl.sig);
+ PushTypes(block.decl.sig.param_types);
Write(Newline(), block.exprs);
ResetTypeStack(mark);
PopLabel();
@@ -2263,6 +2350,7 @@ void CWriter::WriteCHeader() {
Write("#ifndef ", guard, Newline());
Write("#define ", guard, Newline());
Write(s_header_top);
+ WriteMultivalueTypes();
WriteImports();
WriteExports(WriteExportsKind::Declarations);
Write(s_header_bottom);
diff --git a/src/prebuilt/wasm2c.include.c b/src/prebuilt/wasm2c.include.c
index e1002734..3ac83a69 100644
--- a/src/prebuilt/wasm2c.include.c
+++ b/src/prebuilt/wasm2c.include.c
@@ -22,8 +22,8 @@ const char SECTION_NAME(declarations)[] =
"#define CALL_INDIRECT(table, t, ft, x, ...) \\\n"
" (LIKELY((x) < table.size && table.data[x].func && \\\n"
" table.data[x].func_type == func_types[ft]) \\\n"
-" ? ((t)table.data[x].func)(__VA_ARGS__) \\\n"
-" : TRAP(CALL_INDIRECT))\n"
+" || TRAP(CALL_INDIRECT) \\\n"
+" , ((t)table.data[x].func)(__VA_ARGS__))\n"
"\n"
"#if WASM_RT_MEMCHECK_SIGNAL_HANDLER\n"
"#define MEMCHECK(mem, a, t)\n"
diff --git a/src/wasm2c.c.tmpl b/src/wasm2c.c.tmpl
index a73927c6..fcc7e3ae 100644
--- a/src/wasm2c.c.tmpl
+++ b/src/wasm2c.c.tmpl
@@ -19,8 +19,8 @@
#define CALL_INDIRECT(table, t, ft, x, ...) \
(LIKELY((x) < table.size && table.data[x].func && \
table.data[x].func_type == func_types[ft]) \
- ? ((t)table.data[x].func)(__VA_ARGS__) \
- : TRAP(CALL_INDIRECT))
+ || TRAP(CALL_INDIRECT) \
+ , ((t)table.data[x].func)(__VA_ARGS__))
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER
#define MEMCHECK(mem, a, t)