1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-11-19 11:31:57 +00:00

Working on improvements regarding global initializers and unnecessary unwinding of constant structs. Moved most unwinding to separate package.

This commit is contained in:
jespergravgaard 2020-01-07 00:25:47 +01:00
parent 6a9f59cda1
commit 4eaa0c5385
32 changed files with 1591 additions and 485 deletions

View File

@ -4,7 +4,10 @@ import dk.camelot64.kickc.model.symbols.ArraySpec;
import dk.camelot64.kickc.model.symbols.ProgramScope; import dk.camelot64.kickc.model.symbols.ProgramScope;
import dk.camelot64.kickc.model.symbols.StructDefinition; import dk.camelot64.kickc.model.symbols.StructDefinition;
import dk.camelot64.kickc.model.types.SymbolType; import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.types.SymbolTypeStruct;
import dk.camelot64.kickc.model.values.*; import dk.camelot64.kickc.model.values.*;
import dk.camelot64.kickc.passes.unwinding.RValueUnwinding;
import dk.camelot64.kickc.passes.unwinding.StructMemberUnwinding;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
@ -70,7 +73,7 @@ public class StructUnwinding {
public RValueUnwinding getMemberUnwinding(String memberName) { public RValueUnwinding getMemberUnwinding(String memberName) {
return new RValueUnwinding() { return new RValueUnwinding() {
@Override @Override
public SymbolType getType() { public SymbolType getSymbolType() {
return structDefinition.getMember(memberName).getType(); return structDefinition.getMember(memberName).getType();
} }
@ -85,7 +88,18 @@ public class StructUnwinding {
} }
@Override @Override
public RValue getArrayUnwinding(ProgramScope scope, ConstantValue arraySize) { public boolean isBulkCopyable() {
return getArraySpec()!=null || getSymbolType() instanceof SymbolTypeStruct;
}
@Override
public LValue getBulkLValue(ProgramScope scope) {
final RValue unwinding = getUnwinding(scope);
return new PointerDereferenceSimple(unwinding);
}
@Override
public RValue getBulkRValue(ProgramScope scope) {
throw new RuntimeException("TODO: Implement!"); throw new RuntimeException("TODO: Implement!");
} }
}; };
@ -93,59 +107,4 @@ public class StructUnwinding {
} }
/** Information about how members of an struct Lvalue is unwound. */
public interface StructMemberUnwinding {
/**
* Get the names of the members of the struct
*
* @return the names
*/
List<String> getMemberNames();
/**
* 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 getUnwinding(ProgramScope programScope);
/**
* 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 getArrayUnwinding(ProgramScope scope, ConstantValue arraySize);
}
} }

View File

@ -9,6 +9,7 @@ import dk.camelot64.kickc.model.symbols.*;
import dk.camelot64.kickc.model.types.SymbolType; import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.types.SymbolTypeStruct; import dk.camelot64.kickc.model.types.SymbolTypeStruct;
import dk.camelot64.kickc.model.values.*; import dk.camelot64.kickc.model.values.*;
import dk.camelot64.kickc.passes.unwinding.RValueUnwinding;
import java.util.*; import java.util.*;
@ -80,7 +81,7 @@ public class Pass1ProcedureCallParameters extends ControlFlowGraphCopyVisitor {
if(returnVarUnwinding!=null) { if(returnVarUnwinding!=null) {
ArrayList<RValue> unwoundReturnVars = new ArrayList<>(); ArrayList<RValue> unwoundReturnVars = new ArrayList<>();
for(String memberName : returnVarUnwinding.getMemberNames()) { for(String memberName : returnVarUnwinding.getMemberNames()) {
StructUnwinding.RValueUnwinding memberUnwinding = returnVarUnwinding.getMemberUnwinding(memberName); RValueUnwinding memberUnwinding = returnVarUnwinding.getMemberUnwinding(memberName);
unwoundReturnVars.add(memberUnwinding.getUnwinding(getScope())); unwoundReturnVars.add(memberUnwinding.getUnwinding(getScope()));
} }
procReturnVarRef = new ValueList(unwoundReturnVars); procReturnVarRef = new ValueList(unwoundReturnVars);

View File

@ -3,18 +3,15 @@ package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.InternalError; import dk.camelot64.kickc.model.InternalError;
import dk.camelot64.kickc.model.*; import dk.camelot64.kickc.model.*;
import dk.camelot64.kickc.model.iterator.ProgramValueIterator; 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.statements.*;
import dk.camelot64.kickc.model.symbols.*; import dk.camelot64.kickc.model.symbols.*;
import dk.camelot64.kickc.model.types.SymbolType; import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.types.SymbolTypeInference; import dk.camelot64.kickc.model.types.SymbolTypeInference;
import dk.camelot64.kickc.model.types.SymbolTypePointer;
import dk.camelot64.kickc.model.types.SymbolTypeStruct; import dk.camelot64.kickc.model.types.SymbolTypeStruct;
import dk.camelot64.kickc.model.values.*; import dk.camelot64.kickc.model.values.*;
import dk.camelot64.kickc.passes.unwinding.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.ListIterator; import java.util.ListIterator;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
@ -72,10 +69,9 @@ public class Pass1UnwindStructValues extends Pass1Base {
if(programValue.get() instanceof StructMemberRef) { if(programValue.get() instanceof StructMemberRef) {
StructMemberRef structMemberRef = (StructMemberRef) programValue.get(); StructMemberRef structMemberRef = (StructMemberRef) programValue.get();
if(structMemberRef.getStruct() instanceof VariableRef) { if(structMemberRef.getStruct() instanceof VariableRef) {
StructUnwinding.StructMemberUnwinding memberVariables = getStructMemberUnwinding(structMemberRef.getStruct(), currentStmt, stmtIt, currentBlock); StructMemberUnwinding memberVariables = getStructMemberUnwinding(structMemberRef.getStruct(), currentStmt, stmtIt, currentBlock);
if(memberVariables != null && memberVariables != POSTPONE_UNWINDING) { if(memberVariables != null && memberVariables != POSTPONE_UNWINDING) {
//RValue structMemberVariable = memberVariables.getMemberUnwinding(structMemberRef.getMemberName(), getScope()); RValueUnwinding memberUnwinding = memberVariables.getMemberUnwinding(structMemberRef.getMemberName());
StructUnwinding.RValueUnwinding memberUnwinding = memberVariables.getMemberUnwinding(structMemberRef.getMemberName());
RValue structMemberVariable = memberUnwinding.getUnwinding(getScope()); RValue structMemberVariable = memberUnwinding.getUnwinding(getScope());
getLog().append("Replacing struct member reference " + structMemberRef.toString(getProgram()) + " with member unwinding reference " + structMemberVariable.toString(getProgram())); getLog().append("Replacing struct member reference " + structMemberRef.toString(getProgram()) + " with member unwinding reference " + structMemberVariable.toString(getProgram()));
programValue.set(structMemberVariable); programValue.set(structMemberVariable);
@ -95,11 +91,11 @@ public class Pass1UnwindStructValues extends Pass1Base {
private boolean unwindCall(StatementCall call, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock) { private boolean unwindCall(StatementCall call, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock) {
// Unwind struct value return value // Unwind struct value return value
boolean lvalUnwound = false; boolean lvalUnwound = false;
StructUnwinding.StructMemberUnwinding lValueUnwinding = getStructMemberUnwinding(call.getlValue(), call, stmtIt, currentBlock); StructMemberUnwinding lValueUnwinding = getStructMemberUnwinding(call.getlValue(), call, stmtIt, currentBlock);
if(lValueUnwinding != null && lValueUnwinding != POSTPONE_UNWINDING) { if(lValueUnwinding != null && lValueUnwinding != POSTPONE_UNWINDING) {
ArrayList<RValue> unwoundMembers = new ArrayList<>(); ArrayList<RValue> unwoundMembers = new ArrayList<>();
for(String memberName : lValueUnwinding.getMemberNames()) { for(String memberName : lValueUnwinding.getMemberNames()) {
StructUnwinding.RValueUnwinding memberUnwinding = lValueUnwinding.getMemberUnwinding(memberName); RValueUnwinding memberUnwinding = lValueUnwinding.getMemberUnwinding(memberName);
unwoundMembers.add(memberUnwinding.getUnwinding(getScope())); unwoundMembers.add(memberUnwinding.getUnwinding(getScope()));
} }
ValueList unwoundLValue = new ValueList(unwoundMembers); ValueList unwoundLValue = new ValueList(unwoundMembers);
@ -113,11 +109,11 @@ public class Pass1UnwindStructValues extends Pass1Base {
boolean anyParameterUnwound = false; boolean anyParameterUnwound = false;
for(RValue parameter : call.getParameters()) { for(RValue parameter : call.getParameters()) {
boolean unwound = false; boolean unwound = false;
StructUnwinding.StructMemberUnwinding parameterUnwinding = getStructMemberUnwinding(parameter, call, stmtIt, currentBlock); StructMemberUnwinding parameterUnwinding = getStructMemberUnwinding(parameter, call, stmtIt, currentBlock);
if(parameterUnwinding != null && parameterUnwinding != POSTPONE_UNWINDING) { if(parameterUnwinding != null && parameterUnwinding != POSTPONE_UNWINDING) {
// Passing a struct variable - convert it to member variables // Passing a struct variable - convert it to member variables
for(String memberName : parameterUnwinding.getMemberNames()) { for(String memberName : parameterUnwinding.getMemberNames()) {
StructUnwinding.RValueUnwinding memberUnwinding = parameterUnwinding.getMemberUnwinding(memberName); RValueUnwinding memberUnwinding = parameterUnwinding.getMemberUnwinding(memberName);
unwoundParameters.add(memberUnwinding.getUnwinding(getScope())); unwoundParameters.add(memberUnwinding.getUnwinding(getScope()));
} }
unwound = true; unwound = true;
@ -144,11 +140,11 @@ public class Pass1UnwindStructValues extends Pass1Base {
private boolean unwindReturn(StatementReturn statementReturn, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock) { private boolean unwindReturn(StatementReturn statementReturn, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock) {
boolean modified = false; boolean modified = false;
// Unwind struct value return value // Unwind struct value return value
StructUnwinding.StructMemberUnwinding returnVarUnwinding = getStructMemberUnwinding(statementReturn.getValue(), statementReturn, stmtIt, currentBlock); StructMemberUnwinding returnVarUnwinding = getStructMemberUnwinding(statementReturn.getValue(), statementReturn, stmtIt, currentBlock);
if(returnVarUnwinding != null && returnVarUnwinding != POSTPONE_UNWINDING) { if(returnVarUnwinding != null && returnVarUnwinding != POSTPONE_UNWINDING) {
ArrayList<RValue> unwoundMembers = new ArrayList<>(); ArrayList<RValue> unwoundMembers = new ArrayList<>();
for(String memberName : returnVarUnwinding.getMemberNames()) { for(String memberName : returnVarUnwinding.getMemberNames()) {
StructUnwinding.RValueUnwinding memberUnwinding = returnVarUnwinding.getMemberUnwinding(memberName); RValueUnwinding memberUnwinding = returnVarUnwinding.getMemberUnwinding(memberName);
unwoundMembers.add(memberUnwinding.getUnwinding(getScope())); unwoundMembers.add(memberUnwinding.getUnwinding(getScope()));
} }
ValueList unwoundReturnValue = new ValueList(unwoundMembers); ValueList unwoundReturnValue = new ValueList(unwoundMembers);
@ -174,7 +170,7 @@ public class Pass1UnwindStructValues extends Pass1Base {
StructUnwinding structUnwinding = getProgram().getStructUnwinding(); StructUnwinding structUnwinding = getProgram().getStructUnwinding();
StructUnwinding.VariableUnwinding parameterUnwinding = structUnwinding.getVariableUnwinding(parameter.getRef()); StructUnwinding.VariableUnwinding parameterUnwinding = structUnwinding.getVariableUnwinding(parameter.getRef());
for(String memberName : parameterUnwinding.getMemberNames()) { for(String memberName : parameterUnwinding.getMemberNames()) {
StructUnwinding.RValueUnwinding memberUnwinding = parameterUnwinding.getMemberUnwinding(memberName); RValueUnwinding memberUnwinding = parameterUnwinding.getMemberUnwinding(memberName);
SymbolVariableRef memberUnwindingRef = (SymbolVariableRef) memberUnwinding.getUnwinding(getScope()); SymbolVariableRef memberUnwindingRef = (SymbolVariableRef) memberUnwinding.getUnwinding(getScope());
unwoundParameterNames.add(memberUnwindingRef.getLocalName()); unwoundParameterNames.add(memberUnwindingRef.getLocalName());
procedureUnwound = true; procedureUnwound = true;
@ -202,55 +198,31 @@ public class Pass1UnwindStructValues extends Pass1Base {
private boolean unwindAssignment(StatementAssignment assignment, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock) { private boolean unwindAssignment(StatementAssignment assignment, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock) {
LValue lValue = assignment.getlValue(); LValue lValue = assignment.getlValue();
SymbolType lValueType = SymbolTypeInference.inferType(getScope(), lValue); SymbolType lValueType = SymbolTypeInference.inferType(getScope(), lValue);
if(assignment.getOperator() == null && lValueType instanceof SymbolTypeStruct) { if(lValueType instanceof SymbolTypeStruct && assignment.getOperator() == null) {
// Assignment to a struct
SymbolTypeStruct lValueStructType = (SymbolTypeStruct) lValueType; SymbolTypeStruct lValueStructType = (SymbolTypeStruct) lValueType;
RValue rValue = assignment.getrValue2(); RValue rValue = assignment.getrValue2();
boolean initialAssignment = assignment.isInitialAssignment(); boolean initialAssignment = assignment.isInitialAssignment();
StatementSource source = assignment.getSource(); StatementSource source = assignment.getSource();
// Check for constant struct value assignment // Check for bulk assignable values
if(rValue instanceof ConstantValue && 1 == 0) { if(isBulkAssignable(lValue) && isBulkAssignable(rValue)) {
// TODO: Only handle __ma structs here! RValueUnwinding lValueUnwinding = getValueUnwinding(lValue, assignment, stmtIt, currentBlock);
if(rValue instanceof StructZero) { RValueUnwinding rValueUnwinding = getValueUnwinding(rValue, assignment, stmtIt, currentBlock);
// Zero-fill the struct value unwindAssignment(lValueUnwinding, rValueUnwinding, null, stmtIt, initialAssignment, source);
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 // Check for struct unwinding
StructUnwinding.StructMemberUnwinding lValueUnwinding = getStructMemberUnwinding(lValue, assignment, stmtIt, currentBlock); StructMemberUnwinding lValueUnwinding = getStructMemberUnwinding(lValue, assignment, stmtIt, currentBlock);
if(lValueUnwinding == null) if(lValueUnwinding == null)
return false; return false;
if(lValueUnwinding == POSTPONE_UNWINDING) if(lValueUnwinding == POSTPONE_UNWINDING)
return true; return true;
if(rValue instanceof StructUnwoundPlaceholder) if(rValue instanceof StructUnwoundPlaceholder)
return false; return false;
SymbolType rValueType = SymbolTypeInference.inferType(getScope(), rValue); SymbolType rValueType = SymbolTypeInference.inferType(getScope(), rValue);
if(rValueType.equals(lValueStructType)) { if(rValueType.equals(lValueStructType)) {
StructUnwinding.StructMemberUnwinding rValueUnwinding = getStructMemberUnwinding(rValue, assignment, stmtIt, currentBlock); StructMemberUnwinding rValueUnwinding = getStructMemberUnwinding(rValue, assignment, stmtIt, currentBlock);
if(rValueUnwinding == null) { if(rValueUnwinding == null) {
throw new CompileError("Incompatible struct assignment " + assignment.toString(getProgram(), false), assignment); throw new CompileError("Incompatible struct assignment " + assignment.toString(getProgram(), false), assignment);
} }
@ -258,8 +230,8 @@ public class Pass1UnwindStructValues extends Pass1Base {
return true; return true;
List<RValue> lValueUnwoundPlaceholder = new ArrayList<>(); List<RValue> lValueUnwoundPlaceholder = new ArrayList<>();
for(String memberName : lValueUnwinding.getMemberNames()) { for(String memberName : lValueUnwinding.getMemberNames()) {
StructUnwinding.RValueUnwinding lValueMemberUnwinding = lValueUnwinding.getMemberUnwinding(memberName); RValueUnwinding lValueMemberUnwinding = lValueUnwinding.getMemberUnwinding(memberName);
StructUnwinding.RValueUnwinding rValueMemberUnwinding = rValueUnwinding.getMemberUnwinding(memberName); RValueUnwinding rValueMemberUnwinding = rValueUnwinding.getMemberUnwinding(memberName);
unwindAssignment(lValueMemberUnwinding, rValueMemberUnwinding, lValueUnwoundPlaceholder, stmtIt, initialAssignment, source); unwindAssignment(lValueMemberUnwinding, rValueMemberUnwinding, lValueUnwoundPlaceholder, stmtIt, initialAssignment, source);
} }
StructUnwoundPlaceholder unwoundPlaceholder = new StructUnwoundPlaceholder(lValueStructType, lValueUnwoundPlaceholder); StructUnwoundPlaceholder unwoundPlaceholder = new StructUnwoundPlaceholder(lValueStructType, lValueUnwoundPlaceholder);
@ -285,17 +257,19 @@ public class Pass1UnwindStructValues extends Pass1Base {
* @param initialAssignment Is this the initial assignment * @param initialAssignment Is this the initial assignment
* @param source The statement source * @param source The statement source
*/ */
private void unwindAssignment(StructUnwinding.RValueUnwinding lValueUnwinding, StructUnwinding.RValueUnwinding rValueUnwinding, List<RValue> lValueUnwoundList, ListIterator<Statement> stmtIt, boolean initialAssignment, StatementSource source) { private void unwindAssignment(RValueUnwinding lValueUnwinding, RValueUnwinding rValueUnwinding, List<RValue> lValueUnwoundList, ListIterator<Statement> stmtIt, boolean initialAssignment, StatementSource source) {
if(lValueUnwinding.getArraySpec() != null) { if(lValueUnwinding.isBulkCopyable() && rValueUnwinding.isBulkCopyable()) {
// Unwinding an array struct member // Use bulk unwinding for a struct member that is an array
stmtIt.previous(); stmtIt.previous();
RValue lValueMemberVarPointer = lValueUnwinding.getUnwinding(getScope()); //RValue lValueMemberVarPointer = lValueUnwinding.getBulkLValue(getScope());
LValue lValueMemberVarRef = new PointerDereferenceSimple(lValueMemberVarPointer); //LValue lValueMemberVarRef = new PointerDereferenceSimple(lValueMemberVarPointer);
ConstantValue arraySize = lValueUnwinding.getArraySpec().getArraySize(); //if(rValueUnwinding.getArraySpec()==null || !lValueUnwinding.getArraySpec().equals(rValueUnwinding.getArraySpec()))
RValue rValueArrayUnwinding = rValueUnwinding.getArrayUnwinding(getScope(), arraySize); // throw new RuntimeException("ArraySpec mismatch!");
LValue lValueMemberVarRef = lValueUnwinding.getBulkLValue(getScope());
RValue rValueBulkUnwinding = rValueUnwinding.getBulkRValue(getScope());
if(lValueUnwoundList != null) if(lValueUnwoundList != null)
lValueUnwoundList.add(lValueMemberVarPointer); lValueUnwoundList.add(lValueMemberVarRef);
Statement copyStmt = new StatementAssignment(lValueMemberVarRef, rValueArrayUnwinding, initialAssignment, source, Comment.NO_COMMENTS); Statement copyStmt = new StatementAssignment(lValueMemberVarRef, rValueBulkUnwinding, initialAssignment, source, Comment.NO_COMMENTS);
stmtIt.add(copyStmt); stmtIt.add(copyStmt);
stmtIt.next(); stmtIt.next();
getLog().append("Adding struct value member variable copy " + copyStmt.toString(getProgram(), false)); getLog().append("Adding struct value member variable copy " + copyStmt.toString(getProgram(), false));
@ -313,6 +287,61 @@ public class Pass1UnwindStructValues extends Pass1Base {
} }
} }
/**
* Determine whether a value can be used in a bulk assignment
*
* @param value The value
* @return true if the value is bulk assignable
*/
private boolean isBulkAssignable(RValue value) {
/*
if(value instanceof SymbolVariableRef) {
Variable var = getScope().getVar((SymbolVariableRef) value);
if(var.isStructClassic())
// A load/store struct value
return true;
}
if(value instanceof StructZero)
// A zero-filled struct value
return true;
if(value instanceof ConstantStructValue)
// A constant struct value
return true;
// TODO: Add support for arrays
// Not bulk assignable
*/
return false;
}
/**
* Get unwinding for a value
*
* @param value The value
* @return Unwinding for the value
*/
private RValueUnwinding getValueUnwinding(RValue value, Statement currentStmt, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock) {
if(value != null) {
SymbolType valueType = SymbolTypeInference.inferType(getScope(), value);
if(valueType instanceof SymbolTypeStruct) {
if(value instanceof VariableRef) {
Variable variable = getScope().getVariable((VariableRef) value);
if(variable.isStructClassic()) {
return new StructVariableValueUnwinding(variable);
}
}
if(value instanceof StructZero) {
return new ZeroValueUnwinding(valueType, null);
}
if(value instanceof ConstantStructValue) {
return new ConstantValueUnwinding(valueType, null, (ConstantStructValue) value);
}
}
}
return null;
}
/** /**
* Examine a value - and if it represents a struct get the unwinding information for the struct members * Examine a value - and if it represents a struct get the unwinding information for the struct members
* *
@ -322,7 +351,7 @@ public class Pass1UnwindStructValues extends Pass1Base {
* @param currentBlock Program Context information. Current block * @param currentBlock Program Context information. Current block
* @return null if the value is not a struct. Unwinding for the passed value if it is a struct. {@link #POSTPONE_UNWINDING} if the struct is not ready for unwinding yet. * @return null if the value is not a struct. Unwinding for the passed value if it is a struct. {@link #POSTPONE_UNWINDING} if the struct is not ready for unwinding yet.
*/ */
private StructUnwinding.StructMemberUnwinding getStructMemberUnwinding(RValue value, Statement currentStmt, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock) { private StructMemberUnwinding getStructMemberUnwinding(RValue value, Statement currentStmt, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock) {
if(value != null) { if(value != null) {
SymbolType valueType = SymbolTypeInference.inferType(getScope(), value); SymbolType valueType = SymbolTypeInference.inferType(getScope(), value);
if(valueType instanceof SymbolTypeStruct) { if(valueType instanceof SymbolTypeStruct) {
@ -366,7 +395,7 @@ public class Pass1UnwindStructValues extends Pass1Base {
} }
/** Singleton signaling that unwinding should be postponed. */ /** Singleton signaling that unwinding should be postponed. */
private static final StructUnwinding.StructMemberUnwinding POSTPONE_UNWINDING = new StructUnwinding.StructMemberUnwinding() { private static final StructMemberUnwinding POSTPONE_UNWINDING = new StructMemberUnwinding() {
@Override @Override
public List<String> getMemberNames() { public List<String> getMemberNames() {
@ -374,359 +403,10 @@ public class Pass1UnwindStructValues extends Pass1Base {
} }
@Override @Override
public StructUnwinding.RValueUnwinding getMemberUnwinding(String memberName) { public RValueUnwinding getMemberUnwinding(String memberName) {
return null; 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;
private final PointerDereferenceSimple pointerDeref;
private final Statement currentStmt;
StructMemberUnwindingPointerDerefSimple(PointerDereferenceSimple pointerDeref, StructDefinition structDefinition, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock, Statement currentStmt) {
this.structDefinition = structDefinition;
this.currentBlock = currentBlock;
this.stmtIt = stmtIt;
this.pointerDeref = pointerDeref;
this.currentStmt = currentStmt;
}
@Override
public List<String> getMemberNames() {
Collection<Variable> structMemberVars = structDefinition.getAllVariables(false);
ArrayList<String> memberNames = new ArrayList<>();
for(Variable structMemberVar : structMemberVars) {
memberNames.add(structMemberVar.getLocalName());
}
return memberNames;
}
@Override
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) {
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 getArrayUnwinding(ProgramScope scope, ConstantValue arraySize) {
throw new RuntimeException("TODO: Implement!");
}
};
}
}
/** Unwinding for a indexed pointer deref to a struct. */
private static class StructMemberUnwindingPointerDerefIndexed implements StructUnwinding.StructMemberUnwinding {
private final PointerDereferenceIndexed pointerDeref;
private final StructDefinition structDefinition;
private final ControlFlowBlock currentBlock;
private final ListIterator<Statement> stmtIt;
private final Statement currentStmt;
StructMemberUnwindingPointerDerefIndexed(PointerDereferenceIndexed pointerDeref, StructDefinition structDefinition, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock, Statement currentStmt) {
this.structDefinition = structDefinition;
this.currentBlock = currentBlock;
this.stmtIt = stmtIt;
this.pointerDeref = pointerDeref;
this.currentStmt = currentStmt;
}
@Override
public List<String> getMemberNames() {
Collection<Variable> structMemberVars = structDefinition.getAllVariables(false);
ArrayList<String> memberNames = new ArrayList<>();
for(Variable structMemberVar : structMemberVars) {
memberNames.add(structMemberVar.getLocalName());
}
return memberNames;
}
@Override
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) {
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 getArrayUnwinding(ProgramScope scope, ConstantValue arraySize) {
throw new RuntimeException("TODO: Implement!");
}
};
}
}
/** Unwinding for constant struct value. */
private static class StructMemberUnwindingConstantValue implements StructUnwinding.StructMemberUnwinding {
private final ConstantStructValue constantStructValue;
private final StructDefinition structDefinition;
StructMemberUnwindingConstantValue(ConstantStructValue constantStructValue, StructDefinition structDefinition) {
this.constantStructValue = constantStructValue;
this.structDefinition = structDefinition;
}
@Override
public List<String> getMemberNames() {
Collection<Variable> structMemberVars = structDefinition.getAllVariables(false);
ArrayList<String> memberNames = new ArrayList<>();
for(Variable structMemberVar : structMemberVars) {
memberNames.add(structMemberVar.getLocalName());
}
return memberNames;
}
@Override
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) {
Variable member = structDefinition.getMember(memberName);
return constantStructValue.getValue(member.getRef());
}
@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);
}
};
}
}
/** Unwinding for a struct value with C-classic memory layout. */
private static class StructVariableMemberUnwinding implements StructUnwinding.StructMemberUnwinding {
private Variable variable;
private StructDefinition structDefinition;
private final ControlFlowBlock currentBlock;
private final ListIterator<Statement> stmtIt;
private final Statement currentStmt;
public StructVariableMemberUnwinding(Variable variable, StructDefinition structDefinition, ControlFlowBlock currentBlock, ListIterator<Statement> stmtIt, Statement currentStmt) {
this.variable = variable;
this.structDefinition = structDefinition;
this.currentBlock = currentBlock;
this.stmtIt = stmtIt;
this.currentStmt = currentStmt;
}
@Override
public List<String> getMemberNames() {
Collection<Variable> structMemberVars = structDefinition.getAllVars(false);
ArrayList<String> memberNames = new ArrayList<>();
for(Variable structMemberVar : structMemberVars) {
memberNames.add(structMemberVar.getLocalName());
}
return memberNames;
}
@Override
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) {
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 getArrayUnwinding(ProgramScope scope, ConstantValue arraySize) {
RValue rValueMemberVarPointer = getUnwinding(scope);
LValue rValueMemberVarRef = new PointerDereferenceSimple(rValueMemberVarPointer);
return new MemcpyValue(rValueMemberVarRef, arraySize);
}
};
}
}
/** Unwinding for StructZero */
private static class StructMemberUnwindingZero implements StructUnwinding.StructMemberUnwinding {
private StructZero structZero;
private StructDefinition structDefinition;
public StructMemberUnwindingZero(StructZero structZero, StructDefinition structDefinition) {
this.structZero = structZero;
this.structDefinition = structDefinition;
}
@Override
public List<String> getMemberNames() {
Collection<Variable> structMemberVars = structDefinition.getAllVariables(false);
ArrayList<String> memberNames = new ArrayList<>();
for(Variable structMemberVar : structMemberVars) {
memberNames.add(structMemberVar.getLocalName());
}
return memberNames;
}
@Override
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) {
return ZeroConstantValues.zeroValue(getType(), programScope);
}
@Override
public RValue getArrayUnwinding(ProgramScope scope, ConstantValue arraySize) {
return new MemsetValue(arraySize);
}
};
}
}
/** Unwinding for ValueList. */
private static class StructMemberUnwindingValueList implements StructUnwinding.StructMemberUnwinding {
StructDefinition structDefinition;
ValueList valueList;
public StructMemberUnwindingValueList(ValueList valueList, StructDefinition structDefinition) {
this.valueList = valueList;
this.structDefinition = structDefinition;
}
@Override
public List<String> getMemberNames() {
Collection<Variable> structMemberVars = structDefinition.getAllVariables(false);
ArrayList<String> memberNames = new ArrayList<>();
for(Variable structMemberVar : structMemberVars) {
memberNames.add(structMemberVar.getLocalName());
}
return memberNames;
}
@Override
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!");
}
};
}
}
} }

