| #include "ir/utils.h" |
| #include "passes/stringify-walker.h" |
| #include "print-test.h" |
| #include "support/suffix_tree.h" |
| |
| using namespace wasm; |
| |
| using StringifyTest = PrintTest; |
| |
| TEST_F(StringifyTest, Print) { |
| auto moduleText = R"wasm( |
| (module |
| (tag $catch_a (param i32)) |
| (tag $catch_b (param i32)) |
| (tag $catch_c (param i32)) |
| (func $d |
| (block $block_a |
| (drop (i32.const 20)) |
| (drop (i32.const 10)) |
| ) |
| (block $block_b |
| (drop (if (i32.const 0) |
| (i32.const 40) |
| (i32.const 5) |
| )) |
| ) |
| (block $block_c |
| (drop (if (i32.const 1) |
| (i32.const 30) |
| )) |
| ) |
| (block $block_d |
| (try $try_a |
| (do |
| (nop) |
| ) |
| (catch $catch_a |
| (drop (i32.const 8)) |
| ) |
| (catch $catch_b |
| (drop (i32.const 15)) |
| ) |
| ) |
| ) |
| (block $block_e |
| (try $try_b |
| (do |
| (nop) |
| ) |
| (catch $catch_c |
| (drop (i32.const 33)) |
| ) |
| ) |
| ) |
| ) |
| ) |
| )wasm"; |
| |
| auto stringifyText = R"stringify(in visitExpression for block |
| adding unique symbol |
| in visitExpression for block $block_a |
| in visitExpression for block $block_b |
| in visitExpression for block $block_c |
| in visitExpression for block $block_d |
| in visitExpression for block $block_e |
| adding unique symbol |
| in visitExpression for i32.const 20 |
| in visitExpression for drop |
| in visitExpression for i32.const 10 |
| in visitExpression for drop |
| adding unique symbol |
| in visitExpression for i32.const 0 |
| in visitExpression for if |
| in visitExpression for drop |
| adding unique symbol |
| in visitExpression for i32.const 1 |
| in visitExpression for if |
| in visitExpression for drop |
| adding unique symbol |
| in visitExpression for try $try_a |
| adding unique symbol |
| in visitExpression for try $try_b |
| adding unique symbol |
| in visitExpression for i32.const 40 |
| adding unique symbol |
| in visitExpression for i32.const 5 |
| adding unique symbol |
| in visitExpression for i32.const 30 |
| adding unique symbol |
| in visitExpression for nop |
| adding unique symbol |
| in visitExpression for i32.const 8 |
| in visitExpression for drop |
| adding unique symbol |
| in visitExpression for i32.const 15 |
| in visitExpression for drop |
| adding unique symbol |
| in visitExpression for nop |
| adding unique symbol |
| in visitExpression for i32.const 33 |
| in visitExpression for drop |
| adding unique symbol |
| )stringify"; |
| |
| struct TestStringifyWalker : public StringifyWalker<TestStringifyWalker> { |
| std::ostream& os; |
| |
| TestStringifyWalker(std::ostream& os) : os(os){}; |
| |
| void addUniqueSymbol() { os << "adding unique symbol\n"; } |
| |
| void visitExpression(Expression* curr) { |
| os << "in visitExpression for " << ShallowExpression{curr, getModule()} |
| << std::endl; |
| } |
| }; |
| |
| Module wasm; |
| parseWast(wasm, moduleText); |
| |
| std::stringstream ss; |
| TestStringifyWalker stringify = TestStringifyWalker(ss); |
| stringify.walkModule(&wasm); |
| |
| EXPECT_EQ(ss.str(), stringifyText); |
| } |
| |
| static auto dupModuleText = R"wasm( |
| (module |
| (func $a |
| (block $block_a |
| (drop (i32.const 20)) |
| (drop (i32.const 10)) |
| ) |
| (block $block_b |
| (drop (if (i32.const 0) |
| (i32.const 40) |
| (i32.const 5) |
| )) |
| ) |
| (block $block_c |
| (drop (if (i32.const 1) |
| (i32.const 30) |
| )) |
| ) |
| (block $block_d |
| (drop (i32.const 20)) |
| (drop (i32.const 10)) |
| ) |
| (block $block_e |
| (drop (if (i32.const 1) |
| (i32.const 30) |
| )) |
| ) |
| (block $block_f |
| (drop (if (i32.const 0) |
| (i32.const 30) |
| )) |
| ) |
| ) |
| ) |
| )wasm"; |
| |
| TEST_F(StringifyTest, Stringify) { |
| Module wasm; |
| parseWast(wasm, dupModuleText); |
| |
| HashStringifyWalker stringify = HashStringifyWalker(); |
| stringify.walkModule(&wasm); |
| |
| EXPECT_EQ(stringify.hashString, |
| (std::vector<uint32_t>{ |
| 0, // function block evaluated as a whole |
| (uint32_t)-1, // separate function block from function contents |
| 1, // block_a evaluated as a whole |
| 2, // block_b evaluated as a whole |
| 3, // block_c evaluated as a whole |
| 1, // block_d has the same contents as block_a |
| 3, // block_e has the same contents as block_c |
| 4, // block_f evaluated as a whole |
| (uint32_t)-2, // separate blocks from block contents |
| 5, // i32.const 20 |
| 6, // drop, all drops will be the same symbol |
| 7, // i32.const 10 |
| 6, // drop |
| (uint32_t)-3, // separate block_a contents |
| 8, // i32.const 0, if condition |
| 9, // block_b's if evaluated as a whole |
| 6, // drop |
| (uint32_t)-4, // separate block_b contents |
| 10, // i32.const 1, if condition |
| 11, // block_c's if evaluated as a whole |
| 6, // drop |
| (uint32_t)-5, // separate block_c contents |
| 5, // i32.const 20 |
| 6, // drop |
| 7, // i32.const 10 |
| 6, // drop |
| (uint32_t)-6, // separate block_d contents |
| 10, // i32.const 1, if condition |
| 11, // block_e if evaluated as a whole |
| 6, // drop |
| (uint32_t)-7, // separate block_e contents |
| 8, // i32.const 0, if condition |
| 11, // block_f's if evaluated as a whole |
| 6, // drop |
| (uint32_t)-8, // separate block_f contents |
| 12, // i32.const 40 |
| (uint32_t)-9, // separate block_b if-true |
| 13, // i32.const 5 |
| (uint32_t)-10, // separate block_b if-false |
| 14, // i32.const 30 |
| (uint32_t)-11, // separate block_c if-true |
| 14, // i32.const 30 |
| (uint32_t)-12, // separate block_e if-true |
| 14, // i32.const 30 |
| (uint32_t)-13 // separate block_f if-true |
| })); |
| } |
| |
| TEST_F(StringifyTest, Substrings) { |
| Module wasm; |
| parseWast(wasm, dupModuleText); |
| |
| HashStringifyWalker stringify = HashStringifyWalker(); |
| stringify.walkModule(&wasm); |
| |
| SuffixTree st(stringify.hashString); |
| std::vector<SuffixTree::RepeatedSubstring> substrings(st.begin(), st.end()); |
| std::sort( |
| substrings.begin(), |
| substrings.end(), |
| [](SuffixTree::RepeatedSubstring a, SuffixTree::RepeatedSubstring b) { |
| size_t aWeight = a.Length * a.StartIndices.size(); |
| size_t bWeight = b.Length * b.StartIndices.size(); |
| if (aWeight == bWeight) { |
| return a.StartIndices[0] < b.StartIndices[0]; |
| } |
| return aWeight > bWeight; |
| }); |
| |
| EXPECT_EQ( |
| substrings, |
| (std::vector<SuffixTree::RepeatedSubstring>{ |
| // 5, 6, 7, 6 appears at idx 9 and again at 22 |
| SuffixTree::RepeatedSubstring{4u, (std::vector<unsigned>{9, 22})}, |
| // 6, 7, 6 appears at idx 10 and again at 23 |
| SuffixTree::RepeatedSubstring{3u, (std::vector<unsigned>{10, 23})}, |
| // 10, 11, 6 appears at idx 18 and again at 27 |
| SuffixTree::RepeatedSubstring{3u, (std::vector<unsigned>{18, 27})}, |
| // 11, 6 appears at idx 32, 19 and again at 28 |
| SuffixTree::RepeatedSubstring{2u, (std::vector<unsigned>{32, 19, 28})}, |
| // 7, 6 appears at idx 11 and again at 24 |
| SuffixTree::RepeatedSubstring{2u, (std::vector<unsigned>{11, 24})}})); |
| } |