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
48 changes: 33 additions & 15 deletions src/passes/Memory64Lowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

#include "ir/bits.h"
#include "ir/import-utils.h"
#include "ir/localize.h"
#include "ir/utils.h"
#include "pass.h"
#include "wasm-builder.h"
#include "wasm.h"
Expand All @@ -34,8 +36,12 @@ static Name MEMORY_BASE32("__memory_base32");
static Name TABLE_BASE("__table_base");
static Name TABLE_BASE32("__table_base32");

static const Address k32GLimit(1ULL << 32);

struct Memory64Lowering : public WalkerPass<PostWalker<Memory64Lowering>> {

bool refinalize = false;

void wrapAddress64(Expression*& ptr,
Name memoryOrTableName,
bool isTable = false) {
Expand Down Expand Up @@ -83,14 +89,27 @@ struct Memory64Lowering : public WalkerPass<PostWalker<Memory64Lowering>> {
return extendAddress64(ptr, tableName, true);
}

void visitLoad(Load* curr) { wrapAddress64(curr->ptr, curr->memory); }
template<typename T> void visitMemoryAccess(T* curr) {
if (curr->offset < k32GLimit) {
return wrapAddress64(curr->ptr, curr->memory);
}
Block* b =
ChildLocalizer(curr, getFunction(), *getModule(), getPassOptions())
.getChildrenReplacement();
b->list.push_back(Builder(*getModule()).makeUnreachable());
b->type = Type::unreachable;
replaceCurrent(b);
refinalize = true;
}

void visitLoad(Load* curr) { visitMemoryAccess(curr); }

void visitStore(Store* curr) { wrapAddress64(curr->ptr, curr->memory); }
void visitStore(Store* curr) { visitMemoryAccess(curr); }

void visitSIMDLoad(SIMDLoad* curr) { wrapAddress64(curr->ptr, curr->memory); }
void visitSIMDLoad(SIMDLoad* curr) { visitMemoryAccess(curr); }

void visitSIMDLoadStoreLane(SIMDLoadStoreLane* curr) {
wrapAddress64(curr->ptr, curr->memory);
visitMemoryAccess(curr);
}

void visitMemorySize(MemorySize* curr) {
Expand Down Expand Up @@ -154,20 +173,19 @@ struct Memory64Lowering : public WalkerPass<PostWalker<Memory64Lowering>> {
wrapAddress64(curr->size, curr->destMemory);
}

void visitAtomicRMW(AtomicRMW* curr) {
wrapAddress64(curr->ptr, curr->memory);
}
void visitAtomicRMW(AtomicRMW* curr) { visitMemoryAccess(curr); }

void visitAtomicCmpxchg(AtomicCmpxchg* curr) {
wrapAddress64(curr->ptr, curr->memory);
}
void visitAtomicCmpxchg(AtomicCmpxchg* curr) { visitMemoryAccess(curr); }

void visitAtomicWait(AtomicWait* curr) {
wrapAddress64(curr->ptr, curr->memory);
}
void visitAtomicWait(AtomicWait* curr) { visitMemoryAccess(curr); }

void visitAtomicNotify(AtomicNotify* curr) {
wrapAddress64(curr->ptr, curr->memory);
void visitAtomicNotify(AtomicNotify* curr) { visitMemoryAccess(curr); }

void visitFunction(Function* func) {
if (refinalize) {
ReFinalize().walkFunctionInModule(func, getModule());
refinalize = false;
}
}

void visitDataSegment(DataSegment* segment) {
Expand Down
134 changes: 134 additions & 0 deletions test/lit/passes/memory64-lowering.wast
Original file line number Diff line number Diff line change
Expand Up @@ -440,3 +440,137 @@
(table.init $t64 $elem64 (i64.const 0) (i32.const 5) (i32.const 10))
)
)

(module
(memory i64 1 1)

;; CHECK: (type $0 (func (param i64 v128)))

;; CHECK: (type $1 (func (param i64) (result i32)))

;; CHECK: (type $2 (func (param i64 i32)))

;; CHECK: (type $3 (func (param i64)))

;; CHECK: (memory $0 1 1)

;; CHECK: (func $test_large_offsets (param $ptr i64) (result i32)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
(func $test_large_offsets (param $ptr i64) (result i32)
(i32.load offset=4294967297 (local.get $ptr))
)

;; CHECK: (func $test_store_large_offset (param $ptr i64) (param $val i32)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
(func $test_store_large_offset (param $ptr i64) (param $val i32)
(i32.store offset=4294967296 (local.get $ptr) (local.get $val))
)

;; CHECK: (func $test_simd_load_large_offset (param $ptr i64)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test_simd_load_large_offset (param $ptr i64)
(drop (v128.load offset=4294967296 (local.get $ptr)))
)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I turn on pass debug I'm getting a validation error:

[wasm-validator error in function test_simd_load_large_offset] stale type found in test_simd_load_large_offset on 0x5647b782bca8
(marked as none, should be unreachable)
, on
(drop
 (block
  (unreachable)
 )
)

I guess I need to propagate the unreachable type from the block up to the drop? Is there a utility for that?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, yes, if you add an unreachable that is a type change. You can note that and then run ReFinalize().walkFunctionInModule(func, module); on the entire function. See e.g. the Heap2Local pass.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, does this look right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, lgtm


;; CHECK: (func $test_simd_load_lane_large_offset (param $ptr i64) (param $val v128)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test_simd_load_lane_large_offset (param $ptr i64) (param $val v128)
(drop (v128.load8_lane offset=4294967296 0 (local.get $ptr) (local.get $val)))
)

;; CHECK: (func $test_simd_store_lane_large_offset (param $ptr i64) (param $val v128)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
(func $test_simd_store_lane_large_offset (param $ptr i64) (param $val v128)
(v128.store8_lane offset=4294967296 0 (local.get $ptr) (local.get $val))
)
)

(module
;; CHECK: (type $0 (func (param i64 i32)))

;; CHECK: (type $1 (func (param i64 i32 i32)))

;; CHECK: (type $2 (func (param i64 i32 i64)))

;; CHECK: (type $3 (func (param i64) (result i32)))

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

;; CHECK: (func $test_atomic_rmw_large_offset (param $ptr i64) (param $val i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test_atomic_rmw_large_offset (param $ptr i64) (param $val i32)
(drop (i32.atomic.rmw.add offset=4294967296 (local.get $ptr) (local.get $val)))
)

;; CHECK: (func $test_atomic_cmpxchg_large_offset (param $ptr i64) (param $exp i32) (param $new i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test_atomic_cmpxchg_large_offset (param $ptr i64) (param $exp i32) (param $new i32)
(drop (i32.atomic.rmw.cmpxchg offset=4294967296 (local.get $ptr) (local.get $exp) (local.get $new)))
)

;; CHECK: (func $test_atomic_wait_large_offset (param $ptr i64) (param $exp i32) (param $timeout i64)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test_atomic_wait_large_offset (param $ptr i64) (param $exp i32) (param $timeout i64)
(drop (memory.atomic.wait32 offset=4294967296 (local.get $ptr) (local.get $exp) (local.get $timeout)))
)

;; CHECK: (func $test_atomic_notify_large_offset (param $ptr i64) (param $count i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test_atomic_notify_large_offset (param $ptr i64) (param $count i32)
(drop (memory.atomic.notify offset=4294967296 (local.get $ptr) (local.get $count)))
)

;; CHECK: (func $test_large_offsets_effect (param $ptr i64) (result i32)
;; CHECK-NEXT: (local $1 i64)
;; CHECK-NEXT: (local.set $1
;; CHECK-NEXT: (i64.div_s
;; CHECK-NEXT: (i64.const 1337)
;; CHECK-NEXT: (local.get $ptr)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
(func $test_large_offsets_effect (param $ptr i64) (result i32)
(i32.load offset=4294967297
;; This might trap, and must be kept around.
(i64.div_s
(i64.const 1337)
(local.get $ptr)
)
)
)
)
Loading