Skip to content

Commit

Permalink
Refactor CFG implementation
Browse files Browse the repository at this point in the history
- Extract BasicBlock to LinearIRBlock and BasicBlock classes
- LinearIRBlock represents the original BasicBlock
- BasicBlock is now a generic class for holding IRNode locations
- Add Loc class to represent a location in BasicBlock
- Update usages of BasicBlock to LinearIRBlock or BasicBlock
- Remove unused methods and fields from LinearIRBlock
- Add CFG class to hold graph data
- Add commons-lang3 dependency
  • Loading branch information
whtoo committed Nov 16, 2023
1 parent 3fbbe7d commit e550152
Show file tree
Hide file tree
Showing 12 changed files with 281 additions and 173 deletions.
6 changes: 0 additions & 6 deletions ep20/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,6 @@
</properties>
<!-- 运行测试 -->
<dependencies>
<dependency>
<groupId>org.jgrapht</groupId>
<artifactId>jgrapht-core</artifactId>
<version>1.5.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
Expand Down
4 changes: 0 additions & 4 deletions ep20/src/main/java/org/teachfx/antlr4/ep20/Compiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,12 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.teachfx.antlr4.ep20.ast.ASTNode;
import org.teachfx.antlr4.ep20.driver.Phase;
import org.teachfx.antlr4.ep20.ir.IRNode;
import org.teachfx.antlr4.ep20.ir.Prog;
import org.teachfx.antlr4.ep20.ir.stmt.Label;
import org.teachfx.antlr4.ep20.parser.CymbolLexer;
import org.teachfx.antlr4.ep20.parser.CymbolParser;
import org.teachfx.antlr4.ep20.pass.ast.CymbolASTBuilder;
//import org.teachfx.antlr4.ep20.pass.ir.CymbolIRBuilder;
import org.teachfx.antlr4.ep20.pass.cfg.BasicBlock;
import org.teachfx.antlr4.ep20.pass.cfg.ControlFlowAnalysis;
import org.teachfx.antlr4.ep20.pass.codegen.CymbolAssembler;
import org.teachfx.antlr4.ep20.pass.ir.CymbolIRBuilder;
import org.teachfx.antlr4.ep20.pass.symtab.LocalDefine;
Expand Down
27 changes: 13 additions & 14 deletions ep20/src/main/java/org/teachfx/antlr4/ep20/ir/Prog.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package org.teachfx.antlr4.ep20.ir;

import lombok.extern.log4j.Log4j2;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.teachfx.antlr4.ep20.ir.stmt.CJMP;
import org.teachfx.antlr4.ep20.ir.stmt.FuncEntryLabel;
import org.teachfx.antlr4.ep20.ir.stmt.JMP;
import org.teachfx.antlr4.ep20.ir.stmt.Label;
import org.teachfx.antlr4.ep20.pass.cfg.BasicBlock;
import org.teachfx.antlr4.ep20.pass.cfg.LinearIRBlock;

import java.util.ArrayList;
import java.util.LinkedList;
Expand All @@ -16,7 +15,7 @@


