diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass1UnwindStructValues.java b/src/main/java/dk/camelot64/kickc/passes/Pass1UnwindStructValues.java index d55fc3c9f..4309dab24 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass1UnwindStructValues.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass1UnwindStructValues.java @@ -199,6 +199,7 @@ public class Pass1UnwindStructValues extends Pass1Base { LValue lValue = assignment.getlValue(); SymbolType lValueType = SymbolTypeInference.inferType(getScope(), lValue); if(lValueType instanceof SymbolTypeStruct && assignment.getOperator() == null) { + // Assignment to a struct SymbolTypeStruct lValueStructType = (SymbolTypeStruct) lValueType; RValue rValue = assignment.getrValue2(); @@ -209,6 +210,19 @@ public class Pass1UnwindStructValues extends Pass1Base { if(assignment.getrValue2() instanceof MemcpyValue || assignment.getrValue2() instanceof MemsetValue) return false; + ValueSource lValueSource = getValueSource(lValue, assignment, stmtIt, currentBlock); + ValueSource rValueSource = getValueSource(rValue, assignment, stmtIt, currentBlock); + List lValueUnwoundList = new ArrayList<>(); + if(copyValues(lValueSource, rValueSource, lValueUnwoundList, initialAssignment, assignment, currentBlock, stmtIt)) { + if(lValue instanceof VariableRef) { + StructUnwoundPlaceholder unwoundPlaceholder = new StructUnwoundPlaceholder(lValueStructType, lValueUnwoundList); + assignment.setrValue2(unwoundPlaceholder); + } else { + stmtIt.remove(); + } + return true; + } + // Check for bulk assignable values if(isBulkAssignable(lValue) && isBulkAssignable(rValue)) { RValueUnwinding lValueUnwinding = getValueUnwinding(lValue, assignment, stmtIt, currentBlock); @@ -253,6 +267,67 @@ public class Pass1UnwindStructValues extends Pass1Base { return false; } + private boolean copyValues(ValueSource lValueSource, ValueSource rValueSource, List lValueUnwoundList, boolean initialAssignment, Statement currentStmt, ControlFlowBlock currentBlock, ListIterator stmtIt) { + if(lValueSource==null || rValueSource==null) + return false; + if(lValueSource.isSimple() && rValueSource.isSimple()) { + stmtIt.previous(); + LValue lValueRef = (LValue) lValueSource.getSimpleValue(getScope()); + RValue rValueRef = rValueSource.getSimpleValue(getScope()); + if(lValueUnwoundList != null) + lValueUnwoundList.add(lValueRef); + Statement copyStmt = new StatementAssignment(lValueRef, rValueRef, initialAssignment, currentStmt.getSource(), Comment.NO_COMMENTS); + stmtIt.add(copyStmt); + stmtIt.next(); + getLog().append("Adding value simple copy " + copyStmt.toString(getProgram(), false)); + return true; + } else if(lValueSource.isBulkCopyable() && rValueSource.isBulkCopyable()) { + // Use bulk unwinding for a struct member that is an array + stmtIt.previous(); + if(lValueSource.getArraySpec() != null) + if(rValueSource.getArraySpec() == null || !lValueSource.getArraySpec().equals(rValueSource.getArraySpec())) + throw new RuntimeException("ArraySpec mismatch!"); + LValue lValueMemberVarRef = lValueSource.getBulkLValue(getScope()); + RValue rValueBulkUnwinding = rValueSource.getBulkRValue(getScope()); + if(lValueUnwoundList != null) + lValueUnwoundList.add(lValueMemberVarRef); + Statement copyStmt = new StatementAssignment(lValueMemberVarRef, rValueBulkUnwinding, initialAssignment, currentStmt.getSource(), Comment.NO_COMMENTS); + stmtIt.add(copyStmt); + stmtIt.next(); + getLog().append("Adding value bulk copy " + copyStmt.toString(getProgram(), false)); + return true; + } else if(lValueSource.isUnwindable() && rValueSource.isUnwindable()) { + getLog().append("Unwinding value copy " + currentStmt.toString(getProgram(), false)); + for(String memberName : lValueSource.getMemberNames(getScope())) { + ValueSource lValueSubSource = lValueSource.getMemberUnwinding(memberName, getScope(), currentStmt, currentBlock, stmtIt); + ValueSource rValueSubSource = rValueSource.getMemberUnwinding(memberName, getScope(), currentStmt, currentBlock, stmtIt); + boolean success = copyValues(lValueSubSource, rValueSubSource, lValueUnwoundList, initialAssignment, currentStmt, currentBlock, stmtIt); + if(!success) + throw new InternalError("Error during value unwinding copy! ", currentStmt); + } + return true; + } + return false; + } + + /** + * Get a value source for copying a value + * @param value The value being copied + * @param currentStmt The current statement + * @param stmtIt The statement iterator + * @param currentBlock The current block + * @return The vaule source for copying. null if no value source can be created. + */ + private ValueSource getValueSource(Value value, Statement currentStmt, ListIterator stmtIt, ControlFlowBlock currentBlock) { + if(value instanceof VariableRef) { + Variable variable = getScope().getVariable((VariableRef) value); + if(variable.isStructClassic()) { + return new ValueSourceStructVariable(variable); + } + } + return null; + } + /** * Unwind assignment from an RValue to an LValue * diff --git a/src/main/java/dk/camelot64/kickc/passes/unwinding/ValueSource.java b/src/main/java/dk/camelot64/kickc/passes/unwinding/ValueSource.java new file mode 100644 index 000000000..c8bb5e233 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/passes/unwinding/ValueSource.java @@ -0,0 +1,91 @@ +package dk.camelot64.kickc.passes.unwinding; + +import dk.camelot64.kickc.model.ControlFlowBlock; +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.types.SymbolType; +import dk.camelot64.kickc.model.values.LValue; +import dk.camelot64.kickc.model.values.RValue; + +import java.util.List; +import java.util.ListIterator; + +/** + * A value that is either the source or destination of a copy operation. + * Handles unwinding of struct copying when needed. Supports bulk copying. + */ +public interface ValueSource { + + /** + * Determine if the value can be simple copied + * @return true if the value is a simple value (not an array or a struct value + */ + boolean isSimple(); + + /** + * Determine if the value can be bulk memory copied + * @return true if the value can be bulk memory copied (from or to). + */ + boolean isBulkCopyable(); + + /** + * Determine if the value can be unwound to sub-values + * @return true if the value is a struct value + */ + boolean isUnwindable(); + + /** + * 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 simple value to use when performing a simple copy + * + * @param programScope The program scope + * @return The unwinding of the member + */ + RValue getSimpleValue(ProgramScope programScope); + + /** + * 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 command. + * @param scope The program scope + * @return The value to use as RValue + */ + RValue getBulkRValue(ProgramScope scope); + + /** + * Get the names of the members of the struct (if the value is an unwindable struct) + * + * @return the names + */ + List getMemberNames(ProgramScope scope); + + /** + * Get a sub value source for one member to use for copying that member. + * + * @param memberName The member name + * @param programScope The program scope + * @param currentStmt + * @param currentBlock + * @param stmtIt + * @return The unwinding of the member + */ + ValueSource getMemberUnwinding(String memberName, ProgramScope programScope, Statement currentStmt, ControlFlowBlock currentBlock, ListIterator stmtIt); + +} diff --git a/src/main/java/dk/camelot64/kickc/passes/unwinding/ValueSourcePointerDereferenceSimple.java b/src/main/java/dk/camelot64/kickc/passes/unwinding/ValueSourcePointerDereferenceSimple.java new file mode 100644 index 000000000..e3591b29f --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/passes/unwinding/ValueSourcePointerDereferenceSimple.java @@ -0,0 +1,135 @@ +package dk.camelot64.kickc.passes.unwinding; + +import dk.camelot64.kickc.model.ControlFlowBlock; +import dk.camelot64.kickc.model.operators.OperatorSizeOf; +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.types.SymbolTypeStruct; +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; + +/** Value Source for a pointer dereference. */ +public class ValueSourcePointerDereferenceSimple implements ValueSource { + + /** The pointer dereference. */ + private final PointerDereferenceSimple pointerDereference; + /** The type of the value. */ + private SymbolType valueType; + /** The array spec of the value. */ + private final ArraySpec valueArraySpec; + + public ValueSourcePointerDereferenceSimple(PointerDereferenceSimple pointerDereference, SymbolType valueType, ArraySpec valueArraySpec) { + this.pointerDereference = pointerDereference; + this.valueType = valueType; + this.valueArraySpec = valueArraySpec; + } + + @Override + public SymbolType getSymbolType() { + return valueType; + } + + @Override + public ArraySpec getArraySpec() { + return valueArraySpec; + } + + @Override + public boolean isSimple() { + return getArraySpec() == null && !(getSymbolType() instanceof SymbolTypeStruct); + } + + @Override + public RValue getSimpleValue(ProgramScope programScope) { + if(getArraySpec() != null) { + // For arrays return the pointer to the array - not the deref + return pointerDereference.getPointer(); + } else { + return pointerDereference; + } + } + + @Override + public boolean isBulkCopyable() { + return getArraySpec() != null || getSymbolType() instanceof SymbolTypeStruct; + } + + @Override + public LValue getBulkLValue(ProgramScope scope) { + RValue memberArrayPointer = pointerDereference.getPointer(); + return new PointerDereferenceSimple(memberArrayPointer); + } + + private ConstantValue getByteSize(ProgramScope scope) { + return getArraySpec() != null ? getArraySpec().getArraySize() : OperatorSizeOf.getSizeOfConstantVar(scope, getSymbolType()); + } + + @Override + public RValue getBulkRValue(ProgramScope scope) { + RValue memberArrayPointer = pointerDereference.getPointer(); + return new MemcpyValue(new PointerDereferenceSimple(memberArrayPointer), getByteSize(scope), getSymbolType()); + } + + @Override + public boolean isUnwindable() { + return getSymbolType() instanceof SymbolTypeStruct; + } + + @Override + public List getMemberNames(ProgramScope scope) { + if(getSymbolType() instanceof SymbolTypeStruct) { + StructDefinition structDefinition = ((SymbolTypeStruct) getSymbolType()).getStructDefinition(scope); + Collection structMemberVars = structDefinition.getAllVars(false); + ArrayList memberNames = new ArrayList<>(); + for(Variable structMemberVar : structMemberVars) { + memberNames.add(structMemberVar.getLocalName()); + } + return memberNames; + } else { + return null; + } + } + + @Override + public ValueSource getMemberUnwinding(String memberName, ProgramScope programScope, Statement currentStmt, ControlFlowBlock currentBlock, ListIterator stmtIt) { + if(getSymbolType() instanceof SymbolTypeStruct) { + StructDefinition structDefinition = ((SymbolTypeStruct) getSymbolType()).getStructDefinition(programScope); + final SymbolType memberType = structDefinition.getMember(memberName).getType(); + final ArraySpec memberArraySpec = structDefinition.getMember(memberName).getArraySpec(); + ConstantRef memberOffsetConstant = PassNStructPointerRewriting.getMemberOffsetConstant(programScope, structDefinition, memberName); + // Simple member value - unwind to value of member *((type*)&struct + OFFSET_MEMBER) + final RValue structPointer = pointerDereference.getPointer(); + if(structPointer instanceof ConstantValue) { + // Pointer to member type + ConstantCastValue structTypedPointer = new ConstantCastValue(new SymbolTypePointer(memberType), (ConstantValue) structPointer); + // Calculate member address (type*)&struct + OFFSET_MEMBER + ConstantBinary memberPointer = new ConstantBinary(structTypedPointer, Operators.PLUS, memberOffsetConstant); + // Unwind to *((type*)&struct + OFFSET_MEMBER) + PointerDereferenceSimple memberDeref = new PointerDereferenceSimple(memberPointer); + return new ValueSourcePointerDereferenceSimple(memberDeref, memberType, memberArraySpec); + } else { + Scope scope = programScope.getScope(currentBlock.getScope()); + Variable memberAddress = scope.addVariableIntermediate(); + memberAddress.setType(new SymbolTypePointer(memberType)); + CastValue structTypedPointer = new CastValue(new SymbolTypePointer(memberType), structPointer); + // Add statement $1 = (memberType*)ptr_struct + OFFSET_MEMBER + stmtIt.add(new StatementAssignment((LValue) memberAddress.getRef(), structTypedPointer, Operators.PLUS, memberOffsetConstant, true, currentStmt.getSource(), currentStmt.getComments())); + // Unwind to *((memberType*)ptr_struct+OFFSET_MEMBER) + PointerDereferenceSimple memberDeref = new PointerDereferenceSimple(memberAddress.getRef()); + return new ValueSourcePointerDereferenceSimple(memberDeref, memberType, memberArraySpec); + } + } else { + return null; + } + } +} + diff --git a/src/main/java/dk/camelot64/kickc/passes/unwinding/ValueSourceStructVariable.java b/src/main/java/dk/camelot64/kickc/passes/unwinding/ValueSourceStructVariable.java new file mode 100644 index 000000000..a2885287b --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/passes/unwinding/ValueSourceStructVariable.java @@ -0,0 +1,115 @@ +package dk.camelot64.kickc.passes.unwinding; + +import dk.camelot64.kickc.model.ControlFlowBlock; +import dk.camelot64.kickc.model.operators.OperatorSizeOf; +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.types.SymbolTypeStruct; +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; + +/** Value Source for a variable */ +public class ValueSourceStructVariable implements ValueSource { + + /** The variable. */ + private final Variable variable; + + public ValueSourceStructVariable(Variable variable) { + this.variable = variable; + } + + @Override + public SymbolType getSymbolType() { + return variable.getType(); + } + + @Override + public ArraySpec getArraySpec() { + return variable.getArraySpec(); + } + + @Override + public boolean isSimple() { + return getArraySpec() == null && !(getSymbolType() instanceof SymbolTypeStruct); + } + + @Override + public RValue getSimpleValue(ProgramScope programScope) { + return new ConstantSymbolPointer(variable.getRef()); + } + + @Override + public boolean isBulkCopyable() { + return getArraySpec() != null || variable.isStructClassic(); + } + + @Override + public LValue getBulkLValue(ProgramScope scope) { + ConstantSymbolPointer pointer = new ConstantSymbolPointer(variable.getRef()); + return new PointerDereferenceSimple(pointer); + } + + private ConstantValue getByteSize(ProgramScope scope) { + return getArraySpec() != null ? getArraySpec().getArraySize() : OperatorSizeOf.getSizeOfConstantVar(scope, getSymbolType()); + } + + @Override + public RValue getBulkRValue(ProgramScope scope) { + ConstantSymbolPointer pointer = new ConstantSymbolPointer(variable.getRef()); + LValue pointerDeref = new PointerDereferenceSimple(pointer); + return new MemcpyValue(pointerDeref, getByteSize(scope), getSymbolType()); + } + + @Override + public boolean isUnwindable() { + return getSymbolType() instanceof SymbolTypeStruct; + } + + @Override + public List getMemberNames(ProgramScope scope) { + if(getSymbolType() instanceof SymbolTypeStruct) { + StructDefinition structDefinition = ((SymbolTypeStruct) getSymbolType()).getStructDefinition(scope); + Collection structMemberVars = structDefinition.getAllVars(false); + ArrayList memberNames = new ArrayList<>(); + for(Variable structMemberVar : structMemberVars) { + memberNames.add(structMemberVar.getLocalName()); + } + return memberNames; + } else { + return null; + } + } + + @Override + public ValueSource getMemberUnwinding(String memberName, ProgramScope programScope, Statement currentStmt, ControlFlowBlock currentBlock, ListIterator stmtIt) { + if(getSymbolType() instanceof SymbolTypeStruct) { + StructDefinition structDefinition = ((SymbolTypeStruct) getSymbolType()).getStructDefinition(programScope); + final SymbolType memberType = structDefinition.getMember(memberName).getType(); + final ArraySpec memberArraySpec = structDefinition.getMember(memberName).getArraySpec(); + ConstantRef memberOffsetConstant = PassNStructPointerRewriting.getMemberOffsetConstant(programScope, structDefinition, memberName); + // Simple member value - unwind to value of member *((type*)&struct + OFFSET_MEMBER) + ConstantSymbolPointer structPointer = new ConstantSymbolPointer(variable.getRef()); + // Pointer to member type + ConstantCastValue structTypedPointer = new ConstantCastValue(new SymbolTypePointer(memberType), structPointer); + // Calculate member address (type*)&struct + OFFSET_MEMBER + ConstantBinary memberPointer = new ConstantBinary(structTypedPointer, Operators.PLUS, memberOffsetConstant); + // Unwind to *((type*)&struct + OFFSET_MEMBER) + PointerDereferenceSimple memberDeref = new PointerDereferenceSimple(memberPointer); + return new ValueSourcePointerDereferenceSimple(memberDeref, memberType, memberArraySpec); + } else { + return null; + } + } + +} \ No newline at end of file diff --git a/src/test/ref/struct-15.log b/src/test/ref/struct-15.log index 608dbb11e..6912dde39 100644 --- a/src/test/ref/struct-15.log +++ b/src/test/ref/struct-15.log @@ -1,5 +1,5 @@ Adding struct value member variable copy *(&(struct Point) main::point1) ← memset(struct Point, (const byte) SIZEOF_STRUCT_POINT) -Adding struct value member variable copy *(&(struct Point) main::point2) ← memcpy(*(&(struct Point) main::point1), struct Point, (const byte) SIZEOF_STRUCT_POINT) +Adding value bulk copy *(&(struct Point) main::point2) ← memcpy(*(&(struct Point) main::point1), struct Point, (const byte) SIZEOF_STRUCT_POINT) Replacing struct member reference (struct Point) main::point1.x with member unwinding reference *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) Replacing struct member reference (struct Point) main::point1.y with member unwinding reference *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_Y) Replacing struct member reference (struct Point) main::point2.x with member unwinding reference *((byte*)&(struct Point) main::point2+(const byte) OFFSET_STRUCT_POINT_X) @@ -15,6 +15,7 @@ main: scope:[main] from @1 *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) ← (number) 2 *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_Y) ← (number) 3 *(&(struct Point) main::point2) ← memcpy(*(&(struct Point) main::point1), struct Point, (const byte) SIZEOF_STRUCT_POINT) + (struct Point) main::point2 ← struct-unwound {*(&(struct Point) main::point2)} *((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_Y) to:main::@return @@ -63,9 +64,10 @@ Finalized unsigned number type (byte) 3 Finalized unsigned number type (byte) 0 Finalized unsigned number type (byte) 1 Successful SSA optimization PassNFinalizeNumberTypeConversions +Removing C-classic struct-unwound assignment [4] (struct Point) main::point2 ← struct-unwound {*(&(struct Point) main::point2)} Simplifying expression containing zero (byte*)&main::point1 in [1] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) ← (byte) 2 -Simplifying expression containing zero (byte*)&main::point2 in [4] *((const byte*) SCREEN + (byte) 0) ← *((byte*)&(struct Point) main::point2+(const byte) OFFSET_STRUCT_POINT_X) -Simplifying expression containing zero SCREEN in [4] *((const byte*) SCREEN + (byte) 0) ← *((byte*)&(struct Point) main::point2) +Simplifying expression containing zero (byte*)&main::point2 in [5] *((const byte*) SCREEN + (byte) 0) ← *((byte*)&(struct Point) main::point2+(const byte) OFFSET_STRUCT_POINT_X) +Simplifying expression containing zero SCREEN in [5] *((const byte*) SCREEN + (byte) 0) ← *((byte*)&(struct Point) main::point2) Successful SSA optimization PassNSimplifyExpressionWithZero Eliminating unused constant (const byte) OFFSET_STRUCT_POINT_X Successful SSA optimization PassNEliminateUnusedVars diff --git a/src/test/ref/struct-2.log b/src/test/ref/struct-2.log index 2b9a9d844..102850a34 100644 --- a/src/test/ref/struct-2.log +++ b/src/test/ref/struct-2.log @@ -1,4 +1,4 @@ -Adding struct value member variable copy *(&(struct Point) point2) ← memcpy(*(&(struct Point) point1), struct Point, (const byte) SIZEOF_STRUCT_POINT) +Adding value bulk copy *(&(struct Point) point2) ← memcpy(*(&(struct Point) point1), struct Point, (const byte) SIZEOF_STRUCT_POINT) Replacing struct member reference (struct Point) point1.x with member unwinding reference *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_X) Replacing struct member reference (struct Point) point1.y with member unwinding reference *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_Y) Replacing struct member reference (struct Point) point2.x with member unwinding reference *((byte*)&(struct Point) point2+(const byte) OFFSET_STRUCT_POINT_X) @@ -16,6 +16,7 @@ main: scope:[main] from @1 *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_X) ← (number) 2 *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_Y) ← (number) 3 *(&(struct Point) point2) ← memcpy(*(&(struct Point) point1), struct Point, (const byte) SIZEOF_STRUCT_POINT) + (struct Point) point2 ← struct-unwound {*(&(struct Point) point2)} *((byte*)&(struct Point) point2+(const byte) OFFSET_STRUCT_POINT_X) ← (number) 4 *((const byte*) main::SCREEN + (number) 0) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_X) *((const byte*) main::SCREEN + (number) 1) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_Y) @@ -77,11 +78,12 @@ Finalized unsigned number type (byte) 1 Finalized unsigned number type (byte) 2 Finalized unsigned number type (byte) 3 Successful SSA optimization PassNFinalizeNumberTypeConversions +Removing C-classic struct-unwound assignment [3] (struct Point) point2 ← struct-unwound {*(&(struct Point) point2)} 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*)&point2 in [3] *((byte*)&(struct Point) point2+(const byte) OFFSET_STRUCT_POINT_X) ← (byte) 4 -Simplifying expression containing zero (byte*)&point1 in [4] *((const byte*) main::SCREEN + (byte) 0) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_X) -Simplifying expression containing zero main::SCREEN in [4] *((const byte*) main::SCREEN + (byte) 0) ← *((byte*)&(struct Point) point1) -Simplifying expression containing zero (byte*)&point2 in [6] *((const byte*) main::SCREEN + (byte) 2) ← *((byte*)&(struct Point) point2+(const byte) OFFSET_STRUCT_POINT_X) +Simplifying expression containing zero (byte*)&point2 in [4] *((byte*)&(struct Point) point2+(const byte) OFFSET_STRUCT_POINT_X) ← (byte) 4 +Simplifying expression containing zero (byte*)&point1 in [5] *((const byte*) main::SCREEN + (byte) 0) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_X) +Simplifying expression containing zero main::SCREEN in [5] *((const byte*) main::SCREEN + (byte) 0) ← *((byte*)&(struct Point) point1) +Simplifying expression containing zero (byte*)&point2 in [7] *((const byte*) main::SCREEN + (byte) 2) ← *((byte*)&(struct Point) point2+(const byte) OFFSET_STRUCT_POINT_X) Successful SSA optimization PassNSimplifyExpressionWithZero Eliminating unused constant (const byte) OFFSET_STRUCT_POINT_X Successful SSA optimization PassNEliminateUnusedVars diff --git a/src/test/ref/struct-26.log b/src/test/ref/struct-26.log index ec1655697..d23c13f04 100644 --- a/src/test/ref/struct-26.log +++ b/src/test/ref/struct-26.log @@ -3,7 +3,7 @@ Fixing struct type size struct Point to 3 Fixing struct type SIZE_OF struct Point to 3 Fixing struct type SIZE_OF struct Point to 3 Adding struct value member variable copy *(&(struct Point) main::point1) ← memset(struct Point, (const byte) SIZEOF_STRUCT_POINT) -Adding struct value member variable copy *(&(struct Point) main::point2) ← memcpy(*(&(struct Point) main::point1), struct Point, (const byte) SIZEOF_STRUCT_POINT) +Adding value bulk copy *(&(struct Point) main::point2) ← memcpy(*(&(struct Point) main::point1), struct Point, (const byte) SIZEOF_STRUCT_POINT) Replacing struct member reference (struct Point) main::point1.x with member unwinding reference *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) Replacing struct member reference (struct Point) main::point1.initials with member unwinding reference (byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS Replacing struct member reference (struct Point) main::point1.initials with member unwinding reference (byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS @@ -22,6 +22,7 @@ main: scope:[main] from @1 *((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' *(&(struct Point) main::point2) ← memcpy(*(&(struct Point) main::point1), struct Point, (const byte) SIZEOF_STRUCT_POINT) + (struct Point) main::point2 ← struct-unwound {*(&(struct Point) main::point2)} *((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) 2) ← *((byte*)&(struct Point) main::point2+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 1) @@ -82,11 +83,12 @@ Finalized unsigned number type (byte) 1 Finalized unsigned number type (byte) 1 Finalized unsigned number type (byte) 2 Successful SSA optimization PassNFinalizeNumberTypeConversions +Removing C-classic struct-unwound assignment [5] (struct Point) main::point2 ← struct-unwound {*(&(struct Point) main::point2)} Simplifying expression containing zero (byte*)&main::point1 in [1] *((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 [2] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (byte) 0) ← (byte) 'j' -Simplifying expression containing zero (byte*)&main::point2 in [5] *((const byte*) SCREEN + (byte) 0) ← *((byte*)&(struct Point) main::point2+(const byte) OFFSET_STRUCT_POINT_X) -Simplifying expression containing zero SCREEN in [5] *((const byte*) SCREEN + (byte) 0) ← *((byte*)&(struct Point) main::point2) -Simplifying expression containing zero (byte*)&main::point2+OFFSET_STRUCT_POINT_INITIALS in [6] *((const byte*) SCREEN + (byte) 1) ← *((byte*)&(struct Point) main::point2+(const byte) OFFSET_STRUCT_POINT_INITIALS + (byte) 0) +Simplifying expression containing zero (byte*)&main::point2 in [6] *((const byte*) SCREEN + (byte) 0) ← *((byte*)&(struct Point) main::point2+(const byte) OFFSET_STRUCT_POINT_X) +Simplifying expression containing zero SCREEN in [6] *((const byte*) SCREEN + (byte) 0) ← *((byte*)&(struct Point) main::point2) +Simplifying expression containing zero (byte*)&main::point2+OFFSET_STRUCT_POINT_INITIALS in [7] *((const byte*) SCREEN + (byte) 1) ← *((byte*)&(struct Point) main::point2+(const byte) OFFSET_STRUCT_POINT_INITIALS + (byte) 0) Successful SSA optimization PassNSimplifyExpressionWithZero Eliminating unused constant (const byte) OFFSET_STRUCT_POINT_X Successful SSA optimization PassNEliminateUnusedVars diff --git a/src/test/ref/struct-32.log b/src/test/ref/struct-32.log index bdb4a8b16..7bbd8b37e 100644 --- a/src/test/ref/struct-32.log +++ b/src/test/ref/struct-32.log @@ -1,5 +1,5 @@ Adding struct value member variable copy *(&(struct Point) main::point1) ← memset(struct Point, (const byte) SIZEOF_STRUCT_POINT) -Adding struct value member variable copy *(&(struct Point) main::point2) ← memcpy(*(&(struct Point) main::point1), struct Point, (const byte) SIZEOF_STRUCT_POINT) +Adding value bulk copy *(&(struct Point) main::point2) ← memcpy(*(&(struct Point) main::point1), struct Point, (const byte) SIZEOF_STRUCT_POINT) Replacing struct member reference (struct Point) main::point1.x with member unwinding reference *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) Replacing struct member reference (struct Point) main::point1.y with member unwinding reference *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_Y) Replacing struct member reference (struct Point) main::point2.x with member unwinding reference *((byte*)&(struct Point) main::point2+(const byte) OFFSET_STRUCT_POINT_X) @@ -15,6 +15,7 @@ main: scope:[main] from @1 *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) ← (number) 2 *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_Y) ← (number) 3 *(&(struct Point) main::point2) ← memcpy(*(&(struct Point) main::point1), struct Point, (const byte) SIZEOF_STRUCT_POINT) + (struct Point) main::point2 ← struct-unwound {*(&(struct Point) main::point2)} *((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_Y) to:main::@return @@ -63,9 +64,10 @@ Finalized unsigned number type (byte) 3 Finalized unsigned number type (byte) 0 Finalized unsigned number type (byte) 1 Successful SSA optimization PassNFinalizeNumberTypeConversions +Removing C-classic struct-unwound assignment [4] (struct Point) main::point2 ← struct-unwound {*(&(struct Point) main::point2)} Simplifying expression containing zero (byte*)&main::point1 in [1] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_X) ← (byte) 2 -Simplifying expression containing zero (byte*)&main::point2 in [4] *((const byte*) SCREEN + (byte) 0) ← *((byte*)&(struct Point) main::point2+(const byte) OFFSET_STRUCT_POINT_X) -Simplifying expression containing zero SCREEN in [4] *((const byte*) SCREEN + (byte) 0) ← *((byte*)&(struct Point) main::point2) +Simplifying expression containing zero (byte*)&main::point2 in [5] *((const byte*) SCREEN + (byte) 0) ← *((byte*)&(struct Point) main::point2+(const byte) OFFSET_STRUCT_POINT_X) +Simplifying expression containing zero SCREEN in [5] *((const byte*) SCREEN + (byte) 0) ← *((byte*)&(struct Point) main::point2) Successful SSA optimization PassNSimplifyExpressionWithZero Eliminating unused constant (const byte) OFFSET_STRUCT_POINT_X Successful SSA optimization PassNEliminateUnusedVars diff --git a/src/test/ref/struct-41.log b/src/test/ref/struct-41.log index 042fc5169..60f711135 100644 --- a/src/test/ref/struct-41.log +++ b/src/test/ref/struct-41.log @@ -22,7 +22,7 @@ Adding struct value member variable copy *((struct Point*)&(struct Vector) main: Adding struct value member variable copy *((struct Point*)&(struct Vector) main::v2+(const byte) OFFSET_STRUCT_VECTOR_Q) ← (struct Point) main::v1_q Adding struct value member variable copy *((struct Point*)&(struct Vector) main::v3+(const byte) OFFSET_STRUCT_VECTOR_P) ← (struct Vector) main::v2.p Adding struct value member variable copy *((struct Point*)&(struct Vector) main::v3+(const byte) OFFSET_STRUCT_VECTOR_Q) ← { x: (byte) 6, y: (byte) 7 } -Adding struct value member variable copy *(&(struct Vector) main::v4) ← memcpy(*(&(struct Vector) main::v3), struct Vector, (const byte) SIZEOF_STRUCT_VECTOR) +Adding value bulk copy *(&(struct Vector) main::v4) ← memcpy(*(&(struct Vector) main::v3), struct Vector, (const byte) SIZEOF_STRUCT_VECTOR) Adding struct value member variable copy (struct Point) main::v5_p ← (struct Point){ (struct Vector) main::v4.p.x, (struct Vector) main::v4.p.y } Adding struct value member variable copy (struct Point) main::v5_q ← { x: (byte) 8, y: (byte) 9 } Replacing struct member reference (struct Vector) main::v2.p with member unwinding reference *((struct Point*)&(struct Vector) main::v2+(const byte) OFFSET_STRUCT_VECTOR_P) @@ -111,6 +111,7 @@ main: scope:[main] from @1 *((struct Point*)&(struct Vector) main::v3+(const byte) OFFSET_STRUCT_VECTOR_Q) ← memcpy(*(&(const struct Point) $0), struct Point, (const byte) SIZEOF_STRUCT_POINT) (struct Vector) main::v3 ← struct-unwound {*((struct Point*)&(struct Vector) main::v3+(const byte) OFFSET_STRUCT_VECTOR_P), *((struct Point*)&(struct Vector) main::v3+(const byte) OFFSET_STRUCT_VECTOR_Q)} *(&(struct Vector) main::v4) ← memcpy(*(&(struct Vector) main::v3), struct Vector, (const byte) SIZEOF_STRUCT_VECTOR) + (struct Vector) main::v4 ← struct-unwound {*(&(struct Vector) main::v4)} (byte*~) main::$4 ← (byte*)(struct Point*)&(struct Vector) main::v4+(const byte) OFFSET_STRUCT_VECTOR_P + (const byte) OFFSET_STRUCT_POINT_X (byte) main::v5_p_x#0 ← *((byte*~) main::$4) (byte*~) main::$5 ← (byte*)(struct Point*)&(struct Vector) main::v4+(const byte) OFFSET_STRUCT_VECTOR_P + (const byte) OFFSET_STRUCT_POINT_Y @@ -255,24 +256,25 @@ Simplifying constant pointer cast (byte*) 1024 Successful SSA optimization PassNCastSimplification Removing C-classic struct-unwound assignment [9] (struct Vector) main::v2 ← struct-unwound {*((struct Point*)&(struct Vector) main::v2+(const byte) OFFSET_STRUCT_VECTOR_P), *((struct Point*)&(struct Vector) main::v2+(const byte) OFFSET_STRUCT_VECTOR_Q)} Removing C-classic struct-unwound assignment [12] (struct Vector) main::v3 ← struct-unwound {*((struct Point*)&(struct Vector) main::v3+(const byte) OFFSET_STRUCT_VECTOR_P), *((struct Point*)&(struct Vector) main::v3+(const byte) OFFSET_STRUCT_VECTOR_Q)} +Removing C-classic struct-unwound assignment [14] (struct Vector) main::v4 ← struct-unwound {*(&(struct Vector) main::v4)} Constant right-side identified [1] (byte*~) main::$0 ← (byte*)(struct Point*)&(struct Vector) main::v2+(const byte) OFFSET_STRUCT_VECTOR_P + (const byte) OFFSET_STRUCT_POINT_X Constant right-side identified [3] (byte*~) main::$1 ← (byte*)(struct Point*)&(struct Vector) main::v2+(const byte) OFFSET_STRUCT_VECTOR_P + (const byte) OFFSET_STRUCT_POINT_Y Constant right-side identified [5] (byte*~) main::$2 ← (byte*)(struct Point*)&(struct Vector) main::v2+(const byte) OFFSET_STRUCT_VECTOR_Q + (const byte) OFFSET_STRUCT_POINT_X Constant right-side identified [7] (byte*~) main::$3 ← (byte*)(struct Point*)&(struct Vector) main::v2+(const byte) OFFSET_STRUCT_VECTOR_Q + (const byte) OFFSET_STRUCT_POINT_Y -Constant right-side identified [14] (byte*~) main::$4 ← (byte*)(struct Point*)&(struct Vector) main::v4+(const byte) OFFSET_STRUCT_VECTOR_P + (const byte) OFFSET_STRUCT_POINT_X -Constant right-side identified [16] (byte*~) main::$5 ← (byte*)(struct Point*)&(struct Vector) main::v4+(const byte) OFFSET_STRUCT_VECTOR_P + (const byte) OFFSET_STRUCT_POINT_Y -Constant right-side identified [26] (byte*~) main::$6 ← (byte*)(struct Point*)&(struct Vector) main::v2+(const byte) OFFSET_STRUCT_VECTOR_P + (const byte) OFFSET_STRUCT_POINT_X -Constant right-side identified [29] (byte*~) main::$7 ← (byte*)(struct Point*)&(struct Vector) main::v2+(const byte) OFFSET_STRUCT_VECTOR_P + (const byte) OFFSET_STRUCT_POINT_Y -Constant right-side identified [32] (byte*~) main::$8 ← (byte*)(struct Point*)&(struct Vector) main::v2+(const byte) OFFSET_STRUCT_VECTOR_Q + (const byte) OFFSET_STRUCT_POINT_X -Constant right-side identified [35] (byte*~) main::$9 ← (byte*)(struct Point*)&(struct Vector) main::v2+(const byte) OFFSET_STRUCT_VECTOR_Q + (const byte) OFFSET_STRUCT_POINT_Y -Constant right-side identified [38] (byte*~) main::$10 ← (byte*)(struct Point*)&(struct Vector) main::v3+(const byte) OFFSET_STRUCT_VECTOR_P + (const byte) OFFSET_STRUCT_POINT_X -Constant right-side identified [41] (byte*~) main::$11 ← (byte*)(struct Point*)&(struct Vector) main::v3+(const byte) OFFSET_STRUCT_VECTOR_P + (const byte) OFFSET_STRUCT_POINT_Y -Constant right-side identified [44] (byte*~) main::$12 ← (byte*)(struct Point*)&(struct Vector) main::v3+(const byte) OFFSET_STRUCT_VECTOR_Q + (const byte) OFFSET_STRUCT_POINT_X -Constant right-side identified [47] (byte*~) main::$13 ← (byte*)(struct Point*)&(struct Vector) main::v3+(const byte) OFFSET_STRUCT_VECTOR_Q + (const byte) OFFSET_STRUCT_POINT_Y -Constant right-side identified [50] (byte*~) main::$14 ← (byte*)(struct Point*)&(struct Vector) main::v4+(const byte) OFFSET_STRUCT_VECTOR_P + (const byte) OFFSET_STRUCT_POINT_X -Constant right-side identified [53] (byte*~) main::$15 ← (byte*)(struct Point*)&(struct Vector) main::v4+(const byte) OFFSET_STRUCT_VECTOR_P + (const byte) OFFSET_STRUCT_POINT_Y -Constant right-side identified [56] (byte*~) main::$16 ← (byte*)(struct Point*)&(struct Vector) main::v4+(const byte) OFFSET_STRUCT_VECTOR_Q + (const byte) OFFSET_STRUCT_POINT_X -Constant right-side identified [59] (byte*~) main::$17 ← (byte*)(struct Point*)&(struct Vector) main::v4+(const byte) OFFSET_STRUCT_VECTOR_Q + (const byte) OFFSET_STRUCT_POINT_Y +Constant right-side identified [15] (byte*~) main::$4 ← (byte*)(struct Point*)&(struct Vector) main::v4+(const byte) OFFSET_STRUCT_VECTOR_P + (const byte) OFFSET_STRUCT_POINT_X +Constant right-side identified [17] (byte*~) main::$5 ← (byte*)(struct Point*)&(struct Vector) main::v4+(const byte) OFFSET_STRUCT_VECTOR_P + (const byte) OFFSET_STRUCT_POINT_Y +Constant right-side identified [27] (byte*~) main::$6 ← (byte*)(struct Point*)&(struct Vector) main::v2+(const byte) OFFSET_STRUCT_VECTOR_P + (const byte) OFFSET_STRUCT_POINT_X +Constant right-side identified [30] (byte*~) main::$7 ← (byte*)(struct Point*)&(struct Vector) main::v2+(const byte) OFFSET_STRUCT_VECTOR_P + (const byte) OFFSET_STRUCT_POINT_Y +Constant right-side identified [33] (byte*~) main::$8 ← (byte*)(struct Point*)&(struct Vector) main::v2+(const byte) OFFSET_STRUCT_VECTOR_Q + (const byte) OFFSET_STRUCT_POINT_X +Constant right-side identified [36] (byte*~) main::$9 ← (byte*)(struct Point*)&(struct Vector) main::v2+(const byte) OFFSET_STRUCT_VECTOR_Q + (const byte) OFFSET_STRUCT_POINT_Y +Constant right-side identified [39] (byte*~) main::$10 ← (byte*)(struct Point*)&(struct Vector) main::v3+(const byte) OFFSET_STRUCT_VECTOR_P + (const byte) OFFSET_STRUCT_POINT_X +Constant right-side identified [42] (byte*~) main::$11 ← (byte*)(struct Point*)&(struct Vector) main::v3+(const byte) OFFSET_STRUCT_VECTOR_P + (const byte) OFFSET_STRUCT_POINT_Y +Constant right-side identified [45] (byte*~) main::$12 ← (byte*)(struct Point*)&(struct Vector) main::v3+(const byte) OFFSET_STRUCT_VECTOR_Q + (const byte) OFFSET_STRUCT_POINT_X +Constant right-side identified [48] (byte*~) main::$13 ← (byte*)(struct Point*)&(struct Vector) main::v3+(const byte) OFFSET_STRUCT_VECTOR_Q + (const byte) OFFSET_STRUCT_POINT_Y +Constant right-side identified [51] (byte*~) main::$14 ← (byte*)(struct Point*)&(struct Vector) main::v4+(const byte) OFFSET_STRUCT_VECTOR_P + (const byte) OFFSET_STRUCT_POINT_X +Constant right-side identified [54] (byte*~) main::$15 ← (byte*)(struct Point*)&(struct Vector) main::v4+(const byte) OFFSET_STRUCT_VECTOR_P + (const byte) OFFSET_STRUCT_POINT_Y +Constant right-side identified [57] (byte*~) main::$16 ← (byte*)(struct Point*)&(struct Vector) main::v4+(const byte) OFFSET_STRUCT_VECTOR_Q + (const byte) OFFSET_STRUCT_POINT_X +Constant right-side identified [60] (byte*~) main::$17 ← (byte*)(struct Point*)&(struct Vector) main::v4+(const byte) OFFSET_STRUCT_VECTOR_Q + (const byte) OFFSET_STRUCT_POINT_Y Successful SSA optimization Pass2ConstantRValueConsolidation Constant (const byte) main::idx#0 = 0 Constant (const byte*) main::$0 = (byte*)(struct Point*)&main::v2+OFFSET_STRUCT_VECTOR_P+OFFSET_STRUCT_POINT_X @@ -315,7 +317,7 @@ Simplifying expression containing zero (struct Point*)&main::v4 in Simplifying expression containing zero (byte*)(struct Point*)&main::v4+OFFSET_STRUCT_VECTOR_Q in Simplifying expression containing zero (struct Point*)&main::v2 in [10] *((struct Point*)&(struct Vector) main::v3+(const byte) OFFSET_STRUCT_VECTOR_P) ← memcpy(*((struct Point*)&(struct Vector) main::v2+(const byte) OFFSET_STRUCT_VECTOR_P), struct Point, (const byte) SIZEOF_STRUCT_POINT) Simplifying expression containing zero (struct Point*)&main::v3 in [10] *((struct Point*)&(struct Vector) main::v3+(const byte) OFFSET_STRUCT_VECTOR_P) ← memcpy(*((struct Point*)&(struct Vector) main::v2), struct Point, (const byte) SIZEOF_STRUCT_POINT) -Simplifying expression containing zero SCREEN in [18] *((const byte*) SCREEN + (const byte) main::idx#0) ← (const byte) main::v1_p_x +Simplifying expression containing zero SCREEN in [19] *((const byte*) SCREEN + (const byte) main::idx#0) ← (const byte) main::v1_p_x Successful SSA optimization PassNSimplifyExpressionWithZero Eliminating unused variable (byte) main::idx#20 and assignment [48] (byte) main::idx#20 ← ++ (byte) main::idx#19 Eliminating unused constant (const byte) OFFSET_STRUCT_VECTOR_P