From faba8863f2b410dc84f7c757bdf5c0d5df25cbce Mon Sep 17 00:00:00 2001 From: Congcong Cai Date: Sun, 20 Oct 2024 05:16:41 +0800 Subject: [PATCH] implement this optimize offset to load constant --- src/passes/OptimizeAddedConstants.cpp | 47 ++++++- ...stants_low-memory-unused_merge-offset.wast | 119 ++++++++++++++++++ ...-constants-propagate_low-memory-unused.txt | 22 ++-- ...mize-added-constants_low-memory-unused.txt | 22 ++-- 4 files changed, 188 insertions(+), 22 deletions(-) create mode 100644 test/lit/passes/optimize-added-constants_low-memory-unused_merge-offset.wast diff --git a/src/passes/OptimizeAddedConstants.cpp b/src/passes/OptimizeAddedConstants.cpp index fd584083641..f7e8a421bad 100644 --- a/src/passes/OptimizeAddedConstants.cpp +++ b/src/passes/OptimizeAddedConstants.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -79,11 +80,18 @@ template class MemoryAccessOptimizer { optimizeConstantPointer(); return false; } - if (auto* add = curr->ptr->template dynCast()) { - if (add->op == AddInt32 || add->op == AddInt64) { + if (auto* binary = curr->ptr->template dynCast()) { + if (binary->op == AddInt32 || binary->op == AddInt64) { // Look for a constant on both sides. - if (tryToOptimizeConstant(add->right, add->left) || - tryToOptimizeConstant(add->left, add->right)) { + if (tryToOptimizeConstantToOffset(binary->left, binary->right)) { + return false; + } + if (tryToOptimizeOffsetToConstant(binary->left, binary->right)) { + return false; + } + } + if (binary->op == SubInt32 || binary->op == SubInt64) { + if (tryToOptimizeOffsetToConstant(binary->left, binary->right)) { return false; } } @@ -176,11 +184,22 @@ template class MemoryAccessOptimizer { Result(Address total) : succeeded(true), total(total) {} }; + static std::pair getConst(Expression* a, Expression* b) { + if (auto* constA = a->dynCast()) { + return {constA, b}; + } else if (auto* constB = b->dynCast()) { + return {constB, a}; + } else { + return {nullptr, nullptr}; + } + } + // See if we can optimize an offset from an expression. If we report // success, the returned offset can be added as a replacement for the // expression here. - bool tryToOptimizeConstant(Expression* oneSide, Expression* otherSide) { - if (auto* c = oneSide->dynCast()) { + bool tryToOptimizeConstantToOffset(Expression* left, Expression* right) { + auto [c, otherSide] = getConst(left, right); + if (c != nullptr) { auto result = canOptimizeConstant(c->value); if (result.succeeded) { curr->offset = result.total; @@ -194,6 +213,22 @@ template class MemoryAccessOptimizer { return false; } + bool tryToOptimizeOffsetToConstant(Expression* left, Expression* right) { + // left '-' right + auto [c, other] = getConst(left, right); + if (c != nullptr) { + if (curr->offset < PassOptions::LowMemoryBound) { + uint64_t value = c->value.getInteger(); + uint64_t total = curr->offset + value; + curr->offset = 0; + c->value = + Literal::makeFromInt64(static_cast(total), c->value.type); + return true; + } + } + return false; + } + bool tryToOptimizePropagatedAdd(Expression* oneSide, Expression* otherSide, LocalGet* ptr, diff --git a/test/lit/passes/optimize-added-constants_low-memory-unused_merge-offset.wast b/test/lit/passes/optimize-added-constants_low-memory-unused_merge-offset.wast new file mode 100644 index 00000000000..2513174d195 --- /dev/null +++ b/test/lit/passes/optimize-added-constants_low-memory-unused_merge-offset.wast @@ -0,0 +1,119 @@ +;; 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 --optimize-added-constants --low-memory-unused -S -o - | filecheck %s + +(module + ;; CHECK: (type $0 (func)) + + ;; CHECK: (memory $0 1 1) + (memory $0 1 1) + ;; CHECK: (func $load_const + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.load + ;; CHECK-NEXT: (i32.const 110) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $load_const + (drop (i32.load offset=100 (i32.const 10))) + ) + ;; CHECK: (func $store_const + ;; CHECK-NEXT: (local $0 i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.load + ;; CHECK-NEXT: (i32.const 110) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $store_const + (local i32) + (drop (i32.load offset=100 (i32.const 10))) + ) + ;; CHECK: (func $load_add + ;; CHECK-NEXT: (local $0 i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.load + ;; CHECK-NEXT: (i32.add + ;; CHECK-NEXT: (i32.const 1100) + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.load + ;; CHECK-NEXT: (i32.add + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: (i32.const 1200) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $load_add + (local i32) + (drop (i32.load offset=1000 (i32.add (i32.const 100) (local.get 0)))) + (drop (i32.load offset=1000 (i32.add (local.get 0) (i32.const 200)))) + ) + ;; CHECK: (func $store_add + ;; CHECK-NEXT: (local $0 i32) + ;; CHECK-NEXT: (i32.store offset=110 + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.store offset=120 + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $store_add + (local i32) + (i32.store offset=100 (i32.add (i32.const 10) (local.get 0)) (local.get 0)) + (i32.store offset=100 (i32.add (local.get 0) (i32.const 20)) (local.get 0)) + ) + ;; CHECK: (func $load_sub + ;; CHECK-NEXT: (local $0 i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.load + ;; CHECK-NEXT: (i32.sub + ;; CHECK-NEXT: (i32.const 110) + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.load + ;; CHECK-NEXT: (i32.sub + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: (i32.const 120) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $load_sub + (local i32) + (drop (i32.load offset=100 (i32.sub (i32.const 10) (local.get 0)))) + (drop (i32.load offset=100 (i32.sub (local.get 0) (i32.const 20)))) + ) + ;; CHECK: (func $store_sub + ;; CHECK-NEXT: (local $0 i32) + ;; CHECK-NEXT: (i32.store + ;; CHECK-NEXT: (i32.sub + ;; CHECK-NEXT: (i32.const 110) + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.store + ;; CHECK-NEXT: (i32.sub + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: (i32.const 120) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $store_sub + (local i32) + (i32.store offset=100 (i32.sub (i32.const 10) (local.get 0)) (local.get 0)) + (i32.store offset=100 (i32.sub (local.get 0) (i32.const 20)) (local.get 0)) + ) +) diff --git a/test/passes/optimize-added-constants-propagate_low-memory-unused.txt b/test/passes/optimize-added-constants-propagate_low-memory-unused.txt index 98169960325..7504feb9099 100644 --- a/test/passes/optimize-added-constants-propagate_low-memory-unused.txt +++ b/test/passes/optimize-added-constants-propagate_low-memory-unused.txt @@ -114,26 +114,32 @@ (local.get $0) (local.get $0) ) - (i32.store offset=2 + (i32.store (i32.add - (i32.const -11) + (i32.const -9) (local.get $0) ) (local.get $0) ) - (i32.store offset=2 + (i32.store (i32.add (local.get $0) - (i32.const -13) + (i32.const -11) ) (local.get $0) ) - (i32.store offset=19 - (i32.const -15) + (i32.store + (i32.add + (i32.const -13) + (i32.const 17) + ) (local.get $0) ) - (i32.store offset=21 - (i32.const -21) + (i32.store + (i32.add + (i32.const -19) + (i32.const 19) + ) (local.get $0) ) (i32.store diff --git a/test/passes/optimize-added-constants_low-memory-unused.txt b/test/passes/optimize-added-constants_low-memory-unused.txt index 9baf092af87..1328362ae0d 100644 --- a/test/passes/optimize-added-constants_low-memory-unused.txt +++ b/test/passes/optimize-added-constants_low-memory-unused.txt @@ -114,26 +114,32 @@ (local.get $0) (local.get $0) ) - (i32.store offset=2 + (i32.store (i32.add - (i32.const -11) + (i32.const -9) (local.get $0) ) (local.get $0) ) - (i32.store offset=2 + (i32.store (i32.add (local.get $0) - (i32.const -13) + (i32.const -11) ) (local.get $0) ) - (i32.store offset=19 - (i32.const -15) + (i32.store + (i32.add + (i32.const -13) + (i32.const 17) + ) (local.get $0) ) - (i32.store offset=21 - (i32.const -21) + (i32.store + (i32.add + (i32.const -19) + (i32.const 19) + ) (local.get $0) ) (i32.store