public class Prog extends IRNode {
public List<BasicBlock> blockList;
public List<LinearIRBlock> blockList;
protected static Logger logger = LogManager.getLogger(Prog.class);
public List<IRNode> instrs = new ArrayList<>();

Expand All @@ -30,23 +29,23 @@ public <S,E> S accept(IRVisitor<S,E> visitor){
return visitor.visit(this);
}

public void addBlock(BasicBlock basicBlock) {
blockList.add(basicBlock);
public void addBlock(LinearIRBlock linearIRBlock) {
blockList.add(linearIRBlock);
}

private void linearInstrsImpl(BasicBlock basicBlock) {
if (!basicBlock.getStmts().isEmpty()) {
if (!basicBlock.getJmpRefMap().isEmpty()){
instrs.add(new Label(basicBlock.toString(),null));
private void linearInstrsImpl(LinearIRBlock linearIRBlock) {
if (!linearIRBlock.getStmts().isEmpty()) {
if (!linearIRBlock.getJmpRefMap().isEmpty()){
instrs.add(new Label(linearIRBlock.toString(),null));
}
instrs.addAll(basicBlock.getStmts());
instrs.addAll(linearIRBlock.getStmts());
} else {
if (basicBlock.getSuccessors().isEmpty()) {
if (linearIRBlock.getSuccessors().isEmpty()) {
return;
}

var nextBlock = basicBlock.getSuccessors().get(0);
for (var ref : basicBlock.getJmpRefMap()){
var nextBlock = linearIRBlock.getSuccessors().get(0);
for (var ref : linearIRBlock.getJmpRefMap()){
if (ref instanceof JMP jmp) {
jmp.next = nextBlock;
} else if (ref instanceof CJMP cjmp) {
Expand All @@ -56,7 +55,7 @@ private void linearInstrsImpl(BasicBlock basicBlock) {

}

for(var successor : basicBlock.getSuccessors()){
for(var successor : linearIRBlock.getSuccessors()){
linearInstrsImpl(successor);
}
}
Expand Down
16 changes: 8 additions & 8 deletions ep20/src/main/java/org/teachfx/antlr4/ep20/ir/stmt/CJMP.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
package org.teachfx.antlr4.ep20.ir.stmt;

import org.teachfx.antlr4.ep20.pass.cfg.BasicBlock;
import org.teachfx.antlr4.ep20.pass.cfg.LinearIRBlock;
import org.teachfx.antlr4.ep20.ir.IRVisitor;
import org.teachfx.antlr4.ep20.ir.expr.VarSlot;

public class CJMP extends Stmt {
public VarSlot cond;

private BasicBlock thenBlock;
private BasicBlock elseBlock;
private LinearIRBlock thenBlock;
private LinearIRBlock elseBlock;


public CJMP(VarSlot cond, BasicBlock thenLabel, BasicBlock elseLabel) {
public CJMP(VarSlot cond, LinearIRBlock thenLabel, LinearIRBlock elseLabel) {
this.cond = cond;
this.thenBlock = thenLabel;
this.elseBlock = elseLabel;
Expand All @@ -34,21 +34,21 @@ public String toString() {
return "jmpIf %s,%s,%s".formatted(cond,thenBlock,elseBlock);
}

public void setElseBlock(BasicBlock elseBlock) {
public void setElseBlock(LinearIRBlock elseBlock) {
this.elseBlock = elseBlock;
elseBlock.refJMP(this);
}

public void setThenBlock(BasicBlock thenBlock) {
public void setThenBlock(LinearIRBlock thenBlock) {
this.thenBlock = thenBlock;
thenBlock.refJMP(this);
}

public BasicBlock getElseBlock() {
public LinearIRBlock getElseBlock() {
return elseBlock;
}

public BasicBlock getThenBlock() {
public LinearIRBlock getThenBlock() {
return thenBlock;
}
}
6 changes: 3 additions & 3 deletions ep20/src/main/java/org/teachfx/antlr4/ep20/ir/stmt/JMP.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.teachfx.antlr4.ep20.ir.stmt;

import org.teachfx.antlr4.ep20.pass.cfg.BasicBlock;
import org.teachfx.antlr4.ep20.pass.cfg.LinearIRBlock;
import org.teachfx.antlr4.ep20.ir.IRVisitor;

public class JMP extends Stmt
Expand All @@ -10,12 +10,12 @@ public <S, E> S accept(IRVisitor<S, E> visitor) {
return visitor.visit(this);
}

public JMP(BasicBlock block)
public JMP(LinearIRBlock block)
{
this.next = block;
block.refJMP(this);
}
public BasicBlock next;
public LinearIRBlock next;

@Override
public StmtType getStmtType() {
Expand Down
156 changes: 39 additions & 117 deletions ep20/src/main/java/org/teachfx/antlr4/ep20/pass/cfg/BasicBlock.java
Original file line number Diff line number Diff line change
@@ -1,140 +1,62 @@
package org.teachfx.antlr4.ep20.pass.cfg;

import org.jetbrains.annotations.NotNull;
import org.teachfx.antlr4.ep20.ir.IRNode;
import org.teachfx.antlr4.ep20.ir.stmt.CJMP;
import org.teachfx.antlr4.ep20.ir.stmt.JMP;
import org.teachfx.antlr4.ep20.ir.stmt.ReturnVal;
import org.teachfx.antlr4.ep20.ir.stmt.Stmt;
import org.teachfx.antlr4.ep20.symtab.scope.Scope;
import org.teachfx.antlr4.ep20.ir.stmt.Label;
import org.teachfx.antlr4.ep20.utils.Kind;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;

public class BasicBlock {
public class BasicBlock<I extends IRNode> implements Iterable<Loc<I>> {

public enum Kind {
/// No jump instruction
CONTINUOUS,
/// Conditional instruction
END_BY_CJMP,
/// Unconditional jump instruction
END_BY_JMP,
/// Return instruction
END_BY_RETURN
}

public Kind kind = Kind.CONTINUOUS;
private static int LABEL_SEQ = 1;
private ArrayList<IRNode> stmts;

private List<BasicBlock> successors;

private List<BasicBlock> predecessors;

protected Scope scope = null;

private List<IRNode> jmpRefMap = new ArrayList<>();

private int ord = 0;

public BasicBlock() {
stmts = new ArrayList<>();
successors = new ArrayList<>();
predecessors = new ArrayList<>();
ord = LABEL_SEQ++;
}
// Generate codes
public List<Loc<I>> codes;

public void addStmt(IRNode stmt) {
stmts.add(stmt);
updateKindByLastInstr(stmt);
}
public int id;

private void updateKindByLastInstr(IRNode stmt) {
if (stmt instanceof CJMP) {
kind = Kind.END_BY_CJMP;
} else if (stmt instanceof JMP) {
kind = Kind.END_BY_JMP;
} else if (stmt instanceof ReturnVal) {
kind = Kind.END_BY_RETURN;
} else {
kind = Kind.CONTINUOUS;
}
}
public static boolean isBasicBlock(Stmt stmt) {
return !(stmt instanceof CJMP) && !(stmt instanceof JMP);
}
protected Optional<Label> label;

public List<IRNode> getStmts() {
return stmts;
}

public void setStmts(ArrayList<IRNode> stmts) {
this.stmts = stmts;
var lastInstr = stmts.get(stmts.size() - 1);
updateKindByLastInstr(lastInstr);
}

public List<BasicBlock> getSuccessors() {
return successors;
}

public void setSuccessors(List<BasicBlock> successors) {
this.successors = successors;
}

public List<BasicBlock> getPredecessors() {
return predecessors;
}

public void setPredecessors(List<BasicBlock> predecessors) {
this.predecessors = predecessors;
}

public static void setLink(BasicBlock current,BasicBlock next) {
current.successors.add(next);
next.predecessors.add(current);
}

public void setLink(BasicBlock next) {
BasicBlock.setLink(this,next);
}

public Scope getScope() {
return scope;
}

public void setScope(Scope scope) {
this.scope = scope;
}
public Kind kind;

@NotNull
@Override
public String toString() {
return "L"+ord;
public Iterator<Loc<I>> iterator() {
return codes.iterator();
}
public Iterator<Loc<I>> backwardIterator() {
return new Iterator<Loc<I>>() {
private int index = codes.size() - 1;
@Override
public boolean hasNext() {
return index != -1;
}

public List<IRNode> getJmpRefMap() {
return jmpRefMap;
@Override
public Loc<I> next() {
var loc = codes.get(index);
index--;
return loc;
}
};
}

public void setJmpRefMap(List<IRNode> jmpRefMap) {
this.jmpRefMap = jmpRefMap;
public BasicBlock(Kind kind, int id, List<Loc<I>> codes, Optional<Label> label) {
this.codes = codes;
this.label = label;
this.id = id;
this.kind = kind;
}

public int getOrd() {
return ord;
public int getId() {
return id;
}


public void refJMP(IRNode node) {
jmpRefMap.add(node);
// Generate isEmpty
public boolean isEmpty() {
return codes.isEmpty();
}

@Override
public boolean equals(Object obj) {
return toString().equalsIgnoreCase(obj.toString());
}

public IRNode getLastInstr() {
return stmts.get(stmts.size() - 1);
}
}
}
32 changes: 32 additions & 0 deletions ep20/src/main/java/org/teachfx/antlr4/ep20/pass/cfg/CFG.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,36 @@
package org.teachfx.antlr4.ep20.pass.cfg;

import org.apache.commons.lang3.tuple.Pair;
import org.teachfx.antlr4.ep20.ir.IRNode;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

public class CFG {
public final List<IRNode> nodes;

public final List<Pair<Integer,Integer>> edges;

private List<Pair<Set<Integer>, Set<Integer>>> links;

public CFG(List<IRNode> nodes, List<Pair<Integer, Integer>> edges) {
// Generate init
this.nodes = nodes;
this.edges = edges;

links = new ArrayList<>();
for (var i = 0;i < nodes.size();i++) {
links.add(Pair.of(new TreeSet<>(), new TreeSet<>()));
}

for (var edge : edges) {
var u = edge.getLeft();
var v = edge.getRight();
links.get(u).getRight().add(v);
links.get(v).getLeft().add(u);

}
}
}
Loading

0 comments on commit e550152

Please sign in to comment.