diff --git a/ml-proto/spec/check.ml b/ml-proto/spec/check.ml index d5a4457248..840daaea86 100644 --- a/ml-proto/spec/check.ml +++ b/ml-proto/spec/check.ml @@ -134,9 +134,9 @@ let rec check_expr c et e = check_expr_opt c (label c x) eo e.at | Br_if (x, eo, e) -> + check_expr_opt c et eo e.at; check_expr_opt c (label c x) eo e.at; - check_expr c (Some Int32Type) e; - check_type None et e.at + check_expr c (Some Int32Type) e | If (e1, e2, e3) -> check_expr c (Some Int32Type) e1; diff --git a/ml-proto/spec/eval.ml b/ml-proto/spec/eval.ml index 403b0859e7..511e8e533f 100644 --- a/ml-proto/spec/eval.ml +++ b/ml-proto/spec/eval.ml @@ -157,7 +157,7 @@ let rec eval_expr (c : config) (e : expr) = | Br_if (x, eo, e) -> let v = eval_expr_opt c eo in let i = int32 (eval_expr c e) e.at in - if i <> 0l then raise (label c x v) else None + if i <> 0l then raise (label c x v) else v | If (e1, e2, e3) -> let i = int32 (eval_expr c e1) e1.at in diff --git a/ml-proto/test/labels.wast b/ml-proto/test/labels.wast index 8c51f054c6..c4ec2743e2 100644 --- a/ml-proto/test/labels.wast +++ b/ml-proto/test/labels.wast @@ -90,28 +90,6 @@ ) ) - (func $br_if0 (result i32) - (local $i i32) - (set_local $i (i32.const 0)) - (block $outer - (block $inner - (br_if $inner (i32.const 0)) - (set_local $i (i32.or (get_local $i) (i32.const 0x1))) - (br_if $inner (i32.const 1)) - (set_local $i (i32.or (get_local $i) (i32.const 0x2))) - ) - (br_if $outer (set_local $i (i32.or (get_local $i) (i32.const 0x4))) (i32.const 0)) - (set_local $i (i32.or (get_local $i) (i32.const 0x8))) - (br_if $outer (set_local $i (i32.or (get_local $i) (i32.const 0x10))) (i32.const 1)) - (set_local $i (i32.or (get_local $i) (i32.const 0x20))) - ) - ) - - (func $br_if1 (result i32) - (block $l0 - (br_if $l0 (block $l1 (br $l1 (i32.const 1))) (i32.const 1)) - (i32.const 1))) - (func $br_if2 (result i32) (block $l0 (if (i32.const 1) @@ -120,15 +98,15 @@ (br $l1 (i32.const 1))))) (i32.const 1))) - (func $br_if3 (result i32) - (local $i1 i32) - (i32.add (block $l0 - (br_if $l0 - (set_local $i1 (i32.const 1)) - (set_local $i1 (i32.const 2))) - (i32.const 0)) - (i32.const 0)) - (get_local $i1)) + (func $br_if4 (result f32) + (block $l + (br_if $l (f32.const 0) (i32.const 1)))) + + (func $br_if5 (param i32) (result f32) + (block $l + (f32.neg + (block $i + (br_if $l (f32.const 3) (get_local 0)))))) (func $misc1 (result i32) (block $l1 (i32.xor (br $l1 (i32.const 1)) (i32.const 2))) @@ -146,10 +124,9 @@ (export "loop5" $loop5) (export "switch" $switch) (export "return" $return) - (export "br_if0" $br_if0) - (export "br_if1" $br_if1) (export "br_if2" $br_if2) - (export "br_if3" $br_if3) + (export "br_if4" $br_if4) + (export "br_if5" $br_if5) (export "misc1" $misc1) (export "misc2" $misc2) ) @@ -169,29 +146,130 @@ (assert_return (invoke "return" (i32.const 0)) (i32.const 0)) (assert_return (invoke "return" (i32.const 1)) (i32.const 2)) (assert_return (invoke "return" (i32.const 2)) (i32.const 2)) -(assert_return (invoke "br_if0") (i32.const 0x1d)) -(assert_return (invoke "br_if1") (i32.const 1)) (assert_return (invoke "br_if2") (i32.const 1)) -(assert_return (invoke "br_if3") (i32.const 2)) +(assert_return (invoke "br_if4") (f32.const 0)) +(assert_return (invoke "br_if5" (i32.const 0)) (f32.const -3)) +(assert_return (invoke "br_if5" (i32.const 1)) (f32.const 3)) (assert_return (invoke "misc1") (i32.const 1)) (assert_return (invoke "misc2") (i32.const 1)) -(assert_invalid (module (func (loop $l (br $l (i32.const 0))))) "arity mismatch") -(assert_invalid (module (func (block $l (f32.neg (br_if $l (i32.const 1))) (nop)))) "type mismatch") +(assert_invalid (module (func (block $l (f32.neg (br_if $l (i32.const 1))) (nop)))) "arity mismatch") -(assert_invalid (module (func (result f32) (block $l (br_if $l (f32.const 0) (i32.const 1))))) "type mismatch") (assert_invalid (module (func (result i32) (block $l (br_if $l (f32.const 0) (i32.const 1))))) "type mismatch") -(assert_invalid (module (func (block $l (f32.neg (br_if $l (f32.const 0) (i32.const 1)))))) "arity mismatch") (assert_invalid (module (func (param i32) (result i32) (block $l (f32.neg (br_if $l (f32.const 0) (get_local 0)))))) "type mismatch") -(assert_invalid (module (func (param i32) (result f32) - (block $l (f32.neg (block $i (br_if $l (f32.const 3) (get_local 0))))))) + +;; If br_if has a value, it should be used in both successors. +(assert_invalid (module + (func (result i32) + (local $i i32) + (set_local $i (i32.const 0)) + (block $outer + (block $inner + (br_if $inner (i32.const 0)) + (set_local $i (i32.or (get_local $i) (i32.const 0x1))) + (br_if $inner (i32.const 1)) + (set_local $i (i32.or (get_local $i) (i32.const 0x2))) + ) + (br_if $outer (set_local $i (i32.or (get_local $i) (i32.const 0x4))) (i32.const 0)) + (set_local $i (i32.or (get_local $i) (i32.const 0x8))) + (br_if $outer (set_local $i (i32.or (get_local $i) (i32.const 0x10))) (i32.const 1)) + (set_local $i (i32.or (get_local $i) (i32.const 0x20))) + )) +) "arity mismatch") + +;; If br_if has a value, it should be used in both successors. +(assert_invalid (module + (func (result i32) + (block $l0 + (br_if $l0 (block $l1 (br $l1 (i32.const 1))) (i32.const 1)) + (i32.const 1))) +) "arity mismatch") + +;; If br_if has a value, it should be used in both successors. +(assert_invalid (module + (func (result i32) + (local $i1 i32) + (i32.add (block $l0 + (br_if $l0 + (set_local $i1 (i32.const 1)) + (set_local $i1 (i32.const 2))) + (i32.const 0)) + (i32.const 0)) + (get_local $i1)) +) "arity mismatch") + +;; If br_if has a value, it should be used in both successors. +(assert_invalid (module + (func + (loop $l0 $l1 + (br $l0 (i32.const 0)))) +) "arity mismatch") + +;; If br_if has a value, it should be used in both successors. +(assert_invalid (module + (func + (block $l0 + (br_if $l0 (nop) (i32.const 1)))) +) "arity mismatch") + +;; If br_if has a value, it should be used in both successors. +(assert_invalid (module + (func + (block $l0 + (if_else (i32.const 1) + (br $l0 (block $l1 (br $l1 (i32.const 1)))) + (block (block $l1 (br $l1 (i32.const 1))) (nop)) + ) + (i32.const 1))) +) "arity mismatch") + +;; If br_if has a value, it should be used in both successors. +(assert_invalid (module + (func + (block $l + (f32.neg (br_if $l (f32.const 0) (i32.const 1))))) +) "arity mismatch") + +;; br_if's own result type doesn't match the result type of the block it's in. +(assert_invalid (module + (func (param i32) (result f32) + (block $l + (f32.convert_s/i32 + (block $i + (br_if $l (f32.const 3) (get_local 0))))))) + "type mismatch") + +;; br_if's result value's type doesn't match the type of the destination block. +(assert_invalid (module + (func (param i32) (result f32) + (block $l + (i32.trunc_s/f32 + (block $i + (br_if $l (f32.const 3) (get_local 0))))))) + "type mismatch") + +;; br_if operand has incorrect type. +(assert_invalid (module + (func (param i32) (result f32) + (block $l + (f32.neg + (block $i + (br_if $l (i32.const 3) (get_local 0))))))) "type mismatch") -(assert_invalid (module (func (block $l0 (br_if $l0 (nop) (i32.const 1))))) + +;; Function return type is wrong. +(assert_invalid (module + (func (param i32) (result i32) + (block $l + (f32.neg + (block $i + (br_if $l (f32.const 3) (get_local 0))))))) + "type mismatch") + +;; br_if result not used, but value's type doesn't match branched-to block. +(assert_invalid (module + (func (param i32) (result i32) + (block $l + (br_if $l (f32.const 3) (get_local 0)) + (i32.const 0)))) "arity mismatch") -(assert_invalid (module (func (result i32) - (block $l0 - (if_else (i32.const 1) - (br $l0 (block $l1 (br $l1 (i32.const 1)))) - (block (block $l1 (br $l1 (i32.const 1))) (nop)) - ) - (i32.const 1)))) "arity mismatch")