Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 24 additions & 9 deletions src/passes/OptimizeAddedConstants.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ template<typename P, typename T> class MemoryAccessOptimizer {
T* curr,
Module* module,
LocalGraph* localGraph)
: parent(parent), curr(curr), module(module), localGraph(localGraph) {}
: parent(parent), curr(curr), module(module), localGraph(localGraph) {
memory64 = module->getMemory(curr->memory)->is64();
}

// Tries to optimize, and returns whether we propagated a change.
bool optimize() {
Expand All @@ -56,7 +58,7 @@ template<typename P, typename T> class MemoryAccessOptimizer {
return false;
}
if (auto* add = curr->ptr->template dynCast<Binary>()) {
if (add->op == AddInt32) {
if (add->op == AddInt32 || add->op == AddInt64) {
// Look for a constant on both sides.
if (tryToOptimizeConstant(add->right, add->left) ||
tryToOptimizeConstant(add->left, add->right)) {
Expand Down Expand Up @@ -110,6 +112,7 @@ template<typename P, typename T> class MemoryAccessOptimizer {
T* curr;
Module* module;
LocalGraph* localGraph;
bool memory64;

void optimizeConstantPointer() {
// The constant and an offset are interchangeable:
Expand All @@ -123,11 +126,23 @@ template<typename P, typename T> class MemoryAccessOptimizer {
// code may know that is valid, even if we can't. Only handle the
// obviously valid case where an overflow can't occur.
auto* c = curr->ptr->template cast<Const>();
uint32_t base = c->value.geti32();
uint32_t offset = curr->offset;
if (uint64_t(base) + uint64_t(offset) < (uint64_t(1) << 32)) {
c->value = c->value.add(Literal(uint32_t(curr->offset)));
curr->offset = 0;
if (memory64) {
uint64_t base = c->value.geti64();
uint64_t offset = curr->offset;

uint64_t max = std::numeric_limits<uint64_t>::max();
bool overflow = (base > max - offset);
if (!overflow) {
c->value = c->value.add(Literal(offset));
curr->offset = 0;
}
} else {
uint32_t base = c->value.geti32();
uint32_t offset = curr->offset;
if (uint64_t(base) + uint64_t(offset) < (uint64_t(1) << 32)) {
c->value = c->value.add(Literal(uint32_t(curr->offset)));
curr->offset = 0;
}
}
}
}
Expand Down Expand Up @@ -222,9 +237,9 @@ template<typename P, typename T> class MemoryAccessOptimizer {

// Sees if we can optimize a particular constant.
Result canOptimizeConstant(Literal literal) {
auto value = literal.geti32();
uint64_t value = literal.getInteger();
// Avoid uninteresting corner cases with peculiar offsets.
if (value >= 0 && value < PassOptions::LowMemoryBound) {
if (value < PassOptions::LowMemoryBound) {
// The total offset must not allow reaching reasonable memory
// by overflowing.
auto total = curr->offset + value;
Expand Down
57 changes: 57 additions & 0 deletions test/lit/passes/optimize-added-constants-memory64.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.

;; RUN: wasm-opt %s -all --roundtrip --optimize-added-constants --low-memory-unused -S -o - | filecheck %s

(module
;; CHECK: (memory $0 i64 1 4294967296)
(memory $0 i64 1 4294967296)


;; CHECK: (func $load_i64 (result i64)
;; CHECK-NEXT: (i64.load
;; CHECK-NEXT: (i64.const 579)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $load_i64 (result i64)
(i64.load offset=123
(i64.const 456)
)
)

;; CHECK: (func $load_overflow_i64 (result i64)
;; CHECK-NEXT: (i64.load offset=32
;; CHECK-NEXT: (i64.const -16)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $load_overflow_i64 (result i64)
(i64.load offset=32
(i64.const 0xfffffffffffffff0)
)
)

;; CHECK: (func $store
;; CHECK-NEXT: (i64.store
;; CHECK-NEXT: (i64.const 579)
;; CHECK-NEXT: (i64.const 123)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $store (result)
(i64.store offset=123
(i64.const 456)
(i64.const 123)
)
)

;; CHECK: (func $store_overflow
;; CHECK-NEXT: (i64.store offset=32
;; CHECK-NEXT: (i64.const -16)
;; CHECK-NEXT: (i64.const 123)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $store_overflow (result)
(i64.store offset=32
(i64.const 0xfffffffffffffff0)
(i64.const 123)
)
)
)