diff --git a/src/passes/I64ToI32Lowering.cpp b/src/passes/I64ToI32Lowering.cpp index 67dfd36d849..0cc6b2bd35b 100644 --- a/src/passes/I64ToI32Lowering.cpp +++ b/src/passes/I64ToI32Lowering.cpp @@ -300,33 +300,35 @@ struct I64ToI32Lowering : public WalkerPass> { void visitRefFunc(RefFunc* curr) { auto sig = curr->type.getHeapType().getSignature(); - auto lowerTypes = [](Type types) { - bool hasI64 = false; - for (auto t : types) { - if (t == Type::i64) { - hasI64 = true; - break; - } - } - if (!hasI64) { - return types; + bool hasI64Param = false; + for (auto t : sig.params) { + if (t == Type::i64) { + hasI64Param = true; + break; } - std::vector newTypes; - for (auto t : types) { + } + auto params = sig.params; + if (hasI64Param) { + std::vector newParams; + for (auto t : sig.params) { if (t == Type::i64) { - newTypes.push_back(Type::i32); - newTypes.push_back(Type::i32); + newParams.push_back(Type::i32); + newParams.push_back(Type::i32); } else { - newTypes.push_back(t); + newParams.push_back(t); } } - return Type(newTypes); + params = Type(newParams); }; + auto results = sig.results; + // Update the results the same way we do when visiting functions. We use a + // global rather than multivalue to lower i64 results. + if (results == Type::i64) { + results = Type::i32; + } - auto newParams = lowerTypes(sig.params); - auto newResults = lowerTypes(sig.results); - if (newParams != sig.params || newResults != sig.results) { - curr->type = curr->type.with(HeapType(Signature(newParams, newResults))); + if (params != sig.params || results != sig.results) { + curr->type = curr->type.with(HeapType(Signature(params, results))); } } diff --git a/test/lit/passes/flatten_i64-to-i32-lowering.wast b/test/lit/passes/flatten_i64-to-i32-lowering.wast index e5e556c79ab..beb15b2e46d 100644 --- a/test/lit/passes/flatten_i64-to-i32-lowering.wast +++ b/test/lit/passes/flatten_i64-to-i32-lowering.wast @@ -665,3 +665,26 @@ ) ) ) + +;; Make sure we update the ref.func in the table with the correct return type. +(module + (table 1 1 funcref) + + (elem (i32.const 0) $f) + + ;; CHECK: (type $0 (func (result i32))) + + ;; CHECK: (global $i64toi32_i32$HIGH_BITS (mut i32) (i32.const 0)) + + ;; CHECK: (table $0 1 1 funcref) + + ;; CHECK: (elem $0 (i32.const 0) $f) + + ;; CHECK: (func $f (type $0) (result i32) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + (func $f (result i64) + (unreachable) + ) +)