Skip to content

Commit 3b4cb93

Browse files
authored
Initial implementation of "Memory64" proposal (WebAssembly#3130)
Also includes a lot of new spec tests that eventually need to go into the spec repo
1 parent 1a928bc commit 3b4cb93

72 files changed

Lines changed: 16590 additions & 263 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

scripts/test/wasm2js.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,11 @@
1818
from scripts.test import support
1919

2020
tests = shared.get_tests(shared.options.binaryen_test)
21+
# memory64 is not supported in wasm2js yet (but may be with BigInt eventually).
22+
tests = [t for t in tests if '64.wast' not in t]
2123
spec_tests = shared.options.spec_tests
2224
spec_tests = [t for t in spec_tests if '.fail' not in t]
25+
spec_tests = [t for t in spec_tests if '64.wast' not in t]
2326
wasm2js_tests = shared.get_tests(shared.get_test_dir('wasm2js'), ['.wast'])
2427
assert_tests = ['wasm2js.wast.asserts']
2528
# These tests exercise functionality not supported by wasm2js

src/binaryen-c.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3262,7 +3262,7 @@ void BinaryenSetMemory(BinaryenModuleRef module,
32623262
uint8_t shared) {
32633263
auto* wasm = (Module*)module;
32643264
wasm->memory.initial = initial;
3265-
wasm->memory.max = maximum;
3265+
wasm->memory.max = int32_t(maximum); // Make sure -1 extends.
32663266
wasm->memory.exists = true;
32673267
wasm->memory.shared = shared;
32683268
if (exportName) {

src/ir/ExpressionAnalyzer.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -475,13 +475,11 @@ size_t ExpressionAnalyzer::hash(Expression* curr) {
475475
void visitLiteral(Literal curr) { rehash(digest, curr); }
476476
void visitType(Type curr) { rehash(digest, curr.getID()); }
477477
void visitIndex(Index curr) {
478-
static_assert(sizeof(Index) == sizeof(int32_t),
478+
static_assert(sizeof(Index) == sizeof(uint32_t),
479479
"wasm64 will need changes here");
480480
rehash(digest, curr);
481481
}
482482
void visitAddress(Address curr) {
483-
static_assert(sizeof(Address) == sizeof(int32_t),
484-
"wasm64 will need changes here");
485483
rehash(digest, curr.addr);
486484
}
487485
};

src/literal.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,21 @@ class Literal {
117117
}
118118
}
119119

120+
static Literal makeFromUInt64(uint64_t x, Type type) {
121+
switch (type.getBasic()) {
122+
case Type::i32:
123+
return Literal(int32_t(x));
124+
case Type::i64:
125+
return Literal(int64_t(x));
126+
case Type::f32:
127+
return Literal(float(x));
128+
case Type::f64:
129+
return Literal(double(x));
130+
default:
131+
WASM_UNREACHABLE("unexpected type");
132+
}
133+
}
134+
120135
static Literals makeZero(Type type);
121136
static Literal makeSingleZero(Type type);
122137

src/passes/AlignmentLowering.cpp

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,10 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
3434
if (curr->align == 0 || curr->align == curr->bytes) {
3535
return curr;
3636
}
37+
auto indexType = getModule()->memory.indexType;
3738
Builder builder(*getModule());
3839
assert(curr->type == Type::i32);
39-
auto temp = builder.addVar(getFunction(), Type::i32);
40+
auto temp = builder.addVar(getFunction(), indexType);
4041
Expression* ret;
4142
if (curr->bytes == 2) {
4243
ret = builder.makeBinary(
@@ -45,15 +46,15 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
4546
false,
4647
curr->offset,
4748
1,
48-
builder.makeLocalGet(temp, Type::i32),
49+
builder.makeLocalGet(temp, indexType),
4950
Type::i32),
5051
builder.makeBinary(
5152
ShlInt32,
5253
builder.makeLoad(1,
5354
false,
5455
curr->offset + 1,
5556
1,
56-
builder.makeLocalGet(temp, Type::i32),
57+
builder.makeLocalGet(temp, indexType),
5758
Type::i32),
5859
builder.makeConst(int32_t(8))));
5960
if (curr->signed_) {
@@ -69,15 +70,15 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
6970
false,
7071
curr->offset,
7172
1,
72-
builder.makeLocalGet(temp, Type::i32),
73+
builder.makeLocalGet(temp, indexType),
7374
Type::i32),
7475
builder.makeBinary(
7576
ShlInt32,
7677
builder.makeLoad(1,
7778
false,
7879
curr->offset + 1,
7980
1,
80-
builder.makeLocalGet(temp, Type::i32),
81+
builder.makeLocalGet(temp, indexType),
8182
Type::i32),
8283
builder.makeConst(int32_t(8)))),
8384
builder.makeBinary(
@@ -88,7 +89,7 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
8889
false,
8990
curr->offset + 2,
9091
1,
91-
builder.makeLocalGet(temp, Type::i32),
92+
builder.makeLocalGet(temp, indexType),
9293
Type::i32),
9394
builder.makeConst(int32_t(16))),
9495
builder.makeBinary(
@@ -97,7 +98,7 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
9798
false,
9899
curr->offset + 3,
99100
1,
100-
builder.makeLocalGet(temp, Type::i32),
101+
builder.makeLocalGet(temp, indexType),
101102
Type::i32),
102103
builder.makeConst(int32_t(24)))));
103104
} else if (curr->align == 2) {
@@ -107,15 +108,15 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
107108
false,
108109
curr->offset,
109110
2,
110-
builder.makeLocalGet(temp, Type::i32),
111+
builder.makeLocalGet(temp, indexType),
111112
Type::i32),
112113
builder.makeBinary(
113114
ShlInt32,
114115
builder.makeLoad(2,
115116
false,
116117
curr->offset + 2,
117118
2,
118-
builder.makeLocalGet(temp, Type::i32),
119+
builder.makeLocalGet(temp, indexType),
119120
Type::i32),
120121
builder.makeConst(int32_t(16))));
121122
} else {
@@ -134,7 +135,8 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
134135
}
135136
Builder builder(*getModule());
136137
assert(curr->value->type == Type::i32);
137-
auto tempPtr = builder.addVar(getFunction(), Type::i32);
138+
auto indexType = getModule()->memory.indexType;
139+
auto tempPtr = builder.addVar(getFunction(), indexType);
138140
auto tempValue = builder.addVar(getFunction(), Type::i32);
139141
auto* block =
140142
builder.makeBlock({builder.makeLocalSet(tempPtr, curr->ptr),
@@ -144,14 +146,14 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
144146
builder.makeStore(1,
145147
curr->offset,
146148
1,
147-
builder.makeLocalGet(tempPtr, Type::i32),
149+
builder.makeLocalGet(tempPtr, indexType),
148150
builder.makeLocalGet(tempValue, Type::i32),
149151
Type::i32));
150152
block->list.push_back(builder.makeStore(
151153
1,
152154
curr->offset + 1,
153155
1,
154-
builder.makeLocalGet(tempPtr, Type::i32),
156+
builder.makeLocalGet(tempPtr, indexType),
155157
builder.makeBinary(ShrUInt32,
156158
builder.makeLocalGet(tempValue, Type::i32),
157159
builder.makeConst(int32_t(8))),
@@ -162,14 +164,14 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
162164
builder.makeStore(1,
163165
curr->offset,
164166
1,
165-
builder.makeLocalGet(tempPtr, Type::i32),
167+
builder.makeLocalGet(tempPtr, indexType),
166168
builder.makeLocalGet(tempValue, Type::i32),
167169
Type::i32));
168170
block->list.push_back(builder.makeStore(
169171
1,
170172
curr->offset + 1,
171173
1,
172-
builder.makeLocalGet(tempPtr, Type::i32),
174+
builder.makeLocalGet(tempPtr, indexType),
173175
builder.makeBinary(ShrUInt32,
174176
builder.makeLocalGet(tempValue, Type::i32),
175177
builder.makeConst(int32_t(8))),
@@ -178,7 +180,7 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
178180
1,
179181
curr->offset + 2,
180182
1,
181-
builder.makeLocalGet(tempPtr, Type::i32),
183+
builder.makeLocalGet(tempPtr, indexType),
182184
builder.makeBinary(ShrUInt32,
183185
builder.makeLocalGet(tempValue, Type::i32),
184186
builder.makeConst(int32_t(16))),
@@ -187,7 +189,7 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
187189
1,
188190
curr->offset + 3,
189191
1,
190-
builder.makeLocalGet(tempPtr, Type::i32),
192+
builder.makeLocalGet(tempPtr, indexType),
191193
builder.makeBinary(ShrUInt32,
192194
builder.makeLocalGet(tempValue, Type::i32),
193195
builder.makeConst(int32_t(24))),
@@ -197,14 +199,14 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
197199
builder.makeStore(2,
198200
curr->offset,
199201
2,
200-
builder.makeLocalGet(tempPtr, Type::i32),
202+
builder.makeLocalGet(tempPtr, indexType),
201203
builder.makeLocalGet(tempValue, Type::i32),
202204
Type::i32));
203205
block->list.push_back(builder.makeStore(
204206
2,
205207
curr->offset + 2,
206208
2,
207-
builder.makeLocalGet(tempPtr, Type::i32),
209+
builder.makeLocalGet(tempPtr, indexType),
208210
builder.makeBinary(ShrUInt32,
209211
builder.makeLocalGet(tempValue, Type::i32),
210212
builder.makeConst(int32_t(16))),
@@ -254,14 +256,15 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
254256
break;
255257
}
256258
// Load two 32-bit pieces, and combine them.
257-
auto temp = builder.addVar(getFunction(), Type::i32);
259+
auto indexType = getModule()->memory.indexType;
260+
auto temp = builder.addVar(getFunction(), indexType);
258261
auto* set = builder.makeLocalSet(temp, curr->ptr);
259262
Expression* low =
260263
lowerLoadI32(builder.makeLoad(4,
261264
false,
262265
curr->offset,
263266
curr->align,
264-
builder.makeLocalGet(temp, Type::i32),
267+
builder.makeLocalGet(temp, indexType),
265268
Type::i32));
266269
low = builder.makeUnary(ExtendUInt32, low);
267270
// Note that the alignment is assumed to be the same here, even though
@@ -273,7 +276,7 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
273276
false,
274277
curr->offset + 4,
275278
curr->align,
276-
builder.makeLocalGet(temp, Type::i32),
279+
builder.makeLocalGet(temp, indexType),
277280
Type::i32));
278281
high = builder.makeUnary(ExtendUInt32, high);
279282
high =
@@ -332,7 +335,8 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
332335
value = builder.makeUnary(ReinterpretFloat64, value);
333336
}
334337
// Store as two 32-bit pieces.
335-
auto tempPtr = builder.addVar(getFunction(), Type::i32);
338+
auto indexType = getModule()->memory.indexType;
339+
auto tempPtr = builder.addVar(getFunction(), indexType);
336340
auto* setPtr = builder.makeLocalSet(tempPtr, curr->ptr);
337341
auto tempValue = builder.addVar(getFunction(), Type::i64);
338342
auto* setValue = builder.makeLocalSet(tempValue, value);
@@ -342,7 +346,7 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
342346
builder.makeStore(4,
343347
curr->offset,
344348
curr->align,
345-
builder.makeLocalGet(tempPtr, Type::i32),
349+
builder.makeLocalGet(tempPtr, indexType),
346350
low,
347351
Type::i32));
348352
Expression* high =
@@ -358,7 +362,7 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
358362
builder.makeStore(4,
359363
curr->offset + 4,
360364
curr->align,
361-
builder.makeLocalGet(tempPtr, Type::i32),
365+
builder.makeLocalGet(tempPtr, indexType),
362366
high,
363367
Type::i32));
364368
replacement = builder.makeBlock({setPtr, setValue, low, high});

