}
+static void TransferOsrValueTypesFromLoopPhis(Zone* zone, Node* osr_loop_entry,
+ Node* osr_loop) {
+ // Find the index of the osr loop entry into the loop.
+ int index = 0;
+ for (index = 0; index < osr_loop->InputCount(); index++) {
+ if (osr_loop->InputAt(index) == osr_loop_entry) break;
+ }
+ if (index == osr_loop->InputCount()) return;
+
+ for (Node* osr_value : osr_loop_entry->uses()) {
+ if (osr_value->opcode() != IrOpcode::kOsrValue) continue;
+ bool unknown = true;
+ for (Node* phi : osr_value->uses()) {
+ if (phi->opcode() != IrOpcode::kPhi) continue;
+ if (NodeProperties::GetControlInput(phi) != osr_loop) continue;
+ if (phi->InputAt(index) != osr_value) continue;
+ if (NodeProperties::IsTyped(phi)) {
+ // Transfer the type from the phi to the OSR value itself.
+ Bounds phi_bounds = NodeProperties::GetBounds(phi);
+ if (unknown) {
+ NodeProperties::SetBounds(osr_value, phi_bounds);
+ } else {
+ Bounds osr_bounds = NodeProperties::GetBounds(osr_value);
+ NodeProperties::SetBounds(osr_value,
+ Bounds::Both(phi_bounds, osr_bounds, zone));
+ }
+ unknown = false;
+ }
+ }
+ if (unknown) NodeProperties::SetBounds(osr_value, Bounds::Unbounded(zone));
+ }
+}
+
+
bool OsrHelper::Deconstruct(JSGraph* jsgraph, CommonOperatorBuilder* common,
Zone* tmp_zone) {
Graph* graph = jsgraph->graph();
CHECK(osr_loop); // Should have found the OSR loop.
+ // Transfer the types from loop phis to the OSR values which flow into them.
+ TransferOsrValueTypesFromLoopPhis(graph->zone(), osr_loop_entry, osr_loop);
+
// Analyze the graph to determine how deeply nested the OSR loop is.
LoopTree* loop_tree = LoopFinder::BuildLoopTree(graph, tmp_zone);
Bounds Typer::Visitor::TypeOsrValue(Node* node) {
- // OSR values explicitly have type {None} before OSR form is deconstructed.
if (node->InputAt(0)->opcode() == IrOpcode::kOsrLoopEntry) {
+ // Before deconstruction, OSR values have type {None} to avoid polluting
+ // the types of phis and other nodes in the graph.
return Bounds(Type::None(), Type::None());
}
- // TODO(turbofan): preserve the type of OSR values after deconstruction.
+ if (NodeProperties::IsTyped(node)) {
+ // After deconstruction, OSR values may have had a type explicitly set.
+ return NodeProperties::GetBounds(node);
+ }
+ // Otherwise, be conservative.
return Bounds::Unbounded(zone());
}
}
+TEST(Deconstruct_osr1_type) {
+ OsrDeconstructorTester T(1);
+
+ Node* loop = T.NewOsrLoop(1);
+ Node* osr_phi =
+ T.NewOsrPhi(loop, T.jsgraph.OneConstant(), 0, T.jsgraph.ZeroConstant());
+ Type* type = Type::Signed32();
+ NodeProperties::SetBounds(osr_phi, Bounds(type, type));
+
+ Node* ret = T.graph.NewNode(T.common.Return(), osr_phi, T.start, loop);
+ T.graph.SetEnd(ret);
+
+ OsrHelper helper(0, 0);
+ helper.Deconstruct(&T.jsgraph, &T.common, T.main_zone());
+
+ CHECK_EQ(type, NodeProperties::GetBounds(T.osr_values[0]).lower);
+ CHECK_EQ(type, NodeProperties::GetBounds(T.osr_values[0]).upper);
+
+ CheckInputs(loop, T.start, loop);
+ CheckInputs(osr_phi, T.osr_values[0], T.jsgraph.ZeroConstant(), loop);
+ CheckInputs(ret, osr_phi, T.start, loop);
+}
+
+
TEST(Deconstruct_osr_remove_prologue) {
OsrDeconstructorTester T(1);
Diamond d(&T.graph, &T.common, T.p0);