1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-08-03 16:29:17 +00:00

Reformatted for code style.

This commit is contained in:
jespergravgaard 2018-01-01 21:25:11 +01:00
parent 20b9ab6881
commit 4d46820cf4
181 changed files with 4407 additions and 4287 deletions

View File

@ -5,6 +5,20 @@
<value>
<option name="JD_ALIGN_PARAM_COMMENTS" value="false" />
<option name="JD_DO_NOT_WRAP_ONE_LINE_COMMENTS" value="true" />
<codeStyleSettings language="JAVA">
<option name="SPACE_BEFORE_IF_PARENTHESES" value="false" />
<option name="SPACE_BEFORE_WHILE_PARENTHESES" value="false" />
<option name="SPACE_BEFORE_FOR_PARENTHESES" value="false" />
<option name="SPACE_BEFORE_TRY_PARENTHESES" value="false" />
<option name="SPACE_BEFORE_CATCH_PARENTHESES" value="false" />
<option name="SPACE_BEFORE_SWITCH_PARENTHESES" value="false" />
<option name="SPACE_BEFORE_SYNCHRONIZED_PARENTHESES" value="false" />
<indentOptions>
<option name="INDENT_SIZE" value="3" />
<option name="CONTINUATION_INDENT_SIZE" value="6" />
<option name="TAB_SIZE" value="3" />
</indentOptions>
</codeStyleSettings>
</value>
</option>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />

View File

