@@ -31,33 +31,58 @@ namespace wasm {
3131static Name MEMORY_BASE (" __memory_base" );
3232static Name MEMORY_BASE32 (" __memory_base32" );
3333
34+ static Name TABLE_BASE (" __table_base" );
35+ static Name TABLE_BASE32 (" __table_base32" );
36+
3437struct Memory64Lowering : public WalkerPass <PostWalker<Memory64Lowering>> {
3538
36- void wrapAddress64 (Expression*& ptr, Name memoryName) {
39+ void wrapAddress64 (Expression*& ptr,
40+ Name memoryOrTableName,
41+ bool isTable = false ) {
3742 if (ptr->type == Type::unreachable) {
3843 return ;
3944 }
4045 auto & module = *getModule ();
41- auto * memory = module .getMemory (memoryName);
42- if (memory->is64 ()) {
46+ bool is64 = false ;
47+ if (isTable) {
48+ is64 = module .getTable (memoryOrTableName)->is64 ();
49+ } else {
50+ is64 = module .getMemory (memoryOrTableName)->is64 ();
51+ }
52+ if (is64) {
4353 assert (ptr->type == Type::i64 );
4454 ptr = Builder (module ).makeUnary (UnaryOp::WrapInt64, ptr);
4555 }
4656 }
4757
48- void extendAddress64 (Expression*& ptr, Name memoryName) {
58+ void extendAddress64 (Expression*& ptr,
59+ Name memoryOrTableName,
60+ bool isTable = false ) {
4961 if (ptr->type == Type::unreachable) {
5062 return ;
5163 }
5264 auto & module = *getModule ();
53- auto * memory = module .getMemory (memoryName);
54- if (memory->is64 ()) {
65+ bool is64 = false ;
66+ if (isTable) {
67+ is64 = module .getTable (memoryOrTableName)->is64 ();
68+ } else {
69+ is64 = module .getMemory (memoryOrTableName)->is64 ();
70+ }
71+ if (is64) {
5572 assert (ptr->type == Type::i64 );
5673 ptr->type = Type::i32 ;
5774 ptr = Builder (module ).makeUnary (UnaryOp::ExtendUInt32, ptr);
5875 }
5976 }
6077
78+ void wrapTableAddress64 (Expression*& ptr, Name tableName) {
79+ return wrapAddress64 (ptr, tableName, true );
80+ }
81+
82+ void extendTableAddress64 (Expression*& ptr, Name tableName) {
83+ return extendAddress64 (ptr, tableName, true );
84+ }
85+
6186 void visitLoad (Load* curr) { wrapAddress64 (curr->ptr , curr->memory ); }
6287
6388 void visitStore (Store* curr) { wrapAddress64 (curr->ptr , curr->memory ); }
@@ -177,14 +202,92 @@ struct Memory64Lowering : public WalkerPass<PostWalker<Memory64Lowering>> {
177202 }
178203 }
179204
205+ void visitTableSize (TableSize* curr) {
206+ auto & module = *getModule ();
207+ auto * table = module .getTable (curr->table );
208+ if (table->is64 ()) {
209+ auto * size = static_cast <Expression*>(curr);
210+ extendTableAddress64 (size, curr->table );
211+ replaceCurrent (size);
212+ }
213+ }
214+
215+ void visitTableGrow (TableGrow* curr) {
216+ auto & module = *getModule ();
217+ auto * table = module .getTable (curr->table );
218+ if (table->is64 ()) {
219+ wrapTableAddress64 (curr->delta , curr->table );
220+ auto * size = static_cast <Expression*>(curr);
221+ extendTableAddress64 (size, curr->table );
222+ replaceCurrent (size);
223+ }
224+ }
225+
226+ void visitTableFill (TableFill* curr) {
227+ wrapTableAddress64 (curr->dest , curr->table );
228+ wrapTableAddress64 (curr->size , curr->table );
229+ }
230+
231+ void visitTableCopy (TableCopy* curr) {
232+ wrapTableAddress64 (curr->dest , curr->destTable );
233+ wrapTableAddress64 (curr->source , curr->sourceTable );
234+ wrapTableAddress64 (curr->size , curr->destTable );
235+ }
236+
237+ void visitTableInit (TableInit* curr) {
238+ wrapTableAddress64 (curr->dest , curr->table );
239+ }
240+
241+ void visitCallIndirect (CallIndirect* curr) {
242+ wrapTableAddress64 (curr->target , curr->table );
243+ }
244+
245+ void visitElementSegment (ElementSegment* segment) {
246+ auto & module = *getModule ();
247+
248+ // Passive segments don't have any offset to update.
249+ if (segment->table .isNull () || !module .getTable (segment->table )->is64 ()) {
250+ return ;
251+ }
252+
253+ if (auto * c = segment->offset ->dynCast <Const>()) {
254+ c->value = Literal (static_cast <uint32_t >(c->value .geti64 ()));
255+ c->type = Type::i32 ;
256+ } else if (auto * get = segment->offset ->dynCast <GlobalGet>()) {
257+ auto * g = module .getGlobal (get->name );
258+ if (g->imported () && g->base == TABLE_BASE) {
259+ ImportInfo info (module );
260+ auto * memoryBase32 = info.getImportedGlobal (g->module , TABLE_BASE32);
261+ if (!memoryBase32) {
262+ Builder builder (module );
263+ memoryBase32 = builder
264+ .makeGlobal (TABLE_BASE32,
265+ Type::i32 ,
266+ builder.makeConst (int32_t (0 )),
267+ Builder::Immutable)
268+ .release ();
269+ memoryBase32->module = g->module ;
270+ memoryBase32->base = TABLE_BASE32;
271+ module .addGlobal (memoryBase32);
272+ }
273+ // Use this alternative import when initializing the segment.
274+ assert (memoryBase32);
275+ get->type = Type::i32 ;
276+ get->name = memoryBase32->name ;
277+ }
278+ } else {
279+ WASM_UNREACHABLE (" unexpected elem offset" );
280+ }
281+ }
282+
180283 void run (Module* module ) override {
181284 if (!module ->features .has (FeatureSet::Memory64)) {
182285 return ;
183286 }
184287 Super::run (module );
185- // Don't modify the memories themselves until after the traversal since we
186- // that would require memories to be the last thing that get visited, and
187- // we don't want to depend on that specific ordering.
288+ // Don't modify the memories or tables themselves until after the traversal
289+ // since we that would require memories to be the last thing that get
290+ // visited, and we don't want to depend on that specific ordering.
188291 for (auto & memory : module ->memories ) {
189292 if (memory->is64 ()) {
190293 memory->addressType = Type::i32 ;
@@ -193,6 +296,11 @@ struct Memory64Lowering : public WalkerPass<PostWalker<Memory64Lowering>> {
193296 }
194297 }
195298 }
299+ for (auto & table : module ->tables ) {
300+ if (table->is64 ()) {
301+ table->addressType = Type::i32 ;
302+ }
303+ }
196304 module ->features .disable (FeatureSet::Memory64);
197305 }
198306};
0 commit comments