diff --git a/src/passes/Directize.cpp b/src/passes/Directize.cpp index 4b0cb6ae78b..5b393a66900 100644 --- a/src/passes/Directize.cpp +++ b/src/passes/Directize.cpp @@ -153,7 +153,7 @@ struct FunctionDirectizer : public WalkerPass> { return CallUtils::Trap{}; } auto* func = getModule()->getFunction(name); - if (original->heapType != func->type) { + if (!HeapType::isSubType(func->type, original->heapType)) { return CallUtils::Trap{}; } return CallUtils::Known{name}; diff --git a/test/lit/passes/directize-gc.wast b/test/lit/passes/directize-gc.wast new file mode 100644 index 00000000000..fcf5c98116f --- /dev/null +++ b/test/lit/passes/directize-gc.wast @@ -0,0 +1,114 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. +;; NOTE: This test was ported using port_passes_tests_to_lit.py and could be cleaned up. + +;; RUN: foreach %s %t wasm-opt --directize -all -S -o - | filecheck %s + +;; Call a subtype with the supertype. This call should succeed. +(module + (rec + ;; CHECK: (type $0 (func)) + + ;; CHECK: (rec + ;; CHECK-NEXT: (type $super (sub (func))) + (type $super (sub (func))) + ;; CHECK: (type $sub (sub final $super (func))) + (type $sub (sub final $super (func))) + ) + + ;; CHECK: (table $table 93 funcref) + (table $table 93 funcref) + + ;; CHECK: (elem $elem (i32.const 0) $target) + (elem $elem (i32.const 0) $target) + + ;; CHECK: (export "caller" (func $caller)) + + ;; CHECK: (func $caller (type $0) + ;; CHECK-NEXT: (call $target) + ;; CHECK-NEXT: ) + (func $caller (export "caller") + ;; This turns into a direct call. + (call_indirect (type $super) + (i32.const 0) + ) + ) + + ;; CHECK: (func $target (type $sub) + ;; CHECK-NEXT: ) + (func $target (type $sub) + ) +) + +;; Remove the subtyping. This call should error. +(module + (rec + ;; CHECK: (type $0 (func)) + + ;; CHECK: (rec + ;; CHECK-NEXT: (type $super (sub (func))) + (type $super (sub (func))) + ;; CHECK: (type $other (sub (func))) + (type $other (sub (func))) + ) + + ;; CHECK: (table $table 93 funcref) + (table $table 93 funcref) + + ;; CHECK: (elem $elem (i32.const 0) $target) + (elem $elem (i32.const 0) $target) + + ;; CHECK: (export "caller" (func $caller)) + + ;; CHECK: (func $caller (type $0) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + (func $caller (export "caller") + ;; This turns into an unreachable. + (call_indirect (type $super) + (i32.const 0) + ) + ) + + ;; CHECK: (func $target (type $other) + ;; CHECK-NEXT: ) + (func $target (type $other) + ) +) + +;; Reverse the subtyping: Call a supertype with a subtype. This call should +;; fail. +(module + (rec + ;; CHECK: (type $0 (func)) + + ;; CHECK: (rec + ;; CHECK-NEXT: (type $super (sub (func))) + (type $super (sub (func))) + ;; CHECK: (type $sub (sub final $super (func))) + (type $sub (sub final $super (func))) + ) + + ;; CHECK: (table $table 93 funcref) + (table $table 93 funcref) + + ;; CHECK: (elem $elem (i32.const 0) $target) + (elem $elem (i32.const 0) $target) + + ;; CHECK: (export "caller" (func $caller)) + + ;; CHECK: (func $caller (type $0) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + (func $caller (export "caller") + ;; This turns into a direct call. + (call_indirect (type $sub) + (i32.const 0) + ) + ) + + ;; CHECK: (func $target (type $super) + ;; CHECK-NEXT: ) + (func $target (type $super) + ) +) +