diff --git a/src/dataflow/graph.h b/src/dataflow/graph.h index 6bd01d8954a..3e6676474f4 100644 --- a/src/dataflow/graph.h +++ b/src/dataflow/graph.h @@ -274,7 +274,7 @@ struct Graph : public UnifiedExpressionVisitor { auto afterIfFalseState = locals; // TODO: optimize mergeIf(afterIfTrueState, afterIfFalseState, condition, curr, locals); } else { - mergeIf(initialState, afterIfTrueState, condition, curr, locals); + mergeIf(afterIfTrueState, initialState, condition, curr, locals); } parent = oldParent; return &bad; diff --git a/test/gtest/CMakeLists.txt b/test/gtest/CMakeLists.txt index ecd351bc489..058766f58e4 100644 --- a/test/gtest/CMakeLists.txt +++ b/test/gtest/CMakeLists.txt @@ -9,6 +9,7 @@ set(unittest_SOURCES arena.cpp cast-check.cpp cfg.cpp + dataflow.cpp dfa_minimization.cpp disjoint_sets.cpp glbs.cpp diff --git a/test/gtest/dataflow.cpp b/test/gtest/dataflow.cpp new file mode 100644 index 00000000000..23ab5fcc00f --- /dev/null +++ b/test/gtest/dataflow.cpp @@ -0,0 +1,76 @@ +#include "dataflow/graph.h" +#include "dataflow/node.h" +#include "parser/wat-parser.h" +#include "wasm.h" +#include "gtest/gtest.h" + +using namespace wasm; +using namespace wasm::DataFlow; + +class DataflowTest : public ::testing::Test { +protected: + void parseWast(Module& wasm, const std::string& wast) { + auto parsed = WATParser::parseModule(wasm, wast); + if (auto* err = parsed.getErr()) { + Fatal() << err->msg << "\n"; + } + } +}; + +// Regression test for https://github.com/WebAssembly/binaryen/issues/8273 +// In the no-else case, mergeIf arguments were swapped: the initial state +// (before the if body) was paired with the ifTrue condition and the +// afterIfTrue state was paired with ifFalse. This test verifies the fix. +TEST_F(DataflowTest, IfNoElseMergeOrder) { + auto moduleText = R"wasm( + (module + (func $test (param $cond i32) + (local $x i32) + (local.set $x (i32.const 10)) + (if (local.get $cond) + (then + (local.set $x (i32.const 42)) + ) + ) + (drop (local.get $x)) + ) + ) + )wasm"; + + Module wasm; + parseWast(wasm, moduleText); + + auto* func = wasm.getFunction("test"); + Graph graph; + graph.build(func, &wasm); + + // Find the phi node for local $x (index 1). + Node* phi = nullptr; + for (auto& node : graph.nodes) { + if (node->isPhi() && node->index == 1) { + phi = node.get(); + break; + } + } + ASSERT_NE(phi, nullptr) << "Expected a phi node for local $x"; + + // Phi structure: values[0] = block, values[1] = ifTrue value, + // values[2] = ifFalse value. + ASSERT_EQ(phi->values.size(), 3u); + + auto* ifTrueNode = phi->values[1]; + auto* ifFalseNode = phi->values[2]; + + ASSERT_TRUE(ifTrueNode->isConst()); + ASSERT_TRUE(ifFalseNode->isConst()); + + int32_t ifTrueValue = ifTrueNode->expr->cast()->value.geti32(); + int32_t ifFalseValue = ifFalseNode->expr->cast()->value.geti32(); + + // When condition is true (body ran), $x should be 42. + EXPECT_EQ(ifTrueValue, 42) + << "When condition is TRUE, phi should select 42 (set in ifTrue body)"; + // When condition is false (body skipped), $x should be 10 (initial value). + EXPECT_EQ(ifFalseValue, 10) + << "When condition is FALSE, phi should select 10 (initial value)"; +}