Skip to content

Commit 89d1cf9

Browse files
authored
Make local.tee's type its local's type (#2511)
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 #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 759c485 commit 89d1cf9

28 files changed

+86
-65
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ full changeset diff at the end of each section.
1515
Current Trunk
1616
-------------
1717

18+
- `local.tee`'s C/Binaryen.js API now takes an additional type parameter for its
19+
local type, like `local.get`. This is required to handle subtypes.
1820
- Added load_splat SIMD instructions
1921
- Binaryen.js instruction API changes:
2022
- `notify` -> `atomic.notify`

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
}
@@ -2158,7 +2158,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
21582158
auto set = allocator.alloc<LocalSet>();
21592159
set->index = function->getLocalIndex(I32_TEMP);
21602160
set->value = value;
2161-
set->setTee(false);
2161+
set->makeSet();
21622162
set->finalize();
21632163
auto get = [&]() {
21642164
auto ret = allocator.alloc<LocalGet>();
@@ -2264,7 +2264,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
22642264
view.bytes,
22652265
0,
22662266
processUnshifted(ast[2][1], view.bytes),
2267-
builder.makeLocalTee(temp, process(ast[2][2])),
2267+
builder.makeLocalTee(temp, process(ast[2][2]), type),
22682268
type),
22692269
builder.makeLocalGet(temp, type));
22702270
} else if (name == Atomics_exchange) {

src/binaryen-c.cpp

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

11981198
ret->index = index;
11991199
ret->value = (Expression*)value;
1200-
ret->setTee(false);
1200+
ret->makeSet();
12011201
ret->finalize();
12021202
return static_cast<Expression*>(ret);
12031203
}
12041204
BinaryenExpressionRef BinaryenLocalTee(BinaryenModuleRef module,
12051205
BinaryenIndex index,
1206-
BinaryenExpressionRef value) {
1206+
BinaryenExpressionRef value,
1207+
BinaryenType type) {
12071208
auto* ret = ((Module*)module)->allocator.alloc<LocalSet>();
12081209

12091210
if (tracing) {
1210-
traceExpression(ret, "BinaryenLocalTee", index, value);
1211+
traceExpression(ret, "BinaryenLocalTee", index, value, type);
12111212
}
12121213

12131214
ret->index = index;
12141215
ret->value = (Expression*)value;
1215-
ret->setTee(true);
1216+
ret->makeTee(Type(type));
12161217
ret->finalize();
12171218
return static_cast<Expression*>(ret);
12181219
}

src/binaryen-c.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -650,8 +650,10 @@ BINARYEN_API BinaryenExpressionRef BinaryenLocalGet(BinaryenModuleRef module,
650650
BinaryenType type);
651651
BINARYEN_API BinaryenExpressionRef BinaryenLocalSet(
652652
BinaryenModuleRef module, BinaryenIndex index, BinaryenExpressionRef value);
653-
BINARYEN_API BinaryenExpressionRef BinaryenLocalTee(
654-
BinaryenModuleRef module, BinaryenIndex index, BinaryenExpressionRef value);
653+
BINARYEN_API BinaryenExpressionRef BinaryenLocalTee(BinaryenModuleRef module,
654+
BinaryenIndex index,
655+
BinaryenExpressionRef value,
656+
BinaryenType type);
655657
BINARYEN_API BinaryenExpressionRef BinaryenGlobalGet(BinaryenModuleRef module,
656658
const char* name,
657659
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: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -540,8 +540,11 @@ function wrapModule(module, self) {
540540
'set': function(index, value) {
541541
return Module['_BinaryenLocalSet'](module, index, value);
542542
},
543-
'tee': function(index, value) {
544-
return Module['_BinaryenLocalTee'](module, index, value);
543+
'tee': function(index, value, type) {
544+
if (typeof type === 'undefined') {
545+
throw new Error("local.tee's type should be defined");
546+
}
547+
return Module['_BinaryenLocalTee'](module, index, value, type);
545548
}
546549
}
547550

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+
Type localType = getFunction()->getLocalType(set->index);
178+
replaceCurrent(builder.makeLocalGet(set->index, localType));
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
}

0 commit comments

Comments
 (0)