View File

@ -0,0 +1,55 @@
package dk.camelot64.kickc.passes.unwinding;
import dk.camelot64.kickc.model.symbols.ArraySpec;
import dk.camelot64.kickc.model.symbols.ProgramScope;
import dk.camelot64.kickc.model.symbols.Scope;
import dk.camelot64.kickc.model.symbols.Variable;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.values.*;
/** Unwinding a constant value. */
public class ConstantValueUnwinding implements RValueUnwinding {
private final SymbolType symbolType;
private final ArraySpec arraySpec;
private final ConstantValue value;
public ConstantValueUnwinding(SymbolType symbolType, ArraySpec arraySpec, ConstantValue value) {
this.symbolType = symbolType;
this.arraySpec = arraySpec;
this.value = value;
}
@Override
public SymbolType getSymbolType() {
return symbolType;
}
@Override
public ArraySpec getArraySpec() {
return arraySpec;
}
@Override
public RValue getUnwinding(ProgramScope programScope) {
return value;
}
@Override
public boolean isBulkCopyable() {
return getArraySpec()!=null;
}
@Override
public LValue getBulkLValue(ProgramScope scope) {
throw new InternalError("Not a valid LValue!");
}
@Override
public RValue getBulkRValue(ProgramScope scope) {
String constName = scope.allocateIntermediateVariableName();
Variable constVar = Variable.createConstant(constName, symbolType, scope, getArraySpec(), value, Scope.SEGMENT_DATA_DEFAULT);
scope.add(constVar);
return new MemcpyValue(new PointerDereferenceSimple(constVar.getRef()), getArraySpec().getArraySize());
}
}

