Skip to content

Commit dad5c60

Browse files
committed
Make local.tee's type its local's type
According to the current spec, `local.tee`'s return type should be the same as its local's type. (Discussions on whether we should change this rule is going on in WebAssembly/reference-types#55, but here I will assume this spec does not change. If this changes, we should change many parts of Binaryen transformation anyway...) But currently in Binaryen `local.tee`'s type is computed from its value's type. This didn't make any difference in the MVP, but after we have subtype relationship in WebAssembly#2451, this can become a problem. For example: ``` (func $test (result funcref) (local $0 anyref) (local.tee $0 (ref.func $test) ) ) ``` This shouldn't validate in the spec, but this will pass Binaryen validation with the current `local.tee` implementation. This makes `local.tee`'s type computed from the local's type, and makes `LocalSet::makeTee` get a type parameter, to which we should pass the its corresponding local's type. We don't embed the local type in the class `LocalSet` because it may increase memory size. This also fixes the type of `local.get` to be the local type where `local.get` and `local.set` pair is created from `local.tee`.
1 parent 65c334d commit dad5c60

26 files changed

Lines changed: 80 additions & 57 deletions

src/asm2wasm.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1907,7 +1907,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
19071907
auto ret = allocator.alloc<LocalSet>();
19081908
ret->index = function->getLocalIndex(assign->target());
19091909
ret->value = process(assign->value());
1910-
ret->setTee(false);
1910+
ret->makeSet();
19111911
ret->finalize();
19121912
return ret;
19131913
}
@@ -2160,7 +2160,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
21602160
auto set = allocator.alloc<LocalSet>();
21612161
set->index = function->getLocalIndex(I32_TEMP);
21622162
set->value = value;
2163-
set->setTee(false);
2163+
set->makeSet();
21642164
set->finalize();
21652165
auto get = [&]() {
21662166
auto ret = allocator.alloc<LocalGet>();
@@ -2266,7 +2266,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
22662266
view.bytes,
22672267
0,
22682268
processUnshifted(ast[2][1], view.bytes),
2269-
builder.makeLocalTee(temp, process(ast[2][2])),
2269+
builder.makeLocalTee(temp, process(ast[2][2]), type),
22702270
type),
22712271
builder.makeLocalGet(temp, type));
22722272
} else if (name == Atomics_exchange) {

src/binaryen-c.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1261,22 +1261,23 @@ BinaryenExpressionRef BinaryenLocalSet(BinaryenModuleRef module,
12611261

12621262
ret->index = index;
12631263
ret->value = (Expression*)value;
1264-
ret->setTee(false);
1264+
ret->makeSet();
12651265
ret->finalize();
12661266
return static_cast<Expression*>(ret);
12671267
}
12681268
BinaryenExpressionRef BinaryenLocalTee(BinaryenModuleRef module,
12691269
BinaryenIndex index,
1270-
BinaryenExpressionRef value) {
1270+
BinaryenExpressionRef value,
1271+
BinaryenType type) {
12711272
auto* ret = ((Module*)module)->allocator.alloc<LocalSet>();
12721273

12731274
if (tracing) {
1274-
traceExpression(ret, "BinaryenLocalTee", index, value);
1275+
traceExpression(ret, "BinaryenLocalTee", index, value, type);
12751276
}
12761277

12771278
ret->index = index;
12781279
ret->value = (Expression*)value;
1279-
ret->setTee(true);
1280+
ret->makeTee(Type(type));
12801281
ret->finalize();
12811282
return static_cast<Expression*>(ret);
12821283
}

src/binaryen-c.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -665,8 +665,10 @@ BINARYEN_API BinaryenExpressionRef BinaryenLocalGet(BinaryenModuleRef module,
665665
BinaryenType type);
666666
BINARYEN_API BinaryenExpressionRef BinaryenLocalSet(
667667
BinaryenModuleRef module, BinaryenIndex index, BinaryenExpressionRef value);
668-
BINARYEN_API BinaryenExpressionRef BinaryenLocalTee(
669-
BinaryenModuleRef module, BinaryenIndex index, BinaryenExpressionRef value);
668+
BINARYEN_API BinaryenExpressionRef BinaryenLocalTee(BinaryenModuleRef module,
669+
BinaryenIndex index,
670+
BinaryenExpressionRef value,
671+
BinaryenType type);
670672
BINARYEN_API BinaryenExpressionRef BinaryenGlobalGet(BinaryenModuleRef module,
671673
const char* name,
672674
BinaryenType type);

src/ir/ExpressionManipulator.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ flexibleCopy(Expression* original, Module& wasm, CustomCopier custom) {
9191
}
9292
Expression* visitLocalSet(LocalSet* curr) {
9393
if (curr->isTee()) {
94-
return builder.makeLocalTee(curr->index, copy(curr->value));
94+
return builder.makeLocalTee(curr->index, copy(curr->value), curr->type);
9595
} else {
9696
return builder.makeLocalSet(curr->index, copy(curr->value));
9797
}

src/ir/localize.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ struct Localizer {
3636
index = set->index;
3737
} else {
3838
index = Builder::addVar(func, expr->type);
39-
expr = Builder(*wasm).makeLocalTee(index, expr);
39+
expr = Builder(*wasm).makeLocalTee(index, expr, expr->type);
4040
}
4141
}
4242
};

