diff --git a/src/passes/Flatten.cpp b/src/passes/Flatten.cpp index 10c791f609e..b9af7eaccb0 100644 --- a/src/passes/Flatten.cpp +++ b/src/passes/Flatten.cpp @@ -258,8 +258,7 @@ struct Flatten auto type = br->value->type; if (type.isConcrete()) { // we are sending a value. use a local instead - Type blockType = findBreakTarget(br->name)->type; - Index temp = getTempForBreakTarget(br->name, blockType); + Index temp = getTempForBreakTarget(br->name); ourPreludes.push_back(builder.makeLocalSet(temp, br->value)); // br_if leaves a value on the stack if not taken, which later can @@ -283,7 +282,7 @@ struct Flatten // with anyref type in case for flowing out. Here we create the // second 'flowing out' local in case two block's types are // different. - if (type != blockType) { + if (type != findBreakTarget(br->name)->type) { temp = builder.addVar(getFunction(), type); ourPreludes.push_back(builder.makeLocalSet( temp, ExpressionManipulator::copy(br->value, *getModule()))); @@ -318,9 +317,8 @@ struct Flatten // we don't know which break target will be hit - assign to them all auto names = BranchUtils::getUniqueTargets(sw); for (auto name : names) { - ourPreludes.push_back( - builder.makeLocalSet(getTempForBreakTarget(name, type), - builder.makeLocalGet(temp, type))); + ourPreludes.push_back(builder.makeLocalSet( + getTempForBreakTarget(name), builder.makeLocalGet(temp, type))); } sw->value = nullptr; sw->finalize(); @@ -408,13 +406,14 @@ struct Flatten // get the temp local to be used for breaks to that target. allocates // one if there isn't one yet - Index getTempForBreakTarget(Name name, Type type) { + Index getTempForBreakTarget(Name name) { auto iter = breakTemps.find(name); if (iter != breakTemps.end()) { return iter->second; } else { return breakTemps[name] = - Builder(*getModule()).addVar(getFunction(), type); + Builder(*getModule()) + .addVar(getFunction(), findBreakTarget(name)->type); } } }; diff --git a/test/lit/passes/flatten.wast b/test/lit/passes/flatten.wast index 7e890d6aeb3..1e524d38c6b 100644 --- a/test/lit/passes/flatten.wast +++ b/test/lit/passes/flatten.wast @@ -18,4 +18,38 @@ ;; modified (local.get $0) ) + + ;; CHECK: (func $br_table-subtype (type $2) (result funcref) + ;; CHECK-NEXT: (local $0 nullfuncref) + ;; CHECK-NEXT: (local $1 funcref) + ;; CHECK-NEXT: (local $2 funcref) + ;; CHECK-NEXT: (block $block + ;; CHECK-NEXT: (local.set $0 + ;; CHECK-NEXT: (ref.null nofunc) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $1 + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (br_table $block $block + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $2 + ;; CHECK-NEXT: (local.get $1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (return + ;; CHECK-NEXT: (local.get $2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $br_table-subtype (result funcref) + ;; The br_table's value is more refined than the place we branch to, so we + ;; need to be careful with the types of our temp locals. + (block $block (result funcref) + (br_table $block $block + (ref.null nofunc) + (i32.const 0) + ) + ) + ) )