DFGBackwardsPropagationPhase.cpp [plain text]
#include "config.h"
#include "DFGBackwardsPropagationPhase.h"
#if ENABLE(DFG_JIT)
#include "DFGBasicBlockInlines.h"
#include "DFGGraph.h"
#include "DFGPhase.h"
#include "JSCInlines.h"
namespace JSC { namespace DFG {
class BackwardsPropagationPhase : public Phase {
public:
BackwardsPropagationPhase(Graph& graph)
: Phase(graph, "backwards propagation")
{
}
bool run()
{
m_changed = true;
while (m_changed) {
m_changed = false;
for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
BasicBlock* block = m_graph.block(blockIndex);
if (!block)
continue;
m_allowNestedOverflowingAdditions = block->size() < (1 << 16);
for (unsigned indexInBlock = block->size(); indexInBlock--;)
propagate(block->at(indexInBlock));
}
}
return true;
}
private:
bool isNotNegZero(Node* node)
{
if (!node->isNumberConstant())
return false;
double value = node->asNumber();
return (value || 1.0 / value > 0.0);
}
bool isNotPosZero(Node* node)
{
if (!node->isNumberConstant())
return false;
double value = node->asNumber();
return (value || 1.0 / value < 0.0);
}
template<int power>
bool isWithinPowerOfTwoForConstant(Node* node)
{
JSValue immediateValue = node->asJSValue();
if (!immediateValue.isNumber())
return false;
double immediate = immediateValue.asNumber();
return immediate > -(static_cast<int64_t>(1) << power) && immediate < (static_cast<int64_t>(1) << power);
}
template<int power>
bool isWithinPowerOfTwoNonRecursive(Node* node)
{
if (!node->isNumberConstant())
return false;
return isWithinPowerOfTwoForConstant<power>(node);
}
template<int power>
bool isWithinPowerOfTwo(Node* node)
{
switch (node->op()) {
case DoubleConstant:
case JSConstant:
case Int52Constant: {
return isWithinPowerOfTwoForConstant<power>(node);
}
case BitAnd: {
if (power > 31)
return true;
return isWithinPowerOfTwoNonRecursive<power>(node->child1().node())
|| isWithinPowerOfTwoNonRecursive<power>(node->child2().node());
}
case BitOr:
case BitXor:
case BitLShift: {
return power > 31;
}
case BitRShift:
case BitURShift: {
if (power > 31)
return true;
Node* shiftAmount = node->child2().node();
if (!node->isNumberConstant())
return false;
JSValue immediateValue = shiftAmount->asJSValue();
if (!immediateValue.isInt32())
return false;
return immediateValue.asInt32() > 32 - power;
}
default:
return false;
}
}
template<int power>
bool isWithinPowerOfTwo(Edge edge)
{
return isWithinPowerOfTwo<power>(edge.node());
}
bool mergeDefaultFlags(Node* node)
{
bool changed = false;
if (node->flags() & NodeHasVarArgs) {
for (unsigned childIdx = node->firstChild();
childIdx < node->firstChild() + node->numChildren();
childIdx++) {
if (!!m_graph.m_varArgChildren[childIdx])
changed |= m_graph.m_varArgChildren[childIdx]->mergeFlags(NodeBytecodeUsesAsValue);
}
} else {
if (!node->child1())
return changed;
changed |= node->child1()->mergeFlags(NodeBytecodeUsesAsValue);
if (!node->child2())
return changed;
changed |= node->child2()->mergeFlags(NodeBytecodeUsesAsValue);
if (!node->child3())
return changed;
changed |= node->child3()->mergeFlags(NodeBytecodeUsesAsValue);
}
return changed;
}
void propagate(Node* node)
{
NodeFlags flags = node->flags() & NodeBytecodeBackPropMask;
switch (node->op()) {
case GetLocal: {
VariableAccessData* variableAccessData = node->variableAccessData();
flags &= ~NodeBytecodeUsesAsInt; m_changed |= variableAccessData->mergeFlags(flags);
break;
}
case SetLocal: {
VariableAccessData* variableAccessData = node->variableAccessData();
if (!variableAccessData->isLoadedFrom())
break;
flags = variableAccessData->flags();
RELEASE_ASSERT(!(flags & ~NodeBytecodeBackPropMask));
flags |= NodeBytecodeUsesAsNumber; node->child1()->mergeFlags(flags);
break;
}
case Flush: {
VariableAccessData* variableAccessData = node->variableAccessData();
m_changed |= variableAccessData->mergeFlags(NodeBytecodeUsesAsValue);
break;
}
case MovHint:
case Check:
break;
case BitAnd:
case BitOr:
case BitXor:
case BitRShift:
case BitLShift:
case BitURShift:
case ArithIMul: {
flags |= NodeBytecodeUsesAsInt;
flags &= ~(NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero | NodeBytecodeUsesAsOther);
flags &= ~NodeBytecodeUsesAsArrayIndex;
node->child1()->mergeFlags(flags);
node->child2()->mergeFlags(flags);
break;
}
case StringCharCodeAt: {
node->child1()->mergeFlags(NodeBytecodeUsesAsValue);
node->child2()->mergeFlags(NodeBytecodeUsesAsValue | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex);
break;
}
case UInt32ToNumber: {
node->child1()->mergeFlags(flags);
break;
}
case ValueAdd: {
if (isNotNegZero(node->child1().node()) || isNotNegZero(node->child2().node()))
flags &= ~NodeBytecodeNeedsNegZero;
if (node->child1()->hasNumberResult() || node->child2()->hasNumberResult())
flags &= ~NodeBytecodeUsesAsOther;
if (!isWithinPowerOfTwo<32>(node->child1()) && !isWithinPowerOfTwo<32>(node->child2()))
flags |= NodeBytecodeUsesAsNumber;
if (!m_allowNestedOverflowingAdditions)
flags |= NodeBytecodeUsesAsNumber;
node->child1()->mergeFlags(flags);
node->child2()->mergeFlags(flags);
break;
}
case ArithAdd: {
if (isNotNegZero(node->child1().node()) || isNotNegZero(node->child2().node()))
flags &= ~NodeBytecodeNeedsNegZero;
if (!isWithinPowerOfTwo<32>(node->child1()) && !isWithinPowerOfTwo<32>(node->child2()))
flags |= NodeBytecodeUsesAsNumber;
if (!m_allowNestedOverflowingAdditions)
flags |= NodeBytecodeUsesAsNumber;
node->child1()->mergeFlags(flags);
node->child2()->mergeFlags(flags);
break;
}
case ArithClz32: {
flags &= ~(NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero | NodeBytecodeUsesAsOther | ~NodeBytecodeUsesAsArrayIndex);
flags |= NodeBytecodeUsesAsInt;
node->child1()->mergeFlags(flags);
break;
}
case ArithSub: {
if (isNotNegZero(node->child1().node()) || isNotPosZero(node->child2().node()))
flags &= ~NodeBytecodeNeedsNegZero;
if (!isWithinPowerOfTwo<32>(node->child1()) && !isWithinPowerOfTwo<32>(node->child2()))
flags |= NodeBytecodeUsesAsNumber;
if (!m_allowNestedOverflowingAdditions)
flags |= NodeBytecodeUsesAsNumber;
node->child1()->mergeFlags(flags);
node->child2()->mergeFlags(flags);
break;
}
case ArithNegate: {
flags &= ~NodeBytecodeUsesAsOther;
node->child1()->mergeFlags(flags);
break;
}
case ArithMul: {
if (!isWithinPowerOfTwo<22>(node->child1().node())
&& !isWithinPowerOfTwo<22>(node->child2().node()))
flags |= NodeBytecodeUsesAsNumber;
node->mergeFlags(flags);
flags |= NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero;
flags &= ~NodeBytecodeUsesAsOther;
node->child1()->mergeFlags(flags);
node->child2()->mergeFlags(flags);
break;
}
case ArithDiv: {
flags |= NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero;
flags &= ~NodeBytecodeUsesAsOther;
node->child1()->mergeFlags(flags);
node->child2()->mergeFlags(flags);
break;
}
case ArithMod: {
flags |= NodeBytecodeUsesAsNumber;
flags &= ~NodeBytecodeUsesAsOther;
node->child1()->mergeFlags(flags);
node->child2()->mergeFlags(flags & ~NodeBytecodeNeedsNegZero);
break;
}
case GetByVal: {
node->child1()->mergeFlags(NodeBytecodeUsesAsValue);
node->child2()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex);
break;
}
case NewArrayWithSize: {
node->child1()->mergeFlags(NodeBytecodeUsesAsValue | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex);
break;
}
case NewTypedArray: {
node->child1()->mergeFlags(NodeBytecodeUsesAsInt | NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsArrayIndex);
break;
}
case StringCharAt: {
node->child1()->mergeFlags(NodeBytecodeUsesAsValue);
node->child2()->mergeFlags(NodeBytecodeUsesAsValue | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex);
break;
}
case ToString:
case CallStringConstructor: {
node->child1()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther);
break;
}
case ToPrimitive: {
node->child1()->mergeFlags(flags);
break;
}
case PutByValDirect:
case PutByVal: {
m_graph.varArgChild(node, 0)->mergeFlags(NodeBytecodeUsesAsValue);
m_graph.varArgChild(node, 1)->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex);
m_graph.varArgChild(node, 2)->mergeFlags(NodeBytecodeUsesAsValue);
break;
}
case Switch: {
SwitchData* data = node->switchData();
switch (data->kind) {
case SwitchImm:
node->child1()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsInt);
break;
case SwitchChar: {
node->child1()->mergeFlags(NodeBytecodeUsesAsNumber);
break;
}
case SwitchString:
node->child1()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther);
break;
case SwitchCell:
mergeDefaultFlags(node);
break;
}
break;
}
case Identity:
RELEASE_ASSERT_NOT_REACHED();
break;
default:
mergeDefaultFlags(node);
break;
}
}
bool m_allowNestedOverflowingAdditions;
bool m_changed;
};
bool performBackwardsPropagation(Graph& graph)
{
SamplingRegion samplingRegion("DFG Backwards Propagation Phase");
return runPhase<BackwardsPropagationPhase>(graph);
}
} }
#endif // ENABLE(DFG_JIT)