src/passes/AvoidReinterprets.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,13 @@ struct AvoidReinterprets : public WalkerPass<PostWalker<AvoidReinterprets>> {
117117

118118
void optimize(Function* func) {
119119
std::set<Load*> unoptimizables;
120+
auto indexType = getModule()->memory.indexType;
120121
for (auto& pair : infos) {
121122
auto* load = pair.first;
122123
auto& info = pair.second;
123124
if (info.reinterpreted && canReplaceWithReinterpret(load)) {
124125
// We should use another load here, to avoid reinterprets.
125-
info.ptrLocal = Builder::addVar(func, Type::i32);
126+
info.ptrLocal = Builder::addVar(func, indexType);
126127
info.reinterpretedLocal =
127128
Builder::addVar(func, load->type.reinterpret());
128129
} else {
@@ -176,7 +177,8 @@ struct AvoidReinterprets : public WalkerPass<PostWalker<AvoidReinterprets>> {
176177
auto& info = iter->second;
177178
Builder builder(*module);
178179
auto* ptr = curr->ptr;
179-
curr->ptr = builder.makeLocalGet(info.ptrLocal, Type::i32);
180+
auto indexType = getModule()->memory.indexType;
181+
curr->ptr = builder.makeLocalGet(info.ptrLocal, indexType);
180182
// Note that the other load can have its sign set to false - if the
181183
// original were an integer, the other is a float anyhow; and if
182184
// original were a float, we don't know what sign to use.
@@ -185,7 +187,7 @@ struct AvoidReinterprets : public WalkerPass<PostWalker<AvoidReinterprets>> {
185187
builder.makeLocalSet(
186188
info.reinterpretedLocal,
187189
makeReinterpretedLoad(
188-
curr, builder.makeLocalGet(info.ptrLocal, Type::i32))),
190+
curr, builder.makeLocalGet(info.ptrLocal, indexType))),
189191
curr}));
190192
}
191193
}
@@ -201,6 +203,7 @@ struct AvoidReinterprets : public WalkerPass<PostWalker<AvoidReinterprets>> {
201203
}
202204
} finalOptimizer(infos, localGraph, getModule(), getPassOptions());
203205