@ -22,34 +22,6 @@ public class Compiler {
this.program = new Program();
}
public CompileLog getLog() {
return program.getLog();
}
public void addImportPath(String path) {
program.getImportPaths().add(path);
}
public Program compile(String fileName) throws IOException {
try {
Pass0GenerateStatementSequence pass0GenerateStatementSequence = new Pass0GenerateStatementSequence(program);
loadAndParseFile(fileName, program, pass0GenerateStatementSequence);
StatementSequence sequence = pass0GenerateStatementSequence.getSequence();
sequence.addStatement(new StatementCall(null, "main", new ArrayList<>()));
program.setStatementSequence(sequence);
pass1GenerateSSA();
pass2OptimizeSSA();
pass3Analysis();
pass4RegisterAllocation();
pass5GenerateAndOptimizeAsm();
return program;
} catch(Exception e) {
System.out.println("EXCEPTION DURING COMPILE " + e.getMessage());
System.out.println(getLog().toString());
throw e;
}
}
public static void loadAndParseFile(String fileName, Program program, Pass0GenerateStatementSequence pass0GenerateStatementSequence) {
try {
File file = loadFile(fileName, program);
@ -100,6 +72,34 @@ public class Compiler {
throw new CompileError("File not found " + fileName);
}
public CompileLog getLog() {
return program.getLog();
}
public void addImportPath(String path) {
program.getImportPaths().add(path);
}
public Program compile(String fileName) throws IOException {
try {
Pass0GenerateStatementSequence pass0GenerateStatementSequence = new Pass0GenerateStatementSequence(program);
loadAndParseFile(fileName, program, pass0GenerateStatementSequence);
StatementSequence sequence = pass0GenerateStatementSequence.getSequence();
sequence.addStatement(new StatementCall(null, "main", new ArrayList<>()));
program.setStatementSequence(sequence);
pass1GenerateSSA();
pass2OptimizeSSA();
pass3Analysis();
pass4RegisterAllocation();
pass5GenerateAndOptimizeAsm();
return program;
} catch(Exception e) {
System.out.println("EXCEPTION DURING COMPILE " + e.getMessage());
System.out.println(getLog().toString());
throw e;
}
}
private Program pass1GenerateSSA() {
new Pass1TypeInference(program).execute();

View File

@ -19,7 +19,7 @@ public class NumberParser {
return parseDecInt(literal);
}
} else {
throw new NumberFormatException("Not Implemented: non-integer parsing. "+literal);
throw new NumberFormatException("Not Implemented: non-integer parsing. " + literal);
}
}

View File

@ -38,7 +38,7 @@ public enum AsmAddressingMode {
public String getAsm(String mnemnonic, String parameter) {
String replaced = template.replace("%i", mnemnonic);
if(parameter!=null) {
if(parameter != null) {
replaced = replaced.replace("%p", parameter);
}
return replaced;

View File

@ -22,7 +22,7 @@ public class AsmBasicUpstart implements AsmLine {
@Override
public String getAsm() {
return ":BasicUpstart("+function+")";
return ":BasicUpstart(" + function + ")";
}
@Override

View File

@ -1,8 +1,9 @@
package dk.camelot64.kickc.asm;
/** Information about what parts of the CPU an ASM instruction clobbers */
/** Information about what parts of the CPU an ASM instruction clobbers */
public class AsmClobber {
public static final AsmClobber CLOBBER_ALL = new AsmClobber(true);
boolean clobberA;
boolean clobberX;
boolean clobberY;
@ -14,6 +15,7 @@ public class AsmClobber {
public AsmClobber() {
}
AsmClobber(boolean clobberAll) {
this.clobberA = clobberAll;
this.clobberX = clobberAll;
@ -24,69 +26,66 @@ public class AsmClobber {
this.clobberZ = clobberAll;
}
public boolean isClobberA() {
return clobberA;
}
public boolean isClobberX() {
return clobberX;
}
public boolean isClobberY() {
return clobberY;
}
public boolean isClobberC() {
return clobberC;
}
public boolean isClobberN() {
return clobberN;
}
public boolean isClobberZ() {
return clobberZ;
}
public boolean isClobberV() {
return clobberV;
}
public void setClobberA(boolean clobberA) {
this.clobberA = clobberA;
}
public boolean isClobberX() {
return clobberX;
}
public void setClobberX(boolean clobberX) {
this.clobberX = clobberX;
}
public boolean isClobberY() {
return clobberY;
}
public void setClobberY(boolean clobberY) {
this.clobberY = clobberY;
}
public boolean isClobberC() {
return clobberC;
}
public void setClobberC(boolean clobberC) {
this.clobberC = clobberC;
}
public boolean isClobberN() {
return clobberN;
}
public void setClobberN(boolean clobberN) {
this.clobberN = clobberN;
}
public boolean isClobberZ() {
return clobberZ;
}
public void setClobberZ(boolean clobberZ) {
this.clobberZ = clobberZ;
}
public boolean isClobberV() {
return clobberV;
}
public void setClobberV(boolean clobberV) {
this.clobberV = clobberV;
}
public static final AsmClobber CLOBBER_ALL = new AsmClobber(true);
/**
* Adds clobber.
* Effective updates so this clobber also clobbers anything added
*
* @param clobber The clobber to add
*/
public void add(AsmClobber clobber) {
@ -102,13 +101,13 @@ public class AsmClobber {
@Override
public String toString() {
return
(clobberA?"A":"") +
(clobberX?"X":"") +
(clobberY?"Y":"") +
(clobberC?"C":"") +
(clobberN?"N":"") +
(clobberZ?"Z":"") +
(clobberV?"V":"") ;
(clobberA ? "A" : "") +
(clobberX ? "X" : "") +
(clobberY ? "Y" : "") +
(clobberC ? "C" : "") +
(clobberN ? "N" : "") +
(clobberZ ? "Z" : "") +
(clobberV ? "V" : "");
}
}

View File

@ -27,7 +27,7 @@ public class AsmComment implements AsmLine {
@Override
public String getAsm() {
return "// "+comment;
return "// " + comment;
}
@Override

View File

@ -1,6 +1,6 @@
package dk.camelot64.kickc.asm;
/** ASM constant declaration */
/** ASM constant declaration */
public class AsmConstant implements AsmLine {
private final String name;
private final String value;
@ -24,7 +24,7 @@ public class AsmConstant implements AsmLine {
@Override
public String getAsm() {
return ".const "+name+" = "+value;
return ".const " + name + " = " + value;
}
@Override

View File

@ -25,7 +25,7 @@ public class AsmDataFill implements AsmLine {
@Override
public int getLineBytes() {
return size*getElementBytes();
return size * getElementBytes();
}
@Override
@ -36,9 +36,9 @@ public class AsmDataFill implements AsmLine {
@Override
public String getAsm() {
StringBuilder asm = new StringBuilder();
asm.append(label+": ");
asm.append(label + ": ");
asm.append(".fill ");
asm.append(AsmFormat.getAsmNumber(size*type.bytes));
asm.append(AsmFormat.getAsmNumber(size * type.bytes));
asm.append(", ");
asm.append(fillValue);
return asm.toString();

View File

@ -12,21 +12,6 @@ public class AsmDataNumeric implements AsmLine {
private List<String> values;
private int index;
public static enum Type {
BYTE("byte", 1),
WORD("word", 2),
DWORD("dword", 4);
public final String asm;
public final int bytes;
Type(String asm, int bytes) {
this.asm = asm;
this.bytes = bytes;
}
}
public AsmDataNumeric(String label, Type type, List<String> values) {
this.label = label;
this.type = type;
@ -74,4 +59,19 @@ public class AsmDataNumeric implements AsmLine {
this.index = index;
}
public static enum Type {
BYTE("byte", 1),
WORD("word", 2),
DWORD("dword", 4);
public final String asm;
public final int bytes;
Type(String asm, int bytes) {
this.asm = asm;
this.bytes = bytes;
}
}
}

View File

@ -25,7 +25,7 @@ public class AsmDataString implements AsmLine {
@Override
public String getAsm() {
StringBuilder asm = new StringBuilder();
asm.append(label+": ");
asm.append(label + ": ");
asm.append(".text ");
asm.append(value);
return asm.toString();

View File

@ -18,10 +18,18 @@ public class AsmInstruction implements AsmLine {
return parameter;
}
public void setParameter(String parameter) {
this.parameter = parameter;
}
public AsmInstructionType getType() {
return type;
}
public void setType(AsmInstructionType type) {
this.type = type;
}
@Override
public int getLineBytes() {
return type.getBytes();
@ -51,12 +59,4 @@ public class AsmInstruction implements AsmLine {
public void setIndex(int index) {
this.index = index;
}
public void setParameter(String parameter) {
this.parameter = parameter;
}
public void setType(AsmInstructionType type) {
this.type = type;
}
}

View File

@ -1,7 +1,5 @@
package dk.camelot64.kickc.asm;
import dk.camelot64.kickc.NumberParser;
import java.util.*;
/**
@ -10,38 +8,10 @@ import java.util.*;
public class AsmInstructionSet {
private static AsmInstructionSet set = new AsmInstructionSet();
public static AsmInstructionType getInstructionType(String mnemonic, AsmAddressingMode mode, boolean isZp) {
AsmInstructionType type = null;
if (AsmAddressingMode.ABS.equals(mode) && isZp) {
type = set.getType(mnemonic, AsmAddressingMode.ZP);
}
if (AsmAddressingMode.ABX.equals(mode) && isZp) {
type = set.getType(mnemonic, AsmAddressingMode.ZPX);
}
if (AsmAddressingMode.ABY.equals(mode) && isZp) {
type = set.getType(mnemonic, AsmAddressingMode.ZPY);
}
if (type == null) {
type = set.getType(mnemonic, mode);
}
if (type == null && AsmAddressingMode.ABS.equals(mode)) {
type = set.getType(mnemonic, AsmAddressingMode.REL);
}
return type;
}
private List<AsmInstructionType> instructions;
/** Maps mnemonic_addressingmMode to the instruction type */
private Map<String, AsmInstructionType> instructionsMap;
private void add(int opcode, String mnemonic, AsmAddressingMode addressingmMode, double cycles) {
AsmInstructionType instructionType = new AsmInstructionType(opcode, mnemonic, addressingmMode, cycles);
instructions.add(instructionType);
instructionsMap.put(mnemonic+"_"+addressingmMode.getName(), instructionType);
}
public AsmInstructionSet() {
this.instructions = new ArrayList<>();
this.instructionsMap = new HashMap<>();
@ -315,43 +285,43 @@ public class AsmInstructionSet {
add(0xfe, "inc", abx, 7.0);
add(0xff, "isc", abx, 7.0);
List<String> jumps = Arrays.asList("jmp", "beq", "bne", "bcc", "bcs", "bvs", "bvc", "bmi", "bpl", "jsr");
for (AsmInstructionType instruction : instructions) {
for(AsmInstructionType instruction : instructions) {
if(jumps.contains(instruction.getMnemnonic())) {
instruction.setJump(true);
}
}
List<String> cxs = Arrays.asList("dex", "inx", "ldx", "tax", "tsx", "las", "lax", "axs");
for (AsmInstructionType instruction : instructions) {
List<String> cxs = Arrays.asList("dex", "inx", "ldx", "tax", "tsx", "las", "lax", "axs");
for(AsmInstructionType instruction : instructions) {
if(cxs.contains(instruction.getMnemnonic())) {
instruction.getClobber().setClobberX(true);
}
}
List<String> cys = Arrays.asList("dey", "iny", "ldy", "tay" );
for (AsmInstructionType instruction : instructions) {
List<String> cys = Arrays.asList("dey", "iny", "ldy", "tay");
for(AsmInstructionType instruction : instructions) {
if(cys.contains(instruction.getMnemnonic())) {
instruction.getClobber().setClobberY(true);
}
}
List<String> cas = Arrays.asList("ora", "and", "eor", "adc", "sbc", "lda", "txa", "tya", "pla", "slo", "rla", "sre", "rra", "isc", "anc", "alr", "arr", "xaa", "lax", "las");
for (AsmInstructionType instruction : instructions) {
for(AsmInstructionType instruction : instructions) {
if(cas.contains(instruction.getMnemnonic())) {
instruction.getClobber().setClobberA(true);
}
}
List<String> ccs = Arrays.asList("adc", "sbc", "cmp", "cpx", "cpy", "asl", "rol", "lsr", "ror", "plp", "rti", "clc", "sec", "slo", "rla", "sre", "rra", "dcp", "isc", "anc", "alr", "arr", "axs");
for (AsmInstructionType instruction : instructions) {
for(AsmInstructionType instruction : instructions) {
if(ccs.contains(instruction.getMnemnonic())) {
instruction.getClobber().setClobberC(true);
}
}
List<String> cvs = Arrays.asList("adc", "sbc", "plp", "rti", "bit", "rra", "isc", "arr");
for (AsmInstructionType instruction : instructions) {
for(AsmInstructionType instruction : instructions) {
if(cvs.contains(instruction.getMnemnonic())) {
instruction.getClobber().setClobberV(true);
}
}
List<String> czs = Arrays.asList("ora", "and", "eor", "adc", "sbc", "cmp", "cpx", "cpy", "dec", "dex", "dey", "inc", "inx", "iny", "asl", "rol", "lsr", "ror", "lda", "ldx", "ldy", "tax", "txa", "tay", "tya", "tsx", "txs", "pla", "plp", "rti", "bit", "slo", "rla", "sre", "rra", "lax", "dcp", "isc", "anc", "alr", "arr", "xaa", "lax", "axs", "las");
for (AsmInstructionType instruction : instructions) {
for(AsmInstructionType instruction : instructions) {
if(czs.contains(instruction.getMnemnonic())) {
instruction.getClobber().setClobberZ(true);
instruction.getClobber().setClobberN(true);
@ -359,8 +329,34 @@ public class AsmInstructionSet {
}
}
public static AsmInstructionType getInstructionType(String mnemonic, AsmAddressingMode mode, boolean isZp) {
AsmInstructionType type = null;
if(AsmAddressingMode.ABS.equals(mode) && isZp) {
type = set.getType(mnemonic, AsmAddressingMode.ZP);
}
if(AsmAddressingMode.ABX.equals(mode) && isZp) {
type = set.getType(mnemonic, AsmAddressingMode.ZPX);
}
if(AsmAddressingMode.ABY.equals(mode) && isZp) {
type = set.getType(mnemonic, AsmAddressingMode.ZPY);
}
if(type == null) {
type = set.getType(mnemonic, mode);
}
if(type == null && AsmAddressingMode.ABS.equals(mode)) {
type = set.getType(mnemonic, AsmAddressingMode.REL);
}
return type;
}
private void add(int opcode, String mnemonic, AsmAddressingMode addressingmMode, double cycles) {
AsmInstructionType instructionType = new AsmInstructionType(opcode, mnemonic, addressingmMode, cycles);
instructions.add(instructionType);
instructionsMap.put(mnemonic + "_" + addressingmMode.getName(), instructionType);
}
public AsmInstructionType getType(String mnemonic, AsmAddressingMode addressingMode) {
String key = mnemonic.toLowerCase()+"_"+addressingMode.getName();
String key = mnemonic.toLowerCase() + "_" + addressingMode.getName();
return instructionsMap.get(key);
}

View File

@ -1,6 +1,6 @@
package dk.camelot64.kickc.asm;
/** A label / jump target */
/** A label / jump target */
public class AsmLabel implements AsmLine {
private String label;
@ -15,6 +15,10 @@ public class AsmLabel implements AsmLine {
return label;
}
public void setLabel(String label) {
this.label = label;
}
@Override
public int getLineBytes() {
return 0;
@ -27,7 +31,7 @@ public class AsmLabel implements AsmLine {
@Override
public String getAsm() {
return label+":";
return label + ":";
}
@Override
@ -44,8 +48,4 @@ public class AsmLabel implements AsmLine {
public String toString() {
return getAsm();
}
public void setLabel(String label) {
this.label = label;
}
}

View File

@ -2,7 +2,7 @@ package dk.camelot64.kickc.asm;
import dk.camelot64.kickc.fragment.AsmFormat;
/** A label declaration .label lbl = val */
/** A label declaration .label lbl = val */
public class AsmLabelDecl implements AsmLine {
private final String name;
private final int address;
@ -26,7 +26,7 @@ public class AsmLabelDecl implements AsmLine {
@Override
public String getAsm() {
return ".label "+name+" = "+ AsmFormat.getAsmNumber(address);
return ".label " + name + " = " + AsmFormat.getAsmNumber(address);
}
@Override

View File

@ -76,15 +76,17 @@ public class AsmProgram {
/**
* Add a constant declararion to the ASM
*
* @param name The name of the constant
* @param value The value of the constant
*/
public void addConstant(String name, String value) {
addLine(new AsmConstant(name, value));
}
public void addConstant(String name, String value) {
addLine(new AsmConstant(name, value));
}
/**
* Add a BYTE/WORD/DWORD data declaration tot the ASM
*
* @param label The label of the data
* @param type The type of the data
* @param asmElements The value of the elements
@ -95,6 +97,7 @@ public class AsmProgram {
/**
* Add a FILL data declaration to the ASM
*
* @param label The label of the data
* @param type The type of the data
* @param size The size of data to fill
@ -105,6 +108,7 @@ public class AsmProgram {
/**
* Add a string data declaration to the ASM
*
* @param label The label of the data
* @param value The value of the string
*/
@ -114,6 +118,7 @@ public class AsmProgram {
/**
* Add data alignment to the ASM
*
* @param alignment The number to align the address of the next data to
*/
public void addDataAlignment(String alignment) {
@ -129,7 +134,7 @@ public class AsmProgram {
*/
public int getBytes() {
int bytes = 0;
for (AsmSegment segment : segments) {
for(AsmSegment segment : segments) {
bytes += segment.getBytes();
}
return bytes;
@ -143,7 +148,7 @@ public class AsmProgram {
*/
public double getCycles() {
double cycles = 0.0;
for (AsmSegment segment : segments) {
for(AsmSegment segment : segments) {
cycles += segment.getCycles();
}
return cycles;
@ -157,7 +162,7 @@ public class AsmProgram {
*/
public AsmClobber getClobber() {
AsmClobber clobber = new AsmClobber();
for (AsmSegment segment : segments) {
for(AsmSegment segment : segments) {
clobber.add(segment.getClobber());
}
return clobber;
@ -169,12 +174,17 @@ public class AsmProgram {
public String toString(AsmPrintState printState) {
StringBuilder out = new StringBuilder();
for (AsmSegment segment : segments) {
for(AsmSegment segment : segments) {
out.append(segment.toString(printState));
}
return out.toString();
}
@Override
public String toString() {
return toString(true);
}
static class AsmPrintState {
boolean comments;
String indent;
@ -193,7 +203,7 @@ public class AsmProgram {
}
public void decIndent() {
if(this.indent.length()>=2) {
if(this.indent.length() >= 2) {
this.indent = this.indent.substring(0, this.indent.length() - 2);
}
}
@ -205,10 +215,4 @@ public class AsmProgram {
}
@Override
public String toString() {
return toString(true);
}
}

View File

@ -18,169 +18,28 @@ public class AsmProgramStaticRegisterValues {
initValues();
}
public AsmRegisterValues getValues(AsmInstruction instruction) {
return values.get(instruction);
}
private void initValues() {
AsmRegisterValues current = new AsmRegisterValues();
for (AsmSegment segment : program.getSegments()) {
for (AsmLine line : segment.getLines()) {
current = updateStaticRegisterValues(current, line);
}
}
}
private AsmRegisterValues updateStaticRegisterValues(AsmRegisterValues current, AsmLine line) {
if (line instanceof AsmLabel) {
current = new AsmRegisterValues();
} else if (line instanceof AsmScopeBegin) {
current = new AsmRegisterValues();
} else if (line instanceof AsmScopeEnd) {
current = new AsmRegisterValues();
} else if (line instanceof AsmInstruction) {
AsmInstruction instruction = (AsmInstruction) line;
values.put(instruction, current);
current = new AsmRegisterValues(current);
AsmInstructionType instructionType = instruction.getType();
AsmClobber clobber = instructionType.getClobber();
if(instruction.getType().getMnemnonic().equals("jsr")) {
clobber = AsmClobber.CLOBBER_ALL;
}
if (clobber.isClobberA()) {
current.setA(null);
current.setaMem(null);
}
if (clobber.isClobberX()) {
current.setX(null);
current.setxMem(null);
}
if (clobber.isClobberY()) {
current.setY(null);
current.setyMem(null);
}
if (clobber.isClobberC()) {
current.setC(null);
}
if (clobber.isClobberN()) {
current.setN(null);
}
if (clobber.isClobberV()) {
current.setV(null);
}
if (clobber.isClobberZ()) {
current.setZ(null);
}
String mnemnonic = instructionType.getMnemnonic();
AsmAddressingMode addressingMode = instructionType.getAddressingMode();
if ((mnemnonic.equals("inc") || mnemnonic.equals("dec") || mnemnonic.equals("ror") || mnemnonic.equals("rol") || mnemnonic.equals("lsr") || mnemnonic.equals("asl")) && (addressingMode.equals(AsmAddressingMode.ZP) || addressingMode.equals(AsmAddressingMode.ABS))) {
String modParam = instruction.getParameter();
if(current.getaMem()!=null && current.getaMem().equals(modParam)) {
current.setaMem(null);
}
if(current.getxMem()!=null && current.getxMem().equals(modParam)) {
current.setxMem(null);
}
if(current.getyMem()!=null && current.getyMem().equals(modParam)) {
current.setyMem(null);
}
}
if (mnemnonic.equals("lda") && addressingMode.equals(AsmAddressingMode.IMM)) {
current.setA(instruction.getParameter());
current.setaMem(null);
Integer immValue = getImmValue(instruction.getParameter());
if (immValue != null) {
current.setZ(immValue == 0);
current.setN(immValue > 127);
}
}
if (mnemnonic.equals("lda") && (addressingMode.equals(AsmAddressingMode.ZP) || addressingMode.equals(AsmAddressingMode.ABS))) {
current.setaMem(instruction.getParameter());
current.setA(null);
}
if (mnemnonic.equals("sta") && (addressingMode.equals(AsmAddressingMode.ZP) || addressingMode.equals(AsmAddressingMode.ABS))) {
current.setaMem(instruction.getParameter());
}
if (mnemnonic.equals("ldx") && addressingMode.equals(AsmAddressingMode.IMM)) {
current.setX(instruction.getParameter());
current.setxMem(null);
Integer immValue = getImmValue(instruction.getParameter());
if (immValue != null) {
current.setZ(immValue == 0);
current.setN(immValue > 127);
}
}
if (mnemnonic.equals("ldx") && (addressingMode.equals(AsmAddressingMode.ZP) || addressingMode.equals(AsmAddressingMode.ABS))) {
current.setxMem(instruction.getParameter());
current.setX(null);
}
if (mnemnonic.equals("stx") && (addressingMode.equals(AsmAddressingMode.ZP) || addressingMode.equals(AsmAddressingMode.ABS))) {
current.setxMem(instruction.getParameter());
}
if (mnemnonic.equals("ldy") && addressingMode.equals(AsmAddressingMode.IMM)) {
current.setY(instruction.getParameter());
current.setyMem(null);
Integer immValue = getImmValue(instruction.getParameter());
if (immValue != null) {
current.setZ(immValue == 0);
current.setN(immValue > 127);
}
}
if (mnemnonic.equals("ldy") && (addressingMode.equals(AsmAddressingMode.ZP) || addressingMode.equals(AsmAddressingMode.ABS))) {
current.setyMem(instruction.getParameter());
}
if (mnemnonic.equals("sty") && (addressingMode.equals(AsmAddressingMode.ZP) || addressingMode.equals(AsmAddressingMode.ABS))) {
current.setyMem(instruction.getParameter());
current.setY(null);
}
if (mnemnonic.equals("txa")) {
current.setA(current.getX());
current.setaMem(current.getxMem());
}
if (mnemnonic.equals("tax")) {
current.setX(current.getA());
current.setxMem(current.getaMem());
}
if (mnemnonic.equals("tya")) {
current.setA(current.getY());
current.setaMem(current.getyMem());
}
if (mnemnonic.equals("tay")) {
current.setY(current.getA());
current.setyMem(current.getaMem());
}
if (mnemnonic.equals("sec")) {
current.setC(Boolean.TRUE);
}
if (mnemnonic.equals("clc")) {
current.setC(Boolean.FALSE);
}
}
return current;
}
public static Integer getImmValue(String parameter) {
Integer immValue = null;
if (parameter != null) {
if(parameter != null) {
if(parameter.startsWith("<")) {
try {
int parValue = Integer.parseInt(parameter.substring(1));
return 0xff & parValue;
} catch (NumberFormatException e) {
} catch(NumberFormatException e) {
// ignore
}
} else if(parameter.startsWith(">")) {
try {
int parValue = Integer.parseInt(parameter.substring(1));
return 0xff & (parValue / 0x100);
} catch (NumberFormatException e) {
} catch(NumberFormatException e) {
// ignore
}
} else {
try {
immValue = Integer.parseInt(parameter);
return immValue;
} catch (NumberFormatException e) {
} catch(NumberFormatException e) {
// ignore
}
}
@ -189,17 +48,158 @@ public class AsmProgramStaticRegisterValues {
}
public static boolean matchImm(String immVal1, String immVal2) {
if (immVal1 != null && immVal2 != null && immVal1.equals(immVal2)) {
if(immVal1 != null && immVal2 != null && immVal1.equals(immVal2)) {
return true;
}
Integer immInt1 = getImmValue(immVal1);
Integer immInt2 = getImmValue(immVal2);
if (immInt1 != null && immInt2 != null && immInt1.equals(immInt2)) {
if(immInt1 != null && immInt2 != null && immInt1.equals(immInt2)) {
return true;
}
return false;
}
public AsmRegisterValues getValues(AsmInstruction instruction) {
return values.get(instruction);
}
private void initValues() {
AsmRegisterValues current = new AsmRegisterValues();
for(AsmSegment segment : program.getSegments()) {
for(AsmLine line : segment.getLines()) {
current = updateStaticRegisterValues(current, line);
}
}
}
private AsmRegisterValues updateStaticRegisterValues(AsmRegisterValues current, AsmLine line) {
if(line instanceof AsmLabel) {
current = new AsmRegisterValues();
} else if(line instanceof AsmScopeBegin) {
current = new AsmRegisterValues();
} else if(line instanceof AsmScopeEnd) {
current = new AsmRegisterValues();
} else if(line instanceof AsmInstruction) {
AsmInstruction instruction = (AsmInstruction) line;
values.put(instruction, current);
current = new AsmRegisterValues(current);
AsmInstructionType instructionType = instruction.getType();
AsmClobber clobber = instructionType.getClobber();
if(instruction.getType().getMnemnonic().equals("jsr")) {
clobber = AsmClobber.CLOBBER_ALL;
}
if(clobber.isClobberA()) {
current.setA(null);
current.setaMem(null);
}
if(clobber.isClobberX()) {
current.setX(null);
current.setxMem(null);
}
if(clobber.isClobberY()) {
current.setY(null);
current.setyMem(null);
}
if(clobber.isClobberC()) {
current.setC(null);
}
if(clobber.isClobberN()) {
current.setN(null);
}
if(clobber.isClobberV()) {
current.setV(null);
}
if(clobber.isClobberZ()) {
current.setZ(null);
}
String mnemnonic = instructionType.getMnemnonic();
AsmAddressingMode addressingMode = instructionType.getAddressingMode();
if((mnemnonic.equals("inc") || mnemnonic.equals("dec") || mnemnonic.equals("ror") || mnemnonic.equals("rol") || mnemnonic.equals("lsr") || mnemnonic.equals("asl")) && (addressingMode.equals(AsmAddressingMode.ZP) || addressingMode.equals(AsmAddressingMode.ABS))) {
String modParam = instruction.getParameter();
if(current.getaMem() != null && current.getaMem().equals(modParam)) {
current.setaMem(null);
}
if(current.getxMem() != null && current.getxMem().equals(modParam)) {
current.setxMem(null);
}
if(current.getyMem() != null && current.getyMem().equals(modParam)) {
current.setyMem(null);
}
}
if(mnemnonic.equals("lda") && addressingMode.equals(AsmAddressingMode.IMM)) {
current.setA(instruction.getParameter());
current.setaMem(null);
Integer immValue = getImmValue(instruction.getParameter());
if(immValue != null) {
current.setZ(immValue == 0);
current.setN(immValue > 127);
}
}
if(mnemnonic.equals("lda") && (addressingMode.equals(AsmAddressingMode.ZP) || addressingMode.equals(AsmAddressingMode.ABS))) {
current.setaMem(instruction.getParameter());
current.setA(null);
}
if(mnemnonic.equals("sta") && (addressingMode.equals(AsmAddressingMode.ZP) || addressingMode.equals(AsmAddressingMode.ABS))) {
current.setaMem(instruction.getParameter());
}
if(mnemnonic.equals("ldx") && addressingMode.equals(AsmAddressingMode.IMM)) {
current.setX(instruction.getParameter());
current.setxMem(null);
Integer immValue = getImmValue(instruction.getParameter());
if(immValue != null) {
current.setZ(immValue == 0);
current.setN(immValue > 127);
}
}
if(mnemnonic.equals("ldx") && (addressingMode.equals(AsmAddressingMode.ZP) || addressingMode.equals(AsmAddressingMode.ABS))) {
current.setxMem(instruction.getParameter());
current.setX(null);
}
if(mnemnonic.equals("stx") && (addressingMode.equals(AsmAddressingMode.ZP) || addressingMode.equals(AsmAddressingMode.ABS))) {
current.setxMem(instruction.getParameter());
}
if(mnemnonic.equals("ldy") && addressingMode.equals(AsmAddressingMode.IMM)) {
current.setY(instruction.getParameter());
current.setyMem(null);
Integer immValue = getImmValue(instruction.getParameter());
if(immValue != null) {
current.setZ(immValue == 0);
current.setN(immValue > 127);
}
}
if(mnemnonic.equals("ldy") && (addressingMode.equals(AsmAddressingMode.ZP) || addressingMode.equals(AsmAddressingMode.ABS))) {
current.setyMem(instruction.getParameter());
}
if(mnemnonic.equals("sty") && (addressingMode.equals(AsmAddressingMode.ZP) || addressingMode.equals(AsmAddressingMode.ABS))) {
current.setyMem(instruction.getParameter());
current.setY(null);
}
if(mnemnonic.equals("txa")) {
current.setA(current.getX());
current.setaMem(current.getxMem());
}
if(mnemnonic.equals("tax")) {
current.setX(current.getA());
current.setxMem(current.getaMem());
}
if(mnemnonic.equals("tya")) {
current.setA(current.getY());
current.setaMem(current.getyMem());
}
if(mnemnonic.equals("tay")) {
current.setY(current.getA());
current.setyMem(current.getaMem());
}
if(mnemnonic.equals("sec")) {
current.setC(Boolean.TRUE);
}
if(mnemnonic.equals("clc")) {
current.setC(Boolean.FALSE);
}
}
return current;
}
/**
* Known values of registers/flags at an instruction. null where value is unknown.
*/
@ -235,48 +235,64 @@ public class AsmProgramStaticRegisterValues {
return a;
}
public void setA(String a) {
this.a = a;
}
public String getaMem() {
return aMem;
}
public void setaMem(String aMem) {
this.aMem = aMem;
}
public String getX() {
return x;
}
public String getY() {
return y;
}
public Boolean getC() {
return c;
}
public Boolean getV() {
return v;
}
public Boolean getN() {
return n;
}
public Boolean getZ() {
return z;
}
public void setX(String x) {
this.x = x;
}
public String getY() {
return y;
}
public void setY(String y) {
this.y = y;
}
public void setA(String a) {
this.a = a;
public Boolean getC() {
return c;
}
public void setaMem(String aMem) {
this.aMem = aMem;
public void setC(Boolean c) {
this.c = c;
}
public Boolean getV() {
return v;
}
public void setV(Boolean v) {
this.v = v;
}
public Boolean getN() {
return n;
}
public void setN(Boolean n) {
this.n = n;
}
public Boolean getZ() {
return z;
}
public void setZ(Boolean z) {
this.z = z;
}
public String getxMem() {
@ -295,22 +311,6 @@ public class AsmProgramStaticRegisterValues {
this.yMem = yMem;
}
public void setC(Boolean c) {
this.c = c;
}
public void setV(Boolean v) {
this.v = v;
}
public void setN(Boolean n) {
this.n = n;
}
public void setZ(Boolean z) {
this.z = z;
}
}

View File

@ -27,7 +27,7 @@ public class AsmScopeBegin implements AsmLine {
@Override
public String getAsm() {
return label+":"+" {";
return label + ":" + " {";
}
@Override

View File

@ -1,6 +1,6 @@
package dk.camelot64.kickc.asm;
/** The end of a scope */
/** The end of a scope */
public class AsmScopeEnd implements AsmLine {
private int index;

View File

@ -70,7 +70,7 @@ public class AsmSegment {
}
public void setFragment(String fragment) {
this.fragment = fragment;
this.fragment = fragment;
}
public String getPhiTransitionId() {
@ -97,7 +97,7 @@ public class AsmSegment {
*/
public int getBytes() {
int bytes = 0;
for (AsmLine line : lines) {
for(AsmLine line : lines) {
bytes += line.getLineBytes();
}
return bytes;
@ -111,7 +111,7 @@ public class AsmSegment {
*/
public double getCycles() {
double cycles = 0.0;
for (AsmLine line : lines) {
for(AsmLine line : lines) {
cycles += line.getLineCycles();
}
return cycles;
@ -125,8 +125,8 @@ public class AsmSegment {
*/
public AsmClobber getClobber() {
AsmClobber clobber = new AsmClobber();
for (AsmLine line : lines) {
if (line instanceof AsmInstruction) {
for(AsmLine line : lines) {
if(line instanceof AsmInstruction) {
AsmInstruction asmInstruction = (AsmInstruction) line;
AsmInstructionType asmInstructionType = asmInstruction.getType();
AsmClobber asmClobber = asmInstructionType.getClobber();
@ -138,27 +138,27 @@ public class AsmSegment {
public String toString(AsmProgram.AsmPrintState printState) {
StringBuffer out = new StringBuffer();
if (printState.isComments()) {
if(printState.isComments()) {
out.append(printState.getIndent()).append("//SEG").append(getIndex());
if (source != null) {
if(source != null) {
out.append(" ").append(source);
}
if(phiTransitionId!=null) {
if(phiTransitionId != null) {
out.append(" [").append(phiTransitionId);
if(phiTransitionAssignmentIdx!=null) {
if(phiTransitionAssignmentIdx != null) {
out.append("#").append(phiTransitionAssignmentIdx);
}
out.append("]");
}
if (fragment!=null) {
if(fragment != null) {
out.append(" -- ");
out.append(fragment).append(" ");
}
out.append("\n");
}
for (AsmLine line : lines) {
if (line instanceof AsmComment && !printState.isComments()) {
if (!((AsmComment) line).getComment().contains("Fragment")) {
for(AsmLine line : lines) {
if(line instanceof AsmComment && !printState.isComments()) {
if(!((AsmComment) line).getComment().contains("Fragment")) {
continue;
}
}
@ -166,7 +166,7 @@ public class AsmSegment {
printState.decIndent();
}
out.append(printState.getIndent());
if (line instanceof AsmComment || line instanceof AsmInstruction || line instanceof AsmLabelDecl || line instanceof AsmConstant || line instanceof AsmDataNumeric || line instanceof AsmDataFill || line instanceof AsmDataString|| line instanceof AsmDataAlignment) {
if(line instanceof AsmComment || line instanceof AsmInstruction || line instanceof AsmLabelDecl || line instanceof AsmConstant || line instanceof AsmDataNumeric || line instanceof AsmDataFill || line instanceof AsmDataString || line instanceof AsmDataAlignment) {
out.append(" ");
}
out.append(line.getAsm() + "\n");

View File

@ -26,7 +26,7 @@ public class AsmSetPc implements AsmLine {
@Override
public String getAsm() {
return ".pc = "+ AsmFormat.getAsmNumber(address)+" \""+name+"\"";
return ".pc = " + AsmFormat.getAsmNumber(address) + " \"" + name + "\"";
}
@Override

View File

@ -2,141 +2,141 @@ package dk.camelot64.kickc.fragment;
import dk.camelot64.kickc.model.*;
/** Formatting of numbers, constants, names and more for KickAssembler */
/** Formatting of numbers, constants, names and more for KickAssembler */
public class AsmFormat {
/**
* Get ASM code for a constant value
*
* @param value The constant value
* @param precedence The precedence of the outer expression operator. Used to generate perenthesis when needed.
* @param codeScope The scope containing the code being generated. Used for adding scope to the name when needed (eg. line.x1 when referencing x1 variable inside line scope from outside line scope).
* @return The ASM string representing the constant value
*/
public static String getAsmConstant(Program program, ConstantValue value, int precedence, ScopeRef codeScope) {
if (value instanceof ConstantRef) {
ConstantVar constantVar = program.getScope().getConstant((ConstantRef) value);
String asmName = constantVar.getAsmName() == null ? constantVar.getLocalName() : constantVar.getAsmName();
return getAsmParamName(constantVar.getScope().getRef(), asmName, codeScope);
} else if (value instanceof ConstantInteger) {
return getAsmNumber(((ConstantInteger) value).getNumber());
} else if (value instanceof ConstantChar) {
return "'" + ((ConstantChar) value).getValue() + "'";
} else if (value instanceof ConstantString) {
return "\"" + ((ConstantString) value).getValue() + "\"";
} else if (value instanceof ConstantUnary) {
ConstantUnary unary = (ConstantUnary) value;
Operator operator = unary.getOperator();
boolean parenthesis = operator.getPrecedence() > precedence;
return (parenthesis ? "(" : "") +
getAsmConstantUnary(program, codeScope, operator, unary.getOperand(), precedence) +
(parenthesis ? ")" : "");
} else if (value instanceof ConstantBinary) {
ConstantBinary binary = (ConstantBinary) value;
Operator operator = binary.getOperator();
boolean parenthesis = operator.getPrecedence() > precedence;
return
(parenthesis ? "(" : "") +
getAsmConstant(program, binary.getLeft(), operator.getPrecedence(), codeScope) +
operator.getOperator() +
getAsmConstant(program, binary.getRight(), operator.getPrecedence(), codeScope) +
(parenthesis ? ")" : "");
} else {
throw new RuntimeException("Constant type not supported " + value);
}
}
/**
* Get ASM code for a constant value
*
* @param value The constant value
* @param precedence The precedence of the outer expression operator. Used to generate perenthesis when needed.
* @param codeScope The scope containing the code being generated. Used for adding scope to the name when needed (eg. line.x1 when referencing x1 variable inside line scope from outside line scope).
* @return The ASM string representing the constant value
*/
public static String getAsmConstant(Program program, ConstantValue value, int precedence, ScopeRef codeScope) {
if(value instanceof ConstantRef) {
ConstantVar constantVar = program.getScope().getConstant((ConstantRef) value);
String asmName = constantVar.getAsmName() == null ? constantVar.getLocalName() : constantVar.getAsmName();
return getAsmParamName(constantVar.getScope().getRef(), asmName, codeScope);
} else if(value instanceof ConstantInteger) {
return getAsmNumber(((ConstantInteger) value).getNumber());
} else if(value instanceof ConstantChar) {
return "'" + ((ConstantChar) value).getValue() + "'";
} else if(value instanceof ConstantString) {
return "\"" + ((ConstantString) value).getValue() + "\"";
} else if(value instanceof ConstantUnary) {
ConstantUnary unary = (ConstantUnary) value;
Operator operator = unary.getOperator();
boolean parenthesis = operator.getPrecedence() > precedence;
return (parenthesis ? "(" : "") +
getAsmConstantUnary(program, codeScope, operator, unary.getOperand(), precedence) +
(parenthesis ? ")" : "");
} else if(value instanceof ConstantBinary) {
ConstantBinary binary = (ConstantBinary) value;
Operator operator = binary.getOperator();
boolean parenthesis = operator.getPrecedence() > precedence;
return
(parenthesis ? "(" : "") +
getAsmConstant(program, binary.getLeft(), operator.getPrecedence(), codeScope) +
operator.getOperator() +
getAsmConstant(program, binary.getRight(), operator.getPrecedence(), codeScope) +
(parenthesis ? ")" : "");
} else {
throw new RuntimeException("Constant type not supported " + value);
}
}
/**
* Get ASM code for a constant unary expression
*
* @param program The program
* @param codeScope The scope containing the code being generated. Used for adding scope to the name when needed (eg. line.x1 when referencing x1 variable inside line scope from outside line scope).
* @param operator The unary operator
* @param operand The operand of the unary expression
* @return The ASM string representing the constant value
*/
private static String getAsmConstantUnary(Program program, ScopeRef codeScope, Operator operator, ConstantValue operand, int outerPrecedence) {
if (Operator.CAST_BYTE.equals(operator) || Operator.CAST_SBYTE.equals(operator)) {
SymbolType operandType = SymbolTypeInference.inferType(program.getScope(), operand);
if (SymbolType.isByte(operandType) || SymbolType.isSByte(operandType)) {
// No cast needed
return getAsmConstant(program, operand, outerPrecedence, codeScope);
} else {
return "$ff & " + getAsmConstant(program, operand, Operator.BOOL_AND.getPrecedence(), codeScope);
}
} else if (Operator.CAST_WORD.equals(operator) || Operator.CAST_SWORD.equals(operator) || Operator.CAST_PTRBY.equals(operator)) {
SymbolType operandType = SymbolTypeInference.inferType(program.getScope(), operand);
if (SymbolType.isWord(operandType) || SymbolType.isSWord(operandType)) {
// No cast needed
return getAsmConstant(program, operand, outerPrecedence, codeScope);
} else {
return "$ffff & " + getAsmConstant(program, operand, Operator.BOOL_AND.getPrecedence(), codeScope);
}
} else if (Operator.INCREMENT.equals(operator)) {
return getAsmConstant(program, operand, Operator.PLUS.getPrecedence(), codeScope) + "+1";
} else if (Operator.DECREMENT.equals(operator)) {
return getAsmConstant(program, operand, Operator.PLUS.getPrecedence(), codeScope) + "-1";
} else {
return operator.getOperator() +
getAsmConstant(program, operand, operator.getPrecedence(), codeScope);
}
}
/**
* Get ASM code for a constant unary expression
*
* @param program The program
* @param codeScope The scope containing the code being generated. Used for adding scope to the name when needed (eg. line.x1 when referencing x1 variable inside line scope from outside line scope).
* @param operator The unary operator
* @param operand The operand of the unary expression
* @return The ASM string representing the constant value
*/
private static String getAsmConstantUnary(Program program, ScopeRef codeScope, Operator operator, ConstantValue operand, int outerPrecedence) {
if(Operator.CAST_BYTE.equals(operator) || Operator.CAST_SBYTE.equals(operator)) {
SymbolType operandType = SymbolTypeInference.inferType(program.getScope(), operand);
if(SymbolType.isByte(operandType) || SymbolType.isSByte(operandType)) {
// No cast needed
return getAsmConstant(program, operand, outerPrecedence, codeScope);
} else {
return "$ff & " + getAsmConstant(program, operand, Operator.BOOL_AND.getPrecedence(), codeScope);
}
} else if(Operator.CAST_WORD.equals(operator) || Operator.CAST_SWORD.equals(operator) || Operator.CAST_PTRBY.equals(operator)) {
SymbolType operandType = SymbolTypeInference.inferType(program.getScope(), operand);
if(SymbolType.isWord(operandType) || SymbolType.isSWord(operandType)) {
// No cast needed
return getAsmConstant(program, operand, outerPrecedence, codeScope);
} else {
return "$ffff & " + getAsmConstant(program, operand, Operator.BOOL_AND.getPrecedence(), codeScope);
}
} else if(Operator.INCREMENT.equals(operator)) {
return getAsmConstant(program, operand, Operator.PLUS.getPrecedence(), codeScope) + "+1";
} else if(Operator.DECREMENT.equals(operator)) {
return getAsmConstant(program, operand, Operator.PLUS.getPrecedence(), codeScope) + "-1";
} else {
return operator.getOperator() +
getAsmConstant(program, operand, operator.getPrecedence(), codeScope);
}
}
public static String getAsmNumber(Number number) {
if (number instanceof Integer) {
if (number.intValue() >= 0 && number.intValue() <= 9) {
return String.format("%d", number.intValue());
} else {
return String.format("$%x", number);
}
}
throw new RuntimeException("Unsupported number type " + number);
}
public static String getAsmNumber(Number number) {
if(number instanceof Integer) {
if(number.intValue() >= 0 && number.intValue() <= 9) {
return String.format("%d", number.intValue());
} else {
return String.format("$%x", number);
}
}
throw new RuntimeException("Unsupported number type " + number);
}
/**
* Get the ASM parameter for a specific bound constant/ variable
*
* @param varScopeRef The scope containing the var/const
* @param asmName The ASM name of the variable (local name or specific ASM name).
* @param codeScopeRef The scope containing the code being generated. Used for adding scope to the name when needed (eg. line.x1 when referencing x1 variable inside line scope from outside line scope).
* @return The ASM parameter to use in the ASM code
*/
static String getAsmParamName(ScopeRef varScopeRef, String asmName, ScopeRef codeScopeRef) {
if (!varScopeRef.equals(codeScopeRef) && varScopeRef.getFullName().length() > 0) {
String param = varScopeRef.getFullName() + "." + asmName
.replace('@', 'b')
.replace(':', '_')
.replace("#", "_")
.replace("$", "_");
//param = ""+((Registers.RegisterZp) register).getZp();
return param;
} else {
String param = asmName.replace('@', 'b').replace(':', '_').replace("#", "_").replace("$", "_");
//param = ""+((Registers.RegisterZp) register).getZp();
return param;
}
}
/**
* Get the ASM parameter for a specific bound constant/ variable
*
* @param varScopeRef The scope containing the var/const
* @param asmName The ASM name of the variable (local name or specific ASM name).
* @param codeScopeRef The scope containing the code being generated. Used for adding scope to the name when needed (eg. line.x1 when referencing x1 variable inside line scope from outside line scope).
* @return The ASM parameter to use in the ASM code
*/
static String getAsmParamName(ScopeRef varScopeRef, String asmName, ScopeRef codeScopeRef) {
if(!varScopeRef.equals(codeScopeRef) && varScopeRef.getFullName().length() > 0) {
String param = varScopeRef.getFullName() + "." + asmName
.replace('@', 'b')
.replace(':', '_')
.replace("#", "_")
.replace("$", "_");
//param = ""+((Registers.RegisterZp) register).getZp();
return param;
} else {
String param = asmName.replace('@', 'b').replace(':', '_').replace("#", "_").replace("$", "_");
//param = ""+((Registers.RegisterZp) register).getZp();
return param;
}
}
/**
* Get the ASM parameter for a specific bound variable
*
* @param boundVar The variable
* @return The ASM parameter to use in the ASM code
*/
static String getAsmParamName(Variable boundVar, ScopeRef codeScopeRef) {
ScopeRef varScopeRef = boundVar.getScope().getRef();
String asmName = boundVar.getAsmName() == null ? boundVar.getLocalName() : boundVar.getAsmName();
return getAsmParamName(varScopeRef, asmName, codeScopeRef);
}
/**
* Get the ASM parameter for a specific bound variable
*
* @param boundVar The variable
* @return The ASM parameter to use in the ASM code
*/
static String getAsmParamName(Variable boundVar, ScopeRef codeScopeRef) {
ScopeRef varScopeRef = boundVar.getScope().getRef();
String asmName = boundVar.getAsmName() == null ? boundVar.getLocalName() : boundVar.getAsmName();
return getAsmParamName(varScopeRef, asmName, codeScopeRef);
}
/**
* Get the ASM parameter for a specific bound constant
*
* @param boundVar The constant
* @return The ASM parameter to use in the ASM code
*/
private static String getAsmParamName(ConstantVar boundVar, ScopeRef codeScopeRef) {
ScopeRef varScopeRef = boundVar.getScope().getRef();
String asmName = boundVar.getAsmName() == null ? boundVar.getLocalName() : boundVar.getAsmName();
return getAsmParamName(varScopeRef, asmName, codeScopeRef);
}
/**
* Get the ASM parameter for a specific bound constant
*
* @param boundVar The constant
* @return The ASM parameter to use in the ASM code
*/
private static String getAsmParamName(ConstantVar boundVar, ScopeRef codeScopeRef) {
ScopeRef varScopeRef = boundVar.getScope().getRef();
String asmName = boundVar.getAsmName() == null ? boundVar.getLocalName() : boundVar.getAsmName();
return getAsmParamName(varScopeRef, asmName, codeScopeRef);
}
}

View File

@ -12,308 +12,308 @@ import java.util.Map;
/** ASM Code Fragment with register/variable bindings that can be used for generating ASM code for a specific statement . */
public class AsmFragment {
/** The symbol table. */
private Program program;
/** The symbol table. */
private Program program;
/** The name of the fragment used in error messages. */
private String name;
/** The name of the fragment used in error messages. */
private String name;
/** The fragment template for the ASM code. */
private AsmFragmentTemplate fragmentTemplate;
/** The fragment template for the ASM code. */
private AsmFragmentTemplate fragmentTemplate;
/** Binding of named values in the fragment to values (constants, variables, ...) . */
private Map<String, Value> bindings;
/** Binding of named values in the fragment to values (constants, variables, ...) . */
private Map<String, Value> bindings;
/** The scope containing the fragment. Used when referencing symbols defined in other scopes. */
private ScopeRef codeScopeRef;
/** The scope containing the fragment. Used when referencing symbols defined in other scopes. */
private ScopeRef codeScopeRef;
public AsmFragment(
Program program,
String name,
ScopeRef codeScopeRef,
AsmFragmentTemplate fragmentTemplate,
Map<String, Value> bindings) {
this.program = program;
this.name = name;
this.fragmentTemplate = fragmentTemplate;
this.bindings = bindings;
this.codeScopeRef = codeScopeRef;
}
public AsmFragment(
Program program,
String name,
ScopeRef codeScopeRef,
AsmFragmentTemplate fragmentTemplate,
Map<String, Value> bindings) {
this.program = program;
this.name = name;
this.fragmentTemplate = fragmentTemplate;
this.bindings = bindings;
this.codeScopeRef = codeScopeRef;
}
public Value getBinding(String name) {
return bindings.get(name);
}
public Value getBinding(String name) {
return bindings.get(name);
}
/**
* Get the value to replace a bound name with from the fragment signature
*
* @param name The name of the bound value in the fragment
* @return The bound value to use in the generated ASM code
*/
public AsmParameter getBoundValue(String name) {
Value boundValue = null;
if (name.length() == 2) {
// Short name!
for (String boundName : bindings.keySet()) {
if (boundName.substring(boundName.length() - 2).equals(name)) {
boundValue = getBinding(boundName);
break;
}
/**
* Get the value to replace a bound name with from the fragment signature
*
* @param name The name of the bound value in the fragment
* @return The bound value to use in the generated ASM code
*/
public AsmParameter getBoundValue(String name) {
Value boundValue = null;
if(name.length() == 2) {
// Short name!
for(String boundName : bindings.keySet()) {
if(boundName.substring(boundName.length() - 2).equals(name)) {
boundValue = getBinding(boundName);
break;
}
} else {
// Long name
boundValue = getBinding(name);
}
}
} else {
// Long name
boundValue = getBinding(name);
}
if (boundValue == null) {
throw new RuntimeException("Binding '" + name + "' not found in fragment " + this.name + ".asm");
}
if (boundValue instanceof Variable) {
Variable boundVar = (Variable) boundValue;
Registers.Register register = boundVar.getAllocation();
if (register != null && register instanceof Registers.RegisterZp) {
return new AsmParameter(AsmFormat.getAsmParamName(boundVar, codeScopeRef), true);
} else {
throw new RuntimeException("Register Type not implemented " + register);
}
} else if (boundValue instanceof ConstantVar) {
ConstantVar constantVar = (ConstantVar) boundValue;
String constantValueAsm = AsmFormat.getAsmConstant(program, constantVar.getRef(), 99, codeScopeRef);
boolean constantValueZp = SymbolType.BYTE.equals(constantVar.getType(program.getScope()));
return new AsmParameter(constantValueAsm, constantValueZp);
} else if (boundValue instanceof ConstantValue) {
ConstantValue boundConst = (ConstantValue) boundValue;
String constantValueAsm = AsmFormat.getAsmConstant(program, boundConst, 99, codeScopeRef);
boolean constantValueZp = SymbolType.BYTE.equals(boundConst.getType(program.getScope()));
return new AsmParameter(constantValueAsm, constantValueZp);
} else if (boundValue instanceof Label) {
String param = ((Label) boundValue).getLocalName().replace('@', 'b').replace(':', '_').replace("$", "_");
return new AsmParameter(param, false);
} else {
throw new RuntimeException("Bound Value Type not implemented " + boundValue);
}
}
if(boundValue == null) {
throw new RuntimeException("Binding '" + name + "' not found in fragment " + this.name + ".asm");
}
if(boundValue instanceof Variable) {
Variable boundVar = (Variable) boundValue;
Registers.Register register = boundVar.getAllocation();
if(register != null && register instanceof Registers.RegisterZp) {
return new AsmParameter(AsmFormat.getAsmParamName(boundVar, codeScopeRef), true);
} else {
throw new RuntimeException("Register Type not implemented " + register);
}
} else if(boundValue instanceof ConstantVar) {
ConstantVar constantVar = (ConstantVar) boundValue;
String constantValueAsm = AsmFormat.getAsmConstant(program, constantVar.getRef(), 99, codeScopeRef);
boolean constantValueZp = SymbolType.BYTE.equals(constantVar.getType(program.getScope()));
return new AsmParameter(constantValueAsm, constantValueZp);
} else if(boundValue instanceof ConstantValue) {
ConstantValue boundConst = (ConstantValue) boundValue;
String constantValueAsm = AsmFormat.getAsmConstant(program, boundConst, 99, codeScopeRef);
boolean constantValueZp = SymbolType.BYTE.equals(boundConst.getType(program.getScope()));
return new AsmParameter(constantValueAsm, constantValueZp);
} else if(boundValue instanceof Label) {
String param = ((Label) boundValue).getLocalName().replace('@', 'b').replace(':', '_').replace("$", "_");
return new AsmParameter(param, false);
} else {
throw new RuntimeException("Bound Value Type not implemented " + boundValue);
}
}
public String getFragmentName() {
return name;
}
public String getFragmentName() {
return name;
}
/**
* A parameter of an ASM instruction from a bound value.
*/
public static class AsmParameter {
/**
* Generate assembler code for the assembler fragment.
*
* @param asm The assembler sequence to generate into.
*/
public void generate(AsmProgram asm) {
AsmSequenceGenerator asmSequenceGenerator = new AsmSequenceGenerator(name, this, asm);
asmSequenceGenerator.generate(fragmentTemplate.getBodyAsm());
}
private String param;
private boolean zp;
/**
* A parameter of an ASM instruction from a bound value.
*/
public static class AsmParameter {
public AsmParameter(String param, boolean zp) {
this.param = param;
this.zp = zp;
}
private String param;
private boolean zp;
public String getParam() {
return param;
}
public AsmParameter(String param, boolean zp) {
this.param = param;
this.zp = zp;
}
public boolean isZp() {
return zp;
}
}
public String getParam() {
return param;
}
/**
* Generate assembler code for the assembler fragment.
*
* @param asm The assembler sequence to generate into.
*/
public void generate(AsmProgram asm) {
AsmSequenceGenerator asmSequenceGenerator = new AsmSequenceGenerator(name, this, asm);
asmSequenceGenerator.generate(fragmentTemplate.getBodyAsm());
}
public boolean isZp() {
return zp;
}
}
private static class AsmSequenceGenerator extends KickCBaseVisitor {
private static class AsmSequenceGenerator extends KickCBaseVisitor {
private String name;
private AsmProgram program;
private AsmFragment bindings;
private String name;
private AsmProgram program;
private AsmFragment bindings;
public AsmSequenceGenerator(String name, AsmFragment bindings, AsmProgram program) {
this.name = name;
this.bindings = bindings;
this.program = program;
}
public AsmSequenceGenerator(String name, AsmFragment bindings, AsmProgram program) {
this.name = name;
this.bindings = bindings;
this.program = program;
}
public AsmProgram getProgram() {
return program;
}
public AsmProgram getProgram() {
return program;
}
public void generate(KickCParser.AsmLinesContext context) {
this.visit(context);
}
public void generate(KickCParser.AsmLinesContext context) {
this.visit(context);
}
@Override
public Object visitAsmLabel(KickCParser.AsmLabelContext ctx) {
program.addLine(new AsmLabel(ctx.getChild(0).getText()));
return null;
}
@Override
public Object visitAsmLabel(KickCParser.AsmLabelContext ctx) {
program.addLine(new AsmLabel(ctx.getChild(0).getText()));
return null;
}
@Override
public Object visitAsmBytes(KickCParser.AsmBytesContext ctx) {
ArrayList<String> values = new ArrayList<>();
for (int i = 1; i < ctx.getChildCount(); i = i + 2) {
values.add(ctx.getChild(i).getText());
}
program.addLine(new AsmDataNumeric(null, AsmDataNumeric.Type.BYTE, values));
return null;
}
@Override
public Object visitAsmBytes(KickCParser.AsmBytesContext ctx) {
ArrayList<String> values = new ArrayList<>();
for(int i = 1; i < ctx.getChildCount(); i = i + 2) {
values.add(ctx.getChild(i).getText());
}
program.addLine(new AsmDataNumeric(null, AsmDataNumeric.Type.BYTE, values));
return null;
}
@Override
public Object visitAsmInstruction(KickCParser.AsmInstructionContext ctx) {
KickCParser.AsmParamModeContext paramModeCtx = ctx.asmParamMode();
AsmInstruction instruction;
if (paramModeCtx == null) {
AsmInstructionType type = AsmInstructionSet.getInstructionType(
ctx.MNEMONIC().getText(),
AsmAddressingMode.NON,
false);
instruction = new AsmInstruction(type, null);
} else {
instruction = (AsmInstruction) this.visit(paramModeCtx);
}
if (instruction != null) {
program.addLine(instruction);
} else {
throw new RuntimeException("Error parsing ASM fragment line in dk/camelot64/kickc/fragment/asm/" + name + ".asm\n - Line: " + ctx.getText());
}
return null;
}
@Override
public Object visitAsmModeAbs(KickCParser.AsmModeAbsContext ctx) {
return createAsmInstruction(ctx, ctx.asmExpr(), AsmAddressingMode.ABS);
}
@Override
public Object visitAsmModeImm(KickCParser.AsmModeImmContext ctx) {
return createAsmInstruction(ctx, ctx.asmExpr(), AsmAddressingMode.IMM);
}
@Override
public Object visitAsmModeAbsXY(KickCParser.AsmModeAbsXYContext ctx) {
String xy = ctx.getChild(ctx.getChildCount() - 1).getText();
if (xy.equals("x")) {
return createAsmInstruction(ctx, ctx.asmExpr(), AsmAddressingMode.ABX);
} else if (xy.equals("y")) {
return createAsmInstruction(ctx, ctx.asmExpr(), AsmAddressingMode.ABY);
} else {
throw new RuntimeException("Unknown addressing mode " + ctx.getText());
}
}
@Override
public Object visitAsmModeIndIdxXY(KickCParser.AsmModeIndIdxXYContext ctx) {
String xy = ctx.getChild(ctx.getChildCount() - 1).getText();
if (xy.equals("y")) {
return createAsmInstruction(ctx, ctx.asmExpr(), AsmAddressingMode.IZY);
} else {
throw new RuntimeException("Unknown addressing mode " + ctx.getText());
}
}
@Override
public Object visitAsmModeIdxIndXY(KickCParser.AsmModeIdxIndXYContext ctx) {
String xy = ctx.getChild(ctx.getChildCount() - 1).getText();
if (xy.equals("x")) {
return createAsmInstruction(ctx, ctx.asmExpr(), AsmAddressingMode.IZX);
} else {
throw new RuntimeException("Unknown addressing mode " + ctx.getText());
}
}
@Override
public Object visitAsmModeInd(KickCParser.AsmModeIndContext ctx) {
return createAsmInstruction(ctx, ctx.asmExpr(), AsmAddressingMode.IND);
}
private AsmInstruction createAsmInstruction(
KickCParser.AsmParamModeContext ctx,
KickCParser.AsmExprContext exprCtx,
AsmAddressingMode addressingMode) {
KickCParser.AsmInstructionContext instructionCtx = (KickCParser.AsmInstructionContext) ctx.getParent();
String mnemonic = instructionCtx.MNEMONIC().getSymbol().getText();
AsmParameter parameter = (AsmParameter) this.visit(exprCtx);
@Override
public Object visitAsmInstruction(KickCParser.AsmInstructionContext ctx) {
KickCParser.AsmParamModeContext paramModeCtx = ctx.asmParamMode();
AsmInstruction instruction;
if(paramModeCtx == null) {
AsmInstructionType type = AsmInstructionSet.getInstructionType(
mnemonic,
addressingMode,
parameter.isZp());
if (type == null) {
throw new RuntimeException("Error in " + name + ".asm line " + ctx.getStart().getLine() + " - Instruction type unknown " + mnemonic + " " + addressingMode + " " + parameter);
}
return new AsmInstruction(type, parameter.getParam());
}
ctx.MNEMONIC().getText(),
AsmAddressingMode.NON,
false);
instruction = new AsmInstruction(type, null);
} else {
instruction = (AsmInstruction) this.visit(paramModeCtx);
}
if(instruction != null) {
program.addLine(instruction);
} else {
throw new RuntimeException("Error parsing ASM fragment line in dk/camelot64/kickc/fragment/asm/" + name + ".asm\n - Line: " + ctx.getText());
}
return null;
}
@Override
public AsmParameter visitAsmExprBinary(KickCParser.AsmExprBinaryContext ctx) {
AsmParameter left = (AsmParameter) this.visit(ctx.asmExpr(0));
AsmParameter right = (AsmParameter) this.visit(ctx.asmExpr(1));
String param = "" + left.getParam() + ctx.getChild(1).getText() + right.getParam();
boolean zp = left.isZp() && right.isZp();
return new AsmParameter(param, zp);
}
@Override
public Object visitAsmModeAbs(KickCParser.AsmModeAbsContext ctx) {
return createAsmInstruction(ctx, ctx.asmExpr(), AsmAddressingMode.ABS);
}
@Override
public AsmParameter visitAsmExprUnary(KickCParser.AsmExprUnaryContext ctx) {
AsmParameter sub = (AsmParameter) this.visit(ctx.asmExpr());
String operator = ctx.getChild(0).getText();
String param = operator + sub.getParam();
boolean isZp = sub.isZp();
if (operator.equals("<") || operator.equals(">")) {
isZp = true;
}
return new AsmParameter(param, isZp);
}
@Override
public Object visitAsmModeImm(KickCParser.AsmModeImmContext ctx) {
return createAsmInstruction(ctx, ctx.asmExpr(), AsmAddressingMode.IMM);
}
@Override
public AsmParameter visitAsmExprInt(KickCParser.AsmExprIntContext ctx) {
Number number = NumberParser.parseLiteral(ctx.NUMBER().getText());
ConstantInteger intVal = new ConstantInteger(number.intValue());
boolean isZp = SymbolType.isByte(intVal.getType()) || SymbolType.isSByte(intVal.getType());
String param = AsmFormat.getAsmNumber(number);
return new AsmParameter(param, isZp);
}
@Override
public Object visitAsmModeAbsXY(KickCParser.AsmModeAbsXYContext ctx) {
String xy = ctx.getChild(ctx.getChildCount() - 1).getText();
if(xy.equals("x")) {
return createAsmInstruction(ctx, ctx.asmExpr(), AsmAddressingMode.ABX);
} else if(xy.equals("y")) {
return createAsmInstruction(ctx, ctx.asmExpr(), AsmAddressingMode.ABY);
} else {
throw new RuntimeException("Unknown addressing mode " + ctx.getText());
}
}
@Override
public Object visitAsmExprChar(KickCParser.AsmExprCharContext ctx) {
return new AsmParameter(ctx.getText(), true);
}
@Override
public Object visitAsmModeIndIdxXY(KickCParser.AsmModeIndIdxXYContext ctx) {
String xy = ctx.getChild(ctx.getChildCount() - 1).getText();
if(xy.equals("y")) {
return createAsmInstruction(ctx, ctx.asmExpr(), AsmAddressingMode.IZY);
} else {
throw new RuntimeException("Unknown addressing mode " + ctx.getText());
}
}
@Override
public AsmParameter visitAsmExprLabel(KickCParser.AsmExprLabelContext ctx) {
String param = ctx.NAME().getSymbol().getText();
return new AsmParameter(param, false);
}
@Override
public Object visitAsmModeIdxIndXY(KickCParser.AsmModeIdxIndXYContext ctx) {
String xy = ctx.getChild(ctx.getChildCount() - 1).getText();
if(xy.equals("x")) {
return createAsmInstruction(ctx, ctx.asmExpr(), AsmAddressingMode.IZX);
} else {
throw new RuntimeException("Unknown addressing mode " + ctx.getText());
}
}
@Override
public Object visitAsmExprLabelRel(KickCParser.AsmExprLabelRelContext ctx) {
String param = ctx.ASMREL().getSymbol().getText();
return new AsmParameter(param, false);
}
@Override
public Object visitAsmModeInd(KickCParser.AsmModeIndContext ctx) {
return createAsmInstruction(ctx, ctx.asmExpr(), AsmAddressingMode.IND);
}
@Override
public AsmParameter visitAsmExprReplace(KickCParser.AsmExprReplaceContext ctx) {
String replaceName = ctx.NAME().getSymbol().getText();
return bindings.getBoundValue(replaceName);
}
}
private AsmInstruction createAsmInstruction(
KickCParser.AsmParamModeContext ctx,
KickCParser.AsmExprContext exprCtx,
AsmAddressingMode addressingMode) {
KickCParser.AsmInstructionContext instructionCtx = (KickCParser.AsmInstructionContext) ctx.getParent();
String mnemonic = instructionCtx.MNEMONIC().getSymbol().getText();
AsmParameter parameter = (AsmParameter) this.visit(exprCtx);
AsmInstructionType type = AsmInstructionSet.getInstructionType(
mnemonic,
addressingMode,
parameter.isZp());
if(type == null) {
throw new RuntimeException("Error in " + name + ".asm line " + ctx.getStart().getLine() + " - Instruction type unknown " + mnemonic + " " + addressingMode + " " + parameter);
}
return new AsmInstruction(type, parameter.getParam());
}
public static class AluNotApplicableException extends RuntimeException {
@Override
public AsmParameter visitAsmExprBinary(KickCParser.AsmExprBinaryContext ctx) {
AsmParameter left = (AsmParameter) this.visit(ctx.asmExpr(0));
AsmParameter right = (AsmParameter) this.visit(ctx.asmExpr(1));
String param = "" + left.getParam() + ctx.getChild(1).getText() + right.getParam();
boolean zp = left.isZp() && right.isZp();
return new AsmParameter(param, zp);
}
public AluNotApplicableException() {
super("ALU register not appicable.");
}
@Override
public AsmParameter visitAsmExprUnary(KickCParser.AsmExprUnaryContext ctx) {
AsmParameter sub = (AsmParameter) this.visit(ctx.asmExpr());
String operator = ctx.getChild(0).getText();
String param = operator + sub.getParam();
boolean isZp = sub.isZp();
if(operator.equals("<") || operator.equals(">")) {
isZp = true;
}
return new AsmParameter(param, isZp);
}
public AluNotApplicableException(String message) {
super(message);
}
}
@Override
public AsmParameter visitAsmExprInt(KickCParser.AsmExprIntContext ctx) {
Number number = NumberParser.parseLiteral(ctx.NUMBER().getText());
ConstantInteger intVal = new ConstantInteger(number.intValue());
boolean isZp = SymbolType.isByte(intVal.getType()) || SymbolType.isSByte(intVal.getType());
String param = AsmFormat.getAsmNumber(number);
return new AsmParameter(param, isZp);
}
@Override
public Object visitAsmExprChar(KickCParser.AsmExprCharContext ctx) {
return new AsmParameter(ctx.getText(), true);
}
@Override
public AsmParameter visitAsmExprLabel(KickCParser.AsmExprLabelContext ctx) {
String param = ctx.NAME().getSymbol().getText();
return new AsmParameter(param, false);
}
@Override
public Object visitAsmExprLabelRel(KickCParser.AsmExprLabelRelContext ctx) {
String param = ctx.ASMREL().getSymbol().getText();
return new AsmParameter(param, false);
}
@Override
public AsmParameter visitAsmExprReplace(KickCParser.AsmExprReplaceContext ctx) {
String replaceName = ctx.NAME().getSymbol().getText();
return bindings.getBoundValue(replaceName);
}
}
public static class AluNotApplicableException extends RuntimeException {
public AluNotApplicableException() {
super("ALU register not appicable.");
}
public AluNotApplicableException(String message) {
super(message);
}
}
}

View File

@ -29,6 +29,13 @@ public class AsmFragmentSignature {
* The scope containing the fragment. Used when referencing symbols defined in other scopes.
*/
private ScopeRef codeScopeRef;
/**
* Zero page register name indexing.
*/
private int nextZpByteIdx = 1;
private int nextZpBoolIdx = 1;
private int nextConstByteIdx = 1;
private int nextLabelIdx = 1;
public AsmFragmentSignature(
StatementConditionalJump conditionalJump,
@ -67,25 +74,29 @@ public class AsmFragmentSignature {
setSignature(assignmentWithAluSignature(assignment, assignmentAlu));
}
private static String getOperatorFragmentName(Operator operator) {
return operator.getAsmOperator();
}
private String assignmentWithAluSignature(StatementAssignment assignment, StatementAssignment assignmentAlu) {
this.codeScopeRef = program.getStatementInfos().getBlock(assignment).getScope();
if (!(assignment.getrValue2() instanceof VariableRef)) {
if(!(assignment.getrValue2() instanceof VariableRef)) {
throw new AsmFragment.AluNotApplicableException("Error! ALU register only allowed as rValue2. " + assignment);
}
VariableRef assignmentRValue2 = (VariableRef) assignment.getrValue2();
Variable assignmentRValue2Var = program.getSymbolInfos().getVariable(assignmentRValue2);
Registers.Register rVal2Register = assignmentRValue2Var.getAllocation();
if (!rVal2Register.getType().equals(Registers.RegisterType.REG_ALU)) {
if(!rVal2Register.getType().equals(Registers.RegisterType.REG_ALU)) {
throw new AsmFragment.AluNotApplicableException("Error! ALU register only allowed as rValue2. " + assignment);
}
StringBuilder signature = new StringBuilder();
signature.append(bind(assignment.getlValue()));
signature.append("=");
if (assignment.getrValue1() != null) {
if(assignment.getrValue1() != null) {
signature.append(bind(assignment.getrValue1()));
}
if (assignment.getOperator() != null) {
if(assignment.getOperator() != null) {
signature.append(getOperatorFragmentName(assignment.getOperator()));
}
signature.append(assignmentRightSideSignature(
@ -105,25 +116,25 @@ public class AsmFragmentSignature {
private String assignmentRightSideSignature(RValue rValue1, Operator operator, RValue rValue2) {
StringBuilder signature = new StringBuilder();
if (rValue1 != null) {
if(rValue1 != null) {
signature.append(bind(rValue1));
}
if (operator != null) {
if(operator != null) {
signature.append(getOperatorFragmentName(operator));
}
if (
if(
rValue2 instanceof ConstantInteger &&
((ConstantInteger) rValue2).getNumber() == 1 &&
operator != null &&
(operator.getOperator().equals("-") || operator.getOperator().equals("+"))) {
signature.append("1");
} else if (
} else if(
rValue2 instanceof ConstantInteger &&
((ConstantInteger) rValue2).getNumber() <= 7 &&
operator != null &&
(operator.getOperator().equals(">>") || operator.getOperator().equals("<<"))) {
signature.append(((ConstantInteger) rValue2).getNumber());
} else if (
} else if(
rValue2 instanceof ConstantInteger &&
((ConstantInteger) rValue2).getNumber() == 0 &&
operator != null &&
@ -140,15 +151,15 @@ public class AsmFragmentSignature {
ControlFlowBlock block,
ControlFlowGraph graph) {
StringBuilder signature = new StringBuilder();
if (conditionalJump.getrValue1() != null) {
if(conditionalJump.getrValue1() != null) {
signature.append(bind(conditionalJump.getrValue1()));
}
if (conditionalJump.getOperator() != null) {
if(conditionalJump.getOperator() != null) {
signature.append(getOperatorFragmentName(conditionalJump.getOperator()));
}
if (conditionalJump.getrValue2() instanceof ConstantInteger && ((ConstantInteger) conditionalJump.getrValue2()).getNumber() == 0) {
if(conditionalJump.getrValue2() instanceof ConstantInteger && ((ConstantInteger) conditionalJump.getrValue2()).getNumber() == 0) {
signature.append("0");
} else if (conditionalJump.getrValue2() instanceof ConstantBool) {
} else if(conditionalJump.getrValue2() instanceof ConstantBool) {
ConstantBool boolValue = (ConstantBool) conditionalJump.getrValue2();
signature.append(boolValue.toString());
} else {
@ -158,7 +169,7 @@ public class AsmFragmentSignature {
LabelRef destination = conditionalJump.getDestination();
ControlFlowBlock destinationBlock = graph.getBlock(destination);
String destinationLabel;
if (destinationBlock.hasPhiBlock()) {
if(destinationBlock.hasPhiBlock()) {
destinationLabel =
(destinationBlock.getLabel().getLocalName() +
"_from_" +
@ -171,10 +182,6 @@ public class AsmFragmentSignature {
return signature.toString();
}
private static String getOperatorFragmentName(Operator operator) {
return operator.getAsmOperator();
}
public String getSignature() {
return signature;
}
@ -183,14 +190,6 @@ public class AsmFragmentSignature {
this.signature = signature;
}
/**
* Zero page register name indexing.
*/
private int nextZpByteIdx = 1;
private int nextZpBoolIdx = 1;
private int nextConstByteIdx = 1;
private int nextLabelIdx = 1;
/**
* Add bindings of a value.
*
@ -198,39 +197,39 @@ public class AsmFragmentSignature {
* @return The bound name of the value. If the value has already been bound the existing bound name is returned.
*/
public String bind(Value value) {
if (value instanceof PointerDereferenceSimple) {
if(value instanceof PointerDereferenceSimple) {
PointerDereferenceSimple deref = (PointerDereferenceSimple) value;
return "_deref_" + bind(deref.getPointer());
} else if (value instanceof PointerDereferenceIndexed) {
} else if(value instanceof PointerDereferenceIndexed) {
PointerDereferenceIndexed deref = (PointerDereferenceIndexed) value;
return bind(deref.getPointer()) + "_derefidx_" + bind(deref.getIndex());
}
if (value instanceof VariableRef) {
if(value instanceof VariableRef) {
value = program.getSymbolInfos().getVariable((VariableRef) value);
}
if (value instanceof ConstantRef) {
if(value instanceof ConstantRef) {
value = program.getScope().getConstant((ConstantRef) value);
}
// Find value if it is already bound
for (String name : bindings.keySet()) {
for(String name : bindings.keySet()) {
Value bound = bindings.get(name);
if (bound.equals(value)) {
if(bound.equals(value)) {
return name;
}
}
if (value instanceof Variable) {
if(value instanceof Variable) {
Variable variable = (Variable) value;
Registers.Register register = variable.getAllocation();
// Find value if it is already bound
for (String name : bindings.keySet()) {
for(String name : bindings.keySet()) {
Value bound = bindings.get(name);
if (bound instanceof Variable) {
if(bound instanceof Variable) {
Registers.Register boundRegister = ((Variable) bound).getAllocation();
if (boundRegister != null && boundRegister.equals(register)) {
if (SymbolTypeInference.typeMatch(((Variable) bound).getType(), variable.getType())) {
if(boundRegister != null && boundRegister.equals(register)) {
if(SymbolTypeInference.typeMatch(((Variable) bound).getType(), variable.getType())) {
return name;
}
}
@ -240,9 +239,9 @@ public class AsmFragmentSignature {
String name = getTypePrefix(varType) + getRegisterName(register);
bindings.put(name, value);
return name;
} else if (value instanceof ConstantVar || value instanceof ConstantValue) {
} else if(value instanceof ConstantVar || value instanceof ConstantValue) {
SymbolType constType;
if (value instanceof ConstantVar) {
if(value instanceof ConstantVar) {
constType = ((ConstantVar) value).getType();
} else {
constType = SymbolTypeInference.inferType(program.getScope(), (ConstantValue) value);
@ -250,7 +249,7 @@ public class AsmFragmentSignature {
String name = getTypePrefix(constType) + "c" + nextConstByteIdx++;
bindings.put(name, value);
return name;
} else if (value instanceof Label) {
} else if(value instanceof Label) {
String name = "la" + nextLabelIdx++;
bindings.put(name, value);
return name;
@ -260,27 +259,28 @@ public class AsmFragmentSignature {
/**
* Get the symbol type part of the binding name (eg. vbu/pws/...)
*
* @param type The type
* @return The type name
*/
private String getTypePrefix(SymbolType type) {
if (SymbolType.isByte(type)) {
if(SymbolType.isByte(type)) {
return "vbu";
} else if (SymbolType.isSByte(type)) {
} else if(SymbolType.isSByte(type)) {
return "vbs";
} else if (SymbolType.isWord(type)) {
} else if(SymbolType.isWord(type)) {
return "vwu";
} else if (SymbolType.isSWord(type)) {
} else if(SymbolType.isSWord(type)) {
return "vws";
} else if (SymbolType.STRING.equals(type)) {
} else if(SymbolType.STRING.equals(type)) {
return "pbu";
} else if (type instanceof SymbolTypePointer) {
} else if(type instanceof SymbolTypePointer) {
SymbolType elementType = ((SymbolTypePointer) type).getElementType();
if (SymbolType.isByte(elementType)) {
if(SymbolType.isByte(elementType)) {
return "pbu";
} else if (SymbolType.isSByte(elementType)) {
} else if(SymbolType.isSByte(elementType)) {
return "pbs";
} else if (SymbolType.isWord(elementType)) {
} else if(SymbolType.isWord(elementType)) {
return "pwu";
} else {
throw new RuntimeException("Not implemented " + type);
@ -293,21 +293,22 @@ public class AsmFragmentSignature {
/**
* Get the register part of the binding name (eg. aa, z1, c2, ...).
* Examines all previous bindings to reuse register index if the same register is bound multiple times.
*
* @param register The register
* @return The register part of the binding name.
*/
private String getRegisterName(Registers.Register register) {
if (Registers.RegisterType.ZP_BYTE.equals(register.getType())) {
if(Registers.RegisterType.ZP_BYTE.equals(register.getType())) {
return "z" + getRegisterZpNameIdx((Registers.RegisterZp) register);
} else if (Registers.RegisterType.ZP_WORD.equals(register.getType())) {
} else if(Registers.RegisterType.ZP_WORD.equals(register.getType())) {
return "z" + getRegisterZpNameIdx((Registers.RegisterZp) register);
} else if (Registers.RegisterType.REG_A_BYTE.equals(register.getType())) {
} else if(Registers.RegisterType.REG_A_BYTE.equals(register.getType())) {
return "aa";
} else if (Registers.RegisterType.REG_X_BYTE.equals(register.getType())) {
} else if(Registers.RegisterType.REG_X_BYTE.equals(register.getType())) {
return "xx";
} else if (Registers.RegisterType.REG_Y_BYTE.equals(register.getType())) {
} else if(Registers.RegisterType.REG_Y_BYTE.equals(register.getType())) {
return "yy";
} else if (Registers.RegisterType.REG_ALU.equals(register.getType())) {
} else if(Registers.RegisterType.REG_ALU.equals(register.getType())) {
throw new AsmFragment.AluNotApplicableException();
} else {
throw new RuntimeException("Not implemented " + register.getType());
@ -317,17 +318,18 @@ public class AsmFragmentSignature {
/**
* Get the register ZP name index to use for a specific register.
* Examines all previous bindings to reuse register index if the same register is bound multiple times.
*
* @param register The register to find an index for
* @return The index. Either reused ot allocated from {@link #nextZpByteIdx}
*/
private String getRegisterZpNameIdx(Registers.RegisterZp register) {
for (String boundName : bindings.keySet()) {
for(String boundName : bindings.keySet()) {
Value boundValue = bindings.get(boundName);
if (boundValue instanceof Variable) {
if(boundValue instanceof Variable) {
Registers.Register boundRegister = ((Variable) boundValue).getAllocation();
if (boundRegister != null && boundRegister.isZp()) {
if(boundRegister != null && boundRegister.isZp()) {
Registers.RegisterZp boundRegisterZp = (Registers.RegisterZp) boundRegister;
if (register.getZp() == boundRegisterZp.getZp()) {
if(register.getZp() == boundRegisterZp.getZp()) {
// Found other register with same ZP address!
return boundName.substring(boundName.length() - 1);
}

View File

@ -10,94 +10,94 @@ import java.util.regex.Pattern;
/** AsmFragment synthesis mechanism based on matching fragment signature and reusing another fragment with added prefix/postfix and some bind-mappings */
class AsmFragmentSynthesis {
private String sigMatch;
private String sigAvoid;
private String asmPrefix;
private String sigReplace;
private String asmPostfix;
private Map<String, String> bindMappings;
private boolean mapSignature;
private String subSignature;
private String sigMatch;
private String sigAvoid;
private String asmPrefix;
private String sigReplace;
private String asmPostfix;
private Map<String, String> bindMappings;
private boolean mapSignature;
private String subSignature;
AsmFragmentSynthesis(String sigMatch, String sigAvoid, String asmPrefix, String sigReplace, String asmPostfix, Map<String, String> bindMappings, boolean mapSignature) {
this.sigMatch = sigMatch;
this.sigAvoid = sigAvoid;
this.asmPrefix = asmPrefix;
this.sigReplace = sigReplace;
this.asmPostfix = asmPostfix;
this.bindMappings = bindMappings;
this.mapSignature = mapSignature;
}
AsmFragmentSynthesis(String sigMatch, String sigAvoid, String asmPrefix, String sigReplace, String asmPostfix, Map<String, String> bindMappings, boolean mapSignature) {
this.sigMatch = sigMatch;
this.sigAvoid = sigAvoid;
this.asmPrefix = asmPrefix;
this.sigReplace = sigReplace;
this.asmPostfix = asmPostfix;
this.bindMappings = bindMappings;
this.mapSignature = mapSignature;
}
public AsmFragmentSynthesis(String sigMatch, String sigAvoid, String asmPrefix, String sigReplace, String asmPostfix, Map<String, String> bindMappings) {
this(sigMatch, sigAvoid, asmPrefix, sigReplace, asmPostfix, bindMappings, true);
}
public AsmFragmentSynthesis(String sigMatch, String sigAvoid, String asmPrefix, String sigReplace, String asmPostfix, Map<String, String> bindMappings) {
this(sigMatch, sigAvoid, asmPrefix, sigReplace, asmPostfix, bindMappings, true);
}
public String getName() {
return sigMatch + (sigAvoid == null ? "" : ("/" + sigAvoid));
}
static String regexpRewriteSignature(String signature, String match, String replace) {
Pattern p = Pattern.compile(match);
Matcher m = p.matcher(signature);
String output = signature;
if(m.find()) {
// getReplacement first number with "number" and second number with the first
output = m.replaceAll(replace);
}
return output;
}
public List<AsmFragmentTemplate> synthesize(String signature, AsmFragmentManager.AsmSynthesisPath path, AsmFragmentManager.AsmFragmentTemplateSynthesizer synthesizer) {
ArrayList<AsmFragmentTemplate> candidates = new ArrayList<>();
if (signature.matches(sigMatch)) {
if (sigAvoid == null || !signature.matches(sigAvoid)) {
subSignature = regexpRewriteSignature(signature, sigMatch, sigReplace);
if (mapSignature && bindMappings != null) {
// When mapping the signature we do the map replacement in the signature
for (String bound : bindMappings.keySet()) {
subSignature = subSignature.replace(bound, bindMappings.get(bound));
}
}
List<AsmFragmentTemplate> subFragmentTemplates = synthesizer.loadOrSynthesizeFragment(subSignature, path);
for (AsmFragmentTemplate subFragmentTemplate : subFragmentTemplates) {
if (subFragmentTemplate != null) {
StringBuilder newFragment = new StringBuilder();
if (asmPrefix != null) {
newFragment.append(asmPrefix).append("\n");
}
String subFragment = subFragmentTemplate.getBody();
if (bindMappings != null) {
if (mapSignature) {
// When mapping the signature we do the reverse replacement in the ASM
List<String> reverse = new ArrayList<>(bindMappings.keySet());
Collections.reverse(reverse);
for (String bound : reverse) {
subFragment = subFragment.replace("{" + bindMappings.get(bound) + "}", "{" + bound + "}");
}
} else {
// When not mapping the signature we do the replacement directly in the ASM
for (String bound : bindMappings.keySet()) {
subFragment = subFragment.replace("{" + bound + "}", "{" + bindMappings.get(bound) + "}");
}
}
}
newFragment.append(subFragment);
if (asmPostfix != null) {
newFragment.append("\n");
newFragment.append(asmPostfix);
}
candidates.add(new AsmFragmentTemplate(signature, newFragment.toString(), this, subFragmentTemplate));
}
}
public String getName() {
return sigMatch + (sigAvoid == null ? "" : ("/" + sigAvoid));
}
public List<AsmFragmentTemplate> synthesize(String signature, AsmFragmentManager.AsmSynthesisPath path, AsmFragmentManager.AsmFragmentTemplateSynthesizer synthesizer) {
ArrayList<AsmFragmentTemplate> candidates = new ArrayList<>();
if(signature.matches(sigMatch)) {
if(sigAvoid == null || !signature.matches(sigAvoid)) {
subSignature = regexpRewriteSignature(signature, sigMatch, sigReplace);
if(mapSignature && bindMappings != null) {
// When mapping the signature we do the map replacement in the signature
for(String bound : bindMappings.keySet()) {
subSignature = subSignature.replace(bound, bindMappings.get(bound));
}
}
}
return candidates;
}
List<AsmFragmentTemplate> subFragmentTemplates = synthesizer.loadOrSynthesizeFragment(subSignature, path);
for(AsmFragmentTemplate subFragmentTemplate : subFragmentTemplates) {
if(subFragmentTemplate != null) {
StringBuilder newFragment = new StringBuilder();
if(asmPrefix != null) {
newFragment.append(asmPrefix).append("\n");
}
String subFragment = subFragmentTemplate.getBody();
if(bindMappings != null) {
if(mapSignature) {
// When mapping the signature we do the reverse replacement in the ASM
List<String> reverse = new ArrayList<>(bindMappings.keySet());
Collections.reverse(reverse);
for(String bound : reverse) {
subFragment = subFragment.replace("{" + bindMappings.get(bound) + "}", "{" + bound + "}");
}
} else {
// When not mapping the signature we do the replacement directly in the ASM
for(String bound : bindMappings.keySet()) {
subFragment = subFragment.replace("{" + bound + "}", "{" + bindMappings.get(bound) + "}");
}
}
}
newFragment.append(subFragment);
if(asmPostfix != null) {
newFragment.append("\n");
newFragment.append(asmPostfix);
}
candidates.add(new AsmFragmentTemplate(signature, newFragment.toString(), this, subFragmentTemplate));
}
}
}
}
return candidates;
}
public String getSubSignature() {
return subSignature;
}
static String regexpRewriteSignature(String signature, String match, String replace) {
Pattern p = Pattern.compile(match);
Matcher m = p.matcher(signature);
String output = signature;
if (m.find()) {
// getReplacement first number with "number" and second number with the first
output = m.replaceAll(replace);
}
return output;
}
public String getSubSignature() {
return subSignature;
}
}

View File

@ -10,119 +10,114 @@ import org.antlr.v4.runtime.*;
*/
public class AsmFragmentTemplate {
/** The fragment template signature name. */
private String signature;
/** true if the fragment was loaded from disk. */
boolean file;
/** The fragment template signature name. */
private String signature;
/** The fragment template body */
private String body;
/** The parsed ASM lines. Initially null. Will be non-null, is the template is ever used to generate ASM code. */
private KickCParser.AsmLinesContext bodyAsm;
/** The synthesis that created the fragment. null if the fragment template was loaded. */
private AsmFragmentSynthesis synthesis;
/** The fragment template body */
private String body;
/** The sub fragment template that the synthesis modified to create this. null if the fragment template was loaded. */
private AsmFragmentTemplate subFragment;
/** The parsed ASM lines. Initially null. Will be non-null, is the template is ever used to generate ASM code. */
private KickCParser.AsmLinesContext bodyAsm;
public AsmFragmentTemplate(String signature, String body) {
this.signature = signature;
this.body = body;
this.file = true;
}
/** true if the fragment was loaded from disk. */
boolean file;
AsmFragmentTemplate(String signature, String body, AsmFragmentSynthesis synthesis, AsmFragmentTemplate subFragment) {
this.signature = signature;
this.body = body;
this.synthesis = synthesis;
this.subFragment = subFragment;
this.file = false;
}
/** The synthesis that created the fragment. null if the fragment template was loaded. */
private AsmFragmentSynthesis synthesis;
/**
* Creates an inline ASM fragment template
*
* @param bodyLines Parsed ASM body
*/
public AsmFragmentTemplate(KickCParser.AsmLinesContext bodyLines) {
this.signature = "--inline--";
this.bodyAsm = bodyLines;
}
/** The sub fragment template that the synthesis modified to create this. null if the fragment template was loaded. */
private AsmFragmentTemplate subFragment;
/**
* Parse an ASM fragment.
*
* @param fragmentBody The stream containing the fragment syntax
* @param fragmentFileName The filename (used in error messages)
* @return The parsed fragment ready for generating
*/
private static KickCParser.AsmLinesContext parseBody(String fragmentBody, final String fragmentFileName) {
CodePointCharStream fragmentCharStream = CharStreams.fromString(fragmentBody);
KickCLexer kickCLexer = new KickCLexer(fragmentCharStream);
KickCParser kickCParser = new KickCParser(new CommonTokenStream(kickCLexer));
kickCParser.addErrorListener(new BaseErrorListener() {
@Override
public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) {
throw new RuntimeException("Error parsing fragment " + fragmentFileName + "\n - Line: " + line + "\n - Message: " + msg);
}
});
kickCParser.setBuildParseTree(true);
KickCParser.AsmFileContext asmFile = kickCParser.asmFile();
return asmFile.asmLines();
}
public AsmFragmentTemplate(String signature, String body) {
this.signature = signature;
this.body = body;
this.file = true;
}
public String getSignature() {
return signature;
}
AsmFragmentTemplate(String signature, String body, AsmFragmentSynthesis synthesis, AsmFragmentTemplate subFragment) {
this.signature = signature;
this.body = body;
this.synthesis = synthesis;
this.subFragment = subFragment;
this.file = false;
}
public String getBody() {
return body;
}
/**
* Creates an inline ASM fragment template
*
* @param bodyLines Parsed ASM body
*/
public AsmFragmentTemplate(KickCParser.AsmLinesContext bodyLines) {
this.signature = "--inline--";
this.bodyAsm = bodyLines;
}
public KickCParser.AsmLinesContext getBodyAsm() {
if(bodyAsm == null) {
bodyAsm = parseBody(body, signature);
}
return bodyAsm;
}
public String getSignature() {
return signature;
}
public boolean isFile() {
return file;
}
public String getBody() {
return body;
}
public AsmFragmentSynthesis getSynthesis() {
return synthesis;
}
public KickCParser.AsmLinesContext getBodyAsm() {
if (bodyAsm == null) {
bodyAsm = parseBody(body, signature);
}
return bodyAsm;
}
public AsmFragmentTemplate getSubFragment() {
return subFragment;
}
/**
* Parse an ASM fragment.
*
* @param fragmentBody The stream containing the fragment syntax
* @param fragmentFileName The filename (used in error messages)
* @return The parsed fragment ready for generating
*/
private static KickCParser.AsmLinesContext parseBody(String fragmentBody, final String fragmentFileName) {
CodePointCharStream fragmentCharStream = CharStreams.fromString(fragmentBody);
KickCLexer kickCLexer = new KickCLexer(fragmentCharStream);
KickCParser kickCParser = new KickCParser(new CommonTokenStream(kickCLexer));
kickCParser.addErrorListener(new BaseErrorListener() {
@Override
public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) {
throw new RuntimeException("Error parsing fragment " + fragmentFileName + "\n - Line: " + line + "\n - Message: " + msg);
}
});
kickCParser.setBuildParseTree(true);
KickCParser.AsmFileContext asmFile = kickCParser.asmFile();
return asmFile.asmLines();
}
public String getName() {
StringBuilder name = new StringBuilder();
name.append(signature);
if(synthesis != null) {
name.append(" < ");
name.append(subFragment.getName());
}
return name.toString();
}
@Override
public boolean equals(Object o) {
if(this == o) return true;
if(o == null || getClass() != o.getClass()) return false;
AsmFragmentTemplate that = (AsmFragmentTemplate) o;
return getName().equals(that.getName());
}
public boolean isFile() {
return file;
}
public AsmFragmentSynthesis getSynthesis() {
return synthesis;
}
public AsmFragmentTemplate getSubFragment() {
return subFragment;
}
public String getName() {
StringBuilder name = new StringBuilder();
name.append(signature);
if (synthesis != null) {
name.append(" < ");
name.append(subFragment.getName());
}
return name.toString();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AsmFragmentTemplate that = (AsmFragmentTemplate) o;
return getName().equals(that.getName());
}
@Override
public int hashCode() {
return getName().hashCode();
}
@Override
public int hashCode() {
return getName().hashCode();
}
}

View File

@ -8,176 +8,176 @@ import java.util.*;
/** Statistics for usage of the ASM fragments. Also contains a methos for identifying redundant/unused files. */
public class AsmFragmentUsages {
/** Usage Statistics for fragment templates. */
private static Map<AsmFragmentTemplate, Integer> fragmentTemplateUsage = new HashMap<>();
/** Usage Statistics for fragment templates. */
private static Map<AsmFragmentTemplate, Integer> fragmentTemplateUsage = new HashMap<>();
/**
* Count one usage of ASM fragment templates - directly or through synthesis
*
* @param fragmentTemplate The template to increment usage of
*/
static void incUsage(AsmFragmentTemplate fragmentTemplate) {
Integer usage = fragmentTemplateUsage.get(fragmentTemplate);
if (usage == null) {
usage = 0;
}
fragmentTemplateUsage.put(fragmentTemplate, usage + 1);
AsmFragmentTemplate subFragment = fragmentTemplate.getSubFragment();
if (subFragment != null) {
incUsage(subFragment);
}
}
/**
* Count one usage of ASM fragment templates - directly or through synthesis
*
* @param fragmentTemplate The template to increment usage of
*/
static void incUsage(AsmFragmentTemplate fragmentTemplate) {
Integer usage = fragmentTemplateUsage.get(fragmentTemplate);
if(usage == null) {
usage = 0;
}
fragmentTemplateUsage.put(fragmentTemplate, usage + 1);
AsmFragmentTemplate subFragment = fragmentTemplate.getSubFragment();
if(subFragment != null) {
incUsage(subFragment);
}
}
/**
* Log the usage of all template fragemnts (both loaded and synthesized).
*
* @param log The compile log to add the output to
*/
public static void logUsages(CompileLog log, boolean logRedundantFiles, boolean logUnusedFiles, boolean logFileDetails, boolean logAllDetails) {
/**
* Log the usage of all template fragemnts (both loaded and synthesized).
*
* @param log The compile log to add the output to
*/
public static void logUsages(CompileLog log, boolean logRedundantFiles, boolean logUnusedFiles, boolean logFileDetails, boolean logAllDetails) {
Map<String, List<AsmFragmentTemplate>> fragmentTemplateCache = AsmFragmentManager.getFragmentTemplateCache();
ArrayList<String> signatures = new ArrayList<>(fragmentTemplateCache.keySet());
Collections.sort(signatures);
File[] files = AsmFragmentManager.allFragmentFiles();
Map<String, List<AsmFragmentTemplate>> fragmentTemplateCache = AsmFragmentManager.getFragmentTemplateCache();
ArrayList<String> signatures = new ArrayList<>(fragmentTemplateCache.keySet());
Collections.sort(signatures);
File[] files = AsmFragmentManager.allFragmentFiles();
if (logRedundantFiles) {
// Find all file fragments that were bested by a synthesized fragment
log.append("\nREDUNDANT ASM FRAGMENT FILE ANALYSIS (if found remove them from disk)");
for (String signature : signatures) {
List<AsmFragmentTemplate> templates = fragmentTemplateCache.get(signature);
AsmFragmentTemplate fileTemplate = null;
int fileUsage = 0;
AsmFragmentTemplate maxTemplate = null;
int maxUsage = 0;
for (AsmFragmentTemplate template : templates) {
Integer usage = fragmentTemplateUsage.get(template);
if (usage == null) usage = 0;
if (template.isFile()) {
fileTemplate = template;
fileUsage = usage;
}
if (usage > maxUsage) {
maxUsage = usage;
maxTemplate = template;
}
}
if (fileTemplate != null && fileUsage == 0 && maxUsage > 0) {
log.append("rm " + fileTemplate.getName() + ".asm #synthesized by " + maxTemplate.getName() + " - usages: " + maxUsage);
}
if(logRedundantFiles) {
// Find all file fragments that were bested by a synthesized fragment
log.append("\nREDUNDANT ASM FRAGMENT FILE ANALYSIS (if found remove them from disk)");
for(String signature : signatures) {
List<AsmFragmentTemplate> templates = fragmentTemplateCache.get(signature);
AsmFragmentTemplate fileTemplate = null;
int fileUsage = 0;
AsmFragmentTemplate maxTemplate = null;
int maxUsage = 0;
for(AsmFragmentTemplate template : templates) {
Integer usage = fragmentTemplateUsage.get(template);
if(usage == null) usage = 0;
if(template.isFile()) {
fileTemplate = template;
fileUsage = usage;
}
if(usage > maxUsage) {
maxUsage = usage;
maxTemplate = template;
}
}
Set<String> redundantSignatures = new LinkedHashSet<>();
for (File file : files) {
String fileName = file.getName();
String signature = fileName.substring(0, fileName.length() - 4);
// Try to synthesize the fragment - and check if the synthesis is as good as the file body
AsmFragmentManager.AsmFragmentTemplateSynthesizer synthesizer = new AsmFragmentManager.AsmFragmentTemplateSynthesizer(signature, log);
List<AsmFragmentTemplate> templates = synthesizer.loadOrSynthesizeFragment(signature, new AsmFragmentManager.AsmSynthesisPath());
AsmFragmentTemplate fileTemplate = null;
for (AsmFragmentTemplate template : templates) {
if (template.isFile()) {
fileTemplate = template;
}
}
for (AsmFragmentTemplate template : templates) {
if (!template.isFile() && template.getBody().equals(fileTemplate.getBody())) {
// Check if the synthesis uses a file marked as redundant
AsmFragmentTemplate sourceFileTemplate = template;
while (!sourceFileTemplate.isFile()) {
sourceFileTemplate = sourceFileTemplate.getSubFragment();
}
if (redundantSignatures.contains(sourceFileTemplate.getSignature())) {
throw new RuntimeException("Problem in redundancy analysis! " + sourceFileTemplate.getSignature() + ".asm seems redundant but is needed for synthesis of " + signature);
}
log.append("rm " + fileTemplate.getName() + ".asm #synthesized same ASM by " + template.getName());
redundantSignatures.add(signature);
break;
}
}
if(fileTemplate != null && fileUsage == 0 && maxUsage > 0) {
log.append("rm " + fileTemplate.getName() + ".asm #synthesized by " + maxTemplate.getName() + " - usages: " + maxUsage);
}
}
}
if (logUnusedFiles) {
log.append("\nUNUSED ASM FRAGMENT FILES ANALYSIS (if found consider removing them from disk)");
for (File file : files) {
String fileName = file.getName();
String signature = fileName.substring(0, fileName.length() - 4);
List<AsmFragmentTemplate> templates = fragmentTemplateCache.get(signature);
if (templates != null && templates.size() > 0) {
// The template has been loaded / synthesized - is the usage count zero?
boolean allZero = true;
Integer fileUsage = null;
for (AsmFragmentTemplate template : templates) {
Integer usage = fragmentTemplateUsage.get(template);
if (usage == null) usage = 0;
if (usage > 0) {
allZero = false;
}
if (template.isFile()) {
fileUsage = usage;
}
}
if (fileUsage == null) {
throw new RuntimeException("Error! Template file never loaded according to usage stats " + fileName);
}
if (allZero) {
log.append("git mv " + fileName + " unused # Loaded but never used");
}
} else {
// The template has never been loaded
log.append("git mv " + fileName + " unused # Never loaded");
}
Set<String> redundantSignatures = new LinkedHashSet<>();
for(File file : files) {
String fileName = file.getName();
String signature = fileName.substring(0, fileName.length() - 4);
// Try to synthesize the fragment - and check if the synthesis is as good as the file body
AsmFragmentManager.AsmFragmentTemplateSynthesizer synthesizer = new AsmFragmentManager.AsmFragmentTemplateSynthesizer(signature, log);
List<AsmFragmentTemplate> templates = synthesizer.loadOrSynthesizeFragment(signature, new AsmFragmentManager.AsmSynthesisPath());
AsmFragmentTemplate fileTemplate = null;
for(AsmFragmentTemplate template : templates) {
if(template.isFile()) {
fileTemplate = template;
}
}
}
if (logFileDetails) {
log.append("\nDETAILED ASM FILE USAGES");
// Find all file templates
List<AsmFragmentTemplate> fileTemplates = new ArrayList<>();
for (String signature : signatures) {
List<AsmFragmentTemplate> templates = fragmentTemplateCache.get(signature);
for (AsmFragmentTemplate template : templates) {
if (template.isFile()) {
fileTemplates.add(template);
}
}
for(AsmFragmentTemplate template : templates) {
if(!template.isFile() && template.getBody().equals(fileTemplate.getBody())) {
// Check if the synthesis uses a file marked as redundant
AsmFragmentTemplate sourceFileTemplate = template;
while(!sourceFileTemplate.isFile()) {
sourceFileTemplate = sourceFileTemplate.getSubFragment();
}
if(redundantSignatures.contains(sourceFileTemplate.getSignature())) {
throw new RuntimeException("Problem in redundancy analysis! " + sourceFileTemplate.getSignature() + ".asm seems redundant but is needed for synthesis of " + signature);
}
log.append("rm " + fileTemplate.getName() + ".asm #synthesized same ASM by " + template.getName());
redundantSignatures.add(signature);
break;
}
}
logTemplatesByUsage(log, fileTemplates);
}
}
}
if (logAllDetails) {
log.append("\nDETAILED ASM FRAGMENT USAGES");
List<AsmFragmentTemplate> allTemplates = new ArrayList<>();
for (String signature : signatures) {
List<AsmFragmentTemplate> templates = fragmentTemplateCache.get(signature);
for (AsmFragmentTemplate template : templates) {
allTemplates.add(template);
}
if(logUnusedFiles) {
log.append("\nUNUSED ASM FRAGMENT FILES ANALYSIS (if found consider removing them from disk)");
for(File file : files) {
String fileName = file.getName();
String signature = fileName.substring(0, fileName.length() - 4);
List<AsmFragmentTemplate> templates = fragmentTemplateCache.get(signature);
if(templates != null && templates.size() > 0) {
// The template has been loaded / synthesized - is the usage count zero?
boolean allZero = true;
Integer fileUsage = null;
for(AsmFragmentTemplate template : templates) {
Integer usage = fragmentTemplateUsage.get(template);
if(usage == null) usage = 0;
if(usage > 0) {
allZero = false;
}
if(template.isFile()) {
fileUsage = usage;
}
}
if(fileUsage == null) {
throw new RuntimeException("Error! Template file never loaded according to usage stats " + fileName);
}
if(allZero) {
log.append("git mv " + fileName + " unused # Loaded but never used");
}
} else {
// The template has never been loaded
log.append("git mv " + fileName + " unused # Never loaded");
}
logTemplatesByUsage(log, allTemplates);
}
}
}
if(logFileDetails) {
log.append("\nDETAILED ASM FILE USAGES");
// Find all file templates
List<AsmFragmentTemplate> fileTemplates = new ArrayList<>();
for(String signature : signatures) {
List<AsmFragmentTemplate> templates = fragmentTemplateCache.get(signature);
for(AsmFragmentTemplate template : templates) {
if(template.isFile()) {
fileTemplates.add(template);
}
}
}
logTemplatesByUsage(log, fileTemplates);
}
if(logAllDetails) {
log.append("\nDETAILED ASM FRAGMENT USAGES");
List<AsmFragmentTemplate> allTemplates = new ArrayList<>();
for(String signature : signatures) {
List<AsmFragmentTemplate> templates = fragmentTemplateCache.get(signature);
for(AsmFragmentTemplate template : templates) {
allTemplates.add(template);
}
}
logTemplatesByUsage(log, allTemplates);
}
}
}
private static void logTemplatesByUsage(CompileLog log, List<AsmFragmentTemplate> fileTemplates) {
// Sort by usage
Collections.sort(fileTemplates, (o1, o2) -> {
Integer u1 = fragmentTemplateUsage.get(o1);
Integer u2 = fragmentTemplateUsage.get(o2);
if (u1 == null) u1 = 0;
if (u2 == null) u2 = 0;
return u2 - u1;
}
);
// Output
for (AsmFragmentTemplate template : fileTemplates) {
Integer usage = fragmentTemplateUsage.get(template);
if (usage == null) usage = 0;
log.append(String.format("%8d", usage) + " " + (template.isFile()?"*":"")+template.getName());
}
}
private static void logTemplatesByUsage(CompileLog log, List<AsmFragmentTemplate> fileTemplates) {
// Sort by usage
Collections.sort(fileTemplates, (o1, o2) -> {
Integer u1 = fragmentTemplateUsage.get(o1);
Integer u2 = fragmentTemplateUsage.get(o2);
if(u1 == null) u1 = 0;
if(u2 == null) u2 = 0;
return u2 - u1;
}
);
// Output
for(AsmFragmentTemplate template : fileTemplates) {
Integer usage = fragmentTemplateUsage.get(template);
if(usage == null) usage = 0;
log.append(String.format("%8d", usage) + " " + (template.isFile() ? "*" : "") + template.getName());
}
}
}

View File

@ -25,7 +25,7 @@ public class CallGraph {
*/
public CallBlock getOrCreateCallBlock(LabelRef scopeLabel) {
CallBlock callBlock = getCallBlock(scopeLabel);
if (callBlock != null) {
if(callBlock != null) {
return callBlock;
}
// Not found - create it
@ -41,8 +41,8 @@ public class CallGraph {
* @return The call block for the scope. Null if the call block does not exist (no calls are made from it).
*/
private CallBlock getCallBlock(LabelRef scopeLabel) {
for (CallBlock callBlock : callBlocks) {
if (callBlock.getScopeLabel().equals(scopeLabel)) {
for(CallBlock callBlock : callBlocks) {
if(callBlock.getScopeLabel().equals(scopeLabel)) {
return callBlock;
}
}
@ -55,13 +55,14 @@ public class CallGraph {
/**
* Get sub call blocks called from a specific call block.
*
* @param block The block to find subs for
* @return The sub call blocks called from the passed block
*/
public Collection<CallBlock> getCalledBlocks(CallBlock block) {
Collection<LabelRef> calledLabels = block.getCalledBlocks();
LinkedHashSet<CallBlock> called = new LinkedHashSet<>();
for (LabelRef calledLabel : calledLabels) {
for(LabelRef calledLabel : calledLabels) {
called.add(getOrCreateCallBlock(calledLabel));
}
return called;
@ -69,13 +70,14 @@ public class CallGraph {
/**
* Get all call blocks that call a specific call block
*
* @param scopeLabel The label of scope (the call block)
* @return The scope labels of call blocks that call the passed block
*/
public Collection<LabelRef> getCallingBlocks(LabelRef scopeLabel) {
ArrayList<LabelRef> callingBlocks = new ArrayList<>();
for (CallBlock callBlock : callBlocks) {
if (callBlock.getCalledBlocks().contains(scopeLabel)) {
for(CallBlock callBlock : callBlocks) {
if(callBlock.getCalledBlocks().contains(scopeLabel)) {
callingBlocks.add(callBlock.getScopeLabel());
}
}
@ -85,7 +87,7 @@ public class CallGraph {
@Override
public String toString() {
StringBuilder out = new StringBuilder();
for (CallBlock callBlock : callBlocks) {
for(CallBlock callBlock : callBlocks) {
out.append(callBlock.toString()).append("\n");
}
return out.toString();
@ -93,14 +95,15 @@ public class CallGraph {
/**
* Get all calls of a specific procedure
*
* @param label The label of the procedure
* @return All calls
*/
public Collection<CallBlock.Call> getCallers(LabelRef label) {
Collection<CallBlock.Call> callers = new ArrayList<>();
for (CallBlock callBlock : callBlocks) {
for (CallBlock.Call call : callBlock.getCalls()) {
if (call.getProcedure().equals(label)) {
for(CallBlock callBlock : callBlocks) {
for(CallBlock.Call call : callBlock.getCalls()) {
if(call.getProcedure().equals(label)) {
callers.add(call);
}
}
@ -140,7 +143,7 @@ public class CallGraph {
*/
public Collection<LabelRef> getCalledBlocks() {
LinkedHashSet<LabelRef> called = new LinkedHashSet<>();
for (Call call : calls) {
for(Call call : calls) {
called.add(call.getProcedure());
}
return called;
@ -150,7 +153,7 @@ public class CallGraph {
public String toString() {
StringBuilder out = new StringBuilder();
out.append("Calls in [").append(scopeLabel.toString()).append("] to ");
for (Call call : calls) {
for(Call call : calls) {
out.append(call.toString()).append(" ");
}
return out.toString();
@ -158,6 +161,7 @@ public class CallGraph {
/**
* Get all calls
*
* @return The calls
*/
public List<Call> getCalls() {
@ -166,13 +170,14 @@ public class CallGraph {
/**
* Get all calls to a specific call block
*
* @param scope The scope label of the block
* @return All calls to the passed scope
*/
public Collection<Call> getCalls(LabelRef scope) {
ArrayList<Call> callsToScope = new ArrayList<>();
for (Call call : calls) {
if (call.getProcedure().equals(scope)) {
for(Call call : calls) {
if(call.getProcedure().equals(scope)) {
callsToScope.add(call);
}
}
@ -211,7 +216,7 @@ public class CallGraph {
public String toString() {
StringBuilder out = new StringBuilder();
out.append(procedure);
if (callStatementIdx != null) {
if(callStatementIdx != null) {
out.append(":").append(callStatementIdx);
}
return out.toString();

View File

@ -1,6 +1,6 @@
package dk.camelot64.kickc.model;
/** Signals some error in the code (or compilation) */
/** Signals some error in the code (or compilation) */
public class CompileError extends RuntimeException {
public CompileError(String message) {

View File

@ -39,8 +39,8 @@ public class ConstantArrayList implements ConstantValue {
StringBuilder out = new StringBuilder();
boolean first = true;
out.append("{ ");
for (ConstantValue constantValue : list) {
if (!first) {
for(ConstantValue constantValue : list) {
if(!first) {
out.append(", ");
}
first = false;

View File

@ -37,7 +37,7 @@ public class ConstantBinary implements ConstantValue {
@Override
public String toString(Program program) {
return left.toString(program)+operator.toString()+right.toString(program);
return left.toString(program) + operator.toString() + right.toString(program);
}
@Override

View File

@ -23,9 +23,9 @@ public class ConstantBool implements ConstantValue {
@Override
public String toString(Program program) {
if(program ==null) {
if(program == null) {
return Boolean.toString(value);
} else {
} else {
return //"("+SymbolTypeBasic.BOOLEAN.getTypeName()+") "+
Boolean.toString(value);
}

View File

@ -22,12 +22,12 @@ public class ConstantChar implements ConstantValue {
@Override
public String toString() {
return toString(null);
return toString(null);
}
@Override
public String toString(Program program) {
if (program == null) {
if(program == null) {
return "'" + value + "'";
} else {
return "(" + SymbolType.BYTE.getTypeName() + ") " + "'" + value + "'";

View File

@ -27,9 +27,9 @@ public class ConstantDouble implements ConstantValue {
@Override
public String toString(Program program) {
if(program ==null) {
if(program == null) {
return Double.toString(number);
} else {
} else {
return "(" + SymbolType.VOID.getTypeName() + ") " + Double.toString(number);
}
}

View File

@ -29,8 +29,8 @@ public class ConstantInteger implements ConstantValue {
public SymbolType getType() {
ArrayList<SymbolType> potentialTypes = new ArrayList<>();
Integer number = getNumber();
for (SymbolTypeInteger typeInteger : SymbolType.getIntegerTypes()) {
if(number>=typeInteger.getMinValue() && number<= typeInteger.getMaxValue()) {
for(SymbolTypeInteger typeInteger : SymbolType.getIntegerTypes()) {
if(number >= typeInteger.getMinValue() && number <= typeInteger.getMaxValue()) {
potentialTypes.add(typeInteger);
}
}
@ -44,7 +44,7 @@ public class ConstantInteger implements ConstantValue {
@Override
public String toString(Program program) {
if (program == null) {
if(program == null) {
return Integer.toString(number);
} else {
return "(" + getType(program.getScope()).getTypeName() + ") " + Integer.toString(number);
@ -53,8 +53,8 @@ public class ConstantInteger implements ConstantValue {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if(this == o) return true;
if(o == null || getClass() != o.getClass()) return false;
ConstantInteger that = (ConstantInteger) o;
return number != null ? number.equals(that.number) : that.number == null;
}

View File

@ -22,12 +22,12 @@ public class ConstantString implements ConstantValue {
@Override
public String toString() {
return toString(null);
return toString(null);
}
@Override
public String toString(Program program) {
if (program == null) {
if(program == null) {
return "\"" + value + "\"";
} else {
return "(" + SymbolType.STRING.getTypeName() + ") " + "\"" + value + "\"";

View File

@ -29,14 +29,14 @@ public class ConstantUnary implements ConstantValue {
@Override
public boolean equals(Object o) {
if (this == o) {
if(this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
if(o == null || getClass() != o.getClass()) {
return false;
}
ConstantUnary that = (ConstantUnary) o;
if (!operator.equals(that.operator)) {
if(!operator.equals(that.operator)) {
return false;
}
return operand.equals(that.operand);
@ -51,7 +51,7 @@ public class ConstantUnary implements ConstantValue {
@Override
public String toString(Program program) {
return operator.toString()+operand.toString(program);
return operator.toString() + operand.toString(program);
}
@Override

View File

@ -1,6 +1,6 @@
package dk.camelot64.kickc.model;
/** Can calculate the exact value for constants (used for type inference).*/
/** Can calculate the exact value for constants (used for type inference). */
public class ConstantValueCalculator {
@ -28,7 +28,7 @@ public class ConstantValueCalculator {
// Cannot calculate value of inline array
return null;
} else {
throw new RuntimeException("Unknown constant value "+value);
throw new RuntimeException("Unknown constant value " + value);
}
}
@ -52,28 +52,28 @@ public class ConstantValueCalculator {
private static ConstantValue castWord(ConstantValue value) {
if(value instanceof ConstantInteger) {
return new ConstantInteger(0xffff&((ConstantInteger) value).getNumber());
return new ConstantInteger(0xffff & ((ConstantInteger) value).getNumber());
}
return null;
}
private static ConstantValue castSWord(ConstantValue value) {
if(value instanceof ConstantInteger) {
return new ConstantInteger(0xffff&((ConstantInteger) value).getNumber());
return new ConstantInteger(0xffff & ((ConstantInteger) value).getNumber());
}
return null;
}
private static ConstantValue castByte(ConstantValue value) {
if(value instanceof ConstantInteger) {
return new ConstantInteger(0xff&((ConstantInteger) value).getNumber());
return new ConstantInteger(0xff & ((ConstantInteger) value).getNumber());
}
return null;
}
private static ConstantValue castSByte(ConstantValue value) {
if(value instanceof ConstantInteger) {
return new ConstantInteger(0xff&((ConstantInteger) value).getNumber());
return new ConstantInteger(0xff & ((ConstantInteger) value).getNumber());
}
return null;
}
@ -83,7 +83,6 @@ public class ConstantValueCalculator {
}
public static ConstantValue calcValue(ProgramScope programScope, ConstantValue value1, Operator operator, ConstantValue value2) {
if(operator.equals(Operator.MULTIPLY)) {
return multiply(calcValue(programScope, value1), calcValue(programScope, value2));
@ -113,21 +112,25 @@ public class ConstantValueCalculator {
private static ConstantValue multiply(ConstantValue value1, ConstantValue value2) {
if(value1 instanceof ConstantInteger && value2 instanceof ConstantInteger) {
return new ConstantInteger(((ConstantInteger) value1).getNumber()*((ConstantInteger) value2).getNumber());
return new ConstantInteger(((ConstantInteger) value1).getNumber() * ((ConstantInteger) value2).getNumber());
}
return null;
}
private static ConstantValue plus(ConstantValue value1, ConstantValue value2) {
if(value1 instanceof ConstantInteger && value2 instanceof ConstantInteger) {
return new ConstantInteger(((ConstantInteger) value1).getNumber()+((ConstantInteger) value2).getNumber());
} if(value1 instanceof ConstantInteger && value2 instanceof ConstantChar) {
return new ConstantInteger(((ConstantInteger) value1).getNumber()+((ConstantChar) value2).getValue());
} if(value1 instanceof ConstantChar && value2 instanceof ConstantInteger) {
return new ConstantInteger(((ConstantChar) value1).getValue()+((ConstantInteger) value2).getNumber());
} if(value1 instanceof ConstantString && value2 instanceof ConstantString) {
return new ConstantInteger(((ConstantInteger) value1).getNumber() + ((ConstantInteger) value2).getNumber());
}
if(value1 instanceof ConstantInteger && value2 instanceof ConstantChar) {
return new ConstantInteger(((ConstantInteger) value1).getNumber() + ((ConstantChar) value2).getValue());
}
if(value1 instanceof ConstantChar && value2 instanceof ConstantInteger) {
return new ConstantInteger(((ConstantChar) value1).getValue() + ((ConstantInteger) value2).getNumber());
}
if(value1 instanceof ConstantString && value2 instanceof ConstantString) {
return new ConstantString(((ConstantString) value1).getValue() + ((ConstantString) value2).getValue());
} if(value1 instanceof ConstantString && value2 instanceof ConstantChar) {
}
if(value1 instanceof ConstantString && value2 instanceof ConstantChar) {
return new ConstantString(((ConstantString) value1).getValue() + ((ConstantChar) value2).getValue());
}
return null;
@ -135,14 +138,14 @@ public class ConstantValueCalculator {
private static ConstantValue minus(ConstantValue value1, ConstantValue value2) {
if(value1 instanceof ConstantInteger && value2 instanceof ConstantInteger) {
return new ConstantInteger(((ConstantInteger) value1).getNumber()-((ConstantInteger) value2).getNumber());
return new ConstantInteger(((ConstantInteger) value1).getNumber() - ((ConstantInteger) value2).getNumber());
}
return null;
}
private static ConstantValue div(ConstantValue value1, ConstantValue value2) {
if(value1 instanceof ConstantInteger && value2 instanceof ConstantInteger) {
return new ConstantInteger(((ConstantInteger) value1).getNumber()/((ConstantInteger) value2).getNumber());
return new ConstantInteger(((ConstantInteger) value1).getNumber() / ((ConstantInteger) value2).getNumber());
}
return null;
}

View File

@ -64,17 +64,17 @@ public class ConstantVar implements Symbol {
}
@Override
public int getScopeDepth() {
if(scope==null) {
return 0;
} else {
return scope.getScopeDepth()+1;
}
public void setScope(Scope scope) {
this.scope = scope;
}
@Override
public void setScope(Scope scope) {
this.scope = scope;
public int getScopeDepth() {
if(scope == null) {
return 0;
} else {
return scope.getScopeDepth() + 1;
}
}
public ConstantValue getValue() {
@ -101,7 +101,7 @@ public class ConstantVar implements Symbol {
public String toString(Program program) {
String s = new StringBuilder()
.append("(")
.append("const"+" ")
.append("const" + " ")
.append(type.getTypeName())
.append(") ")
.append(getFullName()).toString();
@ -115,22 +115,22 @@ public class ConstantVar implements Symbol {
@Override
public boolean equals(Object o) {
if (this == o) {
if(this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
if(o == null || getClass() != o.getClass()) {
return false;
}
ConstantVar that = (ConstantVar) o;
if (name != null ? !name.equals(that.name) : that.name != null) {
if(name != null ? !name.equals(that.name) : that.name != null) {
return false;
}
if (scope != null ? !scope.equals(that.scope) : that.scope != null) {
if(scope != null ? !scope.equals(that.scope) : that.scope != null) {
return false;
}
if (type != null ? !type.equals(that.type) : that.type != null) {
if(type != null ? !type.equals(that.type) : that.type != null) {
return false;
}
return value != null ? value.equals(that.value) : that.value == null;

View File

@ -9,9 +9,11 @@ import java.util.Collection;
import java.util.List;
import java.util.ListIterator;
/** A named/labelled sequence of SSA statements connected to other basic blocks.
/**
* A named/labelled sequence of SSA statements connected to other basic blocks.
* The connections defines the control flow of the program.
* The block only knows its own successors. To find predecessor blocks access to the entire graph is needed.*/
* The block only knows its own successors. To find predecessor blocks access to the entire graph is needed.
*/
public class ControlFlowBlock {
/** The label representing the block. */
@ -70,14 +72,14 @@ public class ControlFlowBlock {
/**
* Add a statement just before the call statement.
*
* <p>
* Fails if there is no call statement
*
* @param statement The statement to add.
*/
public void addStatementBeforeCall(Statement newStatement) {
ListIterator<Statement> listIterator = statements.listIterator();
while (listIterator.hasNext()) {
while(listIterator.hasNext()) {
Statement statement = listIterator.next();
if(statement instanceof StatementCall) {
listIterator.previous();
@ -85,17 +87,17 @@ public class ControlFlowBlock {
return;
}
}
throw new RuntimeException("No call statement in block "+getLabel().getFullName());
}
public void setDefaultSuccessor(LabelRef defaultSuccessor) {
this.defaultSuccessor = defaultSuccessor;
throw new RuntimeException("No call statement in block " + getLabel().getFullName());
}
public LabelRef getDefaultSuccessor() {
return defaultSuccessor;
}
public void setDefaultSuccessor(LabelRef defaultSuccessor) {
this.defaultSuccessor = defaultSuccessor;
}
public LabelRef getConditionalSuccessor() {
return conditionalSuccessor;
}
@ -118,6 +120,7 @@ public class ControlFlowBlock {
/**
* Is the block the entry of a procedure, ie. the first block of the code of the procedure.
*
* @return true if this is the entry of a procedure
*/
public boolean isProcedureEntry(Program program) {
@ -126,7 +129,8 @@ public class ControlFlowBlock {
}
/**
* Is the block the exit of a procedure, ie. the last block of code of the the procedure
* Is the block the exit of a procedure, ie. the last block of code of the the procedure
*
* @param program
* @return true if this is the exit of a procedure
*/
@ -139,12 +143,12 @@ public class ControlFlowBlock {
ControlFlowGraph graph = program.getGraph();
StringBuffer out = new StringBuffer();
out.append(label.getFullName() + ":");
out.append(" scope:["+scope.getFullName()+"] ");
out.append(" scope:[" + scope.getFullName() + "] ");
out.append(" from");
if (graph != null) {
if(graph != null) {
List<ControlFlowBlock> predecessors = graph.getPredecessors(this);
if (predecessors.size() > 0) {
for (ControlFlowBlock predecessor : predecessors) {
if(predecessors.size() > 0) {
for(ControlFlowBlock predecessor : predecessors) {
out.append(" " + predecessor.getLabel().getFullName());
}
}
@ -152,10 +156,10 @@ public class ControlFlowBlock {
out.append(" @UNKNOWN");
}
out.append("\n");
for (Statement statement : statements) {
for(Statement statement : statements) {
out.append(" " + statement.toString(program, true) + "\n");
}
if (defaultSuccessor != null) {
if(defaultSuccessor != null) {
out.append(" to:");
out.append(defaultSuccessor.getFullName());
out.append("\n");
@ -165,16 +169,16 @@ public class ControlFlowBlock {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if(this == o) return true;
if(o == null || getClass() != o.getClass()) return false;
ControlFlowBlock that = (ControlFlowBlock) o;
if (!label.equals(that.label)) return false;
if (statements != null ? !statements.equals(that.statements) : that.statements != null) return false;
if (defaultSuccessor != null ? !defaultSuccessor.equals(that.defaultSuccessor) : that.defaultSuccessor != null)
if(!label.equals(that.label)) return false;
if(statements != null ? !statements.equals(that.statements) : that.statements != null) return false;
if(defaultSuccessor != null ? !defaultSuccessor.equals(that.defaultSuccessor) : that.defaultSuccessor != null)
return false;
if (conditionalSuccessor != null ? !conditionalSuccessor.equals(that.conditionalSuccessor) : that.conditionalSuccessor != null)
if(conditionalSuccessor != null ? !conditionalSuccessor.equals(that.conditionalSuccessor) : that.conditionalSuccessor != null)
return false;
return callSuccessor != null ? callSuccessor.equals(that.callSuccessor) : that.callSuccessor == null;
}
@ -191,15 +195,16 @@ public class ControlFlowBlock {
/**
* Get the phi block for the block. If the phi block has not yet been created it is created.
*
* @return
*/
@JsonIgnore
public StatementPhiBlock getPhiBlock() {
StatementPhiBlock phiBlock = null;
if (statements.size() > 0 && statements.get(0) instanceof StatementPhiBlock) {
if(statements.size() > 0 && statements.get(0) instanceof StatementPhiBlock) {
phiBlock = (StatementPhiBlock) statements.get(0);
}
if (phiBlock == null) {
if(phiBlock == null) {
phiBlock = new StatementPhiBlock();
statements.add(0, phiBlock);
}
@ -207,8 +212,8 @@ public class ControlFlowBlock {
}
public boolean hasPhiBlock() {
if (statements.size() > 0) {
if (statements.get(0) instanceof StatementPhiBlock) {
if(statements.size() > 0) {
if(statements.get(0) instanceof StatementPhiBlock) {
return true;
}
}
@ -216,20 +221,21 @@ public class ControlFlowBlock {
}
/** Get all successors of the block
/**
* Get all successors of the block
*
* @return All successors
*/
@JsonIgnore
public Collection<LabelRef> getSuccessors() {
List<LabelRef> successors = new ArrayList<>();
if (defaultSuccessor != null) {
if(defaultSuccessor != null) {
successors.add(defaultSuccessor);
}
if (conditionalSuccessor != null) {
if(conditionalSuccessor != null) {
successors.add(conditionalSuccessor);
}
if (callSuccessor != null) {
if(callSuccessor != null) {
successors.add(callSuccessor);
}
return successors;

View File

@ -50,9 +50,9 @@ public class ControlFlowGraph {
@JsonIgnore
public Collection<ControlFlowBlock> getAllBlocks() {
if (sequence != null) {
if(sequence != null) {
ArrayList<ControlFlowBlock> blocks = new ArrayList<>();
for (LabelRef labelRef : sequence) {
for(LabelRef labelRef : sequence) {
blocks.add(getBlock(labelRef));
}
return blocks;
@ -72,11 +72,11 @@ public class ControlFlowGraph {
* @return The assignment. null if the variable is not assigned. The variable is assigned by a Phi-statement instead.
*/
public StatementAssignment getAssignment(VariableRef variable) {
for (ControlFlowBlock block : getAllBlocks()) {
for (Statement statement : block.getStatements()) {
if (statement instanceof StatementAssignment) {
for(ControlFlowBlock block : getAllBlocks()) {
for(Statement statement : block.getStatements()) {
if(statement instanceof StatementAssignment) {
StatementAssignment assignment = (StatementAssignment) statement;
if (assignment.getlValue().equals(variable)) {
if(assignment.getlValue().equals(variable)) {
return assignment;
}
}
@ -92,15 +92,15 @@ public class ControlFlowGraph {
* @return The block containing the assignment. null if the variable is not assigned.
*/
public ControlFlowBlock getAssignmentBlock(VariableRef variable) {
for (ControlFlowBlock block : getAllBlocks()) {
for (Statement statement : block.getStatements()) {
if (statement instanceof StatementAssignment) {
for(ControlFlowBlock block : getAllBlocks()) {
for(Statement statement : block.getStatements()) {
if(statement instanceof StatementAssignment) {
StatementAssignment assignment = (StatementAssignment) statement;
if (assignment.getlValue().equals(variable)) {
if(assignment.getlValue().equals(variable)) {
return block;
}
} else if(statement instanceof StatementPhiBlock) {
for (StatementPhiBlock.PhiVariable phiVariable : ((StatementPhiBlock) statement).getPhiVariables()) {
for(StatementPhiBlock.PhiVariable phiVariable : ((StatementPhiBlock) statement).getPhiVariables()) {
if(phiVariable.getVariable().equals(variable)) {
return block;
}
@ -113,7 +113,7 @@ public class ControlFlowGraph {
public ControlFlowBlock getDefaultSuccessor(ControlFlowBlock block) {
if (block.getDefaultSuccessor() != null) {
if(block.getDefaultSuccessor() != null) {
return blocks.get(block.getDefaultSuccessor());
} else {
return null;
@ -121,7 +121,7 @@ public class ControlFlowGraph {
}
public ControlFlowBlock getCallSuccessor(ControlFlowBlock block) {
if (block.getCallSuccessor() != null) {
if(block.getCallSuccessor() != null) {
return blocks.get(block.getCallSuccessor());
} else {
return null;
@ -129,7 +129,7 @@ public class ControlFlowGraph {
}
public ControlFlowBlock getConditionalSuccessor(ControlFlowBlock block) {
if (block.getConditionalSuccessor() != null) {
if(block.getConditionalSuccessor() != null) {
return blocks.get(block.getConditionalSuccessor());
} else {
return null;
@ -139,14 +139,14 @@ public class ControlFlowGraph {
public List<ControlFlowBlock> getPredecessors(ControlFlowBlock block) {
ArrayList<ControlFlowBlock> predecessorBlocks = new ArrayList<>();
for (ControlFlowBlock other : getAllBlocks()) {
if (block.getLabel().equals(other.getDefaultSuccessor())) {
for(ControlFlowBlock other : getAllBlocks()) {
if(block.getLabel().equals(other.getDefaultSuccessor())) {
predecessorBlocks.add(other);
}
if (block.getLabel().equals(other.getConditionalSuccessor())) {
if(block.getLabel().equals(other.getConditionalSuccessor())) {
predecessorBlocks.add(other);
}
if (block.getLabel().equals(other.getCallSuccessor())) {
if(block.getLabel().equals(other.getCallSuccessor())) {
predecessorBlocks.add(other);
}
}
@ -164,9 +164,9 @@ public class ControlFlowGraph {
@JsonIgnore
public ControlFlowBlock getMainBlock() {
for (ControlFlowBlock block : getAllBlocks()) {
for(ControlFlowBlock block : getAllBlocks()) {
LabelRef label = block.getLabel();
if (label.getFullName().equals("main")) {
if(label.getFullName().equals("main")) {
return block;
}
}
@ -180,7 +180,7 @@ public class ControlFlowGraph {
public String toString(Program program) {
StringBuffer out = new StringBuffer();
for (ControlFlowBlock block : getAllBlocks()) {
for(ControlFlowBlock block : getAllBlocks()) {
out.append(block.toString(program));
}
return out.toString();
@ -188,13 +188,13 @@ public class ControlFlowGraph {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if(this == o) return true;
if(o == null || getClass() != o.getClass()) return false;
ControlFlowGraph that = (ControlFlowGraph) o;
if (!blocks.equals(that.blocks)) return false;
if (!firstBlockRef.equals(that.firstBlockRef)) return false;
if(!blocks.equals(that.blocks)) return false;
if(!firstBlockRef.equals(that.firstBlockRef)) return false;
return sequence != null ? sequence.equals(that.sequence) : that.sequence == null;
}
@ -213,9 +213,9 @@ public class ControlFlowGraph {
* @return The statement
*/
public Statement getStatementByIndex(int statementIdx) {
for (ControlFlowBlock block : getAllBlocks()) {
for (Statement statement : block.getStatements()) {
if (statementIdx == statement.getIndex()) {
for(ControlFlowBlock block : getAllBlocks()) {
for(Statement statement : block.getStatements()) {
if(statementIdx == statement.getIndex()) {
return statement;
}
}
@ -231,8 +231,8 @@ public class ControlFlowGraph {
*/
public List<ControlFlowBlock> getScopeBlocks(ScopeRef scope) {
ArrayList<ControlFlowBlock> scopeBlocks = new ArrayList<>();
for (ControlFlowBlock block : getAllBlocks()) {
if (block.getScope().equals(scope)) {
for(ControlFlowBlock block : getAllBlocks()) {
if(block.getScope().equals(scope)) {
scopeBlocks.add(block);
}
}

View File

@ -7,14 +7,14 @@ public class ControlFlowGraphBaseVisitor<T> {
public T visitGraph(ControlFlowGraph graph) {
Collection<ControlFlowBlock> blocks = graph.getAllBlocks();
for (ControlFlowBlock block : blocks) {
for(ControlFlowBlock block : blocks) {
this.visitBlock(block);
}
return null;
}
public T visitBlock(ControlFlowBlock block) {
for (Statement statement : block.getStatements()) {
for(Statement statement : block.getStatements()) {
this.visitStatement(statement);
}
return null;
@ -42,7 +42,7 @@ public class ControlFlowGraphBaseVisitor<T> {
} else if(statement instanceof StatementAsm) {
return visitAsm((StatementAsm) statement);
} else {
throw new RuntimeException("Unhandled statement type "+statement);
throw new RuntimeException("Unhandled statement type " + statement);
}
}

View File

@ -33,9 +33,9 @@ public class ControlFlowGraphCopyVisitor extends ControlFlowGraphBaseVisitor<Obj
this.origGraph = origGraph;
// Copy all blocks
this.copyBlockMap = new LinkedHashMap<>();
for (ControlFlowBlock origBlock : origGraph.getAllBlocks()) {
for(ControlFlowBlock origBlock : origGraph.getAllBlocks()) {
ControlFlowBlock copyBlock = visitBlock(origBlock);
if (copyBlock != null) {
if(copyBlock != null) {
copyBlockMap.put(copyBlock.getLabel(), copyBlock);
}
}
@ -52,20 +52,20 @@ public class ControlFlowGraphCopyVisitor extends ControlFlowGraphBaseVisitor<Obj
this.copyBlock = copyBlock;
// Handle statements
List<Statement> origBlockStatements = origBlock.getStatements();
for (Statement origStatement : origBlockStatements) {
for(Statement origStatement : origBlockStatements) {
Statement copyStatement = visitStatement(origStatement);
if (copyStatement != null) {
if(copyStatement != null) {
this.copyBlock.addStatement(copyStatement);
}
}
// Handle successors
if (origBlock.getDefaultSuccessor() != null) {
if(origBlock.getDefaultSuccessor() != null) {
this.copyBlock.setDefaultSuccessor(origBlock.getDefaultSuccessor());
}
if (origBlock.getConditionalSuccessor() != null) {
if(origBlock.getConditionalSuccessor() != null) {
this.copyBlock.setConditionalSuccessor(origBlock.getConditionalSuccessor());
}
if (origBlock.getCallSuccessor() != null) {
if(origBlock.getCallSuccessor() != null) {
this.copyBlock.setCallSuccessor(origBlock.getCallSuccessor());
}
ControlFlowBlock result = this.copyBlock;
@ -120,10 +120,10 @@ public class ControlFlowGraphCopyVisitor extends ControlFlowGraphBaseVisitor<Obj
@Override
public StatementPhiBlock visitPhiBlock(StatementPhiBlock phi) {
StatementPhiBlock copyPhi = new StatementPhiBlock();
for (StatementPhiBlock.PhiVariable phiVariable : phi.getPhiVariables()) {
for(StatementPhiBlock.PhiVariable phiVariable : phi.getPhiVariables()) {
VariableRef variable = phiVariable.getVariable();
StatementPhiBlock.PhiVariable copyVar = copyPhi.addPhiVariable(variable);
for (StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) {
for(StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) {
copyVar.setrValue(phiRValue.getPredecessor(), phiRValue.getrValue());
}
}

View File

@ -5,12 +5,13 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/** The Dominators for a specific block.
/**
* The Dominators for a specific block.
* <p>
* Definition: Block d dominates block i if all paths from entry to block i includes block d
* <p>
* See http://www.cs.colostate.edu/~cs553/ClassNotes/lecture09-control-dominators.ppt.pdf
* */
*/
public class DominatorsBlock {
/**
@ -37,7 +38,7 @@ public class DominatorsBlock {
* @param dominators The dominators to add
*/
public void addAll(Collection<LabelRef> dominators) {
for (LabelRef dominator : dominators) {
for(LabelRef dominator : dominators) {
add(dominator);
}
@ -51,9 +52,9 @@ public class DominatorsBlock {
*/
public void intersect(DominatorsBlock other) {
Iterator<LabelRef> iterator = dominators.iterator();
while (iterator.hasNext()) {
while(iterator.hasNext()) {
LabelRef dominator = iterator.next();
if (!other.contains(dominator)) {
if(!other.contains(dominator)) {
iterator.remove();
}
}
@ -75,8 +76,8 @@ public class DominatorsBlock {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if(this == o) return true;
if(o == null || getClass() != o.getClass()) return false;
DominatorsBlock that = (DominatorsBlock) o;
@ -91,7 +92,7 @@ public class DominatorsBlock {
@Override
public String toString() {
StringBuilder out = new StringBuilder();
for (LabelRef dominator : dominators) {
for(LabelRef dominator : dominators) {
out.append(dominator);
out.append(" ");
}

View File

@ -3,13 +3,13 @@ package dk.camelot64.kickc.model;
import java.util.LinkedHashMap;
import java.util.Map;
/** Dominators for a control flow graph.
/**
* Dominators for a control flow graph.
* <p>
* Definition: Block d dominates block i if all paths from entry to block i includes block d
* <p>
* See http://www.cs.colostate.edu/~cs553/ClassNotes/lecture09-control-dominators.ppt.pdf
*
* */
*/
public class DominatorsGraph {
/**
@ -47,7 +47,7 @@ public class DominatorsGraph {
/**
* Set the dominators for a specific block
*
* @param block The block
* @param block The block
* @param dominators The new dominators
*/
public void setDominators(LabelRef block, DominatorsBlock dominators) {
@ -57,7 +57,7 @@ public class DominatorsGraph {
@Override
public String toString() {
StringBuilder out = new StringBuilder();
for (LabelRef block : blockDominators.keySet()) {
for(LabelRef block : blockDominators.keySet()) {
DominatorsBlock dominators = getDominators(block);
out.append(block);
out.append(" dominated by ");

View File

@ -1,6 +1,6 @@
package dk.camelot64.kickc.model;
/** Assignable value (capable of being on the left part of an assignment)*/
/** Assignable value (capable of being on the left part of an assignment) */
public interface LValue extends RValue {
/**

View File

@ -47,10 +47,10 @@ public class Label implements Symbol {
@Override
public int getScopeDepth() {
if(scope==null) {
if(scope == null) {
return 0;
} else {
return scope.getScopeDepth()+1;
return scope.getScopeDepth() + 1;
}
}
@ -70,13 +70,13 @@ public class Label implements Symbol {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if(this == o) return true;
if(o == null || getClass() != o.getClass()) return false;
Label label = (Label) o;
if (intermediate != label.intermediate) return false;
if (!name.equals(label.name)) return false;
if(intermediate != label.intermediate) return false;
if(!name.equals(label.name)) return false;
return getFullName().equals(label.getFullName());
}
@ -94,10 +94,10 @@ public class Label implements Symbol {
@Override
public String toString(Program program) {
if(program ==null) {
if(program == null) {
return getFullName();
} else {
return "("+getType().getTypeName() + ") "+getFullName();
} else {
return "(" + getType().getTypeName() + ") " + getFullName();
}
}

View File

@ -3,7 +3,7 @@ package dk.camelot64.kickc.model;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
/** A reference to a label */
/** A reference to a label */
public class LabelRef extends SymbolRef {
@JsonCreator

View File

@ -16,6 +16,154 @@ public class LiveRange {
*/
private List<LiveInterval> intervals;
public LiveRange() {
this.intervals = new ArrayList<>();
}
/**
* Add a statement to the live range
*
* @param statement The statement to add
* @return true if the live range was modified by the addition. false otherwise
*/
public boolean add(Statement statement) {
return add(getIndex(statement));
}
private Integer getIndex(Statement statement) {
Integer index = statement.getIndex();
if(index == null) {
throw new RuntimeException("Statement index not defined! Live Ranges only work after defining statement indexes (Pass3LiveRangesAnalysis.generateStatementIndices).");
}
return index;
}
/**
* Get the number of statements in the live range.
*
* @return The number of statements in the live range.
*/
public int size() {
int s = 0;
for(LiveInterval interval : intervals) {
s += interval.size();
}
return s;
}
/**
* Add an index to the live range
*
* @param index The index to add
* @return true if the live range was modified. false otherwise
*/
public boolean add(int index) {
for(int i = 0; i < intervals.size(); i++) {
LiveInterval interval = intervals.get(i);
if(index < interval.firstStatementIdx - 1) {
// Add new interval before the current interval
intervals.add(i, new LiveInterval(index, index));
return true;
} else if(index == interval.firstStatementIdx - 1) {
// Extend the current interval downward
interval.firstStatementIdx = index;
return true;
} else if(index <= interval.lastStatementIdx) {
// Already inside the interval
return false;
} else if(index == interval.lastStatementIdx + 1) {
// Extend current interval upward - and check if next interval should be merged
interval.lastStatementIdx = index;
if(i < intervals.size() - 1) {
LiveInterval nextInterval = intervals.get(i + 1);
if(nextInterval.firstStatementIdx == index + 1) {
// Merge intervals
interval.lastStatementIdx = nextInterval.lastStatementIdx;
intervals.remove(i + 1);
}
}
return true;
}
}
// Not added yet - add a new interval at the end
intervals.add(new LiveInterval(index, index));
return true;
}
/**
* Determines if this live range overlaps another live range
*
* @param other The other live range
* @return true if there is an overlap
*/
public boolean overlaps(LiveRange other) {
if(this.getMaxIndex() == -1 || other.getMaxIndex() == -1) {
return false;
}
int maxIdx = getMaxIndex();
for(int i = 0; i <= maxIdx; i++) {
if(contains(i) && other.contains(i)) {
return true;
}
}
return false;
}
/**
* Adds another live range to this one - extending this live range to include the other one.
*
* @param other The live range to add
*/
public void add(LiveRange other) {
int otherMaxIndex = other.getMaxIndex();
for(int i = 0; i <= otherMaxIndex; i++) {
if(other.contains(i)) {
add(i);
}
}
}
/**
* Determines if the live range contains a statement
*
* @param statement The statement to examine
* @return true if the live range contains the statement
*/
public boolean contains(Statement statement) {
return contains(getIndex(statement));
}
/**
* Determines if the live range contains an index
*
* @param index
* @return true if the live range contains the index
*/
private boolean contains(int index) {
for(LiveInterval interval : intervals) {
if(interval.lastStatementIdx >= index) {
if(interval.firstStatementIdx <= index) {
return true;
} else {
return false;
}
}
}
return false;
}
/**
* Get the maximal index contained in the live range
*
* @return The max index. -1 if the range is empty.
*/
int getMaxIndex() {
if(intervals.isEmpty()) {
return -1;
}
return intervals.get(intervals.size() - 1).lastStatementIdx;
}
public static class LiveInterval {
/**
@ -48,157 +196,16 @@ public class LiveRange {
return lastStatementIdx;
}
/** Get the number of statements in the live interval.
/**
* Get the number of statements in the live interval.
*
* @return The number of statements in the live interval.
*/
public int size() {
return lastStatementIdx-firstStatementIdx+1;
return lastStatementIdx - firstStatementIdx + 1;
}
}
public LiveRange() {
this.intervals = new ArrayList<>();
}
/**
* Add a statement to the live range
*
* @param statement The statement to add
* @return true if the live range was modified by the addition. false otherwise
*/
public boolean add(Statement statement) {
return add(getIndex(statement));
}
private Integer getIndex(Statement statement) {
Integer index = statement.getIndex();
if (index == null) {
throw new RuntimeException("Statement index not defined! Live Ranges only work after defining statement indexes (Pass3LiveRangesAnalysis.generateStatementIndices).");
}
return index;
}
/** Get the number of statements in the live range.
*
* @return The number of statements in the live range.
*/
public int size() {
int s = 0;
for (LiveInterval interval : intervals) {
s += interval.size();
}
return s;
}
/**
* Add an index to the live range
* @param index The index to add
* @return true if the live range was modified. false otherwise
*/
public boolean add(int index) {
for (int i = 0; i < intervals.size(); i++) {
LiveInterval interval = intervals.get(i);
if (index < interval.firstStatementIdx - 1) {
// Add new interval before the current interval
intervals.add(i, new LiveInterval(index, index));
return true;
} else if(index == interval.firstStatementIdx - 1) {
// Extend the current interval downward
interval.firstStatementIdx = index;
return true;
} else if(index <= interval.lastStatementIdx) {
// Already inside the interval
return false;
} else if(index == interval.lastStatementIdx+1) {
// Extend current interval upward - and check if next interval should be merged
interval.lastStatementIdx = index;
if(i<intervals.size()-1) {
LiveInterval nextInterval = intervals.get(i + 1);
if(nextInterval.firstStatementIdx==index+1) {
// Merge intervals
interval.lastStatementIdx = nextInterval.lastStatementIdx;
intervals.remove(i+1);
}
}
return true;
}
}
// Not added yet - add a new interval at the end
intervals.add(new LiveInterval(index, index));
return true;
}
/**
* Determines if this live range overlaps another live range
* @param other The other live range
* @return true if there is an overlap
*/
public boolean overlaps(LiveRange other) {
if(this.getMaxIndex()==-1 || other.getMaxIndex()==-1) {
return false;
}
int maxIdx = getMaxIndex();
for(int i=0;i<=maxIdx; i++) {
if(contains(i) && other.contains(i)) {
return true;
}
}
return false;
}
/**
* Adds another live range to this one - extending this live range to include the other one.
* @param other The live range to add
*/
public void add(LiveRange other) {
int otherMaxIndex = other.getMaxIndex();
for(int i=0;i<=otherMaxIndex; i++) {
if(other.contains(i)) {
add(i);
}
}
}
/**
* Determines if the live range contains a statement
* @param statement The statement to examine
* @return true if the live range contains the statement
*/
public boolean contains(Statement statement) {
return contains(getIndex(statement));
}
/**
* Determines if the live range contains an index
* @param index
* @return true if the live range contains the index
*/
private boolean contains(int index) {
for (LiveInterval interval : intervals) {
if(interval.lastStatementIdx>=index) {
if(interval.firstStatementIdx<=index) {
return true;
} else {
return false;
}
}
}
return false;
}
/**
* Get the maximal index contained in the live range
* @return The max index. -1 if the range is empty.
*/
int getMaxIndex() {
if(intervals.isEmpty()) {
return -1;
}
return intervals.get(intervals.size()-1).lastStatementIdx;
}
}

View File

@ -46,7 +46,7 @@ public class LiveRangeEquivalenceClass {
}
LiveRangeVariables liveRanges = set.getProgram().getLiveRangeVariables();
LiveRange varLiveRange = liveRanges.getLiveRange(variable);
if (liveRange.overlaps(varLiveRange)) {
if(liveRange.overlaps(varLiveRange)) {
throw new RuntimeException("Compilation error! Variable live range overlaps live range equivalence class live range. " + variable);
}
liveRange.add(varLiveRange);
@ -75,15 +75,15 @@ public class LiveRangeEquivalenceClass {
public void addAll(LiveRangeEquivalenceClass other) {
liveRange.add(other.liveRange);
variables.addAll(other.variables);
for (VariableRef variable : other.variables) {
for(VariableRef variable : other.variables) {
set.setVarClass(variable, this);
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if(this == o) return true;
if(o == null || getClass() != o.getClass()) return false;
LiveRangeEquivalenceClass that = (LiveRangeEquivalenceClass) o;
return variables.equals(that.variables);
}
@ -100,11 +100,11 @@ public class LiveRangeEquivalenceClass {
public String toString(boolean includeRegister) {
StringBuilder s = new StringBuilder();
if(includeRegister && register!=null) {
if(includeRegister && register != null) {
s.append(register.toString()).append(" ");
}
s.append("[ ");
for (VariableRef variable : variables) {
for(VariableRef variable : variables) {
s.append(variable.toString());
s.append(" ");
}

View File

@ -10,21 +10,19 @@ import java.util.Map;
*/
public class LiveRangeEquivalenceClassSet {
/**
* Maps variables to their containing class.
*/
Map<VariableRef, LiveRangeEquivalenceClass> varClass;
/**
* The containing program.
*/
private Program program;
/**
* The equivalence classes of the set.
*/
private List<LiveRangeEquivalenceClass> equivalenceClasses;
/**
* Maps variables to their containing class.
*/
Map<VariableRef, LiveRangeEquivalenceClass> varClass;
public LiveRangeEquivalenceClassSet(Program program) {
this.program = program;
this.equivalenceClasses = new ArrayList<>();
@ -49,7 +47,7 @@ public class LiveRangeEquivalenceClassSet {
*/
public LiveRangeEquivalenceClass getOrCreateEquivalenceClass(VariableRef variable) {
LiveRangeEquivalenceClass equivalenceClass = getEquivalenceClass(variable);
if (equivalenceClass != null) {
if(equivalenceClass != null) {
return equivalenceClass;
}
// Not found - create it
@ -62,6 +60,7 @@ public class LiveRangeEquivalenceClassSet {
/**
* Consolidates two live range equivalence calsses into one.
* All variables and live ranges from the other class is added to the first one - and the other one is deleted.
*
* @param equivalenceClass The first live range equivalence class.
* @param otherEquivalenceClass The other live range equivalence class, that is added to the first and deleted.
*/
@ -73,7 +72,7 @@ public class LiveRangeEquivalenceClassSet {
/**
* Informs the set that class of a variable has ben set - called by add/remove methods inside LiveRangeEquivalenceClass
*
* @param variable The variable
* @param variable The variable
* @param equivalenceClass The class
*/
void setVarClass(VariableRef variable, LiveRangeEquivalenceClass equivalenceClass) {
@ -102,9 +101,9 @@ public class LiveRangeEquivalenceClassSet {
* Store the register allocation of the live range equivalence classes into the variables in the symbol table (program scope).
*/
public void storeRegisterAllocation() {
for (LiveRangeEquivalenceClass equivalenceClass : getEquivalenceClasses()) {
for(LiveRangeEquivalenceClass equivalenceClass : getEquivalenceClasses()) {
Registers.Register register = equivalenceClass.getRegister();
for (VariableRef variable : equivalenceClass.getVariables()) {
for(VariableRef variable : equivalenceClass.getVariables()) {
Variable var = program.getSymbolInfos().getVariable(variable);
var.setAllocation(register);
}

View File

@ -1,8 +1,11 @@
package dk.camelot64.kickc.model;
import java.util.*;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
/** Live ranges for all variables.
/**
* Live ranges for all variables.
* Created by {@link dk.camelot64.kickc.passes.Pass3CallGraphAnalysis}
*/
public class LiveRangeVariables {
@ -16,7 +19,8 @@ public class LiveRangeVariables {
this.program = program;
}
/** Add a single statement to the live range of a variable.
/**
* Add a single statement to the live range of a variable.
*
* @param variable The variable
* @param statement The statement to add
@ -24,7 +28,7 @@ public class LiveRangeVariables {
*/
public boolean addAlive(VariableRef variable, Statement statement) {
LiveRange liveRange = liveRanges.get(variable);
if (liveRange == null) {
if(liveRange == null) {
liveRange = new LiveRange();
liveRanges.put(variable, liveRange);
}
@ -33,11 +37,12 @@ public class LiveRangeVariables {
/**
* Add an empty alive range for a variable
*
* @param variable The variable
*/
public void addEmptyAlive(VariableRef variable) {
LiveRange liveRange = liveRanges.get(variable);
if (liveRange == null) {
if(liveRange == null) {
liveRange = new LiveRange();
liveRanges.put(variable, liveRange);
}
@ -45,12 +50,13 @@ public class LiveRangeVariables {
/**
* Get all variables alive at a specific statement
*
* @param statement The statement
* @return List of all live variables.
*/
public List<VariableRef> getAlive(Statement statement) {
ArrayList<VariableRef> aliveVars = new ArrayList<>();
for (VariableRef variable : liveRanges.keySet()) {
for(VariableRef variable : liveRanges.keySet()) {
LiveRange liveRange = liveRanges.get(variable);
if(liveRange.contains(statement)) {
aliveVars.add(variable);
@ -61,6 +67,7 @@ public class LiveRangeVariables {
/**
* Get the alive range of a variable
*
* @param variable The variable reference
* @return The alive range for the variable
*/

View File

@ -34,13 +34,84 @@ public class LiveRangeVariablesEffective {
this.procedureCallPaths = procedureCallPaths;
this.referenceInfo = referenceInfo;
this.statementsLiveVariables = new LinkedHashMap<>();
for (ControlFlowBlock block : program.getGraph().getAllBlocks()) {
for (Statement statement : block.getStatements()) {
for(ControlFlowBlock block : program.getGraph().getAllBlocks()) {
for(Statement statement : block.getStatements()) {
statementsLiveVariables.put(statement.getIndex(), liveRangeVariables.getAlive(statement));
}
}
}
/**
* Get all variables potentially alive at a statement.
* If the statement is inside a method this also includes all variables alive at the exit of any call.
* </p>
*
* @param statement The statement to examine
* @return All variables potentially alive at the statement
*/
public Collection<VariableRef> getAliveEffective(Statement statement) {
Set<VariableRef> effectiveAliveTotal = new LinkedHashSet<>();
AliveCombinations aliveCombinations = getAliveCombinations(statement);
for(CallPath callPath : aliveCombinations.getCallPaths().getCallPaths()) {
Collection<VariableRef> alive = aliveCombinations.getEffectiveAliveAtStmt(callPath);
effectiveAliveTotal.addAll(alive);
}
return effectiveAliveTotal;
}
/**
* Get all combinations of variables alive at a statement.
* If the statement is inside a method the different combinations in the result arises from different calls of the method
* (recursively up til the main()-method.)
* Each combination includes all variables alive at the exit of any surrounding call.
* Also includes variable aliases that are part of the parameter assignments to the calls on the path.
* </p>
*
* @param statement The statement to examine
* @return All combinations of variables alive at the statement
*/
public AliveCombinations getAliveCombinations(Statement statement) {
Collection<VariableRef> aliveAtStmt = statementsLiveVariables.get(statement.getIndex());
CallPaths callPaths;
Collection<VariableRef> referencedInProcedure;
ControlFlowBlock block = program.getStatementInfos().getBlock(statement);
ScopeRef scopeRef = block.getScope();
Scope scope = program.getScope().getScope(scopeRef);
if(scope instanceof Procedure) {
Procedure procedure = (Procedure) scope;
callPaths = procedureCallPaths.get(procedure.getRef());
referencedInProcedure = referenceInfo.getReferencedVars(procedure.getRef().getLabelRef());
} else {
callPaths = new CallPaths(Procedure.ROOT);
referencedInProcedure = new ArrayList<>();
}
Pass2AliasElimination.Aliases callAliases = null;
// Examine if the statement is a parameter assignment before a call
LabelRef callSuccessor = block.getCallSuccessor();
if(callSuccessor != null) {
ProcedureRef calledRef = new ProcedureRef(callSuccessor.getFullName());
CallPaths calledRefs = procedureCallPaths.get(calledRef);
for(CallPath calledPath : calledRefs.getCallPaths()) {
List<CallGraph.CallBlock.Call> path = calledPath.getPath();
CallGraph.CallBlock.Call lastCall = path.get(path.size() - 1);
Integer lastCallStatementIdx = lastCall.getCallStatementIdx();
LabelRef lastCallBlockRef = program.getStatementInfos().getBlockRef(lastCallStatementIdx);
if(lastCallBlockRef.equals(block.getLabel())) {
if(callAliases == null) {
// Found a matching call!
callAliases = calledPath.getInnerAliases();
} else {
// Found another matching call!
callAliases = new Pass2AliasElimination.Aliases(callAliases);
callAliases.addAll(calledPath.getInnerAliases());
}
}
}
}
return new AliveCombinations(callPaths, referencedInProcedure, aliveAtStmt, callAliases);
}
/**
* All call-paths leading into a specific procedure.
*/
@ -104,6 +175,7 @@ public class LiveRangeVariablesEffective {
/**
* The path from main() to the procedure. First element is the call to main(), last element is the call to the procedure.
*
* @return Tha call path
*/
public List<CallGraph.CallBlock.Call> getPath() {
@ -112,6 +184,7 @@ public class LiveRangeVariablesEffective {
/**
* Alive variables on the call-path. Based on alive vars at each call in the path.
*
* @return The alive variables
*/
public Collection<VariableRef> getAlive() {
@ -120,6 +193,7 @@ public class LiveRangeVariablesEffective {
/**
* Alias variables from the entire call-path. Any variables alias-assigned as part of a call on the path (in parameter assignment or phi block).
*
* @return The aliases
*/
public Pass2AliasElimination.Aliases getPathAliases() {
@ -128,6 +202,7 @@ public class LiveRangeVariablesEffective {
/**
* Alias variables for the innermost call. Variables alias-assigned as part of the innermost call on the path (in parameter assignment or phi block).
*
* @return The aliases
*/
public Pass2AliasElimination.Aliases getInnerAliases() {
@ -135,78 +210,6 @@ public class LiveRangeVariablesEffective {
}
}
/**
* Get all variables potentially alive at a statement.
* If the statement is inside a method this also includes all variables alive at the exit of any call.
* </p>
*
* @param statement The statement to examine
* @return All variables potentially alive at the statement
*/
public Collection<VariableRef> getAliveEffective(Statement statement) {
Set<VariableRef> effectiveAliveTotal = new LinkedHashSet<>();
AliveCombinations aliveCombinations = getAliveCombinations(statement);
for (CallPath callPath : aliveCombinations.getCallPaths().getCallPaths()) {
Collection<VariableRef> alive = aliveCombinations.getEffectiveAliveAtStmt(callPath);
effectiveAliveTotal.addAll(alive);
}
return effectiveAliveTotal;
}
/**
* Get all combinations of variables alive at a statement.
* If the statement is inside a method the different combinations in the result arises from different calls of the method
* (recursively up til the main()-method.)
* Each combination includes all variables alive at the exit of any surrounding call.
* Also includes variable aliases that are part of the parameter assignments to the calls on the path.
* </p>
*
* @param statement The statement to examine
* @return All combinations of variables alive at the statement
*/
public AliveCombinations getAliveCombinations(Statement statement) {
Collection<VariableRef> aliveAtStmt = statementsLiveVariables.get(statement.getIndex());
CallPaths callPaths;
Collection<VariableRef> referencedInProcedure;
ControlFlowBlock block = program.getStatementInfos().getBlock(statement);
ScopeRef scopeRef = block.getScope();
Scope scope = program.getScope().getScope(scopeRef);
if (scope instanceof Procedure) {
Procedure procedure = (Procedure) scope;
callPaths = procedureCallPaths.get(procedure.getRef());
referencedInProcedure = referenceInfo.getReferencedVars(procedure.getRef().getLabelRef());
} else {
callPaths = new CallPaths(Procedure.ROOT);
referencedInProcedure = new ArrayList<>();
}
Pass2AliasElimination.Aliases callAliases = null;
// Examine if the statement is a parameter assignment before a call
LabelRef callSuccessor = block.getCallSuccessor();
if(callSuccessor !=null) {
ProcedureRef calledRef = new ProcedureRef(callSuccessor.getFullName());
CallPaths calledRefs = procedureCallPaths.get(calledRef);
for (CallPath calledPath : calledRefs.getCallPaths()) {
List<CallGraph.CallBlock.Call> path = calledPath.getPath();
CallGraph.CallBlock.Call lastCall = path.get(path.size() - 1);
Integer lastCallStatementIdx = lastCall.getCallStatementIdx();
LabelRef lastCallBlockRef = program.getStatementInfos().getBlockRef(lastCallStatementIdx);
if(lastCallBlockRef.equals(block.getLabel())) {
if (callAliases == null) {
// Found a matching call!
callAliases = calledPath.getInnerAliases();
} else {
// Found another matching call!
callAliases = new Pass2AliasElimination.Aliases(callAliases);
callAliases.addAll(calledPath.getInnerAliases());
}
}
}
}
return new AliveCombinations(callPaths, referencedInProcedure, aliveAtStmt, callAliases);
}
/**
* Combinations of variables effectively alive at a specific statement.
* If the statement is inside a method the combinations are the live variables inside the method combined with each calling statements alive vars.
@ -244,6 +247,7 @@ public class LiveRangeVariablesEffective {
/**
* Get all variables effective alive at the statement for a specific call path.
*
* @param callPath The call path (returned from getCallPaths)
* @return All variables effectively alive at the statement on the call-path
*/
@ -259,7 +263,7 @@ public class LiveRangeVariablesEffective {
}
public Pass2AliasElimination.Aliases getEffectiveAliasesAtStmt(CallPath callPath) {
if(callAliases==null) {
if(callAliases == null) {
return callPath.getPathAliases();
} else {
Pass2AliasElimination.Aliases aliases = new Pass2AliasElimination.Aliases();

View File

@ -15,13 +15,13 @@ public class LvalueIntermediate implements LValue {
return variable;
}
public void setVariable(VariableRef variable) {
this.variable = variable;
}
@Override
public String toString(Program program) {
return "lval" + "(" + variable.toString(program) + ")";
}
public void setVariable(VariableRef variable) {
this.variable = variable;
}
}

View File

@ -64,19 +64,19 @@ public class NaturalLoop {
out.append("Loop head: ")
.append(head)
.append(" tails: ");
for (LabelRef tail : tails) {
for(LabelRef tail : tails) {
out.append(tail).append(" ");
}
out.append("blocks: ");
if (blocks != null) {
for (LabelRef block : blocks) {
if(blocks != null) {
for(LabelRef block : blocks) {
out.append(block.toString()).append(" ");
}
} else {
out.append("null");
}
if(depth!=null) {
out.append(" depth: "+depth);
if(depth != null) {
out.append(" depth: " + depth);
}
return out.toString();
}
@ -88,8 +88,8 @@ public class NaturalLoop {
* @return true if this loop contains the other loop
*/
public boolean nests(NaturalLoop other) {
for (LabelRef otherBlock : other.getBlocks()) {
if (!blocks.contains(otherBlock)) {
for(LabelRef otherBlock : other.getBlocks()) {
if(!blocks.contains(otherBlock)) {
return false;
}
}
@ -98,6 +98,7 @@ public class NaturalLoop {
/**
* Add more tails to the loop
*
* @param tails The tails to add
*/
public void addTails(Set<LabelRef> tails) {
@ -106,6 +107,7 @@ public class NaturalLoop {
/**
* Add more blocks to the loop
*
* @param blocks The blocks to add
*/
public void addBlocks(Set<LabelRef> blocks) {
@ -122,13 +124,13 @@ public class NaturalLoop {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if(this == o) return true;
if(o == null || getClass() != o.getClass()) return false;
NaturalLoop that = (NaturalLoop) o;
if (head != null ? !head.equals(that.head) : that.head != null) return false;
if (tails != null ? !tails.equals(that.tails) : that.tails != null) return false;
if(head != null ? !head.equals(that.head) : that.head != null) return false;
if(tails != null ? !tails.equals(that.tails) : that.tails != null) return false;
return blocks != null ? blocks.equals(that.blocks) : that.blocks == null;
}

View File

@ -2,10 +2,11 @@ package dk.camelot64.kickc.model;
import java.util.*;
/** A set of natural loops in a control flow graph.
/**
* A set of natural loops in a control flow graph.
* <p>For definitions and more see http://www.cs.colostate.edu/~cs553/ClassNotes/lecture09-control-dominators.ppt.pdf
* <p>Created by {@link dk.camelot64.kickc.passes.Pass3LoopAnalysis}
* */
*/
public class NaturalLoopSet {
private List<NaturalLoop> loops;
@ -25,6 +26,7 @@ public class NaturalLoopSet {
/**
* Get all the loops
*
* @return The loops
*/
public List<NaturalLoop> getLoops() {
@ -34,7 +36,7 @@ public class NaturalLoopSet {
@Override
public String toString() {
StringBuilder out = new StringBuilder();
for (NaturalLoop loop : loops) {
for(NaturalLoop loop : loops) {
out.append(loop.toString());
out.append("\n");
}
@ -43,11 +45,12 @@ public class NaturalLoopSet {
/**
* Get all blocks that are heads of a loop
*
* @return The labels for all blocks that are head of a loop.
*/
public Set<LabelRef> getLoopHeads() {
LinkedHashSet<LabelRef> heads = new LinkedHashSet<>();
for (NaturalLoop loop : loops) {
for(NaturalLoop loop : loops) {
heads.add(loop.getHead());
}
return heads;
@ -55,12 +58,13 @@ public class NaturalLoopSet {
/**
* Get all loops with a given loop head
*
* @param loopHead The loop head
* @return Set with all loops that have the given head
*/
public Set<NaturalLoop> getLoopsFromHead(LabelRef loopHead) {
LinkedHashSet<NaturalLoop> result = new LinkedHashSet<>();
for (NaturalLoop loop : loops) {
for(NaturalLoop loop : loops) {
if(loopHead.equals(loop.getHead())) {
result.add(loop);
}
@ -76,8 +80,8 @@ public class NaturalLoopSet {
*/
public Collection<NaturalLoop> getLoopsContainingBlock(LabelRef block) {
ArrayList<NaturalLoop> containing = new ArrayList<>();
for (NaturalLoop loop : loops) {
for (LabelRef loopBlock : loop.getBlocks()) {
for(NaturalLoop loop : loops) {
for(LabelRef loopBlock : loop.getBlocks()) {
if(block.equals(loopBlock)) {
containing.add(loop);
break;
@ -90,6 +94,7 @@ public class NaturalLoopSet {
/**
* Remove a loop from the set
*
* @param loop The loop to remove
*/
public void remove(NaturalLoop loop) {
@ -98,8 +103,8 @@ public class NaturalLoopSet {
public int getMaxLoopDepth(LabelRef block) {
int maxDepth = 0;
for (NaturalLoop loop : getLoopsContainingBlock(block)) {
if(loop.getDepth()>maxDepth) {
for(NaturalLoop loop : getLoopsContainingBlock(block)) {
if(loop.getDepth() > maxDepth) {
maxDepth = loop.getDepth();
}
}

View File

@ -5,14 +5,45 @@ package dk.camelot64.kickc.model;
*/
public class Operator {
public static final Operator INCREMENT = new Operator("++", "_inc_", Type.UNARY, 1);
public static final Operator DECREMENT = new Operator("--", "_dec_", Type.UNARY, 1);
public static final Operator POS = new Operator("+", "_pos_", Type.UNARY, 2);
public static final Operator NEG = new Operator("-", "_neg_", Type.UNARY, 2);
public static final Operator BOOL_NOT = new Operator("~", "_not_", Type.UNARY, 2);
public static final Operator NOT = new Operator("!", "_not_", Type.UNARY, 2);
public static final Operator DEREF = new Operator("*", "_deref_", Type.UNARY, 2);
public static final Operator WORD = new Operator("w=", "_word_", Type.BINARY, 2);
public static final Operator DEREF_IDX = new Operator("*idx", "_derefidx_", Type.BINARY, 2);
public static final Operator SET_LOWBYTE = new Operator("lo=", "_setlo_", Type.BINARY, 2);
public static final Operator SET_HIBYTE = new Operator("hi=", "_sethi_", Type.BINARY, 2);
public static final Operator CAST_BYTE = new Operator("((byte))", "_byte_", Type.UNARY, 2);
public static final Operator CAST_SBYTE = new Operator("((signed byte))", "_sbyte_", Type.UNARY, 2);
public static final Operator CAST_WORD = new Operator("((word))", "_word_", Type.UNARY, 2);
public static final Operator CAST_SWORD = new Operator("((signed word))", "_sword_", Type.UNARY, 2);
public static final Operator CAST_PTRBY = new Operator("((byte*))", "_ptrby_", Type.UNARY, 2);
public static final Operator MULTIPLY = new Operator("*", "_mul_", Type.BINARY, 3);
public static final Operator DIVIDE = new Operator("/", "_div_", Type.BINARY, 3);
public static final Operator PLUS = new Operator("+", "_plus_", Type.BINARY, 4);
public static final Operator MINUS = new Operator("-", "_minus_", Type.BINARY, 4);
public static final Operator SHIFT_LEFT = new Operator("<<", "_rol_", Type.BINARY, 5);
public static final Operator SHIFT_RIGHT = new Operator(">>", "_ror_", Type.BINARY, 5);
public static final Operator LOWBYTE = new Operator("<", "_lo_", Type.UNARY, 6);
public static final Operator HIBYTE = new Operator(">", "_hi_", Type.UNARY, 6);
public static final Operator LT = new Operator("<", "_lt_", Type.BINARY, 7);
public static final Operator LE = new Operator("<=", "_le_", Type.BINARY, 7);
public static final Operator GT = new Operator(">", "_gt_", Type.BINARY, 7);
public static final Operator GE = new Operator(">=", "_ge_", Type.BINARY, 7);
public static final Operator EQ = new Operator("==", "_eq_", Type.BINARY, 8);
public static final Operator NEQ = new Operator("!=", "_neq_", Type.BINARY, 8);
public static final Operator BOOL_AND = new Operator("&", "_band_", Type.BINARY, 9);
public static final Operator BOOL_XOR = new Operator("^", "_bxor_", Type.BINARY, 10);
public static final Operator BOOL_OR = new Operator("|", "_bor_", Type.BINARY, 11);
public static final Operator LOGIC_AND = new Operator("&&", "_and_", Type.BINARY, 12);
public static final Operator LOGIC_OR = new Operator("||", "_or_", Type.BINARY, 13);
private String operator;
private int precedence;
private Type type;
private String asmOperator;
public Operator(String operator, String asmOperator, Type type, int precedence) {
this.operator = operator;
this.precedence = precedence;
@ -21,7 +52,7 @@ public class Operator {
}
public static Operator getBinary(String op) {
switch (op) {
switch(op) {
case "+":
return PLUS;
case "-":
@ -68,7 +99,7 @@ public class Operator {
}
public static Operator getUnary(String op) {
switch (op) {
switch(op) {
case "+":
return POS;
case "-":
@ -93,15 +124,15 @@ public class Operator {
}
public static Operator getCastUnary(SymbolType castType) {
if (SymbolType.BYTE.equals(castType)) {
if(SymbolType.BYTE.equals(castType)) {
return CAST_BYTE;
} else if (SymbolType.SBYTE.equals(castType)) {
} else if(SymbolType.SBYTE.equals(castType)) {
return CAST_SBYTE;
} else if (SymbolType.WORD.equals(castType)) {
} else if(SymbolType.WORD.equals(castType)) {
return CAST_WORD;
} else if (SymbolType.SWORD.equals(castType)) {
} else if(SymbolType.SWORD.equals(castType)) {
return CAST_SWORD;
} else if (castType instanceof SymbolTypePointer && SymbolType.BYTE.equals(((SymbolTypePointer) castType).getElementType())) {
} else if(castType instanceof SymbolTypePointer && SymbolType.BYTE.equals(((SymbolTypePointer) castType).getElementType())) {
return CAST_PTRBY;
} else {
throw new RuntimeException("Unknown cast type " + castType);
@ -109,46 +140,6 @@ public class Operator {
}
}
public enum Type {
UNARY, BINARY
}
public static final Operator INCREMENT = new Operator("++", "_inc_", Type.UNARY, 1);
public static final Operator DECREMENT = new Operator("--", "_dec_", Type.UNARY, 1);
public static final Operator POS = new Operator("+", "_pos_", Type.UNARY, 2);
public static final Operator NEG = new Operator("-", "_neg_", Type.UNARY, 2);
public static final Operator BOOL_NOT = new Operator("~", "_not_", Type.UNARY, 2);
public static final Operator NOT = new Operator("!", "_not_", Type.UNARY, 2);
public static final Operator DEREF = new Operator("*", "_deref_", Type.UNARY, 2);
public static final Operator WORD = new Operator("w=", "_word_", Type.BINARY, 2);
public static final Operator DEREF_IDX = new Operator("*idx", "_derefidx_", Type.BINARY, 2);
public static final Operator SET_LOWBYTE = new Operator("lo=", "_setlo_", Type.BINARY, 2);
public static final Operator SET_HIBYTE = new Operator("hi=", "_sethi_", Type.BINARY, 2);
public static final Operator CAST_BYTE = new Operator("((byte))", "_byte_", Type.UNARY, 2);
public static final Operator CAST_SBYTE = new Operator("((signed byte))", "_sbyte_", Type.UNARY, 2);
public static final Operator CAST_WORD = new Operator("((word))", "_word_", Type.UNARY, 2);
public static final Operator CAST_SWORD = new Operator("((signed word))", "_sword_", Type.UNARY, 2);
public static final Operator CAST_PTRBY = new Operator("((byte*))", "_ptrby_", Type.UNARY, 2);
public static final Operator MULTIPLY = new Operator("*", "_mul_", Type.BINARY, 3);
public static final Operator DIVIDE = new Operator("/", "_div_", Type.BINARY, 3);
public static final Operator PLUS = new Operator("+", "_plus_", Type.BINARY, 4);
public static final Operator MINUS = new Operator("-", "_minus_", Type.BINARY, 4);
public static final Operator SHIFT_LEFT = new Operator("<<", "_rol_", Type.BINARY, 5);
public static final Operator SHIFT_RIGHT = new Operator(">>", "_ror_", Type.BINARY, 5);
public static final Operator LOWBYTE = new Operator("<", "_lo_", Type.UNARY, 6);
public static final Operator HIBYTE = new Operator(">", "_hi_", Type.UNARY, 6);
public static final Operator LT = new Operator("<", "_lt_", Type.BINARY, 7);
public static final Operator LE = new Operator("<=", "_le_", Type.BINARY, 7);
public static final Operator GT = new Operator(">", "_gt_", Type.BINARY, 7);
public static final Operator GE = new Operator(">=", "_ge_", Type.BINARY, 7);
public static final Operator EQ = new Operator("==", "_eq_", Type.BINARY, 8);
public static final Operator NEQ = new Operator("!=", "_neq_", Type.BINARY, 8);
public static final Operator BOOL_AND = new Operator("&", "_band_", Type.BINARY, 9);
public static final Operator BOOL_XOR = new Operator("^", "_bxor_", Type.BINARY, 10);
public static final Operator BOOL_OR = new Operator("|", "_bor_", Type.BINARY, 11);
public static final Operator LOGIC_AND = new Operator("&&", "_and_", Type.BINARY, 12);
public static final Operator LOGIC_OR = new Operator("||", "_or_", Type.BINARY, 13);
public String getOperator() {
return operator;
}
@ -172,11 +163,11 @@ public class Operator {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if(this == o) return true;
if(o == null || getClass() != o.getClass()) return false;
Operator operator1 = (Operator) o;
if (precedence != operator1.precedence) return false;
if (!operator.equals(operator1.operator)) return false;
if(precedence != operator1.precedence) return false;
if(!operator.equals(operator1.operator)) return false;
return type == operator1.type;
}
@ -188,4 +179,8 @@ public class Operator {
return result;
}
public enum Type {
UNARY, BINARY
}
}

View File

@ -25,7 +25,7 @@ public class PhiTransitions {
this.program = program;
this.toBlock = toBlock;
this.transitions = new LinkedHashMap<>();
if (toBlock.hasPhiBlock()) {
if(toBlock.hasPhiBlock()) {
this.phiBlock = toBlock.getPhiBlock();
List<ControlFlowBlock> predecessors = new ArrayList<>(program.getGraph().getPredecessors(toBlock));
Collections.sort(predecessors, new Comparator<ControlFlowBlock>() {
@ -34,7 +34,7 @@ public class PhiTransitions {
return o1.getLabel().getFullName().compareTo(o2.getLabel().getFullName());
}
});
for (ControlFlowBlock predecessor : predecessors) {
for(ControlFlowBlock predecessor : predecessors) {
PhiTransition transition = findTransition(predecessor);
transitions.put(predecessor, transition);
}
@ -51,10 +51,10 @@ public class PhiTransitions {
private PhiTransition findTransition(ControlFlowBlock fromBlock) {
PhiTransition transition = new PhiTransition(fromBlock);
boolean isCallTransition = toBlock.getLabel().equals(fromBlock.getCallSuccessor());
if (!isCallTransition) {
if(!isCallTransition) {
// If the transition is not a call - then attempt to join with other equal transition(s)
for (PhiTransition candidate : transitions.values()) {
if (candidate.equalAssignments(transition)) {
for(PhiTransition candidate : transitions.values()) {
if(candidate.equalAssignments(transition)) {
candidate.addFromBlock(fromBlock);
return candidate;
}
@ -80,11 +80,12 @@ public class PhiTransitions {
/**
* Get a phi transition from it's phi transition ID.
*
* @param transitionId The ID to look for
* @return The transition with the given ID, or nulll if not found.
*/
public PhiTransition getTransition(String transitionId) {
for (PhiTransition phiTransition : transitions.values()) {
for(PhiTransition phiTransition : transitions.values()) {
if(transitionId.equals(phiTransition.getTransitionId())) {
return phiTransition;
}
@ -117,10 +118,10 @@ public class PhiTransitions {
private void initAssignments(ControlFlowBlock fromBlock) {
this.assignments = new ArrayList<>();
if (phiBlock != null) {
if(phiBlock != null) {
List<StatementPhiBlock.PhiVariable> phiVariables = new ArrayList<>(phiBlock.getPhiVariables());
Collections.reverse(phiVariables);
for (StatementPhiBlock.PhiVariable phiVariable : phiVariables) {
for(StatementPhiBlock.PhiVariable phiVariable : phiVariables) {
List<StatementPhiBlock.PhiRValue> phiRValues = new ArrayList<>(phiVariable.getValues());
Collections.sort(phiRValues, new Comparator<StatementPhiBlock.PhiRValue>() {
@Override
@ -128,8 +129,8 @@ public class PhiTransitions {
return o1.getPredecessor().getFullName().compareTo(o2.getPredecessor().getFullName());
}
});
for (StatementPhiBlock.PhiRValue phiRValue : phiRValues) {
if (phiRValue.getPredecessor().equals(fromBlock.getLabel())) {
for(StatementPhiBlock.PhiRValue phiRValue : phiRValues) {
if(phiRValue.getPredecessor().equals(fromBlock.getLabel())) {
this.assignments.add(new PhiTransition.PhiAssignment(phiVariable, phiRValue, nextIdx++));
}
}
@ -139,13 +140,14 @@ public class PhiTransitions {
/**
* Get a string ID uniquely identifying the PHI transition within the program
*
* @return Transition ID
*/
public String getTransitionId() {
StringBuilder id = new StringBuilder();
id.append("phi:");
boolean first = true;
for (ControlFlowBlock fromBlock : fromBlocks) {
for(ControlFlowBlock fromBlock : fromBlocks) {
if(!first) {
id.append("/");
}
@ -180,28 +182,28 @@ public class PhiTransitions {
*/
public boolean equalAssignments(PhiTransition other) {
List<PhiTransition.PhiAssignment> otherAssignments = other.getAssignments();
if (assignments.size() != otherAssignments.size()) {
if(assignments.size() != otherAssignments.size()) {
return false;
}
for (int i = 0; i < assignments.size(); i++) {
for(int i = 0; i < assignments.size(); i++) {
PhiTransition.PhiAssignment assignment = assignments.get(i);
PhiTransition.PhiAssignment otherAssignment = otherAssignments.get(i);
if (assignment.getVariable() != null && otherAssignment.getVariable() != null) {
if(assignment.getVariable() != null && otherAssignment.getVariable() != null) {
Variable var = program.getSymbolInfos().getVariable(assignment.getVariable());
Variable otherVar = program.getSymbolInfos().getVariable(otherAssignment.getVariable());
if (!var.getAllocation().equals(otherVar.getAllocation())) {
if(!var.getAllocation().equals(otherVar.getAllocation())) {
return false;
}
} else if (!assignment.getVariable().equals(otherAssignment.getVariable())) {
} else if(!assignment.getVariable().equals(otherAssignment.getVariable())) {
return false;
}
if (assignment.getrValue() instanceof VariableRef && otherAssignment.getrValue() instanceof VariableRef) {
if(assignment.getrValue() instanceof VariableRef && otherAssignment.getrValue() instanceof VariableRef) {
Variable var = program.getSymbolInfos().getVariable((VariableRef) assignment.getrValue());
Variable otherVar = program.getSymbolInfos().getVariable((VariableRef) otherAssignment.getrValue());
if (!var.getAllocation().equals(otherVar.getAllocation())) {
if(!var.getAllocation().equals(otherVar.getAllocation())) {
return false;
}
} else if (!assignment.getrValue().equals(otherAssignment.getrValue())) {
} else if(!assignment.getrValue().equals(otherAssignment.getrValue())) {
return false;
}
}

View File

@ -1,6 +1,6 @@
package dk.camelot64.kickc.model;
/** A dereferenced variable pointer plus an index (used for array writes)*/
/** A dereferenced variable pointer plus an index (used for array writes) */
public class PointerDereferenceIndexed implements PointerDereference {
private RValue pointer;
@ -35,7 +35,7 @@ public class PointerDereferenceIndexed implements PointerDereference {
@Override
public String toString(Program program) {
return "*(" + pointer.toString(program) + " + " +index.toString(program) + ')';
return "*(" + pointer.toString(program) + " + " + index.toString(program) + ')';
}
}

View File

@ -1,6 +1,6 @@
package dk.camelot64.kickc.model;
/** A dereferenced pointer (based on a variable or a constant pointer)*/
/** A dereferenced pointer (based on a variable or a constant pointer) */
public class PointerDereferenceSimple implements PointerDereference {
private RValue pointer;

View File

@ -11,11 +11,10 @@ import java.util.List;
/** Symbol describing a procedure/function */
public class Procedure extends Scope {
public static final ProcedureRef ROOT = new ProcedureRef("");
private final SymbolType returnType;
private List<String> parameterNames;
public static final ProcedureRef ROOT = new ProcedureRef("");
public Procedure(String name, SymbolType returnType, Scope parentScope) {
super(name, parentScope);
this.returnType = returnType;
@ -42,14 +41,6 @@ public class Procedure extends Scope {
this.parameterNames = parameterNames;
}
public void setParameters(List<Variable> parameters) {
this.parameterNames = new ArrayList<>();
for (Variable parameter : parameters) {
add(parameter);
parameterNames.add(parameter.getLocalName());
}
}
@JsonIgnore
public Label getLabel() {
return new Label(getFullName(), getScope(), false);
@ -62,12 +53,20 @@ public class Procedure extends Scope {
@JsonIgnore
public List<Variable> getParameters() {
ArrayList<Variable> parameters = new ArrayList<>();
for (String name : parameterNames) {
for(String name : parameterNames) {
parameters.add(this.getVariable(name));
}
return parameters;
}
public void setParameters(List<Variable> parameters) {
this.parameterNames = new ArrayList<>();
for(Variable parameter : parameters) {
add(parameter);
parameterNames.add(parameter.getLocalName());
}
}
@Override
public String getFullName() {
return super.getFullName();
@ -94,13 +93,13 @@ public class Procedure extends Scope {
@Override
public String toString(Program program) {
StringBuilder res = new StringBuilder();
res.append("("+getType().getTypeName() + ") ");
res.append("(" + getType().getTypeName() + ") ");
res.append(getFullName());
res.append("(");
boolean first = true;
if(parameterNames !=null) {
for (Variable parameter : getParameters()) {
if (!first) res.append(" , ");
if(parameterNames != null) {
for(Variable parameter : getParameters()) {
if(!first) res.append(" , ");
first = false;
res.append(parameter.toString(program));
}
@ -116,13 +115,13 @@ public class Procedure extends Scope {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
if(this == o) return true;
if(o == null || getClass() != o.getClass()) return false;
if(!super.equals(o)) return false;
Procedure procedure = (Procedure) o;
if (returnType != null ? !returnType.equals(procedure.returnType) : procedure.returnType != null) return false;
if(returnType != null ? !returnType.equals(procedure.returnType) : procedure.returnType != null) return false;
return parameterNames != null ? parameterNames.equals(procedure.parameterNames) : procedure.parameterNames == null;
}

View File

@ -1,6 +1,7 @@
package dk.camelot64.kickc.model;
import java.util.*;
import java.util.Map;
import java.util.Set;
/**
* Contains all variables modified inside procedures. Contain the unversioned VariableRefs.
@ -20,9 +21,9 @@ public class ProcedureModifiedVars {
public String toString(Program program) {
StringBuilder out = new StringBuilder();
for (ProcedureRef procedureRef : modified.keySet()) {
for (VariableRef variableRef : getModifiedVars(procedureRef)) {
out.append(procedureRef.getFullName()).append(" modifies "+variableRef.getFullName()).append("\n");
for(ProcedureRef procedureRef : modified.keySet()) {
for(VariableRef variableRef : getModifiedVars(procedureRef)) {
out.append(procedureRef.getFullName()).append(" modifies " + variableRef.getFullName()).append("\n");
}
}
return out.toString();

View File

@ -8,12 +8,13 @@ import com.fasterxml.jackson.annotation.JsonProperty;
public class ProcedureRef extends ScopeRef {
@JsonCreator
public ProcedureRef( @JsonProperty("fullName") String fullName) {
public ProcedureRef(@JsonProperty("fullName") String fullName) {
super(fullName);
}
/**
* Get the label of the block where the procedure code starts
*
* @return The label of the code block
*/
@JsonIgnore
@ -23,10 +24,11 @@ public class ProcedureRef extends ScopeRef {
/**
* Get the label of the block containing the final procedure return
*
* @return The label of the code block
*/
@JsonIgnore
public LabelRef getReturnBlock() {
return new LabelRef(getFullName()+"::"+SymbolRef.PROCEXIT_BLOCK_NAME);
return new LabelRef(getFullName() + "::" + SymbolRef.PROCEXIT_BLOCK_NAME);
}
}

View File

@ -29,14 +29,14 @@ public class Program {
private ProcedureModifiedVars procedureModifiedVars;
/** Information about calls. */
private CallGraph callGraph;
/** Information about dominators of all blocks*/
/** Information about dominators of all blocks */
private DominatorsGraph dominators;
/** Information about loops. */
private NaturalLoopSet loopSet;
/** Which block is each statement a part of. */
private StatementInfos statementInfos;
/** Cached information about symbols. Contains a symbol table cache for fast access.*/
/** Cached information about symbols. Contains a symbol table cache for fast access. */
private SymbolInfos symbolInfos;
/** The variables referenced by blocks/statements. */
private VariableReferenceInfos variableReferenceInfos;
@ -92,14 +92,14 @@ public class Program {
this.graph = graph;
}
public void setProcedureModifiedVars(ProcedureModifiedVars procedureModifiedVars) {
this.procedureModifiedVars = procedureModifiedVars;
}
public ProcedureModifiedVars getProcedureModifiedVars() {
return procedureModifiedVars;
}
public void setProcedureModifiedVars(ProcedureModifiedVars procedureModifiedVars) {
this.procedureModifiedVars = procedureModifiedVars;
}
public AsmProgram getAsm() {
return asm;
}
@ -116,22 +116,22 @@ public class Program {
this.callGraph = callGraph;
}
public void setDominators(DominatorsGraph dominators) {
this.dominators = dominators;
}
public DominatorsGraph getDominators() {
return dominators;
}
public void setLoopSet(NaturalLoopSet loopSet) {
this.loopSet = loopSet;
public void setDominators(DominatorsGraph dominators) {
this.dominators = dominators;
}
public NaturalLoopSet getLoopSet() {
return loopSet;
}
public void setLoopSet(NaturalLoopSet loopSet) {
this.loopSet = loopSet;
}
public VariableReferenceInfos getVariableReferenceInfos() {
return variableReferenceInfos;
}
@ -156,14 +156,14 @@ public class Program {
this.symbolInfos = symbolInfos;
}
public void setLiveRangeVariables(LiveRangeVariables liveRangeVariables) {
this.liveRangeVariables = liveRangeVariables;
}
public LiveRangeVariables getLiveRangeVariables() {
return liveRangeVariables;
}
public void setLiveRangeVariables(LiveRangeVariables liveRangeVariables) {
this.liveRangeVariables = liveRangeVariables;
}
public LiveRangeVariablesEffective getLiveRangeVariablesEffective() {
return liveRangeVariablesEffective;
}
@ -172,38 +172,38 @@ public class Program {
this.liveRangeVariablesEffective = liveRangeVariablesEffective;
}
public void setLiveRangeEquivalenceClassSet(LiveRangeEquivalenceClassSet liveRangeEquivalenceClassSet) {
this.liveRangeEquivalenceClassSet = liveRangeEquivalenceClassSet;
}
public LiveRangeEquivalenceClassSet getLiveRangeEquivalenceClassSet() {
return liveRangeEquivalenceClassSet;
}
public void setVariableRegisterWeights(VariableRegisterWeights variableRegisterWeights) {
this.variableRegisterWeights = variableRegisterWeights;
public void setLiveRangeEquivalenceClassSet(LiveRangeEquivalenceClassSet liveRangeEquivalenceClassSet) {
this.liveRangeEquivalenceClassSet = liveRangeEquivalenceClassSet;
}
public VariableRegisterWeights getVariableRegisterWeights() {
return variableRegisterWeights;
}
public void setRegisterPotentials(RegisterPotentials registerPotentials) {
this.registerPotentials = registerPotentials;
public void setVariableRegisterWeights(VariableRegisterWeights variableRegisterWeights) {
this.variableRegisterWeights = variableRegisterWeights;
}
public RegisterPotentials getRegisterPotentials() {
return registerPotentials;
}
public void setRegisterUpliftProgram(RegisterUpliftProgram registerUpliftProgram) {
this.registerUpliftProgram = registerUpliftProgram;
public void setRegisterPotentials(RegisterPotentials registerPotentials) {
this.registerPotentials = registerPotentials;
}
public RegisterUpliftProgram getRegisterUpliftProgram() {
return registerUpliftProgram;
}
public void setRegisterUpliftProgram(RegisterUpliftProgram registerUpliftProgram) {
this.registerUpliftProgram = registerUpliftProgram;
}
public CompileLog getLog() {
return log;
}
@ -215,13 +215,13 @@ public class Program {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if(this == o) return true;
if(o == null || getClass() != o.getClass()) return false;
Program program = (Program) o;
if (scope != null ? !scope.equals(program.scope) : program.scope != null) return false;
if (graph != null ? !graph.equals(program.graph) : program.graph != null) return false;
if(scope != null ? !scope.equals(program.scope) : program.scope != null) return false;
if(graph != null ? !graph.equals(program.graph) : program.graph != null) return false;
return asm != null ? asm.equals(program.asm) : program.asm == null;
}

View File

@ -38,9 +38,9 @@ public class ProgramScope extends Scope {
LiveRangeEquivalenceClassSet liveRangeEquivalenceClassSet = program.getLiveRangeEquivalenceClassSet();
StringBuilder out = new StringBuilder();
out.append(super.toString(program, symbolClass));
if(liveRangeEquivalenceClassSet!=null) {
if(liveRangeEquivalenceClassSet != null) {
out.append("\n");
for (LiveRangeEquivalenceClass liveRangeEquivalenceClass : liveRangeEquivalenceClassSet.getEquivalenceClasses()) {
for(LiveRangeEquivalenceClass liveRangeEquivalenceClass : liveRangeEquivalenceClassSet.getEquivalenceClasses()) {
out.append(liveRangeEquivalenceClass);
out.append("\n");
}

View File

@ -1,6 +1,6 @@
package dk.camelot64.kickc.model;
/** A value usable as part of a calculation (ib the right side of an assignment)*/
/** A value usable as part of a calculation (ib the right side of an assignment) */
public interface RValue extends Value {
}

View File

@ -3,7 +3,7 @@ package dk.camelot64.kickc.model;
import java.util.LinkedHashMap;
import java.util.Map;
/** A combination of register/ZP assignments for a set of equivalence classes */
/** A combination of register/ZP assignments for a set of equivalence classes */
public class RegisterCombination {
/** The registers allocated to each equivalence class. */
@ -26,9 +26,9 @@ public class RegisterCombination {
* (does not update the allocation in the equivalence classes).
*/
public void allocate(Program program) {
for (LiveRangeEquivalenceClass equivalenceClass : allocation.keySet()) {
for(LiveRangeEquivalenceClass equivalenceClass : allocation.keySet()) {
Registers.Register register = allocation.get(equivalenceClass);
for (VariableRef variable : equivalenceClass.getVariables()) {
for(VariableRef variable : equivalenceClass.getVariables()) {
Variable var = program.getSymbolInfos().getVariable(variable);
var.setAllocation(register);
}
@ -39,7 +39,7 @@ public class RegisterCombination {
* Store the combination in the equivalence classes.
*/
public void store(LiveRangeEquivalenceClassSet equivalenceClassSet) {
for (LiveRangeEquivalenceClass equivalenceClass : allocation.keySet()) {
for(LiveRangeEquivalenceClass equivalenceClass : allocation.keySet()) {
VariableRef variable = equivalenceClass.getVariables().get(0);
LiveRangeEquivalenceClass globalEquivalenceClass = equivalenceClassSet.getEquivalenceClass(variable);
Registers.Register register = allocation.get(equivalenceClass);
@ -50,7 +50,7 @@ public class RegisterCombination {
@Override
public String toString() {
StringBuilder out = new StringBuilder();
for (LiveRangeEquivalenceClass equivalenceClass : allocation.keySet()) {
for(LiveRangeEquivalenceClass equivalenceClass : allocation.keySet()) {
Registers.Register register = allocation.get(equivalenceClass);
out.append(register.toString()).append(" ").append(equivalenceClass.toString(false)).append(" ");
}

View File

@ -30,7 +30,7 @@ public class RegisterCombinationIterator implements Iterator<RegisterCombination
public int getNumIterations() {
int numIterations = 1;
for (LiveRangeEquivalenceClass equivalenceClass : equivalenceClasses) {
for(LiveRangeEquivalenceClass equivalenceClass : equivalenceClasses) {
List<Registers.Register> registers = registerPotentials.getPotentialRegisters(equivalenceClass);
numIterations = numIterations * registers.size();
}
@ -41,7 +41,7 @@ public class RegisterCombinationIterator implements Iterator<RegisterCombination
public RegisterCombination next() {
RegisterCombination combination = new RegisterCombination();
int combinationIdRest = nextIterationId;
for (LiveRangeEquivalenceClass equivalenceClass : equivalenceClasses) {
for(LiveRangeEquivalenceClass equivalenceClass : equivalenceClasses) {
List<Registers.Register> potentials = registerPotentials.getPotentialRegisters(equivalenceClass);
int registerIdx = (combinationIdRest % potentials.size());
Registers.Register register = potentials.get(registerIdx);

View File

@ -33,12 +33,12 @@ public class RegisterPotentials {
@Override
public String toString() {
StringBuilder out = new StringBuilder();
for (LiveRangeEquivalenceClass liveRangeEquivalenceClass : potentials.keySet()) {
for(LiveRangeEquivalenceClass liveRangeEquivalenceClass : potentials.keySet()) {
out.append("Potential registers ");
out.append(liveRangeEquivalenceClass.toString());
out.append(" : ");
List<Registers.Register> registers = potentials.get(liveRangeEquivalenceClass);
for (Registers.Register register : registers) {
for(Registers.Register register : registers) {
out.append(register.toString());
out.append(" , ");
}
@ -49,11 +49,11 @@ public class RegisterPotentials {
public void addPotentialRegister(LiveRangeEquivalenceClass equivalenceClass, Registers.Register register) {
List<Registers.Register> registers = potentials.get(equivalenceClass);
if(registers==null) {
registers= new ArrayList<>();
if(registers == null) {
registers = new ArrayList<>();
potentials.put(equivalenceClass, registers);
}
if (!registers.contains(register)) {
if(!registers.contains(register)) {
registers.add(register);
}
}

View File

@ -30,7 +30,7 @@ public class RegisterUpliftProgram {
public String toString(VariableRegisterWeights variableRegisterWeights) {
StringBuilder out = new StringBuilder();
for (RegisterUpliftScope upliftScope : registerUpliftScopes) {
for(RegisterUpliftScope upliftScope : registerUpliftScopes) {
out.append(upliftScope.toString(variableRegisterWeights)).append("\n");
}
return out.toString();

View File

@ -2,7 +2,10 @@ package dk.camelot64.kickc.model;
import com.ibm.icu.text.NumberFormat;
import java.util.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
/** Register Uplift information for a single scope. */
public class RegisterUpliftScope {
@ -20,10 +23,6 @@ public class RegisterUpliftScope {
this.equivalenceClasses = new ArrayList<>();
}
public void setEquivalenceClasses(List<LiveRangeEquivalenceClass> equivalenceClasses) {
this.equivalenceClasses = equivalenceClasses;
}
public ScopeRef getScopeRef() {
return scopeRef;
}
@ -32,11 +31,15 @@ public class RegisterUpliftScope {
return equivalenceClasses;
}
public void setEquivalenceClasses(List<LiveRangeEquivalenceClass> equivalenceClasses) {
this.equivalenceClasses = equivalenceClasses;
}
public String toString(VariableRegisterWeights weights) {
StringBuilder out = new StringBuilder();
out.append("Uplift Scope [" + scopeRef.toString() + "] ");
for (LiveRangeEquivalenceClass equivalenceClass : equivalenceClasses) {
if (weights != null) {
for(LiveRangeEquivalenceClass equivalenceClass : equivalenceClasses) {
if(weights != null) {
NumberFormat fmt = NumberFormat.getInstance(Locale.ENGLISH);
fmt.setMaximumFractionDigits(2);
out.append(fmt.format(weights.getTotalWeight(equivalenceClass)) + ": ");
@ -53,6 +56,7 @@ public class RegisterUpliftScope {
/**
* Get all register allocation combinations using the passed potential registers
*
* @param registerPotentials The potential registers to use for each live range equivalence class
* @return Iterator of all combinations
*/

View File

@ -1,6 +1,6 @@
package dk.camelot64.kickc.model;
/** The different registers available for a program */
/** The different registers available for a program */
public class Registers {
@ -71,10 +71,10 @@ public class Registers {
@Override
public boolean equals(Object o) {
if (this == o) {
if(this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
if(o == null || getClass() != o.getClass()) {
return false;
}
@ -150,10 +150,10 @@ public class Registers {
@Override
public boolean equals(Object obj) {
if (this == obj) {
if(this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
if(obj == null || getClass() != obj.getClass()) {
return false;
}
return true;
@ -253,7 +253,7 @@ public class Registers {
@Override
public String toString(Program program) {
return "const "+constantValue.toString(program);
return "const " + constantValue.toString(program);
}
@Override
@ -263,8 +263,8 @@ public class Registers {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if(this == o) return true;
if(o == null || getClass() != o.getClass()) return false;
RegisterConstant that = (RegisterConstant) o;
return constantValue != null ? constantValue.equals(that.constantValue) : that.constantValue == null;
}

View File

@ -34,7 +34,7 @@ public abstract class Scope implements Symbol {
this.symbols = symbols;
this.intermediateVarCount = intermediateVarCount;
this.intermediateLabelCount = intermediateLabelCount;
for (Symbol symbol : symbols.values()) {
for(Symbol symbol : symbols.values()) {
symbol.setScope(this);
}
}
@ -45,6 +45,16 @@ public abstract class Scope implements Symbol {
this.symbols = new LinkedHashMap<>();
}
public static String getFullName(Symbol symbol) {
if(symbol.getScope() != null) {
String scopeName = symbol.getScope().getFullName();
if(scopeName.length() > 0) {
return scopeName + "::" + symbol.getLocalName();
}
}
return symbol.getLocalName();
}
public HashMap<String, Symbol> getSymbols() {
return symbols;
}
@ -59,16 +69,6 @@ public abstract class Scope implements Symbol {
return getFullName(this);
}
public static String getFullName(Symbol symbol) {
if (symbol.getScope() != null) {
String scopeName = symbol.getScope().getFullName();
if (scopeName.length() > 0) {
return scopeName + "::" + symbol.getLocalName();
}
}
return symbol.getLocalName();
}
public ScopeRef getRef() {
return new ScopeRef(this);
}
@ -79,6 +79,11 @@ public abstract class Scope implements Symbol {
return parentScope;
}
@Override
public void setScope(Scope scope) {
this.parentScope = scope;
}
@Override
@JsonIgnore
public abstract SymbolType getType();
@ -86,7 +91,7 @@ public abstract class Scope implements Symbol {
@Override
@JsonIgnore
public int getScopeDepth() {
if (parentScope == null) {
if(parentScope == null) {
return 0;
} else {
return parentScope.getScopeDepth() + 1;
@ -94,7 +99,7 @@ public abstract class Scope implements Symbol {
}
public Symbol add(Symbol symbol) {
if (symbols.get(symbol.getLocalName()) != null) {
if(symbols.get(symbol.getLocalName()) != null) {
throw new RuntimeException("Symbol already declared " + symbol.getLocalName());
}
symbols.put(symbol.getLocalName(), symbol);
@ -120,12 +125,13 @@ public abstract class Scope implements Symbol {
/**
* Get all versions of an unversioned variable
*
* @param unversioned The unversioned variable
* @return All versions of the variable
*/
public Collection<VariableVersion> getVersions(VariableUnversioned unversioned) {
LinkedHashSet<VariableVersion> versions = new LinkedHashSet<>();
for (Symbol symbol : symbols.values()) {
for(Symbol symbol : symbols.values()) {
if(symbol instanceof VariableVersion) {
if(((VariableVersion) symbol).isVersioned()) {
if(((VariableVersion) symbol).getVersionOf().equals(unversioned)) {
@ -137,7 +143,6 @@ public abstract class Scope implements Symbol {
return versions;
}
public String allocateIntermediateVariableName() {
return "$" + intermediateVarCount++;
}
@ -148,11 +153,11 @@ public abstract class Scope implements Symbol {
public Symbol getSymbol(String name) {
int pos = name.indexOf("::");
if (pos >= 0) {
if(pos >= 0) {
String scopeName = name.substring(0, pos);
String rest = name.substring(pos + 2);
Symbol scopeSym = getSymbol(scopeName);
if (scopeSym instanceof Scope) {
if(scopeSym instanceof Scope) {
return ((Scope) scopeSym).getSymbol(rest);
} else {
return null;
@ -160,8 +165,8 @@ public abstract class Scope implements Symbol {
}
} else {
Symbol symbol = symbols.get(name);
if (symbol == null) {
if (parentScope != null) {
if(symbol == null) {
if(parentScope != null) {
symbol = parentScope.getSymbol(name);
}
}
@ -188,11 +193,11 @@ public abstract class Scope implements Symbol {
@JsonIgnore
public Collection<Variable> getAllVariables(boolean includeSubScopes) {
Collection<Variable> vars = new ArrayList<>();
for (Symbol symbol : symbols.values()) {
if (symbol instanceof Variable) {
for(Symbol symbol : symbols.values()) {
if(symbol instanceof Variable) {
vars.add((Variable) symbol);
}
if (includeSubScopes && symbol instanceof Scope) {
if(includeSubScopes && symbol instanceof Scope) {
Scope subScope = (Scope) symbol;
vars.addAll(subScope.getAllVariables(true));
}
@ -203,11 +208,11 @@ public abstract class Scope implements Symbol {
public Collection<ConstantVar> getAllConstants(boolean includeSubScopes) {
Collection<ConstantVar> vars = new ArrayList<>();
for (Symbol symbol : symbols.values()) {
if (symbol instanceof ConstantVar) {
for(Symbol symbol : symbols.values()) {
if(symbol instanceof ConstantVar) {
vars.add((ConstantVar) symbol);
}
if (includeSubScopes && symbol instanceof Scope) {
if(includeSubScopes && symbol instanceof Scope) {
Scope subScope = (Scope) symbol;
vars.addAll(subScope.getAllConstants(true));
}
@ -216,19 +221,19 @@ public abstract class Scope implements Symbol {
return vars;
}
/**
* Get all scopes contained in the scope. This does not include this scope itself.
*
* @param includeSubScopes Include sub-scopes og sub-scopes
* @return The scopes
*/
@JsonIgnore
public Collection<Scope> getAllScopes(boolean includeSubScopes) {
Collection<Scope> scopes = new ArrayList<>();
for (Symbol symbol : symbols.values()) {
if (symbol instanceof Scope) {
for(Symbol symbol : symbols.values()) {
if(symbol instanceof Scope) {
scopes.add((Scope) symbol);
if (includeSubScopes) {
if(includeSubScopes) {
Scope subScope = (Scope) symbol;
scopes.addAll(subScope.getAllScopes(true));
}
@ -239,15 +244,14 @@ public abstract class Scope implements Symbol {
public Collection<Procedure> getAllProcedures(boolean includeSubScopes) {
Collection<Procedure> procedures = new ArrayList<>();
for (Scope scope : getAllScopes(includeSubScopes)) {
if (scope instanceof Procedure) {
for(Scope scope : getAllScopes(includeSubScopes)) {
if(scope instanceof Procedure) {
procedures.add((Procedure) scope);
}
}
return procedures;
}
public Label addLabel(String name) {
Label symbol = new Label(name, this, false);
add(symbol);
@ -271,7 +275,7 @@ public abstract class Scope implements Symbol {
public Procedure addProcedure(String name, SymbolType type) {
Symbol symbol = symbols.get(name);
if (symbol != null) {
if(symbol != null) {
throw new RuntimeException("Error! Symbol already defined " + symbol);
}
Procedure procedure = new Procedure(name, type, this);
@ -281,7 +285,7 @@ public abstract class Scope implements Symbol {
public Procedure getProcedure(String name) {
Symbol symbol = getSymbol(name);
if (symbol != null && symbol instanceof Procedure) {
if(symbol != null && symbol instanceof Procedure) {
return (Procedure) symbol;
} else {
return null;
@ -289,19 +293,18 @@ public abstract class Scope implements Symbol {
}
public Scope getScope(ScopeRef scopeRef) {
if (scopeRef.getFullName().equals("") && this instanceof ProgramScope) {
if(scopeRef.getFullName().equals("") && this instanceof ProgramScope) {
// Special case for the outer program scope
return this;
}
Symbol symbol = getSymbol(scopeRef);
if (symbol instanceof Scope) {
if(symbol instanceof Scope) {
return (Scope) symbol;
} else {
return null;
}
}
public Procedure getProcedure(ProcedureRef ref) {
return (Procedure) getSymbol(ref);
}
@ -313,35 +316,35 @@ public abstract class Scope implements Symbol {
Set<String> names = symbols.keySet();
List<String> sortedNames = new ArrayList<>(names);
Collections.sort(sortedNames);
for (String name : sortedNames) {
for(String name : sortedNames) {
Symbol symbol = symbols.get(name);
if (symbol instanceof Scope) {
if(symbol instanceof Scope) {
res.append(((Scope) symbol).toString(program, symbolClass));
} else {
if (symbolClass == null || symbolClass.isInstance(symbol)) {
if(symbolClass == null || symbolClass.isInstance(symbol)) {
res.append(symbol.toString(program));
if (symbol instanceof Variable) {
if(symbol instanceof Variable) {
Variable var = (Variable) symbol;
String asmName = var.getAsmName();
if (asmName != null) {
if(asmName != null) {
res.append(" " + asmName);
}
Registers.Register register = var.getAllocation();
if (register != null) {
if(register != null) {
res.append(" " + register);
}
}
if (symbol instanceof Variable && registerWeights != null) {
if(symbol instanceof Variable && registerWeights != null) {
Variable var = (Variable) symbol;
Double weight = registerWeights.getWeight(var.getRef());
if (weight != null) {
if(weight != null) {
res.append(" " + weight);
}
}
if (symbol instanceof ConstantVar) {
if(symbol instanceof ConstantVar) {
ConstantVar constantVar = (ConstantVar) symbol;
String asmName = constantVar.getAsmName();
if (asmName != null) {
if(asmName != null) {
res.append(" " + asmName);
}
res.append(" = " + constantVar.getValue().toString(program));
@ -358,32 +361,27 @@ public abstract class Scope implements Symbol {
return symbols.values();
}
@Override
public void setScope(Scope scope) {
this.parentScope = scope;
}
@Override
public boolean equals(Object o) {
if (this == o) {
if(this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
if(o == null || getClass() != o.getClass()) {
return false;
}
Scope scope = (Scope) o;
if (intermediateVarCount != scope.intermediateVarCount) {
if(intermediateVarCount != scope.intermediateVarCount) {
return false;
}
if (intermediateLabelCount != scope.intermediateLabelCount) {
if(intermediateLabelCount != scope.intermediateLabelCount) {
return false;
}
if (!name.equals(scope.name)) {
if(!name.equals(scope.name)) {
return false;
}
if (!symbols.equals(scope.symbols)) {
if(!symbols.equals(scope.symbols)) {
return false;
}
return true;

View File

@ -3,7 +3,7 @@ package dk.camelot64.kickc.model;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
/** A reference to a scope */
/** A reference to a scope */
public class ScopeRef extends SymbolRef {
/** The ROOT scope of the program. */

View File

@ -23,9 +23,9 @@ public interface Statement {
String toString(Program program, boolean aliveInfo);
/** Set the index of the statement. Indexes are used during live range analysis. */
void setIndex(Integer idx);
/** Get the index of the statement. Indexes are used during live range analysis. */
Integer getIndex();
/** Set the index of the statement. Indexes are used during live range analysis. */
void setIndex(Integer idx);
}

View File

@ -97,24 +97,24 @@ public class StatementAssignment extends StatementBase implements StatementLValu
public String toString(Program program, boolean aliveInfo) {
return
super.idxString() +
lValue.toString(program) + "" +
(rValue1==null?"":rValue1.toString(program)+" ") +
(operator==null?"":operator+" ") +
lValue.toString(program) + "" +
(rValue1 == null ? "" : rValue1.toString(program) + " ") +
(operator == null ? "" : operator + " ") +
rValue2.toString(program) +
(aliveInfo?super.aliveString(program):"");
(aliveInfo ? super.aliveString(program) : "");
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
if(this == o) return true;
if(o == null || getClass() != o.getClass()) return false;
if(!super.equals(o)) return false;
StatementAssignment that = (StatementAssignment) o;
if (!lValue.equals(that.lValue)) return false;
if (rValue1 != null ? !rValue1.equals(that.rValue1) : that.rValue1 != null) return false;
if (operator != null ? !operator.equals(that.operator) : that.operator != null) return false;
if(!lValue.equals(that.lValue)) return false;
if(rValue1 != null ? !rValue1.equals(that.rValue1) : that.rValue1 != null) return false;
if(operator != null ? !operator.equals(that.operator) : that.operator != null) return false;
return rValue2 != null ? rValue2.equals(that.rValue2) : that.rValue2 == null;
}

View File

@ -3,7 +3,7 @@ package dk.camelot64.kickc.model;
import java.util.Collection;
import java.util.List;
/** Statement base class implementing shared properties and logic */
/** Statement base class implementing shared properties and logic */
public abstract class StatementBase implements Statement {
private Integer index;
@ -24,8 +24,8 @@ public abstract class StatementBase implements Statement {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if(this == o) return true;
if(o == null || getClass() != o.getClass()) return false;
StatementBase that = (StatementBase) o;
return index != null ? index.equals(that.index) : that.index == null;
}
@ -36,7 +36,7 @@ public abstract class StatementBase implements Statement {
}
public String idxString() {
return index==null?"":("["+index+"] ");
return index == null ? "" : ("[" + index + "] ");
}
@Override
@ -45,17 +45,17 @@ public abstract class StatementBase implements Statement {
}
public String aliveString(Program program) {
if(program==null || program.getLiveRangeVariables()==null) {
if(program == null || program.getLiveRangeVariables() == null) {
return "";
}
LiveRangeVariables liveRanges = program.getLiveRangeVariables();
StringBuilder alive = new StringBuilder();
alive.append(getAliveString(liveRanges.getAlive(this)));
LiveRangeVariablesEffective liveRangeVariablesEffective = program.getLiveRangeVariablesEffective();
if(liveRangeVariablesEffective!=null) {
if(liveRangeVariablesEffective != null) {
LiveRangeVariablesEffective.AliveCombinations aliveCombinations = liveRangeVariablesEffective.getAliveCombinations(this);
alive.append(" ( ");
for (LiveRangeVariablesEffective.CallPath callPath : aliveCombinations.getCallPaths().getCallPaths()) {
for(LiveRangeVariablesEffective.CallPath callPath : aliveCombinations.getCallPaths().getCallPaths()) {
alive.append(getCallPathString(callPath.getPath()));
alive.append(getAliveString(aliveCombinations.getEffectiveAliveAtStmt(callPath)));
alive.append(" ");
@ -68,7 +68,7 @@ public abstract class StatementBase implements Statement {
private String getCallPathString(List<CallGraph.CallBlock.Call> path) {
StringBuilder out = new StringBuilder();
boolean first = true;
for (CallGraph.CallBlock.Call call : path) {
for(CallGraph.CallBlock.Call call : path) {
if(!first) {
out.append("::");
}
@ -81,7 +81,7 @@ public abstract class StatementBase implements Statement {
private String getAliveString(Collection<VariableRef> alive) {
StringBuilder str = new StringBuilder();
str.append(" [ ");
for (VariableRef variableRef : alive) {
for(VariableRef variableRef : alive) {
str.append(variableRef.getFullName());
str.append(" ");
}

View File

@ -100,22 +100,22 @@ public class StatementCall extends StatementBase implements StatementLValue {
public String toString(Program program, boolean aliveInfo) {
StringBuilder res = new StringBuilder();
res.append(super.idxString());
if (lValue != null) {
if(lValue != null) {
res.append(lValue.toString(program));
res.append("");
}
res.append("call ");
if (procedure != null) {
if(procedure != null) {
res.append(procedure.getFullName() + " ");
} else {
res.append(procedureName + " ");
}
if (parameters != null) {
for (RValue parameter : parameters) {
if(parameters != null) {
for(RValue parameter : parameters) {
res.append(parameter.toString(program) + " ");
}
}
if (parametersByAssignment) {
if(parametersByAssignment) {
res.append("param-assignment");
}
if(aliveInfo) {
@ -126,16 +126,16 @@ public class StatementCall extends StatementBase implements StatementLValue {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
if(this == o) return true;
if(o == null || getClass() != o.getClass()) return false;
if(!super.equals(o)) return false;
StatementCall that = (StatementCall) o;
if (parametersByAssignment != that.parametersByAssignment) return false;
if (lValue != null ? !lValue.equals(that.lValue) : that.lValue != null) return false;
if (!procedureName.equals(that.procedureName)) return false;
if (procedure != null ? !procedure.equals(that.procedure) : that.procedure != null) return false;
if(parametersByAssignment != that.parametersByAssignment) return false;
if(lValue != null ? !lValue.equals(that.lValue) : that.lValue != null) return false;
if(!procedureName.equals(that.procedureName)) return false;
if(procedure != null ? !procedure.equals(that.procedure) : that.procedure != null) return false;
return parameters != null ? parameters.equals(that.parameters) : that.parameters == null;
}

View File

@ -10,7 +10,6 @@ import com.fasterxml.jackson.annotation.JsonProperty;
* <i> if ( Y<sub>j</sub> ) goto XX </i>
* <br>
* The condition may be a single boolean variable, or a comparison between two variables (==, &lt;&gt;, &lt;, &gt;, &lt;=, &gt;= )
*
*/
public class StatementConditionalJump extends StatementBase {
@ -53,30 +52,30 @@ public class StatementConditionalJump extends StatementBase {
return rValue1;
}
public Operator getOperator() {
return operator;
}
public RValue getrValue2() {
return rValue2;
}
public LabelRef getDestination() {
return destination;
}
public void setrValue1(RValue rValue1) {
this.rValue1 = rValue1;
}
public Operator getOperator() {
return operator;
}
public void setOperator(Operator operator) {
this.operator = operator;
}
public RValue getrValue2() {
return rValue2;
}
public void setrValue2(RValue rValue2) {
this.rValue2 = rValue2;
}
public LabelRef getDestination() {
return destination;
}
public void setDestination(LabelRef destination) {
this.destination = destination;
}
@ -86,7 +85,7 @@ public class StatementConditionalJump extends StatementBase {
StringBuilder out = new StringBuilder();
out.append(super.idxString());
out.append("if(");
if(rValue1!=null) {
if(rValue1 != null) {
out.append(rValue1.toString(program));
out.append(operator.getOperator());
}
@ -101,15 +100,15 @@ public class StatementConditionalJump extends StatementBase {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
if(this == o) return true;
if(o == null || getClass() != o.getClass()) return false;
if(!super.equals(o)) return false;
StatementConditionalJump that = (StatementConditionalJump) o;
if (rValue1 != null ? !rValue1.equals(that.rValue1) : that.rValue1 != null) return false;
if (operator != null ? !operator.equals(that.operator) : that.operator != null) return false;
if (rValue2 != null ? !rValue2.equals(that.rValue2) : that.rValue2 != null) return false;
if(rValue1 != null ? !rValue1.equals(that.rValue1) : that.rValue1 != null) return false;
if(operator != null ? !operator.equals(that.operator) : that.operator != null) return false;
if(rValue2 != null ? !rValue2.equals(that.rValue2) : that.rValue2 != null) return false;
return destination.equals(that.destination);
}

View File

@ -22,6 +22,7 @@ public class StatementInfos {
/**
* Get the label of the block containing a statement
*
* @param stmtIdx The statement index
* @return The block label
*/
@ -31,6 +32,7 @@ public class StatementInfos {
/**
* Get the label of the block containing a statement
*
* @param stmt The statement
* @return The block label
*/
@ -40,6 +42,7 @@ public class StatementInfos {
/**
* Get the block containing a statement
*
* @param stmt The statement
* @return The containing block
*/
@ -49,6 +52,7 @@ public class StatementInfos {
/**
* Get the block containing a statement
*
* @param stmtIdx The statement index
* @return The containing block
*/
@ -58,6 +62,7 @@ public class StatementInfos {
/**
* Get statement from index
*
* @param Statement index
* @return The statement with the passed index
*/

View File

@ -25,7 +25,7 @@ public class StatementJump extends StatementBase {
@Override
public String toString(Program program, boolean aliveInfo) {
return super.idxString() + "goto " + destination.getFullName()+ (aliveInfo?super.aliveString(program):"");
return super.idxString() + "goto " + destination.getFullName() + (aliveInfo ? super.aliveString(program) : "");
}
}

View File

@ -18,7 +18,7 @@ public class StatementLabel extends StatementBase {
@Override
public String toString(Program program, boolean aliveInfo) {
return super.idxString() + label.getFullName() + ":"+(aliveInfo?super.aliveString(program):"");
return super.idxString() + label.getFullName() + ":" + (aliveInfo ? super.aliveString(program) : "");
}
}

View File

@ -4,7 +4,9 @@ import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* The Phi Block initializing the necessary SSA-variables of a predecessor.
@ -38,7 +40,7 @@ public class StatementPhiBlock extends StatementBase {
@JsonIgnore
public List<VariableRef> getVariables() {
ArrayList<VariableRef> vars = new ArrayList<>();
for (PhiVariable phiVariable : phiVariables) {
for(PhiVariable phiVariable : phiVariables) {
vars.add(phiVariable.getVariable());
}
return vars;
@ -46,8 +48,8 @@ public class StatementPhiBlock extends StatementBase {
}
public PhiVariable getPhiVariable(VariableRef variable) {
for (PhiVariable phiVariable : phiVariables) {
if (phiVariable.getVariable().equals(variable)) {
for(PhiVariable phiVariable : phiVariables) {
if(phiVariable.getVariable().equals(variable)) {
return phiVariable;
}
}
@ -67,7 +69,7 @@ public class StatementPhiBlock extends StatementBase {
StringBuilder s = new StringBuilder();
List<PhiVariable> variables = new ArrayList<>(phiVariables);
Collections.reverse(variables);
if(phiVariables.size()==0) {
if(phiVariables.size() == 0) {
s.append(super.idxString());
s.append("phi()");
if(aliveInfo) {
@ -75,16 +77,16 @@ public class StatementPhiBlock extends StatementBase {
}
s.append("\n ");
}
for (PhiVariable phiVariable : variables) {
for(PhiVariable phiVariable : variables) {
s.append(super.idxString());
s.append(phiVariable.getVariable().toString(program));
s.append(" ← phi(");
for (PhiRValue phiRValue : phiVariable.getValues()) {
for(PhiRValue phiRValue : phiVariable.getValues()) {
s.append(" ");
s.append(phiRValue.getPredecessor().toString(null));
s.append("/");
RValue rValue = phiRValue.getrValue();
s.append(rValue==null?"null":rValue.toString(program));
s.append(rValue == null ? "null" : rValue.toString(program));
}
s.append(" )");
if(aliveInfo) {
@ -92,7 +94,7 @@ public class StatementPhiBlock extends StatementBase {
}
s.append("\n ");
}
if(s.length()>0) {
if(s.length() > 0) {
return s.toString().substring(0, s.length() - 3);
} else {
return s.toString();
@ -112,9 +114,9 @@ public class StatementPhiBlock extends StatementBase {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
if(this == o) return true;
if(o == null || getClass() != o.getClass()) return false;
if(!super.equals(o)) return false;
StatementPhiBlock phiBlock = (StatementPhiBlock) o;
@ -167,18 +169,17 @@ public class StatementPhiBlock extends StatementBase {
this.variable = variable;
}
public void setValues(List<PhiRValue> values) {
this.values = values;
}
public List<PhiRValue> getValues() {
return values;
}
public void setValues(List<PhiRValue> values) {
this.values = values;
}
public RValue getrValue(LabelRef predecessor) {
for (PhiRValue phiRValue : values) {
if (phiRValue.getPredecessor().equals(predecessor)) {
for(PhiRValue phiRValue : values) {
if(phiRValue.getPredecessor().equals(predecessor)) {
return phiRValue.getrValue();
}
}
@ -193,8 +194,8 @@ public class StatementPhiBlock extends StatementBase {
* @return The rValue assigned to the phi variable when entering from the passed block.
*/
public PhiRValue getPhirValue(LabelRef predecessor) {
for (PhiRValue phiRValue : values) {
if (phiRValue.getPredecessor().equals(predecessor)) {
for(PhiRValue phiRValue : values) {
if(phiRValue.getPredecessor().equals(predecessor)) {
return phiRValue;
}
}
@ -215,12 +216,12 @@ public class StatementPhiBlock extends StatementBase {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if(this == o) return true;
if(o == null || getClass() != o.getClass()) return false;
PhiVariable that = (PhiVariable) o;
if (!variable.equals(that.variable)) return false;
if(!variable.equals(that.variable)) return false;
return values.equals(that.values);
}
@ -263,6 +264,10 @@ public class StatementPhiBlock extends StatementBase {
return predecessor;
}
public void setPredecessor(LabelRef predecessor) {
this.predecessor = predecessor;
}
public RValue getrValue() {
return rValue;
}
@ -271,18 +276,14 @@ public class StatementPhiBlock extends StatementBase {
this.rValue = rValue;
}
public void setPredecessor(LabelRef predecessor) {
this.predecessor = predecessor;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if(this == o) return true;
if(o == null || getClass() != o.getClass()) return false;
PhiRValue phiRValue = (PhiRValue) o;
if (!predecessor.equals(phiRValue.predecessor)) return false;
if(!predecessor.equals(phiRValue.predecessor)) return false;
return rValue != null ? rValue.equals(phiRValue.rValue) : phiRValue.rValue == null;
}

View File

@ -7,11 +7,6 @@ public class StatementProcedureBegin extends StatementBase {
private Strategy strategy;
public static enum Strategy {
PASS_BY_REGISTER,
INLINE
}
public StatementProcedureBegin(ProcedureRef procedure) {
super(null);
this.procedure = procedure;
@ -31,7 +26,12 @@ public class StatementProcedureBegin extends StatementBase {
@Override
public String toString(Program program, boolean aliveInfo) {
return super.idxString() + "proc " + procedure.toString(program) + (aliveInfo?super.aliveString(program):"");
return super.idxString() + "proc " + procedure.toString(program) + (aliveInfo ? super.aliveString(program) : "");
}
public static enum Strategy {
PASS_BY_REGISTER,
INLINE
}
}

View File

@ -18,6 +18,6 @@ public class StatementProcedureEnd extends StatementBase {
@Override
public String toString(Program program, boolean aliveInfo) {
return super.idxString() + "endproc // " + procedure.getFullName() + "()"+(aliveInfo?super.aliveString(program):"");
return super.idxString() + "endproc // " + procedure.getFullName() + "()" + (aliveInfo ? super.aliveString(program) : "");
}
}

View File

@ -36,14 +36,14 @@ public class StatementReturn extends StatementBase {
@Override
public String toString(Program program, boolean aliveInfo) {
return super.idxString() + "return " + (value == null ? "" : value.toString(program)) + (aliveInfo?super.aliveString(program):"");
return super.idxString() + "return " + (value == null ? "" : value.toString(program)) + (aliveInfo ? super.aliveString(program) : "");
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
if(this == o) return true;
if(o == null || getClass() != o.getClass()) return false;
if(!super.equals(o)) return false;
StatementReturn that = (StatementReturn) o;

View File

@ -22,11 +22,11 @@ public class StatementSequence {
public String toString(Program program) {
StringBuffer out = new StringBuffer();
for (Statement statement : statements) {
for(Statement statement : statements) {
if(!(statement instanceof StatementLabel) && !(statement instanceof StatementProcedureBegin) && !(statement instanceof StatementProcedureEnd)) {
out.append(" ");
}
out.append(statement.toString(program, true)+"\n");
out.append(statement.toString(program, true) + "\n");
}
return out.toString();
}

View File

@ -16,10 +16,10 @@ public interface Symbol extends Value {
@JsonIgnore
Scope getScope();
void setScope(Scope scope);
@JsonIgnore
int getScopeDepth();
void setScope(Scope scope);
SymbolRef getRef();
}

View File

@ -26,10 +26,10 @@ public class SymbolRef implements Value {
@Override
public boolean equals(Object o) {
if (this == o) {
if(this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
if(o == null || getClass() != o.getClass()) {
return false;
}
@ -45,12 +45,12 @@ public class SymbolRef implements Value {
@Override
public String toString(Program program) {
if (program == null) {
if(program == null) {
return fullName;
} else {
try {
return program.getScope().getSymbol(fullName).toString(program);
} catch (NullPointerException e) {
} catch(NullPointerException e) {
throw e;
}
}
@ -60,10 +60,10 @@ public class SymbolRef implements Value {
public int getScopeDepth() {
int depth = 0;
char[] chars = fullName.toCharArray();
for (char c : chars) {
if(c==':') depth++;
for(char c : chars) {
if(c == ':') depth++;
}
return depth/2;
return depth / 2;
}
@JsonIgnore
@ -75,7 +75,7 @@ public class SymbolRef implements Value {
public boolean isIntermediate() {
if(
fullName.contains(BEGIN_BLOCK_NAME) ||
fullName.contains(END_BLOCK_NAME) ) return false;
fullName.contains(END_BLOCK_NAME)) return false;
return fullName.contains("$") || fullName.contains("@");
}
@ -87,17 +87,17 @@ public class SymbolRef implements Value {
@JsonIgnore
public String getLocalName() {
int lastScopeIdx = fullName.lastIndexOf("::");
if(lastScopeIdx==-1) {
if(lastScopeIdx == -1) {
return fullName;
} else {
return fullName.substring(lastScopeIdx+2);
return fullName.substring(lastScopeIdx + 2);
}
}
@JsonIgnore
public String getScopeNames() {
int lastScopeIdx = fullName.lastIndexOf("::");
if(lastScopeIdx==-1) {
if(lastScopeIdx == -1) {
return "";
} else {
return fullName.substring(0, lastScopeIdx);
@ -112,7 +112,7 @@ public class SymbolRef implements Value {
public String getFullNameUnversioned() {
if(isVersion()) {
return fullName.substring(0, fullName.indexOf("#"));
} else {
} else {
return fullName;
}

View File

@ -10,8 +10,8 @@ public interface SymbolType {
SymbolTypeInteger BYTE = new SymbolTypeInteger("byte", 0, 255);
/** Signed byte (8 bits). */
SymbolTypeInteger SBYTE = new SymbolTypeInteger("signed byte", -128, 127);
/** Unsigned word (2 bytes, 16 bits). */
SymbolTypeInteger WORD = new SymbolTypeInteger("word", 0, 65_535);
/** Unsigned word (2 bytes, 16 bits). */
SymbolTypeInteger WORD = new SymbolTypeInteger("word", 0, 65_535);
/** Signed word (2 bytes, 16 bits). */
SymbolTypeInteger SWORD = new SymbolTypeInteger("signed word", -32_768, 32_767);
/** String value (treated like byte* ). */
@ -27,32 +27,35 @@ public interface SymbolType {
/** An unresolved type. Will be infered later. */
SymbolTypeBasic VAR = new SymbolTypeBasic("var");
/**
* Get the name of the type
* @return The type name
*/
String getTypeName();
/**
* Get a simple symbol type from the type name.
*
* @param name The type name.
* @return The simple symbol type
*/
static SymbolType get(String name) {
switch (name) {
case "byte": return BYTE;
case "signed byte": return SBYTE;
case "word": return WORD;
case "signed word": return SWORD;
case "string": return STRING;
case "boolean": return BOOLEAN;
case "void": return VOID;
switch(name) {
case "byte":
return BYTE;
case "signed byte":
return SBYTE;
case "word":
return WORD;
case "signed word":
return SWORD;
case "string":
return STRING;
case "boolean":
return BOOLEAN;
case "void":
return VOID;
}
return null;
}
/**
* Get all integer types.
*
* @return All integeer types
*/
static Collection<SymbolTypeInteger> getIntegerTypes() {
@ -66,6 +69,7 @@ public interface SymbolType {
/**
* Is the type {@link #BYTE} or compatible {@link SymbolTypeInline}
*
* @param type The type to examine
* @return true if the type is BYTE compatible
*/
@ -81,6 +85,7 @@ public interface SymbolType {
/**
* Is the type {@link #SBYTE} or compatible {@link SymbolTypeInline}
*
* @param type The type to examine
* @return true if the type is SBYTE compatible
*/
@ -96,6 +101,7 @@ public interface SymbolType {
/**
* Is the type {@link #WORD} or compatible {@link SymbolTypeInline}
*
* @param type The type to examine
* @return true if the type is WORD compatible
*/
@ -111,6 +117,7 @@ public interface SymbolType {
/**
* Is the type {@link #SWORD} or compatible {@link SymbolTypeInline}
*
* @param type The type to examine
* @return true if the type is SWORD compatible
*/
@ -124,4 +131,11 @@ public interface SymbolType {
}
}
/**
* Get the name of the type
*
* @return The type name
*/
String getTypeName();
}

View File

@ -15,10 +15,10 @@ public class SymbolTypeBasic implements SymbolType {
@Override
public boolean equals(Object o) {
if (this == o) {
if(this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
if(o == null || getClass() != o.getClass()) {
return false;
}

View File

@ -14,8 +14,8 @@ public class SymbolTypeInference {
* Infer the type of a unary operator on a value
*
* @param programScope The program scope usable for accessing the symbol table
* @param operator The unary operator
* @param rValue The value
* @param operator The unary operator
* @param rValue The value
* @return The type of the resulting value
*/
public static SymbolType inferType(ProgramScope programScope, Operator operator, RValue rValue) {
@ -179,7 +179,7 @@ public class SymbolTypeInference {
return SymbolType.STRING;
} else if(type1.equals(SymbolType.STRING) && type2 instanceof SymbolTypeArray && SymbolType.isByte(((SymbolTypeArray) type2).getElementType())) {
return SymbolType.STRING;
} else if(type1 instanceof SymbolTypeArray && SymbolType.isByte(((SymbolTypeArray) type1).getElementType()) && type2.equals(SymbolType.STRING) ) {
} else if(type1 instanceof SymbolTypeArray && SymbolType.isByte(((SymbolTypeArray) type1).getElementType()) && type2.equals(SymbolType.STRING)) {
return SymbolType.STRING;
} else if(type1 instanceof SymbolTypeArray && type2 instanceof SymbolTypeArray) {
SymbolType elemType1 = ((SymbolTypeArray) type1).getElementType();
@ -287,7 +287,7 @@ public class SymbolTypeInference {
type = inferTypeList(symbols, (ValueList) rValue);
} else if(rValue instanceof PointerDereference) {
SymbolType pointerType = inferType(symbols, ((PointerDereference) rValue).getPointer());
if(pointerType instanceof SymbolTypePointer ) {
if(pointerType instanceof SymbolTypePointer) {
return ((SymbolTypePointer) pointerType).getElementType();
} else if(pointerType.equals(SymbolType.STRING)) {
return SymbolType.BYTE;
@ -380,7 +380,7 @@ public class SymbolTypeInference {
if(SymbolType.isByte(((SymbolTypePointer) lValueType).getElementType())) {
return true;
}
} else if(SymbolType.STRING.equals(lValueType) && rValueType instanceof SymbolTypePointer ) {
} else if(SymbolType.STRING.equals(lValueType) && rValueType instanceof SymbolTypePointer) {
if(SymbolType.isByte(((SymbolTypePointer) rValueType).getElementType())) {
return true;
}
@ -401,7 +401,7 @@ public class SymbolTypeInference {
* Determine is a list of potential inferred types contains a match for another type
*
* @param lValueType The type (rValue) we want to find a match for in the list
* @param rTypes The list of inferred potential types
* @param rTypes The list of inferred potential types
* @return true if the list has a match
*/
private static boolean typeContainsMatch(SymbolType lValueType, Collection<SymbolType> rTypes) {

View File

@ -9,6 +9,8 @@ import java.util.Collection;
*/
public class SymbolTypeInline implements SymbolType {
/** All numeric types. */
public static final SymbolTypeInline NUMERIC = new SymbolTypeInline(Arrays.asList(BYTE, SBYTE, WORD, SWORD));
/**
* All potential types for the inline constant.
*/
@ -22,15 +24,12 @@ public class SymbolTypeInline implements SymbolType {
return types;
}
/** All numeric types. */
public static final SymbolTypeInline NUMERIC = new SymbolTypeInline(Arrays.asList(BYTE, SBYTE, WORD, SWORD) );
@Override
public String getTypeName() {
StringBuilder name = new StringBuilder();
boolean first = true;
for (SymbolType type : types) {
if (first) {
for(SymbolType type : types) {
if(first) {
first = false;
} else {
name.append("/");
@ -42,10 +41,10 @@ public class SymbolTypeInline implements SymbolType {
@Override
public boolean equals(Object o) {
if (this == o) {
if(this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
if(o == null || getClass() != o.getClass()) {
return false;
}
SymbolTypeInline that = (SymbolTypeInline) o;
@ -64,6 +63,7 @@ public class SymbolTypeInline implements SymbolType {
/**
* Is unsigned byte one of the potential types
*
* @return true if unsigned byte is a potential type
*/
public boolean isByte() {
@ -72,6 +72,7 @@ public class SymbolTypeInline implements SymbolType {
/**
* Is signed byte one of the potential types
*
* @return true if signed byte is a potential type
*/
public boolean isSByte() {
@ -80,6 +81,7 @@ public class SymbolTypeInline implements SymbolType {
/**
* Is unsigned word one of the potential types
*
* @return true if unsigned word is a potential type
*/
public boolean isWord() {
@ -88,6 +90,7 @@ public class SymbolTypeInline implements SymbolType {
/**
* Is signed word one of the potential types
*
* @return true if signed word is a potential type
*/
public boolean isSWord() {

View File

@ -1,6 +1,6 @@
package dk.camelot64.kickc.model;
/** Integer symbol types (byte, signed byte, word, ...). */
/** Integer symbol types (byte, signed byte, word, ...). */
public class SymbolTypeInteger implements SymbolType {
private final String typeName;

View File

@ -26,15 +26,15 @@ public class SymbolTypePointer implements SymbolType {
@Override
@JsonIgnore
public String getTypeName() {
return elementType.getTypeName()+"*";
return elementType.getTypeName() + "*";
}
@Override
public boolean equals(Object o) {
if (this == o) {
if(this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
if(o == null || getClass() != o.getClass()) {
return false;
}

View File

@ -4,7 +4,7 @@ import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
/** A function returning another type */
/** A function returning another type */
public class SymbolTypeProcedure implements SymbolType {
private SymbolType returnType;

View File

@ -2,7 +2,7 @@ package dk.camelot64.kickc.model;
import com.fasterxml.jackson.annotation.JsonIgnore;
/** A program */
/** A program */
public class SymbolTypeProgram implements SymbolType {
public SymbolTypeProgram() {

View File

@ -21,9 +21,9 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
@JsonSubTypes.Type(value = PointerDereferenceSimple.class, name = "pointer_simple"),
@JsonSubTypes.Type(value = ProgramScope.class, name = "program"),
@JsonSubTypes.Type(value = Procedure.class, name = "procedure")
})
})
public interface Value {
String toString(Program program);
String toString(Program program);
}

View File

@ -2,10 +2,12 @@ package dk.camelot64.kickc.model;
import java.util.List;
/** A list of sub-values. Used for array variable initializers and word from byte constructors
/**
* A list of sub-values. Used for array variable initializers and word from byte constructors
* (in the future also usable for dword from byte, dword from double etc.).
* Compilation execution will resolve into a constant array,
* constant word or word constructor operator before ASM-generation. */
* constant word or word constructor operator before ASM-generation.
*/
public class ValueList implements RValue {
private List<RValue> list;
@ -23,8 +25,8 @@ public class ValueList implements RValue {
StringBuilder out = new StringBuilder();
boolean first = true;
out.append("{ ");
for (RValue constantValue : list) {
if (!first) {
for(RValue constantValue : list) {
if(!first) {
out.append(", ");
}
first = false;

Some files were not shown because too many files have changed in this diff Show More