From 56a31f6e4ab6e2944d8d69a7b5de08892830d9c6 Mon Sep 17 00:00:00 2001 From: willson walter Date: Sun, 19 Nov 2023 17:29:55 +0800 Subject: [PATCH] Add basic block CFG visualization - Generate CFG from linear IR blocks - Insert block labels for visualization - Override BasicBlock's compareTo for deterministic order - Render sample CFG in README --- ep20/README.md | 9 ++++++- .../org/teachfx/antlr4/ep20/Compiler.java | 8 +++--- .../java/org/teachfx/antlr4/ep20/ir/Prog.java | 3 --- .../antlr4/ep20/pass/cfg/BasicBlock.java | 8 +++++- .../org/teachfx/antlr4/ep20/pass/cfg/CFG.java | 11 +++++++- .../antlr4/ep20/pass/cfg/CFGBuilder.java | 27 +++++++++++++++++-- .../antlr4/ep20/pass/cfg/LinearIRBlock.java | 21 ++++++++++----- .../org/teachfx/antlr4/ep20/pass/cfg/Loc.java | 7 +++++ .../ep20/pass/codegen/CymbolAssembler.java | 5 +++- .../antlr4/ep20/pass/ir/CymbolIRBuilder.java | 22 +++++++++++++++ ep21/README.md | 21 ++++++++++++++- 11 files changed, 122 insertions(+), 20 deletions(-) diff --git a/ep20/README.md b/ep20/README.md index 0b4fbff..168c6a3 100644 --- a/ep20/README.md +++ b/ep20/README.md @@ -30,4 +30,11 @@ graph LR ### 线性化IR 我们的IR本质上是tree模式的,这样一来我们的线性化实际上延迟到了指令生成时。 但是,这样一来我们就无法进行活性分析和很多与TAC表示相关的分析(或者是我没找到 -直接对栈代码做分析的例子)。因此,我要对ep20的输出code过程进行线性改造。 \ No newline at end of file +直接对栈代码做分析的例子)。因此,我要对ep20的输出code过程进行线性改造。 + +### CFG + +```mermaid +graph TD; + L0["iconst 0;istore 0;;iconst 7;igt"] +``` \ No newline at end of file diff --git a/ep20/src/main/java/org/teachfx/antlr4/ep20/Compiler.java b/ep20/src/main/java/org/teachfx/antlr4/ep20/Compiler.java index dab69c9..bfb8d43 100644 --- a/ep20/src/main/java/org/teachfx/antlr4/ep20/Compiler.java +++ b/ep20/src/main/java/org/teachfx/antlr4/ep20/Compiler.java @@ -12,7 +12,7 @@ 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.codegen.CymbolAssembler; import org.teachfx.antlr4.ep20.pass.ir.CymbolIRBuilder; import org.teachfx.antlr4.ep20.pass.symtab.LocalDefine; @@ -49,11 +49,13 @@ public static void main(String[] args) throws IOException { var irBuilder = new CymbolIRBuilder(); astRoot.accept(irBuilder); - // printIRTree(irBuilder.prog.linearInstrs()); + + var cfg = irBuilder.getCFG(); + logger.info("CFG:\n" + cfg); var assembler = new CymbolAssembler(); irBuilder.prog.accept(assembler); - saveToEp18Res(assembler.getAsmInfo()); +// saveToEp18Res(assembler.getAsmInfo()); logger.info("\n%s".formatted(assembler.getAsmInfo())); } diff --git a/ep20/src/main/java/org/teachfx/antlr4/ep20/ir/Prog.java b/ep20/src/main/java/org/teachfx/antlr4/ep20/ir/Prog.java index 963b9a1..4202170 100644 --- a/ep20/src/main/java/org/teachfx/antlr4/ep20/ir/Prog.java +++ b/ep20/src/main/java/org/teachfx/antlr4/ep20/ir/Prog.java @@ -37,9 +37,6 @@ public void addBlock(LinearIRBlock linearIRBlock) { private void linearInstrsImpl(@NotNull LinearIRBlock linearIRBlock) { // Add all instr from non-empty block if (!linearIRBlock.getStmts().isEmpty()) { - if (!linearIRBlock.getJmpRefMap().isEmpty()){ - instrs.add(linearIRBlock.getLabel()); - } instrs.addAll(linearIRBlock.getStmts()); } else { // Drop empty block diff --git a/ep20/src/main/java/org/teachfx/antlr4/ep20/pass/cfg/BasicBlock.java b/ep20/src/main/java/org/teachfx/antlr4/ep20/pass/cfg/BasicBlock.java index 0e7cc5f..8502e2d 100644 --- a/ep20/src/main/java/org/teachfx/antlr4/ep20/pass/cfg/BasicBlock.java +++ b/ep20/src/main/java/org/teachfx/antlr4/ep20/pass/cfg/BasicBlock.java @@ -13,7 +13,13 @@ import java.util.Optional; import java.util.Set; -public class BasicBlock implements Iterable> { +public class BasicBlock implements Comparable>, Iterable> { + + @Override + public int compareTo(@NotNull BasicBlock o) { + return this.id - o.id; + } + // Generate codes public List> codes; diff --git a/ep20/src/main/java/org/teachfx/antlr4/ep20/pass/cfg/CFG.java b/ep20/src/main/java/org/teachfx/antlr4/ep20/pass/cfg/CFG.java index 8847590..513a623 100644 --- a/ep20/src/main/java/org/teachfx/antlr4/ep20/pass/cfg/CFG.java +++ b/ep20/src/main/java/org/teachfx/antlr4/ep20/pass/cfg/CFG.java @@ -5,6 +5,7 @@ import org.teachfx.antlr4.ep20.ir.IRNode; import java.util.*; +import java.util.LinkedList; public class CFG implements Iterable> { public final List> nodes; @@ -15,7 +16,7 @@ public class CFG implements Iterable> { public CFG(List> nodes, List> edges) { // Generate init - this.nodes = nodes; + this.nodes = new LinkedList<>(nodes); ///.stream().sorted(Comparator.comparingInt(BasicBlock::getId)).toList(); this.edges = edges; links = new ArrayList<>(); @@ -57,4 +58,12 @@ public int getOutDegree(int id) { public Iterator> iterator() { return nodes.iterator(); } + + + @Override + public String toString() { + var graphRenderBuffer = new StringBuffer(); + + return graphRenderBuffer.toString(); + } } diff --git a/ep20/src/main/java/org/teachfx/antlr4/ep20/pass/cfg/CFGBuilder.java b/ep20/src/main/java/org/teachfx/antlr4/ep20/pass/cfg/CFGBuilder.java index 7b32f00..36d134b 100644 --- a/ep20/src/main/java/org/teachfx/antlr4/ep20/pass/cfg/CFGBuilder.java +++ b/ep20/src/main/java/org/teachfx/antlr4/ep20/pass/cfg/CFGBuilder.java @@ -1,11 +1,34 @@ 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.Map; -public class CFGBuilder { - public CFGBuilder(BasicBlock startNode){ +public class CFGBuilder { + private CFG cfg; + private List> basicBlocks; + private List> edges; + public CFGBuilder(List blockList){ + basicBlocks =new ArrayList<>(); + edges = new ArrayList<>(); + for (var funcLabelBlock : blockList) { + build(funcLabelBlock); + } + cfg = new CFG<>(basicBlocks, edges); + } + + private void build(LinearIRBlock block){ + basicBlocks.add(BasicBlock.buildFromLinearBlock(block)); + for(var successor : block.getSuccessors()){ + edges.add(Pair.of(block.getOrd(), successor.getOrd())); + build(successor); + } + } + public CFG getCFG() { + return cfg; } } diff --git a/ep20/src/main/java/org/teachfx/antlr4/ep20/pass/cfg/LinearIRBlock.java b/ep20/src/main/java/org/teachfx/antlr4/ep20/pass/cfg/LinearIRBlock.java index 3320a31..e9766a9 100644 --- a/ep20/src/main/java/org/teachfx/antlr4/ep20/pass/cfg/LinearIRBlock.java +++ b/ep20/src/main/java/org/teachfx/antlr4/ep20/pass/cfg/LinearIRBlock.java @@ -11,9 +11,9 @@ public class LinearIRBlock { // Fields - private static int LABEL_SEQ = 1; + private static int LABEL_SEQ = 0; private Kind kind = Kind.CONTINUOUS; - private int ord = 1; + private int ord = 0; private ArrayList stmts; private List successors; private List predecessors; @@ -120,10 +120,11 @@ public void refJMP(IRNode node) { // Utility Methods @Override public String toString() { - var firstInstr = stmts.get(0); - - if (firstInstr instanceof FuncEntryLabel) { - return firstInstr.toString(); + if (stmts.isEmpty()) { + return "L" + ord; + } + if (stmts.get(0) instanceof FuncEntryLabel funcEntryLabel) { + return funcEntryLabel.toSource(); } return "L" + ord; } @@ -139,12 +140,18 @@ public String toSource(){ } public Label getLabel() { - var firstInstr = stmts.get(0); + if (stmts.isEmpty()) { + return new Label(toString(),scope); + } + + var firstInstr = stmts.get(0); if (firstInstr instanceof FuncEntryLabel funcEntryLabel) { return funcEntryLabel; } return new Label(toString(),scope); } + + } \ No newline at end of file diff --git a/ep20/src/main/java/org/teachfx/antlr4/ep20/pass/cfg/Loc.java b/ep20/src/main/java/org/teachfx/antlr4/ep20/pass/cfg/Loc.java index be54d21..9bcb013 100644 --- a/ep20/src/main/java/org/teachfx/antlr4/ep20/pass/cfg/Loc.java +++ b/ep20/src/main/java/org/teachfx/antlr4/ep20/pass/cfg/Loc.java @@ -15,4 +15,11 @@ public Loc(I instr) { public Set liveIn; public Set liveOut; + + @Override + public String toString() { + return "Loc{" + + "instr=" + instr + + '}'; + } } diff --git a/ep20/src/main/java/org/teachfx/antlr4/ep20/pass/codegen/CymbolAssembler.java b/ep20/src/main/java/org/teachfx/antlr4/ep20/pass/codegen/CymbolAssembler.java index 05f7f85..6d18905 100644 --- a/ep20/src/main/java/org/teachfx/antlr4/ep20/pass/codegen/CymbolAssembler.java +++ b/ep20/src/main/java/org/teachfx/antlr4/ep20/pass/codegen/CymbolAssembler.java @@ -70,6 +70,9 @@ public Void visit(CallFunc callFunc) { @Override public Void visit(Label label) { + // label不存在嵌套可能,下面这种情况必定是空块导致的label悬空。 + if (indents > 0) { indents--; } + if (label instanceof FuncEntryLabel){ emit("%s".formatted(label.toSource())); } else { @@ -88,7 +91,7 @@ public Void visit(JMP jmp) { @Override public Void visit(CJMP cjmp) { - emit("brf %s".formatted(cjmp.getElseBlock().toString())); + emit("brf %s".formatted(cjmp.getElseBlock().getLabel().toString())); indents--; return null; } diff --git a/ep20/src/main/java/org/teachfx/antlr4/ep20/pass/ir/CymbolIRBuilder.java b/ep20/src/main/java/org/teachfx/antlr4/ep20/pass/ir/CymbolIRBuilder.java index 483a05e..f41b6bb 100644 --- a/ep20/src/main/java/org/teachfx/antlr4/ep20/pass/ir/CymbolIRBuilder.java +++ b/ep20/src/main/java/org/teachfx/antlr4/ep20/pass/ir/CymbolIRBuilder.java @@ -11,6 +11,8 @@ import org.teachfx.antlr4.ep20.ast.stmt.*; import org.teachfx.antlr4.ep20.ast.type.TypeNode; import org.teachfx.antlr4.ep20.ir.expr.Operand; +import org.teachfx.antlr4.ep20.pass.cfg.CFG; +import org.teachfx.antlr4.ep20.pass.cfg.CFGBuilder; import org.teachfx.antlr4.ep20.pass.cfg.LinearIRBlock; import org.teachfx.antlr4.ep20.ir.IRNode; import org.teachfx.antlr4.ep20.ir.Prog; @@ -25,6 +27,7 @@ import org.teachfx.antlr4.ep20.symtab.symbol.MethodSymbol; import org.teachfx.antlr4.ep20.symtab.symbol.VariableSymbol; +import java.util.Objects; import java.util.Optional; import java.util.Stack; @@ -418,4 +421,23 @@ protected VarSlot popEvalOperand() { protected VarSlot peekEvalOperand() { return evalExprStack.peek(); } + + public CFG getCFG() { + for (var func : prog.blockList){ + insertBlockLabel(func); + } + + var cfgBuilder = new CFGBuilder(prog.blockList); + return cfgBuilder.getCFG(); + } + + public void insertBlockLabel(LinearIRBlock startBlock) { + var firstInstr = startBlock.getLabel(); + if (!(firstInstr instanceof FuncEntryLabel)) { + startBlock.getStmts().add(0,firstInstr); + } + for (var successor : startBlock.getSuccessors()) { + insertBlockLabel(successor); + } + } } diff --git a/ep21/README.md b/ep21/README.md index 90c95e4..693485f 100644 --- a/ep21/README.md +++ b/ep21/README.md @@ -20,4 +20,23 @@ graph LR ## DONE - +```mermaid +graph TD; + A[基本块1] --> B[基本块2] + B --> C[基本块3] + C -->|条件跳转| D[基本块6] + C -->|否则| E[基本块4] + E -->|条件跳转| F[基本块7] + F --> B + E -->|否则| G[基本块5] + G -->|条件跳转| F + G -->|否则| H[基本块8] + H --> I[基本块9] + D --> I + subgraph dec1 + A + end + subgraph main + B --> C --> D --> E --> F --> G --> H --> I + end +```