1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-04-08 14:37:40 +00:00

Arrays of structs with arrays now working - with some minor flaws (Size of sub-array is not checked, Const Strings are output as data twice, ASM for indexing into array inside struct by pointer is not optimal). Closes "274"

This commit is contained in:
jespergravgaard 2019-09-13 01:23:55 +02:00
parent 24e40b9083
commit 8b441f6814
42 changed files with 2901 additions and 277 deletions

View File

@ -1,25 +1,32 @@
package dk.camelot64.kickc.asm;
import dk.camelot64.kickc.model.values.ConstantString;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/** A sequence of data elements to add to the ASM program. */
public class AsmDataChunk {
public interface AsmDataElement {
interface AsmDataElement {
}
/** A single numeric data element. */
public static class AsmDataNumericElement implements AsmDataElement {
/** The type of the data element. */
AsmDataNumeric.Type type;
/** The value of the data element. */
String value;
/** The string encoding used in any char/string value */
Set<ConstantString.Encoding> encoding;
public AsmDataNumericElement(AsmDataNumeric.Type type, String value) {
AsmDataNumericElement(AsmDataNumeric.Type type, String value, Set<ConstantString.Encoding> encoding) {
this.type = type;
this.value = value;
this.encoding = encoding;
}
public AsmDataNumeric.Type getType() {
@ -29,27 +36,38 @@ public class AsmDataChunk {
public String getValue() {
return value;
}
public Set<ConstantString.Encoding> getEncoding() {
return encoding;
}
}
/** A number of identical numerical data elements. */
public static class AsmDataFilledElement implements AsmDataElement {
/** The type of the element */
AsmDataNumeric.Type type;
/** The ASM specifying how many elements to fill. */
String sizeAsm;
/** The literal integer number of elements. */
int size;
/** The fill value. */
String fillValue;
/** The string encoding used in any char/string value */
Set<ConstantString.Encoding> encoding;
public AsmDataFilledElement(AsmDataNumeric.Type type, String sizeAsm, int size, String fillValue) {
AsmDataFilledElement(AsmDataNumeric.Type type, String sizeAsm, int size, String fillValue, Set<ConstantString.Encoding> encoding) {
this.type = type;
this.sizeAsm = sizeAsm;
this.size = size;
this.fillValue = fillValue;
this.encoding = encoding;
}
public AsmDataNumeric.Type getType() {
return type;
}
public String getSizeAsm() {
String getSizeAsm() {
return sizeAsm;
}
@ -57,42 +75,53 @@ public class AsmDataChunk {
return size;
}
public String getFillValue() {
String getFillValue() {
return fillValue;
}
public Set<ConstantString.Encoding> getEncoding() {
return encoding;
}
}
/** A string data elements. */
public static class AsmDataStringElement implements AsmDataElement {
/** The string value. */
String value;
/** The string encoding used in the string value */
Set<ConstantString.Encoding> encoding;
public AsmDataStringElement(String value) {
AsmDataStringElement(String value, Set<ConstantString.Encoding> encoding) {
this.value = value;
this.encoding = encoding;
}
public String getValue() {
return value;
}
public Set<ConstantString.Encoding> getEncoding() {
return encoding;
}
}
/** A sequence of data elements. */
List<AsmDataElement> elements;
private List<AsmDataElement> elements;
public AsmDataChunk() {
this.elements = new ArrayList<>();
}
public void addDataNumeric(AsmDataNumeric.Type type, String value) {
elements.add(new AsmDataNumericElement(type, value));
public void addDataNumeric(AsmDataNumeric.Type type, String value, Set<ConstantString.Encoding> encoding) {
elements.add(new AsmDataNumericElement(type, value, encoding));
}
public void addDataFilled(AsmDataNumeric.Type type, String sizeAsm, int size, String fillValue) {
elements.add(new AsmDataFilledElement(type, sizeAsm, size, fillValue));
public void addDataFilled(AsmDataNumeric.Type type, String sizeAsm, int size, String fillValue, Set<ConstantString.Encoding> encoding) {
elements.add(new AsmDataFilledElement(type, sizeAsm, size, fillValue, encoding));
}
public void addDataString(String string) {
elements.add(new AsmDataStringElement(string));
public void addDataString(String string, Set<ConstantString.Encoding> encoding) {
elements.add(new AsmDataStringElement(string, encoding));
}
public List<AsmDataElement> getElements() {
@ -104,32 +133,38 @@ public class AsmDataChunk {
* Produces 1-N ASM lines depending on the number of and types of data added.
*
* @param label The label of the data. Can be null.
* @param dataChunk The chunk of numeric data to add.
* @param asm The ASM program to add the data to
*/
public void addToAsm(String label, AsmProgram asm) {
AsmDataNumeric.Type currentNumericType = null;
List<String> currentNumericElements = null;
for(AsmDataChunk.AsmDataElement element : this.getElements()) {
if(element instanceof AsmDataFilledElement) {
if(currentNumericElements.size()>0) {
if(currentNumericElements!=null && currentNumericElements.size() > 0) {
asm.addDataNumeric(label, currentNumericType, currentNumericElements);
label = null; // Only output label once
currentNumericElements = null;
currentNumericType = null;
}
AsmDataFilledElement filledElement = (AsmDataFilledElement) element;
asm.ensureEncoding(filledElement.getEncoding());
asm.addDataFilled(label, filledElement.getType(), filledElement.getSizeAsm(), filledElement.getSize(), filledElement.getFillValue());
label = null; // Only output label once
} else if(element instanceof AsmDataStringElement) {
if(currentNumericElements.size()>0) {
} else if(element instanceof AsmDataStringElement) {
if(currentNumericElements!=null && currentNumericElements.size() > 0) {
asm.addDataNumeric(label, currentNumericType, currentNumericElements);
label = null; // Only output label once
currentNumericElements = null;
currentNumericType = null;
}
asm.addDataString(label, ((AsmDataStringElement) element).getValue());
AsmDataStringElement stringElement = (AsmDataStringElement) element;
asm.ensureEncoding(stringElement.getEncoding());
asm.addDataString(label, stringElement.getValue());
label = null; // Only output label once
} else if(element instanceof AsmDataNumericElement) {
} else if(element instanceof AsmDataNumericElement) {
AsmDataNumericElement numericElement = (AsmDataNumericElement) element;
AsmDataNumeric.Type type = numericElement.getType();
asm.ensureEncoding(numericElement.getEncoding());
if(currentNumericType == null) {
// First element - initialize current
currentNumericType = type;
@ -149,7 +184,7 @@ public class AsmDataChunk {
}
}
// Output final list if present
if(currentNumericElements!=null && currentNumericElements.size()>0) {
if(currentNumericElements != null && currentNumericElements.size() > 0) {
asm.addDataNumeric(label, currentNumericType, currentNumericElements);
}
}

View File

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

View File

@ -1,6 +1,8 @@
package dk.camelot64.kickc.asm;
import dk.camelot64.kickc.model.CompileError;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.values.ConstantString;
import dk.camelot64.kickc.model.values.ScopeRef;
import java.util.ArrayList;
@ -27,6 +29,9 @@ public class AsmProgram {
*/
private int nextLineIndex;
/** The current encoding used for printing strings. */
private ConstantString.Encoding currentEncoding = ConstantString.Encoding.SCREENCODE_MIXED;
public AsmProgram() {
this.chunks = new ArrayList<>();
this.nextLineIndex = 0;
@ -50,8 +55,31 @@ public class AsmProgram {
public void addLine(AsmLine line) {
line.setIndex(nextLineIndex++);
getCurrentChunk().addLine(line);
if(line instanceof AsmSetEncoding)
currentEncoding = ((AsmSetEncoding) line).getEncoding();
}
/**
* Get the current encoding used for strings/chars
* @return The encoding
*/
public ConstantString.Encoding getCurrentEncoding() {
return currentEncoding;
}
public void ensureEncoding(Collection<ConstantString.Encoding> encodings) {
if(encodings == null || encodings.size() == 0) return;
if(encodings.size() > 1) {
throw new CompileError("Different character encodings in one ASM statement not supported!");
}
// Size is 1 - grab it!
ConstantString.Encoding encoding = encodings.iterator().next();
if(!getCurrentEncoding().equals(encoding)) {
addLine(new AsmSetEncoding(encoding));
}
}
public void addComment(String comment, boolean isBlock) {
addLine(new AsmComment(comment, isBlock));
}

View File

@ -36,4 +36,8 @@ public class AsmSetEncoding implements AsmLine {
public void setIndex(int index) {
this.index = index;
}
public ConstantString.Encoding getEncoding() {
return encoding;
}
}

View File

@ -38,9 +38,6 @@ public class Pass4CodeGeneration {
*/
private Map<PhiTransitions.PhiTransition, Boolean> transitionsGenerated = new LinkedHashMap<>();
/** The current encoding used for printing strings. */
private ConstantString.Encoding currentEncoding = ConstantString.Encoding.SCREENCODE_MIXED;
/**
* Determines if a phi-transition has already been code-generated
*
@ -82,25 +79,25 @@ public class Pass4CodeGeneration {
asm.startChunk(currentScope, null, "File Comments");
generateComments(asm, program.getFileComments());
String outputPrgPath = new File(program.getFileName()).getName()+".prg";
String outputPrgPath = new File(program.getFileName()).getName() + ".prg";
asm.startChunk(currentScope, null, "Upstart");
Number programPc = program.getProgramPc();
if(TargetPlatform.C64BASIC.equals(program.getTargetPlatform())) {
useSegments = false;
if(programPc==null) programPc = 0x080d;
if(programPc == null) programPc = 0x080d;
asm.addLine(new AsmSetPc("Basic", AsmFormat.getAsmNumber(0x0801)));
asm.addLine(new AsmBasicUpstart("bbegin"));
asm.addLine(new AsmSetPc("Program", AsmFormat.getAsmNumber(programPc)));
} else if(TargetPlatform.ASM6502.equals(program.getTargetPlatform())) {
useSegments = false;
if(programPc==null) programPc = 0x2000;
if(programPc == null) programPc = 0x2000;
asm.addLine(new AsmSetPc("Program", AsmFormat.getAsmNumber(programPc)));
} else if(TargetPlatform.CUSTOM.equals(program.getTargetPlatform())) {
useSegments = true;
if(program.getLinkScriptBody()!=null) {
if(program.getLinkScriptBody() != null) {
asm.addLine(new AsmInlineKickAsm(program.getLinkScriptBody(), 0L, 0L));
}
if(programPc!=null) {
if(programPc != null) {
asm.addLine(new AsmSetPc("Program", AsmFormat.getAsmNumber(programPc)));
}
}
@ -455,67 +452,9 @@ public class Pass4CodeGeneration {
}
ConstantValue constantValue = constantVar.getValue();
if(constantValue instanceof ConstantArrayList) {
SymbolTypeArray constTypeArray = (SymbolTypeArray) constantVar.getType();
SymbolType elementType = constTypeArray.getElementType();
ConstantArrayList constantArrayList = (ConstantArrayList) constantValue;
if(elementType instanceof SymbolTypeStruct) {
// Constant array of structs - output each struct as a separate chunk
asm.addLabel(asmName).setDontOptimize(true);
for(ConstantValue element : constantArrayList.getElements()) {
AsmDataChunk asmDataChunk = new AsmDataChunk();
ensureEncoding(asm, element);
addChunkData(asmDataChunk, element, scopeRef);
asmDataChunk.addToAsm(null, asm);
}
// Pad output to match declared size (if larger than the data list)
int dataSize = constantArrayList.getElements().size();
Integer declaredSize = getArrayDeclaredSize(constantVar);
if(declaredSize!=null && declaredSize>dataSize) {
int padding = declaredSize - dataSize;
ConstantStructValue zeroStructValue = (ConstantStructValue) ZeroConstantValues.zeroValue(elementType, program.getScope());
for(int i=0; i<padding; i++) {
AsmDataChunk asmDataChunk = new AsmDataChunk();
addChunkData(asmDataChunk, zeroStructValue, scopeRef);
asmDataChunk.addToAsm(null, asm);
}
}
} else if(elementType instanceof SymbolTypeArray) {
// Constant array of sub-arrays
throw new InternalError("Array of array not supported");
} else {
// Constant array of a "simple" type - add to a single chunk
AsmDataChunk asmDataChunk = new AsmDataChunk();
for(ConstantValue element : constantArrayList.getElements()) {
ensureEncoding(asm, element);
addChunkData(asmDataChunk, element, scopeRef);
}
asmDataChunk.addToAsm(asmName, asm);
// Pad output to match declared size (if larger than the data list)
int dataSize = constantArrayList.getElements().size();
Integer declaredSize = getArrayDeclaredSize(constantVar);
if(declaredSize!=null && declaredSize>dataSize) {
int padding = declaredSize-dataSize;
AsmDataNumeric.Type dataType;
if(SymbolType.BYTE.equals(elementType)) {
dataType = AsmDataNumeric.Type.BYTE;
} else if(SymbolType.SBYTE.equals(elementType)) {
dataType = AsmDataNumeric.Type.BYTE;
} else if(SymbolType.WORD.equals(elementType)) {
dataType = AsmDataNumeric.Type.WORD;
} else if(SymbolType.SWORD.equals(elementType)) {
dataType = AsmDataNumeric.Type.WORD;
} else if(SymbolType.DWORD.equals(elementType)) {
dataType = AsmDataNumeric.Type.DWORD;
} else if(SymbolType.SDWORD.equals(elementType)) {
dataType = AsmDataNumeric.Type.DWORD;
} else if(elementType instanceof SymbolTypePointer) {
dataType = AsmDataNumeric.Type.WORD;
} else {
throw new InternalError("Unhandled constant array element type " + constantArrayList.toString(program));
}
asm.addDataFilled(null, dataType, Integer.toString(padding), padding, "0");
}
}
AsmDataChunk asmDataChunk = new AsmDataChunk();
addChunkData(asmDataChunk, constantValue, constantVar.getType(), scopeRef);
asmDataChunk.addToAsm(asmName, asm);
} else if(constantValue instanceof ConstantArrayFilled) {
ConstantArrayFilled constantArrayFilled = (ConstantArrayFilled) constantValue;
ConstantValue arraySize = constantArrayFilled.getSize();
@ -589,11 +528,11 @@ public class Pass4CodeGeneration {
if(((ConstantString) literal).isZeroTerminated()) {
asm.addDataNumeric(null, AsmDataNumeric.Type.BYTE, Collections.singletonList(AsmFormat.getAsmNumber(0L)));
}
int dataSize = ((ConstantString) literal).getStringLength();
// Pad output to match declared size (if larger than the data list)
Integer declaredSize = getArrayDeclaredSize(constantVar);
int dataSize = ((ConstantString) literal).getStringLength();
if(declaredSize!=null && declaredSize>dataSize) {
int padding = declaredSize-dataSize;
if(declaredSize != null && declaredSize > dataSize) {
int padding = declaredSize - dataSize;
asm.addDataFilled(null, AsmDataNumeric.Type.BYTE, Integer.toString(padding), padding, "0");
}
added.add(asmName);
@ -608,25 +547,38 @@ public class Pass4CodeGeneration {
/**
* Get the declared size of an array variable.
*
* @param constantVar The array variable
* @return The declared size. Null if the type is not array or no size is declared.
*/
private Integer getArrayDeclaredSize(ConstantVar constantVar) {
SymbolType constantType = constantVar.getType();
if(constantType instanceof SymbolTypeArray) {
RValue declaredSize = ((SymbolTypeArray) constantType).getSize();
Integer declaredSizeVal = getArrayDeclaredSize(constantType);
if(declaredSizeVal != null) return declaredSizeVal;
return null;
}
/**
* Get the declared size of an array type
*
* @param type The type
* @return The declared size. Null if the type is not array or no size is declared.
*/
private Integer getArrayDeclaredSize(SymbolType type) {
if(type instanceof SymbolTypeArray) {
RValue declaredSize = ((SymbolTypeArray) type).getSize();
if(declaredSize != null) {
if(!(declaredSize instanceof ConstantValue)) {
throw new CompileError("Error! Array declared size is not constant " + constantType.toString());
throw new CompileError("Error! Array declared size is not constant " + type.toString());
}
ConstantLiteral declaredSizeVal = ((ConstantValue) declaredSize).calculateLiteral(getScope());
if(!(declaredSizeVal instanceof ConstantInteger)) {
throw new CompileError("Error! Array declared size is not integer " + constantType.toString());
throw new CompileError("Error! Array declared size is not integer " + type.toString());
}
return ((ConstantInteger) declaredSizeVal).getInteger().intValue();
}
}
return null;
return null;
}
@ -636,25 +588,86 @@ public class Pass4CodeGeneration {
* @param dataChunk The data chunk
* @param value The constant value
*/
private void addChunkData(AsmDataChunk dataChunk, ConstantValue value, ScopeRef scopeRef) {
SymbolType elementType = value.getType(program.getScope());
if(elementType instanceof SymbolTypeStruct) {
private void addChunkData(AsmDataChunk dataChunk, ConstantValue value, SymbolType valueType, ScopeRef scopeRef) {
if(valueType instanceof SymbolTypeStruct) {
// Add each struct member recursively
ConstantStructValue structValue = (ConstantStructValue) value;
for(VariableRef memberRef : structValue.getMembers()) {
ConstantValue memberValue = structValue.getValue(memberRef);
addChunkData(dataChunk, memberValue, scopeRef);
Variable memberVariable = getScope().getVariable(memberRef);
addChunkData(dataChunk, memberValue, memberVariable.getType(), scopeRef);
}
} else if(SymbolType.BYTE.equals(elementType) || SymbolType.SBYTE.equals(elementType)) {
dataChunk.addDataNumeric(AsmDataNumeric.Type.BYTE, AsmFormat.getAsmConstant(program, value, 99, scopeRef));
} else if(SymbolType.WORD.equals(elementType) || SymbolType.SWORD.equals(elementType)) {
dataChunk.addDataNumeric(AsmDataNumeric.Type.WORD, AsmFormat.getAsmConstant(program, value, 99, scopeRef));
} else if(SymbolType.DWORD.equals(elementType) || SymbolType.SDWORD.equals(elementType)) {
dataChunk.addDataNumeric(AsmDataNumeric.Type.DWORD, AsmFormat.getAsmConstant(program, value, 99, scopeRef));
} else if(elementType instanceof SymbolTypePointer) {
dataChunk.addDataNumeric(AsmDataNumeric.Type.WORD, AsmFormat.getAsmConstant(program, value, 99, scopeRef));
} else if(valueType instanceof SymbolTypeArray) {
SymbolTypeArray constTypeArray = (SymbolTypeArray) valueType;
SymbolType elementType = constTypeArray.getElementType();
SymbolType dataType = value.getType(program.getScope());
int dataSize = 0;
if(dataType.equals(SymbolType.STRING)) {
try {
ConstantLiteral literal = value.calculateLiteral(getScope());
if(literal instanceof ConstantString) {
// Ensure encoding is good
String asmConstant = AsmFormat.getAsmConstant(program, literal, 99, scopeRef);
dataChunk.addDataString(asmConstant, getEncoding(literal));
if(((ConstantString) literal).isZeroTerminated()) {
dataChunk.addDataNumeric(AsmDataNumeric.Type.BYTE, "0", null);
}
dataSize = ((ConstantString) literal).getStringLength();
}
} catch(ConstantNotLiteral e) {
// can't calculate literal value, so it is not data - just return
}
} else {
ConstantArrayList constantArrayList = (ConstantArrayList) value;
// Output each element to the chunk
for(ConstantValue element : constantArrayList.getElements()) {
addChunkData(dataChunk, element, elementType, scopeRef);
}
dataSize = constantArrayList.getElements().size();
}
// Pad output to match declared size (if larger than the data list)
Integer declaredSize = getArrayDeclaredSize(valueType);
if(declaredSize != null && declaredSize > dataSize) {
int padding = declaredSize - dataSize;
ConstantValue zeroValue = ZeroConstantValues.zeroValue(elementType, program.getScope());
if(zeroValue instanceof ConstantInteger) {
dataChunk.addDataFilled(getNumericType(elementType), AsmFormat.getAsmNumber(padding), padding, AsmFormat.getAsmConstant(program, zeroValue, 99, scopeRef), getEncoding(zeroValue));
} else {
for(int i = 0; i < padding; i++) {
addChunkData(dataChunk, zeroValue, elementType, scopeRef);
}
}
}
} else if(SymbolType.BYTE.equals(valueType) || SymbolType.SBYTE.equals(valueType)) {
dataChunk.addDataNumeric(AsmDataNumeric.Type.BYTE, AsmFormat.getAsmConstant(program, value, 99, scopeRef), getEncoding(value));
} else if(SymbolType.WORD.equals(valueType) || SymbolType.SWORD.equals(valueType)) {
dataChunk.addDataNumeric(AsmDataNumeric.Type.WORD, AsmFormat.getAsmConstant(program, value, 99, scopeRef), getEncoding(value));
} else if(SymbolType.DWORD.equals(valueType) || SymbolType.SDWORD.equals(valueType)) {
dataChunk.addDataNumeric(AsmDataNumeric.Type.DWORD, AsmFormat.getAsmConstant(program, value, 99, scopeRef), getEncoding(value));
} else if(valueType instanceof SymbolTypePointer) {
dataChunk.addDataNumeric(AsmDataNumeric.Type.WORD, AsmFormat.getAsmConstant(program, value, 99, scopeRef), getEncoding(value));
} else {
throw new InternalError("Unhandled array element type " + elementType.toString() + " value " + value.toString(program));
throw new InternalError("Unhandled array element type " + valueType.toString() + " value " + value.toString(program));
}
}
/**
* Get the numeric data type to use when outputting a value type to ASM
* @param valueType The value type
* @return The numeric data type
*/
private static AsmDataNumeric.Type getNumericType(SymbolType valueType) {
if(SymbolType.BYTE.equals(valueType) || SymbolType.SBYTE.equals(valueType)) {
return AsmDataNumeric.Type.BYTE;
} else if(SymbolType.WORD.equals(valueType) || SymbolType.SWORD.equals(valueType)) {
return AsmDataNumeric.Type.WORD;
} else if(SymbolType.DWORD.equals(valueType) || SymbolType.SDWORD.equals(valueType)) {
return AsmDataNumeric.Type.DWORD;
} else if(valueType instanceof SymbolTypePointer) {
return AsmDataNumeric.Type.WORD;
} else {
throw new InternalError("Unhandled type " + valueType.toString());
}
}
@ -693,13 +706,13 @@ public class Pass4CodeGeneration {
generateStatementAsm(asm, block, statement, aluState, true);
} catch(AsmFragmentTemplateSynthesizer.UnknownFragmentException e) {
if(warnFragmentMissing) {
program.getLog().append("Warning! Unknown fragment for statement " + statement.toString(program, false) + "\nMissing ASM fragment " + e.getFragmentSignature()+"\n"+statement.getSource().toString());
asm.addLine(new AsmInlineKickAsm(".assert \"Missing ASM fragment "+ e.getFragmentSignature()+"\", 0, 1", 0L, 0L));
} else {
program.getLog().append("Warning! Unknown fragment for statement " + statement.toString(program, false) + "\nMissing ASM fragment " + e.getFragmentSignature() + "\n" + statement.getSource().toString());
asm.addLine(new AsmInlineKickAsm(".assert \"Missing ASM fragment " + e.getFragmentSignature() + "\", 0, 1", 0L, 0L));
} else {
throw new CompileError("Unknown fragment for statement " + statement.toString(program, false) + "\nMissing ASM fragment " + e.getFragmentSignature(), statement.getSource());
}
} catch(CompileError e) {
if(e.getSource()==null) {
if(e.getSource() == null) {
throw new CompileError(e.getMessage(), statement);
}
}
@ -716,7 +729,7 @@ public class Pass4CodeGeneration {
* @param aluState State of the special ALU register. Used to generate composite fragments when two consecutive statements can be executed effectively.
* For example ADC $1100,x combines two statements $0 = $1100 staridx X, A = A+$0 .
*/
public void generateStatementAsm(AsmProgram asm, ControlFlowBlock block, Statement statement, AsmCodegenAluState aluState, boolean genCallPhiEntry) {
void generateStatementAsm(AsmProgram asm, ControlFlowBlock block, Statement statement, AsmCodegenAluState aluState, boolean genCallPhiEntry) {
asm.startChunk(block.getScope(), statement.getIndex(), statement.toString(program, verboseAliveInfo));
generateComments(asm, statement.getComments());
@ -1068,31 +1081,12 @@ public class Pass4CodeGeneration {
* @param asm The ASM program (where any .encoding directive will be emitted)
* @param asmFragmentInstance The ASM fragment to be emitted
*/
private void ensureEncoding(AsmProgram asm, AsmFragmentInstanceSpecFactory asmFragmentInstance) {
ensureEncoding(asm, getEncoding(asmFragmentInstance));
private static void ensureEncoding(AsmProgram asm, AsmFragmentInstanceSpecFactory asmFragmentInstance) {
asm.ensureEncoding(getEncoding(asmFragmentInstance));
}
private void ensureEncoding(AsmProgram asm, Value value) {
ensureEncoding(asm, getEncoding(value));
}
/**
* Ensure that the current encoding in the ASM matches any encoding in the data to be emitted
*
* @param asm The ASM program (where any .encoding directive will be emitted)
* @param encodings The encodings to ensure
*/
private void ensureEncoding(AsmProgram asm, Collection<ConstantString.Encoding> encodings) {
if(encodings == null || encodings.size() == 0) return;
if(encodings.size() > 1) {
throw new CompileError("Different character encodings in one ASM statement not supported!");
}
// Size is 1 - grab it!
ConstantString.Encoding encoding = encodings.iterator().next();
if(!currentEncoding.equals(encoding)) {
asm.addLine(new AsmSetEncoding(encoding));
currentEncoding = encoding;
}
private static void ensureEncoding(AsmProgram asm, Value value) {
asm.ensureEncoding(getEncoding(value));
}
/**
@ -1101,7 +1095,7 @@ public class Pass4CodeGeneration {
* @param value The constant to examine
* @return Any encoding found inside the constant
*/
private Set<ConstantString.Encoding> getEncoding(Value value) {
private static Set<ConstantString.Encoding> getEncoding(Value value) {
LinkedHashSet<ConstantString.Encoding> encodings = new LinkedHashSet<>();
ProgramValue programValue = new ProgramValue.GenericValue(value);
ProgramValueHandler handler = (ProgramValue pVal, Statement currentStmt, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock) -> {
@ -1123,7 +1117,7 @@ public class Pass4CodeGeneration {
* @param asmFragmentInstance The asm fragment instance to examine
* @return Any encoding found inside the constant
*/
private Set<ConstantString.Encoding> getEncoding(AsmFragmentInstanceSpecFactory asmFragmentInstance) {
private static Set<ConstantString.Encoding> getEncoding(AsmFragmentInstanceSpecFactory asmFragmentInstance) {
LinkedHashSet<ConstantString.Encoding> encodings = new LinkedHashSet<>();
Map<String, Value> bindings = asmFragmentInstance.getBindings();
for(Value boundValue : bindings.values()) {

View File

@ -58,12 +58,13 @@ public class TestPrograms {
}
*/
/** Fix number type resolving https://gitlab.com/camelot/kickc/issues/199
@Test
public void testConstBool0() throws IOException, URISyntaxException {
compileAndCompare("const-bool-0");
}
*/
/**
* Fix number type resolving https://gitlab.com/camelot/kickc/issues/199
*
* @Test public void testConstBool0() throws IOException, URISyntaxException {
* compileAndCompare("const-bool-0");
* }
*/
@Test
public void testAsmCullingJmp() throws IOException, URISyntaxException {
@ -654,22 +655,20 @@ public class TestPrograms {
}
*/
// TODO: FIX problem with initializers of array-elements inside structs
//@Test
//public void testStructPtr33() throws IOException, URISyntaxException {
// compileAndCompare("struct-ptr-33", log());
//}
@Test
public void testStructPtr33() throws IOException, URISyntaxException {
compileAndCompare("struct-ptr-33", log());
}
@Test
public void testStructPtr32() throws IOException, URISyntaxException {
compileAndCompare("struct-ptr-32");
}
//@Test
//public void testStructPtr31() throws IOException, URISyntaxException {
// compileAndCompare("struct-ptr-31");
//}
@Test
public void testStructPtr31() throws IOException, URISyntaxException {
compileAndCompare("struct-ptr-31");
}
@Test
public void testStructPtr30() throws IOException, URISyntaxException {
@ -702,12 +701,10 @@ public class TestPrograms {
compileAndCompare("struct-ptr-24");
}
/* TODO: Fix array of struct containing array https://gitlab.com/camelot/kickc/issues/274
@Test
public void testStructPtr23() throws IOException, URISyntaxException {
compileAndCompare("struct-ptr-23");
compileAndCompare("struct-ptr-23", log());
}
*/
@Test
public void testStructPtr22() throws IOException, URISyntaxException {

View File

@ -1,15 +1,13 @@
// Example of a struct containing an array
// Currently fails when put into an array itself
struct Person {
char id;
char[2] initials;
char[4] initials;
};
struct Person[] persons =
{ { 1, "jg" },
{ 8, "hg" }
{ { 1, "jgr" },
{ 8, "hbg" }
};
void main() {
@ -27,5 +25,6 @@ void print_person(struct Person *person) {
SCREEN[idx++] = ' ';
SCREEN[idx++] = person->initials[0];
SCREEN[idx++] = person->initials[1];
SCREEN[idx++] = person->initials[2];
SCREEN[idx++] = ' ';
}

View File

@ -1,7 +1,4 @@
// Example of a struct containing an array
// Fails with an exception because the initializers do not work properly - and the memory layout is wrong
// https://gitlab.com/camelot/kickc/issues/274
// https://gitlab.com/camelot/kickc/issues/312
struct Person {
char id;

View File

@ -1,5 +1,4 @@
// Example of a struct containing an array
// https://gitlab.com/camelot/kickc/issues/312
struct Person {
char id;

View File

@ -1,6 +1,4 @@
// Example of a struct containing an array
// Fails (by displaying "BB" ) because the memory layout is wrong - and the name is treated like a pointer (to 0x0000) instead of a value.
// https://gitlab.com/camelot/kickc/issues/312
struct Person {
char id;
@ -16,9 +14,9 @@ struct Person[2] persons = {
void main() {
const char* SCREEN = 0x0400;
struct Person* person = persons;
SCREEN[0] = person->name[8];
SCREEN[0] = person->name[2];
person++;
SCREEN[1] = person->name[8];
SCREEN[1] = person->name[2];
}

View File

@ -30,4 +30,4 @@ main: {
.byte 0
.fill 8, 0
msg2: .byte 'c', 'm', 'l'
.fill 13, 0
.fill $d, 0

View File

@ -300,7 +300,7 @@ main: {
.byte 0
.fill 8, 0
msg2: .byte 'c', 'm', 'l'
.fill 13, 0
.fill $d, 0
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [6] if((byte) 0!=*((const byte[$10]) msg1#0 + (byte) main::i#2)) goto main::@2 [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte a
@ -405,7 +405,7 @@ main: {
.byte 0
.fill 8, 0
msg2: .byte 'c', 'm', 'l'
.fill 13, 0
.fill $d, 0
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b1
@ -533,5 +533,5 @@ main: {
.byte 0
.fill 8, 0
msg2: .byte 'c', 'm', 'l'
.fill 13, 0
.fill $d, 0

View File

@ -1360,8 +1360,7 @@ mulf_init: {
.align $100
mulf_sqr2_hi: .fill $200, 0
// True type letter c
letter_c:
.byte MOVE_TO
letter_c: .byte MOVE_TO
.word $6c, $92, 0, 0
.byte SPLINE_TO
.word $59, $b6, $67, $a9

View File

@ -8825,8 +8825,7 @@ mulf_init: {
.align $100
mulf_sqr2_hi: .fill $200, 0
// True type letter c
letter_c:
.byte MOVE_TO
letter_c: .byte MOVE_TO
.word $6c, $92, 0, 0
.byte SPLINE_TO
.word $59, $b6, $67, $a9
@ -11889,8 +11888,7 @@ mulf_init: {
.align $100
mulf_sqr2_hi: .fill $200, 0
// True type letter c
letter_c:
.byte MOVE_TO
letter_c: .byte MOVE_TO
.word $6c, $92, 0, 0
.byte SPLINE_TO
.word $59, $b6, $67, $a9
@ -15018,8 +15016,7 @@ mulf_init: {
.align $100
mulf_sqr2_hi: .fill $200, 0
// True type letter c
letter_c:
.byte MOVE_TO
letter_c: .byte MOVE_TO
.word $6c, $92, 0, 0
.byte SPLINE_TO
.word $59, $b6, $67, $a9

View File

@ -137,15 +137,12 @@ syscall1: {
MESSAGE: .text "hello world!"
.byte 0
.segment Syscall
SYSCALLS:
.byte JMP
SYSCALLS: .byte JMP
.word syscall1
.byte NOP
.byte JMP
.byte NOP, JMP
.word syscall2
.byte NOP
.align $100
SYSCALL_RESET:
.byte JMP
SYSCALL_RESET: .byte JMP
.word main
.byte NOP

View File

@ -867,16 +867,13 @@ syscall1: {
MESSAGE: .text "hello world!"
.byte 0
.segment Syscall
SYSCALLS:
.byte JMP
SYSCALLS: .byte JMP
.word syscall1
.byte NOP
.byte JMP
.byte NOP, JMP
.word syscall2
.byte NOP
.align $100
SYSCALL_RESET:
.byte JMP
SYSCALL_RESET: .byte JMP
.word main
.byte NOP
@ -1178,16 +1175,13 @@ syscall1: {
MESSAGE: .text "hello world!"
.byte 0
.segment Syscall
SYSCALLS:
.byte JMP
SYSCALLS: .byte JMP
.word syscall1
.byte NOP
.byte JMP
.byte NOP, JMP
.word syscall2
.byte NOP
.align $100
SYSCALL_RESET:
.byte JMP
SYSCALL_RESET: .byte JMP
.word main
.byte NOP
@ -1531,16 +1525,13 @@ syscall1: {
MESSAGE: .text "hello world!"
.byte 0
.segment Syscall
SYSCALLS:
.byte JMP
SYSCALLS: .byte JMP
.word syscall1
.byte NOP
.byte JMP
.byte NOP, JMP
.word syscall2
.byte NOP
.align $100
SYSCALL_RESET:
.byte JMP
SYSCALL_RESET: .byte JMP
.word main
.byte NOP

View File

@ -26,7 +26,4 @@ main: {
bne b1
rts
}
points:
.byte 1, 2
.byte 3, 4
.byte 5, 6
points: .byte 1, 2, 3, 4, 5, 6

View File

@ -301,10 +301,7 @@ main: {
rts
}
// File Data
points:
.byte 1, 2
.byte 3, 4
.byte 5, 6
points: .byte 1, 2, 3, 4, 5, 6
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [6] (byte~) main::$2 ← (byte) main::i#2 << (byte) 1 [ main::i#2 main::idx#3 main::$2 ] ( main:2 [ main::i#2 main::idx#3 main::$2 ] ) always clobbers reg byte a
@ -405,10 +402,7 @@ main: {
rts
}
// File Data
points:
.byte 1, 2
.byte 3, 4
.byte 5, 6
points: .byte 1, 2, 3, 4, 5, 6
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b1
@ -530,8 +524,5 @@ main: {
rts
}
// File Data
points:
.byte 1, 2
.byte 3, 4
.byte 5, 6
points: .byte 1, 2, 3, 4, 5, 6

View File

@ -38,8 +38,7 @@ main: {
bne b1
rts
}
points:
.byte 1
points: .byte 1
.word 2
.byte 3
.word 4

View File

@ -365,8 +365,7 @@ main: {
rts
}
// File Data
points:
.byte 1
points: .byte 1
.word 2
.byte 3
.word 4
@ -509,8 +508,7 @@ main: {
rts
}
// File Data
points:
.byte 1
points: .byte 1
.word 2
.byte 3
.word 4
@ -665,8 +663,7 @@ main: {
rts
}
// File Data
points:
.byte 1
points: .byte 1
.word 2
.byte 3
.word 4

View File

@ -42,7 +42,4 @@ main: {
!:
jmp b1
}
settings:
.byte 0, 'a'
.byte 1, 'b'
.byte 0, 'c'
settings: .byte 0, 'a', 1, 'b', 0, 'c'

View File

@ -383,10 +383,7 @@ main: {
jmp b1
}
// File Data
settings:
.byte 0, 'a'
.byte 1, 'b'
.byte 0, 'c'
settings: .byte 0, 'a', 1, 'b', 0, 'c'
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [6] if((struct Setting*) main::setting#2<(const struct Setting[]) settings#0+(const byte) main::len#0*(const byte) SIZEOF_STRUCT_SETTING) goto main::@2 [ main::setting#2 main::idx#2 ] ( main:2 [ main::setting#2 main::idx#2 ] ) always clobbers reg byte a
@ -506,10 +503,7 @@ main: {
jmp b1
}
// File Data
settings:
.byte 0, 'a'
.byte 1, 'b'
.byte 0, 'c'
settings: .byte 0, 'a', 1, 'b', 0, 'c'
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b1
@ -655,8 +649,5 @@ main: {
jmp b1
}
// File Data
settings:
.byte 0, 'a'
.byte 1, 'b'
.byte 0, 'c'
settings: .byte 0, 'a', 1, 'b', 0, 'c'

View File

@ -27,6 +27,5 @@ main: {
jmp b1
}
seq: .word 1, 2, 3
settings:
.byte 3
settings: .byte 3
.word seq

View File

@ -319,8 +319,7 @@ main: {
}
// File Data
seq: .word 1, 2, 3
settings:
.byte 3
settings: .byte 3
.word seq
REGISTER UPLIFT POTENTIAL REGISTERS
@ -410,8 +409,7 @@ main: {
}
// File Data
seq: .word 1, 2, 3
settings:
.byte 3
settings: .byte 3
.word seq
ASSEMBLER OPTIMIZATIONS
@ -523,7 +521,6 @@ main: {
}
// File Data
seq: .word 1, 2, 3
settings:
.byte 3
settings: .byte 3
.word seq

View File

@ -0,0 +1,76 @@
// Example of a struct containing an array
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.const SIZEOF_STRUCT_PERSON = 5
.const OFFSET_STRUCT_PERSON_INITIALS = 1
.label SCREEN = $400
main: {
.label person = persons+SIZEOF_STRUCT_PERSON
ldx #0
lda #<persons
sta.z print_person.person
lda #>persons
sta.z print_person.person+1
jsr print_person
lda #<person
sta.z print_person.person
lda #>person
sta.z print_person.person+1
jsr print_person
rts
}
// print_person(struct Person* zeropage(2) person)
print_person: {
.label _3 = 4
.label _4 = 2
.label person = 2
lda #'0'
clc
ldy #0
adc (person),y
sta SCREEN,x
inx
lda #' '
sta SCREEN,x
inx
ldy #OFFSET_STRUCT_PERSON_INITIALS
lda (person),y
sta SCREEN,x
inx
tya
clc
adc.z person
sta.z _3
lda #0
adc.z person+1
sta.z _3+1
ldy #1
lda (_3),y
sta SCREEN,x
inx
lda #OFFSET_STRUCT_PERSON_INITIALS
clc
adc.z _4
sta.z _4
bcc !+
inc.z _4+1
!:
ldy #2
lda (_4),y
sta SCREEN,x
inx
lda #' '
sta SCREEN,x
inx
rts
}
_0: .text "jgr"
.byte 0
_1: .text "hbg"
.byte 0
persons: .byte 1
.text "jgr"
.byte 0, 8
.text "hbg"
.byte 0

View File

@ -0,0 +1,42 @@
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
main: scope:[main] from @1
[4] phi()
[5] call print_person
to:main::@1
main::@1: scope:[main] from main
[6] phi()
[7] call print_person
to:main::@return
main::@return: scope:[main] from main::@1
[8] return
to:@return
print_person: scope:[print_person] from main main::@1
[9] (byte) idx#15 ← phi( main/(byte) 0 main::@1/(byte) idx#10 )
[9] (struct Person*) print_person::person#2 ← phi( main/(const struct Person[]) persons#0 main::@1/(const struct Person*) main::person#1 )
[10] (byte~) print_person::$0 ← (byte) '0' + *((byte*)(struct Person*) print_person::person#2)
[11] *((const byte*) SCREEN#0 + (byte) idx#15) ← (byte~) print_person::$0
[12] (byte) idx#4 ← ++ (byte) idx#15
[13] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' '
[14] (byte) idx#5 ← ++ (byte) idx#4
[15] *((const byte*) SCREEN#0 + (byte) idx#5) ← *((byte[4])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_INITIALS)
[16] (byte) idx#6 ← ++ (byte) idx#5
[17] (byte[4]) print_person::$3 ← (byte[4])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_INITIALS
[18] *((const byte*) SCREEN#0 + (byte) idx#6) ← *((byte[4]) print_person::$3 + (byte) 1)
[19] (byte) idx#7 ← ++ (byte) idx#6
[20] (byte[4]) print_person::$4 ← (byte[4])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_INITIALS
[21] *((const byte*) SCREEN#0 + (byte) idx#7) ← *((byte[4]) print_person::$4 + (byte) 2)
[22] (byte) idx#8 ← ++ (byte) idx#7
[23] *((const byte*) SCREEN#0 + (byte) idx#8) ← (byte) ' '
[24] (byte) idx#10 ← ++ (byte) idx#8
to:print_person::@return
print_person::@return: scope:[print_person] from print_person
[25] return
to:@return

View File

@ -0,0 +1,906 @@
Fixing struct type size struct Person to 5
Fixing struct type size struct Person to 5
Fixing struct type size struct Person to 5
Fixing pointer increment (struct Person*) main::person ← ++ (struct Person*) main::person
Rewriting struct pointer member access *((struct Person*) print_person::person).id
Rewriting struct pointer member access *((struct Person*) print_person::person).initials
Rewriting struct pointer member access *((struct Person*) print_person::person).initials
Rewriting struct pointer member access *((struct Person*) print_person::person).initials
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
(struct Person[]) persons#0 ← { { (number) 1, (const string) $0 }, { (number) 8, (const string) $1 } }
to:@1
main: scope:[main] from @2
(byte) idx#18 ← phi( @2/(byte) idx#19 )
(struct Person*) main::person#0 ← (struct Person[]) persons#0
(struct Person*) print_person::person#0 ← (struct Person*) main::person#0
call print_person
to:main::@1
main::@1: scope:[main] from main
(struct Person*) main::person#2 ← phi( main/(struct Person*) main::person#0 )
(byte) idx#12 ← phi( main/(byte) idx#10 )
(byte) idx#0 ← (byte) idx#12
(struct Person*) main::person#1 ← (struct Person*) main::person#2 + (const byte) SIZEOF_STRUCT_PERSON
(struct Person*) print_person::person#1 ← (struct Person*) main::person#1
call print_person
to:main::@2
main::@2: scope:[main] from main::@1
(byte) idx#13 ← phi( main::@1/(byte) idx#10 )
(byte) idx#1 ← (byte) idx#13
to:main::@return
main::@return: scope:[main] from main::@2
(byte) idx#14 ← phi( main::@2/(byte) idx#1 )
(byte) idx#2 ← (byte) idx#14
return
to:@return
@1: scope:[] from @begin
(byte*) SCREEN#0 ← ((byte*)) (number) $400
(byte) idx#3 ← (number) 0
to:@2
print_person: scope:[print_person] from main main::@1
(byte) idx#15 ← phi( main/(byte) idx#18 main::@1/(byte) idx#0 )
(struct Person*) print_person::person#2 ← phi( main/(struct Person*) print_person::person#0 main::@1/(struct Person*) print_person::person#1 )
(byte*) print_person::$1 ← (byte*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_ID
(byte~) print_person::$0 ← (byte) '0' + *((byte*) print_person::$1)
*((byte*) SCREEN#0 + (byte) idx#15) ← (byte~) print_person::$0
(byte) idx#4 ← ++ (byte) idx#15
*((byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' '
(byte) idx#5 ← ++ (byte) idx#4
(byte[4]) print_person::$2 ← (byte[4])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_INITIALS
*((byte*) SCREEN#0 + (byte) idx#5) ← *((byte[4]) print_person::$2 + (number) 0)
(byte) idx#6 ← ++ (byte) idx#5
(byte[4]) print_person::$3 ← (byte[4])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_INITIALS
*((byte*) SCREEN#0 + (byte) idx#6) ← *((byte[4]) print_person::$3 + (number) 1)
(byte) idx#7 ← ++ (byte) idx#6
(byte[4]) print_person::$4 ← (byte[4])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_INITIALS
*((byte*) SCREEN#0 + (byte) idx#7) ← *((byte[4]) print_person::$4 + (number) 2)
(byte) idx#8 ← ++ (byte) idx#7
*((byte*) SCREEN#0 + (byte) idx#8) ← (byte) ' '
(byte) idx#9 ← ++ (byte) idx#8
to:print_person::@return
print_person::@return: scope:[print_person] from print_person
(byte) idx#16 ← phi( print_person/(byte) idx#9 )
(byte) idx#10 ← (byte) idx#16
return
to:@return
@2: scope:[] from @1
(byte) idx#19 ← phi( @1/(byte) idx#3 )
call main
to:@3
@3: scope:[] from @2
(byte) idx#17 ← phi( @2/(byte) idx#2 )
(byte) idx#11 ← (byte) idx#17
to:@end
@end: scope:[] from @3
SYMBOL TABLE SSA
(const string) $0 = (string) "jgr"
(const string) $1 = (string) "hbg"
(label) @1
(label) @2
(label) @3
(label) @begin
(label) @end
(const byte) OFFSET_STRUCT_PERSON_ID = (byte) 0
(const byte) OFFSET_STRUCT_PERSON_INITIALS = (byte) 1
(byte) Person::id
(byte[4]) Person::initials
(byte*) SCREEN
(byte*) SCREEN#0
(const byte) SIZEOF_STRUCT_PERSON = (byte) 5
(byte) idx
(byte) idx#0
(byte) idx#1
(byte) idx#10
(byte) idx#11
(byte) idx#12
(byte) idx#13
(byte) idx#14
(byte) idx#15
(byte) idx#16
(byte) idx#17
(byte) idx#18
(byte) idx#19
(byte) idx#2
(byte) idx#3
(byte) idx#4
(byte) idx#5
(byte) idx#6
(byte) idx#7
(byte) idx#8
(byte) idx#9
(void()) main()
(label) main::@1
(label) main::@2
(label) main::@return
(struct Person*) main::person
(struct Person*) main::person#0
(struct Person*) main::person#1
(struct Person*) main::person#2
(struct Person[]) persons
(struct Person[]) persons#0
(void()) print_person((struct Person*) print_person::person)
(byte~) print_person::$0
(byte*) print_person::$1
(byte[4]) print_person::$2
(byte[4]) print_person::$3
(byte[4]) print_person::$4
(label) print_person::@return
(struct Person*) print_person::person
(struct Person*) print_person::person#0
(struct Person*) print_person::person#1
(struct Person*) print_person::person#2
Adding number conversion cast (unumber) 0 in (byte) idx#3 ← (number) 0
Adding number conversion cast (unumber) 0 in *((byte*) SCREEN#0 + (byte) idx#5) ← *((byte[4]) print_person::$2 + (number) 0)
Adding number conversion cast (unumber) 1 in *((byte*) SCREEN#0 + (byte) idx#6) ← *((byte[4]) print_person::$3 + (number) 1)
Adding number conversion cast (unumber) 2 in *((byte*) SCREEN#0 + (byte) idx#7) ← *((byte[4]) print_person::$4 + (number) 2)
Successful SSA optimization PassNAddNumberTypeConversions
Added casts to value list in (struct Person[]) persons#0 ← (struct Person[]){ (struct Person){ (byte)(number) 1, (const string) $0 }, (struct Person){ (byte)(number) 8, (const string) $1 } }
Successful SSA optimization PassNAddInitializerValueListTypeCasts
Inlining cast (byte*) SCREEN#0 ← (byte*)(number) $400
Inlining cast (byte) idx#3 ← (unumber)(number) 0
Successful SSA optimization Pass2InlineCast
Simplifying constant integer cast 1
Simplifying constant integer cast 8
Simplifying constant pointer cast (byte*) 1024
Simplifying constant integer cast 0
Simplifying constant integer cast 0
Simplifying constant integer cast 1
Simplifying constant integer cast 2
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 0
Finalized unsigned number type (byte) 0
Finalized unsigned number type (byte) 1
Finalized unsigned number type (byte) 2
Successful SSA optimization PassNFinalizeNumberTypeConversions
Alias (struct Person*) main::person#0 = (struct Person*) main::person#2
Alias (byte) idx#0 = (byte) idx#12
Alias (byte) idx#1 = (byte) idx#13 (byte) idx#14 (byte) idx#2
Alias (byte) idx#10 = (byte) idx#16 (byte) idx#9
Alias (byte) idx#19 = (byte) idx#3
Alias (byte) idx#11 = (byte) idx#17
Successful SSA optimization Pass2AliasElimination
Identical Phi Values (byte) idx#18 (byte) idx#19
Identical Phi Values (byte) idx#0 (byte) idx#10
Identical Phi Values (byte) idx#1 (byte) idx#10
Identical Phi Values (byte) idx#11 (byte) idx#1
Successful SSA optimization Pass2IdenticalPhiElimination
Identified constant from value list (struct Person) { id: (byte) 1, initials: (const string) $0 }
Identified constant from value list (struct Person) { id: (byte) 8, initials: (const string) $1 }
Successful SSA optimization Pass2ConstantInitializerValueLists
Identified constant from value list (struct Person[]) { { id: (byte) 1, initials: (const string) $0 }, { id: (byte) 8, initials: (const string) $1 } }
Successful SSA optimization Pass2ConstantInitializerValueLists
Constant (const struct Person[]) persons#0 = { { id: 1, initials: $0 }, { id: 8, initials: $1 } }
Constant (const byte*) SCREEN#0 = (byte*) 1024
Constant (const byte) idx#19 = 0
Successful SSA optimization Pass2ConstantIdentification
Constant (const struct Person*) main::person#0 = persons#0
Successful SSA optimization Pass2ConstantIdentification
Constant (const struct Person*) print_person::person#0 = main::person#0
Successful SSA optimization Pass2ConstantIdentification
Converting *(pointer+n) to pointer[n] [19] (byte~) print_person::$0 ← (byte) '0' + *((byte*) print_person::$1) -- *((byte*)print_person::person#2 + OFFSET_STRUCT_PERSON_ID)
Successful SSA optimization Pass2InlineDerefIdx
Simplifying expression containing zero (byte*)print_person::person#2 in [18] (byte*) print_person::$1 ← (byte*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_ID
Simplifying expression containing zero (byte*)print_person::person#2 in [19] (byte~) print_person::$0 ← (byte) '0' + *((byte*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_ID)
Simplifying expression containing zero print_person::$2 in [25] *((const byte*) SCREEN#0 + (byte) idx#5) ← *((byte[4]) print_person::$2 + (byte) 0)
Successful SSA optimization PassNSimplifyExpressionWithZero
Eliminating unused variable (byte*) print_person::$1 and assignment [6] (byte*) print_person::$1 ← (byte*)(struct Person*) print_person::person#2
Eliminating unused constant (const byte) OFFSET_STRUCT_PERSON_ID
Successful SSA optimization PassNEliminateUnusedVars
Constant right-side identified [1] (struct Person*) main::person#1 ← (const struct Person*) main::person#0 + (const byte) SIZEOF_STRUCT_PERSON
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const struct Person*) main::person#1 = main::person#0+SIZEOF_STRUCT_PERSON
Successful SSA optimization Pass2ConstantIdentification
Constant (const struct Person*) print_person::person#1 = main::person#1
Successful SSA optimization Pass2ConstantIdentification
Converting *(pointer+n) to pointer[n] [12] *((const byte*) SCREEN#0 + (byte) idx#5) ← *((byte[4]) print_person::$2) -- *((byte[4])print_person::person#2 + OFFSET_STRUCT_PERSON_INITIALS)
Successful SSA optimization Pass2InlineDerefIdx
Eliminating unused variable (byte[4]) print_person::$2 and assignment [9] (byte[4]) print_person::$2 ← (byte[4])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_INITIALS
Successful SSA optimization PassNEliminateUnusedVars
Inlining constant with different constant siblings (const struct Person*) main::person#0
Inlining constant with var siblings (const struct Person*) print_person::person#0
Inlining constant with var siblings (const struct Person*) print_person::person#1
Inlining constant with var siblings (const byte) idx#19
Constant inlined idx#19 = (byte) 0
Constant inlined print_person::person#0 = (const struct Person[]) persons#0
Constant inlined main::person#0 = (const struct Person[]) persons#0
Constant inlined print_person::person#1 = (const struct Person*) main::person#1
Successful SSA optimization Pass2ConstantInlining
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @2
Adding NOP phi() at start of @3
Adding NOP phi() at start of @end
Adding NOP phi() at start of main
Adding NOP phi() at start of main::@2
CALL GRAPH
Calls in [] to main:3
Calls in [main] to print_person:7 print_person:9
Created 2 initial phi equivalence classes
Coalesced [8] idx#20 ← idx#10
Coalesced down to 2 phi equivalence classes
Culled Empty Block (label) @1
Culled Empty Block (label) @3
Culled Empty Block (label) main::@2
Renumbering block @2 to @1
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
Adding NOP phi() at start of main
Adding NOP phi() at start of main::@1
FINAL CONTROL FLOW GRAPH
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
main: scope:[main] from @1
[4] phi()
[5] call print_person
to:main::@1
main::@1: scope:[main] from main
[6] phi()
[7] call print_person
to:main::@return
main::@return: scope:[main] from main::@1
[8] return
to:@return
print_person: scope:[print_person] from main main::@1
[9] (byte) idx#15 ← phi( main/(byte) 0 main::@1/(byte) idx#10 )
[9] (struct Person*) print_person::person#2 ← phi( main/(const struct Person[]) persons#0 main::@1/(const struct Person*) main::person#1 )
[10] (byte~) print_person::$0 ← (byte) '0' + *((byte*)(struct Person*) print_person::person#2)
[11] *((const byte*) SCREEN#0 + (byte) idx#15) ← (byte~) print_person::$0
[12] (byte) idx#4 ← ++ (byte) idx#15
[13] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' '
[14] (byte) idx#5 ← ++ (byte) idx#4
[15] *((const byte*) SCREEN#0 + (byte) idx#5) ← *((byte[4])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_INITIALS)
[16] (byte) idx#6 ← ++ (byte) idx#5
[17] (byte[4]) print_person::$3 ← (byte[4])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_INITIALS
[18] *((const byte*) SCREEN#0 + (byte) idx#6) ← *((byte[4]) print_person::$3 + (byte) 1)
[19] (byte) idx#7 ← ++ (byte) idx#6
[20] (byte[4]) print_person::$4 ← (byte[4])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_INITIALS
[21] *((const byte*) SCREEN#0 + (byte) idx#7) ← *((byte[4]) print_person::$4 + (byte) 2)
[22] (byte) idx#8 ← ++ (byte) idx#7
[23] *((const byte*) SCREEN#0 + (byte) idx#8) ← (byte) ' '
[24] (byte) idx#10 ← ++ (byte) idx#8
to:print_person::@return
print_person::@return: scope:[print_person] from print_person
[25] return
to:@return
VARIABLE REGISTER WEIGHTS
(byte) Person::id
(byte[4]) Person::initials
(byte*) SCREEN
(byte) idx
(byte) idx#10 1.0
(byte) idx#15 2.0
(byte) idx#4 3.0
(byte) idx#5 3.0
(byte) idx#6 2.0
(byte) idx#7 2.0
(byte) idx#8 3.0
(void()) main()
(struct Person*) main::person
(struct Person[]) persons
(void()) print_person((struct Person*) print_person::person)
(byte~) print_person::$0 4.0
(byte[4]) print_person::$3 4.0
(byte[4]) print_person::$4 4.0
(struct Person*) print_person::person
(struct Person*) print_person::person#2
Initial phi equivalence classes
[ print_person::person#2 ]
[ idx#15 idx#10 ]
Added variable print_person::$0 to zero page equivalence class [ print_person::$0 ]
Added variable idx#4 to zero page equivalence class [ idx#4 ]
Added variable idx#5 to zero page equivalence class [ idx#5 ]
Added variable idx#6 to zero page equivalence class [ idx#6 ]
Added variable print_person::$3 to zero page equivalence class [ print_person::$3 ]
Added variable idx#7 to zero page equivalence class [ idx#7 ]
Added variable print_person::$4 to zero page equivalence class [ print_person::$4 ]
Added variable idx#8 to zero page equivalence class [ idx#8 ]
Complete equivalence classes
[ print_person::person#2 ]
[ idx#15 idx#10 ]
[ print_person::$0 ]
[ idx#4 ]
[ idx#5 ]
[ idx#6 ]
[ print_person::$3 ]
[ idx#7 ]
[ print_person::$4 ]
[ idx#8 ]
Allocated zp ZP_WORD:2 [ print_person::person#2 ]
Allocated zp ZP_BYTE:4 [ idx#15 idx#10 ]
Allocated zp ZP_BYTE:5 [ print_person::$0 ]
Allocated zp ZP_BYTE:6 [ idx#4 ]
Allocated zp ZP_BYTE:7 [ idx#5 ]
Allocated zp ZP_BYTE:8 [ idx#6 ]
Allocated zp ZP_WORD:9 [ print_person::$3 ]
Allocated zp ZP_BYTE:11 [ idx#7 ]
Allocated zp ZP_WORD:12 [ print_person::$4 ]
Allocated zp ZP_BYTE:14 [ idx#8 ]
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Example of a struct containing an array
// Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
// Global Constants & labels
.const SIZEOF_STRUCT_PERSON = 5
.const OFFSET_STRUCT_PERSON_INITIALS = 1
.label SCREEN = $400
.label idx = 6
.label idx_5 = 7
.label idx_6 = 8
.label idx_7 = $b
.label idx_8 = $e
.label idx_10 = 4
.label idx_15 = 4
// @begin
bbegin:
// [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
// @1
b1:
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
main_from_b1:
jsr main
// [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
// @end
bend:
// main
main: {
.label person = persons+SIZEOF_STRUCT_PERSON
// [5] call print_person
// [9] phi from main to print_person [phi:main->print_person]
print_person_from_main:
// [9] phi (byte) idx#15 = (byte) 0 [phi:main->print_person#0] -- vbuz1=vbuc1
lda #0
sta.z idx_15
// [9] phi (struct Person*) print_person::person#2 = (const struct Person[]) persons#0 [phi:main->print_person#1] -- pssz1=pssc1
lda #<persons
sta.z print_person.person
lda #>persons
sta.z print_person.person+1
jsr print_person
// [6] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
jmp b1
// main::@1
b1:
// [7] call print_person
// [9] phi from main::@1 to print_person [phi:main::@1->print_person]
print_person_from_b1:
// [9] phi (byte) idx#15 = (byte) idx#10 [phi:main::@1->print_person#0] -- register_copy
// [9] phi (struct Person*) print_person::person#2 = (const struct Person*) main::person#1 [phi:main::@1->print_person#1] -- pssz1=pssc1
lda #<person
sta.z print_person.person
lda #>person
sta.z print_person.person+1
jsr print_person
jmp breturn
// main::@return
breturn:
// [8] return
rts
}
// print_person
// print_person(struct Person* zeropage(2) person)
print_person: {
.label _0 = 5
.label _3 = 9
.label _4 = $c
.label person = 2
// [10] (byte~) print_person::$0 ← (byte) '0' + *((byte*)(struct Person*) print_person::person#2) -- vbuz1=vbuc1_plus__deref_pbuz2
lda #'0'
clc
ldy #0
adc (person),y
sta.z _0
// [11] *((const byte*) SCREEN#0 + (byte) idx#15) ← (byte~) print_person::$0 -- pbuc1_derefidx_vbuz1=vbuz2
lda.z _0
ldy.z idx_15
sta SCREEN,y
// [12] (byte) idx#4 ← ++ (byte) idx#15 -- vbuz1=_inc_vbuz2
ldy.z idx_15
iny
sty.z idx
// [13] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' ' -- pbuc1_derefidx_vbuz1=vbuc2
lda #' '
ldy.z idx
sta SCREEN,y
// [14] (byte) idx#5 ← ++ (byte) idx#4 -- vbuz1=_inc_vbuz2
ldy.z idx
iny
sty.z idx_5
// [15] *((const byte*) SCREEN#0 + (byte) idx#5) ← *((byte[4])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_INITIALS) -- pbuc1_derefidx_vbuz1=pbuz2_derefidx_vbuc2
ldx.z idx_5
ldy #OFFSET_STRUCT_PERSON_INITIALS
lda (person),y
sta SCREEN,x
// [16] (byte) idx#6 ← ++ (byte) idx#5 -- vbuz1=_inc_vbuz2
ldy.z idx_5
iny
sty.z idx_6
// [17] (byte[4]) print_person::$3 ← (byte[4])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_INITIALS -- pbuz1=pbuz2_plus_vbuc1
lda #OFFSET_STRUCT_PERSON_INITIALS
clc
adc.z person
sta.z _3
lda #0
adc.z person+1
sta.z _3+1
// [18] *((const byte*) SCREEN#0 + (byte) idx#6) ← *((byte[4]) print_person::$3 + (byte) 1) -- pbuc1_derefidx_vbuz1=pbuz2_derefidx_vbuc2
ldx.z idx_6
ldy #1
lda (_3),y
sta SCREEN,x
// [19] (byte) idx#7 ← ++ (byte) idx#6 -- vbuz1=_inc_vbuz2
ldy.z idx_6
iny
sty.z idx_7
// [20] (byte[4]) print_person::$4 ← (byte[4])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_INITIALS -- pbuz1=pbuz2_plus_vbuc1
lda #OFFSET_STRUCT_PERSON_INITIALS
clc
adc.z person
sta.z _4
lda #0
adc.z person+1
sta.z _4+1
// [21] *((const byte*) SCREEN#0 + (byte) idx#7) ← *((byte[4]) print_person::$4 + (byte) 2) -- pbuc1_derefidx_vbuz1=pbuz2_derefidx_vbuc2
ldx.z idx_7
ldy #2
lda (_4),y
sta SCREEN,x
// [22] (byte) idx#8 ← ++ (byte) idx#7 -- vbuz1=_inc_vbuz2
ldy.z idx_7
iny
sty.z idx_8
// [23] *((const byte*) SCREEN#0 + (byte) idx#8) ← (byte) ' ' -- pbuc1_derefidx_vbuz1=vbuc2
lda #' '
ldy.z idx_8
sta SCREEN,y
// [24] (byte) idx#10 ← ++ (byte) idx#8 -- vbuz1=_inc_vbuz2
ldy.z idx_8
iny
sty.z idx_10
jmp breturn
// print_person::@return
breturn:
// [25] return
rts
}
// File Data
_0: .text "jgr"
.byte 0
_1: .text "hbg"
.byte 0
persons: .byte 1
.text "jgr"
.byte 0, 8
.text "hbg"
.byte 0
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [10] (byte~) print_person::$0 ← (byte) '0' + *((byte*)(struct Person*) print_person::person#2) [ print_person::person#2 idx#15 print_person::$0 ] ( main:2::print_person:5 [ print_person::person#2 idx#15 print_person::$0 ] main:2::print_person:7 [ print_person::person#2 idx#15 print_person::$0 ] ) always clobbers reg byte a reg byte y
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:4 [ idx#15 idx#10 ]
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:4 [ idx#15 idx#10 ]
Statement [13] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' ' [ print_person::person#2 idx#4 ] ( main:2::print_person:5 [ print_person::person#2 idx#4 ] main:2::print_person:7 [ print_person::person#2 idx#4 ] ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:6 [ idx#4 ]
Statement [15] *((const byte*) SCREEN#0 + (byte) idx#5) ← *((byte[4])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_INITIALS) [ print_person::person#2 idx#5 ] ( main:2::print_person:5 [ print_person::person#2 idx#5 ] main:2::print_person:7 [ print_person::person#2 idx#5 ] ) always clobbers reg byte a reg byte y
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:7 [ idx#5 ]
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:7 [ idx#5 ]
Statement [17] (byte[4]) print_person::$3 ← (byte[4])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_INITIALS [ print_person::person#2 idx#6 print_person::$3 ] ( main:2::print_person:5 [ print_person::person#2 idx#6 print_person::$3 ] main:2::print_person:7 [ print_person::person#2 idx#6 print_person::$3 ] ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:8 [ idx#6 ]
Statement [18] *((const byte*) SCREEN#0 + (byte) idx#6) ← *((byte[4]) print_person::$3 + (byte) 1) [ print_person::person#2 idx#6 ] ( main:2::print_person:5 [ print_person::person#2 idx#6 ] main:2::print_person:7 [ print_person::person#2 idx#6 ] ) always clobbers reg byte a reg byte y
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:8 [ idx#6 ]
Statement [20] (byte[4]) print_person::$4 ← (byte[4])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_INITIALS [ idx#7 print_person::$4 ] ( main:2::print_person:5 [ idx#7 print_person::$4 ] main:2::print_person:7 [ idx#7 print_person::$4 ] ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:11 [ idx#7 ]
Statement [21] *((const byte*) SCREEN#0 + (byte) idx#7) ← *((byte[4]) print_person::$4 + (byte) 2) [ idx#7 ] ( main:2::print_person:5 [ idx#7 ] main:2::print_person:7 [ idx#7 ] ) always clobbers reg byte a reg byte y
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:11 [ idx#7 ]
Statement [23] *((const byte*) SCREEN#0 + (byte) idx#8) ← (byte) ' ' [ idx#8 ] ( main:2::print_person:5 [ idx#8 ] main:2::print_person:7 [ idx#8 ] ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:14 [ idx#8 ]
Statement [10] (byte~) print_person::$0 ← (byte) '0' + *((byte*)(struct Person*) print_person::person#2) [ print_person::person#2 idx#15 print_person::$0 ] ( main:2::print_person:5 [ print_person::person#2 idx#15 print_person::$0 ] main:2::print_person:7 [ print_person::person#2 idx#15 print_person::$0 ] ) always clobbers reg byte a reg byte y
Statement [13] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' ' [ print_person::person#2 idx#4 ] ( main:2::print_person:5 [ print_person::person#2 idx#4 ] main:2::print_person:7 [ print_person::person#2 idx#4 ] ) always clobbers reg byte a
Statement [15] *((const byte*) SCREEN#0 + (byte) idx#5) ← *((byte[4])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_INITIALS) [ print_person::person#2 idx#5 ] ( main:2::print_person:5 [ print_person::person#2 idx#5 ] main:2::print_person:7 [ print_person::person#2 idx#5 ] ) always clobbers reg byte a reg byte y
Statement [17] (byte[4]) print_person::$3 ← (byte[4])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_INITIALS [ print_person::person#2 idx#6 print_person::$3 ] ( main:2::print_person:5 [ print_person::person#2 idx#6 print_person::$3 ] main:2::print_person:7 [ print_person::person#2 idx#6 print_person::$3 ] ) always clobbers reg byte a
Statement [18] *((const byte*) SCREEN#0 + (byte) idx#6) ← *((byte[4]) print_person::$3 + (byte) 1) [ print_person::person#2 idx#6 ] ( main:2::print_person:5 [ print_person::person#2 idx#6 ] main:2::print_person:7 [ print_person::person#2 idx#6 ] ) always clobbers reg byte a reg byte y
Statement [20] (byte[4]) print_person::$4 ← (byte[4])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_INITIALS [ idx#7 print_person::$4 ] ( main:2::print_person:5 [ idx#7 print_person::$4 ] main:2::print_person:7 [ idx#7 print_person::$4 ] ) always clobbers reg byte a
Statement [21] *((const byte*) SCREEN#0 + (byte) idx#7) ← *((byte[4]) print_person::$4 + (byte) 2) [ idx#7 ] ( main:2::print_person:5 [ idx#7 ] main:2::print_person:7 [ idx#7 ] ) always clobbers reg byte a reg byte y
Statement [23] *((const byte*) SCREEN#0 + (byte) idx#8) ← (byte) ' ' [ idx#8 ] ( main:2::print_person:5 [ idx#8 ] main:2::print_person:7 [ idx#8 ] ) always clobbers reg byte a
Potential registers zp ZP_WORD:2 [ print_person::person#2 ] : zp ZP_WORD:2 ,
Potential registers zp ZP_BYTE:4 [ idx#15 idx#10 ] : zp ZP_BYTE:4 , reg byte x ,
Potential registers zp ZP_BYTE:5 [ print_person::$0 ] : zp ZP_BYTE:5 , reg byte a , reg byte x , reg byte y ,
Potential registers zp ZP_BYTE:6 [ idx#4 ] : zp ZP_BYTE:6 , reg byte x , reg byte y ,
Potential registers zp ZP_BYTE:7 [ idx#5 ] : zp ZP_BYTE:7 , reg byte x ,
Potential registers zp ZP_BYTE:8 [ idx#6 ] : zp ZP_BYTE:8 , reg byte x ,
Potential registers zp ZP_WORD:9 [ print_person::$3 ] : zp ZP_WORD:9 ,
Potential registers zp ZP_BYTE:11 [ idx#7 ] : zp ZP_BYTE:11 , reg byte x ,
Potential registers zp ZP_WORD:12 [ print_person::$4 ] : zp ZP_WORD:12 ,
Potential registers zp ZP_BYTE:14 [ idx#8 ] : zp ZP_BYTE:14 , reg byte x , reg byte y ,
REGISTER UPLIFT SCOPES
Uplift Scope [] 3: zp ZP_BYTE:4 [ idx#15 idx#10 ] 3: zp ZP_BYTE:6 [ idx#4 ] 3: zp ZP_BYTE:7 [ idx#5 ] 3: zp ZP_BYTE:14 [ idx#8 ] 2: zp ZP_BYTE:8 [ idx#6 ] 2: zp ZP_BYTE:11 [ idx#7 ]
Uplift Scope [print_person] 4: zp ZP_BYTE:5 [ print_person::$0 ] 4: zp ZP_WORD:9 [ print_person::$3 ] 4: zp ZP_WORD:12 [ print_person::$4 ] 0: zp ZP_WORD:2 [ print_person::person#2 ]
Uplift Scope [Person]
Uplift Scope [main]
Uplifting [] best 196 combination reg byte x [ idx#15 idx#10 ] reg byte x [ idx#4 ] reg byte x [ idx#5 ] reg byte x [ idx#8 ] reg byte x [ idx#6 ] zp ZP_BYTE:11 [ idx#7 ]
Limited combination testing to 100 combinations of 144 possible.
Uplifting [print_person] best 190 combination reg byte a [ print_person::$0 ] zp ZP_WORD:9 [ print_person::$3 ] zp ZP_WORD:12 [ print_person::$4 ] zp ZP_WORD:2 [ print_person::person#2 ]
Uplifting [Person] best 190 combination
Uplifting [main] best 190 combination
Attempting to uplift remaining variables inzp ZP_BYTE:11 [ idx#7 ]
Uplifting [] best 181 combination reg byte x [ idx#7 ]
Coalescing zero page register [ zp ZP_WORD:2 [ print_person::person#2 ] ] with [ zp ZP_WORD:12 [ print_person::$4 ] ] - score: 1
Allocated (was zp ZP_WORD:9) zp ZP_WORD:4 [ print_person::$3 ]
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Example of a struct containing an array
// Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
// Global Constants & labels
.const SIZEOF_STRUCT_PERSON = 5
.const OFFSET_STRUCT_PERSON_INITIALS = 1
.label SCREEN = $400
// @begin
bbegin:
// [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
// @1
b1:
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
main_from_b1:
jsr main
// [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
// @end
bend:
// main
main: {
.label person = persons+SIZEOF_STRUCT_PERSON
// [5] call print_person
// [9] phi from main to print_person [phi:main->print_person]
print_person_from_main:
// [9] phi (byte) idx#15 = (byte) 0 [phi:main->print_person#0] -- vbuxx=vbuc1
ldx #0
// [9] phi (struct Person*) print_person::person#2 = (const struct Person[]) persons#0 [phi:main->print_person#1] -- pssz1=pssc1
lda #<persons
sta.z print_person.person
lda #>persons
sta.z print_person.person+1
jsr print_person
// [6] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
jmp b1
// main::@1
b1:
// [7] call print_person
// [9] phi from main::@1 to print_person [phi:main::@1->print_person]
print_person_from_b1:
// [9] phi (byte) idx#15 = (byte) idx#10 [phi:main::@1->print_person#0] -- register_copy
// [9] phi (struct Person*) print_person::person#2 = (const struct Person*) main::person#1 [phi:main::@1->print_person#1] -- pssz1=pssc1
lda #<person
sta.z print_person.person
lda #>person
sta.z print_person.person+1
jsr print_person
jmp breturn
// main::@return
breturn:
// [8] return
rts
}
// print_person
// print_person(struct Person* zeropage(2) person)
print_person: {
.label _3 = 4
.label _4 = 2
.label person = 2
// [10] (byte~) print_person::$0 ← (byte) '0' + *((byte*)(struct Person*) print_person::person#2) -- vbuaa=vbuc1_plus__deref_pbuz1
lda #'0'
clc
ldy #0
adc (person),y
// [11] *((const byte*) SCREEN#0 + (byte) idx#15) ← (byte~) print_person::$0 -- pbuc1_derefidx_vbuxx=vbuaa
sta SCREEN,x
// [12] (byte) idx#4 ← ++ (byte) idx#15 -- vbuxx=_inc_vbuxx
inx
// [13] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' ' -- pbuc1_derefidx_vbuxx=vbuc2
lda #' '
sta SCREEN,x
// [14] (byte) idx#5 ← ++ (byte) idx#4 -- vbuxx=_inc_vbuxx
inx
// [15] *((const byte*) SCREEN#0 + (byte) idx#5) ← *((byte[4])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_INITIALS) -- pbuc1_derefidx_vbuxx=pbuz1_derefidx_vbuc2
ldy #OFFSET_STRUCT_PERSON_INITIALS
lda (person),y
sta SCREEN,x
// [16] (byte) idx#6 ← ++ (byte) idx#5 -- vbuxx=_inc_vbuxx
inx
// [17] (byte[4]) print_person::$3 ← (byte[4])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_INITIALS -- pbuz1=pbuz2_plus_vbuc1
lda #OFFSET_STRUCT_PERSON_INITIALS
clc
adc.z person
sta.z _3
lda #0
adc.z person+1
sta.z _3+1
// [18] *((const byte*) SCREEN#0 + (byte) idx#6) ← *((byte[4]) print_person::$3 + (byte) 1) -- pbuc1_derefidx_vbuxx=pbuz1_derefidx_vbuc2
ldy #1
lda (_3),y
sta SCREEN,x
// [19] (byte) idx#7 ← ++ (byte) idx#6 -- vbuxx=_inc_vbuxx
inx
// [20] (byte[4]) print_person::$4 ← (byte[4])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_INITIALS -- pbuz1=pbuz1_plus_vbuc1
lda #OFFSET_STRUCT_PERSON_INITIALS
clc
adc.z _4
sta.z _4
bcc !+
inc.z _4+1
!:
// [21] *((const byte*) SCREEN#0 + (byte) idx#7) ← *((byte[4]) print_person::$4 + (byte) 2) -- pbuc1_derefidx_vbuxx=pbuz1_derefidx_vbuc2
ldy #2
lda (_4),y
sta SCREEN,x
// [22] (byte) idx#8 ← ++ (byte) idx#7 -- vbuxx=_inc_vbuxx
inx
// [23] *((const byte*) SCREEN#0 + (byte) idx#8) ← (byte) ' ' -- pbuc1_derefidx_vbuxx=vbuc2
lda #' '
sta SCREEN,x
// [24] (byte) idx#10 ← ++ (byte) idx#8 -- vbuxx=_inc_vbuxx
inx
jmp breturn
// print_person::@return
breturn:
// [25] return
rts
}
// File Data
_0: .text "jgr"
.byte 0
_1: .text "hbg"
.byte 0
persons: .byte 1
.text "jgr"
.byte 0, 8
.text "hbg"
.byte 0
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b1
Removing instruction jmp bend
Removing instruction jmp b1
Removing instruction jmp breturn
Removing instruction jmp breturn
Succesful ASM optimization Pass5NextJumpElimination
Replacing instruction lda #OFFSET_STRUCT_PERSON_INITIALS with TYA
Removing instruction b1_from_bbegin:
Removing instruction b1:
Removing instruction main_from_b1:
Removing instruction bend_from_b1:
Removing instruction b1_from_main:
Removing instruction print_person_from_b1:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction bend:
Removing instruction print_person_from_main:
Removing instruction b1:
Removing instruction breturn:
Removing instruction breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Updating BasicUpstart to call main directly
Removing instruction jsr main
Succesful ASM optimization Pass5SkipBegin
Removing instruction bbegin:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(const string) $0 $0 = (string) "jgr"
(const string) $1 $1 = (string) "hbg"
(label) @1
(label) @begin
(label) @end
(const byte) OFFSET_STRUCT_PERSON_INITIALS OFFSET_STRUCT_PERSON_INITIALS = (byte) 1
(byte) Person::id
(byte[4]) Person::initials
(byte*) SCREEN
(const byte*) SCREEN#0 SCREEN = (byte*) 1024
(const byte) SIZEOF_STRUCT_PERSON SIZEOF_STRUCT_PERSON = (byte) 5
(byte) idx
(byte) idx#10 reg byte x 1.0
(byte) idx#15 reg byte x 2.0
(byte) idx#4 reg byte x 3.0
(byte) idx#5 reg byte x 3.0
(byte) idx#6 reg byte x 2.0
(byte) idx#7 reg byte x 2.0
(byte) idx#8 reg byte x 3.0
(void()) main()
(label) main::@1
(label) main::@return
(struct Person*) main::person
(const struct Person*) main::person#1 person = (const struct Person[]) persons#0+(const byte) SIZEOF_STRUCT_PERSON
(struct Person[]) persons
(const struct Person[]) persons#0 persons = { { id: (byte) 1, initials: (const string) $0 }, { id: (byte) 8, initials: (const string) $1 } }
(void()) print_person((struct Person*) print_person::person)
(byte~) print_person::$0 reg byte a 4.0
(byte[4]) print_person::$3 $3 zp ZP_WORD:4 4.0
(byte[4]) print_person::$4 $4 zp ZP_WORD:2 4.0
(label) print_person::@return
(struct Person*) print_person::person
(struct Person*) print_person::person#2 person zp ZP_WORD:2
zp ZP_WORD:2 [ print_person::person#2 print_person::$4 ]
reg byte x [ idx#15 idx#10 ]
reg byte a [ print_person::$0 ]
reg byte x [ idx#4 ]
reg byte x [ idx#5 ]
reg byte x [ idx#6 ]
zp ZP_WORD:4 [ print_person::$3 ]
reg byte x [ idx#7 ]
reg byte x [ idx#8 ]
FINAL ASSEMBLER
Score: 159
// File Comments
// Example of a struct containing an array
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.const SIZEOF_STRUCT_PERSON = 5
.const OFFSET_STRUCT_PERSON_INITIALS = 1
.label SCREEN = $400
// @begin
// [1] phi from @begin to @1 [phi:@begin->@1]
// @1
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
// [3] phi from @1 to @end [phi:@1->@end]
// @end
// main
main: {
.label person = persons+SIZEOF_STRUCT_PERSON
// print_person(person)
// [5] call print_person
// [9] phi from main to print_person [phi:main->print_person]
// [9] phi (byte) idx#15 = (byte) 0 [phi:main->print_person#0] -- vbuxx=vbuc1
ldx #0
// [9] phi (struct Person*) print_person::person#2 = (const struct Person[]) persons#0 [phi:main->print_person#1] -- pssz1=pssc1
lda #<persons
sta.z print_person.person
lda #>persons
sta.z print_person.person+1
jsr print_person
// [6] phi from main to main::@1 [phi:main->main::@1]
// main::@1
// print_person(person)
// [7] call print_person
// [9] phi from main::@1 to print_person [phi:main::@1->print_person]
// [9] phi (byte) idx#15 = (byte) idx#10 [phi:main::@1->print_person#0] -- register_copy
// [9] phi (struct Person*) print_person::person#2 = (const struct Person*) main::person#1 [phi:main::@1->print_person#1] -- pssz1=pssc1
lda #<person
sta.z print_person.person
lda #>person
sta.z print_person.person+1
jsr print_person
// main::@return
// }
// [8] return
rts
}
// print_person
// print_person(struct Person* zeropage(2) person)
print_person: {
.label _3 = 4
.label _4 = 2
.label person = 2
// '0'+person->id
// [10] (byte~) print_person::$0 ← (byte) '0' + *((byte*)(struct Person*) print_person::person#2) -- vbuaa=vbuc1_plus__deref_pbuz1
lda #'0'
clc
ldy #0
adc (person),y
// SCREEN[idx++] = '0'+person->id
// [11] *((const byte*) SCREEN#0 + (byte) idx#15) ← (byte~) print_person::$0 -- pbuc1_derefidx_vbuxx=vbuaa
sta SCREEN,x
// SCREEN[idx++] = '0'+person->id;
// [12] (byte) idx#4 ← ++ (byte) idx#15 -- vbuxx=_inc_vbuxx
inx
// SCREEN[idx++] = ' '
// [13] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' ' -- pbuc1_derefidx_vbuxx=vbuc2
lda #' '
sta SCREEN,x
// SCREEN[idx++] = ' ';
// [14] (byte) idx#5 ← ++ (byte) idx#4 -- vbuxx=_inc_vbuxx
inx
// SCREEN[idx++] = person->initials[0]
// [15] *((const byte*) SCREEN#0 + (byte) idx#5) ← *((byte[4])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_INITIALS) -- pbuc1_derefidx_vbuxx=pbuz1_derefidx_vbuc2
ldy #OFFSET_STRUCT_PERSON_INITIALS
lda (person),y
sta SCREEN,x
// SCREEN[idx++] = person->initials[0];
// [16] (byte) idx#6 ← ++ (byte) idx#5 -- vbuxx=_inc_vbuxx
inx
// SCREEN[idx++] = person->initials[1]
// [17] (byte[4]) print_person::$3 ← (byte[4])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_INITIALS -- pbuz1=pbuz2_plus_vbuc1
tya
clc
adc.z person
sta.z _3
lda #0
adc.z person+1
sta.z _3+1
// [18] *((const byte*) SCREEN#0 + (byte) idx#6) ← *((byte[4]) print_person::$3 + (byte) 1) -- pbuc1_derefidx_vbuxx=pbuz1_derefidx_vbuc2
ldy #1
lda (_3),y
sta SCREEN,x
// SCREEN[idx++] = person->initials[1];
// [19] (byte) idx#7 ← ++ (byte) idx#6 -- vbuxx=_inc_vbuxx
inx
// SCREEN[idx++] = person->initials[2]
// [20] (byte[4]) print_person::$4 ← (byte[4])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_INITIALS -- pbuz1=pbuz1_plus_vbuc1
lda #OFFSET_STRUCT_PERSON_INITIALS
clc
adc.z _4
sta.z _4
bcc !+
inc.z _4+1
!:
// [21] *((const byte*) SCREEN#0 + (byte) idx#7) ← *((byte[4]) print_person::$4 + (byte) 2) -- pbuc1_derefidx_vbuxx=pbuz1_derefidx_vbuc2
ldy #2
lda (_4),y
sta SCREEN,x
// SCREEN[idx++] = person->initials[2];
// [22] (byte) idx#8 ← ++ (byte) idx#7 -- vbuxx=_inc_vbuxx
inx
// SCREEN[idx++] = ' '
// [23] *((const byte*) SCREEN#0 + (byte) idx#8) ← (byte) ' ' -- pbuc1_derefidx_vbuxx=vbuc2
lda #' '
sta SCREEN,x
// SCREEN[idx++] = ' ';
// [24] (byte) idx#10 ← ++ (byte) idx#8 -- vbuxx=_inc_vbuxx
inx
// print_person::@return
// }
// [25] return
rts
}
// File Data
_0: .text "jgr"
.byte 0
_1: .text "hbg"
.byte 0
persons: .byte 1
.text "jgr"
.byte 0, 8
.text "hbg"
.byte 0

View File

@ -0,0 +1,43 @@
(const string) $0 $0 = (string) "jgr"
(const string) $1 $1 = (string) "hbg"
(label) @1
(label) @begin
(label) @end
(const byte) OFFSET_STRUCT_PERSON_INITIALS OFFSET_STRUCT_PERSON_INITIALS = (byte) 1
(byte) Person::id
(byte[4]) Person::initials
(byte*) SCREEN
(const byte*) SCREEN#0 SCREEN = (byte*) 1024
(const byte) SIZEOF_STRUCT_PERSON SIZEOF_STRUCT_PERSON = (byte) 5
(byte) idx
(byte) idx#10 reg byte x 1.0
(byte) idx#15 reg byte x 2.0
(byte) idx#4 reg byte x 3.0
(byte) idx#5 reg byte x 3.0
(byte) idx#6 reg byte x 2.0
(byte) idx#7 reg byte x 2.0
(byte) idx#8 reg byte x 3.0
(void()) main()
(label) main::@1
(label) main::@return
(struct Person*) main::person
(const struct Person*) main::person#1 person = (const struct Person[]) persons#0+(const byte) SIZEOF_STRUCT_PERSON
(struct Person[]) persons
(const struct Person[]) persons#0 persons = { { id: (byte) 1, initials: (const string) $0 }, { id: (byte) 8, initials: (const string) $1 } }
(void()) print_person((struct Person*) print_person::person)
(byte~) print_person::$0 reg byte a 4.0
(byte[4]) print_person::$3 $3 zp ZP_WORD:4 4.0
(byte[4]) print_person::$4 $4 zp ZP_WORD:2 4.0
(label) print_person::@return
(struct Person*) print_person::person
(struct Person*) print_person::person#2 person zp ZP_WORD:2
zp ZP_WORD:2 [ print_person::person#2 print_person::$4 ]
reg byte x [ idx#15 idx#10 ]
reg byte a [ print_person::$0 ]
reg byte x [ idx#4 ]
reg byte x [ idx#5 ]
reg byte x [ idx#6 ]
zp ZP_WORD:4 [ print_person::$3 ]
reg byte x [ idx#7 ]
reg byte x [ idx#8 ]

View File

@ -69,8 +69,7 @@ print_person: {
.byte 0
DIGIT: .text "0123456789"
.byte 0
persons:
.byte 4
persons: .byte 4
.word name1
.byte 7
.word name2

View File

@ -549,8 +549,7 @@ print_person: {
.byte 0
DIGIT: .text "0123456789"
.byte 0
persons:
.byte 4
persons: .byte 4
.word name1
.byte 7
.word name2
@ -734,8 +733,7 @@ print_person: {
.byte 0
DIGIT: .text "0123456789"
.byte 0
persons:
.byte 4
persons: .byte 4
.word name1
.byte 7
.word name2
@ -951,8 +949,7 @@ print_person: {
.byte 0
DIGIT: .text "0123456789"
.byte 0
persons:
.byte 4
persons: .byte 4
.word name1
.byte 7
.word name2

View File

@ -48,8 +48,7 @@ print: {
sty.z idx
rts
}
points:
.byte 1
points: .byte 1
.word $83f
.byte 3
.word $107e

View File

@ -479,8 +479,7 @@ print: {
rts
}
// File Data
points:
.byte 1
points: .byte 1
.word $83f
.byte 3
.word $107e
@ -653,8 +652,7 @@ print: {
rts
}
// File Data
points:
.byte 1
points: .byte 1
.word $83f
.byte 3
.word $107e
@ -853,8 +851,7 @@ print: {
rts
}
// File Data
points:
.byte 1
points: .byte 1
.word $83f
.byte 3
.word $107e

View File

@ -0,0 +1,79 @@
// Example of a struct containing an array
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.const SIZEOF_STRUCT_PERSON = $11
.const OFFSET_STRUCT_PERSON_NAME = 1
.label SCREEN = $400
main: {
ldx #0
lda #<persons
sta.z print_person.person
lda #>persons
sta.z print_person.person+1
jsr print_person
lda #<persons+1*SIZEOF_STRUCT_PERSON
sta.z print_person.person
lda #>persons+1*SIZEOF_STRUCT_PERSON
sta.z print_person.person+1
jsr print_person
rts
}
// print_person(struct Person* zeropage(2) person)
print_person: {
.label _1 = 4
.label _2 = 6
.label person = 2
ldy #0
lda (person),y
tay
lda DIGIT,y
sta SCREEN,x
inx
lda #' '
sta SCREEN,x
inx
ldy #0
b1:
lda #OFFSET_STRUCT_PERSON_NAME
clc
adc.z person
sta.z _1
lda #0
adc.z person+1
sta.z _1+1
lda (_1),y
cmp #0
bne b2
lda #' '
sta SCREEN,x
inx
rts
b2:
lda #OFFSET_STRUCT_PERSON_NAME
clc
adc.z person
sta.z _2
lda #0
adc.z person+1
sta.z _2+1
lda (_2),y
sta SCREEN,x
inx
iny
jmp b1
}
_0: .text "jesper"
.byte 0
_1: .text "henriette"
.byte 0
persons: .byte 4
.text "jesper"
.byte 0
.fill 9, 0
.byte 7
.text "henriette"
.byte 0
.fill 6, 0
DIGIT: .text "0123456789"
.byte 0

View File

@ -0,0 +1,47 @@
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
main: scope:[main] from @1
[4] phi()
[5] call print_person
to:main::@1
main::@1: scope:[main] from main
[6] phi()
[7] call print_person
to:main::@return
main::@return: scope:[main] from main::@1
[8] return
to:@return
print_person: scope:[print_person] from main main::@1
[9] (byte) idx#13 ← phi( main/(byte) 0 main::@1/(byte) idx#16 )
[9] (struct Person*) print_person::person#2 ← phi( main/(const struct Person[]) persons#0 main::@1/(const struct Person[]) persons#0+(byte) 1*(const byte) SIZEOF_STRUCT_PERSON )
[10] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*)(struct Person*) print_person::person#2))
[11] (byte) idx#4 ← ++ (byte) idx#13
[12] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' '
[13] (byte) idx#5 ← ++ (byte) idx#4
to:print_person::@1
print_person::@1: scope:[print_person] from print_person print_person::@2
[14] (byte) idx#14 ← phi( print_person/(byte) idx#5 print_person::@2/(byte) idx#6 )
[14] (byte) print_person::i#2 ← phi( print_person/(byte) 0 print_person::@2/(byte) print_person::i#1 )
[15] (byte[$10]) print_person::$1 ← (byte[$10])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME
[16] if((byte) 0!=*((byte[$10]) print_person::$1 + (byte) print_person::i#2)) goto print_person::@2
to:print_person::@3
print_person::@3: scope:[print_person] from print_person::@1
[17] *((const byte*) SCREEN#0 + (byte) idx#14) ← (byte) ' '
[18] (byte) idx#16 ← ++ (byte) idx#14
to:print_person::@return
print_person::@return: scope:[print_person] from print_person::@3
[19] return
to:@return
print_person::@2: scope:[print_person] from print_person::@1
[20] (byte[$10]) print_person::$2 ← (byte[$10])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME
[21] *((const byte*) SCREEN#0 + (byte) idx#14) ← *((byte[$10]) print_person::$2 + (byte) print_person::i#2)
[22] (byte) idx#6 ← ++ (byte) idx#14
[23] (byte) print_person::i#1 ← ++ (byte) print_person::i#2
to:print_person::@1

View File

@ -0,0 +1,956 @@
Fixing struct type size struct Person to 17
Fixing struct type size struct Person to 17
Fixing pointer addition (struct Person*~) main::$1 ← (struct Person[]) persons + (number) 1
Rewriting struct pointer member access *((struct Person*) print_person::person).id
Rewriting struct pointer member access *((struct Person*) print_person::person).name
Rewriting struct pointer member access *((struct Person*) print_person::person).name
Warning! Adding boolean cast to non-boolean condition *((byte[$10]) print_person::$1 + (byte) print_person::i)
Culled Empty Block (label) print_person::@4
Culled Empty Block (label) print_person::@5
Culled Empty Block (label) print_person::@6
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
(struct Person[]) persons#0 ← { { (number) 4, (const string) $0 }, { (number) 7, (const string) $1 } }
to:@1
main: scope:[main] from @2
(byte) idx#18 ← phi( @2/(byte) idx#20 )
(struct Person*) print_person::person#0 ← (struct Person[]) persons#0
call print_person
to:main::@1
main::@1: scope:[main] from main
(byte) idx#10 ← phi( main/(byte) idx#8 )
(byte) idx#0 ← (byte) idx#10
(number~) main::$3 ← (number) 1 * (const byte) SIZEOF_STRUCT_PERSON
(struct Person*~) main::$1 ← (struct Person[]) persons#0 + (number~) main::$3
(struct Person*) print_person::person#1 ← (struct Person*~) main::$1
call print_person
to:main::@2
main::@2: scope:[main] from main::@1
(byte) idx#11 ← phi( main::@1/(byte) idx#8 )
(byte) idx#1 ← (byte) idx#11
to:main::@return
main::@return: scope:[main] from main::@2
(byte) idx#12 ← phi( main::@2/(byte) idx#1 )
(byte) idx#2 ← (byte) idx#12
return
to:@return
@1: scope:[] from @begin
(byte*) SCREEN#0 ← ((byte*)) (number) $400
(byte) idx#3 ← (number) 0
(byte[]) DIGIT#0 ← (const string) $2
to:@2
print_person: scope:[print_person] from main main::@1
(byte) idx#13 ← phi( main/(byte) idx#18 main::@1/(byte) idx#0 )
(struct Person*) print_person::person#2 ← phi( main/(struct Person*) print_person::person#0 main::@1/(struct Person*) print_person::person#1 )
(byte*) print_person::$0 ← (byte*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_ID
*((byte*) SCREEN#0 + (byte) idx#13) ← *((byte[]) DIGIT#0 + *((byte*) print_person::$0))
(byte) idx#4 ← ++ (byte) idx#13
*((byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' '
(byte) idx#5 ← ++ (byte) idx#4
(byte) print_person::i#0 ← (number) 0
to:print_person::@1
print_person::@1: scope:[print_person] from print_person print_person::@2
(byte) idx#19 ← phi( print_person/(byte) idx#5 print_person::@2/(byte) idx#6 )
(byte) print_person::i#2 ← phi( print_person/(byte) print_person::i#0 print_person::@2/(byte) print_person::i#1 )
(struct Person*) print_person::person#3 ← phi( print_person/(struct Person*) print_person::person#2 print_person::@2/(struct Person*) print_person::person#4 )
(byte[$10]) print_person::$1 ← (byte[$10])(struct Person*) print_person::person#3 + (const byte) OFFSET_STRUCT_PERSON_NAME
(bool~) print_person::$3 ← (number) 0 != *((byte[$10]) print_person::$1 + (byte) print_person::i#2)
if((bool~) print_person::$3) goto print_person::@2
to:print_person::@3
print_person::@2: scope:[print_person] from print_person::@1
(byte) idx#14 ← phi( print_person::@1/(byte) idx#19 )
(byte) print_person::i#3 ← phi( print_person::@1/(byte) print_person::i#2 )
(struct Person*) print_person::person#4 ← phi( print_person::@1/(struct Person*) print_person::person#3 )
(byte[$10]) print_person::$2 ← (byte[$10])(struct Person*) print_person::person#4 + (const byte) OFFSET_STRUCT_PERSON_NAME
*((byte*) SCREEN#0 + (byte) idx#14) ← *((byte[$10]) print_person::$2 + (byte) print_person::i#3)
(byte) idx#6 ← ++ (byte) idx#14
(byte) print_person::i#1 ← ++ (byte) print_person::i#3
to:print_person::@1
print_person::@3: scope:[print_person] from print_person::@1
(byte) idx#15 ← phi( print_person::@1/(byte) idx#19 )
*((byte*) SCREEN#0 + (byte) idx#15) ← (byte) ' '
(byte) idx#7 ← ++ (byte) idx#15
to:print_person::@return
print_person::@return: scope:[print_person] from print_person::@3
(byte) idx#16 ← phi( print_person::@3/(byte) idx#7 )
(byte) idx#8 ← (byte) idx#16
return
to:@return
@2: scope:[] from @1
(byte) idx#20 ← phi( @1/(byte) idx#3 )
call main
to:@3
@3: scope:[] from @2
(byte) idx#17 ← phi( @2/(byte) idx#2 )
(byte) idx#9 ← (byte) idx#17
to:@end
@end: scope:[] from @3
SYMBOL TABLE SSA
(const string) $0 = (string) "jesper"
(const string) $1 = (string) "henriette"
(const string) $2 = (string) "0123456789"
(label) @1
(label) @2
(label) @3
(label) @begin
(label) @end
(byte[]) DIGIT
(byte[]) DIGIT#0
(const byte) OFFSET_STRUCT_PERSON_ID = (byte) 0
(const byte) OFFSET_STRUCT_PERSON_NAME = (byte) 1
(byte) Person::id
(byte[$10]) Person::name
(byte*) SCREEN
(byte*) SCREEN#0
(const byte) SIZEOF_STRUCT_PERSON = (byte) $11
(byte) idx
(byte) idx#0
(byte) idx#1
(byte) idx#10
(byte) idx#11
(byte) idx#12
(byte) idx#13
(byte) idx#14
(byte) idx#15
(byte) idx#16
(byte) idx#17
(byte) idx#18
(byte) idx#19
(byte) idx#2
(byte) idx#20
(byte) idx#3
(byte) idx#4
(byte) idx#5
(byte) idx#6
(byte) idx#7
(byte) idx#8
(byte) idx#9
(void()) main()
(struct Person*~) main::$1
(number~) main::$3
(label) main::@1
(label) main::@2
(label) main::@return
(struct Person[]) persons
(struct Person[]) persons#0
(void()) print_person((struct Person*) print_person::person)
(byte*) print_person::$0
(byte[$10]) print_person::$1
(byte[$10]) print_person::$2
(bool~) print_person::$3
(label) print_person::@1
(label) print_person::@2
(label) print_person::@3
(label) print_person::@return
(byte) print_person::i
(byte) print_person::i#0
(byte) print_person::i#1
(byte) print_person::i#2
(byte) print_person::i#3
(struct Person*) print_person::person
(struct Person*) print_person::person#0
(struct Person*) print_person::person#1
(struct Person*) print_person::person#2
(struct Person*) print_person::person#3
(struct Person*) print_person::person#4
Adding number conversion cast (unumber) 1 in (number~) main::$3 ← (number) 1 * (const byte) SIZEOF_STRUCT_PERSON
Adding number conversion cast (unumber) main::$3 in (number~) main::$3 ← (unumber)(number) 1 * (const byte) SIZEOF_STRUCT_PERSON
Adding number conversion cast (unumber) 0 in (byte) idx#3 ← (number) 0
Adding number conversion cast (unumber) 0 in (byte) print_person::i#0 ← (number) 0
Adding number conversion cast (unumber) 0 in (bool~) print_person::$3 ← (number) 0 != *((byte[$10]) print_person::$1 + (byte) print_person::i#2)
Successful SSA optimization PassNAddNumberTypeConversions
Added casts to value list in (struct Person[]) persons#0 ← (struct Person[]){ (struct Person){ (byte)(number) 4, (const string) $0 }, (struct Person){ (byte)(number) 7, (const string) $1 } }
Successful SSA optimization PassNAddInitializerValueListTypeCasts
Inlining cast (byte*) SCREEN#0 ← (byte*)(number) $400
Inlining cast (byte) idx#3 ← (unumber)(number) 0
Inlining cast (byte) print_person::i#0 ← (unumber)(number) 0
Successful SSA optimization Pass2InlineCast
Simplifying constant integer cast 4
Simplifying constant integer cast 7
Simplifying constant integer cast 1
Simplifying constant pointer cast (byte*) 1024
Simplifying constant integer cast 0
Simplifying constant integer cast 0
Simplifying constant integer cast 0
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 1
Finalized unsigned number type (byte) 0
Finalized unsigned number type (byte) 0
Finalized unsigned number type (byte) 0
Successful SSA optimization PassNFinalizeNumberTypeConversions
Inferred type updated to byte in (unumber~) main::$3 ← (byte) 1 * (const byte) SIZEOF_STRUCT_PERSON
Alias (byte) idx#0 = (byte) idx#10
Alias (struct Person*) print_person::person#1 = (struct Person*~) main::$1
Alias (byte) idx#1 = (byte) idx#11 (byte) idx#12 (byte) idx#2
Alias (struct Person*) print_person::person#3 = (struct Person*) print_person::person#4
Alias (byte) print_person::i#2 = (byte) print_person::i#3
Alias (byte) idx#14 = (byte) idx#19 (byte) idx#15
Alias (byte) idx#16 = (byte) idx#7 (byte) idx#8
Alias (byte) idx#20 = (byte) idx#3
Alias (byte) idx#17 = (byte) idx#9
Successful SSA optimization Pass2AliasElimination
Identical Phi Values (byte) idx#18 (byte) idx#20
Identical Phi Values (byte) idx#0 (byte) idx#16
Identical Phi Values (byte) idx#1 (byte) idx#16
Identical Phi Values (struct Person*) print_person::person#3 (struct Person*) print_person::person#2
Identical Phi Values (byte) idx#17 (byte) idx#1
Successful SSA optimization Pass2IdenticalPhiElimination
Simple Condition (bool~) print_person::$3 [28] if((byte) 0!=*((byte[$10]) print_person::$1 + (byte) print_person::i#2)) goto print_person::@2
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant right-side identified [6] (byte~) main::$3 ← (byte) 1 * (const byte) SIZEOF_STRUCT_PERSON
Successful SSA optimization Pass2ConstantRValueConsolidation
Identified constant from value list (struct Person) { id: (byte) 4, name: (const string) $0 }
Identified constant from value list (struct Person) { id: (byte) 7, name: (const string) $1 }
Successful SSA optimization Pass2ConstantInitializerValueLists
Identified constant from value list (struct Person[]) { { id: (byte) 4, name: (const string) $0 }, { id: (byte) 7, name: (const string) $1 } }
Successful SSA optimization Pass2ConstantInitializerValueLists
Constant (const struct Person[]) persons#0 = { { id: 4, name: $0 }, { id: 7, name: $1 } }
Constant (const byte) main::$3 = 1*SIZEOF_STRUCT_PERSON
Constant (const byte*) SCREEN#0 = (byte*) 1024
Constant (const byte) idx#20 = 0
Constant (const byte[]) DIGIT#0 = $2
Constant (const byte) print_person::i#0 = 0
Successful SSA optimization Pass2ConstantIdentification
Constant (const struct Person*) print_person::person#0 = persons#0
Successful SSA optimization Pass2ConstantIdentification
Converting *(pointer+n) to pointer[n] [20] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*) print_person::$0)) -- *((byte*)print_person::person#2 + OFFSET_STRUCT_PERSON_ID)
Successful SSA optimization Pass2InlineDerefIdx
Simplifying expression containing zero (byte*)print_person::person#2 in [19] (byte*) print_person::$0 ← (byte*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_ID
Simplifying expression containing zero (byte*)print_person::person#2 in [20] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_ID))
Successful SSA optimization PassNSimplifyExpressionWithZero
Eliminating unused variable (byte*) print_person::$0 and assignment [5] (byte*) print_person::$0 ← (byte*)(struct Person*) print_person::person#2
Eliminating unused constant (const byte) OFFSET_STRUCT_PERSON_ID
Successful SSA optimization PassNEliminateUnusedVars
Constant right-side identified [1] (struct Person*) print_person::person#1 ← (const struct Person[]) persons#0 + (const byte) main::$3
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const struct Person*) print_person::person#1 = persons#0+main::$3
Successful SSA optimization Pass2ConstantIdentification
Inlining constant with var siblings (const byte) print_person::i#0
Inlining constant with var siblings (const struct Person*) print_person::person#0
Inlining constant with var siblings (const struct Person*) print_person::person#1
Inlining constant with var siblings (const byte) idx#20
Constant inlined idx#20 = (byte) 0
Constant inlined main::$3 = (byte) 1*(const byte) SIZEOF_STRUCT_PERSON
Constant inlined print_person::person#0 = (const struct Person[]) persons#0
Constant inlined print_person::i#0 = (byte) 0
Constant inlined $2 = (const byte[]) DIGIT#0
Constant inlined print_person::person#1 = (const struct Person[]) persons#0+(byte) 1*(const byte) SIZEOF_STRUCT_PERSON
Successful SSA optimization Pass2ConstantInlining
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @2
Adding NOP phi() at start of @3
Adding NOP phi() at start of @end
Adding NOP phi() at start of main
Adding NOP phi() at start of main::@2
CALL GRAPH
Calls in [] to main:3
Calls in [main] to print_person:7 print_person:9
Created 4 initial phi equivalence classes
Coalesced [8] idx#21 ← idx#16
Coalesced [17] idx#22 ← idx#5
Coalesced [28] print_person::i#4 ← print_person::i#1
Coalesced [29] idx#23 ← idx#6
Coalesced down to 4 phi equivalence classes
Culled Empty Block (label) @1
Culled Empty Block (label) @3
Culled Empty Block (label) main::@2
Renumbering block @2 to @1
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
Adding NOP phi() at start of main
Adding NOP phi() at start of main::@1
FINAL CONTROL FLOW GRAPH
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
main: scope:[main] from @1
[4] phi()
[5] call print_person
to:main::@1
main::@1: scope:[main] from main
[6] phi()
[7] call print_person
to:main::@return
main::@return: scope:[main] from main::@1
[8] return
to:@return
print_person: scope:[print_person] from main main::@1
[9] (byte) idx#13 ← phi( main/(byte) 0 main::@1/(byte) idx#16 )
[9] (struct Person*) print_person::person#2 ← phi( main/(const struct Person[]) persons#0 main::@1/(const struct Person[]) persons#0+(byte) 1*(const byte) SIZEOF_STRUCT_PERSON )
[10] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*)(struct Person*) print_person::person#2))
[11] (byte) idx#4 ← ++ (byte) idx#13
[12] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' '
[13] (byte) idx#5 ← ++ (byte) idx#4
to:print_person::@1
print_person::@1: scope:[print_person] from print_person print_person::@2
[14] (byte) idx#14 ← phi( print_person/(byte) idx#5 print_person::@2/(byte) idx#6 )
[14] (byte) print_person::i#2 ← phi( print_person/(byte) 0 print_person::@2/(byte) print_person::i#1 )
[15] (byte[$10]) print_person::$1 ← (byte[$10])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME
[16] if((byte) 0!=*((byte[$10]) print_person::$1 + (byte) print_person::i#2)) goto print_person::@2
to:print_person::@3
print_person::@3: scope:[print_person] from print_person::@1
[17] *((const byte*) SCREEN#0 + (byte) idx#14) ← (byte) ' '
[18] (byte) idx#16 ← ++ (byte) idx#14
to:print_person::@return
print_person::@return: scope:[print_person] from print_person::@3
[19] return
to:@return
print_person::@2: scope:[print_person] from print_person::@1
[20] (byte[$10]) print_person::$2 ← (byte[$10])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME
[21] *((const byte*) SCREEN#0 + (byte) idx#14) ← *((byte[$10]) print_person::$2 + (byte) print_person::i#2)
[22] (byte) idx#6 ← ++ (byte) idx#14
[23] (byte) print_person::i#1 ← ++ (byte) print_person::i#2
to:print_person::@1
VARIABLE REGISTER WEIGHTS
(byte[]) DIGIT
(byte) Person::id
(byte[$10]) Person::name
(byte*) SCREEN
(byte) idx
(byte) idx#13 3.0
(byte) idx#14 6.5
(byte) idx#16 1.0
(byte) idx#4 3.0
(byte) idx#5 4.0
(byte) idx#6 11.0
(void()) main()
(struct Person[]) persons
(void()) print_person((struct Person*) print_person::person)
(byte[$10]) print_person::$1 22.0
(byte[$10]) print_person::$2 22.0
(byte) print_person::i
(byte) print_person::i#1 22.0
(byte) print_person::i#2 7.333333333333333
(struct Person*) print_person::person
(struct Person*) print_person::person#2
Initial phi equivalence classes
[ print_person::person#2 ]
[ idx#13 idx#16 ]
[ print_person::i#2 print_person::i#1 ]
[ idx#14 idx#5 idx#6 ]
Added variable idx#4 to zero page equivalence class [ idx#4 ]
Added variable print_person::$1 to zero page equivalence class [ print_person::$1 ]
Added variable print_person::$2 to zero page equivalence class [ print_person::$2 ]
Complete equivalence classes
[ print_person::person#2 ]
[ idx#13 idx#16 ]
[ print_person::i#2 print_person::i#1 ]
[ idx#14 idx#5 idx#6 ]
[ idx#4 ]
[ print_person::$1 ]
[ print_person::$2 ]
Allocated zp ZP_WORD:2 [ print_person::person#2 ]
Allocated zp ZP_BYTE:4 [ idx#13 idx#16 ]
Allocated zp ZP_BYTE:5 [ print_person::i#2 print_person::i#1 ]
Allocated zp ZP_BYTE:6 [ idx#14 idx#5 idx#6 ]
Allocated zp ZP_BYTE:7 [ idx#4 ]
Allocated zp ZP_WORD:8 [ print_person::$1 ]
Allocated zp ZP_WORD:10 [ print_person::$2 ]
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Example of a struct containing an array
// Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
// Global Constants & labels
.const SIZEOF_STRUCT_PERSON = $11
.const OFFSET_STRUCT_PERSON_NAME = 1
.label SCREEN = $400
.label idx = 7
.label idx_5 = 6
.label idx_6 = 6
.label idx_13 = 4
.label idx_14 = 6
.label idx_16 = 4
// @begin
bbegin:
// [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
// @1
b1:
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
main_from_b1:
jsr main
// [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
// @end
bend:
// main
main: {
// [5] call print_person
// [9] phi from main to print_person [phi:main->print_person]
print_person_from_main:
// [9] phi (byte) idx#13 = (byte) 0 [phi:main->print_person#0] -- vbuz1=vbuc1
lda #0
sta.z idx_13
// [9] phi (struct Person*) print_person::person#2 = (const struct Person[]) persons#0 [phi:main->print_person#1] -- pssz1=pssc1
lda #<persons
sta.z print_person.person
lda #>persons
sta.z print_person.person+1
jsr print_person
// [6] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
jmp b1
// main::@1
b1:
// [7] call print_person
// [9] phi from main::@1 to print_person [phi:main::@1->print_person]
print_person_from_b1:
// [9] phi (byte) idx#13 = (byte) idx#16 [phi:main::@1->print_person#0] -- register_copy
// [9] phi (struct Person*) print_person::person#2 = (const struct Person[]) persons#0+(byte) 1*(const byte) SIZEOF_STRUCT_PERSON [phi:main::@1->print_person#1] -- pssz1=pssc1
lda #<persons+1*SIZEOF_STRUCT_PERSON
sta.z print_person.person
lda #>persons+1*SIZEOF_STRUCT_PERSON
sta.z print_person.person+1
jsr print_person
jmp breturn
// main::@return
breturn:
// [8] return
rts
}
// print_person
// print_person(struct Person* zeropage(2) person)
print_person: {
.label _1 = 8
.label _2 = $a
.label i = 5
.label person = 2
// [10] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*)(struct Person*) print_person::person#2)) -- pbuc1_derefidx_vbuz1=pbuc2_derefidx_(_deref_pbuz2)
ldx.z idx_13
ldy #0
lda (person),y
tay
lda DIGIT,y
sta SCREEN,x
// [11] (byte) idx#4 ← ++ (byte) idx#13 -- vbuz1=_inc_vbuz2
ldy.z idx_13
iny
sty.z idx
// [12] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' ' -- pbuc1_derefidx_vbuz1=vbuc2
lda #' '
ldy.z idx
sta SCREEN,y
// [13] (byte) idx#5 ← ++ (byte) idx#4 -- vbuz1=_inc_vbuz2
ldy.z idx
iny
sty.z idx_5
// [14] phi from print_person to print_person::@1 [phi:print_person->print_person::@1]
b1_from_print_person:
// [14] phi (byte) idx#14 = (byte) idx#5 [phi:print_person->print_person::@1#0] -- register_copy
// [14] phi (byte) print_person::i#2 = (byte) 0 [phi:print_person->print_person::@1#1] -- vbuz1=vbuc1
lda #0
sta.z i
jmp b1
// print_person::@1
b1:
// [15] (byte[$10]) print_person::$1 ← (byte[$10])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME -- pbuz1=pbuz2_plus_vbuc1
lda #OFFSET_STRUCT_PERSON_NAME
clc
adc.z person
sta.z _1
lda #0
adc.z person+1
sta.z _1+1
// [16] if((byte) 0!=*((byte[$10]) print_person::$1 + (byte) print_person::i#2)) goto print_person::@2 -- vbuc1_neq_pbuz1_derefidx_vbuz2_then_la1
ldy.z i
lda (_1),y
cmp #0
bne b2
jmp b3
// print_person::@3
b3:
// [17] *((const byte*) SCREEN#0 + (byte) idx#14) ← (byte) ' ' -- pbuc1_derefidx_vbuz1=vbuc2
lda #' '
ldy.z idx_14
sta SCREEN,y
// [18] (byte) idx#16 ← ++ (byte) idx#14 -- vbuz1=_inc_vbuz2
ldy.z idx_14
iny
sty.z idx_16
jmp breturn
// print_person::@return
breturn:
// [19] return
rts
// print_person::@2
b2:
// [20] (byte[$10]) print_person::$2 ← (byte[$10])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME -- pbuz1=pbuz2_plus_vbuc1
lda #OFFSET_STRUCT_PERSON_NAME
clc
adc.z person
sta.z _2
lda #0
adc.z person+1
sta.z _2+1
// [21] *((const byte*) SCREEN#0 + (byte) idx#14) ← *((byte[$10]) print_person::$2 + (byte) print_person::i#2) -- pbuc1_derefidx_vbuz1=pbuz2_derefidx_vbuz3
ldx.z idx_14
ldy.z i
lda (_2),y
sta SCREEN,x
// [22] (byte) idx#6 ← ++ (byte) idx#14 -- vbuz1=_inc_vbuz1
inc.z idx_6
// [23] (byte) print_person::i#1 ← ++ (byte) print_person::i#2 -- vbuz1=_inc_vbuz1
inc.z i
// [14] phi from print_person::@2 to print_person::@1 [phi:print_person::@2->print_person::@1]
b1_from_b2:
// [14] phi (byte) idx#14 = (byte) idx#6 [phi:print_person::@2->print_person::@1#0] -- register_copy
// [14] phi (byte) print_person::i#2 = (byte) print_person::i#1 [phi:print_person::@2->print_person::@1#1] -- register_copy
jmp b1
}
// File Data
_0: .text "jesper"
.byte 0
_1: .text "henriette"
.byte 0
persons: .byte 4
.text "jesper"
.byte 0
.fill 9, 0
.byte 7
.text "henriette"
.byte 0
.fill 6, 0
DIGIT: .text "0123456789"
.byte 0
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [10] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*)(struct Person*) print_person::person#2)) [ print_person::person#2 idx#13 ] ( main:2::print_person:5 [ print_person::person#2 idx#13 ] main:2::print_person:7 [ print_person::person#2 idx#13 ] ) always clobbers reg byte a reg byte y
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:4 [ idx#13 idx#16 ]
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:4 [ idx#13 idx#16 ]
Statement [12] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' ' [ print_person::person#2 idx#4 ] ( main:2::print_person:5 [ print_person::person#2 idx#4 ] main:2::print_person:7 [ print_person::person#2 idx#4 ] ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:7 [ idx#4 ]
Statement [15] (byte[$10]) print_person::$1 ← (byte[$10])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME [ print_person::person#2 print_person::i#2 idx#14 print_person::$1 ] ( main:2::print_person:5 [ print_person::person#2 print_person::i#2 idx#14 print_person::$1 ] main:2::print_person:7 [ print_person::person#2 print_person::i#2 idx#14 print_person::$1 ] ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:5 [ print_person::i#2 print_person::i#1 ]
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:6 [ idx#14 idx#5 idx#6 ]
Statement [16] if((byte) 0!=*((byte[$10]) print_person::$1 + (byte) print_person::i#2)) goto print_person::@2 [ print_person::person#2 print_person::i#2 idx#14 ] ( main:2::print_person:5 [ print_person::person#2 print_person::i#2 idx#14 ] main:2::print_person:7 [ print_person::person#2 print_person::i#2 idx#14 ] ) always clobbers reg byte a
Statement [17] *((const byte*) SCREEN#0 + (byte) idx#14) ← (byte) ' ' [ idx#14 ] ( main:2::print_person:5 [ idx#14 ] main:2::print_person:7 [ idx#14 ] ) always clobbers reg byte a
Statement [20] (byte[$10]) print_person::$2 ← (byte[$10])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME [ print_person::person#2 print_person::i#2 idx#14 print_person::$2 ] ( main:2::print_person:5 [ print_person::person#2 print_person::i#2 idx#14 print_person::$2 ] main:2::print_person:7 [ print_person::person#2 print_person::i#2 idx#14 print_person::$2 ] ) always clobbers reg byte a
Statement [21] *((const byte*) SCREEN#0 + (byte) idx#14) ← *((byte[$10]) print_person::$2 + (byte) print_person::i#2) [ print_person::person#2 print_person::i#2 idx#14 ] ( main:2::print_person:5 [ print_person::person#2 print_person::i#2 idx#14 ] main:2::print_person:7 [ print_person::person#2 print_person::i#2 idx#14 ] ) always clobbers reg byte a
Statement [10] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*)(struct Person*) print_person::person#2)) [ print_person::person#2 idx#13 ] ( main:2::print_person:5 [ print_person::person#2 idx#13 ] main:2::print_person:7 [ print_person::person#2 idx#13 ] ) always clobbers reg byte a reg byte y
Statement [12] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' ' [ print_person::person#2 idx#4 ] ( main:2::print_person:5 [ print_person::person#2 idx#4 ] main:2::print_person:7 [ print_person::person#2 idx#4 ] ) always clobbers reg byte a
Statement [15] (byte[$10]) print_person::$1 ← (byte[$10])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME [ print_person::person#2 print_person::i#2 idx#14 print_person::$1 ] ( main:2::print_person:5 [ print_person::person#2 print_person::i#2 idx#14 print_person::$1 ] main:2::print_person:7 [ print_person::person#2 print_person::i#2 idx#14 print_person::$1 ] ) always clobbers reg byte a
Statement [16] if((byte) 0!=*((byte[$10]) print_person::$1 + (byte) print_person::i#2)) goto print_person::@2 [ print_person::person#2 print_person::i#2 idx#14 ] ( main:2::print_person:5 [ print_person::person#2 print_person::i#2 idx#14 ] main:2::print_person:7 [ print_person::person#2 print_person::i#2 idx#14 ] ) always clobbers reg byte a
Statement [17] *((const byte*) SCREEN#0 + (byte) idx#14) ← (byte) ' ' [ idx#14 ] ( main:2::print_person:5 [ idx#14 ] main:2::print_person:7 [ idx#14 ] ) always clobbers reg byte a
Statement [20] (byte[$10]) print_person::$2 ← (byte[$10])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME [ print_person::person#2 print_person::i#2 idx#14 print_person::$2 ] ( main:2::print_person:5 [ print_person::person#2 print_person::i#2 idx#14 print_person::$2 ] main:2::print_person:7 [ print_person::person#2 print_person::i#2 idx#14 print_person::$2 ] ) always clobbers reg byte a
Statement [21] *((const byte*) SCREEN#0 + (byte) idx#14) ← *((byte[$10]) print_person::$2 + (byte) print_person::i#2) [ print_person::person#2 print_person::i#2 idx#14 ] ( main:2::print_person:5 [ print_person::person#2 print_person::i#2 idx#14 ] main:2::print_person:7 [ print_person::person#2 print_person::i#2 idx#14 ] ) always clobbers reg byte a
Potential registers zp ZP_WORD:2 [ print_person::person#2 ] : zp ZP_WORD:2 ,
Potential registers zp ZP_BYTE:4 [ idx#13 idx#16 ] : zp ZP_BYTE:4 , reg byte x ,
Potential registers zp ZP_BYTE:5 [ print_person::i#2 print_person::i#1 ] : zp ZP_BYTE:5 , reg byte x , reg byte y ,
Potential registers zp ZP_BYTE:6 [ idx#14 idx#5 idx#6 ] : zp ZP_BYTE:6 , reg byte x , reg byte y ,
Potential registers zp ZP_BYTE:7 [ idx#4 ] : zp ZP_BYTE:7 , reg byte x , reg byte y ,
Potential registers zp ZP_WORD:8 [ print_person::$1 ] : zp ZP_WORD:8 ,
Potential registers zp ZP_WORD:10 [ print_person::$2 ] : zp ZP_WORD:10 ,
REGISTER UPLIFT SCOPES
Uplift Scope [print_person] 29.33: zp ZP_BYTE:5 [ print_person::i#2 print_person::i#1 ] 22: zp ZP_WORD:8 [ print_person::$1 ] 22: zp ZP_WORD:10 [ print_person::$2 ] 0: zp ZP_WORD:2 [ print_person::person#2 ]
Uplift Scope [] 21.5: zp ZP_BYTE:6 [ idx#14 idx#5 idx#6 ] 4: zp ZP_BYTE:4 [ idx#13 idx#16 ] 3: zp ZP_BYTE:7 [ idx#4 ]
Uplift Scope [Person]
Uplift Scope [main]
Uplifting [print_person] best 911 combination reg byte y [ print_person::i#2 print_person::i#1 ] zp ZP_WORD:8 [ print_person::$1 ] zp ZP_WORD:10 [ print_person::$2 ] zp ZP_WORD:2 [ print_person::person#2 ]
Uplifting [] best 821 combination reg byte x [ idx#14 idx#5 idx#6 ] reg byte x [ idx#13 idx#16 ] reg byte x [ idx#4 ]
Uplifting [Person] best 821 combination
Uplifting [main] best 821 combination
Allocated (was zp ZP_WORD:8) zp ZP_WORD:4 [ print_person::$1 ]
Allocated (was zp ZP_WORD:10) zp ZP_WORD:6 [ print_person::$2 ]
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Example of a struct containing an array
// Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
// Global Constants & labels
.const SIZEOF_STRUCT_PERSON = $11
.const OFFSET_STRUCT_PERSON_NAME = 1
.label SCREEN = $400
// @begin
bbegin:
// [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
// @1
b1:
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
main_from_b1:
jsr main
// [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
// @end
bend:
// main
main: {
// [5] call print_person
// [9] phi from main to print_person [phi:main->print_person]
print_person_from_main:
// [9] phi (byte) idx#13 = (byte) 0 [phi:main->print_person#0] -- vbuxx=vbuc1
ldx #0
// [9] phi (struct Person*) print_person::person#2 = (const struct Person[]) persons#0 [phi:main->print_person#1] -- pssz1=pssc1
lda #<persons
sta.z print_person.person
lda #>persons
sta.z print_person.person+1
jsr print_person
// [6] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
jmp b1
// main::@1
b1:
// [7] call print_person
// [9] phi from main::@1 to print_person [phi:main::@1->print_person]
print_person_from_b1:
// [9] phi (byte) idx#13 = (byte) idx#16 [phi:main::@1->print_person#0] -- register_copy
// [9] phi (struct Person*) print_person::person#2 = (const struct Person[]) persons#0+(byte) 1*(const byte) SIZEOF_STRUCT_PERSON [phi:main::@1->print_person#1] -- pssz1=pssc1
lda #<persons+1*SIZEOF_STRUCT_PERSON
sta.z print_person.person
lda #>persons+1*SIZEOF_STRUCT_PERSON
sta.z print_person.person+1
jsr print_person
jmp breturn
// main::@return
breturn:
// [8] return
rts
}
// print_person
// print_person(struct Person* zeropage(2) person)
print_person: {
.label _1 = 4
.label _2 = 6
.label person = 2
// [10] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*)(struct Person*) print_person::person#2)) -- pbuc1_derefidx_vbuxx=pbuc2_derefidx_(_deref_pbuz1)
ldy #0
lda (person),y
tay
lda DIGIT,y
sta SCREEN,x
// [11] (byte) idx#4 ← ++ (byte) idx#13 -- vbuxx=_inc_vbuxx
inx
// [12] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' ' -- pbuc1_derefidx_vbuxx=vbuc2
lda #' '
sta SCREEN,x
// [13] (byte) idx#5 ← ++ (byte) idx#4 -- vbuxx=_inc_vbuxx
inx
// [14] phi from print_person to print_person::@1 [phi:print_person->print_person::@1]
b1_from_print_person:
// [14] phi (byte) idx#14 = (byte) idx#5 [phi:print_person->print_person::@1#0] -- register_copy
// [14] phi (byte) print_person::i#2 = (byte) 0 [phi:print_person->print_person::@1#1] -- vbuyy=vbuc1
ldy #0
jmp b1
// print_person::@1
b1:
// [15] (byte[$10]) print_person::$1 ← (byte[$10])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME -- pbuz1=pbuz2_plus_vbuc1
lda #OFFSET_STRUCT_PERSON_NAME
clc
adc.z person
sta.z _1
lda #0
adc.z person+1
sta.z _1+1
// [16] if((byte) 0!=*((byte[$10]) print_person::$1 + (byte) print_person::i#2)) goto print_person::@2 -- vbuc1_neq_pbuz1_derefidx_vbuyy_then_la1
lda (_1),y
cmp #0
bne b2
jmp b3
// print_person::@3
b3:
// [17] *((const byte*) SCREEN#0 + (byte) idx#14) ← (byte) ' ' -- pbuc1_derefidx_vbuxx=vbuc2
lda #' '
sta SCREEN,x
// [18] (byte) idx#16 ← ++ (byte) idx#14 -- vbuxx=_inc_vbuxx
inx
jmp breturn
// print_person::@return
breturn:
// [19] return
rts
// print_person::@2
b2:
// [20] (byte[$10]) print_person::$2 ← (byte[$10])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME -- pbuz1=pbuz2_plus_vbuc1
lda #OFFSET_STRUCT_PERSON_NAME
clc
adc.z person
sta.z _2
lda #0
adc.z person+1
sta.z _2+1
// [21] *((const byte*) SCREEN#0 + (byte) idx#14) ← *((byte[$10]) print_person::$2 + (byte) print_person::i#2) -- pbuc1_derefidx_vbuxx=pbuz1_derefidx_vbuyy
lda (_2),y
sta SCREEN,x
// [22] (byte) idx#6 ← ++ (byte) idx#14 -- vbuxx=_inc_vbuxx
inx
// [23] (byte) print_person::i#1 ← ++ (byte) print_person::i#2 -- vbuyy=_inc_vbuyy
iny
// [14] phi from print_person::@2 to print_person::@1 [phi:print_person::@2->print_person::@1]
b1_from_b2:
// [14] phi (byte) idx#14 = (byte) idx#6 [phi:print_person::@2->print_person::@1#0] -- register_copy
// [14] phi (byte) print_person::i#2 = (byte) print_person::i#1 [phi:print_person::@2->print_person::@1#1] -- register_copy
jmp b1
}
// File Data
_0: .text "jesper"
.byte 0
_1: .text "henriette"
.byte 0
persons: .byte 4
.text "jesper"
.byte 0
.fill 9, 0
.byte 7
.text "henriette"
.byte 0
.fill 6, 0
DIGIT: .text "0123456789"
.byte 0
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b1
Removing instruction jmp bend
Removing instruction jmp b1
Removing instruction jmp breturn
Removing instruction jmp b1
Removing instruction jmp b3
Removing instruction jmp breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction b1_from_bbegin:
Removing instruction b1:
Removing instruction main_from_b1:
Removing instruction bend_from_b1:
Removing instruction b1_from_main:
Removing instruction print_person_from_b1:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction bend:
Removing instruction print_person_from_main:
Removing instruction b1:
Removing instruction breturn:
Removing instruction b1_from_print_person:
Removing instruction b3:
Removing instruction breturn:
Removing instruction b1_from_b2:
Succesful ASM optimization Pass5UnusedLabelElimination
Updating BasicUpstart to call main directly
Removing instruction jsr main
Succesful ASM optimization Pass5SkipBegin
Removing instruction bbegin:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(const string) $0 $0 = (string) "jesper"
(const string) $1 $1 = (string) "henriette"
(label) @1
(label) @begin
(label) @end
(byte[]) DIGIT
(const byte[]) DIGIT#0 DIGIT = (string) "0123456789"
(const byte) OFFSET_STRUCT_PERSON_NAME OFFSET_STRUCT_PERSON_NAME = (byte) 1
(byte) Person::id
(byte[$10]) Person::name
(byte*) SCREEN
(const byte*) SCREEN#0 SCREEN = (byte*) 1024
(const byte) SIZEOF_STRUCT_PERSON SIZEOF_STRUCT_PERSON = (byte) $11
(byte) idx
(byte) idx#13 reg byte x 3.0
(byte) idx#14 reg byte x 6.5
(byte) idx#16 reg byte x 1.0
(byte) idx#4 reg byte x 3.0
(byte) idx#5 reg byte x 4.0
(byte) idx#6 reg byte x 11.0
(void()) main()
(label) main::@1
(label) main::@return
(struct Person[]) persons
(const struct Person[]) persons#0 persons = { { id: (byte) 4, name: (const string) $0 }, { id: (byte) 7, name: (const string) $1 } }
(void()) print_person((struct Person*) print_person::person)
(byte[$10]) print_person::$1 $1 zp ZP_WORD:4 22.0
(byte[$10]) print_person::$2 $2 zp ZP_WORD:6 22.0
(label) print_person::@1
(label) print_person::@2
(label) print_person::@3
(label) print_person::@return
(byte) print_person::i
(byte) print_person::i#1 reg byte y 22.0
(byte) print_person::i#2 reg byte y 7.333333333333333
(struct Person*) print_person::person
(struct Person*) print_person::person#2 person zp ZP_WORD:2
zp ZP_WORD:2 [ print_person::person#2 ]
reg byte x [ idx#13 idx#16 ]
reg byte y [ print_person::i#2 print_person::i#1 ]
reg byte x [ idx#14 idx#5 idx#6 ]
reg byte x [ idx#4 ]
zp ZP_WORD:4 [ print_person::$1 ]
zp ZP_WORD:6 [ print_person::$2 ]
FINAL ASSEMBLER
Score: 740
// File Comments
// Example of a struct containing an array
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.const SIZEOF_STRUCT_PERSON = $11
.const OFFSET_STRUCT_PERSON_NAME = 1
.label SCREEN = $400
// @begin
// [1] phi from @begin to @1 [phi:@begin->@1]
// @1
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
// [3] phi from @1 to @end [phi:@1->@end]
// @end
// main
main: {
// print_person(persons)
// [5] call print_person
// [9] phi from main to print_person [phi:main->print_person]
// [9] phi (byte) idx#13 = (byte) 0 [phi:main->print_person#0] -- vbuxx=vbuc1
ldx #0
// [9] phi (struct Person*) print_person::person#2 = (const struct Person[]) persons#0 [phi:main->print_person#1] -- pssz1=pssc1
lda #<persons
sta.z print_person.person
lda #>persons
sta.z print_person.person+1
jsr print_person
// [6] phi from main to main::@1 [phi:main->main::@1]
// main::@1
// print_person(persons+1)
// [7] call print_person
// [9] phi from main::@1 to print_person [phi:main::@1->print_person]
// [9] phi (byte) idx#13 = (byte) idx#16 [phi:main::@1->print_person#0] -- register_copy
// [9] phi (struct Person*) print_person::person#2 = (const struct Person[]) persons#0+(byte) 1*(const byte) SIZEOF_STRUCT_PERSON [phi:main::@1->print_person#1] -- pssz1=pssc1
lda #<persons+1*SIZEOF_STRUCT_PERSON
sta.z print_person.person
lda #>persons+1*SIZEOF_STRUCT_PERSON
sta.z print_person.person+1
jsr print_person
// main::@return
// }
// [8] return
rts
}
// print_person
// print_person(struct Person* zeropage(2) person)
print_person: {
.label _1 = 4
.label _2 = 6
.label person = 2
// SCREEN[idx++] = DIGIT[person->id]
// [10] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*)(struct Person*) print_person::person#2)) -- pbuc1_derefidx_vbuxx=pbuc2_derefidx_(_deref_pbuz1)
ldy #0
lda (person),y
tay
lda DIGIT,y
sta SCREEN,x
// SCREEN[idx++] = DIGIT[person->id];
// [11] (byte) idx#4 ← ++ (byte) idx#13 -- vbuxx=_inc_vbuxx
inx
// SCREEN[idx++] = ' '
// [12] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' ' -- pbuc1_derefidx_vbuxx=vbuc2
lda #' '
sta SCREEN,x
// SCREEN[idx++] = ' ';
// [13] (byte) idx#5 ← ++ (byte) idx#4 -- vbuxx=_inc_vbuxx
inx
// [14] phi from print_person to print_person::@1 [phi:print_person->print_person::@1]
// [14] phi (byte) idx#14 = (byte) idx#5 [phi:print_person->print_person::@1#0] -- register_copy
// [14] phi (byte) print_person::i#2 = (byte) 0 [phi:print_person->print_person::@1#1] -- vbuyy=vbuc1
ldy #0
// print_person::@1
b1:
// for(byte i=0; person->name[i]; i++)
// [15] (byte[$10]) print_person::$1 ← (byte[$10])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME -- pbuz1=pbuz2_plus_vbuc1
lda #OFFSET_STRUCT_PERSON_NAME
clc
adc.z person
sta.z _1
lda #0
adc.z person+1
sta.z _1+1
// [16] if((byte) 0!=*((byte[$10]) print_person::$1 + (byte) print_person::i#2)) goto print_person::@2 -- vbuc1_neq_pbuz1_derefidx_vbuyy_then_la1
lda (_1),y
cmp #0
bne b2
// print_person::@3
// SCREEN[idx++] = ' '
// [17] *((const byte*) SCREEN#0 + (byte) idx#14) ← (byte) ' ' -- pbuc1_derefidx_vbuxx=vbuc2
lda #' '
sta SCREEN,x
// SCREEN[idx++] = ' ';
// [18] (byte) idx#16 ← ++ (byte) idx#14 -- vbuxx=_inc_vbuxx
inx
// print_person::@return
// }
// [19] return
rts
// print_person::@2
b2:
// SCREEN[idx++] = person->name[i]
// [20] (byte[$10]) print_person::$2 ← (byte[$10])(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME -- pbuz1=pbuz2_plus_vbuc1
lda #OFFSET_STRUCT_PERSON_NAME
clc
adc.z person
sta.z _2
lda #0
adc.z person+1
sta.z _2+1
// [21] *((const byte*) SCREEN#0 + (byte) idx#14) ← *((byte[$10]) print_person::$2 + (byte) print_person::i#2) -- pbuc1_derefidx_vbuxx=pbuz1_derefidx_vbuyy
lda (_2),y
sta SCREEN,x
// SCREEN[idx++] = person->name[i];
// [22] (byte) idx#6 ← ++ (byte) idx#14 -- vbuxx=_inc_vbuxx
inx
// for(byte i=0; person->name[i]; i++)
// [23] (byte) print_person::i#1 ← ++ (byte) print_person::i#2 -- vbuyy=_inc_vbuyy
iny
// [14] phi from print_person::@2 to print_person::@1 [phi:print_person::@2->print_person::@1]
// [14] phi (byte) idx#14 = (byte) idx#6 [phi:print_person::@2->print_person::@1#0] -- register_copy
// [14] phi (byte) print_person::i#2 = (byte) print_person::i#1 [phi:print_person::@2->print_person::@1#1] -- register_copy
jmp b1
}
// File Data
_0: .text "jesper"
.byte 0
_1: .text "henriette"
.byte 0
persons: .byte 4
.text "jesper"
.byte 0
.fill 9, 0
.byte 7
.text "henriette"
.byte 0
.fill 6, 0
DIGIT: .text "0123456789"
.byte 0

View File

@ -0,0 +1,45 @@
(const string) $0 $0 = (string) "jesper"
(const string) $1 $1 = (string) "henriette"
(label) @1
(label) @begin
(label) @end
(byte[]) DIGIT
(const byte[]) DIGIT#0 DIGIT = (string) "0123456789"
(const byte) OFFSET_STRUCT_PERSON_NAME OFFSET_STRUCT_PERSON_NAME = (byte) 1
(byte) Person::id
(byte[$10]) Person::name
(byte*) SCREEN
(const byte*) SCREEN#0 SCREEN = (byte*) 1024
(const byte) SIZEOF_STRUCT_PERSON SIZEOF_STRUCT_PERSON = (byte) $11
(byte) idx
(byte) idx#13 reg byte x 3.0
(byte) idx#14 reg byte x 6.5
(byte) idx#16 reg byte x 1.0
(byte) idx#4 reg byte x 3.0
(byte) idx#5 reg byte x 4.0
(byte) idx#6 reg byte x 11.0
(void()) main()
(label) main::@1
(label) main::@return
(struct Person[]) persons
(const struct Person[]) persons#0 persons = { { id: (byte) 4, name: (const string) $0 }, { id: (byte) 7, name: (const string) $1 } }
(void()) print_person((struct Person*) print_person::person)
(byte[$10]) print_person::$1 $1 zp ZP_WORD:4 22.0
(byte[$10]) print_person::$2 $2 zp ZP_WORD:6 22.0
(label) print_person::@1
(label) print_person::@2
(label) print_person::@3
(label) print_person::@return
(byte) print_person::i
(byte) print_person::i#1 reg byte y 22.0
(byte) print_person::i#2 reg byte y 7.333333333333333
(struct Person*) print_person::person
(struct Person*) print_person::person#2 person zp ZP_WORD:2
zp ZP_WORD:2 [ print_person::person#2 ]
reg byte x [ idx#13 idx#16 ]
reg byte y [ print_person::i#2 print_person::i#1 ]
reg byte x [ idx#14 idx#5 idx#6 ]
reg byte x [ idx#4 ]
zp ZP_WORD:4 [ print_person::$1 ]
zp ZP_WORD:6 [ print_person::$2 ]

View File

@ -1,5 +1,4 @@
// Example of a struct containing an array
// https://gitlab.com/camelot/kickc/issues/312
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"

View File

@ -314,7 +314,6 @@ INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Example of a struct containing an array
// https://gitlab.com/camelot/kickc/issues/312
// Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
@ -400,7 +399,6 @@ Uplifting [] best 85 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Example of a struct containing an array
// https://gitlab.com/camelot/kickc/issues/312
// Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
@ -508,7 +506,6 @@ Score: 70
// File Comments
// Example of a struct containing an array
// https://gitlab.com/camelot/kickc/issues/312
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)

View File

@ -0,0 +1,29 @@
// Example of a struct containing an array
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.const SIZEOF_STRUCT_PERSON = $10
.const OFFSET_STRUCT_PERSON_NAME = 1
main: {
.label SCREEN = $400
.label person = persons+SIZEOF_STRUCT_PERSON
lda persons+OFFSET_STRUCT_PERSON_NAME+2
sta SCREEN
lda person+OFFSET_STRUCT_PERSON_NAME+2
sta SCREEN+1
rts
}
_0: .text "jesper"
.byte 0
_1: .text "henry"
.byte 0
persons: .byte 7
.text "jesper"
.byte 0
.fill 6, 0
.word $141
.byte 9
.text "henry"
.byte 0
.fill 7, 0
.word $7b

View File

@ -0,0 +1,16 @@
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
main: scope:[main] from @1
[4] *((const byte*) main::SCREEN#0) ← *((byte[$d])(const struct Person[2]) persons#0+(const byte) OFFSET_STRUCT_PERSON_NAME+(byte) 2)
[5] *((const byte*) main::SCREEN#0+(byte) 1) ← *((byte[$d])(const struct Person*) main::person#1+(const byte) OFFSET_STRUCT_PERSON_NAME+(byte) 2)
to:main::@return
main::@return: scope:[main] from main
[6] return
to:@return

View File

@ -0,0 +1,374 @@
Fixing struct type size struct Person to 16
Fixing struct type size struct Person to 16
Fixing pointer increment (struct Person*) main::person ← ++ (struct Person*) main::person
Rewriting struct pointer member access *((struct Person*) main::person).name
Rewriting struct pointer member access *((struct Person*) main::person).name
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
(struct Person[2]) persons#0 ← { { (number) 7, (const string) $0, (number) $141 }, { (number) 9, (const string) $1, (number) $7b } }
to:@1
main: scope:[main] from @1
(byte*) main::SCREEN#0 ← ((byte*)) (number) $400
(struct Person*) main::person#0 ← (struct Person[2]) persons#0
(byte[$d]) main::$0 ← (byte[$d])(struct Person*) main::person#0 + (const byte) OFFSET_STRUCT_PERSON_NAME
*((byte*) main::SCREEN#0 + (number) 0) ← *((byte[$d]) main::$0 + (number) 2)
(struct Person*) main::person#1 ← (struct Person*) main::person#0 + (const byte) SIZEOF_STRUCT_PERSON
(byte[$d]) main::$1 ← (byte[$d])(struct Person*) main::person#1 + (const byte) OFFSET_STRUCT_PERSON_NAME
*((byte*) main::SCREEN#0 + (number) 1) ← *((byte[$d]) main::$1 + (number) 2)
to:main::@return
main::@return: scope:[main] from main
return
to:@return
@1: scope:[] from @begin
call main
to:@2
@2: scope:[] from @1
to:@end
@end: scope:[] from @2
SYMBOL TABLE SSA
(const string) $0 = (string) "jesper"
(const string) $1 = (string) "henry"
(label) @1
(label) @2
(label) @begin
(label) @end
(const byte) OFFSET_STRUCT_PERSON_NAME = (byte) 1
(word) Person::age
(byte) Person::id
(byte[$d]) Person::name
(const byte) SIZEOF_STRUCT_PERSON = (byte) $10
(void()) main()
(byte[$d]) main::$0
(byte[$d]) main::$1
(label) main::@return
(byte*) main::SCREEN
(byte*) main::SCREEN#0
(struct Person*) main::person
(struct Person*) main::person#0
(struct Person*) main::person#1
(struct Person[2]) persons
(struct Person[2]) persons#0
Adding number conversion cast (unumber) 2 in *((byte*) main::SCREEN#0 + (number) 0) ← *((byte[$d]) main::$0 + (number) 2)
Adding number conversion cast (unumber) 0 in *((byte*) main::SCREEN#0 + (number) 0) ← *((byte[$d]) main::$0 + (unumber)(number) 2)
Adding number conversion cast (unumber) 2 in *((byte*) main::SCREEN#0 + (number) 1) ← *((byte[$d]) main::$1 + (number) 2)
Adding number conversion cast (unumber) 1 in *((byte*) main::SCREEN#0 + (number) 1) ← *((byte[$d]) main::$1 + (unumber)(number) 2)
Successful SSA optimization PassNAddNumberTypeConversions
Added casts to value list in (struct Person[2]) persons#0 ← (struct Person[2]){ (struct Person){ (byte)(number) 7, (const string) $0, (word)(number) $141 }, (struct Person){ (byte)(number) 9, (const string) $1, (word)(number) $7b } }
Successful SSA optimization PassNAddInitializerValueListTypeCasts
Inlining cast (byte*) main::SCREEN#0 ← (byte*)(number) $400
Successful SSA optimization Pass2InlineCast
Simplifying constant integer cast 7
Simplifying constant integer cast $141
Simplifying constant integer cast 9
Simplifying constant integer cast $7b
Simplifying constant pointer cast (byte*) 1024
Simplifying constant integer cast 2
Simplifying constant integer cast 0
Simplifying constant integer cast 2
Simplifying constant integer cast 1
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 2
Finalized unsigned number type (byte) 0
Finalized unsigned number type (byte) 2
Finalized unsigned number type (byte) 1
Successful SSA optimization PassNFinalizeNumberTypeConversions
Identified constant from value list (struct Person) { id: (byte) 7, name: (const string) $0, age: (word) $141 }
Identified constant from value list (struct Person) { id: (byte) 9, name: (const string) $1, age: (word) $7b }
Successful SSA optimization Pass2ConstantInitializerValueLists
Identified constant from value list (struct Person[2]) { { id: (byte) 7, name: (const string) $0, age: (word) $141 }, { id: (byte) 9, name: (const string) $1, age: (word) $7b } }
Successful SSA optimization Pass2ConstantInitializerValueLists
Constant (const struct Person[2]) persons#0 = { { id: 7, name: $0, age: $141 }, { id: 9, name: $1, age: $7b } }
Constant (const byte*) main::SCREEN#0 = (byte*) 1024
Successful SSA optimization Pass2ConstantIdentification
Constant (const struct Person*) main::person#0 = persons#0
Successful SSA optimization Pass2ConstantIdentification
Constant value identified (byte[$d])main::person#0 in [3] (byte[$d]) main::$0 ← (byte[$d])(const struct Person*) main::person#0 + (const byte) OFFSET_STRUCT_PERSON_NAME
Successful SSA optimization Pass2ConstantValues
Simplifying expression containing zero main::SCREEN#0 in [4] *((const byte*) main::SCREEN#0 + (byte) 0) ← *((byte[$d]) main::$0 + (byte) 2)
Successful SSA optimization PassNSimplifyExpressionWithZero
Constant right-side identified [0] (byte[$d]) main::$0 ← (byte[$d])(const struct Person*) main::person#0 + (const byte) OFFSET_STRUCT_PERSON_NAME
Constant right-side identified [2] (struct Person*) main::person#1 ← (const struct Person*) main::person#0 + (const byte) SIZEOF_STRUCT_PERSON
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const byte[$d]) main::$0 = (byte[$d])main::person#0+OFFSET_STRUCT_PERSON_NAME
Constant (const struct Person*) main::person#1 = main::person#0+SIZEOF_STRUCT_PERSON
Successful SSA optimization Pass2ConstantIdentification
Constant value identified (byte[$d])main::person#1 in [3] (byte[$d]) main::$1 ← (byte[$d])(const struct Person*) main::person#1 + (const byte) OFFSET_STRUCT_PERSON_NAME
Successful SSA optimization Pass2ConstantValues
Constant right-side identified [1] (byte[$d]) main::$1 ← (byte[$d])(const struct Person*) main::person#1 + (const byte) OFFSET_STRUCT_PERSON_NAME
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const byte[$d]) main::$1 = (byte[$d])main::person#1+OFFSET_STRUCT_PERSON_NAME
Successful SSA optimization Pass2ConstantIdentification
Inlining constant with different constant siblings (const struct Person*) main::person#0
Constant inlined main::$1 = (byte[$d])(const struct Person*) main::person#1+(const byte) OFFSET_STRUCT_PERSON_NAME
Constant inlined main::person#0 = (const struct Person[2]) persons#0
Constant inlined main::$0 = (byte[$d])(const struct Person[2]) persons#0+(const byte) OFFSET_STRUCT_PERSON_NAME
Successful SSA optimization Pass2ConstantInlining
Consolidated array index constant in *((byte[$d])persons#0+OFFSET_STRUCT_PERSON_NAME+2)
Consolidated array index constant in *((byte[$d])main::person#1+OFFSET_STRUCT_PERSON_NAME+2)
Consolidated array index constant in *(main::SCREEN#0+1)
Successful SSA optimization Pass2ConstantAdditionElimination
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @2
Adding NOP phi() at start of @end
CALL GRAPH
Calls in [] to main:2
Created 0 initial phi equivalence classes
Coalesced down to 0 phi equivalence classes
Culled Empty Block (label) @2
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
FINAL CONTROL FLOW GRAPH
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
main: scope:[main] from @1
[4] *((const byte*) main::SCREEN#0) ← *((byte[$d])(const struct Person[2]) persons#0+(const byte) OFFSET_STRUCT_PERSON_NAME+(byte) 2)
[5] *((const byte*) main::SCREEN#0+(byte) 1) ← *((byte[$d])(const struct Person*) main::person#1+(const byte) OFFSET_STRUCT_PERSON_NAME+(byte) 2)
to:main::@return
main::@return: scope:[main] from main
[6] return
to:@return
VARIABLE REGISTER WEIGHTS
(word) Person::age
(byte) Person::id
(byte[$d]) Person::name
(void()) main()
(byte*) main::SCREEN
(struct Person*) main::person
(struct Person[2]) persons
Initial phi equivalence classes
Complete equivalence classes
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Example of a struct containing an array
// Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
// Global Constants & labels
.const SIZEOF_STRUCT_PERSON = $10
.const OFFSET_STRUCT_PERSON_NAME = 1
// @begin
bbegin:
// [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
// @1
b1:
// [2] call main
jsr main
// [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
// @end
bend:
// main
main: {
.label SCREEN = $400
.label person = persons+SIZEOF_STRUCT_PERSON
// [4] *((const byte*) main::SCREEN#0) ← *((byte[$d])(const struct Person[2]) persons#0+(const byte) OFFSET_STRUCT_PERSON_NAME+(byte) 2) -- _deref_pbuc1=_deref_pbuc2
lda persons+OFFSET_STRUCT_PERSON_NAME+2
sta SCREEN
// [5] *((const byte*) main::SCREEN#0+(byte) 1) ← *((byte[$d])(const struct Person*) main::person#1+(const byte) OFFSET_STRUCT_PERSON_NAME+(byte) 2) -- _deref_pbuc1=_deref_pbuc2
lda person+OFFSET_STRUCT_PERSON_NAME+2
sta SCREEN+1
jmp breturn
// main::@return
breturn:
// [6] return
rts
}
// File Data
_0: .text "jesper"
.byte 0
_1: .text "henry"
.byte 0
persons: .byte 7
.text "jesper"
.byte 0
.fill 6, 0
.word $141
.byte 9
.text "henry"
.byte 0
.fill 7, 0
.word $7b
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [4] *((const byte*) main::SCREEN#0) ← *((byte[$d])(const struct Person[2]) persons#0+(const byte) OFFSET_STRUCT_PERSON_NAME+(byte) 2) [ ] ( main:2 [ ] ) always clobbers reg byte a
Statement [5] *((const byte*) main::SCREEN#0+(byte) 1) ← *((byte[$d])(const struct Person*) main::person#1+(const byte) OFFSET_STRUCT_PERSON_NAME+(byte) 2) [ ] ( main:2 [ ] ) always clobbers reg byte a
REGISTER UPLIFT SCOPES
Uplift Scope [Person]
Uplift Scope [main]
Uplift Scope []
Uplifting [Person] best 37 combination
Uplifting [main] best 37 combination
Uplifting [] best 37 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Example of a struct containing an array
// Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
// Global Constants & labels
.const SIZEOF_STRUCT_PERSON = $10
.const OFFSET_STRUCT_PERSON_NAME = 1
// @begin
bbegin:
// [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
// @1
b1:
// [2] call main
jsr main
// [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
// @end
bend:
// main
main: {
.label SCREEN = $400
.label person = persons+SIZEOF_STRUCT_PERSON
// [4] *((const byte*) main::SCREEN#0) ← *((byte[$d])(const struct Person[2]) persons#0+(const byte) OFFSET_STRUCT_PERSON_NAME+(byte) 2) -- _deref_pbuc1=_deref_pbuc2
lda persons+OFFSET_STRUCT_PERSON_NAME+2
sta SCREEN
// [5] *((const byte*) main::SCREEN#0+(byte) 1) ← *((byte[$d])(const struct Person*) main::person#1+(const byte) OFFSET_STRUCT_PERSON_NAME+(byte) 2) -- _deref_pbuc1=_deref_pbuc2
lda person+OFFSET_STRUCT_PERSON_NAME+2
sta SCREEN+1
jmp breturn
// main::@return
breturn:
// [6] return
rts
}
// File Data
_0: .text "jesper"
.byte 0
_1: .text "henry"
.byte 0
persons: .byte 7
.text "jesper"
.byte 0
.fill 6, 0
.word $141
.byte 9
.text "henry"
.byte 0
.fill 7, 0
.word $7b
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b1
Removing instruction jmp bend
Removing instruction jmp breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction b1_from_bbegin:
Removing instruction b1:
Removing instruction bend_from_b1:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction bend:
Removing instruction breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Updating BasicUpstart to call main directly
Removing instruction jsr main
Succesful ASM optimization Pass5SkipBegin
Removing instruction bbegin:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(const string) $0 $0 = (string) "jesper"
(const string) $1 $1 = (string) "henry"
(label) @1
(label) @begin
(label) @end
(const byte) OFFSET_STRUCT_PERSON_NAME OFFSET_STRUCT_PERSON_NAME = (byte) 1
(word) Person::age
(byte) Person::id
(byte[$d]) Person::name
(const byte) SIZEOF_STRUCT_PERSON SIZEOF_STRUCT_PERSON = (byte) $10
(void()) main()
(label) main::@return
(byte*) main::SCREEN
(const byte*) main::SCREEN#0 SCREEN = (byte*) 1024
(struct Person*) main::person
(const struct Person*) main::person#1 person = (const struct Person[2]) persons#0+(const byte) SIZEOF_STRUCT_PERSON
(struct Person[2]) persons
(const struct Person[2]) persons#0 persons = { { id: (byte) 7, name: (const string) $0, age: (word) $141 }, { id: (byte) 9, name: (const string) $1, age: (word) $7b } }
FINAL ASSEMBLER
Score: 22
// File Comments
// Example of a struct containing an array
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.const SIZEOF_STRUCT_PERSON = $10
.const OFFSET_STRUCT_PERSON_NAME = 1
// @begin
// [1] phi from @begin to @1 [phi:@begin->@1]
// @1
// [2] call main
// [3] phi from @1 to @end [phi:@1->@end]
// @end
// main
main: {
.label SCREEN = $400
.label person = persons+SIZEOF_STRUCT_PERSON
// SCREEN[0] = person->name[2]
// [4] *((const byte*) main::SCREEN#0) ← *((byte[$d])(const struct Person[2]) persons#0+(const byte) OFFSET_STRUCT_PERSON_NAME+(byte) 2) -- _deref_pbuc1=_deref_pbuc2
lda persons+OFFSET_STRUCT_PERSON_NAME+2
sta SCREEN
// SCREEN[1] = person->name[2]
// [5] *((const byte*) main::SCREEN#0+(byte) 1) ← *((byte[$d])(const struct Person*) main::person#1+(const byte) OFFSET_STRUCT_PERSON_NAME+(byte) 2) -- _deref_pbuc1=_deref_pbuc2
lda person+OFFSET_STRUCT_PERSON_NAME+2
sta SCREEN+1
// main::@return
// }
// [6] return
rts
}
// File Data
_0: .text "jesper"
.byte 0
_1: .text "henry"
.byte 0
persons: .byte 7
.text "jesper"
.byte 0
.fill 6, 0
.word $141
.byte 9
.text "henry"
.byte 0
.fill 7, 0
.word $7b

View File

@ -0,0 +1,19 @@
(const string) $0 $0 = (string) "jesper"
(const string) $1 $1 = (string) "henry"
(label) @1
(label) @begin
(label) @end
(const byte) OFFSET_STRUCT_PERSON_NAME OFFSET_STRUCT_PERSON_NAME = (byte) 1
(word) Person::age
(byte) Person::id
(byte[$d]) Person::name
(const byte) SIZEOF_STRUCT_PERSON SIZEOF_STRUCT_PERSON = (byte) $10
(void()) main()
(label) main::@return
(byte*) main::SCREEN
(const byte*) main::SCREEN#0 SCREEN = (byte*) 1024
(struct Person*) main::person
(const struct Person*) main::person#1 person = (const struct Person[2]) persons#0+(const byte) SIZEOF_STRUCT_PERSON
(struct Person[2]) persons
(const struct Person[2]) persons#0 persons = { { id: (byte) 7, name: (const string) $0, age: (word) $141 }, { id: (byte) 9, name: (const string) $1, age: (word) $7b } }