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:
parent
24e40b9083
commit
8b441f6814
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -36,4 +36,8 @@ public class AsmSetEncoding implements AsmLine {
|
||||
public void setIndex(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public ConstantString.Encoding getEncoding() {
|
||||
return encoding;
|
||||
}
|
||||
}
|
||||
|
@ -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()) {
|
||||
|
@ -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 {
|
||||
|
@ -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++] = ' ';
|
||||
}
|
@ -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;
|
||||
|
@ -1,5 +1,4 @@
|
||||
// Example of a struct containing an array
|
||||
// https://gitlab.com/camelot/kickc/issues/312
|
||||
|
||||
struct Person {
|
||||
char id;
|
||||
|
@ -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];
|
||||
}
|
||||
|
||||
|
||||
|
@ -30,4 +30,4 @@ main: {
|
||||
.byte 0
|
||||
.fill 8, 0
|
||||
msg2: .byte 'c', 'm', 'l'
|
||||
.fill 13, 0
|
||||
.fill $d, 0
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -38,8 +38,7 @@ main: {
|
||||
bne b1
|
||||
rts
|
||||
}
|
||||
points:
|
||||
.byte 1
|
||||
points: .byte 1
|
||||
.word 2
|
||||
.byte 3
|
||||
.word 4
|
||||
|
@ -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
|
||||
|
@ -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'
|
||||
|
@ -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'
|
||||
|
||||
|
@ -27,6 +27,5 @@ main: {
|
||||
jmp b1
|
||||
}
|
||||
seq: .word 1, 2, 3
|
||||
settings:
|
||||
.byte 3
|
||||
settings: .byte 3
|
||||
.word seq
|
||||
|
@ -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
|
||||
|
||||
|
76
src/test/ref/struct-ptr-23.asm
Normal file
76
src/test/ref/struct-ptr-23.asm
Normal 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
|
42
src/test/ref/struct-ptr-23.cfg
Normal file
42
src/test/ref/struct-ptr-23.cfg
Normal 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
|
906
src/test/ref/struct-ptr-23.log
Normal file
906
src/test/ref/struct-ptr-23.log
Normal 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
|
||||
|
43
src/test/ref/struct-ptr-23.sym
Normal file
43
src/test/ref/struct-ptr-23.sym
Normal 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 ]
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -48,8 +48,7 @@ print: {
|
||||
sty.z idx
|
||||
rts
|
||||
}
|
||||
points:
|
||||
.byte 1
|
||||
points: .byte 1
|
||||
.word $83f
|
||||
.byte 3
|
||||
.word $107e
|
||||
|
@ -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
|
||||
|
79
src/test/ref/struct-ptr-31.asm
Normal file
79
src/test/ref/struct-ptr-31.asm
Normal 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
|
47
src/test/ref/struct-ptr-31.cfg
Normal file
47
src/test/ref/struct-ptr-31.cfg
Normal 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
|
956
src/test/ref/struct-ptr-31.log
Normal file
956
src/test/ref/struct-ptr-31.log
Normal 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
|
||||
|
45
src/test/ref/struct-ptr-31.sym
Normal file
45
src/test/ref/struct-ptr-31.sym
Normal 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 ]
|
@ -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"
|
||||
|
@ -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)
|
||||
|
29
src/test/ref/struct-ptr-33.asm
Normal file
29
src/test/ref/struct-ptr-33.asm
Normal 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
|
16
src/test/ref/struct-ptr-33.cfg
Normal file
16
src/test/ref/struct-ptr-33.cfg
Normal 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
|
374
src/test/ref/struct-ptr-33.log
Normal file
374
src/test/ref/struct-ptr-33.log
Normal 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
|
||||
|
19
src/test/ref/struct-ptr-33.sym
Normal file
19
src/test/ref/struct-ptr-33.sym
Normal 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 } }
|
||||
|
Loading…
x
Reference in New Issue
Block a user