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:
parent
6a9f59cda1
commit
4eaa0c5385
@ -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);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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!");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
|
|
||||||
|
}
|
@ -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!");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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!");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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!");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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
16
src/test/kc/struct-30.kc
Normal 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
15
src/test/kc/struct-31.kc
Normal 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;
|
||||||
|
}
|
@ -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
|
||||||
|
@ -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'
|
||||||
|
@ -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'
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
24
src/test/ref/struct-30.asm
Normal file
24
src/test/ref/struct-30.asm
Normal 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
|
20
src/test/ref/struct-30.cfg
Normal file
20
src/test/ref/struct-30.cfg
Normal 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
324
src/test/ref/struct-30.log
Normal 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
|
||||||
|
|
12
src/test/ref/struct-30.sym
Normal file
12
src/test/ref/struct-30.sym
Normal 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
|
||||||
|
|
14
src/test/ref/struct-31.asm
Normal file
14
src/test/ref/struct-31.asm
Normal 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
|
||||||
|
}
|
18
src/test/ref/struct-31.cfg
Normal file
18
src/test/ref/struct-31.cfg
Normal 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
264
src/test/ref/struct-31.log
Normal 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
|
||||||
|
|
11
src/test/ref/struct-31.sym
Normal file
11
src/test/ref/struct-31.sym
Normal 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
|
||||||
|
|
Loading…
Reference in New Issue
Block a user