View File

@ -0,0 +1,55 @@
package dk.camelot64.kickc.passes.unwinding;
import dk.camelot64.kickc.model.symbols.ArraySpec;
import dk.camelot64.kickc.model.symbols.ProgramScope;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.values.LValue;
import dk.camelot64.kickc.model.values.RValue;
/**
* Assignment unwinding value used for copying one value to another using the most effective method.
* Assignment uses typed copy for simple types. For arrays/struct values bulk-copying of memory is used when feasible and member-by-member copying when necessary.
*/
public interface RValueUnwinding {
/**
* Get the type of the value
* @return The type of the value
*/
SymbolType getSymbolType();
/**
* 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 getUnwinding(ProgramScope programScope);
/**
* Determine if the value can be bulk memory copied
* @return true if the value can be bulk memory copied (from or to).
*/
boolean isBulkCopyable();
/**
* Get Lvalue to use when for copying/setting a bulk value at once. Must returns a byte* type.
* @param scope The program scope
* @return The value to use as RValue
*/
LValue getBulkLValue(ProgramScope scope);
/**
* Get Rvalue to use when for copying/setting a bulk value at once. Typically returns a memset/memcpy commands.
* @param scope The program scope
* @return The value to use as RValue
*/
RValue getBulkRValue(ProgramScope scope);
}

