From 1196f7088d2ed3ec1227343d9a50eccd0aa4e18e Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Mon, 23 Mar 2026 15:40:31 -0700 Subject: [PATCH] Do not copy function annotations when copying expressions When copying expressions from one function to another, we previously also copied the function-level annotations from the source function to the destination. This is not correct, and caused a bug where the @binaryen.removable.if.unused annotation was copied from an inlined function to its caller, resulting in side effects being dropped. Fix the problem by moving responsibility for copying function annotations from `copyBetweenFunctions to `copyFunctionWithoutAdd`. --- src/ir/metadata.cpp | 6 +--- src/ir/module-utils.cpp | 1 + ...lining-optimizing-removable-if-unused.wast | 33 +++++++++++++++++++ 3 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 test/lit/passes/inlining-optimizing-removable-if-unused.wast diff --git a/src/ir/metadata.cpp b/src/ir/metadata.cpp index 6ac749b1fff..61c5da9bc06 100644 --- a/src/ir/metadata.cpp +++ b/src/ir/metadata.cpp @@ -44,8 +44,7 @@ void copyBetweenFunctions(Expression* origin, Function* originFunc, Function* copyFunc) { if (originFunc->debugLocations.empty() && - originFunc->codeAnnotations.empty() && - originFunc->funcAnnotations.empty()) { + originFunc->codeAnnotations.empty()) { // Nothing to copy. return; } @@ -75,9 +74,6 @@ void copyBetweenFunctions(Expression* origin, } } } - - // Also copy function-level annotations. - copyFunc->funcAnnotations = originFunc->funcAnnotations; } #pragma GCC diagnostic push diff --git a/src/ir/module-utils.cpp b/src/ir/module-utils.cpp index ea83a7e05bd..5b815eb4fea 100644 --- a/src/ir/module-utils.cpp +++ b/src/ir/module-utils.cpp @@ -73,6 +73,7 @@ copyFunctionWithoutAdd(Function* func, ret->localIndices = func->localIndices; ret->body = ExpressionManipulator::copy(func->body, out); metadata::copyBetweenFunctions(func->body, ret->body, func, ret.get()); + ret->funcAnnotations = func->funcAnnotations; ret->prologLocation = func->prologLocation; ret->epilogLocation = func->epilogLocation; // Update file indices if needed diff --git a/test/lit/passes/inlining-optimizing-removable-if-unused.wast b/test/lit/passes/inlining-optimizing-removable-if-unused.wast new file mode 100644 index 00000000000..50e2be8dabc --- /dev/null +++ b/test/lit/passes/inlining-optimizing-removable-if-unused.wast @@ -0,0 +1,33 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. + +;; RUN: wasm-opt %s --inlining-optimizing -S -o - | filecheck %s + +(module + ;; CHECK: (import "" "" (func $import (param i32))) + (import "" "" (func $import (param i32))) + ;; CHECK: (export "test" (func $test)) + (export "test" (func $test)) + ;; CHECK: (func $test + ;; CHECK-NEXT: (call $import + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $test + (call $main) + ) + (func $main + (call $print) + ) + (func $print + ;; $print should not inherit the removable.if.unused attribute from the + ;; inlined call to $removable. (If it did, then we would incorrectly remove + ;; the call to the import.) + (call $import + (call $removable) + ) + ) + (@binaryen.removable.if.unused) + (func $removable (result i32) + (i32.const 0) + ) +)