mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-06-03 07:29:37 +00:00
- Visualization of the Control Flow Graph in Mermaid syntax.
- Added new option -vmermaid, which creates in the output directory .mmd files containing the Mermaid CFGs generated at the different stages of the compilation. - Use the mermaid plug-in of IntelliJ to view those files. - Added -vnoasm to stop verbosing asembler output. Currently in DRAFT, but functional.
This commit is contained in:
parent
ff29404f24
commit
3b571bbe6a
|
@ -27,6 +27,12 @@ public class CompileLog {
|
|||
*/
|
||||
private boolean verboseAsmOptimize = false;
|
||||
|
||||
/**
|
||||
* Should ASM output be verbose.
|
||||
*/
|
||||
|
||||
private boolean verboseAsm = true;
|
||||
|
||||
/**
|
||||
* Should SSA optimization be verbose.
|
||||
*/
|
||||
|
@ -65,7 +71,8 @@ public class CompileLog {
|
|||
/**
|
||||
* Should the creation of the SSA be verbose.
|
||||
*/
|
||||
private boolean verboseCreateSsa = false;
|
||||
|
||||
private boolean verboseSsaMermaid = false;
|
||||
|
||||
/**
|
||||
* Output information about struct unwinding
|
||||
|
@ -234,6 +241,11 @@ public class CompileLog {
|
|||
this.verboseCreateSsa = verboseCreateSsa;
|
||||
}
|
||||
|
||||
public CompileLog verboseSsaMermaid() {
|
||||
setVerboseSsaMermaid(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isVerboseUplift() {
|
||||
return verboseUplift;
|
||||
}
|
||||
|
@ -273,6 +285,10 @@ public class CompileLog {
|
|||
return this;
|
||||
}
|
||||
|
||||
public boolean isVerboseAsm() { return verboseAsm; }
|
||||
|
||||
public void setVerboseAsm(boolean verboseAsm) { this.verboseAsm = verboseAsm; }
|
||||
|
||||
public boolean isVerboseAsmOptimize() {
|
||||
return verboseAsmOptimize;
|
||||
}
|
||||
|
@ -335,4 +351,14 @@ public class CompileLog {
|
|||
public boolean isVerboseComments() {
|
||||
return verboseComments;
|
||||
}
|
||||
|
||||
private boolean verboseCreateSsa = false;
|
||||
|
||||
public boolean isVerboseSsaMermaid() {
|
||||
return verboseSsaMermaid;
|
||||
}
|
||||
|
||||
public void setVerboseSsaMermaid(boolean verboseSsaMermaid) {
|
||||
this.verboseSsaMermaid = verboseSsaMermaid;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -220,6 +220,8 @@ public class Compiler {
|
|||
new Pass1GenerateControlFlowGraph(program).execute();
|
||||
if(getLog().isVerbosePass1CreateSsa()) {
|
||||
getLog().append("FIRST CONTROL FLOW GRAPH");
|
||||
if(getLog().isVerboseSsaMermaid())
|
||||
program.toFileMermaidControlFlowGraph("pass1-cfg-after-parsing");
|
||||
getLog().append(program.prettyControlFlowGraph());
|
||||
}
|
||||
new Pass1ResolveForwardReferences(program).execute();
|
||||
|
@ -249,13 +251,17 @@ public class Compiler {
|
|||
new Pass1AssertNoLValueIntermediate(program).execute();
|
||||
new PassNAddTypeConversionAssignment(program, true).execute();
|
||||
new Pass1AddressOfHandling(program).execute();
|
||||
|
||||
new Pass1AsmUsesHandling(program).execute();
|
||||
|
||||
new Pass1AssertProcedureCallParameters(program).execute();
|
||||
new Pass1ModifiedVarsAnalysis(program).execute();
|
||||
new Pass1CallStackVarPrepare(program).execute();
|
||||
|
||||
if(getLog().isVerbosePass1CreateSsa()) {
|
||||
getLog().append("CONTROL FLOW GRAPH BEFORE SIZEOF FIX");
|
||||
if(getLog().isVerboseSsaMermaid())
|
||||
program.toFileMermaidControlFlowGraph("pass1-cfg-before-sizeof-fix");
|
||||
getLog().append(program.prettyControlFlowGraph());
|
||||
}
|
||||
|
||||
|
@ -270,6 +276,8 @@ public class Compiler {
|
|||
|
||||
if(getLog().isVerbosePass1CreateSsa()) {
|
||||
getLog().append("CONTROL FLOW GRAPH AFTER UNWIND");
|
||||
if(getLog().isVerboseSsaMermaid())
|
||||
program.toFileMermaidControlFlowGraph("pass1-cfg-after-unwind");
|
||||
getLog().append(program.prettyControlFlowGraph());
|
||||
}
|
||||
|
||||
|
@ -283,6 +291,8 @@ public class Compiler {
|
|||
|
||||
if(getLog().isVerbosePass1CreateSsa()) {
|
||||
getLog().append("CONTROL FLOW GRAPH BEFORE INLINING");
|
||||
if(getLog().isVerboseSsaMermaid())
|
||||
program.toFileMermaidControlFlowGraph("pass1-cfg-before-inlining");
|
||||
getLog().append(program.prettyControlFlowGraph());
|
||||
}
|
||||
new Pass1ProcedureInline(program).execute();
|
||||
|
@ -293,6 +303,8 @@ public class Compiler {
|
|||
|
||||
if(getLog().isVerbosePass1CreateSsa()) {
|
||||
getLog().append("INITIAL CONTROL FLOW GRAPH");
|
||||
if(getLog().isVerboseSsaMermaid())
|
||||
program.toFileMermaidControlFlowGraph("pass1-cfg-initial");
|
||||
getLog().append(program.prettyControlFlowGraph());
|
||||
}
|
||||
|
||||
|
@ -314,6 +326,8 @@ public class Compiler {
|
|||
new Pass1CallStackVarConvert(program).execute();
|
||||
if(getLog().isVerbosePass1CreateSsa()) {
|
||||
getLog().append("PROCEDURE CALLS");
|
||||
if(getLog().isVerboseSsaMermaid())
|
||||
program.toFileMermaidControlFlowGraph("pass1-cfg-procedure-calls");
|
||||
getLog().append(program.prettyControlFlowGraph());
|
||||
}
|
||||
new Pass1CallStack(program).execute();
|
||||
|
@ -321,6 +335,8 @@ public class Compiler {
|
|||
new Pass1CallPhiParameters(program).execute();
|
||||
if(getLog().isVerbosePass1CreateSsa()) {
|
||||
getLog().append("PROCEDURE PARAMETERS");
|
||||
if(getLog().isVerboseSsaMermaid())
|
||||
program.toFileMermaidControlFlowGraph("pass1-cfg-procedure-parameters");
|
||||
getLog().append(program.prettyControlFlowGraph());
|
||||
}
|
||||
new PassNUnwindLValueLists(program).execute();
|
||||
|
@ -334,6 +350,8 @@ public class Compiler {
|
|||
|
||||
|
||||
getLog().append("\nCONTROL FLOW GRAPH SSA");
|
||||
if(getLog().isVerboseSsaMermaid())
|
||||
program.toFileMermaidControlFlowGraph("pass1-cfg-final-ssa");
|
||||
getLog().append(program.prettyControlFlowGraph());
|
||||
|
||||
getLog().append("SYMBOL TABLE SSA");
|
||||
|
@ -465,6 +483,8 @@ public class Compiler {
|
|||
|
||||
if(getLog().isVerboseLoopUnroll()) {
|
||||
getLog().append("CONTROL FLOW GRAPH BEFORE UNROLLING");
|
||||
if(getLog().isVerboseSsaMermaid())
|
||||
program.toFileMermaidControlFlowGraph("pass2-cfg-before-unrolling");
|
||||
getLog().append(program.prettyControlFlowGraph());
|
||||
}
|
||||
|
||||
|
@ -474,6 +494,8 @@ public class Compiler {
|
|||
if(unrolled) {
|
||||
if(getLog().isVerboseLoopUnroll()) {
|
||||
getLog().append("UNROLLED CONTROL FLOW GRAPH");
|
||||
if(getLog().isVerboseSsaMermaid())
|
||||
program.toFileMermaidControlFlowGraph("pass2-cfg-after-unrolling");
|
||||
getLog().append(program.prettyControlFlowGraph());
|
||||
}
|
||||
pass2Optimize();
|
||||
|
@ -560,6 +582,8 @@ public class Compiler {
|
|||
getLog().append("Successful SSA optimization " + optimization.getClass().getSimpleName() + "");
|
||||
if(getLog().isVerboseSSAOptimize()) {
|
||||
getLog().append("CONTROL FLOW GRAPH");
|
||||
if(getLog().isVerboseSsaMermaid())
|
||||
program.toFileMermaidControlFlowGraph("pass-2-cfg-ssa-" + optimization.getClass().getSimpleName());
|
||||
getLog().append(program.prettyControlFlowGraph());
|
||||
}
|
||||
}
|
||||
|
@ -604,16 +628,22 @@ public class Compiler {
|
|||
|
||||
if(getLog().isVerboseSSAOptimize()) {
|
||||
getLog().append("CONTROL FLOW GRAPH");
|
||||
if(getLog().isVerboseSsaMermaid())
|
||||
program.toFileMermaidControlFlowGraph("pass3x-cfg-optimized");
|
||||
getLog().append(program.prettyControlFlowGraph());
|
||||
}
|
||||
new PassNCullEmptyBlocks(program, false).step();
|
||||
if(getLog().isVerboseSSAOptimize()) {
|
||||
getLog().append("CONTROL FLOW GRAPH");
|
||||
if(getLog().isVerboseSsaMermaid())
|
||||
program.toFileMermaidControlFlowGraph("pass3-cfg-empty-blocks-culled");
|
||||
getLog().append(program.prettyControlFlowGraph());
|
||||
}
|
||||
new PassNRenumberLabels(program, false).execute();
|
||||
if(getLog().isVerboseSSAOptimize()) {
|
||||
getLog().append("CONTROL FLOW GRAPH");
|
||||
if(getLog().isVerboseSsaMermaid())
|
||||
program.toFileMermaidControlFlowGraph("pass3-cfg-labels-renumbered");
|
||||
getLog().append(program.prettyControlFlowGraph());
|
||||
}
|
||||
new PassNBlockSequencePlanner(program).step();
|
||||
|
@ -637,6 +667,8 @@ public class Compiler {
|
|||
program.getLiveRangeVariablesEffective();
|
||||
|
||||
getLog().append("\nFINAL CONTROL FLOW GRAPH");
|
||||
if(getLog().isVerboseSsaMermaid())
|
||||
program.toFileMermaidControlFlowGraph("pass3-cfg-final");
|
||||
getLog().append(program.prettyControlFlowGraph());
|
||||
|
||||
}
|
||||
|
@ -747,8 +779,10 @@ public class Compiler {
|
|||
|
||||
private void pass5GenerateAndOptimizeAsm() {
|
||||
|
||||
getLog().append("\nASSEMBLER BEFORE OPTIMIZATION");
|
||||
getLog().append(program.getAsm().toString(new AsmProgram.AsmPrintState(true), program));
|
||||
if(getLog().isVerboseAsm()) {
|
||||
getLog().append("\nASSEMBLER BEFORE OPTIMIZATION");
|
||||
getLog().append(program.getAsm().toString(new AsmProgram.AsmPrintState(true), program));
|
||||
}
|
||||
|
||||
getLog().append("ASSEMBLER OPTIMIZATIONS");
|
||||
List<Pass5AsmOptimization> pass5Optimizations = new ArrayList<>();
|
||||
|
@ -769,8 +803,10 @@ public class Compiler {
|
|||
getLog().append("Succesful ASM optimization " + optimization.getClass().getSimpleName());
|
||||
asmOptimized = true;
|
||||
if(getLog().isVerboseAsmOptimize()) {
|
||||
getLog().append("ASSEMBLER");
|
||||
getLog().append(program.getAsm().toString());
|
||||
if(getLog().isVerboseAsm()) {
|
||||
getLog().append("ASSEMBLER");
|
||||
getLog().append(program.getAsm().toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -786,9 +822,11 @@ public class Compiler {
|
|||
getLog().append("\nFINAL SYMBOL TABLE");
|
||||
getLog().append(program.getScope().toStringVars(program, false));
|
||||
|
||||
getLog().append("\nFINAL ASSEMBLER");
|
||||
getLog().append("Score: " + Pass4RegisterUpliftCombinations.getAsmScore(program) + "\n");
|
||||
getLog().append(program.getAsm().toString(new AsmProgram.AsmPrintState(false, true, true, false), program));
|
||||
if(getLog().isVerboseAsm()) {
|
||||
getLog().append("\nFINAL ASSEMBLER");
|
||||
getLog().append("Score: " + Pass4RegisterUpliftCombinations.getAsmScore(program) + "\n");
|
||||
getLog().append(program.getAsm().toString(new AsmProgram.AsmPrintState(false, true, true, false), program));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -114,6 +114,9 @@ public class KickC implements Callable<Integer> {
|
|||
@CommandLine.Option(names = {"-v"}, description = "Verbose output describing the compilation process")
|
||||
private boolean verbose = false;
|
||||
|
||||
@CommandLine.Option(names = {"-vnoasm"}, description = "Verbosity Option. Don't show any generated assembler during compilation.")
|
||||
private boolean verboseAsm = false;
|
||||
|
||||
@CommandLine.Option(names = {"-vasmout"}, description = "Verbosity Option. Show KickAssembler standard output during compilation.")
|
||||
private boolean verboseAsmOut = false;
|
||||
|
||||
|
@ -123,6 +126,9 @@ public class KickC implements Callable<Integer> {
|
|||
@CommandLine.Option(names = {"-vcreate"}, description = "Verbosity Option. Creation of the Single Static Assignment Control Flow Graph.")
|
||||
private boolean verboseCreateSsa = false;
|
||||
|
||||
@CommandLine.Option(names = {"-vmermaid"}, description = "Verbosity Option. Visualize the Single Static Assignment Control Flow Graph in Mermaid.")
|
||||
private boolean verboseCreateSsaMermaid = false;
|
||||
|
||||
@CommandLine.Option(names = {"-voptimize"}, description = "Verbosity Option. Control Flow Graph Optimization.")
|
||||
private boolean verboseSSAOptimize = false;
|
||||
|
||||
|
@ -499,34 +505,25 @@ public class KickC implements Callable<Integer> {
|
|||
|
||||
// Execute the binary file if instructed
|
||||
if(emulator != null) {
|
||||
List<String> emulatorCommand = new ArrayList<>();
|
||||
emulatorCommand.addAll(Arrays.asList(emulator.split(" ")));
|
||||
|
||||
// Find commandline options for the emulator
|
||||
if( emulator.equals("C64Debugger") ) {
|
||||
String emuOptions = "";
|
||||
if(emulator.equals("C64Debugger")) {
|
||||
Path viceSymbolsPath = program.getOutputFileManager().getOutputFile("vs");
|
||||
emulatorCommand.add("-symbol");
|
||||
emulatorCommand.add(viceSymbolsPath.toString());
|
||||
emulatorCommand.add("-autojmp");
|
||||
emulatorCommand.add("-prg");
|
||||
emuOptions = "-symbols " + viceSymbolsPath + " -autojmp -prg ";
|
||||
}
|
||||
// The program names used by VICE emulators
|
||||
List<String> viceEmus = Arrays.asList("x64", "x64sc", "x128", "x64dtv", "xcbm2", "xcbm5x0", "xpet", "xplus4", "xscpu64", "xvic");
|
||||
if(viceEmus.contains(emulator)) {
|
||||
Path viceSymbolsPath = program.getOutputFileManager().getOutputFile("vs");
|
||||
emulatorCommand.add("-moncommands");
|
||||
emulatorCommand.add(viceSymbolsPath.toAbsolutePath().toString());
|
||||
emuOptions = "-moncommands " + viceSymbolsPath.toAbsolutePath().toString() + " ";
|
||||
}
|
||||
emulatorCommand.add(outputBinaryFilePath.toAbsolutePath().toString());
|
||||
System.out.println("Executing " + outputBinaryFilePath + " using " + emulator);
|
||||
String executeCommand = emulator + " " + emuOptions + outputBinaryFilePath.toAbsolutePath().toString();
|
||||
if(verbose) {
|
||||
System.out.println("Executing command: " + String.join(" ", emulatorCommand));
|
||||
System.out.println("Executing command: " + executeCommand);
|
||||
}
|
||||
try {
|
||||
ProcessBuilder processBuilder = new ProcessBuilder();
|
||||
processBuilder.command(emulatorCommand);
|
||||
processBuilder.inheritIO();
|
||||
Process process = processBuilder.start();
|
||||
Process process = Runtime.getRuntime().exec(executeCommand);
|
||||
process.waitFor();
|
||||
} catch(Throwable e) {
|
||||
System.err.println("Executing emulator failed! " + e.getMessage());
|
||||
|
@ -554,6 +551,10 @@ public class KickC implements Callable<Integer> {
|
|||
compiler.getLog().setVerboseCreateSsa(true);
|
||||
compiler.getLog().setSysOut(true);
|
||||
}
|
||||
if(verboseCreateSsaMermaid) {
|
||||
compiler.getLog().setVerboseSsaMermaid(true);
|
||||
compiler.getLog().setSysOut(true);
|
||||
}
|
||||
if(verboseSSAOptimize) {
|
||||
compiler.getLog().setVerboseSSAOptimize(true);
|
||||
compiler.getLog().setSysOut(true);
|
||||
|
@ -594,6 +595,10 @@ public class KickC implements Callable<Integer> {
|
|||
compiler.getLog().setVerboseAsmOptimize(true);
|
||||
compiler.getLog().setSysOut(true);
|
||||
}
|
||||
if(verboseAsm) {
|
||||
compiler.getLog().setVerboseAsm(false);
|
||||
compiler.getLog().setSysOut(true);
|
||||
}
|
||||
if(verboseFixLongBranch) {
|
||||
compiler.getLog().setVerboseFixLongBranch(true);
|
||||
compiler.getLog().setSysOut(true);
|
||||
|
|
|
@ -129,6 +129,20 @@ public class OutputFileManager {
|
|||
return outputFile.normalize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the extended output file name in a specific directory with a name and specific extension
|
||||
*
|
||||
* @return The output file.
|
||||
*/
|
||||
public Path getMermaidOutputFile(String name, String extension) {
|
||||
Path outputDir = getOutputDirectory();
|
||||
String fileName = getOutputBaseName();
|
||||
fileName += "-" + name;
|
||||
if(extension.length() > 0) fileName += "." + extension;
|
||||
final Path outputFile = outputDir.resolve(fileName);
|
||||
return outputFile.normalize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the output directory
|
||||
* <i>Output-path</i> is the directory where the output files are generated. The following is a prioritized list specifying how the compiler finds this folder:
|
||||
|
|
|
@ -5,10 +5,7 @@ import dk.camelot64.kickc.model.symbols.Procedure;
|
|||
import dk.camelot64.kickc.model.values.LabelRef;
|
||||
import dk.camelot64.kickc.model.values.ScopeRef;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* A named/labelled sequence of SSA statements connected to other basic blocks.
|
||||
|
@ -191,6 +188,67 @@ public class ControlFlowBlock implements Graph.Block {
|
|||
return out.toString();
|
||||
}
|
||||
|
||||
private String mermaidString(String label) {
|
||||
return label.replace(":","_").replace("@","_");
|
||||
}
|
||||
public String toMermaid(Program program, Graph graph, HashSet<String> mermaidFlow) {
|
||||
StringBuilder out = new StringBuilder();
|
||||
StringBuilder outStatements = new StringBuilder();
|
||||
|
||||
if(graph != null) {
|
||||
List<Graph.Block> predecessors = program.getGraph().getPredecessors(this);
|
||||
if(predecessors.size() > 0) {
|
||||
for(Graph.Block predecessor : predecessors) {
|
||||
String flow = mermaidString(predecessor.getLabel().getFullName()) +
|
||||
"-->" +
|
||||
mermaidString(this.getLabel().getFullName()) +
|
||||
"\n";
|
||||
mermaidFlow.add(flow);
|
||||
if (program.isProcedureEntry(this)) {
|
||||
flow = mermaidString(this.getLabel().getLocalName() + "___return") +
|
||||
"-->" +
|
||||
mermaidString(predecessor.getLabel().getFullName()) +
|
||||
"\n";
|
||||
mermaidFlow.add(flow);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mermaidFlow.add(" @UNKNOWN");
|
||||
}
|
||||
outStatements.append("\n");
|
||||
outStatements.append(mermaidString(this.getLabel().getFullName())).append("[\"`");
|
||||
outStatements.append("**" + this.getLabel().getFullName() + "**");
|
||||
outStatements.append("\n");
|
||||
int index = 0;
|
||||
if(!statements.isEmpty()) {
|
||||
for (Statement statement : statements) {
|
||||
// String statementString = statement.toString(program, program.getLog().isVerboseLiveRanges());
|
||||
if(statement instanceof StatementCall) {
|
||||
// outStatements.append("[").append(index).append("] ");
|
||||
outStatements.append(statement.toString(program, program.getLog().isVerboseLiveRanges()));
|
||||
outStatements.append("\n");
|
||||
}
|
||||
index++;
|
||||
}
|
||||
} else {
|
||||
outStatements.append(" <-> ");
|
||||
}
|
||||
outStatements.append("`\"]\n");
|
||||
|
||||
// if(defaultSuccessor != null) {
|
||||
// String flow = mermaidString(this.getLabel().getFullName()) +
|
||||
// "-->" +
|
||||
// mermaidString(defaultSuccessor.getFullName()) +
|
||||
// " \n";
|
||||
// mermaidFlow.add(flow);
|
||||
// }
|
||||
|
||||
out.append(outStatements);
|
||||
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if(this == o) return true;
|
||||
|
|
|
@ -2,6 +2,7 @@ package dk.camelot64.kickc.model;
|
|||
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementPhiBlock;
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
import dk.camelot64.kickc.model.values.LabelRef;
|
||||
import dk.camelot64.kickc.model.values.ScopeRef;
|
||||
|
||||
|
@ -102,6 +103,21 @@ public interface Graph {
|
|||
return out.toString();
|
||||
}
|
||||
|
||||
default String toMermaid(ProcedureCompilation procedureCompilation, Program program) {
|
||||
StringBuilder mermaid = new StringBuilder();
|
||||
Procedure procedure = (Procedure) program.getScope().getProcedure(procedureCompilation.getProcedureRef());
|
||||
mermaid.append("\nsubgraph \"").append(procedure.toString(program)).append("\"\n");
|
||||
HashSet<String> flow = new HashSet<String>();
|
||||
for(Graph.Block block : getAllBlocks()) {
|
||||
mermaid.append(block.toMermaid(program, this, flow));
|
||||
}
|
||||
mermaid.append("\nend\n");
|
||||
for(String edge : flow) {
|
||||
mermaid.append(edge);
|
||||
}
|
||||
return mermaid.toString();
|
||||
}
|
||||
|
||||
interface Block {
|
||||
|
||||
LabelRef getLabel();
|
||||
|
@ -156,5 +172,7 @@ public interface Graph {
|
|||
void addStatementBeforeCall(Statement newStatement);
|
||||
|
||||
String toString(Program program, Graph graph);
|
||||
|
||||
String toMermaid(Program program, Graph graph, HashSet<String> flow);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@ import dk.camelot64.kickc.model.values.ScopeRef;
|
|||
import dk.camelot64.kickc.passes.calcs.*;
|
||||
import dk.camelot64.kickc.passes.utils.ProcedureUtils;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
|
@ -181,11 +183,53 @@ public class Program {
|
|||
public String prettyControlFlowGraph() {
|
||||
StringBuilder graphPretty = new StringBuilder();
|
||||
for(ProcedureCompilation procedureCompilation : getProcedureCompilations()) {
|
||||
graphPretty.append(procedureCompilation.getGraph().toString(this));
|
||||
Graph graph = procedureCompilation.getGraph();
|
||||
if(graph != null)
|
||||
graphPretty.append(graph.toString(this));
|
||||
}
|
||||
return graphPretty.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Mermaid-print the entire control flow graph of all procedures.
|
||||
* @return The mermaid-printed control flow graph
|
||||
*/
|
||||
public String mermaidControlFlowGraph() {
|
||||
StringBuilder mermaid = new StringBuilder();
|
||||
// mermaid.append("```mermaid\n");
|
||||
mermaid.append("---\n");
|
||||
mermaid.append("config:\n");
|
||||
mermaid.append(" theme: dark\n");
|
||||
mermaid.append(" flowchart:\n");
|
||||
mermaid.append(" wrappingWidth: 600\n");
|
||||
mermaid.append("---\n");
|
||||
mermaid.append("graph TD\n");
|
||||
for(ProcedureCompilation procedureCompilation : getProcedureCompilations()) {
|
||||
Graph graph = procedureCompilation.getGraph();
|
||||
if(graph != null) {
|
||||
mermaid.append(graph.toMermaid(procedureCompilation,this));
|
||||
}
|
||||
}
|
||||
return mermaid.toString();
|
||||
}
|
||||
|
||||
public void toFileMermaidControlFlowGraph(String pass) {
|
||||
Path mermaidPath = getOutputFileManager().getMermaidOutputFile(pass, "mmd");
|
||||
System.out.println("Writing mermaid file " + mermaidPath);
|
||||
try {
|
||||
FileOutputStream mermaidOutputStream = new FileOutputStream(mermaidPath.toFile());
|
||||
OutputStreamWriter mermaidWriter = new OutputStreamWriter(mermaidOutputStream);
|
||||
String mermaidDiagramString = mermaidControlFlowGraph();
|
||||
if(mermaidDiagramString != null) {
|
||||
mermaidWriter.write(mermaidDiagramString);
|
||||
}
|
||||
mermaidWriter.close();
|
||||
mermaidOutputStream.close();
|
||||
} catch(Exception e) {
|
||||
throw new InternalError("Cannot open " + mermaidPath, e);
|
||||
}
|
||||
}
|
||||
|
||||
public OutputFileManager getOutputFileManager() {
|
||||
return outputFileManager;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user