From f2f144c3ee9fffa10fb42cbbaca0f5fcb1059971 Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Mon, 8 Jul 2019 11:32:07 +0200 Subject: [PATCH] Added command line switches for adding comments containing source file information to the ASM. Closes #215 --- .../java/dk/camelot64/kickc/Compiler.java | 7 +- src/main/java/dk/camelot64/kickc/KickC.java | 13 +++- .../dk/camelot64/kickc/asm/AsmProgram.java | 74 ++++++++++++++----- .../dk/camelot64/kickc/asm/AsmSegment.java | 61 ++++++++++++--- .../model/statements/StatementSource.java | 27 +++++++ .../kickc/passes/Pass5FixLongBranches.java | 2 +- .../dk/camelot64/kickc/test/TestPrograms.java | 5 +- 7 files changed, 153 insertions(+), 36 deletions(-) diff --git a/src/main/java/dk/camelot64/kickc/Compiler.java b/src/main/java/dk/camelot64/kickc/Compiler.java index fe2b0c818..3ce4f2f35 100644 --- a/src/main/java/dk/camelot64/kickc/Compiler.java +++ b/src/main/java/dk/camelot64/kickc/Compiler.java @@ -1,5 +1,6 @@ package dk.camelot64.kickc; +import dk.camelot64.kickc.asm.AsmProgram; import dk.camelot64.kickc.model.Comment; import dk.camelot64.kickc.model.CompileError; import dk.camelot64.kickc.model.Program; @@ -482,7 +483,7 @@ public class Compiler { new Pass4CodeGeneration(program, false).generate(); new Pass4AssertNoCpuClobber(program).check(); getLog().append("\nINITIAL ASM"); - getLog().append(program.getAsm().toString()); + getLog().append(program.getAsm().toString(new AsmProgram.AsmPrintState(true, false), program)); // Find potential registers for each live range equivalence class - based on clobbering of fragments getLog().append("REGISTER UPLIFT POTENTIAL REGISTERS"); @@ -530,7 +531,7 @@ public class Compiler { new Pass4InterruptClobberFix(program).fix(); getLog().append("\nASSEMBLER BEFORE OPTIMIZATION"); - getLog().append(program.getAsm().toString()); + getLog().append(program.getAsm().toString(new AsmProgram.AsmPrintState(true, false), program)); getLog().append("ASSEMBLER OPTIMIZATIONS"); List pass5Optimizations = new ArrayList<>(); @@ -568,7 +569,7 @@ public class Compiler { getLog().append("\nFINAL ASSEMBLER"); getLog().append("Score: " + Pass4RegisterUpliftCombinations.getAsmScore(program) + "\n"); - getLog().append(program.getAsm().toString()); + getLog().append(program.getAsm().toString(new AsmProgram.AsmPrintState(true, false), program)); } diff --git a/src/main/java/dk/camelot64/kickc/KickC.java b/src/main/java/dk/camelot64/kickc/KickC.java index 70ae1c43a..40b5996b5 100644 --- a/src/main/java/dk/camelot64/kickc/KickC.java +++ b/src/main/java/dk/camelot64/kickc/KickC.java @@ -1,5 +1,6 @@ package dk.camelot64.kickc; +import dk.camelot64.kickc.asm.AsmProgram; import dk.camelot64.kickc.fragment.AsmFragmentTemplate; import dk.camelot64.kickc.fragment.AsmFragmentTemplateSynthesizer; import dk.camelot64.kickc.fragment.AsmFragmentTemplateUsages; @@ -96,6 +97,16 @@ public class KickC implements Callable { @CommandLine.Option(names = {"-fragment" }, description = "Print the ASM code for a named fragment. The fragment is loaded/synthesized and the ASM variations are written to the output.") private String fragment = null; + @CommandLine.Option(names = {"-S", "-Sc" }, description = "Interleave comments with C source code in the generated ASM.") + private boolean interleaveSourceCode = false; + + @CommandLine.Option(names = {"-Sl" }, description = "Interleave comments with C source file name and line number in the generated ASM.") + private boolean interleaveSourceFile = false; + + @CommandLine.Option(names = {"-Si" }, description = "Interleave comments with intermediate language code and ASM fragment names in the generated ASM.") + private boolean interleaveIclFile = false; + + /** Program Exit Code signaling a compile error. */ public static final int COMPILE_ERROR = 1; @@ -180,7 +191,7 @@ public class KickC implements Callable { System.out.println("Writing asm file " + asmPath); FileOutputStream asmOutputStream = new FileOutputStream(asmPath.toFile()); OutputStreamWriter asmWriter = new OutputStreamWriter(asmOutputStream); - String asmCodeString = program.getAsm().toString(false); + String asmCodeString = program.getAsm().toString(new AsmProgram.AsmPrintState(interleaveSourceFile, interleaveSourceCode, interleaveIclFile, false), program); asmWriter.write(asmCodeString); asmWriter.close(); asmOutputStream.close(); diff --git a/src/main/java/dk/camelot64/kickc/asm/AsmProgram.java b/src/main/java/dk/camelot64/kickc/asm/AsmProgram.java index 38a6c6467..7554d0104 100644 --- a/src/main/java/dk/camelot64/kickc/asm/AsmProgram.java +++ b/src/main/java/dk/camelot64/kickc/asm/AsmProgram.java @@ -1,6 +1,7 @@ package dk.camelot64.kickc.asm; import dk.camelot64.kickc.fragment.AsmFormat; +import dk.camelot64.kickc.model.Program; import dk.camelot64.kickc.model.values.ScopeRef; import java.util.ArrayList; @@ -196,26 +197,17 @@ public class AsmProgram { return clobber; } - public String toString(boolean comments) { - return toString(new AsmPrintState(comments, false)); - } - - public String toString(boolean comments, boolean lineIdx) { - return toString(new AsmPrintState(comments, lineIdx)); - } - - - public String toString(AsmPrintState printState) { + public String toString(AsmPrintState printState, Program program) { StringBuilder out = new StringBuilder(); for(AsmSegment segment : segments) { - out.append(segment.toString(printState)); + out.append(segment.toString(printState, program)); } return out.toString(); } @Override public String toString() { - return toString(true); + return toString(new AsmPrintState(false, false), null); } /** @@ -242,19 +234,61 @@ public class AsmProgram { return null; } - static class AsmPrintState { - boolean comments; - boolean lineIdx; - String indent; + public static class AsmPrintState { + // Output comments with information about the file/line number in the source file + private boolean sourceFileInfo; + // Output comments with C-source from the source file + private boolean sourceCodeInfo; + // Output comments with ICL-code and the ASM fragment name + private boolean sourceIclInfo; + // Output segment ID in the ICL-comment + private boolean sourceSegmentIdInfo; + // Output ASM line numbers + private boolean lineIdx; + // Current indent - used during printing + private String indent; - public AsmPrintState(boolean comments, boolean lineIdx) { - this.comments = comments; + public AsmPrintState(boolean sourceFileInfo, boolean sourceCodeInfo, boolean sourceIclInfo, boolean lineIdx) { + this.sourceFileInfo = sourceFileInfo; + this.sourceCodeInfo = sourceCodeInfo; + this.sourceIclInfo = sourceIclInfo; this.lineIdx = lineIdx; this.indent = ""; } - public boolean isComments() { - return comments; + public AsmPrintState(boolean sourceIclInfo, boolean lineIdx) { + this.sourceIclInfo = sourceIclInfo; + this.sourceSegmentIdInfo = sourceIclInfo; + this.lineIdx = lineIdx; + this.indent = ""; + } + + public boolean isSourceCodeInfo() { + return sourceCodeInfo; + } + + public void setSourceCodeInfo(boolean sourceCodeInfo) { + this.sourceCodeInfo = sourceCodeInfo; + } + + public boolean isSourceFileInfo() { + return sourceFileInfo; + } + + public void setSourceFileInfo(boolean sourceFileInfo) { + this.sourceFileInfo = sourceFileInfo; + } + + public boolean isSourceIclInfo() { + return sourceIclInfo; + } + + public boolean isSourceSegmentIdInfo() { + return sourceSegmentIdInfo; + } + + public void setSourceSegmentIdInfo(boolean sourceSegmentIdInfo) { + this.sourceSegmentIdInfo = sourceSegmentIdInfo; } public void incIndent() { diff --git a/src/main/java/dk/camelot64/kickc/asm/AsmSegment.java b/src/main/java/dk/camelot64/kickc/asm/AsmSegment.java index 00dc8355f..d74efbef2 100644 --- a/src/main/java/dk/camelot64/kickc/asm/AsmSegment.java +++ b/src/main/java/dk/camelot64/kickc/asm/AsmSegment.java @@ -1,6 +1,9 @@ package dk.camelot64.kickc.asm; import dk.camelot64.kickc.model.PhiTransitions; +import dk.camelot64.kickc.model.Program; +import dk.camelot64.kickc.model.statements.Statement; +import dk.camelot64.kickc.model.statements.StatementSource; import dk.camelot64.kickc.model.values.ScopeRef; import java.util.ArrayList; @@ -77,6 +80,7 @@ public class AsmSegment { /** * Add a new line just after another line + * * @param line The line to look for. If it is not found an Exception is thrown * @param add The line to add */ @@ -89,7 +93,7 @@ public class AsmSegment { return; } } - throw new NoSuchElementException("Item not found "+line); + throw new NoSuchElementException("Item not found " + line); } public int getIndex() { @@ -163,7 +167,7 @@ public class AsmSegment { * @return The registers clobbered */ public AsmClobber getClobber() { - if(clobberOverwrite!=null) { + if(clobberOverwrite != null) { return clobberOverwrite; } AsmClobber clobber = new AsmClobber(); @@ -180,6 +184,7 @@ public class AsmSegment { /** * Get ASM line by index + * * @param idx The index of the line to get * @return The line with the passed index. Null if not found inside the segment. */ @@ -192,11 +197,48 @@ public class AsmSegment { return null; } - - public String toString(AsmProgram.AsmPrintState printState) { + public String toString(AsmProgram.AsmPrintState printState, Program program) { StringBuffer out = new StringBuffer(); - if(printState.isComments()) { - out.append(printState.getIndent()).append("//SEG").append(getIndex()); + if(printState.isSourceFileInfo()) { + if(this.statementIdx != null && program != null) { + Statement statement = program.getGraph().getStatementByIndex(this.statementIdx); + if(statement != null) { + StatementSource source = statement.getSource(); + if(source != null) { + if(source.getFile() != null || source.getLineNumber() != null) { + out.append(printState.getIndent()).append("// "); + if(source.getFile() != null) + out.append(source.getFile()); + out.append(":"); + if(source.getLineNumber() != null) + out.append(source.getLineNumber()); + out.append("\n"); + } + } + } + } + } + if(printState.isSourceCodeInfo()) { + if(this.statementIdx != null && program != null) { + Statement statement = program.getGraph().getStatementByIndex(this.statementIdx); + if(statement != null) { + StatementSource source = statement.getSource(); + if(source != null) { + if(source.getCode() != null) { + out.append(printState.getIndent()).append("// "); + if(source.getCode() != null) + out.append(source.getCode().replace("\n", "\n" + printState.getIndent() + "// ")); + out.append("\n"); + } + } + } + } + } + if(printState.isSourceIclInfo()) { + out.append(printState.getIndent()).append("//"); + if(printState.isSourceSegmentIdInfo()) { + out.append("SEG").append(getIndex()); + } if(source != null) { out.append(" ").append(source.replace('\r', ' ').replace('\n', ' ')); } @@ -219,7 +261,7 @@ public class AsmSegment { printState.decIndent(); } if(printState.getLineIdx()) { - out.append("["+line.getIndex()+"]"); + out.append("[" + line.getIndex() + "]"); } out.append(printState.getIndent()); if(shouldIndentAsm(line)) { @@ -227,7 +269,7 @@ public class AsmSegment { } if(line instanceof AsmComment) { // Peek forward to find the comment indent - for(int j=i;j