public function process(GraphState $state) { $graph = $state->getGraph(); $vars = Helper::findVariables($graph); $postdominator = $state->getPostDominator(); $dominator = $state->getDominator(); foreach ($vars as $var) { $usages = []; foreach ($graph->vertices() as $vertex) { if (in_array($var, $vertex->getVariables(), true)) { $usages[] = $vertex; } } $dom = $postdominator->immediateDominatorArray($usages); while ($dom) { foreach ($usages as $usage) { if ($dominator->strictlyDominates($usage, $dom)) { $dom = $postdominator->immediateDominator($dom); continue 2; } } break; } if (!$dom) { continue; } if ($dom instanceof Jump || $dom instanceof JumpZ) { Helper::insertBefore($dom, new Free($var), $graph); } else { Helper::insertAfter($dom, new Free($var), $graph); } } }
/** * Build the dominator tree, and initialize it * * @param DirectedAdjacencyList $graph The graph to build the tree for * @param Vertex $start The start node of the dominator */ public function __construct(Digraph $graph, Vertex $start) { $this->dominator = new \SplObjectStorage(); $this->graph = $graph; $this->predecessors = Helper::computePredecessors($this->graph); $this->iPredecessors = Helper::computeImmediatePredecessors($this->graph); $this->build($start); }
public function process(Vertex $vertex, Digraph $graph) { if ($vertex instanceof Assignment && $vertex->isIdempotent() && 1 >= $this->countUsages($vertex->getResult(), $graph)) { Helper::remove($vertex, $graph); return true; } return false; }
public function process(Vertex $vertex, Digraph $graph) { if ($graph->inDegreeOf($vertex) === 0 && !$vertex instanceof Vertex\Function_) { Helper::remove($vertex, $graph); return true; } return false; }
public function process(Vertex $vertex, Digraph $graph) { if ($vertex instanceof Vertex\Phi) { $types = []; foreach ($vertex->getValues() as $value) { $types[] = (string) $value->getType(); } $types = array_unique($types); if ($vertex->getResult()->getType()->isUnknown()) { $type = null; $setAll = false; if (count($types) === 1 && $types[0] !== 'unknown') { $type = Type::normalizeType($types[0]); } elseif (count($types) === 2 && in_array('long', $types) && in_array('numeric', $types)) { $type = new Type(Type::TYPE_LONG); $setAll = true; } elseif (count($types) === 2 && in_array('double', $types) && in_array('numeric', $types)) { $type = new Type(Type::TYPE_DOUBLE); $setAll = true; } elseif (count($types) === 2 && in_array('bool', $types) && in_array('numeric', $types)) { $type = new Type(Type::TYPE_BOOLEAN); } if ($type) { $vertex->getResult()->setType($type); if ($setAll) { foreach ($vertex->getValues() as $value) { $value->setType($type); } } return true; } } if (count($vertex->getValues()) === 1) { // remove phi node list($val) = iterator_to_array($vertex->getValues()); $result = $vertex->getResult(); foreach ($graph->vertices() as $vtx) { $vtx->replaceVariable($result, $val); if ($vtx instanceof Assignment && $vtx->getResult() === $result) { $vtx->setResult($val); } } Helper::remove($vertex, $graph); return true; } } return false; }
/** * @covers ::isLiveVar */ public function testIsLiveVarWithCycleAndLaterValue() { $graph = new DirectedAdjacencyList(); $var = new Variable(); $vertex = $this->getMock(Vertex::class); $graph->ensureVertex($vertex); $vertex->expects($this->once())->method('getVariables')->will($this->returnValue([])); $v1 = $this->getMock(Vertex::class); $v1->expects($this->once())->method('getVariables')->will($this->returnValue([$var])); $graph->ensureArc($vertex, $v1); $this->assertTrue(Helper::isLiveVar($var, $vertex, $graph)); }
public function process(Vertex $vertex, Digraph $graph) { if ($vertex instanceof JitBinaryOp && $vertex->getA() instanceof Constant && $vertex->getB() instanceof Constant) { $ret = null; switch ($vertex->getKind()) { case JitBinaryOp::CONCAT: $ret = $vertex->getA()->getValue() . $vertex->getB()->getValue(); break; case JitBinaryOp::PLUS: $ret = $vertex->getA()->getValue() + $vertex->getB()->getValue(); break; case JitBinaryOp::MINUS: $ret = $vertex->getA()->getValue() - $vertex->getB()->getValue(); break; case JitBinaryOp::MUL: $ret = $vertex->getA()->getValue() * $vertex->getB()->getValue(); break; case JitBinaryOp::DIV: $ret = $vertex->getA()->getValue() / $vertex->getB()->getValue(); break; case JitBinaryOp::MOD: $ret = $vertex->getA()->getValue() % $vertex->getB()->getValue(); break; case JitBinaryOp::EQUAL: $ret = $vertex->getA()->getValue() == $vertex->getB()->getValue(); break; case JitBinaryOp::NOT_EQUAL: $ret = $vertex->getA()->getValue() != $vertex->getB()->getValue(); break; case JitBinaryOp::IDENTICAL: $ret = $vertex->getA()->getValue() == $vertex->getB()->getValue(); break; case JitBinaryOp::NOT_IDENTICAL: $ret = $vertex->getA()->getValue() !== $vertex->getB()->getValue(); break; case JitBinaryOp::GREATER: $ret = $vertex->getA()->getValue() > $vertex->getB()->getValue(); break; case JitBinaryOp::GREATER_EQUAL: $ret = $vertex->getA()->getValue() >= $vertex->getB()->getValue(); break; case JitBinaryOp::SMALLER: $ret = $vertex->getA()->getValue() < $vertex->getB()->getValue(); break; case JitBinaryOp::SMALLER_EQUAL: $ret = $vertex->getA()->getValue() <= $vertex->getB()->getValue(); break; case JitBinaryOp::BITWISE_AND: $ret = $vertex->getA()->getValue() & $vertex->getB()->getValue(); break; case JitBinaryOp::BITWISE_OR: $ret = $vertex->getA()->getValue() | $vertex->getB()->getValue(); break; case JitBinaryOp::BITWISE_XOR: $ret = $vertex->getA()->getValue() ^ $vertex->getB()->getValue(); break; case JitBinaryOp::SHIFT_LEFT: $ret = $vertex->getA()->getValue() << $vertex->getB()->getValue(); break; case JitBinaryOp::SHIFT_RIGHT: $ret = $vertex->getA()->getValue() >> $vertex->getB()->getValue(); break; } // replace binary op with assign op Helper::replace($vertex, new JitAssign(new Constant($ret), $vertex->getResult()), $graph); return true; } return false; }
public function getPostDominator() { return new Dominator($this->getInverseGraph(), Helper::findVerticesByClass(End::class, $this->graph)[0]); }
public function findPhiNodes(Variable $var, array $assignments, Dominator $dominator, Digraph $graph) { $allDf = new \SplObjectStorage(); $new = $assignments; do { $runAgain = false; $new = $this->findFrontier($new, $dominator); foreach ($new as $obj) { if (!$allDf->contains($obj)) { $allDf->attach($obj); // found a new one!!! $runAgain = true; } } } while ($runAgain); $phiNodes = new \SplObjectStorage(); foreach ($allDf as $node) { if ($node instanceof JitNoOp) { if (Helper::isLiveVar($var, $node, $graph)) { // only add the phi node if the variable is live afterwards $phiNodes[$node] = true; } } elseif (!$node instanceof End) { throw new \RuntimeException('A non-NoOp Phi Node was found, possible corrupted graph'); } } return $phiNodes; }
public function checkForCircularReference(array $phiNodes, GraphState $state) { $graph = new DirectedAdjacencyList(); foreach ($phiNodes as $phi) { $result = $phi->getResult(); foreach ($phi->getValues() as $value) { $graph->ensureArc($value, $result); } } $cycles = $graph->getCycles(); foreach ($cycles as $cycle) { if ($this->areAllUnknown($cycle)) { // All are unknown, process! $types = array(); foreach ($cycle as $component) { foreach (Helper::getInboundNodes($component, $graph) as $node) { if (in_array($node, $cycle, true)) { continue; } $types[] = $node->getType()->getType(); } } $types = array_unique($types); $newType = 0; switch (count($types)) { case 1: if ($types[0] != Type::TYPE_UNKNOWN) { $newType = $types[0]; } break; case 2: if (in_array(Type::TYPE_NUMERIC, $types) && in_array(Type::TYPE_LONG, $types)) { $newType = Type::TYPE_NUMERIC; } elseif (in_array(Type::TYPE_NUMERIC, $types) && in_array(Type::TYPE_DOUBLE, $types)) { $newType = Type::TYPE_DOUBLE; } break; } if ($newType) { foreach ($cycle as $component) { $component->setType(new Type($newType)); } return true; } } } return false; }