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

Working on improvements regarding global initializers and unnecessary unwinding of constant structs. Introduced RValueUnwinding for handling a single value.

This commit is contained in:
jespergravgaard 2020-01-02 14:36:02 +01:00
parent db595d0b53
commit 6a9f59cda1
19 changed files with 769 additions and 251 deletions

@ -66,23 +66,29 @@ public class StructUnwinding {
return new ArrayList<>(memberUnwinding.keySet());
}
public RValue getMemberUnwinding(String memberName, ProgramScope programScope) {
return this.memberUnwinding.get(memberName);
}
@Override
public SymbolType getMemberType(String memberName) {
return structDefinition.getMember(memberName).getType();
}
public RValueUnwinding getMemberUnwinding(String memberName) {
return new RValueUnwinding() {
@Override
public SymbolType getType() {
return structDefinition.getMember(memberName).getType();
}
@Override
public ArraySpec getArraySpec(String memberName) {
return structDefinition.getMember(memberName).getArraySpec();
}
@Override
public ArraySpec getArraySpec() {
return structDefinition.getMember(memberName).getArraySpec();
}
@Override
public RValue getMemberArrayUnwinding(String memberName, ProgramScope scope, ConstantValue arraySize) {
throw new RuntimeException("TODO: Implement!");
@Override
public RValue getUnwinding(ProgramScope programScope) {
return memberUnwinding.get(memberName);
}
@Override
public RValue getArrayUnwinding(ProgramScope scope, ConstantValue arraySize) {
throw new RuntimeException("TODO: Implement!");
}
};
}
}
@ -98,36 +104,48 @@ public class StructUnwinding {
List<String> getMemberNames();
/**
* Get the RValue that a specific member was unwound to
* Get the RValue unwinding to use for copying a single member of the struct
*
* @param memberName The member name
* @return The unwinding of the member
*/
RValueUnwinding getMemberUnwinding(String memberName);
}
/**
* Unwinding value used for copying a value from one variable to another.
*/
public interface RValueUnwinding {
/**
* Get the type of the value
* @return The type of the value
*/
SymbolType getType();
/**
* Get the array nature of the value
* @return The array nature of the value
*/
ArraySpec getArraySpec();
/**
* Get the RValue to use in the assignment as LValue - and as RValue if the member is a not an array value
*
* @param programScope The program scope
* @return The unwinding of the member
*/
RValue getMemberUnwinding(String memberName, ProgramScope programScope);
RValue getUnwinding(ProgramScope programScope);
/**
* Get the type of a specific member
* @param memberName The name of the struct member
* @return The type of the member
*/
SymbolType getMemberType(String memberName);
/**
* Get the array nature of a specific member
* @param memberName The member name
* @return The array nature of the member
*/
ArraySpec getArraySpec(String memberName);
/**
* Get unwinding value to use as RValue when for copying/setting an array member value
* @param memberName The name of the member
* Get Rvalue to use when for copying/setting an array value. Typically returns memset/memcpy commands.
* @param scope The program scope
* @param arraySize The declared size of the array
* @return The value to use as RValue
*/
RValue getMemberArrayUnwinding(String memberName, ProgramScope scope, ConstantValue arraySize);
RValue getArrayUnwinding(ProgramScope scope, ConstantValue arraySize);
}
}

