Skip to content

Commit 835a178

Browse files
authored
Fix RefFunc type updating in I64ToI32Lowering (WebAssembly#7390)
We recently started updating RefFunc types in I64ToI32Lowering to ensure that their types matched the updated types of their functions. But the way we updated the types of RefFunc expressions and Functions were not the same. When updating Functions that return i64, we replace the result type with i32 and use a global to propagate the remaining bits to the caller. Previously when updating RefFunc result types, we would instead split i64s into pairs of i32s, depending on multivalue to lower the type. Update the logic for updating RefFunc results to match the existing logic for updating Functions.
1 parent cd3b26d commit 835a178

File tree

2 files changed

+45
-20
lines changed

2 files changed

+45
-20
lines changed

src/passes/I64ToI32Lowering.cpp

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -300,33 +300,35 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
300300
void visitRefFunc(RefFunc* curr) {
301301
auto sig = curr->type.getHeapType().getSignature();
302302

303-
auto lowerTypes = [](Type types) {
304-
bool hasI64 = false;
305-
for (auto t : types) {
306-
if (t == Type::i64) {
307-
hasI64 = true;
308-
break;
309-
}
310-
}
311-
if (!hasI64) {
312-
return types;
303+
bool hasI64Param = false;
304+
for (auto t : sig.params) {
305+
if (t == Type::i64) {
306+
hasI64Param = true;
307+
break;
313308
}
314-
std::vector<Type> newTypes;
315-
for (auto t : types) {
309+
}
310+
auto params = sig.params;
311+
if (hasI64Param) {
312+
std::vector<Type> newParams;
313+
for (auto t : sig.params) {
316314
if (t == Type::i64) {
317-
newTypes.push_back(Type::i32);
318-
newTypes.push_back(Type::i32);
315+
newParams.push_back(Type::i32);
316+
newParams.push_back(Type::i32);
319317
} else {
320-
newTypes.push_back(t);
318+
newParams.push_back(t);
321319
}
322320
}
323-
return Type(newTypes);
321+
params = Type(newParams);
324322
};
323+
auto results = sig.results;
324+
// Update the results the same way we do when visiting functions. We use a
325+
// global rather than multivalue to lower i64 results.
326+
if (results == Type::i64) {
327+
results = Type::i32;
328+
}
325329

326-
auto newParams = lowerTypes(sig.params);
327-
auto newResults = lowerTypes(sig.results);
328-
if (newParams != sig.params || newResults != sig.results) {
329-
curr->type = curr->type.with(HeapType(Signature(newParams, newResults)));
330+
if (params != sig.params || results != sig.results) {
331+
curr->type = curr->type.with(HeapType(Signature(params, results)));
330332
}
331333
}
332334

test/lit/passes/flatten_i64-to-i32-lowering.wast

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -665,3 +665,26 @@
665665
)
666666
)
667667
)
668+
669+
;; Make sure we update the ref.func in the table with the correct return type.
670+
(module
671+
(table 1 1 funcref)
672+
673+
(elem (i32.const 0) $f)
674+
675+
;; CHECK: (type $0 (func (result i32)))
676+
677+
;; CHECK: (global $i64toi32_i32$HIGH_BITS (mut i32) (i32.const 0))
678+
679+
;; CHECK: (table $0 1 1 funcref)
680+
681+
;; CHECK: (elem $0 (i32.const 0) $f)
682+
683+
;; CHECK: (func $f (type $0) (result i32)
684+
;; CHECK-NEXT: (unreachable)
685+
;; CHECK-NEXT: (unreachable)
686+
;; CHECK-NEXT: )
687+
(func $f (result i64)
688+
(unreachable)
689+
)
690+
)

0 commit comments

Comments
 (0)