View File

@ -0,0 +1,51 @@
package dk.camelot64.kickc.passes.unwinding;
import dk.camelot64.kickc.model.symbols.ArraySpec;
import dk.camelot64.kickc.model.symbols.ProgramScope;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.values.LValue;
import dk.camelot64.kickc.model.values.RValue;
/** Value unwinding that just returns a non-unwindable RValue. */
class SimpleRValueUnwinding implements RValueUnwinding {
private final SymbolType type;
private final ArraySpec arraySpec;
private final RValue memberValue;
public SimpleRValueUnwinding(SymbolType type, ArraySpec arraySpec, RValue memberValue) {
this.type = type;
this.arraySpec = arraySpec;
this.memberValue = memberValue;
}
@Override
public SymbolType getSymbolType() {
return type;
}
@Override
public ArraySpec getArraySpec() {
return arraySpec;
}
@Override
public RValue getUnwinding(ProgramScope programScope) {
return memberValue;
}
@Override
public boolean isBulkCopyable() {
return false;
}
@Override
public LValue getBulkLValue(ProgramScope scope) {
throw new RuntimeException("TODO: Implement!");
}
@Override
public RValue getBulkRValue(ProgramScope scope) {
throw new RuntimeException("TODO: Implement!");
}
}

View File

@ -0,0 +1,23 @@
package dk.camelot64.kickc.passes.unwinding;
import java.util.List;
/** Assignment unwinding information for a struct value into separate members. */
public interface StructMemberUnwinding {
/**
* Get the names of the members of the struct
*
* @return the names
*/
List<String> getMemberNames();
/**
* 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);
}

View File

@ -0,0 +1,43 @@
package dk.camelot64.kickc.passes.unwinding;
import dk.camelot64.kickc.model.symbols.ArraySpec;
import dk.camelot64.kickc.model.symbols.StructDefinition;
import dk.camelot64.kickc.model.symbols.Variable;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.values.ConstantStructValue;
import dk.camelot64.kickc.model.values.ConstantValue;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/** Member unwinding for constant struct value. */
public class StructMemberUnwindingConstantValue implements StructMemberUnwinding {
private final ConstantStructValue constantStructValue;
private final StructDefinition structDefinition;
public StructMemberUnwindingConstantValue(ConstantStructValue constantStructValue, StructDefinition structDefinition) {
this.constantStructValue = constantStructValue;
this.structDefinition = structDefinition;
}
@Override
public List<String> getMemberNames() {
Collection<Variable> structMemberVars = structDefinition.getAllVariables(false);
ArrayList<String> memberNames = new ArrayList<>();
for(Variable structMemberVar : structMemberVars) {
memberNames.add(structMemberVar.getLocalName());
}
return memberNames;
}
@Override
public RValueUnwinding getMemberUnwinding(String memberName) {
final Variable member = structDefinition.getMember(memberName);
final SymbolType type = member.getType();
final ArraySpec arraySpec = member.getArraySpec();
final ConstantValue memberValue = constantStructValue.getValue(member.getRef());
return new ConstantValueUnwinding(type, arraySpec, memberValue);
}
}

View File

@ -0,0 +1,88 @@
package dk.camelot64.kickc.passes.unwinding;
import dk.camelot64.kickc.model.ControlFlowBlock;
import dk.camelot64.kickc.model.operators.Operators;
import dk.camelot64.kickc.model.statements.Statement;
import dk.camelot64.kickc.model.statements.StatementAssignment;
import dk.camelot64.kickc.model.symbols.*;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.types.SymbolTypePointer;
import dk.camelot64.kickc.model.values.*;
import dk.camelot64.kickc.passes.PassNStructPointerRewriting;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.ListIterator;
/** Unwinding for a indexed pointer deref to a struct. */
public class StructMemberUnwindingPointerDerefIndexed implements StructMemberUnwinding {
private final PointerDereferenceIndexed pointerDeref;
private final StructDefinition structDefinition;
private final ControlFlowBlock currentBlock;
private final ListIterator<Statement> stmtIt;
private final Statement currentStmt;
public StructMemberUnwindingPointerDerefIndexed(PointerDereferenceIndexed pointerDeref, StructDefinition structDefinition, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock, Statement currentStmt) {
this.structDefinition = structDefinition;
this.currentBlock = currentBlock;
this.stmtIt = stmtIt;
this.pointerDeref = pointerDeref;
this.currentStmt = currentStmt;
}
@Override
public List<String> getMemberNames() {
Collection<Variable> structMemberVars = structDefinition.getAllVariables(false);
ArrayList<String> memberNames = new ArrayList<>();
for(Variable structMemberVar : structMemberVars) {
memberNames.add(structMemberVar.getLocalName());
}
return memberNames;
}
@Override
public RValueUnwinding getMemberUnwinding(String memberName) {
return new RValueUnwinding() {
@Override
public SymbolType getSymbolType() {
return structDefinition.getMember(memberName).getType();
}
@Override
public ArraySpec getArraySpec() {
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 boolean isBulkCopyable() {
return getArraySpec()!=null;
}
@Override
public LValue getBulkLValue(ProgramScope scope) {
return (LValue) getUnwinding(scope);
}
@Override
public RValue getBulkRValue(ProgramScope scope) {
throw new RuntimeException("TODO: Implement!");
}
};
}
}

View File

@ -0,0 +1,89 @@
package dk.camelot64.kickc.passes.unwinding;
import dk.camelot64.kickc.model.ControlFlowBlock;
import dk.camelot64.kickc.model.operators.Operators;
import dk.camelot64.kickc.model.statements.Statement;
import dk.camelot64.kickc.model.statements.StatementAssignment;
import dk.camelot64.kickc.model.symbols.*;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.types.SymbolTypePointer;
import dk.camelot64.kickc.model.values.*;
import dk.camelot64.kickc.passes.PassNStructPointerRewriting;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.ListIterator;
/** Unwinding for a simple pointer deref to a struct. */
public class StructMemberUnwindingPointerDerefSimple implements StructMemberUnwinding {
private final StructDefinition structDefinition;
private final ControlFlowBlock currentBlock;
private final ListIterator<Statement> stmtIt;
private final PointerDereferenceSimple pointerDeref;
private final Statement currentStmt;
public StructMemberUnwindingPointerDerefSimple(PointerDereferenceSimple pointerDeref, StructDefinition structDefinition, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock, Statement currentStmt) {
this.structDefinition = structDefinition;
this.currentBlock = currentBlock;
this.stmtIt = stmtIt;
this.pointerDeref = pointerDeref;
this.currentStmt = currentStmt;
}
@Override
public List<String> getMemberNames() {
Collection<Variable> structMemberVars = structDefinition.getAllVariables(false);
ArrayList<String> memberNames = new ArrayList<>();
for(Variable structMemberVar : structMemberVars) {
memberNames.add(structMemberVar.getLocalName());
}
return memberNames;
}
@Override
public RValueUnwinding getMemberUnwinding(String memberName) {
return new RValueUnwinding() {
@Override
public SymbolType getSymbolType() {
return structDefinition.getMember(memberName).getType();
}
@Override
public ArraySpec getArraySpec() {
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 boolean isBulkCopyable() {
return getArraySpec()!=null;
}
@Override
public LValue getBulkLValue(ProgramScope scope) {
return (LValue) getUnwinding(scope);
}
@Override
public RValue getBulkRValue(ProgramScope scope) {
throw new RuntimeException("TODO: Implement!");
}
};
}
}

View File

@ -0,0 +1,44 @@
package dk.camelot64.kickc.passes.unwinding;
import dk.camelot64.kickc.model.symbols.ArraySpec;
import dk.camelot64.kickc.model.symbols.StructDefinition;
import dk.camelot64.kickc.model.symbols.Variable;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.values.RValue;
import dk.camelot64.kickc.model.values.ValueList;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/** Member unwinding for a struct valueList. */
public class StructMemberUnwindingValueList implements StructMemberUnwinding {
private final StructDefinition structDefinition;
private final ValueList valueList;
public StructMemberUnwindingValueList(ValueList valueList, StructDefinition structDefinition) {
this.valueList = valueList;
this.structDefinition = structDefinition;
}
@Override
public List<String> getMemberNames() {
Collection<Variable> structMemberVars = structDefinition.getAllVariables(false);
ArrayList<String> memberNames = new ArrayList<>();
for(Variable structMemberVar : structMemberVars) {
memberNames.add(structMemberVar.getLocalName());
}
return memberNames;
}
@Override
public RValueUnwinding getMemberUnwinding(String memberName) {
final SymbolType type = structDefinition.getMember(memberName).getType();
final ArraySpec arraySpec = structDefinition.getMember(memberName).getArraySpec();
int memberIndex = getMemberNames().indexOf(memberName);
final RValue memberValue = valueList.getList().get(memberIndex);
return new SimpleRValueUnwinding(type, arraySpec, memberValue);
}
}

View File

@ -0,0 +1,37 @@
package dk.camelot64.kickc.passes.unwinding;
import dk.camelot64.kickc.model.symbols.StructDefinition;
import dk.camelot64.kickc.model.symbols.Variable;
import dk.camelot64.kickc.model.values.StructZero;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/** Unwinding for StructZero */
public class StructMemberUnwindingZero implements StructMemberUnwinding {
private StructZero structZero;
private StructDefinition structDefinition;
public StructMemberUnwindingZero(StructZero structZero, StructDefinition structDefinition) {
this.structZero = structZero;
this.structDefinition = structDefinition;
}
@Override
public List<String> getMemberNames() {
Collection<Variable> structMemberVars = structDefinition.getAllVariables(false);
ArrayList<String> memberNames = new ArrayList<>();
for(Variable structMemberVar : structMemberVars) {
memberNames.add(structMemberVar.getLocalName());
}
return memberNames;
}
@Override
public RValueUnwinding getMemberUnwinding(String memberName) {
Variable member = structDefinition.getMember(memberName);
return new ZeroValueUnwinding(member.getType(), member.getArraySpec());
}
}

View File

@ -0,0 +1,141 @@
package dk.camelot64.kickc.passes.unwinding;
import dk.camelot64.kickc.model.ControlFlowBlock;
import dk.camelot64.kickc.model.operators.Operators;
import dk.camelot64.kickc.model.statements.Statement;
import dk.camelot64.kickc.model.symbols.ArraySpec;
import dk.camelot64.kickc.model.symbols.ProgramScope;
import dk.camelot64.kickc.model.symbols.StructDefinition;
import dk.camelot64.kickc.model.symbols.Variable;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.types.SymbolTypePointer;
import dk.camelot64.kickc.model.values.*;
import dk.camelot64.kickc.passes.PassNStructPointerRewriting;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.ListIterator;
/** Unwinding for a struct value with C-classic memory layout. */
public class StructVariableMemberUnwinding implements StructMemberUnwinding {
private Variable variable;
private StructDefinition structDefinition;
private final ControlFlowBlock currentBlock;
private final ListIterator<Statement> stmtIt;
private final Statement currentStmt;
public StructVariableMemberUnwinding(Variable variable, StructDefinition structDefinition, ControlFlowBlock currentBlock, ListIterator<Statement> stmtIt, Statement currentStmt) {
this.variable = variable;
this.structDefinition = structDefinition;
this.currentBlock = currentBlock;
this.stmtIt = stmtIt;
this.currentStmt = currentStmt;
}
@Override
public List<String> getMemberNames() {
Collection<Variable> structMemberVars = structDefinition.getAllVars(false);
ArrayList<String> memberNames = new ArrayList<>();
for(Variable structMemberVar : structMemberVars) {
memberNames.add(structMemberVar.getLocalName());
}
return memberNames;
}
@Override
public RValueUnwinding getMemberUnwinding(String memberName) {
final SymbolType symbolType = structDefinition.getMember(memberName).getType();
final ArraySpec arraySpec = structDefinition.getMember(memberName).getArraySpec();
if(arraySpec==null) {
// Simple member value - unwind to value of member *((type*)&struct + OFFSET_MEMBER)
return new RValueUnwinding() {
@Override
public SymbolType getSymbolType() {
return symbolType;
}
@Override
public ArraySpec getArraySpec() {
return arraySpec;
}
@Override
public RValue getUnwinding(ProgramScope programScope) {
ConstantRef memberOffsetConstant = PassNStructPointerRewriting.getMemberOffsetConstant(programScope, structDefinition, memberName);
ConstantSymbolPointer structPointer = new ConstantSymbolPointer(variable.getRef());
// Pointer to member type
ConstantCastValue structTypedPointer = new ConstantCastValue(new SymbolTypePointer(getSymbolType()), structPointer);
// Calculate member address (type*)&struct + OFFSET_MEMBER
ConstantBinary memberArrayPointer = new ConstantBinary(structTypedPointer, Operators.PLUS, memberOffsetConstant);
// Unwind to *((type*)&struct + OFFSET_MEMBER)
return new PointerDereferenceSimple(memberArrayPointer);
}
@Override
public boolean isBulkCopyable() {
return false;
}
@Override
public LValue getBulkLValue(ProgramScope scope) {
return null;
}
@Override
public RValue getBulkRValue(ProgramScope scope) {
return null;
}
};
} else {
// Array struct member - unwind to pointer to first element (elmtype*)&struct + OFFSET_MEMBER
return new RValueUnwinding() {
@Override
public SymbolType getSymbolType() {
return symbolType;
}
@Override
public ArraySpec getArraySpec() {
return arraySpec;
}
@Override
public RValue getUnwinding(ProgramScope programScope) {
ConstantRef memberOffsetConstant = PassNStructPointerRewriting.getMemberOffsetConstant(programScope, structDefinition, memberName);
ConstantSymbolPointer structPointer = new ConstantSymbolPointer(variable.getRef());
// Pointer to member element type (elmtype*)&struct
SymbolTypePointer memberType = (SymbolTypePointer) getSymbolType();
ConstantCastValue structTypedPointer = new ConstantCastValue(new SymbolTypePointer(memberType.getElementType()), structPointer);
// Calculate member address (elmtype*)&struct + OFFSET_MEMBER
ConstantBinary memberArrayPointer = new ConstantBinary(structTypedPointer, Operators.PLUS, memberOffsetConstant);
// Unwind to (elmtype*)&struct + OFFSET_MEMBER
return memberArrayPointer;
}
@Override
public boolean isBulkCopyable() {
return true;
}
@Override
public LValue getBulkLValue(ProgramScope scope) {
RValue memberArrayPointer = getUnwinding(scope);
return new PointerDereferenceSimple(memberArrayPointer);
}
@Override
public RValue getBulkRValue(ProgramScope scope) {
RValue memberArrayPointer = getUnwinding(scope);
return new MemcpyValue(new PointerDereferenceSimple(memberArrayPointer), getArraySpec().getArraySize());
}
};
}
}
}

View File

@ -0,0 +1,53 @@
package dk.camelot64.kickc.passes.unwinding;
import dk.camelot64.kickc.model.symbols.ArraySpec;
import dk.camelot64.kickc.model.symbols.ProgramScope;
import dk.camelot64.kickc.model.symbols.Variable;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.values.*;
/** Value unwinding for a variable. */
public class StructVariableValueUnwinding implements RValueUnwinding {
private final Variable variable;
public StructVariableValueUnwinding(Variable variable) {
this.variable = variable;
}
@Override
public SymbolType getSymbolType() {
return variable.getType();
}
@Override
public ArraySpec getArraySpec() {
return variable.getArraySpec();
}
@Override
public RValue getUnwinding(ProgramScope programScope) {
ConstantSymbolPointer pointer = new ConstantSymbolPointer(variable.getRef());
return pointer;
}
@Override
public boolean isBulkCopyable() {
return getArraySpec()!=null;
}
@Override
public LValue getBulkLValue(ProgramScope scope) {
ConstantSymbolPointer pointer = new ConstantSymbolPointer(variable.getRef());
LValue pointerDeref = new PointerDereferenceSimple(pointer);
return pointerDeref;
}
@Override
public RValue getBulkRValue(ProgramScope scope) {
ConstantSymbolPointer pointer = new ConstantSymbolPointer(variable.getRef());
LValue pointerDeref = new PointerDereferenceSimple(pointer);
return new MemcpyValue(pointerDeref, getArraySpec().getArraySize());
}
}

View File

@ -0,0 +1,59 @@
package dk.camelot64.kickc.passes.unwinding;
import dk.camelot64.kickc.model.InternalError;
import dk.camelot64.kickc.model.operators.OperatorSizeOf;
import dk.camelot64.kickc.model.symbols.ArraySpec;
import dk.camelot64.kickc.model.symbols.ProgramScope;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.types.SymbolTypeStruct;
import dk.camelot64.kickc.model.values.*;
/** Assignment unwinding for a zero value. */
public class ZeroValueUnwinding implements RValueUnwinding {
private final SymbolType symbolType;
private final ArraySpec arraySpec;
public ZeroValueUnwinding(SymbolType symbolType, ArraySpec arraySpec) {
this.symbolType = symbolType;
this.arraySpec = arraySpec;
}
@Override
public SymbolType getSymbolType() {
return symbolType;
}
@Override
public ArraySpec getArraySpec() {
return arraySpec;
}
@Override
public RValue getUnwinding(ProgramScope programScope) {
return ZeroConstantValues.zeroValue(getSymbolType(), programScope);
}
@Override
public boolean isBulkCopyable() {
return arraySpec!=null;
}
@Override
public LValue getBulkLValue(ProgramScope scope) {
throw new InternalError("Not a legal LValue!");
}
@Override
public RValue getBulkRValue(ProgramScope scope) {
ConstantValue byteSize;
if(getArraySpec()!=null) {
byteSize = getArraySpec().getArraySize();
} else if(symbolType instanceof SymbolTypeStruct) {
byteSize = OperatorSizeOf.getSizeOfConstantVar(scope, symbolType);
} else {
throw new InternalError("Bulk unwinding of zero value not handled "+symbolType.getTypeName());
}
return new MemsetValue(byteSize);
}
}

View File

@ -1127,14 +1127,24 @@ public class TestPrograms {
assertError("struct-err-0", "Unknown struct type"); assertError("struct-err-0", "Unknown struct type");
} }
@Test
public void testStruct31() throws IOException, URISyntaxException {
compileAndCompare("struct-31");
}
@Test
public void testStruct30() throws IOException, URISyntaxException {
compileAndCompare("struct-30");
}
@Test @Test
public void testStruct29() throws IOException, URISyntaxException { public void testStruct29() throws IOException, URISyntaxException {
compileAndCompare("struct-29", log()); compileAndCompare("struct-29");
} }
@Test @Test
public void testStruct28() throws IOException, URISyntaxException { public void testStruct28() throws IOException, URISyntaxException {
compileAndCompare("struct-28", log()); compileAndCompare("struct-28");
} }
@Test @Test
@ -1189,7 +1199,7 @@ public class TestPrograms {
@Test @Test
public void testStruct17() throws IOException, URISyntaxException { public void testStruct17() throws IOException, URISyntaxException {
compileAndCompare("struct-17"); compileAndCompare("struct-17", log());
} }
@Test @Test

16
src/test/kc/struct-30.kc Normal file
View File

@ -0,0 +1,16 @@
// Minimal struct with MemberUnwind behavior - array member and local initializer
struct Point {
char x;
char[3] initials;
};
const char* SCREEN = 0x0400;
void main() {
struct Point point1 = { 2, "jg" };
SCREEN[0] = point1.x;
SCREEN[1] = point1.initials[0];
SCREEN[2] = point1.initials[1];
}

15
src/test/kc/struct-31.kc Normal file
View File

@ -0,0 +1,15 @@
// Minimal struct with MemberUnwind behavior - simple members and local initializer
struct Point {
char x;
char y;
};
const char* SCREEN = 0x0400;
void main() {
struct Point point1 = { 2, 3 };
SCREEN[0] = point1.x;
SCREEN[1] = point1.y;
}

View File

@ -18,7 +18,7 @@ CONTROL FLOW GRAPH SSA
*((byte*)&(struct foo) bar+(const byte) OFFSET_STRUCT_FOO_THING1) ← (byte) 'a' *((byte*)&(struct foo) bar+(const byte) OFFSET_STRUCT_FOO_THING1) ← (byte) 'a'
*((byte*)&(struct foo) bar+(const byte) OFFSET_STRUCT_FOO_THING2) ← (byte) 'b' *((byte*)&(struct foo) bar+(const byte) OFFSET_STRUCT_FOO_THING2) ← (byte) 'b'
*((byte*)&(struct foo) bar+(const byte) OFFSET_STRUCT_FOO_THING3) ← memcpy(*((const byte*) $0), (number) $c) *((byte*)&(struct foo) bar+(const byte) OFFSET_STRUCT_FOO_THING3) ← memcpy(*((const byte*) $0), (number) $c)
(struct foo) bar ← struct-unwound {*((byte*)&(struct foo) bar+(const byte) OFFSET_STRUCT_FOO_THING1), *((byte*)&(struct foo) bar+(const byte) OFFSET_STRUCT_FOO_THING2), (byte*)&(struct foo) bar+(const byte) OFFSET_STRUCT_FOO_THING3} (struct foo) bar ← struct-unwound {*((byte*)&(struct foo) bar+(const byte) OFFSET_STRUCT_FOO_THING1), *((byte*)&(struct foo) bar+(const byte) OFFSET_STRUCT_FOO_THING2), *((byte*)&(struct foo) bar+(const byte) OFFSET_STRUCT_FOO_THING3)}
to:@1 to:@1
(void()) main() (void()) main()
@ -89,7 +89,7 @@ Simplifying constant pointer cast (byte*) 1024
Successful SSA optimization PassNCastSimplification Successful SSA optimization PassNCastSimplification
Simple Condition (bool~) main::$0 [18] if((byte) main::j#1!=rangelast(0,$b)) goto main::@1 Simple Condition (bool~) main::$0 [18] if((byte) main::j#1!=rangelast(0,$b)) goto main::@1
Successful SSA optimization Pass2ConditionalJumpSimplification Successful SSA optimization Pass2ConditionalJumpSimplification
Removing C-classic struct-unwound assignment [3] (struct foo) bar ← struct-unwound {*((byte*)&(struct foo) bar+(const byte) OFFSET_STRUCT_FOO_THING1), *((byte*)&(struct foo) bar+(const byte) OFFSET_STRUCT_FOO_THING2), (byte*)&(struct foo) bar+(const byte) OFFSET_STRUCT_FOO_THING3} Removing C-classic struct-unwound assignment [3] (struct foo) bar ← struct-unwound {*((byte*)&(struct foo) bar+(const byte) OFFSET_STRUCT_FOO_THING1), *((byte*)&(struct foo) bar+(const byte) OFFSET_STRUCT_FOO_THING2), *((byte*)&(struct foo) bar+(const byte) OFFSET_STRUCT_FOO_THING3)}
Constant right-side identified [5] (byte*~) main::$1 ← (byte*)(const struct foo*) main::barp + (const byte) OFFSET_STRUCT_FOO_THING1 Constant right-side identified [5] (byte*~) main::$1 ← (byte*)(const struct foo*) main::barp + (const byte) OFFSET_STRUCT_FOO_THING1
Constant right-side identified [8] (byte*~) main::$2 ← (byte*)(const struct foo*) main::barp + (const byte) OFFSET_STRUCT_FOO_THING2 Constant right-side identified [8] (byte*~) main::$2 ← (byte*)(const struct foo*) main::barp + (const byte) OFFSET_STRUCT_FOO_THING2
Constant right-side identified [13] (byte*~) main::$3 ← (byte*)(const struct foo*) main::barp + (const byte) OFFSET_STRUCT_FOO_THING3 Constant right-side identified [13] (byte*~) main::$3 ← (byte*)(const struct foo*) main::barp + (const byte) OFFSET_STRUCT_FOO_THING3

View File

@ -19,7 +19,7 @@ CONTROL FLOW GRAPH SSA
main: scope:[main] from @1 main: scope:[main] from @1
*((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) ← (byte) 0 *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) ← (byte) 0
*((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) ← memset((number) 2) *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) ← memset((number) 2)
(struct Point) main::point1 ← struct-unwound {*((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X), (byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS} (struct Point) main::point1 ← struct-unwound {*((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X), *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS)}
*((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) ← (number) 2 *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) ← (number) 2
*((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 0) ← (byte) 'j' *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 0) ← (byte) 'j'
*((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 1) ← (byte) 'g' *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 1) ← (byte) 'g'
@ -81,7 +81,7 @@ Finalized unsigned number type (byte) 1
Finalized unsigned number type (byte) 1 Finalized unsigned number type (byte) 1
Finalized unsigned number type (byte) 2 Finalized unsigned number type (byte) 2
Successful SSA optimization PassNFinalizeNumberTypeConversions Successful SSA optimization PassNFinalizeNumberTypeConversions
Removing C-classic struct-unwound assignment [2] (struct Point) main::point1 ← struct-unwound {*((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X), (byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS} Removing C-classic struct-unwound assignment [2] (struct Point) main::point1 ← struct-unwound {*((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X), *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS)}
Simplifying expression containing zero (byte*)&main::point1 in [0] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) ← (byte) 0 Simplifying expression containing zero (byte*)&main::point1 in [0] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) ← (byte) 0
Simplifying expression containing zero (byte*)&main::point1 in [3] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) ← (byte) 2 Simplifying expression containing zero (byte*)&main::point1 in [3] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) ← (byte) 2
Simplifying expression containing zero (byte*)&main::point1+OFFSET_STRUCT_POINT_INITIALS in [4] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (byte) 0) ← (byte) 'j' Simplifying expression containing zero (byte*)&main::point1+OFFSET_STRUCT_POINT_INITIALS in [4] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (byte) 0) ← (byte) 'j'

View File

@ -23,13 +23,13 @@ CONTROL FLOW GRAPH SSA
main: scope:[main] from @1 main: scope:[main] from @1
*((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) ← (byte) 0 *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) ← (byte) 0
*((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) ← memset((number) 2) *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) ← memset((number) 2)
(struct Point) main::point1 ← struct-unwound {*((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X), (byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS} (struct Point) main::point1 ← struct-unwound {*((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X), *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS)}
*((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) ← (number) 2 *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) ← (number) 2
*((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 0) ← (byte) 'j' *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 0) ← (byte) 'j'
*((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 1) ← (byte) 'g' *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 1) ← (byte) 'g'
*((byte*)&(struct Point) main::point2+(const byte) OFFSET_STRUCT_POINT_X) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) *((byte*)&(struct Point) main::point2+(const byte) OFFSET_STRUCT_POINT_X) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X)
*((byte*)&(struct Point) main::point2+(const byte) OFFSET_STRUCT_POINT_INITIALS) ← memcpy(*((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS), (number) 2) *((byte*)&(struct Point) main::point2+(const byte) OFFSET_STRUCT_POINT_INITIALS) ← memcpy(*((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS), (number) 2)
(struct Point) main::point2 ← struct-unwound {*((byte*)&(struct Point) main::point2+(const byte) OFFSET_STRUCT_POINT_X), (byte*)&(struct Point) main::point2+(const byte) OFFSET_STRUCT_POINT_INITIALS} (struct Point) main::point2 ← struct-unwound {*((byte*)&(struct Point) main::point2+(const byte) OFFSET_STRUCT_POINT_X), *((byte*)&(struct Point) main::point2+(const byte) OFFSET_STRUCT_POINT_INITIALS)}
*((const byte*) SCREEN + (number) 0) ← *((byte*)&(struct Point) main::point2+(const byte) OFFSET_STRUCT_POINT_X) *((const byte*) SCREEN + (number) 0) ← *((byte*)&(struct Point) main::point2+(const byte) OFFSET_STRUCT_POINT_X)
*((const byte*) SCREEN + (number) 1) ← *((byte*)&(struct Point) main::point2+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 0) *((const byte*) SCREEN + (number) 1) ← *((byte*)&(struct Point) main::point2+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 0)
*((const byte*) SCREEN + (number) 2) ← *((byte*)&(struct Point) main::point2+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 1) *((const byte*) SCREEN + (number) 2) ← *((byte*)&(struct Point) main::point2+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 1)
@ -89,8 +89,8 @@ Finalized unsigned number type (byte) 1
Finalized unsigned number type (byte) 1 Finalized unsigned number type (byte) 1
Finalized unsigned number type (byte) 2 Finalized unsigned number type (byte) 2
Successful SSA optimization PassNFinalizeNumberTypeConversions Successful SSA optimization PassNFinalizeNumberTypeConversions
Removing C-classic struct-unwound assignment [2] (struct Point) main::point1 ← struct-unwound {*((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X), (byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS} Removing C-classic struct-unwound assignment [2] (struct Point) main::point1 ← struct-unwound {*((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X), *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS)}
Removing C-classic struct-unwound assignment [8] (struct Point) main::point2 ← struct-unwound {*((byte*)&(struct Point) main::point2+(const byte) OFFSET_STRUCT_POINT_X), (byte*)&(struct Point) main::point2+(const byte) OFFSET_STRUCT_POINT_INITIALS} Removing C-classic struct-unwound assignment [8] (struct Point) main::point2 ← struct-unwound {*((byte*)&(struct Point) main::point2+(const byte) OFFSET_STRUCT_POINT_X), *((byte*)&(struct Point) main::point2+(const byte) OFFSET_STRUCT_POINT_INITIALS)}
Simplifying expression containing zero (byte*)&main::point1 in [0] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) ← (byte) 0 Simplifying expression containing zero (byte*)&main::point1 in [0] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) ← (byte) 0
Simplifying expression containing zero (byte*)&main::point1 in [3] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) ← (byte) 2 Simplifying expression containing zero (byte*)&main::point1 in [3] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) ← (byte) 2
Simplifying expression containing zero (byte*)&main::point1+OFFSET_STRUCT_POINT_INITIALS in [4] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (byte) 0) ← (byte) 'j' Simplifying expression containing zero (byte*)&main::point1+OFFSET_STRUCT_POINT_INITIALS in [4] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (byte) 0) ← (byte) 'j'

