mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-04-09 21:37:31 +00:00
Implemented unwound struct address-of rewriting to use first member.
This commit is contained in:
parent
00c8d5c857
commit
afc1b74ef8
@ -274,6 +274,7 @@ public class Compiler {
|
||||
optimizations.add(new Pass2ConditionalAndOrRewriting(program));
|
||||
optimizations.add(new PassNAddBooleanCasts(program));
|
||||
optimizations.add(new PassNStructPointerRewriting(program));
|
||||
optimizations.add(new PassNStructAddressOfRewriting(program));
|
||||
optimizations.add(new Pass2ConditionalJumpSequenceImprovement(program));
|
||||
optimizations.add(new Pass2ConstantRValueConsolidation(program));
|
||||
optimizations.add(new Pass2ConstantIdentification(program));
|
||||
@ -387,7 +388,6 @@ public class Compiler {
|
||||
}
|
||||
|
||||
private void pass3Analysis() {
|
||||
new PassNEliminateStructUnwoundPlaceholder(program).step();
|
||||
new Pass3AssertNoTypeId(program).check();
|
||||
new Pass3AssertRValues(program).check();
|
||||
new Pass3AssertNoNumbers(program).check();
|
||||
|
@ -49,10 +49,12 @@ public class LiveRangeEquivalenceClass {
|
||||
}
|
||||
LiveRangeVariables liveRanges = set.getProgram().getLiveRangeVariables();
|
||||
LiveRange varLiveRange = liveRanges.getLiveRange(variable);
|
||||
if(liveRange.overlaps(varLiveRange)) {
|
||||
throw new RuntimeException("Compilation error! Variable live range overlaps live range equivalence class live range. " + variable);
|
||||
if(varLiveRange!=null) {
|
||||
if(liveRange.overlaps(varLiveRange)) {
|
||||
throw new RuntimeException("Compilation error! Variable live range overlaps live range equivalence class live range. " + variable);
|
||||
}
|
||||
liveRange.add(varLiveRange);
|
||||
}
|
||||
liveRange.add(varLiveRange);
|
||||
variables.add(variable);
|
||||
set.setVarClass(variable, this);
|
||||
}
|
||||
|
@ -770,6 +770,28 @@ public interface ProgramValue {
|
||||
|
||||
}
|
||||
|
||||
class ProgramValueStructUnwoundPlaceholderMember implements ProgramValue {
|
||||
private StructUnwoundPlaceholder placeholder;
|
||||
private int idx;
|
||||
|
||||
public ProgramValueStructUnwoundPlaceholderMember(StructUnwoundPlaceholder placeholder, int idx) {
|
||||
this.placeholder = placeholder;
|
||||
this.idx = idx;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value get() {
|
||||
return placeholder.getUnwoundMembers().get(idx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(Value value) {
|
||||
placeholder.getUnwoundMembers().set(idx, (RValue) value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pointer index inside a indexed pointer dererence value.
|
||||
*/
|
||||
|
@ -188,6 +188,11 @@ public class ProgramValueIterator {
|
||||
subValues.add(new ProgramValue.ProgramValuePointer((PointerDereference) value));
|
||||
} else if(value instanceof StructMemberRef) {
|
||||
subValues.add(new ProgramValue.ProgramValueStruct((StructMemberRef) value));
|
||||
} else if(value instanceof StructUnwoundPlaceholder) {
|
||||
int size = ((StructUnwoundPlaceholder) value).getUnwoundMembers().size();
|
||||
for(int i = 0; i < size; i++) {
|
||||
subValues.add(new ProgramValue.ProgramValueStructUnwoundPlaceholderMember((StructUnwoundPlaceholder) value, i));
|
||||
}
|
||||
} else if(value instanceof ValueList) {
|
||||
ValueList valueList = (ValueList) value;
|
||||
int size = valueList.getList().size();
|
||||
@ -226,7 +231,6 @@ public class ProgramValueIterator {
|
||||
value instanceof ConstantLiteral ||
|
||||
value instanceof ConstantRef ||
|
||||
value instanceof StructZero ||
|
||||
value instanceof StructUnwoundPlaceholder ||
|
||||
value instanceof LabelRef
|
||||
) {
|
||||
// No sub values
|
||||
|
@ -3,23 +3,45 @@ package dk.camelot64.kickc.model.values;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypeStruct;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/** Used as a placeholder value, where a struct has been unwound. */
|
||||
public class StructUnwoundPlaceholder implements RValue {
|
||||
|
||||
public StructUnwoundPlaceholder(SymbolTypeStruct typeStruct) {
|
||||
public StructUnwoundPlaceholder(SymbolTypeStruct typeStruct, List<RValue> unwoundMembers) {
|
||||
this.typeStruct = typeStruct;
|
||||
this.unwoundMembers = unwoundMembers;
|
||||
}
|
||||
|
||||
/** The type of the struct. */
|
||||
private SymbolTypeStruct typeStruct;
|
||||
|
||||
/** The unwound struct members. */
|
||||
private List<RValue> unwoundMembers;
|
||||
|
||||
public SymbolTypeStruct getTypeStruct() {
|
||||
return typeStruct;
|
||||
}
|
||||
|
||||
public List<RValue> getUnwoundMembers() {
|
||||
return unwoundMembers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(Program program) {
|
||||
return "struct-unwound";
|
||||
StringBuffer str = new StringBuffer();
|
||||
str.append("struct-unwound {");
|
||||
boolean first = true;
|
||||
for(RValue unwoundMember : unwoundMembers) {
|
||||
if(first) {
|
||||
first = false;
|
||||
} else {
|
||||
str.append(", ");
|
||||
}
|
||||
str.append(unwoundMember.toString(program));
|
||||
}
|
||||
str.append("}");
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -276,9 +276,11 @@ public class Pass1UnwindStructValues extends Pass1Base {
|
||||
|
||||
if(assignment.getOperator() == null && assignment.getrValue2() instanceof StructZero && assignment.getlValue() instanceof VariableRef) {
|
||||
// Zero-initializing a struct - unwind to assigning zero to each member!
|
||||
List<RValue> membersUnwound = new ArrayList<>();
|
||||
stmtIt.previous();
|
||||
for(String memberName : memberUnwinding.getMemberNames()) {
|
||||
VariableRef memberVarRef = (VariableRef) memberUnwinding.getMemberUnwinding(memberName);
|
||||
membersUnwound.add(memberVarRef);
|
||||
Variable memberVar = getScope().getVariable(memberVarRef);
|
||||
Statement initStmt = Pass0GenerateStatementSequence.createDefaultInitializationStatement(memberVarRef, memberVar.getType(), assignment.getSource(), Comment.NO_COMMENTS);
|
||||
stmtIt.add(initStmt);
|
||||
@ -286,7 +288,7 @@ public class Pass1UnwindStructValues extends Pass1Base {
|
||||
}
|
||||
stmtIt.next();
|
||||
if(assignment.getlValue() instanceof VariableRef) {
|
||||
assignment.setrValue2(new StructUnwoundPlaceholder(structType));
|
||||
assignment.setrValue2(new StructUnwoundPlaceholder(structType, membersUnwound));
|
||||
} else {
|
||||
stmtIt.remove();
|
||||
}
|
||||
@ -298,16 +300,18 @@ public class Pass1UnwindStructValues extends Pass1Base {
|
||||
throw new CompileError("Struct initialization list has wrong size. Need " + memberUnwinding.getMemberNames().size() + " got " + valueList.getList().size(), assignment);
|
||||
}
|
||||
stmtIt.previous();
|
||||
List<RValue> membersUnwound = new ArrayList<>();
|
||||
int idx = 0;
|
||||
for(String memberName : memberUnwinding.getMemberNames()) {
|
||||
LValue memberLvalue = memberUnwinding.getMemberUnwinding(memberName);
|
||||
membersUnwound.add(memberLvalue);
|
||||
Statement initStmt = new StatementAssignment(memberLvalue, valueList.getList().get(idx++), assignment.getSource(), Comment.NO_COMMENTS);
|
||||
stmtIt.add(initStmt);
|
||||
getLog().append("Adding struct value list initializer " + initStmt.toString(getProgram(), false));
|
||||
}
|
||||
stmtIt.next();
|
||||
if(assignment.getlValue() instanceof VariableRef) {
|
||||
assignment.setrValue2(new StructUnwoundPlaceholder(structType));
|
||||
assignment.setrValue2(new StructUnwoundPlaceholder(structType, membersUnwound));
|
||||
} else {
|
||||
stmtIt.remove();
|
||||
}
|
||||
@ -320,17 +324,19 @@ public class Pass1UnwindStructValues extends Pass1Base {
|
||||
// Copying a struct - unwind to assigning each member!
|
||||
StructMemberUnwinding sourceMemberUnwinding = getStructMemberUnwinding((LValue) assignment.getrValue2(), structType, structUnwinding, assignment, stmtIt, currentBlock);
|
||||
if(sourceMemberUnwinding != null) {
|
||||
List<RValue> membersUnwound = new ArrayList<>();
|
||||
stmtIt.previous();
|
||||
for(String memberName : memberUnwinding.getMemberNames()) {
|
||||
LValue assignedMemberVarRef = memberUnwinding.getMemberUnwinding(memberName);
|
||||
LValue sourceMemberVarRef = sourceMemberUnwinding.getMemberUnwinding(memberName);
|
||||
membersUnwound.add(assignedMemberVarRef);
|
||||
Statement copyStmt = new StatementAssignment(assignedMemberVarRef, sourceMemberVarRef, assignment.getSource(), Comment.NO_COMMENTS);
|
||||
stmtIt.add(copyStmt);
|
||||
getLog().append("Adding struct value member variable copy " + copyStmt.toString(getProgram(), false));
|
||||
}
|
||||
stmtIt.next();
|
||||
if(assignment.getlValue() instanceof VariableRef) {
|
||||
assignment.setrValue2(new StructUnwoundPlaceholder(structType));
|
||||
assignment.setrValue2(new StructUnwoundPlaceholder(structType, membersUnwound));
|
||||
} else {
|
||||
stmtIt.remove();
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
import dk.camelot64.kickc.model.ConstantNotLiteral;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
|
||||
@ -80,11 +81,18 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
|
||||
}
|
||||
|
||||
if(!SymbolTypeConversion.assignmentTypeMatch(variableType, valueType)) {
|
||||
throw new CompileError(
|
||||
"Constant variable has a non-matching type \n variable: " + variable.toString(getProgram()) +
|
||||
"\n value: (" + valueType.toString() + ") " + constVal.calculateLiteral(getScope()) +
|
||||
"\n value definition: " + constVal.toString(getProgram())
|
||||
);
|
||||
ConstantLiteral constantLiteral = null;
|
||||
try {
|
||||
constantLiteral = constVal.calculateLiteral(getScope());
|
||||
} catch(ConstantNotLiteral e) {
|
||||
// ignore
|
||||
}
|
||||
String literalStr = (constantLiteral == null) ? "null" : constantLiteral.toString(getProgram());
|
||||
throw new CompileError(
|
||||
"Constant variable has a non-matching type \n variable: " + variable.toString(getProgram()) +
|
||||
"\n value: (" + valueType.toString() + ") " + literalStr +
|
||||
"\n value definition: " + constVal.toString(getProgram())
|
||||
);
|
||||
}
|
||||
|
||||
ConstantVar constantVar = new ConstantVar(
|
||||
@ -197,7 +205,7 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
|
||||
// Volatile variables cannot be constant
|
||||
return;
|
||||
}
|
||||
if(assignment.getrValue1()==null && assignment.getOperator()==null && assignment.getrValue2() instanceof ConstantValue) {
|
||||
if(assignment.getrValue1() == null && assignment.getOperator() == null && assignment.getrValue2() instanceof ConstantValue) {
|
||||
constants.put(variable, new ConstantVariableValue(variable, (ConstantValue) assignment.getrValue2(), assignment));
|
||||
}
|
||||
}
|
||||
@ -324,7 +332,7 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
|
||||
// If the symbol is part of an unwound struct - look at the struct itself
|
||||
Pass1UnwindStructValues.StructUnwinding structUnwinding = program.getStructUnwinding();
|
||||
VariableRef structVarRef = structUnwinding.getContainingStructVariable(symbolRef);
|
||||
if(structVarRef!=null) {
|
||||
if(structVarRef != null) {
|
||||
return isAddressOfUsed(structVarRef, program);
|
||||
}
|
||||
|
||||
|
@ -1,37 +0,0 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementAssignment;
|
||||
import dk.camelot64.kickc.model.values.StructUnwoundPlaceholder;
|
||||
|
||||
import java.util.ListIterator;
|
||||
|
||||
/** Remove any assignments with {@link dk.camelot64.kickc.model.values.StructUnwoundPlaceholder} as RValue */
|
||||
public class PassNEliminateStructUnwoundPlaceholder extends Pass2SsaOptimization {
|
||||
|
||||
public PassNEliminateStructUnwoundPlaceholder(Program program) {
|
||||
super(program);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean step() {
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
ListIterator<Statement> stmtIt = block.getStatements().listIterator();
|
||||
while(stmtIt.hasNext()) {
|
||||
Statement stmt = stmtIt.next();
|
||||
if(stmt instanceof StatementAssignment) {
|
||||
StatementAssignment assignment = (StatementAssignment) stmt;
|
||||
if(assignment.getOperator() == null && assignment.getrValue2() instanceof StructUnwoundPlaceholder) {
|
||||
getLog().append("Eliminating struct unwound placeholder "+stmt.toString(getProgram(), false));
|
||||
stmtIt.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -6,8 +6,8 @@ import dk.camelot64.kickc.model.VariableReferenceInfos;
|
||||
import dk.camelot64.kickc.model.statements.*;
|
||||
import dk.camelot64.kickc.model.symbols.ConstantVar;
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
import dk.camelot64.kickc.model.symbols.Scope;
|
||||
import dk.camelot64.kickc.model.symbols.Variable;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypeStruct;
|
||||
import dk.camelot64.kickc.model.values.LValue;
|
||||
import dk.camelot64.kickc.model.values.VariableRef;
|
||||
|
||||
@ -41,9 +41,27 @@ public class PassNEliminateUnusedVars extends Pass2SsaOptimization {
|
||||
LValue lValue = assignment.getlValue();
|
||||
if(lValue instanceof VariableRef && referenceInfos.isUnused((VariableRef) lValue) && !Pass2ConstantIdentification.isAddressOfUsed((VariableRef) lValue, getProgram())) {
|
||||
Variable variable = getScope().getVariable((VariableRef) lValue);
|
||||
if(variable==null || !variable.isDeclaredVolatile()) {
|
||||
boolean eliminate = false;
|
||||
if(variable == null) {
|
||||
// Already deleted
|
||||
eliminate = true;
|
||||
} else if(!variable.isDeclaredVolatile()) {
|
||||
// Not volatile
|
||||
eliminate = true;
|
||||
} else if(variable.isDeclaredVolatile() && variable.getType() instanceof SymbolTypeStruct) {
|
||||
// If an unwound volatile struct - eliminate it
|
||||
if(variable.getRef().isVersion()) {
|
||||
String fullNameUnversioned = variable.getRef().getFullNameUnversioned();
|
||||
VariableRef unversionedRef = new VariableRef(fullNameUnversioned);
|
||||
Pass1UnwindStructValues.StructUnwinding.VariableUnwinding variableUnwinding = getProgram().getStructUnwinding().getVariableUnwinding(unversionedRef);
|
||||
if(variableUnwinding != null) {
|
||||
eliminate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(eliminate) {
|
||||
if(!pass2 && isReturnValue(variable)) {
|
||||
// Do not eliminate reutn variables in pass 1
|
||||
// Do not eliminate return variables in pass 1
|
||||
continue;
|
||||
}
|
||||
if(pass2 || getLog().isVerbosePass1CreateSsa()) {
|
||||
@ -124,11 +142,12 @@ public class PassNEliminateUnusedVars extends Pass2SsaOptimization {
|
||||
|
||||
/**
|
||||
* Determines if a variable is the return value for a procedure
|
||||
*
|
||||
* @param variable The variable
|
||||
* @return true if this is the return variable for a function
|
||||
*/
|
||||
private boolean isReturnValue(Variable variable) {
|
||||
if(variable==null) return false;
|
||||
if(variable == null) return false;
|
||||
return variable.getScope() instanceof Procedure && variable.getLocalName().equals("return");
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,86 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
|
||||
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.statements.StatementLValue;
|
||||
import dk.camelot64.kickc.model.symbols.Symbol;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypePointer;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypeStruct;
|
||||
import dk.camelot64.kickc.model.values.*;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* Rewrite struct address-of to use the first member if the struct is unwound
|
||||
*/
|
||||
public class PassNStructAddressOfRewriting extends Pass2SsaOptimization {
|
||||
|
||||
public PassNStructAddressOfRewriting(Program program) {
|
||||
super(program);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean step() {
|
||||
AtomicBoolean modified = new AtomicBoolean(false);
|
||||
ProgramValueIterator.execute(getProgram(), (programValue, currentStmt, stmtIt, currentBlock) -> {
|
||||
Value value = programValue.get();
|
||||
if(value instanceof ConstantSymbolPointer) {
|
||||
ConstantSymbolPointer constantSymbolPointer = (ConstantSymbolPointer) value;
|
||||
SymbolRef toSymbolRef = constantSymbolPointer.getToSymbol();
|
||||
Symbol toSymbol = getScope().getSymbol(toSymbolRef);
|
||||
if(toSymbol.getType() instanceof SymbolTypeStruct) {
|
||||
RValue rewrite = rewriteStructAddressOf((VariableRef) toSymbol);
|
||||
if(rewrite!=null) {
|
||||
programValue.set(rewrite);
|
||||
}
|
||||
getLog().append("Rewriting struct address-of to first member "+value.toString(getProgram()));
|
||||
modified.set(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Examine all statements
|
||||
for(ControlFlowBlock block : getProgram().getGraph().getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementAssignment) {
|
||||
StatementAssignment assignment = (StatementAssignment) statement;
|
||||
if(Operators.ADDRESS_OF.equals(assignment.getOperator()) ) {
|
||||
RValue rValue = assignment.getrValue2();
|
||||
if(rValue instanceof SymbolVariableRef) {
|
||||
Symbol toSymbol = getScope().getSymbol((SymbolVariableRef) rValue);
|
||||
if(toSymbol.getType() instanceof SymbolTypeStruct) {
|
||||
RValue rewrite = rewriteStructAddressOf((VariableRef) toSymbol.getRef());
|
||||
if(rewrite!=null) {
|
||||
assignment.setOperator(null);
|
||||
assignment.setrValue2(rewrite);
|
||||
getLog().append("Rewriting struct address-of to first member "+assignment.toString(getProgram(), false));
|
||||
}
|
||||
modified.set(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return modified.get();
|
||||
}
|
||||
|
||||
private RValue rewriteStructAddressOf(VariableRef toSymbol) {
|
||||
StatementLValue toSymbolAssignment = getGraph().getAssignment(toSymbol);
|
||||
if(toSymbolAssignment instanceof StatementAssignment) {
|
||||
StatementAssignment assignment = (StatementAssignment) toSymbolAssignment;
|
||||
if(assignment.getrValue2() instanceof StructUnwoundPlaceholder) {
|
||||
// Found placeholder assignment!
|
||||
StructUnwoundPlaceholder placeholder = (StructUnwoundPlaceholder) assignment.getrValue2();
|
||||
SymbolRef firstMember = (SymbolRef) placeholder.getUnwoundMembers().get(0);
|
||||
return new CastValue(new SymbolTypePointer(placeholder.getTypeStruct()), new ConstantSymbolPointer(firstMember));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -75,15 +75,13 @@ public class TestPrograms {
|
||||
|
||||
@Test
|
||||
public void testStructPtr12Ref() throws IOException, URISyntaxException {
|
||||
compileAndCompare("struct-ptr-12-ref", log());
|
||||
compileAndCompare("struct-ptr-12-ref");
|
||||
}
|
||||
|
||||
/*
|
||||
@Test
|
||||
public void testStructPtr12() throws IOException, URISyntaxException {
|
||||
compileAndCompare("struct-ptr-12", log().verboseCreateSsa().verboseParse().verboseStatementSequence());
|
||||
compileAndCompare("struct-ptr-12");
|
||||
}
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testStructPtr11() throws IOException, URISyntaxException {
|
||||
|
@ -5,7 +5,7 @@ struct Point {
|
||||
};
|
||||
|
||||
void main() {
|
||||
struct Point p = { 2, 3 };
|
||||
volatile struct Point p = { 2, 3 };
|
||||
struct Point *q = &p;
|
||||
const byte* SCREEN = 0x0400;
|
||||
SCREEN[0] = q->x;
|
||||
|
@ -473,7 +473,7 @@ getCharToProcess::@1: scope:[getCharToProcess] from getCharToProcess::@10 getCh
|
||||
(byte) getCharToProcess::return_x#1 ← (byte) getCharToProcess::closest_x#2
|
||||
(byte) getCharToProcess::return_y#1 ← (byte) getCharToProcess::closest_y#2
|
||||
(word) getCharToProcess::return_dist#1 ← (word) getCharToProcess::closest_dist#4
|
||||
(struct ProcessingChar) getCharToProcess::return#0 ← struct-unwound
|
||||
(struct ProcessingChar) getCharToProcess::return#0 ← struct-unwound {(byte) getCharToProcess::return_x#1, (byte) getCharToProcess::return_y#1, (word) getCharToProcess::return_dist#1}
|
||||
to:getCharToProcess::@return
|
||||
getCharToProcess::@11: scope:[getCharToProcess] from getCharToProcess::@10
|
||||
(word) getCharToProcess::closest_dist#7 ← phi( getCharToProcess::@10/(word) getCharToProcess::closest_dist#3 )
|
||||
@ -492,7 +492,7 @@ getCharToProcess::@return: scope:[getCharToProcess] from getCharToProcess::@1
|
||||
(byte) getCharToProcess::return_x#2 ← (byte) getCharToProcess::return_x#4
|
||||
(byte) getCharToProcess::return_y#2 ← (byte) getCharToProcess::return_y#4
|
||||
(word) getCharToProcess::return_dist#2 ← (word) getCharToProcess::return_dist#4
|
||||
(struct ProcessingChar) getCharToProcess::return#1 ← struct-unwound
|
||||
(struct ProcessingChar) getCharToProcess::return#1 ← struct-unwound {(byte) getCharToProcess::return_x#2, (byte) getCharToProcess::return_y#2, (word) getCharToProcess::return_dist#2}
|
||||
return
|
||||
to:@return
|
||||
startProcessing: scope:[startProcessing] from main::@6
|
||||
@ -2597,9 +2597,9 @@ Simplifying expression containing zero (word*)processChars::processing#0 in [371
|
||||
Simplifying expression containing zero (word*)processChars::processing#0 in [371] *((word*)(struct ProcessingSprite*) processChars::processing#0 + (const byte) OFFSET_STRUCT_PROCESSINGSPRITE_X) ← *((word*)(struct ProcessingSprite*) processChars::processing#0) + *((word*)(struct ProcessingSprite*) processChars::processing#0 + (const byte) OFFSET_STRUCT_PROCESSINGSPRITE_VX)
|
||||
Successful SSA optimization PassNSimplifyExpressionWithZero
|
||||
Eliminating unused variable (word) startProcessing::center_dist#0 and assignment [51] (word) startProcessing::center_dist#0 ← (word) main::center_dist#0
|
||||
Eliminating unused variable (struct ProcessingChar) getCharToProcess::return#0 and assignment [72] (struct ProcessingChar) getCharToProcess::return#0 ← struct-unwound
|
||||
Eliminating unused variable (struct ProcessingChar) getCharToProcess::return#0 and assignment [72] (struct ProcessingChar) getCharToProcess::return#0 ← struct-unwound {(byte) getCharToProcess::return_x#1, (byte) getCharToProcess::return_y#1, (word) getCharToProcess::return_dist#1}
|
||||
Eliminating unused variable (byte*~) getCharToProcess::$12 and assignment [76] (byte*~) getCharToProcess::$12 ← (byte*~) getCharToProcess::$11 + (byte) getCharToProcess::return_x#1
|
||||
Eliminating unused variable (struct ProcessingChar) getCharToProcess::return#1 and assignment [78] (struct ProcessingChar) getCharToProcess::return#1 ← struct-unwound
|
||||
Eliminating unused variable (struct ProcessingChar) getCharToProcess::return#1 and assignment [78] (struct ProcessingChar) getCharToProcess::return#1 ← struct-unwound {(byte) getCharToProcess::return_x#1, (byte) getCharToProcess::return_y#1, (word) getCharToProcess::return_dist#1}
|
||||
Eliminating unused variable (byte*) processChars::$40 and assignment [157] (byte*) processChars::$40 ← (byte*)(struct ProcessingSprite*) processChars::processing#0 + (const byte) OFFSET_STRUCT_PROCESSINGSPRITE_ID
|
||||
Eliminating unused variable (byte*) processChars::$41 and assignment [159] (byte*) processChars::$41 ← (byte*)(struct ProcessingSprite*) processChars::processing#0 + (const byte) OFFSET_STRUCT_PROCESSINGSPRITE_STATUS
|
||||
Eliminating unused variable (byte*) processChars::$42 and assignment [164] (byte*) processChars::$42 ← (byte*)(struct ProcessingSprite*) processChars::processing#0 + (const byte) OFFSET_STRUCT_PROCESSINGSPRITE_STATUS
|
||||
|
@ -61,14 +61,14 @@ point: scope:[point] from main
|
||||
(byte) point::p_y#0 ← (number) 3
|
||||
(byte) point::return_x#1 ← (byte) point::p_x#0
|
||||
(byte) point::return_y#1 ← (byte) point::p_y#0
|
||||
(struct Point) point::return#0 ← struct-unwound
|
||||
(struct Point) point::return#0 ← struct-unwound {(byte) point::return_x#1, (byte) point::return_y#1}
|
||||
to:point::@return
|
||||
point::@return: scope:[point] from point
|
||||
(byte) point::return_y#4 ← phi( point/(byte) point::return_y#1 )
|
||||
(byte) point::return_x#4 ← phi( point/(byte) point::return_x#1 )
|
||||
(byte) point::return_x#2 ← (byte) point::return_x#4
|
||||
(byte) point::return_y#2 ← (byte) point::return_y#4
|
||||
(struct Point) point::return#1 ← struct-unwound
|
||||
(struct Point) point::return#1 ← struct-unwound {(byte) point::return_x#2, (byte) point::return_y#2}
|
||||
return
|
||||
to:@return
|
||||
@2: scope:[] from @begin
|
||||
@ -162,8 +162,8 @@ Constant (const byte) main::q_y#1 = point::return_y#0
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Simplifying expression containing zero main::SCREEN#0 in [11] *((const byte*) main::SCREEN#0 + (byte) 0) ← (const byte) main::q_x#1
|
||||
Successful SSA optimization PassNSimplifyExpressionWithZero
|
||||
Eliminating unused variable (struct Point) point::return#0 and assignment [4] (struct Point) point::return#0 ← struct-unwound
|
||||
Eliminating unused variable (struct Point) point::return#1 and assignment [5] (struct Point) point::return#1 ← struct-unwound
|
||||
Eliminating unused variable (struct Point) point::return#0 and assignment [4] (struct Point) point::return#0 ← struct-unwound {(const byte) point::p_x#0, (const byte) point::p_y#0}
|
||||
Eliminating unused variable (struct Point) point::return#1 and assignment [5] (struct Point) point::return#1 ← struct-unwound {(const byte) point::p_x#0, (const byte) point::p_y#0}
|
||||
Eliminating unused constant (const byte) main::q_x#0
|
||||
Eliminating unused constant (const byte) main::q_y#0
|
||||
Successful SSA optimization PassNEliminateUnusedVars
|
||||
|
20
src/test/ref/struct-ptr-12.asm
Normal file
20
src/test/ref/struct-ptr-12.asm
Normal file
@ -0,0 +1,20 @@
|
||||
// Minimal struct - using address-of
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
.const OFFSET_STRUCT_POINT_Y = 1
|
||||
main: {
|
||||
.label q = p_x
|
||||
.label SCREEN = $400
|
||||
.label p_x = 2
|
||||
.label p_y = 3
|
||||
lda #2
|
||||
sta p_x
|
||||
lda #3
|
||||
sta p_y
|
||||
lda q
|
||||
sta SCREEN
|
||||
lda q+OFFSET_STRUCT_POINT_Y
|
||||
sta SCREEN+1
|
||||
rts
|
||||
}
|
18
src/test/ref/struct-ptr-12.cfg
Normal file
18
src/test/ref/struct-ptr-12.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()
|
||||
main: scope:[main] from @1
|
||||
[4] (byte) main::p_x#0 ← (byte) 2
|
||||
[5] (byte) main::p_y#0 ← (byte) 3
|
||||
[6] *((const byte*) main::SCREEN#0) ← *((byte*)(const struct Point*) main::q#0)
|
||||
[7] *((const byte*) main::SCREEN#0+(byte) 1) ← *((byte*)(const struct Point*) main::q#0+(const byte) OFFSET_STRUCT_POINT_Y)
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
[8] return
|
||||
to:@return
|
358
src/test/ref/struct-ptr-12.log
Normal file
358
src/test/ref/struct-ptr-12.log
Normal file
@ -0,0 +1,358 @@
|
||||
Created struct value member variable (byte) main::p_x
|
||||
Created struct value member variable (byte) main::p_y
|
||||
Converted struct value to member variables (struct Point) main::p
|
||||
Adding struct value list initializer (byte) main::p_x ← (number) 2
|
||||
Adding struct value list initializer (byte) main::p_y ← (number) 3
|
||||
Rewriting struct pointer member access *((struct Point*) main::q).x
|
||||
Rewriting struct pointer member access *((struct Point*) main::q).y
|
||||
Adding pointer type conversion cast (byte*) main::SCREEN in (byte*) main::SCREEN ← (number) $400
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
@begin: scope:[] from
|
||||
to:@1
|
||||
main: scope:[main] from @1
|
||||
(byte) main::p_x#0 ← (number) 2
|
||||
(byte) main::p_y#0 ← (number) 3
|
||||
(struct Point) main::p#0 ← struct-unwound {(byte) main::p_x#0, (byte) main::p_y#0}
|
||||
(struct Point*~) main::$0 ← & (struct Point) main::p#0
|
||||
(struct Point*) main::q#0 ← (struct Point*~) main::$0
|
||||
(byte*) main::SCREEN#0 ← ((byte*)) (number) $400
|
||||
(byte*) main::$1 ← (byte*)(struct Point*) main::q#0 + (const byte) OFFSET_STRUCT_POINT_X
|
||||
*((byte*) main::SCREEN#0 + (number) 0) ← *((byte*) main::$1)
|
||||
(byte*) main::$2 ← (byte*)(struct Point*) main::q#0 + (const byte) OFFSET_STRUCT_POINT_Y
|
||||
*((byte*) main::SCREEN#0 + (number) 1) ← *((byte*) main::$2)
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
return
|
||||
to:@return
|
||||
@1: scope:[] from @begin
|
||||
call main
|
||||
to:@2
|
||||
@2: scope:[] from @1
|
||||
to:@end
|
||||
@end: scope:[] from @2
|
||||
|
||||
SYMBOL TABLE SSA
|
||||
(label) @1
|
||||
(label) @2
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(const byte) OFFSET_STRUCT_POINT_X = (byte) 0
|
||||
(const byte) OFFSET_STRUCT_POINT_Y = (byte) 1
|
||||
(byte) Point::x
|
||||
(byte) Point::y
|
||||
(void()) main()
|
||||
(struct Point*~) main::$0
|
||||
(byte*) main::$1
|
||||
(byte*) main::$2
|
||||
(label) main::@return
|
||||
(byte*) main::SCREEN
|
||||
(byte*) main::SCREEN#0
|
||||
(struct Point) main::p
|
||||
(struct Point) main::p#0
|
||||
(byte) main::p_x
|
||||
(byte) main::p_x#0
|
||||
(byte) main::p_y
|
||||
(byte) main::p_y#0
|
||||
(struct Point*) main::q
|
||||
(struct Point*) main::q#0
|
||||
|
||||
Adding number conversion cast (unumber) 2 in (byte) main::p_x#0 ← (number) 2
|
||||
Adding number conversion cast (unumber) 3 in (byte) main::p_y#0 ← (number) 3
|
||||
Adding number conversion cast (unumber) 0 in *((byte*) main::SCREEN#0 + (number) 0) ← *((byte*) main::$1)
|
||||
Adding number conversion cast (unumber) 1 in *((byte*) main::SCREEN#0 + (number) 1) ← *((byte*) main::$2)
|
||||
Successful SSA optimization PassNAddNumberTypeConversions
|
||||
Inlining cast (byte) main::p_x#0 ← (unumber)(number) 2
|
||||
Inlining cast (byte) main::p_y#0 ← (unumber)(number) 3
|
||||
Inlining cast (byte*) main::SCREEN#0 ← (byte*)(number) $400
|
||||
Successful SSA optimization Pass2InlineCast
|
||||
Simplifying constant integer cast 2
|
||||
Simplifying constant integer cast 3
|
||||
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) 2
|
||||
Finalized unsigned number type (byte) 3
|
||||
Finalized unsigned number type (byte) 0
|
||||
Finalized unsigned number type (byte) 1
|
||||
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||
Alias (struct Point*) main::q#0 = (struct Point*~) main::$0
|
||||
Successful SSA optimization Pass2AliasElimination
|
||||
Rewriting struct address-of to first member [3] (struct Point*) main::q#0 ← (struct Point*)&(byte) main::p_x#0
|
||||
Successful SSA optimization PassNStructAddressOfRewriting
|
||||
Constant right-side identified [3] (struct Point*) main::q#0 ← (struct Point*)&(byte) main::p_x#0
|
||||
Successful SSA optimization Pass2ConstantRValueConsolidation
|
||||
Constant (const struct Point*) main::q#0 = (struct Point*)&main::p_x#0
|
||||
Constant (const byte*) main::SCREEN#0 = (byte*) 1024
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Constant value identified (byte*)main::q#0 in [6] (byte*) main::$1 ← (byte*)(const struct Point*) main::q#0 + (const byte) OFFSET_STRUCT_POINT_X
|
||||
Constant value identified (byte*)main::q#0 in [8] (byte*) main::$2 ← (byte*)(const struct Point*) main::q#0 + (const byte) OFFSET_STRUCT_POINT_Y
|
||||
Successful SSA optimization Pass2ConstantValues
|
||||
Converting *(pointer+n) to pointer[n] [7] *((const byte*) main::SCREEN#0 + (byte) 0) ← *((byte*) main::$1) -- *((byte*)main::q#0 + OFFSET_STRUCT_POINT_X)
|
||||
Converting *(pointer+n) to pointer[n] [9] *((const byte*) main::SCREEN#0 + (byte) 1) ← *((byte*) main::$2) -- *((byte*)main::q#0 + OFFSET_STRUCT_POINT_Y)
|
||||
Successful SSA optimization Pass2InlineDerefIdx
|
||||
Simplifying expression containing zero (byte*)main::q#0 in [6] (byte*) main::$1 ← (byte*)(const struct Point*) main::q#0 + (const byte) OFFSET_STRUCT_POINT_X
|
||||
Simplifying expression containing zero (byte*)main::q#0 in [7] *((const byte*) main::SCREEN#0 + (byte) 0) ← *((byte*)(const struct Point*) main::q#0 + (const byte) OFFSET_STRUCT_POINT_X)
|
||||
Simplifying expression containing zero main::SCREEN#0 in [7] *((const byte*) main::SCREEN#0 + (byte) 0) ← *((byte*)(const struct Point*) main::q#0)
|
||||
Successful SSA optimization PassNSimplifyExpressionWithZero
|
||||
Eliminating unused variable (struct Point) main::p#0 and assignment [2] (struct Point) main::p#0 ← struct-unwound {(byte) main::p_x#0, (byte) main::p_y#0}
|
||||
Eliminating unused variable (byte*) main::$1 and assignment [3] (byte*) main::$1 ← (byte*)(const struct Point*) main::q#0
|
||||
Eliminating unused variable (byte*) main::$2 and assignment [5] (byte*) main::$2 ← (byte*)(const struct Point*) main::q#0 + (const byte) OFFSET_STRUCT_POINT_Y
|
||||
Eliminating unused constant (const byte) OFFSET_STRUCT_POINT_X
|
||||
Successful SSA optimization PassNEliminateUnusedVars
|
||||
Consolidated array index constant in *((byte*)main::q#0+OFFSET_STRUCT_POINT_Y)
|
||||
Consolidated array index constant in *(main::SCREEN#0+1)
|
||||
Successful SSA optimization Pass2ConstantAdditionElimination
|
||||
Adding NOP phi() at start of @begin
|
||||
Adding NOP phi() at start of @1
|
||||
Adding NOP phi() at start of @2
|
||||
Adding NOP phi() at start of @end
|
||||
CALL GRAPH
|
||||
Calls in [] to main:2
|
||||
|
||||
Created 0 initial phi equivalence classes
|
||||
Coalesced down to 0 phi equivalence classes
|
||||
Culled Empty Block (label) @2
|
||||
Adding NOP phi() at start of @begin
|
||||
Adding NOP phi() at start of @1
|
||||
Adding NOP phi() at start of @end
|
||||
|
||||
FINAL CONTROL FLOW GRAPH
|
||||
@begin: scope:[] from
|
||||
[0] phi()
|
||||
to:@1
|
||||
@1: scope:[] from @begin
|
||||
[1] phi()
|
||||
[2] call main
|
||||
to:@end
|
||||
@end: scope:[] from @1
|
||||
[3] phi()
|
||||
main: scope:[main] from @1
|
||||
[4] (byte) main::p_x#0 ← (byte) 2
|
||||
[5] (byte) main::p_y#0 ← (byte) 3
|
||||
[6] *((const byte*) main::SCREEN#0) ← *((byte*)(const struct Point*) main::q#0)
|
||||
[7] *((const byte*) main::SCREEN#0+(byte) 1) ← *((byte*)(const struct Point*) main::q#0+(const byte) OFFSET_STRUCT_POINT_Y)
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
[8] return
|
||||
to:@return
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
(byte) Point::x
|
||||
(byte) Point::y
|
||||
(void()) main()
|
||||
(byte*) main::SCREEN
|
||||
(struct Point) main::p
|
||||
(byte) main::p_x
|
||||
(byte) main::p_x#0 20.0
|
||||
(byte) main::p_y
|
||||
(byte) main::p_y#0 20.0
|
||||
(struct Point*) main::q
|
||||
|
||||
Initial phi equivalence classes
|
||||
Complete equivalence classes
|
||||
[ main::p_x#0 ]
|
||||
[ main::p_y#0 ]
|
||||
Allocated zp ZP_BYTE:2 [ main::p_x#0 ]
|
||||
Allocated zp ZP_BYTE:3 [ main::p_y#0 ]
|
||||
|
||||
INITIAL ASM
|
||||
//SEG0 File Comments
|
||||
// Minimal struct - using address-of
|
||||
//SEG1 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(bbegin)
|
||||
.pc = $80d "Program"
|
||||
//SEG2 Global Constants & labels
|
||||
.const OFFSET_STRUCT_POINT_Y = 1
|
||||
//SEG3 @begin
|
||||
bbegin:
|
||||
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
|
||||
b1_from_bbegin:
|
||||
jmp b1
|
||||
//SEG5 @1
|
||||
b1:
|
||||
//SEG6 [2] call main
|
||||
jsr main
|
||||
//SEG7 [3] phi from @1 to @end [phi:@1->@end]
|
||||
bend_from_b1:
|
||||
jmp bend
|
||||
//SEG8 @end
|
||||
bend:
|
||||
//SEG9 main
|
||||
main: {
|
||||
.label q = p_x
|
||||
.label SCREEN = $400
|
||||
.label p_x = 2
|
||||
.label p_y = 3
|
||||
//SEG10 [4] (byte) main::p_x#0 ← (byte) 2 -- vbuz1=vbuc1
|
||||
lda #2
|
||||
sta p_x
|
||||
//SEG11 [5] (byte) main::p_y#0 ← (byte) 3 -- vbuz1=vbuc1
|
||||
lda #3
|
||||
sta p_y
|
||||
//SEG12 [6] *((const byte*) main::SCREEN#0) ← *((byte*)(const struct Point*) main::q#0) -- _deref_pbuc1=_deref_pbuc2
|
||||
lda q
|
||||
sta SCREEN
|
||||
//SEG13 [7] *((const byte*) main::SCREEN#0+(byte) 1) ← *((byte*)(const struct Point*) main::q#0+(const byte) OFFSET_STRUCT_POINT_Y) -- _deref_pbuc1=_deref_pbuc2
|
||||
lda q+OFFSET_STRUCT_POINT_Y
|
||||
sta SCREEN+1
|
||||
jmp breturn
|
||||
//SEG14 main::@return
|
||||
breturn:
|
||||
//SEG15 [8] return
|
||||
rts
|
||||
}
|
||||
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [4] (byte) main::p_x#0 ← (byte) 2 [ ] ( main:2 [ ] ) always clobbers reg byte a
|
||||
Statement [5] (byte) main::p_y#0 ← (byte) 3 [ ] ( main:2 [ ] ) always clobbers reg byte a
|
||||
Statement [6] *((const byte*) main::SCREEN#0) ← *((byte*)(const struct Point*) main::q#0) [ ] ( main:2 [ ] ) always clobbers reg byte a
|
||||
Statement [7] *((const byte*) main::SCREEN#0+(byte) 1) ← *((byte*)(const struct Point*) main::q#0+(const byte) OFFSET_STRUCT_POINT_Y) [ ] ( main:2 [ ] ) always clobbers reg byte a
|
||||
Potential registers zp ZP_BYTE:2 [ main::p_x#0 ] : zp ZP_BYTE:2 ,
|
||||
Potential registers zp ZP_BYTE:3 [ main::p_y#0 ] : zp ZP_BYTE:3 ,
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [main] 20: zp ZP_BYTE:2 [ main::p_x#0 ] 20: zp ZP_BYTE:3 [ main::p_y#0 ]
|
||||
Uplift Scope [Point]
|
||||
Uplift Scope []
|
||||
|
||||
Uplifting [main] best 47 combination zp ZP_BYTE:2 [ main::p_x#0 ] zp ZP_BYTE:3 [ main::p_y#0 ]
|
||||
Uplifting [Point] best 47 combination
|
||||
Uplifting [] best 47 combination
|
||||
Attempting to uplift remaining variables inzp ZP_BYTE:2 [ main::p_x#0 ]
|
||||
Uplifting [main] best 47 combination zp ZP_BYTE:2 [ main::p_x#0 ]
|
||||
Attempting to uplift remaining variables inzp ZP_BYTE:3 [ main::p_y#0 ]
|
||||
Uplifting [main] best 47 combination zp ZP_BYTE:3 [ main::p_y#0 ]
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
//SEG0 File Comments
|
||||
// Minimal struct - using address-of
|
||||
//SEG1 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(bbegin)
|
||||
.pc = $80d "Program"
|
||||
//SEG2 Global Constants & labels
|
||||
.const OFFSET_STRUCT_POINT_Y = 1
|
||||
//SEG3 @begin
|
||||
bbegin:
|
||||
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
|
||||
b1_from_bbegin:
|
||||
jmp b1
|
||||
//SEG5 @1
|
||||
b1:
|
||||
//SEG6 [2] call main
|
||||
jsr main
|
||||
//SEG7 [3] phi from @1 to @end [phi:@1->@end]
|
||||
bend_from_b1:
|
||||
jmp bend
|
||||
//SEG8 @end
|
||||
bend:
|
||||
//SEG9 main
|
||||
main: {
|
||||
.label q = p_x
|
||||
.label SCREEN = $400
|
||||
.label p_x = 2
|
||||
.label p_y = 3
|
||||
//SEG10 [4] (byte) main::p_x#0 ← (byte) 2 -- vbuz1=vbuc1
|
||||
lda #2
|
||||
sta p_x
|
||||
//SEG11 [5] (byte) main::p_y#0 ← (byte) 3 -- vbuz1=vbuc1
|
||||
lda #3
|
||||
sta p_y
|
||||
//SEG12 [6] *((const byte*) main::SCREEN#0) ← *((byte*)(const struct Point*) main::q#0) -- _deref_pbuc1=_deref_pbuc2
|
||||
lda q
|
||||
sta SCREEN
|
||||
//SEG13 [7] *((const byte*) main::SCREEN#0+(byte) 1) ← *((byte*)(const struct Point*) main::q#0+(const byte) OFFSET_STRUCT_POINT_Y) -- _deref_pbuc1=_deref_pbuc2
|
||||
lda q+OFFSET_STRUCT_POINT_Y
|
||||
sta SCREEN+1
|
||||
jmp breturn
|
||||
//SEG14 main::@return
|
||||
breturn:
|
||||
//SEG15 [8] return
|
||||
rts
|
||||
}
|
||||
|
||||
ASSEMBLER OPTIMIZATIONS
|
||||
Removing instruction jmp b1
|
||||
Removing instruction jmp bend
|
||||
Removing instruction jmp breturn
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
Removing instruction b1_from_bbegin:
|
||||
Removing instruction b1:
|
||||
Removing instruction bend_from_b1:
|
||||
Succesful ASM optimization Pass5RedundantLabelElimination
|
||||
Removing instruction bend:
|
||||
Removing instruction breturn:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
Updating BasicUpstart to call main directly
|
||||
Removing instruction jsr main
|
||||
Succesful ASM optimization Pass5SkipBegin
|
||||
Removing instruction bbegin:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
(label) @1
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(const byte) OFFSET_STRUCT_POINT_Y OFFSET_STRUCT_POINT_Y = (byte) 1
|
||||
(byte) Point::x
|
||||
(byte) Point::y
|
||||
(void()) main()
|
||||
(label) main::@return
|
||||
(byte*) main::SCREEN
|
||||
(const byte*) main::SCREEN#0 SCREEN = (byte*) 1024
|
||||
(struct Point) main::p
|
||||
(byte) main::p_x
|
||||
(byte) main::p_x#0 p_x zp ZP_BYTE:2 20.0
|
||||
(byte) main::p_y
|
||||
(byte) main::p_y#0 p_y zp ZP_BYTE:3 20.0
|
||||
(struct Point*) main::q
|
||||
(const struct Point*) main::q#0 q = (struct Point*)&(byte) main::p_x#0
|
||||
|
||||
zp ZP_BYTE:2 [ main::p_x#0 ]
|
||||
zp ZP_BYTE:3 [ main::p_y#0 ]
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 32
|
||||
|
||||
//SEG0 File Comments
|
||||
// Minimal struct - using address-of
|
||||
//SEG1 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
//SEG2 Global Constants & labels
|
||||
.const OFFSET_STRUCT_POINT_Y = 1
|
||||
//SEG3 @begin
|
||||
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
|
||||
//SEG5 @1
|
||||
//SEG6 [2] call main
|
||||
//SEG7 [3] phi from @1 to @end [phi:@1->@end]
|
||||
//SEG8 @end
|
||||
//SEG9 main
|
||||
main: {
|
||||
.label q = p_x
|
||||
.label SCREEN = $400
|
||||
.label p_x = 2
|
||||
.label p_y = 3
|
||||
//SEG10 [4] (byte) main::p_x#0 ← (byte) 2 -- vbuz1=vbuc1
|
||||
lda #2
|
||||
sta p_x
|
||||
//SEG11 [5] (byte) main::p_y#0 ← (byte) 3 -- vbuz1=vbuc1
|
||||
lda #3
|
||||
sta p_y
|
||||
//SEG12 [6] *((const byte*) main::SCREEN#0) ← *((byte*)(const struct Point*) main::q#0) -- _deref_pbuc1=_deref_pbuc2
|
||||
lda q
|
||||
sta SCREEN
|
||||
//SEG13 [7] *((const byte*) main::SCREEN#0+(byte) 1) ← *((byte*)(const struct Point*) main::q#0+(const byte) OFFSET_STRUCT_POINT_Y) -- _deref_pbuc1=_deref_pbuc2
|
||||
lda q+OFFSET_STRUCT_POINT_Y
|
||||
sta SCREEN+1
|
||||
//SEG14 main::@return
|
||||
//SEG15 [8] return
|
||||
rts
|
||||
}
|
||||
|
20
src/test/ref/struct-ptr-12.sym
Normal file
20
src/test/ref/struct-ptr-12.sym
Normal file
@ -0,0 +1,20 @@
|
||||
(label) @1
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(const byte) OFFSET_STRUCT_POINT_Y OFFSET_STRUCT_POINT_Y = (byte) 1
|
||||
(byte) Point::x
|
||||
(byte) Point::y
|
||||
(void()) main()
|
||||
(label) main::@return
|
||||
(byte*) main::SCREEN
|
||||
(const byte*) main::SCREEN#0 SCREEN = (byte*) 1024
|
||||
(struct Point) main::p
|
||||
(byte) main::p_x
|
||||
(byte) main::p_x#0 p_x zp ZP_BYTE:2 20.0
|
||||
(byte) main::p_y
|
||||
(byte) main::p_y#0 p_y zp ZP_BYTE:3 20.0
|
||||
(struct Point*) main::q
|
||||
(const struct Point*) main::q#0 q = (struct Point*)&(byte) main::p_x#0
|
||||
|
||||
zp ZP_BYTE:2 [ main::p_x#0 ]
|
||||
zp ZP_BYTE:3 [ main::p_y#0 ]
|
Loading…
x
Reference in New Issue
Block a user