@ -1,12 +1,15 @@
package dk.camelot64.kickc.model.values;
import dk.camelot64.kickc.model.ConstantNotLiteral;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.symbols.ProgramScope;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.types.SymbolTypeStruct;
/**
* An zero-filled struct.
*/
public class StructZero implements RValue {
public class StructZero implements ConstantValue {
private SymbolTypeStruct typeStruct;
@ -18,6 +21,16 @@ public class StructZero implements RValue {
return typeStruct;
}
@Override
public SymbolType getType(ProgramScope scope) {
return typeStruct;
}
@Override
public ConstantLiteral calculateLiteral(ProgramScope scope) {
throw new ConstantNotLiteral("Cannot calculate literal struct.");
}
@Override
public String toString(Program program) {
return "{}";

@ -80,7 +80,8 @@ public class Pass1ProcedureCallParameters extends ControlFlowGraphCopyVisitor {
if(returnVarUnwinding!=null) {
ArrayList<RValue> unwoundReturnVars = new ArrayList<>();
for(String memberName : returnVarUnwinding.getMemberNames()) {
unwoundReturnVars.add(returnVarUnwinding.getMemberUnwinding(memberName, getScope()));
StructUnwinding.RValueUnwinding memberUnwinding = returnVarUnwinding.getMemberUnwinding(memberName);
unwoundReturnVars.add(memberUnwinding.getUnwinding(getScope()));
}
procReturnVarRef = new ValueList(unwoundReturnVars);
}

@ -3,6 +3,7 @@ package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.InternalError;
import dk.camelot64.kickc.model.*;
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
import dk.camelot64.kickc.model.operators.OperatorSizeOf;
import dk.camelot64.kickc.model.operators.Operators;
import dk.camelot64.kickc.model.statements.*;
import dk.camelot64.kickc.model.symbols.*;
@ -73,7 +74,9 @@ public class Pass1UnwindStructValues extends Pass1Base {
if(structMemberRef.getStruct() instanceof VariableRef) {
StructUnwinding.StructMemberUnwinding memberVariables = getStructMemberUnwinding(structMemberRef.getStruct(), currentStmt, stmtIt, currentBlock);
if(memberVariables != null && memberVariables != POSTPONE_UNWINDING) {
RValue structMemberVariable = memberVariables.getMemberUnwinding(structMemberRef.getMemberName(), getScope());
//RValue structMemberVariable = memberVariables.getMemberUnwinding(structMemberRef.getMemberName(), getScope());
StructUnwinding.RValueUnwinding memberUnwinding = memberVariables.getMemberUnwinding(structMemberRef.getMemberName());
RValue structMemberVariable = memberUnwinding.getUnwinding(getScope());
getLog().append("Replacing struct member reference " + structMemberRef.toString(getProgram()) + " with member unwinding reference " + structMemberVariable.toString(getProgram()));
programValue.set(structMemberVariable);
modified.set(true);
@ -96,7 +99,8 @@ public class Pass1UnwindStructValues extends Pass1Base {
if(lValueUnwinding != null && lValueUnwinding != POSTPONE_UNWINDING) {
ArrayList<RValue> unwoundMembers = new ArrayList<>();
for(String memberName : lValueUnwinding.getMemberNames()) {
unwoundMembers.add(lValueUnwinding.getMemberUnwinding(memberName, getScope()));
StructUnwinding.RValueUnwinding memberUnwinding = lValueUnwinding.getMemberUnwinding(memberName);
unwoundMembers.add(memberUnwinding.getUnwinding(getScope()));
}
ValueList unwoundLValue = new ValueList(unwoundMembers);
call.setlValue(unwoundLValue);
@ -113,7 +117,8 @@ public class Pass1UnwindStructValues extends Pass1Base {
if(parameterUnwinding != null && parameterUnwinding != POSTPONE_UNWINDING) {
// Passing a struct variable - convert it to member variables
for(String memberName : parameterUnwinding.getMemberNames()) {
unwoundParameters.add(parameterUnwinding.getMemberUnwinding(memberName, getScope()));
StructUnwinding.RValueUnwinding memberUnwinding = parameterUnwinding.getMemberUnwinding(memberName);
unwoundParameters.add(memberUnwinding.getUnwinding(getScope()));
}
unwound = true;
anyParameterUnwound = true;
@ -143,7 +148,8 @@ public class Pass1UnwindStructValues extends Pass1Base {
if(returnVarUnwinding != null && returnVarUnwinding != POSTPONE_UNWINDING) {
ArrayList<RValue> unwoundMembers = new ArrayList<>();
for(String memberName : returnVarUnwinding.getMemberNames()) {
unwoundMembers.add(returnVarUnwinding.getMemberUnwinding(memberName, getScope()));
StructUnwinding.RValueUnwinding memberUnwinding = returnVarUnwinding.getMemberUnwinding(memberName);
unwoundMembers.add(memberUnwinding.getUnwinding(getScope()));
}
ValueList unwoundReturnValue = new ValueList(unwoundMembers);
statementReturn.setValue(unwoundReturnValue);
@ -168,8 +174,9 @@ public class Pass1UnwindStructValues extends Pass1Base {
StructUnwinding structUnwinding = getProgram().getStructUnwinding();
StructUnwinding.VariableUnwinding parameterUnwinding = structUnwinding.getVariableUnwinding(parameter.getRef());
for(String memberName : parameterUnwinding.getMemberNames()) {
SymbolVariableRef memberUnwinding = (SymbolVariableRef) parameterUnwinding.getMemberUnwinding(memberName, getScope());
unwoundParameterNames.add(memberUnwinding.getLocalName());
StructUnwinding.RValueUnwinding memberUnwinding = parameterUnwinding.getMemberUnwinding(memberName);
SymbolVariableRef memberUnwindingRef = (SymbolVariableRef) memberUnwinding.getUnwinding(getScope());
unwoundParameterNames.add(memberUnwindingRef.getLocalName());
procedureUnwound = true;
}
} else {
@ -194,22 +201,54 @@ public class Pass1UnwindStructValues extends Pass1Base {
*/
private boolean unwindAssignment(StatementAssignment assignment, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock) {
LValue lValue = assignment.getlValue();
StructUnwinding.StructMemberUnwinding lValueUnwinding = getStructMemberUnwinding(lValue, assignment, stmtIt, currentBlock);
if(lValueUnwinding == null) {
return false;
} else if(lValueUnwinding == POSTPONE_UNWINDING) {
return true;
}
if(assignment.getOperator() == null) {
SymbolTypeStruct lValueStructType = (SymbolTypeStruct) SymbolTypeInference.inferType(getScope(), lValue);
SymbolType lValueType = SymbolTypeInference.inferType(getScope(), lValue);
if(assignment.getOperator() == null && lValueType instanceof SymbolTypeStruct) {
SymbolTypeStruct lValueStructType = (SymbolTypeStruct) lValueType;
RValue rValue = assignment.getrValue2();
boolean initialAssignment = assignment.isInitialAssignment();
StatementSource source = assignment.getSource();
// Check for constant struct value assignment
if(rValue instanceof ConstantValue && 1 == 0) {
// TODO: Only handle __ma structs here!
if(rValue instanceof StructZero) {
// Zero-fill the struct value
stmtIt.previous();
ConstantValue structSize = OperatorSizeOf.getSizeOfConstantVar(getScope(), lValueStructType);
MemsetValue rValueMemset = new MemsetValue(structSize);
Statement copyStmt = new StatementAssignment(lValue, rValueMemset, initialAssignment, source, Comment.NO_COMMENTS);
stmtIt.add(copyStmt);
getLog().append("Adding struct variable zero-fill " + copyStmt.toString(getProgram(), false));
stmtIt.next();
} else if(rValue instanceof ConstantStructValue) {
// Create global constant - and memcpy the value into the variable
// Create a constant variable holding the array
String constName = getScope().allocateIntermediateVariableName();
Variable constVar = Variable.createConstant(constName, lValueType, getScope(), null, (ConstantValue) rValue, Scope.SEGMENT_DATA_DEFAULT);
getScope().add(constVar);
stmtIt.previous();
ConstantValue structSize = OperatorSizeOf.getSizeOfConstantVar(getScope(), lValueStructType);
MemcpyValue rValueMemcpy = new MemcpyValue(new PointerDereferenceSimple(constVar.getRef()), structSize);
Statement copyStmt = new StatementAssignment(lValue, rValueMemcpy, initialAssignment, source, Comment.NO_COMMENTS);
stmtIt.add(copyStmt);
getLog().append("Adding struct variable copy " + copyStmt.toString(getProgram(), false));
stmtIt.next();
} else {
throw new InternalError("Unknown constant struct value " + rValue);
}
return true;
}
// Check for struct unwinding
StructUnwinding.StructMemberUnwinding lValueUnwinding = getStructMemberUnwinding(lValue, assignment, stmtIt, currentBlock);
if(lValueUnwinding == null)
return false;
if(lValueUnwinding == POSTPONE_UNWINDING)
return true;
if(rValue instanceof StructUnwoundPlaceholder)
return false;
SymbolType rValueType = SymbolTypeInference.inferType(getScope(), rValue);
boolean initialAssignment = assignment.isInitialAssignment();
StatementSource source = assignment.getSource();
if(rValueType.equals(lValueStructType)) {
StructUnwinding.StructMemberUnwinding rValueUnwinding = getStructMemberUnwinding(rValue, assignment, stmtIt, currentBlock);
if(rValueUnwinding == null) {
@ -217,7 +256,13 @@ public class Pass1UnwindStructValues extends Pass1Base {
}
if(rValueUnwinding == POSTPONE_UNWINDING)
return true;
StructUnwoundPlaceholder unwoundPlaceholder = unwindAssignment(lValueStructType, lValueUnwinding, rValueUnwinding, stmtIt, initialAssignment, source);
List<RValue> lValueUnwoundPlaceholder = new ArrayList<>();
for(String memberName : lValueUnwinding.getMemberNames()) {
StructUnwinding.RValueUnwinding lValueMemberUnwinding = lValueUnwinding.getMemberUnwinding(memberName);
StructUnwinding.RValueUnwinding rValueMemberUnwinding = rValueUnwinding.getMemberUnwinding(memberName);
unwindAssignment(lValueMemberUnwinding, rValueMemberUnwinding, lValueUnwoundPlaceholder, stmtIt, initialAssignment, source);
}
StructUnwoundPlaceholder unwoundPlaceholder = new StructUnwoundPlaceholder(lValueStructType, lValueUnwoundPlaceholder);
if(lValue instanceof VariableRef) {
assignment.setrValue2(unwoundPlaceholder);
} else {
@ -225,47 +270,47 @@ public class Pass1UnwindStructValues extends Pass1Base {
}
return true;
}
throw new CompileError("Incompatible struct assignment " + assignment.toString(getProgram(), false), assignment);
}
throw new CompileError("Incompatible struct assignment " + assignment.toString(getProgram(), false), assignment);
return false;
}
/**
* Unwind assignment of members from an RValue to an LValue
* Unwind assignment from an RValue to an LValue
*
* @param structType The type of struct being unwound
* @param lValueUnwinding The member unwinding of the LValue
* @param rValueUnwinding The member unwinding of the RValue
* @param lValueUnwinding The unwinding of the LValue
* @param rValueUnwinding The unwinding of the RValue
* @param lValueUnwoundList will receive the actual unwinding used for the lValue (if non-null)
* @param stmtIt Statement iterator used for adding unwound assignment statements (before the current statement)
* @param initialAssignment Is this the initial assignment
* @param source The statement source
* @return Struct unwound placeholder describing the performed unwinding
*/
private StructUnwoundPlaceholder unwindAssignment(SymbolTypeStruct structType, StructUnwinding.StructMemberUnwinding lValueUnwinding, StructUnwinding.StructMemberUnwinding rValueUnwinding, ListIterator<Statement> stmtIt, boolean initialAssignment, StatementSource source) {
List<RValue> lValueUnwoundPlaceholder = new ArrayList<>();
stmtIt.previous();
for(String memberName : lValueUnwinding.getMemberNames()) {
if(lValueUnwinding.getArraySpec(memberName) != null) {
// Unwinding an array struct member
RValue lValueMemberVarPointer = lValueUnwinding.getMemberUnwinding(memberName, getScope());
LValue lValueMemberVarRef = new PointerDereferenceSimple(lValueMemberVarPointer);
ConstantValue arraySize = lValueUnwinding.getArraySpec(memberName).getArraySize();
RValue rValueArrayUnwinding = rValueUnwinding.getMemberArrayUnwinding(memberName, getScope(), arraySize);
lValueUnwoundPlaceholder.add(lValueMemberVarPointer);
Statement copyStmt = new StatementAssignment(lValueMemberVarRef, rValueArrayUnwinding, initialAssignment, source, Comment.NO_COMMENTS);
stmtIt.add(copyStmt);
getLog().append("Adding struct value member variable copy " + copyStmt.toString(getProgram(), false));
} else {
// Unwinding a non-array struct member
LValue lValueMemberVarRef = (LValue) lValueUnwinding.getMemberUnwinding(memberName, getScope());
RValue rValueMemberVarRef = rValueUnwinding.getMemberUnwinding(memberName, getScope());
lValueUnwoundPlaceholder.add(lValueMemberVarRef);
Statement copyStmt = new StatementAssignment(lValueMemberVarRef, rValueMemberVarRef, initialAssignment, source, Comment.NO_COMMENTS);
stmtIt.add(copyStmt);
getLog().append("Adding struct value member variable copy " + copyStmt.toString(getProgram(), false));
}
private void unwindAssignment(StructUnwinding.RValueUnwinding lValueUnwinding, StructUnwinding.RValueUnwinding rValueUnwinding, List<RValue> lValueUnwoundList, ListIterator<Statement> stmtIt, boolean initialAssignment, StatementSource source) {
if(lValueUnwinding.getArraySpec() != null) {
// Unwinding an array struct member
stmtIt.previous();
RValue lValueMemberVarPointer = lValueUnwinding.getUnwinding(getScope());
LValue lValueMemberVarRef = new PointerDereferenceSimple(lValueMemberVarPointer);
ConstantValue arraySize = lValueUnwinding.getArraySpec().getArraySize();
RValue rValueArrayUnwinding = rValueUnwinding.getArrayUnwinding(getScope(), arraySize);
if(lValueUnwoundList != null)
lValueUnwoundList.add(lValueMemberVarPointer);
Statement copyStmt = new StatementAssignment(lValueMemberVarRef, rValueArrayUnwinding, initialAssignment, source, Comment.NO_COMMENTS);
stmtIt.add(copyStmt);
stmtIt.next();
getLog().append("Adding struct value member variable copy " + copyStmt.toString(getProgram(), false));
} else {
// Unwinding a non-array struct member
stmtIt.previous();
LValue lValueMemberVarRef = (LValue) lValueUnwinding.getUnwinding(getScope());
RValue rValueMemberVarRef = rValueUnwinding.getUnwinding(getScope());
if(lValueUnwoundList != null)
lValueUnwoundList.add(lValueMemberVarRef);
Statement copyStmt = new StatementAssignment(lValueMemberVarRef, rValueMemberVarRef, initialAssignment, source, Comment.NO_COMMENTS);
stmtIt.add(copyStmt);
stmtIt.next();
getLog().append("Adding struct value member variable copy " + copyStmt.toString(getProgram(), false));
}
stmtIt.next();
return new StructUnwoundPlaceholder(structType, lValueUnwoundPlaceholder);
}
/**
@ -322,34 +367,21 @@ public class Pass1UnwindStructValues extends Pass1Base {
/** Singleton signaling that unwinding should be postponed. */
private static final StructUnwinding.StructMemberUnwinding POSTPONE_UNWINDING = new StructUnwinding.StructMemberUnwinding() {
@Override
public List<String> getMemberNames() {
return null;
}
@Override
public LValue getMemberUnwinding(String memberName, ProgramScope programScope) {
return null;
}
@Override
public SymbolType getMemberType(String memberName) {
return null;
}
@Override
public ArraySpec getArraySpec(String memberName) {
return null;
}
@Override
public RValue getMemberArrayUnwinding(String memberName, ProgramScope scope, ConstantValue arraySize) {
public StructUnwinding.RValueUnwinding getMemberUnwinding(String memberName) {
return null;
}
};
/** Unwinding for a simple pointer deref to a struct. */
private static class StructMemberUnwindingPointerDerefSimple implements StructUnwinding.StructMemberUnwinding {
private final StructDefinition structDefinition;
private final ControlFlowBlock currentBlock;
private final ListIterator<Statement> stmtIt;
@ -375,32 +407,37 @@ public class Pass1UnwindStructValues extends Pass1Base {
}
@Override
public LValue getMemberUnwinding(String memberName, ProgramScope programScope) {
ConstantRef memberOffsetConstant = PassNStructPointerRewriting.getMemberOffsetConstant(programScope, structDefinition, memberName);
Variable member = structDefinition.getMember(memberName);
Scope scope = programScope.getScope(currentBlock.getScope());
Variable memberAddress = scope.addVariableIntermediate();
memberAddress.setType(new SymbolTypePointer(member.getType()));
CastValue structTypedPointer = new CastValue(new SymbolTypePointer(member.getType()), pointerDeref.getPointer());
// Add statement $1 = ptr_struct + OFFSET_STRUCT_NAME_MEMBER
stmtIt.add(new StatementAssignment((LValue) memberAddress.getRef(), structTypedPointer, Operators.PLUS, memberOffsetConstant, true, currentStmt.getSource(), currentStmt.getComments()));
// Unwind to *(ptr_struct+OFFSET_STRUCT_NAME_MEMBER)
return new PointerDereferenceSimple(memberAddress.getRef());
}
public StructUnwinding.RValueUnwinding getMemberUnwinding(String memberName) {
return new StructUnwinding.RValueUnwinding() {
@Override
public SymbolType getType() {
return structDefinition.getMember(memberName).getType();
}
@Override
public SymbolType getMemberType(String memberName) {
return structDefinition.getMember(memberName).getType();
}
@Override
public ArraySpec getArraySpec() {
return structDefinition.getMember(memberName).getArraySpec();
}
@Override
public ArraySpec getArraySpec(String memberName) {
return structDefinition.getMember(memberName).getArraySpec();
}
@Override
public RValue getUnwinding(ProgramScope programScope) {
ConstantRef memberOffsetConstant = PassNStructPointerRewriting.getMemberOffsetConstant(programScope, structDefinition, memberName);
Variable member = structDefinition.getMember(memberName);
Scope scope = programScope.getScope(currentBlock.getScope());
Variable memberAddress = scope.addVariableIntermediate();
memberAddress.setType(new SymbolTypePointer(member.getType()));
CastValue structTypedPointer = new CastValue(new SymbolTypePointer(member.getType()), pointerDeref.getPointer());
// Add statement $1 = ptr_struct + OFFSET_STRUCT_NAME_MEMBER
stmtIt.add(new StatementAssignment((LValue) memberAddress.getRef(), structTypedPointer, Operators.PLUS, memberOffsetConstant, true, currentStmt.getSource(), currentStmt.getComments()));
// Unwind to *(ptr_struct+OFFSET_STRUCT_NAME_MEMBER)
return new PointerDereferenceSimple(memberAddress.getRef());
}
@Override
public RValue getMemberArrayUnwinding(String memberName, ProgramScope scope, ConstantValue arraySize) {
throw new RuntimeException("TODO: Implement!");
@Override
public RValue getArrayUnwinding(ProgramScope scope, ConstantValue arraySize) {
throw new RuntimeException("TODO: Implement!");
}
};
}
}
@ -432,32 +469,37 @@ public class Pass1UnwindStructValues extends Pass1Base {
}
@Override
public LValue getMemberUnwinding(String memberName, ProgramScope programScope) {
ConstantRef memberOffsetConstant = PassNStructPointerRewriting.getMemberOffsetConstant(programScope, structDefinition, memberName);
Variable member = structDefinition.getMember(memberName);
Scope scope = programScope.getScope(currentBlock.getScope());
Variable memberAddress = scope.addVariableIntermediate();
memberAddress.setType(new SymbolTypePointer(member.getType()));
CastValue structTypedPointer = new CastValue(new SymbolTypePointer(member.getType()), pointerDeref.getPointer());
// Add statement $1 = ptr_struct + OFFSET_STRUCT_NAME_MEMBER
stmtIt.add(new StatementAssignment((LValue) memberAddress.getRef(), structTypedPointer, Operators.PLUS, memberOffsetConstant, true, currentStmt.getSource(), currentStmt.getComments()));
// Unwind to *(ptr_struct+OFFSET_STRUCT_NAME_MEMBER[idx]
return new PointerDereferenceIndexed(memberAddress.getRef(), pointerDeref.getIndex());
}
public StructUnwinding.RValueUnwinding getMemberUnwinding(String memberName) {
return new StructUnwinding.RValueUnwinding() {
@Override
public SymbolType getType() {
return structDefinition.getMember(memberName).getType();
}
@Override
public SymbolType getMemberType(String memberName) {
return structDefinition.getMember(memberName).getType();
}
@Override
public ArraySpec getArraySpec() {
return structDefinition.getMember(memberName).getArraySpec();
}
@Override
public ArraySpec getArraySpec(String memberName) {
return structDefinition.getMember(memberName).getArraySpec();
}
@Override
public RValue getUnwinding(ProgramScope programScope) {
ConstantRef memberOffsetConstant = PassNStructPointerRewriting.getMemberOffsetConstant(programScope, structDefinition, memberName);
Variable member = structDefinition.getMember(memberName);
Scope scope = programScope.getScope(currentBlock.getScope());
Variable memberAddress = scope.addVariableIntermediate();
memberAddress.setType(new SymbolTypePointer(member.getType()));
CastValue structTypedPointer = new CastValue(new SymbolTypePointer(member.getType()), pointerDeref.getPointer());
// Add statement $1 = ptr_struct + OFFSET_STRUCT_NAME_MEMBER
stmtIt.add(new StatementAssignment((LValue) memberAddress.getRef(), structTypedPointer, Operators.PLUS, memberOffsetConstant, true, currentStmt.getSource(), currentStmt.getComments()));
// Unwind to *(ptr_struct+OFFSET_STRUCT_NAME_MEMBER[idx]
return new PointerDereferenceIndexed(memberAddress.getRef(), pointerDeref.getIndex());
}
@Override
public RValue getMemberArrayUnwinding(String memberName, ProgramScope scope, ConstantValue arraySize) {
throw new RuntimeException("TODO: Implement!");
@Override
public RValue getArrayUnwinding(ProgramScope scope, ConstantValue arraySize) {
throw new RuntimeException("TODO: Implement!");
}
};
}
}
@ -483,31 +525,36 @@ public class Pass1UnwindStructValues extends Pass1Base {
}
@Override
public RValue getMemberUnwinding(String memberName, ProgramScope programScope) {
Variable member = structDefinition.getMember(memberName);
return constantStructValue.getValue(member.getRef());
}
public StructUnwinding.RValueUnwinding getMemberUnwinding(String memberName) {
return new StructUnwinding.RValueUnwinding() {
@Override
public SymbolType getType() {
return structDefinition.getMember(memberName).getType();
}
@Override
public SymbolType getMemberType(String memberName) {
return structDefinition.getMember(memberName).getType();
}
@Override
public ArraySpec getArraySpec() {
return structDefinition.getMember(memberName).getArraySpec();
}
@Override
public ArraySpec getArraySpec(String memberName) {
return structDefinition.getMember(memberName).getArraySpec();
}
@Override
public RValue getUnwinding(ProgramScope programScope) {
Variable member = structDefinition.getMember(memberName);
return constantStructValue.getValue(member.getRef());
}
@Override
public RValue getMemberArrayUnwinding(String memberName, ProgramScope scope, ConstantValue arraySize) {
// Create a constant variable holding the array
String constName = scope.allocateIntermediateVariableName();
Variable member = structDefinition.getMember(memberName);
SymbolType memberType = member.getType();
ConstantValue constValue = constantStructValue.getValue(member.getRef());
Variable constVar = Variable.createConstant(constName, memberType, scope, new ArraySpec(arraySize), constValue, Scope.SEGMENT_DATA_DEFAULT);
scope.add(constVar);
return new MemcpyValue(new PointerDereferenceSimple(constVar.getRef()), arraySize);
@Override
public RValue getArrayUnwinding(ProgramScope scope, ConstantValue arraySize) {
// Create a constant variable holding the array
String constName = scope.allocateIntermediateVariableName();
Variable member = structDefinition.getMember(memberName);
SymbolType memberType = member.getType();
ConstantValue constValue = constantStructValue.getValue(member.getRef());
Variable constVar = Variable.createConstant(constName, memberType, scope, new ArraySpec(arraySize), constValue, Scope.SEGMENT_DATA_DEFAULT);
scope.add(constVar);
return new MemcpyValue(new PointerDereferenceSimple(constVar.getRef()), arraySize);
}
};
}
}
@ -539,44 +586,50 @@ public class Pass1UnwindStructValues extends Pass1Base {
}
@Override
public RValue getMemberUnwinding(String memberName, ProgramScope programScope) {
ConstantRef memberOffsetConstant = PassNStructPointerRewriting.getMemberOffsetConstant(programScope, structDefinition, memberName);
Variable member = structDefinition.getMember(memberName);
ConstantSymbolPointer structPointer = new ConstantSymbolPointer(variable.getRef());
ConstantCastValue structTypedPointer;
if(member.isArray()) {
// Pointer to array element type
SymbolTypePointer arrayType = (SymbolTypePointer) member.getType();
structTypedPointer = new ConstantCastValue(new SymbolTypePointer(arrayType.getElementType()), structPointer);
// Calculate member address (elementtype*)&struct + OFFSET_STRUCT_NAME_MEMBER
ConstantBinary memberArrayPointer = new ConstantBinary(structTypedPointer, Operators.PLUS, memberOffsetConstant);
// Unwind to *(&struct + OFFSET_STRUCT_NAME_MEMBER)
return memberArrayPointer;
} else {
// Pointer to member element type
structTypedPointer = new ConstantCastValue(new SymbolTypePointer(member.getType()), structPointer);
// Calculate member address (elementtype*)&struct + OFFSET_STRUCT_NAME_MEMBER
ConstantBinary memberArrayPointer = new ConstantBinary(structTypedPointer, Operators.PLUS, memberOffsetConstant);
// Unwind to *(&struct + OFFSET_STRUCT_NAME_MEMBER)
return new PointerDereferenceSimple(memberArrayPointer);
}
}
public StructUnwinding.RValueUnwinding getMemberUnwinding(String memberName) {
return new StructUnwinding.RValueUnwinding() {
@Override
public SymbolType getType() {
return structDefinition.getMember(memberName).getType();
}
@Override
public SymbolType getMemberType(String memberName) {
return structDefinition.getMember(memberName).getType();
}
@Override
public ArraySpec getArraySpec() {
return structDefinition.getMember(memberName).getArraySpec();
}
@Override
public ArraySpec getArraySpec(String memberName) {
return structDefinition.getMember(memberName).getArraySpec();
}
@Override
public RValue getUnwinding(ProgramScope programScope) {
ConstantRef memberOffsetConstant = PassNStructPointerRewriting.getMemberOffsetConstant(programScope, structDefinition, memberName);
Variable member = structDefinition.getMember(memberName);
ConstantSymbolPointer structPointer = new ConstantSymbolPointer(variable.getRef());
ConstantCastValue structTypedPointer;
if(member.isArray()) {
// Pointer to array element type
SymbolTypePointer arrayType = (SymbolTypePointer) member.getType();
structTypedPointer = new ConstantCastValue(new SymbolTypePointer(arrayType.getElementType()), structPointer);
// Calculate member address (elementtype*)&struct + OFFSET_STRUCT_NAME_MEMBER
ConstantBinary memberArrayPointer = new ConstantBinary(structTypedPointer, Operators.PLUS, memberOffsetConstant);
// Unwind to *(&struct + OFFSET_STRUCT_NAME_MEMBER)
return memberArrayPointer;
} else {
// Pointer to member element type
structTypedPointer = new ConstantCastValue(new SymbolTypePointer(member.getType()), structPointer);
// Calculate member address (elementtype*)&struct + OFFSET_STRUCT_NAME_MEMBER
ConstantBinary memberArrayPointer = new ConstantBinary(structTypedPointer, Operators.PLUS, memberOffsetConstant);
// Unwind to *(&struct + OFFSET_STRUCT_NAME_MEMBER)
return new PointerDereferenceSimple(memberArrayPointer);
}
}
@Override
public RValue getMemberArrayUnwinding(String memberName, ProgramScope scope, ConstantValue arraySize) {
RValue rValueMemberVarPointer = getMemberUnwinding(memberName, scope);
LValue rValueMemberVarRef = new PointerDereferenceSimple(rValueMemberVarPointer);
return new MemcpyValue(rValueMemberVarRef, arraySize);
@Override
public RValue getArrayUnwinding(ProgramScope scope, ConstantValue arraySize) {
RValue rValueMemberVarPointer = getUnwinding(scope);
LValue rValueMemberVarRef = new PointerDereferenceSimple(rValueMemberVarPointer);
return new MemcpyValue(rValueMemberVarRef, arraySize);
}
};
}
}
@ -602,23 +655,28 @@ public class Pass1UnwindStructValues extends Pass1Base {
}
@Override
public RValue getMemberUnwinding(String memberName, ProgramScope programScope) {
return ZeroConstantValues.zeroValue(getMemberType(memberName), programScope);
}
public StructUnwinding.RValueUnwinding getMemberUnwinding(String memberName) {
return new StructUnwinding.RValueUnwinding() {
@Override
public SymbolType getType() {
return structDefinition.getMember(memberName).getType();
}
@Override
public SymbolType getMemberType(String memberName) {
return structDefinition.getMember(memberName).getType();
}
@Override
public ArraySpec getArraySpec() {
return structDefinition.getMember(memberName).getArraySpec();
}
@Override
public ArraySpec getArraySpec(String memberName) {
return structDefinition.getMember(memberName).getArraySpec();
}
@Override
public RValue getUnwinding(ProgramScope programScope) {
return ZeroConstantValues.zeroValue(getType(), programScope);
}
@Override
public RValue getMemberArrayUnwinding(String memberName, ProgramScope scope, ConstantValue arraySize) {
return new MemsetValue(arraySize);
@Override
public RValue getArrayUnwinding(ProgramScope scope, ConstantValue arraySize) {
return new MemsetValue(arraySize);
}
};
}
}
@ -645,24 +703,30 @@ public class Pass1UnwindStructValues extends Pass1Base {
}
@Override
public RValue getMemberUnwinding(String memberName, ProgramScope programScope) {
int memberIndex = getMemberNames().indexOf(memberName);
return valueList.getList().get(memberIndex);
public StructUnwinding.RValueUnwinding getMemberUnwinding(String memberName) {
return new StructUnwinding.RValueUnwinding() {
@Override
public SymbolType getType() {
return structDefinition.getMember(memberName).getType();
}
@Override
public ArraySpec getArraySpec() {
return structDefinition.getMember(memberName).getArraySpec();
}
@Override
public RValue getUnwinding(ProgramScope programScope) {
int memberIndex = getMemberNames().indexOf(memberName);
return valueList.getList().get(memberIndex);
}
@Override
public RValue getArrayUnwinding(ProgramScope scope, ConstantValue arraySize) {
throw new RuntimeException("TODO: Implement!");
}
};
}
@Override
public SymbolType getMemberType(String memberName) {
return structDefinition.getMember(memberName).getType();
}
@Override
public ArraySpec getArraySpec(String memberName) {
return structDefinition.getMember(memberName).getArraySpec();
}
@Override
public RValue getMemberArrayUnwinding(String memberName, ProgramScope scope, ConstantValue arraySize) {
throw new RuntimeException("TODO: Implement!");
}
}
}

@ -1127,9 +1127,14 @@ public class TestPrograms {
assertError("struct-err-0", "Unknown struct type");
}
@Test
public void testStruct29() throws IOException, URISyntaxException {
compileAndCompare("struct-29", log());
}
@Test
public void testStruct28() throws IOException, URISyntaxException {
compileAndCompare("struct-28");
compileAndCompare("struct-28", log());
}
@Test

@ -1,4 +1,4 @@
// Minimal struct with C-Standard behavior - member is array, copy assignment (not supported yet)
// Minimal struct with C-Standard behavior - member is array, copy assignment
struct Point {
char x;

@ -1,4 +1,4 @@
// Minimal struct with C-Standard behavior - member is array, copy assignment (not supported yet)
// Minimal struct with C-Standard behavior - member is array, copy assignment
struct Point {
char x;

@ -1,4 +1,4 @@
// Minimal struct with C-Standard behavior - member is array, copy assignment (not supported yet)
// Minimal struct with C-Standard behavior - member is array, copy assignment
struct Point {
char x;

16
src/test/kc/struct-29.kc Normal file

@ -0,0 +1,16 @@
// Minimal struct with C-Standard behavior - global main-mem struct should be initialized in data, not code
struct Point {
char x;
char[2] initials;
};
__mem __ma struct Point point1 = { 2, { 'j', 'g' } };
const char* SCREEN = 0x0400;
void main() {
SCREEN[0] = point1.x;
SCREEN[1] = point1.initials[0];
SCREEN[2] = point1.initials[1];
}

@ -1,4 +1,4 @@
// Minimal struct with C-Standard behavior - member is array, copy assignment (not supported yet)
// Minimal struct with C-Standard behavior - member is array, copy assignment
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"

@ -168,7 +168,7 @@ Allocated zp[3]:5 [ main::point2 ]
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Minimal struct with C-Standard behavior - member is array, copy assignment (not supported yet)
// Minimal struct with C-Standard behavior - member is array, copy assignment
// Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
@ -265,7 +265,7 @@ Uplifting [] best 101 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Minimal struct with C-Standard behavior - member is array, copy assignment (not supported yet)
// Minimal struct with C-Standard behavior - member is array, copy assignment
// Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
@ -379,7 +379,7 @@ FINAL ASSEMBLER
Score: 84
// File Comments
// Minimal struct with C-Standard behavior - member is array, copy assignment (not supported yet)
// Minimal struct with C-Standard behavior - member is array, copy assignment
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)

@ -1,4 +1,4 @@
// Minimal struct with C-Standard behavior - member is array, copy assignment (not supported yet)
// Minimal struct with C-Standard behavior - member is array, copy assignment
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"

@ -129,7 +129,7 @@ Allocated zp[4]:2 [ main::point1 ]
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Minimal struct with C-Standard behavior - member is array, copy assignment (not supported yet)
// Minimal struct with C-Standard behavior - member is array, copy assignment
// Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
@ -202,7 +202,7 @@ Uplifting [] best 65 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Minimal struct with C-Standard behavior - member is array, copy assignment (not supported yet)
// Minimal struct with C-Standard behavior - member is array, copy assignment
// Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
@ -295,7 +295,7 @@ FINAL ASSEMBLER
Score: 50
// File Comments
// Minimal struct with C-Standard behavior - member is array, copy assignment (not supported yet)
// Minimal struct with C-Standard behavior - member is array, copy assignment
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)

@ -1,4 +1,4 @@
// Minimal struct with C-Standard behavior - member is array, copy assignment (not supported yet)
// Minimal struct with C-Standard behavior - member is array, copy assignment
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"

@ -129,7 +129,7 @@ Allocated zp[3]:2 [ main::point1 ]
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Minimal struct with C-Standard behavior - member is array, copy assignment (not supported yet)
// Minimal struct with C-Standard behavior - member is array, copy assignment
// Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
@ -201,7 +201,7 @@ Uplifting [] best 65 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Minimal struct with C-Standard behavior - member is array, copy assignment (not supported yet)
// Minimal struct with C-Standard behavior - member is array, copy assignment
// Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
@ -294,7 +294,7 @@ FINAL ASSEMBLER
Score: 50
// File Comments
// Minimal struct with C-Standard behavior - member is array, copy assignment (not supported yet)
// Minimal struct with C-Standard behavior - member is array, copy assignment
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)

@ -0,0 +1,28 @@
// Minimal struct with C-Standard behavior - global main-mem struct should be initialized in data, not code
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
.label SCREEN = $400
.const OFFSET_STRUCT_POINT_INITIALS = 1
__bbegin:
lda #2
sta point1
tay
!:
lda __0-1,y
sta point1+OFFSET_STRUCT_POINT_INITIALS-1,y
dey
bne !-
jsr main
rts
main: {
lda point1
sta SCREEN
lda point1+OFFSET_STRUCT_POINT_INITIALS
sta SCREEN+1
lda point1+OFFSET_STRUCT_POINT_INITIALS+1
sta SCREEN+2
rts
}
__0: .byte 'j', 'g'
point1: .byte 0

@ -0,0 +1,20 @@
@begin: scope:[] from
[0] *((byte*)&(struct Point) point1) ← (byte) 2
[1] *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) ← memcpy(*((const byte*) $0), (number) 2)
to:@1
@1: scope:[] from @begin
[2] phi()
[3] call main
to:@end
@end: scope:[] from @1
[4] phi()
(void()) main()
main: scope:[main] from @1
[5] *((const byte*) SCREEN) ← *((byte*)&(struct Point) point1)
[6] *((const byte*) SCREEN+(byte) 1) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS)
[7] *((const byte*) SCREEN+(byte) 2) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS+(byte) 1)
to:main::@return
main::@return: scope:[main] from main
[8] return
to:@return

340
src/test/ref/struct-29.log Normal file

@ -0,0 +1,340 @@
Fixing struct type size struct Point to 3
Fixing struct type SIZE_OF struct Point to 3
Fixing struct type SIZE_OF struct Point to 3
Adding struct value member variable copy *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_X) ← (byte) 2
Adding struct value member variable copy *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) ← memcpy(*((const byte*) $0), (number) 2)
Replacing struct member reference (struct Point) point1.x with member unwinding reference *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_X)
Replacing struct member reference (struct Point) point1.initials with member unwinding reference (byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS
Replacing struct member reference (struct Point) point1.initials with member unwinding reference (byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS
Adding versioned struct unwinding for (struct Point) point1
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
*((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_X) ← (byte) 2
*((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) ← memcpy(*((const byte*) $0), (number) 2)
(struct Point) point1 ← struct-unwound {*((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_X), (byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS}
to:@1
(void()) main()
main: scope:[main] from @1
*((const byte*) SCREEN + (number) 0) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_X)
*((const byte*) SCREEN + (number) 1) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 0)
*((const byte*) SCREEN + (number) 2) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 1)
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 byte*) $0[(number) 2] = { (byte) 'j', (byte) 'g' }
(label) @1
(label) @2
(label) @begin
(label) @end
(const byte) OFFSET_STRUCT_POINT_INITIALS = (byte) 1
(const byte) OFFSET_STRUCT_POINT_X = (byte) 0
(const byte*) Point::initials[(number) 2] = { fill( 2, 0) }
(byte) Point::x
(const byte*) SCREEN = (byte*)(number) $400
(void()) main()
(label) main::@return
(struct Point) point1 loadstore
Adding number conversion cast (unumber) 0 in *((const byte*) SCREEN + (number) 0) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_X)
Adding number conversion cast (unumber) 0 in *((const byte*) SCREEN + (number) 1) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 0)
Adding number conversion cast (unumber) 1 in *((const byte*) SCREEN + (number) 1) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (unumber)(number) 0)
Adding number conversion cast (unumber) 1 in *((const byte*) SCREEN + (number) 2) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 1)
Adding number conversion cast (unumber) 2 in *((const byte*) SCREEN + (number) 2) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (unumber)(number) 1)
Successful SSA optimization PassNAddNumberTypeConversions
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 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) 1
Finalized unsigned number type (byte) 2
Successful SSA optimization PassNFinalizeNumberTypeConversions
Removing C-classic struct-unwound assignment [2] (struct Point) point1 ← struct-unwound {*((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_X), (byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS}
Simplifying expression containing zero (byte*)&point1 in [0] *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_X) ← (byte) 2
Simplifying expression containing zero (byte*)&point1 in [3] *((const byte*) SCREEN + (byte) 0) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_X)
Simplifying expression containing zero SCREEN in [3] *((const byte*) SCREEN + (byte) 0) ← *((byte*)&(struct Point) point1)
Simplifying expression containing zero (byte*)&point1+OFFSET_STRUCT_POINT_INITIALS in [4] *((const byte*) SCREEN + (byte) 1) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (byte) 0)
Successful SSA optimization PassNSimplifyExpressionWithZero
Eliminating unused constant (const byte) OFFSET_STRUCT_POINT_X
Successful SSA optimization PassNEliminateUnusedVars
Consolidated array index constant in *(SCREEN+1)
Consolidated array index constant in *((byte*)&point1+OFFSET_STRUCT_POINT_INITIALS+1)
Consolidated array index constant in *(SCREEN+2)
Successful SSA optimization Pass2ConstantAdditionElimination
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:3
Created 0 initial phi equivalence classes
Coalesced down to 0 phi equivalence classes
Culled Empty Block (label) @2
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
FINAL CONTROL FLOW GRAPH
@begin: scope:[] from
[0] *((byte*)&(struct Point) point1) ← (byte) 2
[1] *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) ← memcpy(*((const byte*) $0), (number) 2)
to:@1
@1: scope:[] from @begin
[2] phi()
[3] call main
to:@end
@end: scope:[] from @1
[4] phi()
(void()) main()
main: scope:[main] from @1
[5] *((const byte*) SCREEN) ← *((byte*)&(struct Point) point1)
[6] *((const byte*) SCREEN+(byte) 1) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS)
[7] *((const byte*) SCREEN+(byte) 2) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS+(byte) 1)
to:main::@return
main::@return: scope:[main] from main
[8] return
to:@return
VARIABLE REGISTER WEIGHTS
(byte) Point::x
(void()) main()
(struct Point) point1 loadstore
Initial phi equivalence classes
Added variable point1 to live range equivalence class [ point1 ]
Complete equivalence classes
[ point1 ]
Allocated mem[3] [ point1 ]
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Minimal struct with C-Standard behavior - global main-mem struct should be initialized in data, not code
// Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
.label SCREEN = $400
.const OFFSET_STRUCT_POINT_INITIALS = 1
// @begin
__bbegin:
// [0] *((byte*)&(struct Point) point1) ← (byte) 2 -- _deref_pbuc1=vbuc2
lda #2
sta point1
// [1] *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) ← memcpy(*((const byte*) $0), (number) 2) -- _deref_pbuc1=_deref_pbuc2_memcpy_vbuc3
ldy #2
!:
lda __0-1,y
sta point1+OFFSET_STRUCT_POINT_INITIALS-1,y
dey
bne !-
// [2] phi from @begin to @1 [phi:@begin->@1]
__b1_from___bbegin:
jmp __b1
// @1
__b1:
// [3] call main
jsr main
// [4] phi from @1 to @end [phi:@1->@end]
__bend_from___b1:
jmp __bend
// @end
__bend:
// main
main: {
// [5] *((const byte*) SCREEN) ← *((byte*)&(struct Point) point1) -- _deref_pbuc1=_deref_pbuc2
lda point1
sta SCREEN
// [6] *((const byte*) SCREEN+(byte) 1) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) -- _deref_pbuc1=_deref_pbuc2
lda point1+OFFSET_STRUCT_POINT_INITIALS
sta SCREEN+1
// [7] *((const byte*) SCREEN+(byte) 2) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS+(byte) 1) -- _deref_pbuc1=_deref_pbuc2
lda point1+OFFSET_STRUCT_POINT_INITIALS+1
sta SCREEN+2
jmp __breturn
// main::@return
__breturn:
// [8] return
rts
}
// File Data
__0: .byte 'j', 'g'
point1: .byte 0
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [0] *((byte*)&(struct Point) point1) ← (byte) 2 [ point1 ] ( [ point1 ] ) always clobbers reg byte a
Statement [1] *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) ← memcpy(*((const byte*) $0), (number) 2) [ point1 ] ( [ point1 ] ) always clobbers reg byte a reg byte y
Statement [5] *((const byte*) SCREEN) ← *((byte*)&(struct Point) point1) [ point1 ] ( main:3 [ point1 ] ) always clobbers reg byte a
Statement [6] *((const byte*) SCREEN+(byte) 1) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) [ point1 ] ( main:3 [ point1 ] ) always clobbers reg byte a
Statement [7] *((const byte*) SCREEN+(byte) 2) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS+(byte) 1) [ ] ( main:3 [ ] ) always clobbers reg byte a
Potential registers mem[3] [ point1 ] : mem[3] ,
REGISTER UPLIFT SCOPES
Uplift Scope [Point]
Uplift Scope [main]
Uplift Scope [] 0: mem[3] [ point1 ]
Uplifting [Point] best 67 combination
Uplifting [main] best 67 combination
Uplifting [] best 67 combination mem[3] [ point1 ]
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Minimal struct with C-Standard behavior - global main-mem struct should be initialized in data, not code
// Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
.label SCREEN = $400
.const OFFSET_STRUCT_POINT_INITIALS = 1
// @begin
__bbegin:
// [0] *((byte*)&(struct Point) point1) ← (byte) 2 -- _deref_pbuc1=vbuc2
lda #2
sta point1
// [1] *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) ← memcpy(*((const byte*) $0), (number) 2) -- _deref_pbuc1=_deref_pbuc2_memcpy_vbuc3
ldy #2
!:
lda __0-1,y
sta point1+OFFSET_STRUCT_POINT_INITIALS-1,y
dey
bne !-
// [2] phi from @begin to @1 [phi:@begin->@1]
__b1_from___bbegin:
jmp __b1
// @1
__b1:
// [3] call main
jsr main
// [4] phi from @1 to @end [phi:@1->@end]
__bend_from___b1:
jmp __bend
// @end
__bend:
// main
main: {
// [5] *((const byte*) SCREEN) ← *((byte*)&(struct Point) point1) -- _deref_pbuc1=_deref_pbuc2
lda point1
sta SCREEN
// [6] *((const byte*) SCREEN+(byte) 1) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) -- _deref_pbuc1=_deref_pbuc2
lda point1+OFFSET_STRUCT_POINT_INITIALS
sta SCREEN+1
// [7] *((const byte*) SCREEN+(byte) 2) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS+(byte) 1) -- _deref_pbuc1=_deref_pbuc2
lda point1+OFFSET_STRUCT_POINT_INITIALS+1
sta SCREEN+2
jmp __breturn
// main::@return
__breturn:
// [8] return
rts
}
// File Data
__0: .byte 'j', 'g'
point1: .byte 0
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
Removing instruction jmp __bend
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Replacing instruction ldy #2 with TAY
Removing instruction __b1_from___bbegin:
Removing instruction __bend_from___b1:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction __b1:
Removing instruction __bend:
Removing instruction __breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Adding RTS to root block
Succesful ASM optimization Pass5AddMainRts
FINAL SYMBOL TABLE
(const byte*) $0[(number) 2] = { (byte) 'j', (byte) 'g' }
(label) @1
(label) @begin
(label) @end
(const byte) OFFSET_STRUCT_POINT_INITIALS = (byte) 1
(const byte*) Point::initials[(number) 2] = { fill( 2, 0) }
(byte) Point::x
(const byte*) SCREEN = (byte*) 1024
(void()) main()
(label) main::@return
(struct Point) point1 loadstore mem[3]
mem[3] [ point1 ]
FINAL ASSEMBLER
Score: 64
// File Comments
// Minimal struct with C-Standard behavior - global main-mem struct should be initialized in data, not code
// Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
.label SCREEN = $400
.const OFFSET_STRUCT_POINT_INITIALS = 1
// @begin
__bbegin:
// point1 = { 2, { 'j', 'g' } }
// [0] *((byte*)&(struct Point) point1) ← (byte) 2 -- _deref_pbuc1=vbuc2
lda #2
sta point1
// [1] *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) ← memcpy(*((const byte*) $0), (number) 2) -- _deref_pbuc1=_deref_pbuc2_memcpy_vbuc3
tay
!:
lda __0-1,y
sta point1+OFFSET_STRUCT_POINT_INITIALS-1,y
dey
bne !-
// [2] phi from @begin to @1 [phi:@begin->@1]
// @1
// [3] call main
jsr main
rts
// [4] phi from @1 to @end [phi:@1->@end]
// @end
// main
main: {
// SCREEN[0] = point1.x
// [5] *((const byte*) SCREEN) ← *((byte*)&(struct Point) point1) -- _deref_pbuc1=_deref_pbuc2
lda point1
sta SCREEN
// SCREEN[1] = point1.initials[0]
// [6] *((const byte*) SCREEN+(byte) 1) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) -- _deref_pbuc1=_deref_pbuc2
lda point1+OFFSET_STRUCT_POINT_INITIALS
sta SCREEN+1
// SCREEN[2] = point1.initials[1]
// [7] *((const byte*) SCREEN+(byte) 2) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS+(byte) 1) -- _deref_pbuc1=_deref_pbuc2
lda point1+OFFSET_STRUCT_POINT_INITIALS+1
sta SCREEN+2
// main::@return
// }
// [8] return
rts
}
// File Data
__0: .byte 'j', 'g'
point1: .byte 0

@ -0,0 +1,13 @@
(const byte*) $0[(number) 2] = { (byte) 'j', (byte) 'g' }
(label) @1
(label) @begin
(label) @end
(const byte) OFFSET_STRUCT_POINT_INITIALS = (byte) 1
(const byte*) Point::initials[(number) 2] = { fill( 2, 0) }
(byte) Point::x
(const byte*) SCREEN = (byte*) 1024
(void()) main()
(label) main::@return
(struct Point) point1 loadstore mem[3]
mem[3] [ point1 ]