View File

@ -16,7 +16,7 @@ CONTROL FLOW GRAPH SSA
main: scope:[main] from @1 main: scope:[main] from @1
*((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) ← (byte) 2 *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) ← (byte) 2
*((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) ← memcpy(*((const byte*) $0), (number) 3) *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) ← memcpy(*((const byte*) $0), (number) 3)
(struct Point) main::point1 ← struct-unwound {*((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X), (byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS} (struct Point) main::point1 ← struct-unwound {*((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X), *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS)}
*((const byte*) SCREEN + (number) 0) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) *((const byte*) SCREEN + (number) 0) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X)
*((const byte*) SCREEN + (number) 1) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 0) *((const byte*) SCREEN + (number) 1) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 0)
*((const byte*) SCREEN + (number) 2) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 1) *((const byte*) SCREEN + (number) 2) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 1)
@ -65,7 +65,7 @@ Finalized unsigned number type (byte) 1
Finalized unsigned number type (byte) 1 Finalized unsigned number type (byte) 1
Finalized unsigned number type (byte) 2 Finalized unsigned number type (byte) 2
Successful SSA optimization PassNFinalizeNumberTypeConversions Successful SSA optimization PassNFinalizeNumberTypeConversions
Removing C-classic struct-unwound assignment [2] (struct Point) main::point1 ← struct-unwound {*((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X), (byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS} Removing C-classic struct-unwound assignment [2] (struct Point) main::point1 ← struct-unwound {*((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X), *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS)}
Simplifying expression containing zero (byte*)&main::point1 in [0] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) ← (byte) 2 Simplifying expression containing zero (byte*)&main::point1 in [0] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) ← (byte) 2
Simplifying expression containing zero (byte*)&main::point1 in [3] *((const byte*) SCREEN + (byte) 0) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) Simplifying expression containing zero (byte*)&main::point1 in [3] *((const byte*) SCREEN + (byte) 0) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X)
Simplifying expression containing zero SCREEN in [3] *((const byte*) SCREEN + (byte) 0) ← *((byte*)&(struct Point) main::point1) Simplifying expression containing zero SCREEN in [3] *((const byte*) SCREEN + (byte) 0) ← *((byte*)&(struct Point) main::point1)

