Skip to content

Commit ed28219

Browse files
committed
[Table64Lowering] Don't assume that all segments are from 64-bit tables
This allows modules to contains both 32-bit and 64-bit segment. In order to check the table/memory state when visiting segments we need to ensure that memories/tables are visited only after their segments. The comments in visitTable/visitMemory already assumed this but its wasn't actually true in practice.
1 parent 85f677a commit ed28219

File tree

4 files changed

+40
-22
lines changed

4 files changed

+40
-22
lines changed

src/passes/Memory64Lowering.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ struct Memory64Lowering : public WalkerPass<PostWalker<Memory64Lowering>> {
118118

119119
void visitMemory(Memory* memory) {
120120
// This is visited last.
121+
seenMemory = true;
121122
if (memory->is64()) {
122123
memory->indexType = Type::i32;
123124
if (memory->hasMax() && memory->max > Memory::kMaxSize32) {
@@ -127,16 +128,19 @@ struct Memory64Lowering : public WalkerPass<PostWalker<Memory64Lowering>> {
127128
}
128129

129130
void visitDataSegment(DataSegment* segment) {
130-
if (segment->isPassive) {
131-
// passive segments don't have any offset to adjust
131+
// We assume that memories are visitied after segments, so assert that here.
132+
assert(!seenMemory);
133+
auto& module = *getModule();
134+
135+
// passive segments don't have any offset to adjust
136+
if (segment->isPassive || !module.getMemory(segment->memory)->is64()) {
132137
return;
133138
}
134139

135140
if (auto* c = segment->offset->dynCast<Const>()) {
136141
c->value = Literal(static_cast<uint32_t>(c->value.geti64()));
137142
c->type = Type::i32;
138143
} else if (auto* get = segment->offset->dynCast<GlobalGet>()) {
139-
auto& module = *getModule();
140144
auto* g = module.getGlobal(get->name);
141145
if (g->imported() && g->base == MEMORY_BASE) {
142146
ImportInfo info(module);
@@ -170,6 +174,8 @@ struct Memory64Lowering : public WalkerPass<PostWalker<Memory64Lowering>> {
170174
super::run(module);
171175
module->features.disable(FeatureSet::Memory64);
172176
}
177+
178+
bool seenMemory = false;
173179
};
174180

175181
Pass* createMemory64LoweringPass() { return new Memory64Lowering(); }

src/passes/Table64Lowering.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,22 +97,26 @@ struct Table64Lowering : public WalkerPass<PostWalker<Table64Lowering>> {
9797

9898
void visitTable(Table* table) {
9999
// This is visited last.
100+
seenTable = true;
100101
if (table->is64()) {
101102
table->indexType = Type::i32;
102103
}
103104
}
104105

105106
void visitElementSegment(ElementSegment* segment) {
106-
if (segment->table.isNull()) {
107-
// Passive segments don't have any offset to update.
107+
// We assume that memories are visitied after segments, so assert that here.
108+
assert(!seenTable);
109+
auto& module = *getModule();
110+
111+
// Passive segments don't have any offset to update.
112+
if (segment->table.isNull() || !module.getTable(segment->table)->is64()) {
108113
return;
109114
}
110115

111116
if (auto* c = segment->offset->dynCast<Const>()) {
112117
c->value = Literal(static_cast<uint32_t>(c->value.geti64()));
113118
c->type = Type::i32;
114119
} else if (auto* get = segment->offset->dynCast<GlobalGet>()) {
115-
auto& module = *getModule();
116120
auto* g = module.getGlobal(get->name);
117121
if (g->imported() && g->base == TABLE_BASE) {
118122
ImportInfo info(module);
@@ -138,6 +142,8 @@ struct Table64Lowering : public WalkerPass<PostWalker<Table64Lowering>> {
138142
WASM_UNREACHABLE("unexpected elem offset");
139143
}
140144
}
145+
146+
bool seenTable = false;
141147
};
142148

143149
Pass* createTable64LoweringPass() { return new Table64Lowering(); }

src/wasm-traversal.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -256,18 +256,18 @@ struct Walker : public VisitorType {
256256
self->walkTag(curr.get());
257257
}
258258
}
259-
for (auto& curr : module->tables) {
260-
self->walkTable(curr.get());
261-
}
262259
for (auto& curr : module->elementSegments) {
263260
self->walkElementSegment(curr.get());
264261
}
265-
for (auto& curr : module->memories) {
266-
self->walkMemory(curr.get());
262+
for (auto& curr : module->tables) {
263+
self->walkTable(curr.get());
267264
}
268265
for (auto& curr : module->dataSegments) {
269266
self->walkDataSegment(curr.get());
270267
}
268+
for (auto& curr : module->memories) {
269+
self->walkMemory(curr.get());
270+
}
271271
}
272272

273273
// Walks module-level code, that is, code that is not in functions.

test/lit/passes/table64-lowering-features.wast renamed to test/lit/passes/table64-lowering.wast

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,20 @@
77

88
;; CHECK: (type $1 (func (result i64)))
99

10-
;; CHECK: (table $t 10 100 funcref)
11-
(table $t i64 10 100 funcref)
10+
;; CHECK: (table $t64 10 100 funcref)
11+
(table $t64 i64 10 100 funcref)
1212

13-
;; CHECK: (elem $elem (table $t) (i32.const 0) funcref (ref.null nofunc))
14-
(elem $elem (table $t) (i64.const 0) funcref (ref.null func))
13+
;; CHECK: (table $t32 10 100 funcref)
14+
15+
;; CHECK: (elem $elem64 (table $t64) (i32.const 0) funcref (ref.null nofunc))
16+
(elem $elem64 (table $t64) (i64.const 0) funcref (ref.null func))
17+
18+
(table $t32 10 100 funcref)
19+
;; CHECK: (elem $elem32 (table $t32) (i32.const 0) funcref (ref.null nofunc))
20+
(elem $elem32 (table $t32) (i32.const 0) funcref (ref.null func))
1521

1622
;; CHECK: (func $test_call_indirect
17-
;; CHECK-NEXT: (call_indirect $t (type $0)
23+
;; CHECK-NEXT: (call_indirect $t64 (type $0)
1824
;; CHECK-NEXT: (i32.wrap_i64
1925
;; CHECK-NEXT: (i64.const 0)
2026
;; CHECK-NEXT: )
@@ -26,16 +32,16 @@
2632

2733
;; CHECK: (func $test_table_size (result i64)
2834
;; CHECK-NEXT: (i64.extend_i32_u
29-
;; CHECK-NEXT: (table.size $t)
35+
;; CHECK-NEXT: (table.size $t64)
3036
;; CHECK-NEXT: )
3137
;; CHECK-NEXT: )
3238
(func $test_table_size (result i64)
33-
(table.size $t)
39+
(table.size $t64)
3440
)
3541

3642
;; CHECK: (func $test_table_grow (result i64)
3743
;; CHECK-NEXT: (i64.extend_i32_u
38-
;; CHECK-NEXT: (table.grow $t
44+
;; CHECK-NEXT: (table.grow $t64
3945
;; CHECK-NEXT: (ref.null nofunc)
4046
;; CHECK-NEXT: (i32.wrap_i64
4147
;; CHECK-NEXT: (i64.const 10)
@@ -44,11 +50,11 @@
4450
;; CHECK-NEXT: )
4551
;; CHECK-NEXT: )
4652
(func $test_table_grow (result i64)
47-
(table.grow $t (ref.null func) (i64.const 10))
53+
(table.grow $t64 (ref.null func) (i64.const 10))
4854
)
4955

5056
;; CHECK: (func $test_table_fill
51-
;; CHECK-NEXT: (table.fill $t
57+
;; CHECK-NEXT: (table.fill $t64
5258
;; CHECK-NEXT: (i32.wrap_i64
5359
;; CHECK-NEXT: (i64.const 0)
5460
;; CHECK-NEXT: )
@@ -59,6 +65,6 @@
5965
;; CHECK-NEXT: )
6066
;; CHECK-NEXT: )
6167
(func $test_table_fill
62-
(table.fill $t (i64.const 0) (ref.null func) (i64.const 10))
68+
(table.fill $t64 (i64.const 0) (ref.null func) (i64.const 10))
6369
)
6470
)

0 commit comments

Comments
 (0)