summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/wasm/wasm-validator.cpp12
-rw-r--r--test/lit/tail-call.wast78
-rw-r--r--test/tail-call.wast11
3 files changed, 85 insertions, 16 deletions
diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp
index f492c7110..450a7b956 100644
--- a/src/wasm/wasm-validator.cpp
+++ b/src/wasm/wasm-validator.cpp
@@ -460,9 +460,9 @@ private:
Type(Type::unreachable),
curr,
"return_call* should have unreachable type");
- shouldBeEqual(
- getFunction()->getResults(),
+ shouldBeSubType(
sig.results,
+ getFunction()->getResults(),
curr,
"return_call* callee return type must match caller return type");
} else {
@@ -798,9 +798,11 @@ void FunctionValidator::visitCallIndirect(CallIndirect* curr) {
if (curr->target->type != Type::unreachable) {
auto* table = getModule()->getTableOrNull(curr->table);
shouldBeTrue(!!table, curr, "call-indirect table must exist");
- shouldBeTrue(table->type.isFunction(),
- curr,
- "call-indirect table must be of function type.");
+ if (table) {
+ shouldBeTrue(table->type.isFunction(),
+ curr,
+ "call-indirect table must be of function type.");
+ }
}
validateCallParamsAndResult(curr, curr->sig);
diff --git a/test/lit/tail-call.wast b/test/lit/tail-call.wast
new file mode 100644
index 000000000..92dfdbb4e
--- /dev/null
+++ b/test/lit/tail-call.wast
@@ -0,0 +1,78 @@
+;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.
+
+;; Check that tail calls are parsed, validated, and printed correctly
+
+;; RUN: foreach %s %t wasm-opt -all -S -o - | filecheck %s
+;; TODO: --nominal as well
+
+(module
+
+ ;; CHECK: (type $void (func))
+ (type $void (func))
+
+ ;; CHECK: (table $t 1 1 funcref)
+ (table $t 1 1 funcref)
+
+ ;; CHECK: (elem $e (i32.const 0) $foo)
+ (elem $e (i32.const 0) $foo)
+
+ ;; CHECK: (func $foo
+ ;; CHECK-NEXT: (return_call $bar)
+ ;; CHECK-NEXT: )
+ (func $foo
+ (return_call $bar)
+ )
+
+ ;; CHECK: (func $bar
+ ;; CHECK-NEXT: (return_call_indirect $t (type $void)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $bar
+ (return_call_indirect (type $void) (i32.const 0))
+ )
+)
+
+;; Check GC types and subtyping
+(module
+ ;; CHECK: (type $return-B (func (result (ref $B))))
+ (type $return-B (func (result (ref $B))))
+
+ ;; CHECK: (type $return-A (func (result (ref null $A))))
+ (type $return-A (func (result (ref null $A))))
+
+ ;; CHECK: (type $A (struct (field i32)))
+ (type $A (struct i32))
+
+ ;; CHECK: (type $B (struct (field i32) (field i32)))
+ (type $B (struct i32 i32) (supertype $A))
+
+ ;; CHECK: (table $t 1 1 funcref)
+ (table $t 1 1 funcref)
+
+ ;; CHECK: (elem $e (i32.const 0) $callee)
+ (elem $e (i32.const 0) $callee)
+
+ ;; CHECK: (func $caller (result (ref null $A))
+ ;; CHECK-NEXT: (return_call $callee)
+ ;; CHECK-NEXT: )
+ (func $caller (type $return-A)
+ (return_call $callee)
+ )
+
+ ;; CHECK: (func $caller-indirect (result (ref $B))
+ ;; CHECK-NEXT: (return_call_indirect $t (type $return-B)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $caller-indirect (type $return-B)
+ (return_call_indirect $t (type $return-B) (i32.const 0))
+ )
+
+ ;; CHECK: (func $callee (result (ref $B))
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ (func $callee (type $return-B)
+ (unreachable)
+ )
+)
diff --git a/test/tail-call.wast b/test/tail-call.wast
deleted file mode 100644
index ceea1239e..000000000
--- a/test/tail-call.wast
+++ /dev/null
@@ -1,11 +0,0 @@
-(module
- (type $void (func))
- (table 1 1 funcref)
- (elem (i32.const 0) $foo)
- (func $foo
- (return_call $bar)
- )
- (func $bar
- (return_call_indirect (type $void) (i32.const 0))
- )
-) \ No newline at end of file