View File

@ -16,7 +16,7 @@ CONTROL FLOW GRAPH SSA
main: scope:[main] from @1 main: scope:[main] from @1
*((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) ← (byte) 2 *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) ← (byte) 2
*((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) ← memcpy(*((const byte*) $0), (number) 2) *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) ← memcpy(*((const byte*) $0), (number) 2)
(struct Point) main::point1 ← struct-unwound {*((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X), (byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS} (struct Point) main::point1 ← struct-unwound {*((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X), *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS)}
*((const byte*) SCREEN + (number) 0) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) *((const byte*) SCREEN + (number) 0) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X)
*((const byte*) SCREEN + (number) 1) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 0) *((const byte*) SCREEN + (number) 1) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 0)
*((const byte*) SCREEN + (number) 2) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 1) *((const byte*) SCREEN + (number) 2) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 1)
@ -65,7 +65,7 @@ Finalized unsigned number type (byte) 1
Finalized unsigned number type (byte) 1 Finalized unsigned number type (byte) 1
Finalized unsigned number type (byte) 2 Finalized unsigned number type (byte) 2
Successful SSA optimization PassNFinalizeNumberTypeConversions Successful SSA optimization PassNFinalizeNumberTypeConversions
Removing C-classic struct-unwound assignment [2] (struct Point) main::point1 ← struct-unwound {*((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X), (byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS} Removing C-classic struct-unwound assignment [2] (struct Point) main::point1 ← struct-unwound {*((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X), *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS)}
Simplifying expression containing zero (byte*)&main::point1 in [0] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) ← (byte) 2 Simplifying expression containing zero (byte*)&main::point1 in [0] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) ← (byte) 2
Simplifying expression containing zero (byte*)&main::point1 in [3] *((const byte*) SCREEN + (byte) 0) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) Simplifying expression containing zero (byte*)&main::point1 in [3] *((const byte*) SCREEN + (byte) 0) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X)
Simplifying expression containing zero SCREEN in [3] *((const byte*) SCREEN + (byte) 0) ← *((byte*)&(struct Point) main::point1) Simplifying expression containing zero SCREEN in [3] *((const byte*) SCREEN + (byte) 0) ← *((byte*)&(struct Point) main::point1)

