Package org.renjin.compiler.cfg

Source Code of org.renjin.compiler.cfg.ControlFlowGraph

package org.renjin.compiler.cfg;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.renjin.compiler.ir.tac.IRBody;
import org.renjin.compiler.ir.tac.IRLabel;
import org.renjin.compiler.ir.tac.expressions.Variable;
import org.renjin.compiler.ir.tac.statements.BasicBlockEndingStatement;
import org.renjin.compiler.ir.tac.statements.Statement;


import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

import edu.uci.ics.jung.graph.DirectedGraph;
import edu.uci.ics.jung.graph.DirectedSparseGraph;
import edu.uci.ics.jung.graph.Graph;

public class ControlFlowGraph {

  private final IRBody parent;
  private final DirectedGraph<BasicBlock, Edge> graph;
  private final List<BasicBlock> basicBlocks;
  private BasicBlock entry;
  private BasicBlock exit;
  private Map<IRLabel, BasicBlock> basicBlockMap = Maps.newHashMap();
 
  public ControlFlowGraph(IRBody body) {
    this.parent = body;
    this.graph = new DirectedSparseGraph<BasicBlock, Edge>();
    this.basicBlocks = Lists.newArrayList();
   
    addBasicBlocks();
    linkBasicBlocks();
    removeDeadBlocks();
  }

  private void addBasicBlocks() {
    BasicBlock current = null;
    for(int i=0;i<parent.getStatements().size();++i) {
      Statement stmt = parent.getStatements().get(i);
     
      if(current == null || parent.isLabeled(i)) {
        current = addNewBasicBlock(parent, i);
      } else {
        current.addStatement(stmt);
      }
     
      if(stmt instanceof BasicBlockEndingStatement) {
        current = null;
      }
    }
  }
 
  public List<BasicBlock> getLiveBasicBlocks() {
    return Collections.unmodifiableList(basicBlocks);
  }
 
  /**
   *
   * @return all variables used or assigned within this
   * control flow graph
   */
  public Set<Variable> variables() {
    Set<Variable> variables = Sets.newHashSet();
    for(BasicBlock bb : basicBlocks) {
      variables.addAll(bb.variables());
    }
    return Collections.unmodifiableSet(variables);
  }

  private BasicBlock addNewBasicBlock(IRBody body, int i) {
    BasicBlock bb = BasicBlock.createWithStartAt(body, i);
    bb.setDebugId(basicBlocks.size());
    basicBlocks.add(bb);
    graph.addVertex(bb);
    for(IRLabel label : bb.getLabels()) {
      basicBlockMap.put(label, bb);
    }
    return bb;
  }
 
  private void linkBasicBlocks() {
    entry = new BasicBlock(parent);
    entry.setDebugId("entry");
   
    exit = new BasicBlock(parent);
    exit.setDebugId("exit");
   
    for(int i=0;i!=basicBlocks.size();++i) {
      BasicBlock bb = basicBlocks.get(i);
      if(bb.fallsThrough()) {
        graph.addEdge(new Edge(false), bb, basicBlocks.get(i+1));
      } else if(bb.returns()) {
        graph.addEdge(new Edge(false), bb, exit);
      } else {
        for(IRLabel targetLabel : bb.targets()) {
          BasicBlock targetBB = basicBlockMap.get(targetLabel);
          if(targetBB == null) {
            throw new NullPointerException("whoops! no basic block with label '" + targetLabel +
                "' in IRBody " + parent);
          }
          int targetBBIndex = basicBlocks.indexOf(targetBB);
          graph.addEdge(new Edge(targetBBIndex <= i), bb, targetBB);
        }
      }
    }
    graph.addEdge(new Edge(false), entry, exit);
    graph.addEdge(new Edge(false), entry, basicBlocks.get(0));

    basicBlocks.add(entry);
    basicBlocks.add(exit);
  }
 
  private void removeDeadBlocks() {
    boolean changed;
    do {
      changed=false;
     
      for(BasicBlock vertex : Lists.newArrayList(graph.getVertices())) {
        if(vertex != entry && graph.inDegree(vertex) == 0) {
          if(graph.removeVertex(vertex)) {
          }
          changed=true;
        }
      }
    } while(changed);
   
    basicBlocks.retainAll(graph.getVertices());
    int i=1;
    for(BasicBlock bb : basicBlocks) {
      if(bb!=entry && bb!=exit) {
        bb.setDebugId(i++);
      }
    }
  }

  public List<BasicBlock> getBasicBlocks() {
    return basicBlocks;
  }
 
  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder();
    for(BasicBlock bb : basicBlocks) {
      sb.append("\n" + bb.toString());
      if(bb.getLabels() != null) {
        sb.append(": ").append(bb.getLabels());
      }
      sb.append(" =============\n");
      sb.append(bb.statementsToString());
    }
    return sb.toString();
  }

  public Graph<BasicBlock, Edge> getGraph() {
    return graph;
  }

  public BasicBlock getEntry() {
    return entry;
  }

  public BasicBlock getExit() {
    return exit;
  }

  public Collection<BasicBlock> getSuccessors(BasicBlock x) {
    return graph.getSuccessors(x);
  }

  public Collection<BasicBlock> getPredecessors(BasicBlock x) {
    return graph.getPredecessors(x);
  }
}
TOP

Related Classes of org.renjin.compiler.cfg.ControlFlowGraph

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.