/*
- * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
freeUnnecessaryNodes();
m_graph.clearReplacements();
canonicalizeLocalsInBlocks();
+ specialCaseArguments();
propagatePhis<LocalOperand>();
propagatePhis<ArgumentOperand>();
computeIsFlushed();
node->children.setChild1(Edge());
break;
case Phantom:
- if (!node->child1())
+ if (!node->child1()) {
+ m_graph.m_allocator.free(node);
continue;
+ }
switch (node->child1()->op()) {
case Phi:
case SetArgument:
case SetLocal:
- node->convertToPhantomLocal();
+ node->convertPhantomToPhantomLocal();
break;
default:
ASSERT(node->child1()->hasResult());
}
template<OperandKind operandKind>
- void clearVariablesAtHeadAndTail()
+ void clearVariables()
{
ASSERT(
m_block->variablesAtHead.sizeFor<operandKind>()
== m_block->variablesAtTail.sizeFor<operandKind>());
for (unsigned i = m_block->variablesAtHead.sizeFor<operandKind>(); i--;) {
- m_block->variablesAtHead.atFor<operandKind>(i) = 0;
- m_block->variablesAtTail.atFor<operandKind>(i) = 0;
+ m_block->variablesAtHead.atFor<operandKind>(i) = nullptr;
+ m_block->variablesAtTail.atFor<operandKind>(i) = nullptr;
}
}
return;
}
- if (variable->isCaptured()) {
- variable->setIsLoadedFrom(true);
- if (otherNode->op() == GetLocal)
- otherNode = otherNode->child1().node();
- else
- ASSERT(otherNode->op() == SetLocal || otherNode->op() == SetArgument);
-
- ASSERT(otherNode->op() == Phi || otherNode->op() == SetLocal || otherNode->op() == SetArgument);
-
- // Keep this GetLocal but link it to the prior ones.
- node->children.setChild1(Edge(otherNode));
- m_block->variablesAtTail.atFor<operandKind>(idx) = node;
- return;
- }
-
if (otherNode->op() == GetLocal) {
// Replace all references to this GetLocal with otherNode.
- node->misc.replacement = otherNode;
+ node->replaceWith(otherNode);
return;
}
ASSERT(otherNode->op() == SetLocal);
- node->misc.replacement = otherNode->child1().node();
+ node->replaceWith(otherNode->child1().node());
return;
}
canonicalizeGetLocalFor<LocalOperand>(node, variable, variable->local().toLocal());
}
- void canonicalizeSetLocal(Node* node)
- {
- m_block->variablesAtTail.setOperand(node->local(), node);
- }
-
template<NodeType nodeType, OperandKind operandKind>
void canonicalizeFlushOrPhantomLocalFor(Node* node, VariableAccessData* variable, size_t idx)
{
// for the purpose of OSR. PhantomLocal(SetLocal) means: at this point I
// know that I would have read the value written by that SetLocal. This is
// redundant and inefficient, since really it just means that we want to
- // be keeping the operand to the SetLocal alive. The SetLocal may die, and
- // we'll be fine because OSR tracks dead SetLocals.
-
- // So we turn this into a Phantom on the child of the SetLocal.
+ // keep the last MovHinted value of that local alive.
- node->convertToPhantom();
- node->children.setChild1(otherNode->child1());
+ node->remove();
return;
}
canonicalizeFlushOrPhantomLocalFor<nodeType, LocalOperand>(node, variable, variable->local().toLocal());
}
- void canonicalizeSetArgument(Node* node)
+ void canonicalizeSet(Node* node)
{
- VirtualRegister local = node->local();
- ASSERT(local.isArgument());
- int argument = local.toArgument();
- m_block->variablesAtHead.setArgumentFirstTime(argument, node);
- m_block->variablesAtTail.setArgumentFirstTime(argument, node);
+ m_block->variablesAtTail.setOperand(node->local(), node);
}
void canonicalizeLocalsInBlock()
return;
ASSERT(m_block->isReachable);
- clearVariablesAtHeadAndTail<ArgumentOperand>();
- clearVariablesAtHeadAndTail<LocalOperand>();
+ clearVariables<ArgumentOperand>();
+ clearVariables<LocalOperand>();
// Assumes that all phi references have been removed. Assumes that things that
// should be live have a non-zero ref count, but doesn't assume that the ref
// there ever was a SetLocal and it was followed by Flushes, then the tail
// variable will be a SetLocal and not those subsequent Flushes.
//
- // Child of GetLocal: the operation that the GetLocal keeps alive. For
- // uncaptured locals, it may be a Phi from the current block. For arguments,
- // it may be a SetArgument. For captured locals and arguments it may also be
- // a SetLocal.
+ // Child of GetLocal: the operation that the GetLocal keeps alive. It may be
+ // a Phi from the current block. For arguments, it may be a SetArgument.
//
// Child of SetLocal: must be a value producing node.
//
break;
case SetLocal:
- canonicalizeSetLocal(node);
+ canonicalizeSet(node);
break;
case Flush:
break;
case SetArgument:
- canonicalizeSetArgument(node);
+ canonicalizeSet(node);
break;
default:
}
}
+ void specialCaseArguments()
+ {
+ // Normally, a SetArgument denotes the start of a live range for a local's value on the stack.
+ // But those SetArguments used for the actual arguments to the machine CodeBlock get
+ // special-cased. We could have instead used two different node types - one for the arguments
+ // at the prologue case, and another for the other uses. But this seemed like IR overkill.
+ for (unsigned i = m_graph.m_arguments.size(); i--;)
+ m_graph.block(0)->variablesAtHead.setArgumentFirstTime(i, m_graph.m_arguments[i]);
+ }
+
template<OperandKind operandKind>
void propagatePhis()
{
}
while (!m_flushedLocalOpWorklist.isEmpty()) {
Node* node = m_flushedLocalOpWorklist.takeLast();
- ASSERT(node->flags() & NodeIsFlushed);
- DFG_NODE_DO_TO_CHILDREN(m_graph, node, addFlushedLocalEdge);
+ switch (node->op()) {
+ case SetLocal:
+ case SetArgument:
+ break;
+
+ case Flush:
+ case Phi:
+ ASSERT(node->flags() & NodeIsFlushed);
+ DFG_NODE_DO_TO_CHILDREN(m_graph, node, addFlushedLocalEdge);
+ break;
+
+ default:
+ DFG_CRASH(m_graph, node, "Invalid node in flush graph");
+ break;
+ }
}
}