206+
finalOptimizer.setModule(getModule());
204207
finalOptimizer.walk(func->body);
205208
}
206209
};

src/passes/InstrumentMemory.cpp

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,14 @@ struct InstrumentMemory : public WalkerPass<PostWalker<InstrumentMemory>> {
7878
void visitLoad(Load* curr) {
7979
id++;
8080
Builder builder(*getModule());
81+
auto indexType = getModule()->memory.indexType;
82+
auto offset = builder.makeConstPtr(curr->offset.addr);
8183
curr->ptr = builder.makeCall(load_ptr,
8284
{builder.makeConst(int32_t(id)),
8385
builder.makeConst(int32_t(curr->bytes)),
84-
builder.makeConst(int32_t(curr->offset.addr)),
86+
offset,
8587
curr->ptr},
86-
Type::i32);
88+
indexType);
8789
Name target;
8890
switch (curr->type.getBasic()) {
8991
case Type::i32:
@@ -108,12 +110,14 @@ struct InstrumentMemory : public WalkerPass<PostWalker<InstrumentMemory>> {
108110
void visitStore(Store* curr) {
109111
id++;
110112
Builder builder(*getModule());
113+
auto indexType = getModule()->memory.indexType;
114+
auto offset = builder.makeConstPtr(curr->offset.addr);
111115
curr->ptr = builder.makeCall(store_ptr,
112116
{builder.makeConst(int32_t(id)),
113117
builder.makeConst(int32_t(curr->bytes)),
114-
builder.makeConst(int32_t(curr->offset.addr)),
118+
offset,
115119
curr->ptr},
116-
Type::i32);
120+
indexType);
117121
Name target;
118122
switch (curr->value->type.getBasic()) {
119123
case Type::i32:
@@ -136,14 +140,15 @@ struct InstrumentMemory : public WalkerPass<PostWalker<InstrumentMemory>> {
136140
}
137141

138142
void visitModule(Module* curr) {
143+
auto indexType = curr->memory.indexType;
139144
addImport(
140-
curr, load_ptr, {Type::i32, Type::i32, Type::i32, Type::i32}, Type::i32);
145+
curr, load_ptr, {Type::i32, Type::i32, indexType, indexType}, indexType);
141146
addImport(curr, load_val_i32, {Type::i32, Type::i32}, Type::i32);
142147
addImport(curr, load_val_i64, {Type::i32, Type::i64}, Type::i64);
143148
addImport(curr, load_val_f32, {Type::i32, Type::f32}, Type::f32);
144149
addImport(curr, load_val_f64, {Type::i32, Type::f64}, Type::f64);
145150
addImport(
146-
curr, store_ptr, {Type::i32, Type::i32, Type::i32, Type::i32}, Type::i32);
151+
curr, store_ptr, {Type::i32, Type::i32, indexType, indexType}, indexType);
147152
addImport(curr, store_val_i32, {Type::i32, Type::i32}, Type::i32);
148153
addImport(curr, store_val_i64, {Type::i32, Type::i64}, Type::i64);
149154
addImport(curr, store_val_f32, {Type::i32, Type::f32}, Type::f32);

0 commit comments

Comments
 (0)