diff --git a/src/ir/possible-contents.cpp b/src/ir/possible-contents.cpp index 9170a16524d..c018cf628d7 100644 --- a/src/ir/possible-contents.cpp +++ b/src/ir/possible-contents.cpp @@ -2454,6 +2454,11 @@ Flower::Flower(Module& wasm, const PassOptions& options) } } + // configureAll functions are called from outside the module, as if exported. + for (auto func : Intrinsics(wasm).getConfigureAllFunctions()) { + calledFromOutside.insert(func); + } + // Apply changes to all functions called from outside. for (auto funcName : calledFromOutside) { auto* func = wasm.getFunction(funcName); diff --git a/test/lit/passes/gufa-configureAll.wast b/test/lit/passes/gufa-configureAll.wast new file mode 100644 index 00000000000..274ad8fa1d4 --- /dev/null +++ b/test/lit/passes/gufa-configureAll.wast @@ -0,0 +1,103 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. + +;; RUN: foreach %s %t wasm-opt --gufa --closed-world -all -S -o - | filecheck %s + +;; Test that configureAll is respected: referred functions are assumed to be +;; called from outside the module, depsite closed world. + +(module + ;; CHECK: (type $externs (array (mut externref))) + (type $externs (array (mut externref))) + + ;; CHECK: (type $funcs (array (mut funcref))) + (type $funcs (array (mut funcref))) + + ;; CHECK: (type $bytes (array (mut i8))) + (type $bytes (array (mut i8))) + + ;; CHECK: (type $3 (func (param i32) (result i32))) + + ;; CHECK: (type $configureAll (func (param (ref null $externs) (ref null $funcs) (ref null $bytes) externref))) + (type $configureAll (func (param (ref null $externs)) (param (ref null $funcs)) (param (ref null $bytes)) (param externref))) + + ;; CHECK: (type $5 (func)) + + ;; CHECK: (import "wasm:js-prototypes" "configureAll" (func $configureAll (type $configureAll) (param (ref null $externs) (ref null $funcs) (ref null $bytes) externref))) + (import "wasm:js-prototypes" "configureAll" (func $configureAll (type $configureAll))) + + ;; CHECK: (data $bytes "12345678") + (data $bytes "12345678") + + ;; CHECK: (elem $externs externref (item (ref.null noextern))) + (elem $externs externref + (ref.null extern) + ) + + ;; CHECK: (elem $funcs func $configured) + (elem $funcs funcref + (ref.func $configured) + ) + + ;; CHECK: (elem $other func $unconfigured) + (elem $other funcref + (ref.func $unconfigured) + ) + + ;; CHECK: (start $start) + (start $start) + + ;; CHECK: (func $start (type $5) + ;; CHECK-NEXT: (call $configureAll + ;; CHECK-NEXT: (array.new_elem $externs $externs + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (array.new_elem $funcs $funcs + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (array.new_data $bytes $bytes + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (i32.const 8) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null noextern) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $start + (call $configureAll + (array.new_elem $externs $externs + (i32.const 0) (i32.const 1)) + (array.new_elem $funcs $funcs + (i32.const 0) (i32.const 1)) + (array.new_data $bytes $bytes + (i32.const 0) (i32.const 8)) + (ref.null extern) + ) + ) + + ;; CHECK: (func $configured (type $3) (param $x i32) (result i32) + ;; CHECK-NEXT: (i32.eqz + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $configured (param $x i32) (result i32) + ;; The call from outside the module, through configureAll, is the only call + ;; we have - without it, this would be unreachable code, and optimized away. + (i32.eqz + (local.get $x) + ) + ) + + ;; CHECK: (func $unconfigured (type $3) (param $x i32) (result i32) + ;; CHECK-NEXT: (i32.eqz + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $unconfigured (param $x i32) (result i32) + ;; As above, but *not* in configureAll (though it is in a table, so it is + ;; not entirely removed) - so we do optimize. + (i32.eqz + (local.get $x) + ) + ) +)