src/js/binaryen.js-post.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -541,8 +541,8 @@ function wrapModule(module, self) {
541541
'set': function(index, value) {
542542
return Module['_BinaryenLocalSet'](module, index, value);
543543
},
544-
'tee': function(index, value) {
545-
return Module['_BinaryenLocalTee'](module, index, value);
544+
'tee': function(index, value, type) {
545+
return Module['_BinaryenLocalTee'](module, index, value, type);
546546
}
547547
}
548548

src/passes/Flatten.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,9 +172,10 @@ struct Flatten
172172
replaceCurrent(set->value); // trivial, no set happens
173173
} else {
174174
// use a set in a prelude + a get
175-
set->setTee(false);
175+
set->makeSet();
176176
ourPreludes.push_back(set);
177-
replaceCurrent(builder.makeLocalGet(set->index, set->value->type));
177+
replaceCurrent(builder.makeLocalGet(
178+
set->index, getFunction()->getLocalType(set->index)));
178179
}
179180
}
180181
} else if (auto* br = curr->dynCast<Break>()) {

src/passes/LocalCSE.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,9 @@ struct LocalCSE : public WalkerPass<LinearExecutionWalker<LocalCSE>> {
184184
if (iter != usables.end()) {
185185
// already exists in the table, this is good to reuse
186186
auto& info = iter->second;
187+
Type localType = getFunction()->getLocalType(info.index);
187188
set->value =
188-
Builder(*getModule()).makeLocalGet(info.index, value->type);
189+
Builder(*getModule()).makeLocalGet(info.index, localType);
189190
anotherPass = true;
190191
} else {
191192
// not in table, add this, maybe we can help others later

src/passes/MergeLocals.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ struct MergeLocals
8888
if (auto* get = curr->value->dynCast<LocalGet>()) {
8989
if (get->index != curr->index) {
9090
Builder builder(*getModule());
91-
auto* trivial = builder.makeLocalTee(get->index, get);
91+
auto* trivial = builder.makeLocalTee(get->index, get, get->type);
9292
curr->value = trivial;
9393
copies.push_back(curr);
9494
}

src/passes/RemoveUnusedBrs.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
287287
Expression* z;
288288
replaceCurrent(
289289
z = builder.makeIf(
290-
builder.makeLocalTee(temp, curr->condition),
290+
builder.makeLocalTee(temp, curr->condition, i32),
291291
builder.makeIf(builder.makeBinary(EqInt32,
292292
builder.makeLocalGet(temp, i32),
293293
builder.makeConst(Literal(int32_t(
@@ -1074,7 +1074,7 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
10741074
iff->finalize();
10751075
Expression* replacement = iff;
10761076
if (tee) {
1077-
set->setTee(false);
1077+
set->makeSet();
10781078
// We need a block too.
10791079
replacement = builder.makeSequence(iff,
10801080
get // reuse the get

0 commit comments

Comments
 (0)