View File

@ -12,7 +12,7 @@ CONTROL FLOW GRAPH SSA
@begin: scope:[] from @begin: scope:[] from
*((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_X) ← (byte) 2 *((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) *((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} (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 to:@1
(void()) main() (void()) main()
@ -65,7 +65,7 @@ Finalized unsigned number type (byte) 1
Finalized unsigned number type (byte) 1 Finalized unsigned number type (byte) 1
Finalized unsigned number type (byte) 2 Finalized unsigned number type (byte) 2
Successful SSA optimization PassNFinalizeNumberTypeConversions 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} 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 [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 (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 SCREEN in [3] *((const byte*) SCREEN + (byte) 0) ← *((byte*)&(struct Point) point1)

View File

@ -0,0 +1,24 @@
// Minimal struct with MemberUnwind behavior - array member and local initializer
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.label SCREEN = $400
main: {
.const point1_x = 2
ldy #3
!:
lda __0-1,y
sta point1_initials-1,y
dey
bne !-
lda #point1_x
sta SCREEN
lda point1_initials
sta SCREEN+1
lda point1_initials+1
sta SCREEN+2
rts
point1_initials: .fill 3, 0
}
__0: .text "jg"
.byte 0

View File

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

324
src/test/ref/struct-30.log Normal file
View File

@ -0,0 +1,324 @@
Fixing struct type size struct Point to 4
Fixing struct type SIZE_OF struct Point to 4
Fixing struct type SIZE_OF struct Point to 4
Created struct value member variable (byte) main::point1_x
Created struct value member variable (const byte*) main::point1_initials
Converted struct value to member variables (struct Point) main::point1
Adding struct value member variable copy (byte) main::point1_x ← (byte) 2
Adding struct value member variable copy *((const byte*) main::point1_initials) ← memcpy(*((const byte*) $0), (number) 3)
Replacing struct member reference (struct Point) main::point1.x with member unwinding reference (byte) main::point1_x
Replacing struct member reference (struct Point) main::point1.initials with member unwinding reference (const byte*) main::point1_initials
Replacing struct member reference (struct Point) main::point1.initials with member unwinding reference (const byte*) main::point1_initials
Identified constant variable (byte) main::point1_x
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
to:@1
(void()) main()
main: scope:[main] from @1
*((const byte*) main::point1_initials) ← memcpy(*((const byte*) $0), (number) 3)
*((const byte*) SCREEN + (number) 0) ← (const byte) main::point1_x
*((const byte*) SCREEN + (number) 1) ← *((const byte*) main::point1_initials + (number) 0)
*((const byte*) SCREEN + (number) 2) ← *((const byte*) main::point1_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) 3] = (string) "jg"
(label) @1
(label) @2
(label) @begin
(label) @end
(const byte*) Point::initials[(number) 3] = { fill( 3, 0) }
(byte) Point::x
(const byte*) SCREEN = (byte*)(number) $400
(void()) main()
(label) main::@return
(const byte*) main::point1_initials[(number) 3] = { fill( 3, 0) }
(const byte) main::point1_x = (byte) 2
Adding number conversion cast (unumber) 0 in *((const byte*) SCREEN + (number) 0) ← (const byte) main::point1_x
Adding number conversion cast (unumber) 0 in *((const byte*) SCREEN + (number) 1) ← *((const byte*) main::point1_initials + (number) 0)
Adding number conversion cast (unumber) 1 in *((const byte*) SCREEN + (number) 1) ← *((const byte*) main::point1_initials + (unumber)(number) 0)
Adding number conversion cast (unumber) 1 in *((const byte*) SCREEN + (number) 2) ← *((const byte*) main::point1_initials + (number) 1)
Adding number conversion cast (unumber) 2 in *((const byte*) SCREEN + (number) 2) ← *((const byte*) main::point1_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
Simplifying expression containing zero SCREEN in [1] *((const byte*) SCREEN + (byte) 0) ← (const byte) main::point1_x
Simplifying expression containing zero main::point1_initials in [2] *((const byte*) SCREEN + (byte) 1) ← *((const byte*) main::point1_initials + (byte) 0)
Successful SSA optimization PassNSimplifyExpressionWithZero
Consolidated array index constant in *(SCREEN+1)
Consolidated array index constant in *(main::point1_initials+1)
Consolidated array index constant in *(SCREEN+2)
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()
(void()) main()
main: scope:[main] from @1
[4] *((const byte*) main::point1_initials) ← memcpy(*((const byte*) $0), (number) 3)
[5] *((const byte*) SCREEN) ← (const byte) main::point1_x
[6] *((const byte*) SCREEN+(byte) 1) ← *((const byte*) main::point1_initials)
[7] *((const byte*) SCREEN+(byte) 2) ← *((const byte*) main::point1_initials+(byte) 1)
to:main::@return
main::@return: scope:[main] from main
[8] return
to:@return
VARIABLE REGISTER WEIGHTS
(byte) Point::x
(void()) main()
Initial phi equivalence classes
Complete equivalence classes
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Minimal struct with MemberUnwind behavior - array member and local initializer
// Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
.label SCREEN = $400
// @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: {
.const point1_x = 2
// [4] *((const byte*) main::point1_initials) ← memcpy(*((const byte*) $0), (number) 3) -- _deref_pbuc1=_deref_pbuc2_memcpy_vbuc3
ldy #3
!:
lda __0-1,y
sta point1_initials-1,y
dey
bne !-
// [5] *((const byte*) SCREEN) ← (const byte) main::point1_x -- _deref_pbuc1=vbuc2
lda #point1_x
sta SCREEN
// [6] *((const byte*) SCREEN+(byte) 1) ← *((const byte*) main::point1_initials) -- _deref_pbuc1=_deref_pbuc2
lda point1_initials
sta SCREEN+1
// [7] *((const byte*) SCREEN+(byte) 2) ← *((const byte*) main::point1_initials+(byte) 1) -- _deref_pbuc1=_deref_pbuc2
lda point1_initials+1
sta SCREEN+2
jmp __breturn
// main::@return
__breturn:
// [8] return
rts
point1_initials: .fill 3, 0
}
// File Data
__0: .text "jg"
.byte 0
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [4] *((const byte*) main::point1_initials) ← memcpy(*((const byte*) $0), (number) 3) [ ] ( main:2 [ ] ) always clobbers reg byte a reg byte y
Statement [5] *((const byte*) SCREEN) ← (const byte) main::point1_x [ ] ( main:2 [ ] ) always clobbers reg byte a
Statement [6] *((const byte*) SCREEN+(byte) 1) ← *((const byte*) main::point1_initials) [ ] ( main:2 [ ] ) always clobbers reg byte a
Statement [7] *((const byte*) SCREEN+(byte) 2) ← *((const byte*) main::point1_initials+(byte) 1) [ ] ( main:2 [ ] ) always clobbers reg byte a
REGISTER UPLIFT SCOPES
Uplift Scope [Point]
Uplift Scope [main]
Uplift Scope []
Uplifting [Point] best 59 combination
Uplifting [main] best 59 combination
Uplifting [] best 59 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Minimal struct with MemberUnwind behavior - array member and local initializer
// Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
.label SCREEN = $400
// @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: {
.const point1_x = 2
// [4] *((const byte*) main::point1_initials) ← memcpy(*((const byte*) $0), (number) 3) -- _deref_pbuc1=_deref_pbuc2_memcpy_vbuc3
ldy #3
!:
lda __0-1,y
sta point1_initials-1,y
dey
bne !-
// [5] *((const byte*) SCREEN) ← (const byte) main::point1_x -- _deref_pbuc1=vbuc2
lda #point1_x
sta SCREEN
// [6] *((const byte*) SCREEN+(byte) 1) ← *((const byte*) main::point1_initials) -- _deref_pbuc1=_deref_pbuc2
lda point1_initials
sta SCREEN+1
// [7] *((const byte*) SCREEN+(byte) 2) ← *((const byte*) main::point1_initials+(byte) 1) -- _deref_pbuc1=_deref_pbuc2
lda point1_initials+1
sta SCREEN+2
jmp __breturn
// main::@return
__breturn:
// [8] return
rts
point1_initials: .fill 3, 0
}
// File Data
__0: .text "jg"
.byte 0
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
Removing instruction jmp __bend
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Replacing label __bbegin with __b1
Removing instruction __bbegin:
Removing instruction __b1_from___bbegin:
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 __b1:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(const byte*) $0[(number) 3] = (string) "jg"
(label) @1
(label) @begin
(label) @end
(const byte*) Point::initials[(number) 3] = { fill( 3, 0) }
(byte) Point::x
(const byte*) SCREEN = (byte*) 1024
(void()) main()
(label) main::@return
(const byte*) main::point1_initials[(number) 3] = { fill( 3, 0) }
(const byte) main::point1_x = (byte) 2
FINAL ASSEMBLER
Score: 44
// File Comments
// Minimal struct with MemberUnwind behavior - array member and local initializer
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.label SCREEN = $400
// @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: {
.const point1_x = 2
// point1 = { 2, "jg" }
// [4] *((const byte*) main::point1_initials) ← memcpy(*((const byte*) $0), (number) 3) -- _deref_pbuc1=_deref_pbuc2_memcpy_vbuc3
ldy #3
!:
lda __0-1,y
sta point1_initials-1,y
dey
bne !-
// SCREEN[0] = point1.x
// [5] *((const byte*) SCREEN) ← (const byte) main::point1_x -- _deref_pbuc1=vbuc2
lda #point1_x
sta SCREEN
// SCREEN[1] = point1.initials[0]
// [6] *((const byte*) SCREEN+(byte) 1) ← *((const byte*) main::point1_initials) -- _deref_pbuc1=_deref_pbuc2
lda point1_initials
sta SCREEN+1
// SCREEN[2] = point1.initials[1]
// [7] *((const byte*) SCREEN+(byte) 2) ← *((const byte*) main::point1_initials+(byte) 1) -- _deref_pbuc1=_deref_pbuc2
lda point1_initials+1
sta SCREEN+2
// main::@return
// }
// [8] return
rts
point1_initials: .fill 3, 0
}
// File Data
__0: .text "jg"
.byte 0

View File

@ -0,0 +1,12 @@
(const byte*) $0[(number) 3] = (string) "jg"
(label) @1
(label) @begin
(label) @end
(const byte*) Point::initials[(number) 3] = { fill( 3, 0) }
(byte) Point::x
(const byte*) SCREEN = (byte*) 1024
(void()) main()
(label) main::@return
(const byte*) main::point1_initials[(number) 3] = { fill( 3, 0) }
(const byte) main::point1_x = (byte) 2

View File

@ -0,0 +1,14 @@
// Minimal struct with MemberUnwind behavior - simple members and local initializer
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.label SCREEN = $400
main: {
.const point1_x = 2
.const point1_y = 3
lda #point1_x
sta SCREEN
lda #point1_y
sta SCREEN+1
rts
}

View File

@ -0,0 +1,18 @@
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
(void()) main()
main: scope:[main] from @1
[4] *((const byte*) SCREEN) ← (const byte) main::point1_x
[5] *((const byte*) SCREEN+(byte) 1) ← (const byte) main::point1_y
to:main::@return
main::@return: scope:[main] from main
[6] return
to:@return

264
src/test/ref/struct-31.log Normal file
View File

@ -0,0 +1,264 @@
Created struct value member variable (byte) main::point1_x
Created struct value member variable (byte) main::point1_y
Converted struct value to member variables (struct Point) main::point1
Adding struct value member variable copy (byte) main::point1_x ← (byte) 2
Adding struct value member variable copy (byte) main::point1_y ← (byte) 3
Replacing struct member reference (struct Point) main::point1.x with member unwinding reference (byte) main::point1_x
Replacing struct member reference (struct Point) main::point1.y with member unwinding reference (byte) main::point1_y
Identified constant variable (byte) main::point1_x
Identified constant variable (byte) main::point1_y
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
to:@1
(void()) main()
main: scope:[main] from @1
*((const byte*) SCREEN + (number) 0) ← (const byte) main::point1_x
*((const byte*) SCREEN + (number) 1) ← (const byte) main::point1_y
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
(label) @1
(label) @2
(label) @begin
(label) @end
(byte) Point::x
(byte) Point::y
(const byte*) SCREEN = (byte*)(number) $400
(void()) main()
(label) main::@return
(const byte) main::point1_x = (byte) 2
(const byte) main::point1_y = (byte) 3
Adding number conversion cast (unumber) 0 in *((const byte*) SCREEN + (number) 0) ← (const byte) main::point1_x
Adding number conversion cast (unumber) 1 in *((const byte*) SCREEN + (number) 1) ← (const byte) main::point1_y
Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant pointer cast (byte*) 1024
Simplifying constant integer cast 0
Simplifying constant integer cast 1
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 0
Finalized unsigned number type (byte) 1
Successful SSA optimization PassNFinalizeNumberTypeConversions
Simplifying expression containing zero SCREEN in [0] *((const byte*) SCREEN + (byte) 0) ← (const byte) main::point1_x
Successful SSA optimization PassNSimplifyExpressionWithZero
Consolidated array index constant in *(SCREEN+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()
(void()) main()
main: scope:[main] from @1
[4] *((const byte*) SCREEN) ← (const byte) main::point1_x
[5] *((const byte*) SCREEN+(byte) 1) ← (const byte) main::point1_y
to:main::@return
main::@return: scope:[main] from main
[6] return
to:@return
VARIABLE REGISTER WEIGHTS
(byte) Point::x
(byte) Point::y
(void()) main()
Initial phi equivalence classes
Complete equivalence classes
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Minimal struct with MemberUnwind behavior - simple members and local initializer
// Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
.label SCREEN = $400
// @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: {
.const point1_x = 2
.const point1_y = 3
// [4] *((const byte*) SCREEN) ← (const byte) main::point1_x -- _deref_pbuc1=vbuc2
lda #point1_x
sta SCREEN
// [5] *((const byte*) SCREEN+(byte) 1) ← (const byte) main::point1_y -- _deref_pbuc1=vbuc2
lda #point1_y
sta SCREEN+1
jmp __breturn
// main::@return
__breturn:
// [6] return
rts
}
// File Data
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [4] *((const byte*) SCREEN) ← (const byte) main::point1_x [ ] ( main:2 [ ] ) always clobbers reg byte a
Statement [5] *((const byte*) SCREEN+(byte) 1) ← (const byte) main::point1_y [ ] ( main:2 [ ] ) always clobbers reg byte a
REGISTER UPLIFT SCOPES
Uplift Scope [Point]
Uplift Scope [main]
Uplift Scope []
Uplifting [Point] best 33 combination
Uplifting [main] best 33 combination
Uplifting [] best 33 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Minimal struct with MemberUnwind behavior - simple members and local initializer
// Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
.label SCREEN = $400
// @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: {
.const point1_x = 2
.const point1_y = 3
// [4] *((const byte*) SCREEN) ← (const byte) main::point1_x -- _deref_pbuc1=vbuc2
lda #point1_x
sta SCREEN
// [5] *((const byte*) SCREEN+(byte) 1) ← (const byte) main::point1_y -- _deref_pbuc1=vbuc2
lda #point1_y
sta SCREEN+1
jmp __breturn
// main::@return
__breturn:
// [6] return
rts
}
// File Data
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
Removing instruction jmp __bend
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Replacing label __bbegin with __b1
Removing instruction __bbegin:
Removing instruction __b1_from___bbegin:
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 __b1:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(label) @1
(label) @begin
(label) @end
(byte) Point::x
(byte) Point::y
(const byte*) SCREEN = (byte*) 1024
(void()) main()
(label) main::@return
(const byte) main::point1_x = (byte) 2
(const byte) main::point1_y = (byte) 3
FINAL ASSEMBLER
Score: 18
// File Comments
// Minimal struct with MemberUnwind behavior - simple members and local initializer
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.label SCREEN = $400
// @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: {
.const point1_x = 2
.const point1_y = 3
// SCREEN[0] = point1.x
// [4] *((const byte*) SCREEN) ← (const byte) main::point1_x -- _deref_pbuc1=vbuc2
lda #point1_x
sta SCREEN
// SCREEN[1] = point1.y
// [5] *((const byte*) SCREEN+(byte) 1) ← (const byte) main::point1_y -- _deref_pbuc1=vbuc2
lda #point1_y
sta SCREEN+1
// main::@return
// }
// [6] return
rts
}
// File Data

View File

@ -0,0 +1,11 @@
(label) @1
(label) @begin
(label) @end
(byte) Point::x
(byte) Point::y
(const byte*) SCREEN = (byte*) 1024
(void()) main()
(label) main::@return
(const byte) main::point1_x = (byte) 2
(const byte) main::point1_y = (byte) 3