1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-12-26 03:32:23 +00:00

Merge branch 'master' into far-call-isolated

# Conflicts:
#	pom.xml
#	src/main/antlr4/dk/camelot64/kickc/parser/KickCParser.g4
#	src/main/java/dk/camelot64/kickc/preprocessor/CPreprocessor.java
This commit is contained in:
jespergravgaard 2023-04-23 09:44:05 +02:00
commit 93dac7a14c
67 changed files with 4908 additions and 97 deletions

24
pom.xml
View File

@ -5,8 +5,8 @@
<modelVersion>4.0.0</modelVersion>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<argLine>-Xmx2048m</argLine>
</properties>
@ -47,24 +47,24 @@
<dependency>
<groupId>org.antlr</groupId>
<artifactId>antlr4</artifactId>
<version>4.9.3</version>
<version>4.12.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.antlr</groupId>
<artifactId>antlr4-runtime</artifactId>
<version>4.9.3</version>
<version>4.12.0</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.8.2</version>
<version>5.9.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>info.picocli</groupId>
<artifactId>picocli</artifactId>
<version>4.6.2</version>
<version>4.7.1</version>
</dependency>
<dependency>
<groupId>javax.json</groupId>
@ -124,7 +124,7 @@
<plugin>
<groupId>org.antlr</groupId>
<artifactId>antlr4-maven-plugin</artifactId>
<version>4.9.3</version>
<version>4.12.0</version>
<executions>
<execution>
<id>antlr</id>
@ -152,7 +152,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
<version>3.0.0-M9</version>
<configuration>
<excludes>
<exclude>**/TestFragments.java</exclude>
@ -167,7 +167,7 @@
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.8</version>
<version>0.8.9</version>
<executions>
<execution>
<id>pre-unit-test</id>
@ -187,7 +187,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<version>3.3.0</version>
<configuration>
<archive>
<manifest>
@ -201,7 +201,7 @@
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>3.5.0</version>
<version>5.1.8</version>
<executions>
<execution>
<id>bundle-manifest</id>
@ -214,7 +214,7 @@
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.3.0</version>
<version>3.5.0</version>
<configuration>
<finalName>kickc</finalName>
<tarLongFileMode>posix</tarLongFileMode>

View File

@ -136,8 +136,7 @@ parameterDecl
;
pragma
: PRAGMA NAME
| PRAGMA NAME (PAR_BEGIN pragmaParam (COMMA pragmaParam)* PAR_END)?
: PRAGMA NAME PAR_BEGIN (pragmaParam (COMMA pragmaParam)* )? PAR_END
;
pragmaParam
@ -245,9 +244,10 @@ expr
| expr ( '&&' ) expr #exprBinary
| expr ( '||' ) expr #exprBinary
| expr '?' expr COLON expr #exprTernary
| <assoc=right> expr '=' expr #exprAssignment
| <assoc=right> expr ASSIGN expr #exprAssignment
| <assoc=right> expr ASSIGN_COMPOUND expr #exprAssignmentCompound
| CURLY_BEGIN expr (COMMA expr )* COMMA? CURLY_END #initList
| CURLY_BEGIN DOT NAME ASSIGN expr CURLY_END #initUnion
| NAME #exprId
| NUMBER #exprNumber
| STRING+ #exprString

View File

@ -0,0 +1,3 @@
lda ({z1}),y
cmp ({z2}),y
bcc {la1}

View File

@ -89,6 +89,8 @@ public class Initializers {
return new ConstantCastValue(toType, (ConstantValue) constantSub);
}
}
} else if(initValue instanceof UnionDesignator) {
initValue = constantifyUnion((UnionDesignator) initValue, (SymbolTypeStruct) typeSpec.getType(), program, source);
} else if(initValue instanceof ValueList) {
ValueList initList = (ValueList) initValue;
if(typeSpec.getType() instanceof SymbolTypePointer && ((SymbolTypePointer) typeSpec.getType()).getArraySpec() != null) {
@ -96,7 +98,7 @@ public class Initializers {
initValue = constantifyArray(initList, (SymbolTypePointer) typeSpec.getType(), program, source);
} else if(typeSpec.getType() instanceof SymbolTypeStruct) {
// Type is a struct
initValue = constantifyStruct(initList, (SymbolTypeStruct) typeSpec.getType(), program, source);
initValue = constantifyStructOrUnion(initList, (SymbolTypeStruct) typeSpec.getType(), program, source);
} else {
throw new CompileError("Value list cannot initialize type " + typeSpec.getType(), source);
}
@ -127,6 +129,41 @@ public class Initializers {
return initValue;
}
/**
* Convert a union designator initializer to a constant.
*
* @param unionInit The union initializer
* @param structType The union type
* @param program The program
* @param source The source line
* @return The constantified value
*/
private static RValue constantifyUnion(UnionDesignator unionInit, SymbolTypeStruct structType, Program program, StatementSource source) {
StructDefinition structDefinition = structType.getStructDefinition(program.getScope());
Collection<Variable> memberDefinitions = structDefinition.getAllVars(false);
final String memberName = unionInit.getMemberName();
final RValue initValue = unionInit.getMemberValue();
Variable memberDef = null;
for(Variable definition : memberDefinitions) {
if(definition.getLocalName().equals(memberName)) {
memberDef = definition;
}
}
if(memberDef==null)
throw new CompileError( "Union member not found", source);
RValue constantifiedMemberValue = constantify(initValue, new ValueTypeSpec(memberDef.getType()), program, source);
if(constantifiedMemberValue instanceof ConstantValue) {
LinkedHashMap<SymbolVariableRef, ConstantValue> constMemberMap = new LinkedHashMap<>();
constMemberMap.put(memberDef.getRef(), (ConstantValue) constantifiedMemberValue);
return new ConstantStructValue(structType, constMemberMap);
} else {
throw new CompileError( "Union initializer is not constant", source);
}
}
/**
* Convert as much as possible of a struct to constants.
*
@ -136,7 +173,7 @@ public class Initializers {
* @param source The source line
* @return The constantified value
*/
private static RValue constantifyStruct(ValueList valueList, SymbolTypeStruct structType, Program program, StatementSource source) {
private static RValue constantifyStructOrUnion(ValueList valueList, SymbolTypeStruct structType, Program program, StatementSource source) {
// Recursively cast all sub-elements
StructDefinition structDefinition = structType.getStructDefinition(program.getScope());
Collection<Variable> memberDefinitions = structDefinition.getAllVars(false);
@ -144,7 +181,7 @@ public class Initializers {
if(structInitNeedSize != valueList.getList().size()) {
if(structDefinition.isUnion()) {
throw new CompileError(
"Union initializer has too many values, since only one is allowed.\n" +
"Union initializer has wrong size. One value is required.\n" +
" Union initializer: " + valueList.toString(program),
source);
} else {

View File

@ -1,13 +1,11 @@
package dk.camelot64.kickc.model.statements;
import dk.camelot64.kickc.model.Comment;
import dk.camelot64.kickc.model.values.LabelRef;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.values.LabelRef;
import dk.camelot64.kickc.model.values.RValue;
import dk.camelot64.kickc.model.values.VariableRef;
import org.antlr.v4.runtime.RuleContext;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@ -24,7 +22,7 @@ public class StatementPhiBlock extends StatementBase {
private List<PhiVariable> phiVariables;
public StatementPhiBlock(List<Comment> comments) {
super(new StatementSource(RuleContext.EMPTY), comments);
super(StatementSource.NONE, comments);
this.phiVariables = new ArrayList<>();
}

View File

@ -0,0 +1,40 @@
package dk.camelot64.kickc.model.values;
import dk.camelot64.kickc.model.Program;
/**
* A union designator initializer.
*/
public class UnionDesignator implements RValue {
private final String memberName;
private final RValue rValue;
public UnionDesignator(String memberName, RValue rValue) {
this.memberName = memberName;
this.rValue = rValue;
}
public String getMemberName() { return memberName; }
public RValue getMemberValue() {
return rValue;
}
@Override
public String toString(Program program) {
StringBuilder out = new StringBuilder();
out.append("{ ");
out.append(memberName);
out.append("=");
out.append(rValue.toString(program));
out.append(" }");
return out.toString();
}
@Override
public String toString() {
return toString(null);
}
}

View File

@ -136,7 +136,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
initProc.setParameters(new ArrayList<>());
program.getScope().add(initProc);
program.createProcedureCompilation(initProc.getRef());
program.getProcedureCompilation(initProc.getRef()).getStatementSequence().addStatement(new StatementProcedureBegin(initProc.getRef(), new StatementSource(RuleContext.EMPTY), Comment.NO_COMMENTS));
program.getProcedureCompilation(initProc.getRef()).getStatementSequence().addStatement(new StatementProcedureBegin(initProc.getRef(), StatementSource.NONE, Comment.NO_COMMENTS));
}
return initProc;
}
@ -180,9 +180,9 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
if(initCompilation != null) {
final StatementSequence initSequence = initCompilation.getStatementSequence();
final Label initReturnLabel = program.getScope().getProcedure(initProcedureRef).addLabel(SymbolRef.PROCEXIT_BLOCK_NAME);
initSequence.addStatement(new StatementLabel(initReturnLabel.getRef(), new StatementSource(RuleContext.EMPTY), Comment.NO_COMMENTS));
initSequence.addStatement(new StatementReturn(null, new StatementSource(RuleContext.EMPTY), Comment.NO_COMMENTS));
initSequence.addStatement(new StatementProcedureEnd(initProcedureRef, new StatementSource(RuleContext.EMPTY), Comment.NO_COMMENTS));
initSequence.addStatement(new StatementLabel(initReturnLabel.getRef(), StatementSource.NONE, Comment.NO_COMMENTS));
initSequence.addStatement(new StatementReturn(null, StatementSource.NONE, Comment.NO_COMMENTS));
initSequence.addStatement(new StatementProcedureEnd(initProcedureRef, StatementSource.NONE, Comment.NO_COMMENTS));
}
// Add the _start() procedure to the program
@ -193,16 +193,16 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
program.getScope().add(startProcedure);
final ProcedureCompilation startProcedureCompilation = program.createProcedureCompilation(startProcedure.getRef());
final StatementSequence startSequence = startProcedureCompilation.getStatementSequence();
startSequence.addStatement(new StatementProcedureBegin(startProcedure.getRef(), new StatementSource(RuleContext.EMPTY), Comment.NO_COMMENTS));
startSequence.addStatement(new StatementProcedureBegin(startProcedure.getRef(), StatementSource.NONE, Comment.NO_COMMENTS));
if(initCompilation != null)
startSequence.addStatement(new StatementCall(null, SymbolRef.INIT_PROC_NAME, new ArrayList<>(), new StatementSource(RuleContext.EMPTY), Comment.NO_COMMENTS));
startSequence.addStatement(new StatementCall(null, SymbolRef.INIT_PROC_NAME, new ArrayList<>(), StatementSource.NONE, Comment.NO_COMMENTS));
final Procedure mainProc = program.getScope().getLocalProcedure(SymbolRef.MAIN_PROC_NAME);
if(mainProc == null)
throw new CompileError("Required main() not defined in program.");
if(!SymbolType.VOID.equals(mainProc.getReturnType()) && !SymbolType.SWORD.equals(mainProc.getReturnType()))
throw new CompileError("return of main() must be 'void' or of type 'int'.", mainProc.getDefinitionSource());
if(mainProc.getParameterNames().size() == 0) {
startSequence.addStatement(new StatementCall(null, SymbolRef.MAIN_PROC_NAME, new ArrayList<>(), new StatementSource(RuleContext.EMPTY), Comment.NO_COMMENTS));
startSequence.addStatement(new StatementCall(null, SymbolRef.MAIN_PROC_NAME, new ArrayList<>(), StatementSource.NONE, Comment.NO_COMMENTS));
} else if(mainProc.getParameterNames().size() == 2) {
final List<Variable> parameters = mainProc.getParameters();
final Variable argc = parameters.get(0);
@ -214,15 +214,15 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
final ArrayList<RValue> params = new ArrayList<>();
params.add(new ConstantInteger(0L, SymbolType.SWORD));
params.add(new ConstantPointer(0L, new SymbolTypePointer(SymbolType.BYTE)));
startSequence.addStatement(new StatementCall(null, SymbolRef.MAIN_PROC_NAME, params, new StatementSource(RuleContext.EMPTY), Comment.NO_COMMENTS));
startSequence.addStatement(new StatementCall(null, SymbolRef.MAIN_PROC_NAME, params, StatementSource.NONE, Comment.NO_COMMENTS));
} else
throw new CompileError("main() has wrong number of parameters. It must have zero or 2 parameters.", mainProc.getDefinitionSource());
final Label startReturnLabel = startProcedure.addLabel(SymbolRef.PROCEXIT_BLOCK_NAME);
startSequence.addStatement(new StatementLabel(startReturnLabel.getRef(), new StatementSource(RuleContext.EMPTY), Comment.NO_COMMENTS));
startSequence.addStatement(new StatementReturn(null, new StatementSource(RuleContext.EMPTY), Comment.NO_COMMENTS));
startSequence.addStatement(new StatementProcedureEnd(startProcedure.getRef(), new StatementSource(RuleContext.EMPTY), Comment.NO_COMMENTS));
startSequence.addStatement(new StatementLabel(startReturnLabel.getRef(), StatementSource.NONE, Comment.NO_COMMENTS));
startSequence.addStatement(new StatementReturn(null, StatementSource.NONE, Comment.NO_COMMENTS));
startSequence.addStatement(new StatementProcedureEnd(startProcedure.getRef(), StatementSource.NONE, Comment.NO_COMMENTS));
}
}
@ -1963,13 +1963,20 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
return null;
}
@Override
public RValue visitInitUnion(KickCParser.InitUnionContext ctx) {
final String memberName = ctx.NAME().getText();
final RValue rValue = (RValue) visit(ctx.expr());
return new UnionDesignator(memberName, rValue);
}
@Override
public RValue visitInitList(KickCParser.InitListContext ctx) {
List<RValue> initValues = new ArrayList<>();
for(KickCParser.ExprContext initializer : ctx.expr()) {
RValue rValue = (RValue) visit(initializer);
initValues.add(rValue);
}
initValues.add(rValue);
}
return new ValueList(initValues);
}

View File

@ -62,9 +62,7 @@ public class Pass1CallVar extends Pass2SsaOptimization {
final LValue lValue = call.getlValue();
if(lValue!=null) {
Variable returnVar = procedure.getLocalVariable("return");
stmtIt.previous();
generateCallFinalize(lValue, returnVar, source, comments, stmtIt, statement);
stmtIt.next();
}
stmtIt.remove();
}
@ -105,7 +103,9 @@ public class Pass1CallVar extends Pass2SsaOptimization {
if(!(lValue instanceof ValueList) || !(returnType instanceof SymbolTypeStruct)) {
// A simple value - add simple assignment
final StatementAssignment stackPull = new StatementAssignment(lValue, returnVar.getRef(), false, source, comments);
stmtIt.previous();
stmtIt.add(stackPull);
stmtIt.next();
getLog().append("Calling convention " + Procedure.CallingConvention.VAR_CALL + " adding return value assignment " + stackPull);
} else {
final CastValue structLValue = new CastValue(returnType, lValue);
@ -113,21 +113,6 @@ public class Pass1CallVar extends Pass2SsaOptimization {
final ValueSource lValueSource = ValueSourceFactory.getValueSource(structLValue, getProgram(), getScope(), currentStmt, stmtIt, null);
final ValueSource rValueSource = ValueSourceFactory.getValueSource(returnVar.getRef(), getProgram(), getScope(), currentStmt, stmtIt, null);
Pass1UnwindStructValues.copyValues(lValueSource, rValueSource, null, false, currentStmt, null, stmtIt, getProgram());
/*
final List<RValue> memberLValues = ((ValueList) lValue).getList();
final StructVariableMemberUnwinding structVariableMemberUnwinding = getProgram().getStructVariableMemberUnwinding();
final StructVariableMemberUnwinding.VariableUnwinding returnVarUnwinding = structVariableMemberUnwinding.getVariableUnwinding(returnVar.getRef());
for(RValue memberLValue : memberLValues) {
}
for(int i = 0; i < structMemberVars.size(); i++) {
final Variable memberVar = structMemberVars.get(i);
final RValue memberValue = memberLValues.get(i);
generateCallFinalize(memberValue, memberVar.getType(), source, comments, stmtIt);
}
*/
}
}

View File

@ -3,9 +3,7 @@ package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.iterator.ProgramValue;
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
import dk.camelot64.kickc.model.symbols.ProgramScope;
import dk.camelot64.kickc.model.symbols.Symbol;
import dk.camelot64.kickc.model.symbols.Variable;
import dk.camelot64.kickc.model.symbols.*;
import dk.camelot64.kickc.model.values.*;
import dk.camelot64.kickc.passes.utils.AliasReplacer;
@ -55,10 +53,14 @@ public class Pass2ConstantInlining extends Pass2SsaOptimization {
replaceInValues(inline);
// Replace all usages of the constants in the control flow graph or symbol table
replaceVariables(inline);
// Remove parameters
final Set<ConstantRef> inlineRefs = inline.keySet();
removeParameters(inlineRefs);
// Remove from symbol table
deleteSymbols(getScope(), inline.keySet());
deleteSymbols(getScope(), inlineRefs);
for(ConstantRef constantRef : inline.keySet()) {
for(ConstantRef constantRef : inlineRefs) {
getLog().append("Constant inlined " + constantRef.toString() + " = " + inline.get(constantRef).toString(getProgram()));
}
@ -66,6 +68,30 @@ public class Pass2ConstantInlining extends Pass2SsaOptimization {
}
private void removeParameters(Set<ConstantRef> inlineRefs) {
for(ConstantRef inlineRef : inlineRefs) {
final Scope scope = getScope().getConstant(inlineRef).getScope();
final Procedure procedure = getProcedure(scope);
if(procedure!=null) {
final List<Variable> parameters = procedure.getParameters();
final boolean modified = parameters.removeIf(param -> param.getRef().equals(inlineRef));
if(modified) {
procedure.setParameters(parameters);
getLog().append("Parameter inlined " + inlineRef.toString());
}
}
}
}
private static Procedure getProcedure(Scope scope) {
if(scope instanceof Procedure)
return (Procedure) scope;
else if(scope instanceof ProgramScope)
return null;
else
return getProcedure(scope.getScope());
}
/**
* Replace any aliases within the constant values themselves
*

View File

@ -212,7 +212,7 @@ public class Pass4RegistersFinalize extends Pass2Base {
reserved = false;
int candidateZp = currentZp;
for(int i=0;i<size;i++) {
if(reservedZp.contains(new Integer(candidateZp+i))) {
if(reservedZp.contains(Integer.valueOf(candidateZp+i))) {
reserved = true;
currentZp++;
break;

View File

@ -223,29 +223,26 @@ public class CPreprocessor implements TokenSource {
pragmaTokens.add(pragmaType);
pragmaTokens.addAll(skipWhitespace(cTokenSource));
ArrayList<Token> pragmaBody = readBody(cTokenSource);
if(pragmaBody.size()>0) {
final Token pragmaBodyStart = pragmaBody.get(0);
// Convert space-based pragma to parenthesis-based for easier parsing
// #pragma NAME XXX YYY \n => #pragma NAME ( XXX , YYY ) \n
if (pragmaBodyStart.getType() != KickCLexer.PAR_BEGIN) {
ArrayList<Token> parenthesizedBody = new ArrayList<>();
parenthesizedBody.add(new CommonToken(KickCLexer.PAR_BEGIN, "("));
// Parenthesize the parameter list
boolean first = true;
for (Token token : pragmaBody) {
if (token.getChannel() != CParser.CHANNEL_WHITESPACE && !first) {
parenthesizedBody.add(new CommonToken(KickCLexer.COMMA, ","));
}
parenthesizedBody.add(token);
first = false;
// Convert space-based pragma to parenthesis-based for easier parsing
// #pragma NAME XXX YYY \n => #pragma NAME ( XXX , YYY ) \n
if(pragmaBody.isEmpty() || pragmaBody.get(0).getType() != KickCLexer.PAR_BEGIN) {
ArrayList<Token> parenthesizedBody = new ArrayList<>();
parenthesizedBody.add(new CommonToken(KickCLexer.PAR_BEGIN, "("));
// Parenthesize the parameter list
boolean first = true;
for(Token token : pragmaBody) {
if(token.getChannel() != CParser.CHANNEL_WHITESPACE && !first) {
parenthesizedBody.add(new CommonToken(KickCLexer.COMMA, ","));
}
parenthesizedBody.add(new CommonToken(KickCLexer.PAR_END, ")"));
pragmaBody = parenthesizedBody;
parenthesizedBody.add(token);
first = false;
}
pragmaTokens.addAll(pragmaBody);
// Pass on the #pragma to the parser - and mark it as already handled
cTokenSource.addSourceFirst(new ListTokenSource(pragmaTokens));
parenthesizedBody.add(new CommonToken(KickCLexer.PAR_END, ")"));
pragmaBody = parenthesizedBody;
}
pragmaTokens.addAll(pragmaBody);
// Pass on the #pragma to the parser - and mark it as already handled
cTokenSource.addSourceFirst(new ListTokenSource(pragmaTokens));
parserPragmas.add(inputToken);
return true;
}

View File

@ -374,17 +374,33 @@ public class TestProgramsFast extends TestPrograms {
public void testStructUnwinding2() throws IOException {
compileAndCompare("struct-unwinding-2.c");
}
@Test
public void testStructUnwinding1() throws IOException {
compileAndCompare("struct-unwinding-1.c");
}
//@Test
//public void testVarCall5() throws IOException {
// compileAndCompare("varcall-5.c", log().verboseCreateSsa().verboseStructUnwind());
//}
@Test
public void testVarCall9() throws IOException {
compileAndCompare("varcall-9.c");
}
@Test
public void testVarCall8() throws IOException {
compileAndCompare("varcall-8.c");
}
@Test
public void testVarCall7() throws IOException {
compileAndCompare("varcall-7.c");
}
@Test
public void testVarCall6() throws IOException {
compileAndCompare("varcall-6.c");
}
@Test
public void testVarCall5() throws IOException {
compileAndCompare("varcall-5.c");
}
@Test
public void testVarCall4() throws IOException {
compileAndCompare("varcall-4.c");
@ -530,6 +546,11 @@ public class TestProgramsFast extends TestPrograms {
compileAndCompare("pragma-unknown.c");
}
@Test
public void testPragmaNoParametersNoParenthesis() throws IOException {
compileAndCompare("pragma-noparam-noparen.c");
}
@Test
public void testErrorFormatter() throws IOException {
// Error on a char
@ -2612,6 +2633,31 @@ public class TestProgramsFast extends TestPrograms {
compileAndCompare("weeip-bbslist.c");
}
@Test
public void testUnion13() throws IOException {
compileAndCompare("union-13.c");
}
@Test
public void testUnion12() throws IOException {
compileAndCompare("union-12.c");
}
@Test
public void testUnion11() throws IOException {
compileAndCompare("union-11.c");
}
@Test
public void testUnion10() throws IOException {
compileAndCompare("union-10.c");
}
@Test
public void testUnion9() throws IOException {
compileAndCompare("union-9.c");
}
@Test
public void testUnion8() throws IOException {
compileAndCompare("union-8.c");

View File

@ -0,0 +1,8 @@
// Test that #pragma works with no parenthesis and no parameters
#pragma nobank
void main() {
char * const SCREEN = (char*) 0x0400;
*SCREEN = 'a';
}

27
src/test/kc/union-10.c Normal file
View File

@ -0,0 +1,27 @@
// More extensive union with C99 style designator initialization behaviour of the second element.
struct Move {
char f;
char t;
char s;
};
struct Turn {
char t;
char s;
char r;
char d;
};
union Data {
struct Move m;
struct Turn t;
};
union Data data = { .t={1,2,3,4} };
char* const SCREEN = (char*)0x0400;
void main() {
SCREEN[0] = data.m.f;
}

27
src/test/kc/union-11.c Normal file
View File

@ -0,0 +1,27 @@
// More extensive union with C99 style designator initialization behaviour of the first element.
struct Move {
char f;
char t;
char s;
};
struct Turn {
char t;
char s;
char r;
char d;
};
union Data {
struct Move m;
struct Turn t;
};
union Data data = { .m={1,2,3} };
char* const SCREEN = (char*)0x0400;
void main() {
SCREEN[0] = data.m.f;
}

29
src/test/kc/union-12.c Normal file
View File

@ -0,0 +1,29 @@
// More extensive union with C99 style designator initialization behaviour using const expressions.
struct Move {
char f;
char t;
char s;
};
struct Turn {
char t;
char s;
char r;
char d;
};
union Data {
struct Move m;
struct Turn t;
};
const struct Move move = {1,2,3};
union Data data = { .m=move };
char* const SCREEN = (char*)0x0400;
void main() {
SCREEN[0] = data.m.f;
}

20
src/test/kc/union-13.c Normal file
View File

@ -0,0 +1,20 @@
// More extensive union with C99 style designator initialization behaviour using const expressions.
union A {
unsigned char b;
unsigned int w;
};
union B {
union A a;
char b[4];
};
union B b1 = { .a={ .b=1 } };
char* const SCREEN = (char*)0x0400;
void main() {
SCREEN[0] = b1.b[0];
}

14
src/test/kc/union-9.c Normal file
View File

@ -0,0 +1,14 @@
// Minimal union with C99 style designator initialization behaviour.
union Data {
char b;
unsigned w;
};
union Data data = { .w=1234 };
char* const SCREEN = (char*)0x0400;
void main() {
SCREEN[0] = data.b;
}

View File

@ -6,10 +6,17 @@ struct Cols {
char bg;
};
struct Cols * const COLS = (struct Cols *)0xd020;
struct Cols * const COLS = (struct Cols * const)0xd020;
struct Cols a;
__varcall struct Cols make(char v) {
struct Cols c;
c.border = v;
c.bg = v+v;
return c;
}
void main() {
a = make(1);
*COLS = a;
@ -17,6 +24,3 @@ void main() {
*COLS = a;
}
__varcall struct Cols make(char v) {
return { v, v+v };
}

View File

@ -8,15 +8,15 @@ struct Cols {
struct Cols * const COLS = (struct Cols *)0xd020;
void main() {
struct Cols a = { 1, 2 };
//*COLS = a;
a = plus(a, { 2, 3 } );
*COLS = a;
//a = plus(a, a);
//*COLS = a;
}
__varcall struct Cols plus(struct Cols a, struct Cols b) {
return { a.border+b.border, a.bg+b.bg };
}
}
void main() {
struct Cols a = { 1, 2 };
struct Cols c = plus(a, { 2, 3 });
*COLS = c;
c = plus(c, a);
*COLS = c;
}

21
src/test/kc/varcall-7.c Normal file
View File

@ -0,0 +1,21 @@
// Test __varcall calling convention
// Struct parameter & return value - only a single call
struct Cols {
char border;
char bg;
};
struct Cols * const COLS = (struct Cols *)0xd020;
__varcall struct Cols plus(struct Cols a, struct Cols b) {
return { a.border+b.border, a.bg+b.bg };
}
void main() {
struct Cols a = { 1, 2 };
struct Cols b = { 2, 3 };
struct Cols c = plus(a, b);
*COLS = c;
}

28
src/test/kc/varcall-8.c Normal file
View File

@ -0,0 +1,28 @@
// Test __varcall calling convention
// Pointer to Struct parameter & return value
struct Cols {
char border;
char bg;
};
struct Cols * const COLS = (struct Cols *)0xd020;
__varcall struct Cols * min(struct Cols * a, struct Cols * b) {
if(a->bg < b->bg)
return a;
else
return b;
}
void main() {
struct Cols a = { 1, 7 };
struct Cols b = { 2, 6 };
struct Cols c = { 3, 5 };
struct Cols *m = min(&a,&b);
*COLS = *m;
m = min(m,&c);
*COLS = *m;
}

26
src/test/kc/varcall-9.c Normal file
View File

@ -0,0 +1,26 @@
// Test __varcall calling convention
// Struct of struct parameter value
struct Col {
char border;
char bg;
};
struct Cols {
struct Col normal;
struct Col error;
};
char * const COLS = (char*)0xd020;
__varcall char plus(struct Cols a, struct Cols b) {
return a.normal.border + b.normal.border + a.normal.bg + b.normal.bg + a.error.border + b.error.border + a.error.bg + b.error.bg;
}
void main() {
struct Cols a = { { 1, 2 }, { 3, 4 }};
struct Cols b = { { 5, 6 }, { 7, 8 }};
struct Cols c = { { 9, 10 }, { 11, 12 }};
*COLS = plus(a, b);
*COLS = plus(b, c);
}

View File

@ -0,0 +1,18 @@
// Test that #pragma works with no parenthesis and no parameters
// Commodore 64 PRG executable file
.file [name="pragma-noparam-noparen.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
.segment Code
main: {
.label SCREEN = $400
// *SCREEN = 'a'
lda #'a'
sta SCREEN
// }
rts
}

View File

@ -0,0 +1,8 @@
void main()
main: scope:[main] from
[0] *main::SCREEN = 'a'
to:main::@return
main::@return: scope:[main] from main
[1] return
to:@return

View File

@ -0,0 +1,135 @@
Warning! Unknown #pragma nobank
CONTROL FLOW GRAPH SSA
void main()
main: scope:[main] from __start
*main::SCREEN = 'a'
to:main::@return
main::@return: scope:[main] from main
return
to:@return
void __start()
__start: scope:[__start] from
call main
to:__start::@1
__start::@1: scope:[__start] from __start
to:__start::@return
__start::@return: scope:[__start] from __start::@1
return
to:@return
SYMBOL TABLE SSA
void __start()
void main()
__constant char * const main::SCREEN = (char *)$400
Simplifying constant pointer cast (char *) 1024
Successful SSA optimization PassNCastSimplification
Removing unused procedure __start
Removing unused procedure block __start
Removing unused procedure block __start::@1
Removing unused procedure block __start::@return
Successful SSA optimization PassNEliminateEmptyStart
CALL GRAPH
Created 0 initial phi equivalence classes
Coalesced down to 0 phi equivalence classes
FINAL CONTROL FLOW GRAPH
void main()
main: scope:[main] from
[0] *main::SCREEN = 'a'
to:main::@return
main::@return: scope:[main] from main
[1] return
to:@return
VARIABLE REGISTER WEIGHTS
void main()
Initial phi equivalence classes
Complete equivalence classes
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [0] *main::SCREEN = 'a' [ ] ( [ ] { } ) always clobbers reg byte a
REGISTER UPLIFT SCOPES
Uplift Scope [main]
Uplift Scope []
Uplifting [main] best 15 combination
Uplifting [] best 15 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Test that #pragma works with no parenthesis and no parameters
// Upstart
// Commodore 64 PRG executable file
.file [name="pragma-noparam-noparen.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
// Global Constants & labels
.segment Code
// main
main: {
.label SCREEN = $400
// [0] *main::SCREEN = 'a' -- _deref_pbuc1=vbuc2
lda #'a'
sta SCREEN
jmp __breturn
// main::@return
__breturn:
// [1] return
rts
}
// File Data
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction __breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
void main()
__constant char * const main::SCREEN = (char *) 1024
FINAL ASSEMBLER
Score: 12
// File Comments
// Test that #pragma works with no parenthesis and no parameters
// Upstart
// Commodore 64 PRG executable file
.file [name="pragma-noparam-noparen.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
// Global Constants & labels
.segment Code
// main
main: {
.label SCREEN = $400
// *SCREEN = 'a'
// [0] *main::SCREEN = 'a' -- _deref_pbuc1=vbuc2
lda #'a'
sta SCREEN
// main::@return
// }
// [1] return
rts
}
// File Data

View File

@ -0,0 +1,3 @@
void main()
__constant char * const main::SCREEN = (char *) 1024

20
src/test/ref/union-10.asm Normal file
View File

@ -0,0 +1,20 @@
// More extensive union with C99 style designator initialization behaviour of the second element.
// Commodore 64 PRG executable file
.file [name="union-10.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
.label SCREEN = $400
.segment Code
main: {
// SCREEN[0] = data.m.f
lda data
sta SCREEN
// }
rts
}
.segment Data
data: .byte 1, 2, 3, 4

View File

@ -0,0 +1,8 @@
void main()
main: scope:[main] from
[0] *SCREEN = *((char *)(struct Move *)&data)
to:main::@return
main::@return: scope:[main] from main
[1] return
to:@return

166
src/test/ref/union-10.log Normal file
View File

@ -0,0 +1,166 @@
CONTROL FLOW GRAPH SSA
void main()
main: scope:[main] from __start
SCREEN[0] = *((char *)(struct Move *)&data+OFFSET_UNION_DATA_M+OFFSET_STRUCT_MOVE_F)
to:main::@return
main::@return: scope:[main] from main
return
to:@return
void __start()
__start: scope:[__start] from
call main
to:__start::@1
__start::@1: scope:[__start] from __start
to:__start::@return
__start::@return: scope:[__start] from __start::@1
return
to:@return
SYMBOL TABLE SSA
__constant char OFFSET_STRUCT_MOVE_F = 0
__constant char OFFSET_UNION_DATA_M = 0
__constant char * const SCREEN = (char *)$400
void __start()
__loadstore union Data data = { t: { t: 1, s: 2, r: 3, d: 4 } }
void main()
Adding number conversion cast (unumber) 0 in SCREEN[0] = *((char *)(struct Move *)&data+OFFSET_UNION_DATA_M+OFFSET_STRUCT_MOVE_F)
Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant pointer cast (char *) 1024
Simplifying constant integer cast 0
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (char) 0
Successful SSA optimization PassNFinalizeNumberTypeConversions
Simplifying expression containing zero (char *)(struct Move *)&data+OFFSET_UNION_DATA_M in [0] SCREEN[0] = *((char *)(struct Move *)&data+OFFSET_UNION_DATA_M+OFFSET_STRUCT_MOVE_F)
Simplifying expression containing zero (struct Move *)&data in [0] SCREEN[0] = *((char *)(struct Move *)&data+OFFSET_UNION_DATA_M)
Simplifying expression containing zero SCREEN in [0] SCREEN[0] = *((char *)(struct Move *)&data)
Successful SSA optimization PassNSimplifyExpressionWithZero
Eliminating unused constant OFFSET_UNION_DATA_M
Eliminating unused constant OFFSET_STRUCT_MOVE_F
Successful SSA optimization PassNEliminateUnusedVars
Removing unused procedure __start
Removing unused procedure block __start
Removing unused procedure block __start::@1
Removing unused procedure block __start::@return
Successful SSA optimization PassNEliminateEmptyStart
CALL GRAPH
Created 0 initial phi equivalence classes
Coalesced down to 0 phi equivalence classes
FINAL CONTROL FLOW GRAPH
void main()
main: scope:[main] from
[0] *SCREEN = *((char *)(struct Move *)&data)
to:main::@return
main::@return: scope:[main] from main
[1] return
to:@return
VARIABLE REGISTER WEIGHTS
__loadstore union Data data = { t: { t: 1, s: 2, r: 3, d: 4 } }
void main()
Initial phi equivalence classes
Added variable data to live range equivalence class [ data ]
Complete equivalence classes
[ data ]
Allocated mem[4] [ data ]
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [0] *SCREEN = *((char *)(struct Move *)&data) [ ] ( [ ] { } ) always clobbers reg byte a
Potential registers mem[4] [ data ] : mem[4] ,
REGISTER UPLIFT SCOPES
Uplift Scope [Move]
Uplift Scope [Turn]
Uplift Scope [Data]
Uplift Scope [main]
Uplift Scope [] 0: mem[4] [ data ]
Uplifting [Move] best 17 combination
Uplifting [Turn] best 17 combination
Uplifting [Data] best 17 combination
Uplifting [main] best 17 combination
Uplifting [] best 17 combination mem[4] [ data ]
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// More extensive union with C99 style designator initialization behaviour of the second element.
// Upstart
// Commodore 64 PRG executable file
.file [name="union-10.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
// Global Constants & labels
.label SCREEN = $400
.segment Code
// main
main: {
// [0] *SCREEN = *((char *)(struct Move *)&data) -- _deref_pbuc1=_deref_pbuc2
lda data
sta SCREEN
jmp __breturn
// main::@return
__breturn:
// [1] return
rts
}
// File Data
.segment Data
data: .byte 1, 2, 3, 4
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction __breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
__constant char * const SCREEN = (char *) 1024
__loadstore union Data data = { t: { t: 1, s: 2, r: 3, d: 4 } } // mem[4]
void main()
mem[4] [ data ]
FINAL ASSEMBLER
Score: 14
// File Comments
// More extensive union with C99 style designator initialization behaviour of the second element.
// Upstart
// Commodore 64 PRG executable file
.file [name="union-10.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
// Global Constants & labels
.label SCREEN = $400
.segment Code
// main
main: {
// SCREEN[0] = data.m.f
// [0] *SCREEN = *((char *)(struct Move *)&data) -- _deref_pbuc1=_deref_pbuc2
lda data
sta SCREEN
// main::@return
// }
// [1] return
rts
}
// File Data
.segment Data
data: .byte 1, 2, 3, 4

View File

@ -0,0 +1,5 @@
__constant char * const SCREEN = (char *) 1024
__loadstore union Data data = { t: { t: 1, s: 2, r: 3, d: 4 } } // mem[4]
void main()
mem[4] [ data ]

21
src/test/ref/union-11.asm Normal file
View File

@ -0,0 +1,21 @@
// More extensive union with C99 style designator initialization behaviour of the first element.
// Commodore 64 PRG executable file
.file [name="union-11.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
.label SCREEN = $400
.segment Code
main: {
// SCREEN[0] = data.m.f
lda data
sta SCREEN
// }
rts
}
.segment Data
data: .byte 1, 2, 3
.fill 1, 0

View File

@ -0,0 +1,8 @@
void main()
main: scope:[main] from
[0] *SCREEN = *((char *)(struct Move *)&data)
to:main::@return
main::@return: scope:[main] from main
[1] return
to:@return

168
src/test/ref/union-11.log Normal file
View File

@ -0,0 +1,168 @@
CONTROL FLOW GRAPH SSA
void main()
main: scope:[main] from __start
SCREEN[0] = *((char *)(struct Move *)&data+OFFSET_UNION_DATA_M+OFFSET_STRUCT_MOVE_F)
to:main::@return
main::@return: scope:[main] from main
return
to:@return
void __start()
__start: scope:[__start] from
call main
to:__start::@1
__start::@1: scope:[__start] from __start
to:__start::@return
__start::@return: scope:[__start] from __start::@1
return
to:@return
SYMBOL TABLE SSA
__constant char OFFSET_STRUCT_MOVE_F = 0
__constant char OFFSET_UNION_DATA_M = 0
__constant char * const SCREEN = (char *)$400
void __start()
__loadstore union Data data = { m: { f: 1, t: 2, s: 3 } }
void main()
Adding number conversion cast (unumber) 0 in SCREEN[0] = *((char *)(struct Move *)&data+OFFSET_UNION_DATA_M+OFFSET_STRUCT_MOVE_F)
Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant pointer cast (char *) 1024
Simplifying constant integer cast 0
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (char) 0
Successful SSA optimization PassNFinalizeNumberTypeConversions
Simplifying expression containing zero (char *)(struct Move *)&data+OFFSET_UNION_DATA_M in [0] SCREEN[0] = *((char *)(struct Move *)&data+OFFSET_UNION_DATA_M+OFFSET_STRUCT_MOVE_F)
Simplifying expression containing zero (struct Move *)&data in [0] SCREEN[0] = *((char *)(struct Move *)&data+OFFSET_UNION_DATA_M)
Simplifying expression containing zero SCREEN in [0] SCREEN[0] = *((char *)(struct Move *)&data)
Successful SSA optimization PassNSimplifyExpressionWithZero
Eliminating unused constant OFFSET_UNION_DATA_M
Eliminating unused constant OFFSET_STRUCT_MOVE_F
Successful SSA optimization PassNEliminateUnusedVars
Removing unused procedure __start
Removing unused procedure block __start
Removing unused procedure block __start::@1
Removing unused procedure block __start::@return
Successful SSA optimization PassNEliminateEmptyStart
CALL GRAPH
Created 0 initial phi equivalence classes
Coalesced down to 0 phi equivalence classes
FINAL CONTROL FLOW GRAPH
void main()
main: scope:[main] from
[0] *SCREEN = *((char *)(struct Move *)&data)
to:main::@return
main::@return: scope:[main] from main
[1] return
to:@return
VARIABLE REGISTER WEIGHTS
__loadstore union Data data = { m: { f: 1, t: 2, s: 3 } }
void main()
Initial phi equivalence classes
Added variable data to live range equivalence class [ data ]
Complete equivalence classes
[ data ]
Allocated mem[4] [ data ]
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [0] *SCREEN = *((char *)(struct Move *)&data) [ ] ( [ ] { } ) always clobbers reg byte a
Potential registers mem[4] [ data ] : mem[4] ,
REGISTER UPLIFT SCOPES
Uplift Scope [Move]
Uplift Scope [Turn]
Uplift Scope [Data]
Uplift Scope [main]
Uplift Scope [] 0: mem[4] [ data ]
Uplifting [Move] best 17 combination
Uplifting [Turn] best 17 combination
Uplifting [Data] best 17 combination
Uplifting [main] best 17 combination
Uplifting [] best 17 combination mem[4] [ data ]
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// More extensive union with C99 style designator initialization behaviour of the first element.
// Upstart
// Commodore 64 PRG executable file
.file [name="union-11.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
// Global Constants & labels
.label SCREEN = $400
.segment Code
// main
main: {
// [0] *SCREEN = *((char *)(struct Move *)&data) -- _deref_pbuc1=_deref_pbuc2
lda data
sta SCREEN
jmp __breturn
// main::@return
__breturn:
// [1] return
rts
}
// File Data
.segment Data
data: .byte 1, 2, 3
.fill 1, 0
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction __breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
__constant char * const SCREEN = (char *) 1024
__loadstore union Data data = { m: { f: 1, t: 2, s: 3 } } // mem[4]
void main()
mem[4] [ data ]
FINAL ASSEMBLER
Score: 14
// File Comments
// More extensive union with C99 style designator initialization behaviour of the first element.
// Upstart
// Commodore 64 PRG executable file
.file [name="union-11.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
// Global Constants & labels
.label SCREEN = $400
.segment Code
// main
main: {
// SCREEN[0] = data.m.f
// [0] *SCREEN = *((char *)(struct Move *)&data) -- _deref_pbuc1=_deref_pbuc2
lda data
sta SCREEN
// main::@return
// }
// [1] return
rts
}
// File Data
.segment Data
data: .byte 1, 2, 3
.fill 1, 0

View File

@ -0,0 +1,5 @@
__constant char * const SCREEN = (char *) 1024
__loadstore union Data data = { m: { f: 1, t: 2, s: 3 } } // mem[4]
void main()
mem[4] [ data ]

21
src/test/ref/union-12.asm Normal file
View File

@ -0,0 +1,21 @@
// More extensive union with C99 style designator initialization behaviour using const expressions.
// Commodore 64 PRG executable file
.file [name="union-12.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
.label SCREEN = $400
.segment Code
main: {
// SCREEN[0] = data.m.f
lda data
sta SCREEN
// }
rts
}
.segment Data
move: .byte 1, 2, 3
data: .fill 1, 0

View File

@ -0,0 +1,8 @@
void main()
main: scope:[main] from
[0] *SCREEN = *((char *)(struct Move *)&data)
to:main::@return
main::@return: scope:[main] from main
[1] return
to:@return

170
src/test/ref/union-12.log Normal file
View File

@ -0,0 +1,170 @@
CONTROL FLOW GRAPH SSA
void main()
main: scope:[main] from __start
SCREEN[0] = *((char *)(struct Move *)&data+OFFSET_UNION_DATA_M+OFFSET_STRUCT_MOVE_F)
to:main::@return
main::@return: scope:[main] from main
return
to:@return
void __start()
__start: scope:[__start] from
call main
to:__start::@1
__start::@1: scope:[__start] from __start
to:__start::@return
__start::@return: scope:[__start] from __start::@1
return
to:@return
SYMBOL TABLE SSA
__constant char OFFSET_STRUCT_MOVE_F = 0
__constant char OFFSET_UNION_DATA_M = 0
__constant char * const SCREEN = (char *)$400
void __start()
__loadstore union Data data = { m: move }
void main()
__constant const struct Move move = { f: 1, t: 2, s: 3 }
Adding number conversion cast (unumber) 0 in SCREEN[0] = *((char *)(struct Move *)&data+OFFSET_UNION_DATA_M+OFFSET_STRUCT_MOVE_F)
Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant pointer cast (char *) 1024
Simplifying constant integer cast 0
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (char) 0
Successful SSA optimization PassNFinalizeNumberTypeConversions
Simplifying expression containing zero (char *)(struct Move *)&data+OFFSET_UNION_DATA_M in [0] SCREEN[0] = *((char *)(struct Move *)&data+OFFSET_UNION_DATA_M+OFFSET_STRUCT_MOVE_F)
Simplifying expression containing zero (struct Move *)&data in [0] SCREEN[0] = *((char *)(struct Move *)&data+OFFSET_UNION_DATA_M)
Simplifying expression containing zero SCREEN in [0] SCREEN[0] = *((char *)(struct Move *)&data)
Successful SSA optimization PassNSimplifyExpressionWithZero
Eliminating unused constant OFFSET_UNION_DATA_M
Eliminating unused constant OFFSET_STRUCT_MOVE_F
Successful SSA optimization PassNEliminateUnusedVars
Removing unused procedure __start
Removing unused procedure block __start
Removing unused procedure block __start::@1
Removing unused procedure block __start::@return
Successful SSA optimization PassNEliminateEmptyStart
CALL GRAPH
Created 0 initial phi equivalence classes
Coalesced down to 0 phi equivalence classes
FINAL CONTROL FLOW GRAPH
void main()
main: scope:[main] from
[0] *SCREEN = *((char *)(struct Move *)&data)
to:main::@return
main::@return: scope:[main] from main
[1] return
to:@return
VARIABLE REGISTER WEIGHTS
__loadstore union Data data = { m: move }
void main()
Initial phi equivalence classes
Added variable data to live range equivalence class [ data ]
Complete equivalence classes
[ data ]
Allocated mem[4] [ data ]
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [0] *SCREEN = *((char *)(struct Move *)&data) [ ] ( [ ] { } ) always clobbers reg byte a
Potential registers mem[4] [ data ] : mem[4] ,
REGISTER UPLIFT SCOPES
Uplift Scope [Move]
Uplift Scope [Turn]
Uplift Scope [Data]
Uplift Scope [main]
Uplift Scope [] 0: mem[4] [ data ]
Uplifting [Move] best 17 combination
Uplifting [Turn] best 17 combination
Uplifting [Data] best 17 combination
Uplifting [main] best 17 combination
Uplifting [] best 17 combination mem[4] [ data ]
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// More extensive union with C99 style designator initialization behaviour using const expressions.
// Upstart
// Commodore 64 PRG executable file
.file [name="union-12.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
// Global Constants & labels
.label SCREEN = $400
.segment Code
// main
main: {
// [0] *SCREEN = *((char *)(struct Move *)&data) -- _deref_pbuc1=_deref_pbuc2
lda data
sta SCREEN
jmp __breturn
// main::@return
__breturn:
// [1] return
rts
}
// File Data
.segment Data
move: .byte 1, 2, 3
data: .fill 1, 0
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction __breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
__constant char * const SCREEN = (char *) 1024
__loadstore union Data data = { m: move } // mem[4]
void main()
__constant const struct Move move = { f: 1, t: 2, s: 3 }
mem[4] [ data ]
FINAL ASSEMBLER
Score: 14
// File Comments
// More extensive union with C99 style designator initialization behaviour using const expressions.
// Upstart
// Commodore 64 PRG executable file
.file [name="union-12.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
// Global Constants & labels
.label SCREEN = $400
.segment Code
// main
main: {
// SCREEN[0] = data.m.f
// [0] *SCREEN = *((char *)(struct Move *)&data) -- _deref_pbuc1=_deref_pbuc2
lda data
sta SCREEN
// main::@return
// }
// [1] return
rts
}
// File Data
.segment Data
move: .byte 1, 2, 3
data: .fill 1, 0

View File

@ -0,0 +1,6 @@
__constant char * const SCREEN = (char *) 1024
__loadstore union Data data = { m: move } // mem[4]
void main()
__constant const struct Move move = { f: 1, t: 2, s: 3 }
mem[4] [ data ]

22
src/test/ref/union-13.asm Normal file
View File

@ -0,0 +1,22 @@
// More extensive union with C99 style designator initialization behaviour using const expressions.
// Commodore 64 PRG executable file
.file [name="union-13.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
.label SCREEN = $400
.segment Code
main: {
// SCREEN[0] = b1.b[0]
lda b1
sta SCREEN
// }
rts
}
.segment Data
b1: .byte 1
.fill 1, 0
.fill 2, 0

View File

@ -0,0 +1,8 @@
void main()
main: scope:[main] from
[0] *SCREEN = *((char *)&b1)
to:main::@return
main::@return: scope:[main] from main
[1] return
to:@return

176
src/test/ref/union-13.log Normal file
View File

@ -0,0 +1,176 @@
Fixing struct type size union B to 4
Fixing struct type size union B to 4
Fixing struct type SIZE_OF union B to 4
Fixing struct type SIZE_OF union B to 4
CONTROL FLOW GRAPH SSA
void main()
main: scope:[main] from __start
SCREEN[0] = ((char *)&b1+OFFSET_UNION_B_B)[0]
to:main::@return
main::@return: scope:[main] from main
return
to:@return
void __start()
__start: scope:[__start] from
call main
to:__start::@1
__start::@1: scope:[__start] from __start
to:__start::@return
__start::@return: scope:[__start] from __start::@1
return
to:@return
SYMBOL TABLE SSA
__constant char OFFSET_UNION_B_B = 0
__constant char * const SCREEN = (char *)$400
void __start()
__loadstore union B b1 = { a: { b: 1 } }
void main()
Adding number conversion cast (unumber) 0 in SCREEN[0] = ((char *)&b1+OFFSET_UNION_B_B)[0]
Adding number conversion cast (unumber) 0 in SCREEN[0] = ((char *)&b1+OFFSET_UNION_B_B)[(unumber)0]
Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant pointer cast (char *) 1024
Simplifying constant integer cast 0
Simplifying constant integer cast 0
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (char) 0
Finalized unsigned number type (char) 0
Successful SSA optimization PassNFinalizeNumberTypeConversions
Simplifying expression containing zero (char *)&b1+OFFSET_UNION_B_B in [0] SCREEN[0] = ((char *)&b1+OFFSET_UNION_B_B)[0]
Simplifying expression containing zero (char *)&b1 in [0] SCREEN[0] = *((char *)&b1+OFFSET_UNION_B_B)
Simplifying expression containing zero SCREEN in [0] SCREEN[0] = *((char *)&b1)
Successful SSA optimization PassNSimplifyExpressionWithZero
Eliminating unused constant OFFSET_UNION_B_B
Successful SSA optimization PassNEliminateUnusedVars
Removing unused procedure __start
Removing unused procedure block __start
Removing unused procedure block __start::@1
Removing unused procedure block __start::@return
Successful SSA optimization PassNEliminateEmptyStart
Finalized unsigned number type (char) 4
Finalized unsigned number type (char) 4
Successful SSA optimization PassNFinalizeNumberTypeConversions
CALL GRAPH
Created 0 initial phi equivalence classes
Coalesced down to 0 phi equivalence classes
FINAL CONTROL FLOW GRAPH
void main()
main: scope:[main] from
[0] *SCREEN = *((char *)&b1)
to:main::@return
main::@return: scope:[main] from main
[1] return
to:@return
VARIABLE REGISTER WEIGHTS
__loadstore union B b1 = { a: { b: 1 } }
void main()
Initial phi equivalence classes
Added variable b1 to live range equivalence class [ b1 ]
Complete equivalence classes
[ b1 ]
Allocated mem[4] [ b1 ]
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [0] *SCREEN = *((char *)&b1) [ ] ( [ ] { } ) always clobbers reg byte a
Potential registers mem[4] [ b1 ] : mem[4] ,
REGISTER UPLIFT SCOPES
Uplift Scope [A]
Uplift Scope [B]
Uplift Scope [main]
Uplift Scope [] 0: mem[4] [ b1 ]
Uplifting [A] best 17 combination
Uplifting [B] best 17 combination
Uplifting [main] best 17 combination
Uplifting [] best 17 combination mem[4] [ b1 ]
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// More extensive union with C99 style designator initialization behaviour using const expressions.
// Upstart
// Commodore 64 PRG executable file
.file [name="union-13.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
// Global Constants & labels
.label SCREEN = $400
.segment Code
// main
main: {
// [0] *SCREEN = *((char *)&b1) -- _deref_pbuc1=_deref_pbuc2
lda b1
sta SCREEN
jmp __breturn
// main::@return
__breturn:
// [1] return
rts
}
// File Data
.segment Data
b1: .byte 1
.fill 1, 0
.fill 2, 0
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction __breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
__constant char * const SCREEN = (char *) 1024
__loadstore union B b1 = { a: { b: 1 } } // mem[4]
void main()
mem[4] [ b1 ]
FINAL ASSEMBLER
Score: 14
// File Comments
// More extensive union with C99 style designator initialization behaviour using const expressions.
// Upstart
// Commodore 64 PRG executable file
.file [name="union-13.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
// Global Constants & labels
.label SCREEN = $400
.segment Code
// main
main: {
// SCREEN[0] = b1.b[0]
// [0] *SCREEN = *((char *)&b1) -- _deref_pbuc1=_deref_pbuc2
lda b1
sta SCREEN
// main::@return
// }
// [1] return
rts
}
// File Data
.segment Data
b1: .byte 1
.fill 1, 0
.fill 2, 0

View File

@ -0,0 +1,5 @@
__constant char * const SCREEN = (char *) 1024
__loadstore union B b1 = { a: { b: 1 } } // mem[4]
void main()
mem[4] [ b1 ]

20
src/test/ref/union-9.asm Normal file
View File

@ -0,0 +1,20 @@
// Minimal union with C99 style designator initialization behaviour.
// Commodore 64 PRG executable file
.file [name="union-9.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
.label SCREEN = $400
.segment Code
main: {
// SCREEN[0] = data.b
lda data
sta SCREEN
// }
rts
}
.segment Data
data: .word $4d2

8
src/test/ref/union-9.cfg Normal file
View File

@ -0,0 +1,8 @@
void main()
main: scope:[main] from
[0] *SCREEN = *((char *)&data)
to:main::@return
main::@return: scope:[main] from main
[1] return
to:@return

159
src/test/ref/union-9.log Normal file
View File

@ -0,0 +1,159 @@
CONTROL FLOW GRAPH SSA
void main()
main: scope:[main] from __start
SCREEN[0] = *((char *)&data+OFFSET_UNION_DATA_B)
to:main::@return
main::@return: scope:[main] from main
return
to:@return
void __start()
__start: scope:[__start] from
call main
to:__start::@1
__start::@1: scope:[__start] from __start
to:__start::@return
__start::@return: scope:[__start] from __start::@1
return
to:@return
SYMBOL TABLE SSA
__constant char OFFSET_UNION_DATA_B = 0
__constant char * const SCREEN = (char *)$400
void __start()
__loadstore union Data data = { w: $4d2 }
void main()
Adding number conversion cast (unumber) 0 in SCREEN[0] = *((char *)&data+OFFSET_UNION_DATA_B)
Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant pointer cast (char *) 1024
Simplifying constant integer cast 0
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (char) 0
Successful SSA optimization PassNFinalizeNumberTypeConversions
Simplifying expression containing zero (char *)&data in [0] SCREEN[0] = *((char *)&data+OFFSET_UNION_DATA_B)
Simplifying expression containing zero SCREEN in [0] SCREEN[0] = *((char *)&data)
Successful SSA optimization PassNSimplifyExpressionWithZero
Eliminating unused constant OFFSET_UNION_DATA_B
Successful SSA optimization PassNEliminateUnusedVars
Removing unused procedure __start
Removing unused procedure block __start
Removing unused procedure block __start::@1
Removing unused procedure block __start::@return
Successful SSA optimization PassNEliminateEmptyStart
CALL GRAPH
Created 0 initial phi equivalence classes
Coalesced down to 0 phi equivalence classes
FINAL CONTROL FLOW GRAPH
void main()
main: scope:[main] from
[0] *SCREEN = *((char *)&data)
to:main::@return
main::@return: scope:[main] from main
[1] return
to:@return
VARIABLE REGISTER WEIGHTS
__loadstore union Data data = { w: $4d2 }
void main()
Initial phi equivalence classes
Added variable data to live range equivalence class [ data ]
Complete equivalence classes
[ data ]
Allocated mem[2] [ data ]
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [0] *SCREEN = *((char *)&data) [ ] ( [ ] { } ) always clobbers reg byte a
Potential registers mem[2] [ data ] : mem[2] ,
REGISTER UPLIFT SCOPES
Uplift Scope [Data]
Uplift Scope [main]
Uplift Scope [] 0: mem[2] [ data ]
Uplifting [Data] best 17 combination
Uplifting [main] best 17 combination
Uplifting [] best 17 combination mem[2] [ data ]
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Minimal union with C99 style designator initialization behaviour.
// Upstart
// Commodore 64 PRG executable file
.file [name="union-9.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
// Global Constants & labels
.label SCREEN = $400
.segment Code
// main
main: {
// [0] *SCREEN = *((char *)&data) -- _deref_pbuc1=_deref_pbuc2
lda data
sta SCREEN
jmp __breturn
// main::@return
__breturn:
// [1] return
rts
}
// File Data
.segment Data
data: .word $4d2
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction __breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
__constant char * const SCREEN = (char *) 1024
__loadstore union Data data = { w: $4d2 } // mem[2]
void main()
mem[2] [ data ]
FINAL ASSEMBLER
Score: 14
// File Comments
// Minimal union with C99 style designator initialization behaviour.
// Upstart
// Commodore 64 PRG executable file
.file [name="union-9.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
// Global Constants & labels
.label SCREEN = $400
.segment Code
// main
main: {
// SCREEN[0] = data.b
// [0] *SCREEN = *((char *)&data) -- _deref_pbuc1=_deref_pbuc2
lda data
sta SCREEN
// main::@return
// }
// [1] return
rts
}
// File Data
.segment Data
data: .word $4d2

5
src/test/ref/union-9.sym Normal file
View File

@ -0,0 +1,5 @@
__constant char * const SCREEN = (char *) 1024
__loadstore union Data data = { w: $4d2 } // mem[2]
void main()
mem[2] [ data ]

View File

@ -0,0 +1,69 @@
// Test __varcall calling convention
// Struct return value
// Commodore 64 PRG executable file
.file [name="varcall-5.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
.const OFFSET_STRUCT_COLS_BG = 1
.const SIZEOF_STRUCT_COLS = 2
.label COLS = $d020
.segment Code
main: {
// make(1)
lda #1
sta.z make.v
jsr make
ldx.z make.return_border
lda.z make.return_bg
// a = make(1)
stx a
sta a+OFFSET_STRUCT_COLS_BG
// *COLS = a
ldy #SIZEOF_STRUCT_COLS
!:
lda a-1,y
sta COLS-1,y
dey
bne !-
// make(2)
lda #2
sta.z make.v
jsr make
ldx.z make.return_border
lda.z make.return_bg
// a = make(2)
stx a
sta a+OFFSET_STRUCT_COLS_BG
// *COLS = a
ldy #SIZEOF_STRUCT_COLS
!:
lda a-1,y
sta COLS-1,y
dey
bne !-
// }
rts
}
// struct Cols make(__zp(2) char v)
make: {
.label v = 2
.label return_border = 3
.label return_bg = 4
// c.border = v
ldx.z v
// v+v
txa
asl
// c.bg = v+v
// return c;
stx.z return_border
sta.z return_bg
// }
rts
}
.segment Data
a: .fill SIZEOF_STRUCT_COLS, 0

View File

@ -0,0 +1,33 @@
void main()
main: scope:[main] from
[0] make::v = 1
[1] callexecute make
[2] main::$0_border = make::return_border
[3] main::$0_bg = make::return_bg
[4] *((char *)&a) = main::$0_border
[5] *((char *)&a+OFFSET_STRUCT_COLS_BG) = main::$0_bg
[6] *COLS = memcpy(*(&a), struct Cols, SIZEOF_STRUCT_COLS)
[7] make::v = 2
[8] callexecute make
[9] main::$1_border = make::return_border
[10] main::$1_bg = make::return_bg
[11] *((char *)&a) = main::$1_border
[12] *((char *)&a+OFFSET_STRUCT_COLS_BG) = main::$1_bg
[13] *COLS = memcpy(*(&a), struct Cols, SIZEOF_STRUCT_COLS)
to:main::@return
main::@return: scope:[main] from main
[14] return
to:@return
__varcall struct Cols make(char v)
make: scope:[make] from
[15] make::c_border#1 = make::v
[16] make::$0 = make::v + make::v
[17] make::c_bg#1 = make::$0
[18] make::return_border = make::c_border#1
[19] make::return_bg = make::c_bg#1
to:make::@return
make::@return: scope:[make] from make
[20] return
to:@return

496
src/test/ref/varcall-5.log Normal file
View File

@ -0,0 +1,496 @@
Converting parameter in __varcall procedure to load/store make::v
Converting return in __varcall procedure to load/store make::return
Eliminating unused variable with no statement main::$0
Eliminating unused variable with no statement main::$1
Calling convention __varcall adding prepare/execute/finalize for { main::$0_border, main::$0_bg } = call make(1)
Calling convention __varcall adding prepare/execute/finalize for { main::$1_border, main::$1_bg } = call make(2)
Removing C-classic struct-unwound assignment a = struct-unwound {*((char *)&a+OFFSET_STRUCT_COLS_BORDER), *((char *)&a+OFFSET_STRUCT_COLS_BG)}
Removing C-classic struct-unwound assignment a = struct-unwound {*((char *)&a+OFFSET_STRUCT_COLS_BORDER), *((char *)&a+OFFSET_STRUCT_COLS_BG)}
CONTROL FLOW GRAPH SSA
__varcall struct Cols make(char v)
make: scope:[make] from
make::c_border#0 = 0
make::c_bg#0 = 0
make::c_border#1 = make::v
make::$0 = make::v + make::v
make::c_bg#1 = make::$0
make::return_border = make::c_border#1
make::return_bg = make::c_bg#1
make::return = struct-unwound {make::return_border, make::return_bg}
to:make::@return
make::@return: scope:[make] from make
return
to:@return
void main()
main: scope:[main] from __start
make::v = 1
callexecute make
main::$0_border = make::return_border
main::$0_bg = make::return_bg
*((char *)&a+OFFSET_STRUCT_COLS_BORDER) = main::$0_border
*((char *)&a+OFFSET_STRUCT_COLS_BG) = main::$0_bg
*COLS = memcpy(*(&a), struct Cols, SIZEOF_STRUCT_COLS)
make::v = 2
callexecute make
main::$1_border = make::return_border
main::$1_bg = make::return_bg
*((char *)&a+OFFSET_STRUCT_COLS_BORDER) = main::$1_border
*((char *)&a+OFFSET_STRUCT_COLS_BG) = main::$1_bg
*COLS = memcpy(*(&a), struct Cols, SIZEOF_STRUCT_COLS)
to:main::@return
main::@return: scope:[main] from main
return
to:@return
void __start()
__start: scope:[__start] from
call main
to:__start::@1
__start::@1: scope:[__start] from __start
to:__start::@return
__start::@return: scope:[__start] from __start::@1
return
to:@return
SYMBOL TABLE SSA
__constant struct Cols * const COLS = (struct Cols * const )$d020
__constant char OFFSET_STRUCT_COLS_BG = 1
__constant char OFFSET_STRUCT_COLS_BORDER = 0
__constant char SIZEOF_STRUCT_COLS = 2
void __start()
__loadstore struct Cols a = {}
void main()
char main::$0_bg
char main::$0_border
char main::$1_bg
char main::$1_border
__varcall struct Cols make(char v)
char make::$0
char make::c_bg
char make::c_bg#0
char make::c_bg#1
char make::c_border
char make::c_border#0
char make::c_border#1
__loadstore struct Cols make::return
__loadstore char make::return_bg
__loadstore char make::return_border
__loadstore char make::v
Adding number conversion cast (unumber) 1 in make::v = 1
Adding number conversion cast (unumber) 2 in make::v = 2
Successful SSA optimization PassNAddNumberTypeConversions
Inlining cast make::v = (unumber)1
Inlining cast make::v = (unumber)2
Successful SSA optimization Pass2InlineCast
Simplifying constant pointer cast (struct Cols *) 53280
Simplifying constant integer cast 1
Simplifying constant integer cast 2
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (char) 1
Finalized unsigned number type (char) 2
Successful SSA optimization PassNFinalizeNumberTypeConversions
Alias candidate removed (volatile)make::c_bg#1 = make::$0 make::return_bg
Alias candidate removed (volatile)make::c_border#1 = make::return_border
Constant make::c_border#0 = 0
Constant make::c_bg#0 = 0
Successful SSA optimization Pass2ConstantIdentification
Simplifying expression containing zero (char *)&a in [13] *((char *)&a+OFFSET_STRUCT_COLS_BORDER) = main::$0_border
Simplifying expression containing zero (char *)&a in [20] *((char *)&a+OFFSET_STRUCT_COLS_BORDER) = main::$1_border
Successful SSA optimization PassNSimplifyExpressionWithZero
Eliminating unused variable make::return and assignment [5] make::return = struct-unwound {make::return_border, make::return_bg}
Eliminating unused constant make::c_border#0
Eliminating unused constant make::c_bg#0
Eliminating unused constant OFFSET_STRUCT_COLS_BORDER
Successful SSA optimization PassNEliminateUnusedVars
Removing unused procedure __start
Removing unused procedure block __start
Removing unused procedure block __start::@1
Removing unused procedure block __start::@return
Successful SSA optimization PassNEliminateEmptyStart
Alias candidate removed (volatile)make::c_bg#1 = make::$0 make::return_bg
Alias candidate removed (volatile)make::c_border#1 = make::return_border
Alias candidate removed (volatile)make::c_bg#1 = make::$0 make::return_bg
Alias candidate removed (volatile)make::c_border#1 = make::return_border
Alias candidate removed (volatile)make::c_bg#1 = make::$0 make::return_bg
Alias candidate removed (volatile)make::c_border#1 = make::return_border
CALL GRAPH
Calls in [main] to make:1 make:8
Created 0 initial phi equivalence classes
Coalesced down to 0 phi equivalence classes
FINAL CONTROL FLOW GRAPH
void main()
main: scope:[main] from
[0] make::v = 1
[1] callexecute make
[2] main::$0_border = make::return_border
[3] main::$0_bg = make::return_bg
[4] *((char *)&a) = main::$0_border
[5] *((char *)&a+OFFSET_STRUCT_COLS_BG) = main::$0_bg
[6] *COLS = memcpy(*(&a), struct Cols, SIZEOF_STRUCT_COLS)
[7] make::v = 2
[8] callexecute make
[9] main::$1_border = make::return_border
[10] main::$1_bg = make::return_bg
[11] *((char *)&a) = main::$1_border
[12] *((char *)&a+OFFSET_STRUCT_COLS_BG) = main::$1_bg
[13] *COLS = memcpy(*(&a), struct Cols, SIZEOF_STRUCT_COLS)
to:main::@return
main::@return: scope:[main] from main
[14] return
to:@return
__varcall struct Cols make(char v)
make: scope:[make] from
[15] make::c_border#1 = make::v
[16] make::$0 = make::v + make::v
[17] make::c_bg#1 = make::$0
[18] make::return_border = make::c_border#1
[19] make::return_bg = make::c_bg#1
to:make::@return
make::@return: scope:[make] from make
[20] return
to:@return
VARIABLE REGISTER WEIGHTS
__loadstore struct Cols a = {}
void main()
char main::$0_bg // 2.0
char main::$0_border // 2.0
char main::$1_bg // 2.0
char main::$1_border // 2.0
__varcall struct Cols make(char v)
char make::$0 // 22.0
char make::c_bg
char make::c_bg#1 // 11.0
char make::c_border
char make::c_border#1 // 7.333333333333333
__loadstore char make::return_bg // 2.5
__loadstore char make::return_border // 3.0
__loadstore char make::v // 12.333333333333332
Initial phi equivalence classes
Added variable make::v to live range equivalence class [ make::v ]
Added variable main::$0_border to live range equivalence class [ main::$0_border ]
Added variable main::$0_bg to live range equivalence class [ main::$0_bg ]
Added variable main::$1_border to live range equivalence class [ main::$1_border ]
Added variable main::$1_bg to live range equivalence class [ main::$1_bg ]
Added variable make::c_border#1 to live range equivalence class [ make::c_border#1 ]
Added variable make::$0 to live range equivalence class [ make::$0 ]
Added variable make::c_bg#1 to live range equivalence class [ make::c_bg#1 ]
Added variable make::return_border to live range equivalence class [ make::return_border ]
Added variable make::return_bg to live range equivalence class [ make::return_bg ]
Added variable a to live range equivalence class [ a ]
Complete equivalence classes
[ make::v ]
[ main::$0_border ]
[ main::$0_bg ]
[ main::$1_border ]
[ main::$1_bg ]
[ make::c_border#1 ]
[ make::$0 ]
[ make::c_bg#1 ]
[ make::return_border ]
[ make::return_bg ]
[ a ]
Allocated zp[1]:2 [ make::$0 ]
Allocated zp[1]:3 [ make::v ]
Allocated zp[1]:4 [ make::c_bg#1 ]
Allocated zp[1]:5 [ make::c_border#1 ]
Allocated zp[1]:6 [ make::return_border ]
Allocated zp[1]:7 [ make::return_bg ]
Allocated zp[1]:8 [ main::$0_border ]
Allocated zp[1]:9 [ main::$0_bg ]
Allocated zp[1]:10 [ main::$1_border ]
Allocated zp[1]:11 [ main::$1_bg ]
Allocated mem[2] [ a ]
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [0] make::v = 1 [ make::v a ] ( [ make::v a ] { } ) always clobbers reg byte a
Statement [6] *COLS = memcpy(*(&a), struct Cols, SIZEOF_STRUCT_COLS) [ a ] ( [ a ] { } ) always clobbers reg byte a reg byte y
Statement [7] make::v = 2 [ make::v a ] ( [ make::v a ] { } ) always clobbers reg byte a
Statement [13] *COLS = memcpy(*(&a), struct Cols, SIZEOF_STRUCT_COLS) [ ] ( [ ] { } ) always clobbers reg byte a reg byte y
Statement [16] make::$0 = make::v + make::v [ make::c_border#1 make::$0 ] ( make:1 [ a make::c_border#1 make::$0 ] { } make:8 [ a make::c_border#1 make::$0 ] { } ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp[1]:5 [ make::c_border#1 ]
Statement [0] make::v = 1 [ make::v a ] ( [ make::v a ] { } ) always clobbers reg byte a
Statement [6] *COLS = memcpy(*(&a), struct Cols, SIZEOF_STRUCT_COLS) [ a ] ( [ a ] { } ) always clobbers reg byte a reg byte y
Statement [7] make::v = 2 [ make::v a ] ( [ make::v a ] { } ) always clobbers reg byte a
Statement [13] *COLS = memcpy(*(&a), struct Cols, SIZEOF_STRUCT_COLS) [ ] ( [ ] { } ) always clobbers reg byte a reg byte y
Statement [16] make::$0 = make::v + make::v [ make::c_border#1 make::$0 ] ( make:1 [ a make::c_border#1 make::$0 ] { } make:8 [ a make::c_border#1 make::$0 ] { } ) always clobbers reg byte a
Potential registers zp[1]:3 [ make::v ] : zp[1]:3 ,
Potential registers zp[1]:8 [ main::$0_border ] : zp[1]:8 , reg byte a , reg byte x , reg byte y ,
Potential registers zp[1]:9 [ main::$0_bg ] : zp[1]:9 , reg byte a , reg byte x , reg byte y ,
Potential registers zp[1]:10 [ main::$1_border ] : zp[1]:10 , reg byte a , reg byte x , reg byte y ,
Potential registers zp[1]:11 [ main::$1_bg ] : zp[1]:11 , reg byte a , reg byte x , reg byte y ,
Potential registers zp[1]:5 [ make::c_border#1 ] : zp[1]:5 , reg byte x , reg byte y ,
Potential registers zp[1]:2 [ make::$0 ] : zp[1]:2 , reg byte a , reg byte x , reg byte y ,
Potential registers zp[1]:4 [ make::c_bg#1 ] : zp[1]:4 , reg byte a , reg byte x , reg byte y ,
Potential registers zp[1]:6 [ make::return_border ] : zp[1]:6 ,
Potential registers zp[1]:7 [ make::return_bg ] : zp[1]:7 ,
Potential registers mem[2] [ a ] : mem[2] ,
REGISTER UPLIFT SCOPES
Uplift Scope [make] 22: zp[1]:2 [ make::$0 ] 12.33: zp[1]:3 [ make::v ] 11: zp[1]:4 [ make::c_bg#1 ] 7.33: zp[1]:5 [ make::c_border#1 ] 3: zp[1]:6 [ make::return_border ] 2.5: zp[1]:7 [ make::return_bg ]
Uplift Scope [main] 2: zp[1]:8 [ main::$0_border ] 2: zp[1]:9 [ main::$0_bg ] 2: zp[1]:10 [ main::$1_border ] 2: zp[1]:11 [ main::$1_bg ]
Uplift Scope [Cols]
Uplift Scope [] 0: mem[2] [ a ]
Uplifting [make] best 138 combination reg byte a [ make::$0 ] zp[1]:3 [ make::v ] reg byte a [ make::c_bg#1 ] reg byte x [ make::c_border#1 ] zp[1]:6 [ make::return_border ] zp[1]:7 [ make::return_bg ]
Uplifting [main] best 120 combination reg byte x [ main::$0_border ] reg byte a [ main::$0_bg ] reg byte x [ main::$1_border ] zp[1]:11 [ main::$1_bg ]
Limited combination testing to 100 combinations of 256 possible.
Uplifting [Cols] best 120 combination
Uplifting [] best 120 combination mem[2] [ a ]
Attempting to uplift remaining variables inzp[1]:3 [ make::v ]
Uplifting [make] best 120 combination zp[1]:3 [ make::v ]
Attempting to uplift remaining variables inzp[1]:6 [ make::return_border ]
Uplifting [make] best 120 combination zp[1]:6 [ make::return_border ]
Attempting to uplift remaining variables inzp[1]:7 [ make::return_bg ]
Uplifting [make] best 120 combination zp[1]:7 [ make::return_bg ]
Attempting to uplift remaining variables inzp[1]:11 [ main::$1_bg ]
Uplifting [main] best 114 combination reg byte a [ main::$1_bg ]
Allocated (was zp[1]:3) zp[1]:2 [ make::v ]
Allocated (was zp[1]:6) zp[1]:3 [ make::return_border ]
Allocated (was zp[1]:7) zp[1]:4 [ make::return_bg ]
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Test __varcall calling convention
// Struct return value
// Upstart
// Commodore 64 PRG executable file
.file [name="varcall-5.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
// Global Constants & labels
.const OFFSET_STRUCT_COLS_BG = 1
.const SIZEOF_STRUCT_COLS = 2
.label COLS = $d020
.segment Code
// main
main: {
// [0] make::v = 1 -- vbuz1=vbuc1
lda #1
sta.z make.v
// [1] callexecute make -- call_vprc1
jsr make
// [2] main::$0_border = make::return_border -- vbuxx=vbuz1
ldx.z make.return_border
// [3] main::$0_bg = make::return_bg -- vbuaa=vbuz1
lda.z make.return_bg
// [4] *((char *)&a) = main::$0_border -- _deref_pbuc1=vbuxx
stx a
// [5] *((char *)&a+OFFSET_STRUCT_COLS_BG) = main::$0_bg -- _deref_pbuc1=vbuaa
sta a+OFFSET_STRUCT_COLS_BG
// [6] *COLS = memcpy(*(&a), struct Cols, SIZEOF_STRUCT_COLS) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3
ldy #SIZEOF_STRUCT_COLS
!:
lda a-1,y
sta COLS-1,y
dey
bne !-
// [7] make::v = 2 -- vbuz1=vbuc1
lda #2
sta.z make.v
// [8] callexecute make -- call_vprc1
jsr make
// [9] main::$1_border = make::return_border -- vbuxx=vbuz1
ldx.z make.return_border
// [10] main::$1_bg = make::return_bg -- vbuaa=vbuz1
lda.z make.return_bg
// [11] *((char *)&a) = main::$1_border -- _deref_pbuc1=vbuxx
stx a
// [12] *((char *)&a+OFFSET_STRUCT_COLS_BG) = main::$1_bg -- _deref_pbuc1=vbuaa
sta a+OFFSET_STRUCT_COLS_BG
// [13] *COLS = memcpy(*(&a), struct Cols, SIZEOF_STRUCT_COLS) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3
ldy #SIZEOF_STRUCT_COLS
!:
lda a-1,y
sta COLS-1,y
dey
bne !-
jmp __breturn
// main::@return
__breturn:
// [14] return
rts
}
// make
// struct Cols make(__zp(2) char v)
make: {
.label v = 2
.label return_border = 3
.label return_bg = 4
// [15] make::c_border#1 = make::v -- vbuxx=vbuz1
ldx.z v
// [16] make::$0 = make::v + make::v -- vbuaa=vbuz1_plus_vbuz1
lda.z v
asl
// [17] make::c_bg#1 = make::$0
// [18] make::return_border = make::c_border#1 -- vbuz1=vbuxx
stx.z return_border
// [19] make::return_bg = make::c_bg#1 -- vbuz1=vbuaa
sta.z return_bg
jmp __breturn
// make::@return
__breturn:
// [20] return
rts
}
// File Data
.segment Data
a: .fill SIZEOF_STRUCT_COLS, 0
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __breturn
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Replacing instruction lda.z v with TXA
Removing instruction __breturn:
Removing instruction __breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
__constant struct Cols * const COLS = (struct Cols *) 53280
__constant char OFFSET_STRUCT_COLS_BG = 1
__constant char SIZEOF_STRUCT_COLS = 2
__loadstore struct Cols a = {} // mem[2]
void main()
char main::$0_bg // reg byte a 2.0
char main::$0_border // reg byte x 2.0
char main::$1_bg // reg byte a 2.0
char main::$1_border // reg byte x 2.0
__varcall struct Cols make(char v)
char make::$0 // reg byte a 22.0
char make::c_bg
char make::c_bg#1 // reg byte a 11.0
char make::c_border
char make::c_border#1 // reg byte x 7.333333333333333
__loadstore char make::return_bg // zp[1]:4 2.5
__loadstore char make::return_border // zp[1]:3 3.0
__loadstore char make::v // zp[1]:2 12.333333333333332
zp[1]:2 [ make::v ]
reg byte x [ main::$0_border ]
reg byte a [ main::$0_bg ]
reg byte x [ main::$1_border ]
reg byte a [ main::$1_bg ]
reg byte x [ make::c_border#1 ]
reg byte a [ make::$0 ]
reg byte a [ make::c_bg#1 ]
zp[1]:3 [ make::return_border ]
zp[1]:4 [ make::return_bg ]
mem[2] [ a ]
FINAL ASSEMBLER
Score: 107
// File Comments
// Test __varcall calling convention
// Struct return value
// Upstart
// Commodore 64 PRG executable file
.file [name="varcall-5.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
// Global Constants & labels
.const OFFSET_STRUCT_COLS_BG = 1
.const SIZEOF_STRUCT_COLS = 2
.label COLS = $d020
.segment Code
// main
main: {
// make(1)
// [0] make::v = 1 -- vbuz1=vbuc1
lda #1
sta.z make.v
// [1] callexecute make -- call_vprc1
jsr make
// [2] main::$0_border = make::return_border -- vbuxx=vbuz1
ldx.z make.return_border
// [3] main::$0_bg = make::return_bg -- vbuaa=vbuz1
lda.z make.return_bg
// a = make(1)
// [4] *((char *)&a) = main::$0_border -- _deref_pbuc1=vbuxx
stx a
// [5] *((char *)&a+OFFSET_STRUCT_COLS_BG) = main::$0_bg -- _deref_pbuc1=vbuaa
sta a+OFFSET_STRUCT_COLS_BG
// *COLS = a
// [6] *COLS = memcpy(*(&a), struct Cols, SIZEOF_STRUCT_COLS) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3
ldy #SIZEOF_STRUCT_COLS
!:
lda a-1,y
sta COLS-1,y
dey
bne !-
// make(2)
// [7] make::v = 2 -- vbuz1=vbuc1
lda #2
sta.z make.v
// [8] callexecute make -- call_vprc1
jsr make
// [9] main::$1_border = make::return_border -- vbuxx=vbuz1
ldx.z make.return_border
// [10] main::$1_bg = make::return_bg -- vbuaa=vbuz1
lda.z make.return_bg
// a = make(2)
// [11] *((char *)&a) = main::$1_border -- _deref_pbuc1=vbuxx
stx a
// [12] *((char *)&a+OFFSET_STRUCT_COLS_BG) = main::$1_bg -- _deref_pbuc1=vbuaa
sta a+OFFSET_STRUCT_COLS_BG
// *COLS = a
// [13] *COLS = memcpy(*(&a), struct Cols, SIZEOF_STRUCT_COLS) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3
ldy #SIZEOF_STRUCT_COLS
!:
lda a-1,y
sta COLS-1,y
dey
bne !-
// main::@return
// }
// [14] return
rts
}
// make
// struct Cols make(__zp(2) char v)
make: {
.label v = 2
.label return_border = 3
.label return_bg = 4
// c.border = v
// [15] make::c_border#1 = make::v -- vbuxx=vbuz1
ldx.z v
// v+v
// [16] make::$0 = make::v + make::v -- vbuaa=vbuz1_plus_vbuz1
txa
asl
// c.bg = v+v
// [17] make::c_bg#1 = make::$0
// return c;
// [18] make::return_border = make::c_border#1 -- vbuz1=vbuxx
stx.z return_border
// [19] make::return_bg = make::c_bg#1 -- vbuz1=vbuaa
sta.z return_bg
// make::@return
// }
// [20] return
rts
}
// File Data
.segment Data
a: .fill SIZEOF_STRUCT_COLS, 0

View File

@ -0,0 +1,30 @@
__constant struct Cols * const COLS = (struct Cols *) 53280
__constant char OFFSET_STRUCT_COLS_BG = 1
__constant char SIZEOF_STRUCT_COLS = 2
__loadstore struct Cols a = {} // mem[2]
void main()
char main::$0_bg // reg byte a 2.0
char main::$0_border // reg byte x 2.0
char main::$1_bg // reg byte a 2.0
char main::$1_border // reg byte x 2.0
__varcall struct Cols make(char v)
char make::$0 // reg byte a 22.0
char make::c_bg
char make::c_bg#1 // reg byte a 11.0
char make::c_border
char make::c_border#1 // reg byte x 7.333333333333333
__loadstore char make::return_bg // zp[1]:4 2.5
__loadstore char make::return_border // zp[1]:3 3.0
__loadstore char make::v // zp[1]:2 12.333333333333332
zp[1]:2 [ make::v ]
reg byte x [ main::$0_border ]
reg byte a [ main::$0_bg ]
reg byte x [ main::$1_border ]
reg byte a [ main::$1_bg ]
reg byte x [ make::c_border#1 ]
reg byte a [ make::$0 ]
reg byte a [ make::c_bg#1 ]
zp[1]:3 [ make::return_border ]
zp[1]:4 [ make::return_bg ]
mem[2] [ a ]

View File

@ -0,0 +1,71 @@
// Test __varcall calling convention
// Struct parameter & return value
// Commodore 64 PRG executable file
.file [name="varcall-6.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
.const OFFSET_STRUCT_COLS_BG = 1
.label COLS = $d020
.segment Code
main: {
.const a_border = 1
.const a_bg = 2
// struct Cols c = plus(a, { 2, 3 })
lda #a_border
sta.z plus.a_border
lda #a_bg
sta.z plus.a_bg
lda #2
sta.z plus.b_border
lda #3
sta.z plus.b_bg
jsr plus
ldx.z plus.return_border
lda.z plus.return_bg
// *COLS = c
stx COLS
sta COLS+OFFSET_STRUCT_COLS_BG
// plus(c, a)
stx.z plus.a_border
sta.z plus.a_bg
lda #a_border
sta.z plus.b_border
lda #a_bg
sta.z plus.b_bg
jsr plus
// c = plus(c, a)
ldx.z plus.return_border
lda.z plus.return_bg
// *COLS = c
stx COLS
sta COLS+OFFSET_STRUCT_COLS_BG
// }
rts
}
// struct Cols plus(__zp(7) char a_border, __zp(6) char a_bg, __zp(3) char b_border, __zp(2) char b_bg)
plus: {
.label a_border = 7
.label a_bg = 6
.label b_border = 3
.label b_bg = 2
.label return_border = 4
.label return_bg = 5
// a.border+b.border
lda.z a_border
clc
adc.z b_border
tax
// a.bg+b.bg
lda.z a_bg
clc
adc.z b_bg
// return { a.border+b.border, a.bg+b.bg };
stx.z return_border
sta.z return_bg
// }
rts
}

View File

@ -0,0 +1,36 @@
void main()
main: scope:[main] from
[0] plus::a_border = main::a_border
[1] plus::a_bg = main::a_bg
[2] plus::b_border = 2
[3] plus::b_bg = 3
[4] callexecute plus
[5] main::c_border#0 = plus::return_border
[6] main::c_bg#0 = plus::return_bg
[7] *((char *)COLS) = main::c_border#0
[8] *((char *)COLS+OFFSET_STRUCT_COLS_BG) = main::c_bg#0
[9] plus::a_border = main::c_border#0
[10] plus::a_bg = main::c_bg#0
[11] plus::b_border = main::a_border
[12] plus::b_bg = main::a_bg
[13] callexecute plus
[14] main::c_border#1 = plus::return_border
[15] main::c_bg#1 = plus::return_bg
[16] *((char *)COLS) = main::c_border#1
[17] *((char *)COLS+OFFSET_STRUCT_COLS_BG) = main::c_bg#1
to:main::@return
main::@return: scope:[main] from main
[18] return
to:@return
__varcall struct Cols plus(char a_border , char a_bg , char b_border , char b_bg)
plus: scope:[plus] from
[19] plus::$0 = plus::a_border + plus::b_border
[20] plus::$1 = plus::a_bg + plus::b_bg
[21] plus::return_border = plus::$0
[22] plus::return_bg = plus::$1
to:plus::@return
plus::@return: scope:[plus] from plus
[23] return
to:@return

541
src/test/ref/varcall-6.log Normal file
View File

@ -0,0 +1,541 @@
Converting parameter in __varcall procedure to load/store plus::a
Converting parameter in __varcall procedure to load/store plus::b
Converting return in __varcall procedure to load/store plus::return
Constantified RValue plus::return = (struct Cols){ plus::$0, plus::$1 }
Added struct type cast to parameter value list main::c = call plus(main::a, (struct Cols){ 2, 3 })
Eliminating unused variable with no statement plus::a
Eliminating unused variable with no statement plus::b
Eliminating unused variable with no statement main::$0
Eliminating unused variable with no statement main::$1
Calling convention __varcall adding prepare/execute/finalize for { main::c_border, main::c_bg } = call plus(main::a_border, main::a_bg, 2, 3)
Calling convention __varcall adding prepare/execute/finalize for { main::$1_border, main::$1_bg } = call plus(main::c_border, main::c_bg, main::a_border, main::a_bg)
CONTROL FLOW GRAPH SSA
__varcall struct Cols plus(char a_border , char a_bg , char b_border , char b_bg)
plus: scope:[plus] from
plus::$0 = plus::a_border + plus::b_border
plus::$1 = plus::a_bg + plus::b_bg
plus::return_border = plus::$0
plus::return_bg = plus::$1
plus::return = struct-unwound {plus::return_border, plus::return_bg}
to:plus::@return
plus::@return: scope:[plus] from plus
return
to:@return
void main()
main: scope:[main] from __start
plus::a_border = main::a_border
plus::a_bg = main::a_bg
plus::b_border = 2
plus::b_bg = 3
callexecute plus
main::c_border#0 = plus::return_border
main::c_bg#0 = plus::return_bg
*((char *)COLS+OFFSET_STRUCT_COLS_BORDER) = main::c_border#0
*((char *)COLS+OFFSET_STRUCT_COLS_BG) = main::c_bg#0
plus::a_border = main::c_border#0
plus::a_bg = main::c_bg#0
plus::b_border = main::a_border
plus::b_bg = main::a_bg
callexecute plus
main::$1_border = plus::return_border
main::$1_bg = plus::return_bg
main::c_border#1 = main::$1_border
main::c_bg#1 = main::$1_bg
*((char *)COLS+OFFSET_STRUCT_COLS_BORDER) = main::c_border#1
*((char *)COLS+OFFSET_STRUCT_COLS_BG) = main::c_bg#1
to:main::@return
main::@return: scope:[main] from main
return
to:@return
void __start()
__start: scope:[__start] from
call main
to:__start::@1
__start::@1: scope:[__start] from __start
to:__start::@return
__start::@return: scope:[__start] from __start::@1
return
to:@return
SYMBOL TABLE SSA
__constant struct Cols * const COLS = (struct Cols *)$d020
__constant char OFFSET_STRUCT_COLS_BG = 1
__constant char OFFSET_STRUCT_COLS_BORDER = 0
void __start()
void main()
char main::$1_bg
char main::$1_border
__constant char main::a_bg = 2
__constant char main::a_border = 1
char main::c_bg
char main::c_bg#0
char main::c_bg#1
char main::c_border
char main::c_border#0
char main::c_border#1
__varcall struct Cols plus(char a_border , char a_bg , char b_border , char b_bg)
char plus::$0
char plus::$1
__loadstore char plus::a_bg
__loadstore char plus::a_border
__loadstore char plus::b_bg
__loadstore char plus::b_border
__loadstore struct Cols plus::return
__loadstore char plus::return_bg
__loadstore char plus::return_border
Adding number conversion cast (unumber) 2 in plus::b_border = 2
Adding number conversion cast (unumber) 3 in plus::b_bg = 3
Successful SSA optimization PassNAddNumberTypeConversions
Inlining cast plus::b_border = (unumber)2
Inlining cast plus::b_bg = (unumber)3
Successful SSA optimization Pass2InlineCast
Simplifying constant pointer cast (struct Cols *) 53280
Simplifying constant integer cast 2
Simplifying constant integer cast 3
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (char) 2
Finalized unsigned number type (char) 3
Successful SSA optimization PassNFinalizeNumberTypeConversions
Alias candidate removed (volatile)plus::return_border = plus::$0
Alias candidate removed (volatile)plus::return_bg = plus::$1
Alias main::c_border#1 = main::$1_border
Alias main::c_bg#1 = main::$1_bg
Successful SSA optimization Pass2AliasElimination
Alias candidate removed (volatile)plus::return_border = plus::$0
Alias candidate removed (volatile)plus::return_bg = plus::$1
Simplifying expression containing zero (char *)COLS in [13] *((char *)COLS+OFFSET_STRUCT_COLS_BORDER) = main::c_border#0
Simplifying expression containing zero (char *)COLS in [22] *((char *)COLS+OFFSET_STRUCT_COLS_BORDER) = main::c_border#1
Successful SSA optimization PassNSimplifyExpressionWithZero
Eliminating unused variable plus::return and assignment [4] plus::return = struct-unwound {plus::return_border, plus::return_bg}
Eliminating unused constant OFFSET_STRUCT_COLS_BORDER
Successful SSA optimization PassNEliminateUnusedVars
Removing unused procedure __start
Removing unused procedure block __start
Removing unused procedure block __start::@1
Removing unused procedure block __start::@return
Successful SSA optimization PassNEliminateEmptyStart
Alias candidate removed (volatile)plus::return_border = plus::$0
Alias candidate removed (volatile)plus::return_bg = plus::$1
Alias candidate removed (volatile)plus::return_border = plus::$0
Alias candidate removed (volatile)plus::return_bg = plus::$1
Alias candidate removed (volatile)plus::return_border = plus::$0
Alias candidate removed (volatile)plus::return_bg = plus::$1
CALL GRAPH
Calls in [main] to plus:4 plus:13
Created 0 initial phi equivalence classes
Coalesced down to 0 phi equivalence classes
FINAL CONTROL FLOW GRAPH
void main()
main: scope:[main] from
[0] plus::a_border = main::a_border
[1] plus::a_bg = main::a_bg
[2] plus::b_border = 2
[3] plus::b_bg = 3
[4] callexecute plus
[5] main::c_border#0 = plus::return_border
[6] main::c_bg#0 = plus::return_bg
[7] *((char *)COLS) = main::c_border#0
[8] *((char *)COLS+OFFSET_STRUCT_COLS_BG) = main::c_bg#0
[9] plus::a_border = main::c_border#0
[10] plus::a_bg = main::c_bg#0
[11] plus::b_border = main::a_border
[12] plus::b_bg = main::a_bg
[13] callexecute plus
[14] main::c_border#1 = plus::return_border
[15] main::c_bg#1 = plus::return_bg
[16] *((char *)COLS) = main::c_border#1
[17] *((char *)COLS+OFFSET_STRUCT_COLS_BG) = main::c_bg#1
to:main::@return
main::@return: scope:[main] from main
[18] return
to:@return
__varcall struct Cols plus(char a_border , char a_bg , char b_border , char b_bg)
plus: scope:[plus] from
[19] plus::$0 = plus::a_border + plus::b_border
[20] plus::$1 = plus::a_bg + plus::b_bg
[21] plus::return_border = plus::$0
[22] plus::return_bg = plus::$1
to:plus::@return
plus::@return: scope:[plus] from plus
[23] return
to:@return
VARIABLE REGISTER WEIGHTS
void main()
char main::c_bg
char main::c_bg#0 // 1.5
char main::c_bg#1 // 2.0
char main::c_border
char main::c_border#0 // 1.5
char main::c_border#1 // 2.0
__varcall struct Cols plus(char a_border , char a_bg , char b_border , char b_bg)
char plus::$0 // 11.0
char plus::$1 // 11.0
__loadstore char plus::a_bg // 2.142857142857143
__loadstore char plus::a_border // 1.875
__loadstore char plus::b_bg // 5.0
__loadstore char plus::b_border // 3.75
__loadstore char plus::return_bg // 2.5
__loadstore char plus::return_border // 3.0
Initial phi equivalence classes
Added variable plus::a_border to live range equivalence class [ plus::a_border ]
Added variable plus::a_bg to live range equivalence class [ plus::a_bg ]
Added variable plus::b_border to live range equivalence class [ plus::b_border ]
Added variable plus::b_bg to live range equivalence class [ plus::b_bg ]
Added variable main::c_border#0 to live range equivalence class [ main::c_border#0 ]
Added variable main::c_bg#0 to live range equivalence class [ main::c_bg#0 ]
Added variable main::c_border#1 to live range equivalence class [ main::c_border#1 ]
Added variable main::c_bg#1 to live range equivalence class [ main::c_bg#1 ]
Added variable plus::$0 to live range equivalence class [ plus::$0 ]
Added variable plus::$1 to live range equivalence class [ plus::$1 ]
Added variable plus::return_border to live range equivalence class [ plus::return_border ]
Added variable plus::return_bg to live range equivalence class [ plus::return_bg ]
Complete equivalence classes
[ plus::a_border ]
[ plus::a_bg ]
[ plus::b_border ]
[ plus::b_bg ]
[ main::c_border#0 ]
[ main::c_bg#0 ]
[ main::c_border#1 ]
[ main::c_bg#1 ]
[ plus::$0 ]
[ plus::$1 ]
[ plus::return_border ]
[ plus::return_bg ]
Allocated zp[1]:2 [ plus::$0 ]
Allocated zp[1]:3 [ plus::$1 ]
Allocated zp[1]:4 [ plus::b_bg ]
Allocated zp[1]:5 [ plus::b_border ]
Allocated zp[1]:6 [ plus::return_border ]
Allocated zp[1]:7 [ plus::return_bg ]
Allocated zp[1]:8 [ plus::a_bg ]
Allocated zp[1]:9 [ main::c_border#1 ]
Allocated zp[1]:10 [ main::c_bg#1 ]
Allocated zp[1]:11 [ plus::a_border ]
Allocated zp[1]:12 [ main::c_border#0 ]
Allocated zp[1]:13 [ main::c_bg#0 ]
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [0] plus::a_border = main::a_border [ plus::a_border ] ( [ plus::a_border ] { } ) always clobbers reg byte a
Statement [1] plus::a_bg = main::a_bg [ plus::a_border plus::a_bg ] ( [ plus::a_border plus::a_bg ] { } ) always clobbers reg byte a
Statement [2] plus::b_border = 2 [ plus::a_border plus::a_bg plus::b_border ] ( [ plus::a_border plus::a_bg plus::b_border ] { } ) always clobbers reg byte a
Statement [3] plus::b_bg = 3 [ plus::a_border plus::a_bg plus::b_border plus::b_bg ] ( [ plus::a_border plus::a_bg plus::b_border plus::b_bg ] { } ) always clobbers reg byte a
Statement [11] plus::b_border = main::a_border [ plus::a_border plus::a_bg plus::b_border ] ( [ plus::a_border plus::a_bg plus::b_border ] { } ) always clobbers reg byte a
Statement [12] plus::b_bg = main::a_bg [ plus::a_border plus::a_bg plus::b_border plus::b_bg ] ( [ plus::a_border plus::a_bg plus::b_border plus::b_bg ] { } ) always clobbers reg byte a
Statement [19] plus::$0 = plus::a_border + plus::b_border [ plus::a_bg plus::b_bg plus::$0 ] ( plus:4 [ plus::a_bg plus::b_bg plus::$0 ] { { main::c_border#0 = plus::a_border } { main::c_bg#0 = plus::a_bg } } plus:13 [ plus::a_bg plus::b_bg plus::$0 ] { { main::c_border#0 = plus::a_border } { main::c_bg#0 = plus::a_bg } } ) always clobbers reg byte a
Statement [20] plus::$1 = plus::a_bg + plus::b_bg [ plus::$0 plus::$1 ] ( plus:4 [ plus::$0 plus::$1 ] { { main::c_border#0 = plus::a_border } { main::c_bg#0 = plus::a_bg } } plus:13 [ plus::$0 plus::$1 ] { { main::c_border#0 = plus::a_border } { main::c_bg#0 = plus::a_bg } } ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp[1]:2 [ plus::$0 ]
Statement [0] plus::a_border = main::a_border [ plus::a_border ] ( [ plus::a_border ] { } ) always clobbers reg byte a
Statement [1] plus::a_bg = main::a_bg [ plus::a_border plus::a_bg ] ( [ plus::a_border plus::a_bg ] { } ) always clobbers reg byte a
Statement [2] plus::b_border = 2 [ plus::a_border plus::a_bg plus::b_border ] ( [ plus::a_border plus::a_bg plus::b_border ] { } ) always clobbers reg byte a
Statement [3] plus::b_bg = 3 [ plus::a_border plus::a_bg plus::b_border plus::b_bg ] ( [ plus::a_border plus::a_bg plus::b_border plus::b_bg ] { } ) always clobbers reg byte a
Statement [11] plus::b_border = main::a_border [ plus::a_border plus::a_bg plus::b_border ] ( [ plus::a_border plus::a_bg plus::b_border ] { } ) always clobbers reg byte a
Statement [12] plus::b_bg = main::a_bg [ plus::a_border plus::a_bg plus::b_border plus::b_bg ] ( [ plus::a_border plus::a_bg plus::b_border plus::b_bg ] { } ) always clobbers reg byte a
Statement [19] plus::$0 = plus::a_border + plus::b_border [ plus::a_bg plus::b_bg plus::$0 ] ( plus:4 [ plus::a_bg plus::b_bg plus::$0 ] { { main::c_border#0 = plus::a_border } { main::c_bg#0 = plus::a_bg } } plus:13 [ plus::a_bg plus::b_bg plus::$0 ] { { main::c_border#0 = plus::a_border } { main::c_bg#0 = plus::a_bg } } ) always clobbers reg byte a
Statement [20] plus::$1 = plus::a_bg + plus::b_bg [ plus::$0 plus::$1 ] ( plus:4 [ plus::$0 plus::$1 ] { { main::c_border#0 = plus::a_border } { main::c_bg#0 = plus::a_bg } } plus:13 [ plus::$0 plus::$1 ] { { main::c_border#0 = plus::a_border } { main::c_bg#0 = plus::a_bg } } ) always clobbers reg byte a
Potential registers zp[1]:11 [ plus::a_border ] : zp[1]:11 ,
Potential registers zp[1]:8 [ plus::a_bg ] : zp[1]:8 ,
Potential registers zp[1]:5 [ plus::b_border ] : zp[1]:5 ,
Potential registers zp[1]:4 [ plus::b_bg ] : zp[1]:4 ,
Potential registers zp[1]:12 [ main::c_border#0 ] : zp[1]:12 , reg byte a , reg byte x , reg byte y ,
Potential registers zp[1]:13 [ main::c_bg#0 ] : zp[1]:13 , reg byte a , reg byte x , reg byte y ,
Potential registers zp[1]:9 [ main::c_border#1 ] : zp[1]:9 , reg byte a , reg byte x , reg byte y ,
Potential registers zp[1]:10 [ main::c_bg#1 ] : zp[1]:10 , reg byte a , reg byte x , reg byte y ,
Potential registers zp[1]:2 [ plus::$0 ] : zp[1]:2 , reg byte x , reg byte y ,
Potential registers zp[1]:3 [ plus::$1 ] : zp[1]:3 , reg byte a , reg byte x , reg byte y ,
Potential registers zp[1]:6 [ plus::return_border ] : zp[1]:6 ,
Potential registers zp[1]:7 [ plus::return_bg ] : zp[1]:7 ,
REGISTER UPLIFT SCOPES
Uplift Scope [plus] 11: zp[1]:2 [ plus::$0 ] 11: zp[1]:3 [ plus::$1 ] 5: zp[1]:4 [ plus::b_bg ] 3.75: zp[1]:5 [ plus::b_border ] 3: zp[1]:6 [ plus::return_border ] 2.5: zp[1]:7 [ plus::return_bg ] 2.14: zp[1]:8 [ plus::a_bg ] 1.88: zp[1]:11 [ plus::a_border ]
Uplift Scope [main] 2: zp[1]:9 [ main::c_border#1 ] 2: zp[1]:10 [ main::c_bg#1 ] 1.5: zp[1]:12 [ main::c_border#0 ] 1.5: zp[1]:13 [ main::c_bg#0 ]
Uplift Scope [Cols]
Uplift Scope []
Uplifting [plus] best 148 combination reg byte x [ plus::$0 ] reg byte a [ plus::$1 ] zp[1]:4 [ plus::b_bg ] zp[1]:5 [ plus::b_border ] zp[1]:6 [ plus::return_border ] zp[1]:7 [ plus::return_bg ] zp[1]:8 [ plus::a_bg ] zp[1]:11 [ plus::a_border ]
Uplifting [main] best 124 combination reg byte x [ main::c_border#1 ] zp[1]:10 [ main::c_bg#1 ] reg byte x [ main::c_border#0 ] reg byte a [ main::c_bg#0 ]
Limited combination testing to 100 combinations of 256 possible.
Uplifting [Cols] best 124 combination
Uplifting [] best 124 combination
Attempting to uplift remaining variables inzp[1]:4 [ plus::b_bg ]
Uplifting [plus] best 124 combination zp[1]:4 [ plus::b_bg ]
Attempting to uplift remaining variables inzp[1]:5 [ plus::b_border ]
Uplifting [plus] best 124 combination zp[1]:5 [ plus::b_border ]
Attempting to uplift remaining variables inzp[1]:6 [ plus::return_border ]
Uplifting [plus] best 124 combination zp[1]:6 [ plus::return_border ]
Attempting to uplift remaining variables inzp[1]:7 [ plus::return_bg ]
Uplifting [plus] best 124 combination zp[1]:7 [ plus::return_bg ]
Attempting to uplift remaining variables inzp[1]:8 [ plus::a_bg ]
Uplifting [plus] best 124 combination zp[1]:8 [ plus::a_bg ]
Attempting to uplift remaining variables inzp[1]:10 [ main::c_bg#1 ]
Uplifting [main] best 118 combination reg byte a [ main::c_bg#1 ]
Attempting to uplift remaining variables inzp[1]:11 [ plus::a_border ]
Uplifting [plus] best 118 combination zp[1]:11 [ plus::a_border ]
Allocated (was zp[1]:4) zp[1]:2 [ plus::b_bg ]
Allocated (was zp[1]:5) zp[1]:3 [ plus::b_border ]
Allocated (was zp[1]:6) zp[1]:4 [ plus::return_border ]
Allocated (was zp[1]:7) zp[1]:5 [ plus::return_bg ]
Allocated (was zp[1]:8) zp[1]:6 [ plus::a_bg ]
Allocated (was zp[1]:11) zp[1]:7 [ plus::a_border ]
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Test __varcall calling convention
// Struct parameter & return value
// Upstart
// Commodore 64 PRG executable file
.file [name="varcall-6.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
// Global Constants & labels
.const OFFSET_STRUCT_COLS_BG = 1
.label COLS = $d020
.segment Code
// main
main: {
.const a_border = 1
.const a_bg = 2
// [0] plus::a_border = main::a_border -- vbuz1=vbuc1
lda #a_border
sta.z plus.a_border
// [1] plus::a_bg = main::a_bg -- vbuz1=vbuc1
lda #a_bg
sta.z plus.a_bg
// [2] plus::b_border = 2 -- vbuz1=vbuc1
lda #2
sta.z plus.b_border
// [3] plus::b_bg = 3 -- vbuz1=vbuc1
lda #3
sta.z plus.b_bg
// [4] callexecute plus -- call_vprc1
jsr plus
// [5] main::c_border#0 = plus::return_border -- vbuxx=vbuz1
ldx.z plus.return_border
// [6] main::c_bg#0 = plus::return_bg -- vbuaa=vbuz1
lda.z plus.return_bg
// [7] *((char *)COLS) = main::c_border#0 -- _deref_pbuc1=vbuxx
stx COLS
// [8] *((char *)COLS+OFFSET_STRUCT_COLS_BG) = main::c_bg#0 -- _deref_pbuc1=vbuaa
sta COLS+OFFSET_STRUCT_COLS_BG
// [9] plus::a_border = main::c_border#0 -- vbuz1=vbuxx
stx.z plus.a_border
// [10] plus::a_bg = main::c_bg#0 -- vbuz1=vbuaa
sta.z plus.a_bg
// [11] plus::b_border = main::a_border -- vbuz1=vbuc1
lda #a_border
sta.z plus.b_border
// [12] plus::b_bg = main::a_bg -- vbuz1=vbuc1
lda #a_bg
sta.z plus.b_bg
// [13] callexecute plus -- call_vprc1
jsr plus
// [14] main::c_border#1 = plus::return_border -- vbuxx=vbuz1
ldx.z plus.return_border
// [15] main::c_bg#1 = plus::return_bg -- vbuaa=vbuz1
lda.z plus.return_bg
// [16] *((char *)COLS) = main::c_border#1 -- _deref_pbuc1=vbuxx
stx COLS
// [17] *((char *)COLS+OFFSET_STRUCT_COLS_BG) = main::c_bg#1 -- _deref_pbuc1=vbuaa
sta COLS+OFFSET_STRUCT_COLS_BG
jmp __breturn
// main::@return
__breturn:
// [18] return
rts
}
// plus
// struct Cols plus(__zp(7) char a_border, __zp(6) char a_bg, __zp(3) char b_border, __zp(2) char b_bg)
plus: {
.label a_border = 7
.label a_bg = 6
.label b_border = 3
.label b_bg = 2
.label return_border = 4
.label return_bg = 5
// [19] plus::$0 = plus::a_border + plus::b_border -- vbuxx=vbuz1_plus_vbuz2
lda.z a_border
clc
adc.z b_border
tax
// [20] plus::$1 = plus::a_bg + plus::b_bg -- vbuaa=vbuz1_plus_vbuz2
lda.z a_bg
clc
adc.z b_bg
// [21] plus::return_border = plus::$0 -- vbuz1=vbuxx
stx.z return_border
// [22] plus::return_bg = plus::$1 -- vbuz1=vbuaa
sta.z return_bg
jmp __breturn
// plus::@return
__breturn:
// [23] return
rts
}
// File Data
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __breturn
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction __breturn:
Removing instruction __breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
__constant struct Cols * const COLS = (struct Cols *) 53280
__constant char OFFSET_STRUCT_COLS_BG = 1
void main()
__constant char main::a_bg = 2
__constant char main::a_border = 1
char main::c_bg
char main::c_bg#0 // reg byte a 1.5
char main::c_bg#1 // reg byte a 2.0
char main::c_border
char main::c_border#0 // reg byte x 1.5
char main::c_border#1 // reg byte x 2.0
__varcall struct Cols plus(char a_border , char a_bg , char b_border , char b_bg)
char plus::$0 // reg byte x 11.0
char plus::$1 // reg byte a 11.0
__loadstore char plus::a_bg // zp[1]:6 2.142857142857143
__loadstore char plus::a_border // zp[1]:7 1.875
__loadstore char plus::b_bg // zp[1]:2 5.0
__loadstore char plus::b_border // zp[1]:3 3.75
__loadstore char plus::return_bg // zp[1]:5 2.5
__loadstore char plus::return_border // zp[1]:4 3.0
zp[1]:7 [ plus::a_border ]
zp[1]:6 [ plus::a_bg ]
zp[1]:3 [ plus::b_border ]
zp[1]:2 [ plus::b_bg ]
reg byte x [ main::c_border#0 ]
reg byte a [ main::c_bg#0 ]
reg byte x [ main::c_border#1 ]
reg byte a [ main::c_bg#1 ]
reg byte x [ plus::$0 ]
reg byte a [ plus::$1 ]
zp[1]:4 [ plus::return_border ]
zp[1]:5 [ plus::return_bg ]
FINAL ASSEMBLER
Score: 112
// File Comments
// Test __varcall calling convention
// Struct parameter & return value
// Upstart
// Commodore 64 PRG executable file
.file [name="varcall-6.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
// Global Constants & labels
.const OFFSET_STRUCT_COLS_BG = 1
.label COLS = $d020
.segment Code
// main
main: {
.const a_border = 1
.const a_bg = 2
// struct Cols c = plus(a, { 2, 3 })
// [0] plus::a_border = main::a_border -- vbuz1=vbuc1
lda #a_border
sta.z plus.a_border
// [1] plus::a_bg = main::a_bg -- vbuz1=vbuc1
lda #a_bg
sta.z plus.a_bg
// [2] plus::b_border = 2 -- vbuz1=vbuc1
lda #2
sta.z plus.b_border
// [3] plus::b_bg = 3 -- vbuz1=vbuc1
lda #3
sta.z plus.b_bg
// [4] callexecute plus -- call_vprc1
jsr plus
// [5] main::c_border#0 = plus::return_border -- vbuxx=vbuz1
ldx.z plus.return_border
// [6] main::c_bg#0 = plus::return_bg -- vbuaa=vbuz1
lda.z plus.return_bg
// *COLS = c
// [7] *((char *)COLS) = main::c_border#0 -- _deref_pbuc1=vbuxx
stx COLS
// [8] *((char *)COLS+OFFSET_STRUCT_COLS_BG) = main::c_bg#0 -- _deref_pbuc1=vbuaa
sta COLS+OFFSET_STRUCT_COLS_BG
// plus(c, a)
// [9] plus::a_border = main::c_border#0 -- vbuz1=vbuxx
stx.z plus.a_border
// [10] plus::a_bg = main::c_bg#0 -- vbuz1=vbuaa
sta.z plus.a_bg
// [11] plus::b_border = main::a_border -- vbuz1=vbuc1
lda #a_border
sta.z plus.b_border
// [12] plus::b_bg = main::a_bg -- vbuz1=vbuc1
lda #a_bg
sta.z plus.b_bg
// [13] callexecute plus -- call_vprc1
jsr plus
// c = plus(c, a)
// [14] main::c_border#1 = plus::return_border -- vbuxx=vbuz1
ldx.z plus.return_border
// [15] main::c_bg#1 = plus::return_bg -- vbuaa=vbuz1
lda.z plus.return_bg
// *COLS = c
// [16] *((char *)COLS) = main::c_border#1 -- _deref_pbuc1=vbuxx
stx COLS
// [17] *((char *)COLS+OFFSET_STRUCT_COLS_BG) = main::c_bg#1 -- _deref_pbuc1=vbuaa
sta COLS+OFFSET_STRUCT_COLS_BG
// main::@return
// }
// [18] return
rts
}
// plus
// struct Cols plus(__zp(7) char a_border, __zp(6) char a_bg, __zp(3) char b_border, __zp(2) char b_bg)
plus: {
.label a_border = 7
.label a_bg = 6
.label b_border = 3
.label b_bg = 2
.label return_border = 4
.label return_bg = 5
// a.border+b.border
// [19] plus::$0 = plus::a_border + plus::b_border -- vbuxx=vbuz1_plus_vbuz2
lda.z a_border
clc
adc.z b_border
tax
// a.bg+b.bg
// [20] plus::$1 = plus::a_bg + plus::b_bg -- vbuaa=vbuz1_plus_vbuz2
lda.z a_bg
clc
adc.z b_bg
// return { a.border+b.border, a.bg+b.bg };
// [21] plus::return_border = plus::$0 -- vbuz1=vbuxx
stx.z return_border
// [22] plus::return_bg = plus::$1 -- vbuz1=vbuaa
sta.z return_bg
// plus::@return
// }
// [23] return
rts
}
// File Data

View File

@ -0,0 +1,33 @@
__constant struct Cols * const COLS = (struct Cols *) 53280
__constant char OFFSET_STRUCT_COLS_BG = 1
void main()
__constant char main::a_bg = 2
__constant char main::a_border = 1
char main::c_bg
char main::c_bg#0 // reg byte a 1.5
char main::c_bg#1 // reg byte a 2.0
char main::c_border
char main::c_border#0 // reg byte x 1.5
char main::c_border#1 // reg byte x 2.0
__varcall struct Cols plus(char a_border , char a_bg , char b_border , char b_bg)
char plus::$0 // reg byte x 11.0
char plus::$1 // reg byte a 11.0
__loadstore char plus::a_bg // zp[1]:6 2.142857142857143
__loadstore char plus::a_border // zp[1]:7 1.875
__loadstore char plus::b_bg // zp[1]:2 5.0
__loadstore char plus::b_border // zp[1]:3 3.75
__loadstore char plus::return_bg // zp[1]:5 2.5
__loadstore char plus::return_border // zp[1]:4 3.0
zp[1]:7 [ plus::a_border ]
zp[1]:6 [ plus::a_bg ]
zp[1]:3 [ plus::b_border ]
zp[1]:2 [ plus::b_bg ]
reg byte x [ main::c_border#0 ]
reg byte a [ main::c_bg#0 ]
reg byte x [ main::c_border#1 ]
reg byte a [ main::c_bg#1 ]
reg byte x [ plus::$0 ]
reg byte a [ plus::$1 ]
zp[1]:4 [ plus::return_border ]
zp[1]:5 [ plus::return_bg ]

View File

@ -0,0 +1,33 @@
// Test __varcall calling convention
// Struct parameter & return value - only a single call
// Commodore 64 PRG executable file
.file [name="varcall-7.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
.const OFFSET_STRUCT_COLS_BG = 1
.label COLS = $d020
.segment Code
main: {
.label a_border = 1
.label a_bg = 2
.label b_border = 2
.label b_bg = 3
// struct Cols c = plus(a, b)
jsr plus
// *COLS = c
lda #plus.return_border
sta COLS
lda #plus.return_bg
sta COLS+OFFSET_STRUCT_COLS_BG
// }
rts
}
plus: {
.label return_border = main.a_border+main.b_border
.label return_bg = main.a_bg+main.b_bg
rts
}

View File

@ -0,0 +1,19 @@
void main()
main: scope:[main] from
[0] phi()
[1] callexecute plus
[2] *((char *)COLS) = plus::return_border
[3] *((char *)COLS+OFFSET_STRUCT_COLS_BG) = plus::return_bg
to:main::@return
main::@return: scope:[main] from main
[4] return
to:@return
__varcall struct Cols plus()
plus: scope:[plus] from
[5] phi()
to:plus::@return
plus::@return: scope:[plus] from plus
[6] return
to:@return

301
src/test/ref/varcall-7.log Normal file
View File

@ -0,0 +1,301 @@
Converting parameter in __varcall procedure to load/store plus::a
Converting parameter in __varcall procedure to load/store plus::b
Converting return in __varcall procedure to load/store plus::return
Constantified RValue plus::return = (struct Cols){ plus::$0, plus::$1 }
Eliminating unused variable with no statement plus::a
Eliminating unused variable with no statement plus::b
Eliminating unused variable with no statement main::$0
Calling convention __varcall adding prepare/execute/finalize for { main::c_border, main::c_bg } = call plus(main::a_border, main::a_bg, main::b_border, main::b_bg)
CONTROL FLOW GRAPH SSA
__varcall struct Cols plus(char a_border , char a_bg , char b_border , char b_bg)
plus: scope:[plus] from
plus::$0 = plus::a_border + plus::b_border
plus::$1 = plus::a_bg + plus::b_bg
plus::return_border = plus::$0
plus::return_bg = plus::$1
plus::return = struct-unwound {plus::return_border, plus::return_bg}
to:plus::@return
plus::@return: scope:[plus] from plus
return
to:@return
void main()
main: scope:[main] from __start
plus::a_border = main::a_border
plus::a_bg = main::a_bg
plus::b_border = main::b_border
plus::b_bg = main::b_bg
callexecute plus
main::c_border#0 = plus::return_border
main::c_bg#0 = plus::return_bg
*((char *)COLS+OFFSET_STRUCT_COLS_BORDER) = main::c_border#0
*((char *)COLS+OFFSET_STRUCT_COLS_BG) = main::c_bg#0
to:main::@return
main::@return: scope:[main] from main
return
to:@return
void __start()
__start: scope:[__start] from
call main
to:__start::@1
__start::@1: scope:[__start] from __start
to:__start::@return
__start::@return: scope:[__start] from __start::@1
return
to:@return
SYMBOL TABLE SSA
__constant struct Cols * const COLS = (struct Cols *)$d020
__constant char OFFSET_STRUCT_COLS_BG = 1
__constant char OFFSET_STRUCT_COLS_BORDER = 0
void __start()
void main()
__constant char main::a_bg = 2
__constant char main::a_border = 1
__constant char main::b_bg = 3
__constant char main::b_border = 2
struct Cols main::c
char main::c_bg
char main::c_bg#0
char main::c_border
char main::c_border#0
__varcall struct Cols plus(char a_border , char a_bg , char b_border , char b_bg)
char plus::$0
char plus::$1
__loadstore char plus::a_bg
__loadstore char plus::a_border
__loadstore char plus::b_bg
__loadstore char plus::b_border
__loadstore struct Cols plus::return
__loadstore char plus::return_bg
__loadstore char plus::return_border
Simplifying constant pointer cast (struct Cols *) 53280
Successful SSA optimization PassNCastSimplification
Alias candidate removed (volatile)plus::return_border = plus::$0
Alias candidate removed (volatile)plus::return_bg = plus::$1
Constant plus::a_border = main::a_border
Constant plus::a_bg = main::a_bg
Constant plus::b_border = main::b_border
Constant plus::b_bg = main::b_bg
Successful SSA optimization Pass2ConstantIdentification
Simplifying expression containing zero (char *)COLS in [13] *((char *)COLS+OFFSET_STRUCT_COLS_BORDER) = main::c_border#0
Successful SSA optimization PassNSimplifyExpressionWithZero
Eliminating unused variable plus::return and assignment [4] plus::return = struct-unwound {plus::return_border, plus::return_bg}
Eliminating unused constant OFFSET_STRUCT_COLS_BORDER
Successful SSA optimization PassNEliminateUnusedVars
Removing unused procedure __start
Removing unused procedure block __start
Removing unused procedure block __start::@1
Removing unused procedure block __start::@return
Successful SSA optimization PassNEliminateEmptyStart
Alias candidate removed (volatile)plus::return_border = plus::$0
Alias candidate removed (volatile)plus::return_bg = plus::$1
Constant right-side identified [0] plus::$0 = plus::a_border + plus::b_border
Constant right-side identified [1] plus::$1 = plus::a_bg + plus::b_bg
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant plus::$0 = plus::a_border+plus::b_border
Constant plus::$1 = plus::a_bg+plus::b_bg
Successful SSA optimization Pass2ConstantIdentification
Constant plus::return_border = plus::$0
Constant plus::return_bg = plus::$1
Successful SSA optimization Pass2ConstantIdentification
Constant main::c_border#0 = plus::return_border
Constant main::c_bg#0 = plus::return_bg
Successful SSA optimization Pass2ConstantIdentification
Parameter inlined plus::b_bg
Parameter inlined plus::a_bg
Parameter inlined plus::b_border
Parameter inlined plus::a_border
Constant inlined main::c_border#0 = plus::return_border
Constant inlined plus::b_bg = main::b_bg
Constant inlined plus::a_bg = main::a_bg
Constant inlined plus::b_border = main::b_border
Constant inlined plus::a_border = main::a_border
Constant inlined plus::$1 = main::a_bg+main::b_bg
Constant inlined plus::$0 = main::a_border+main::b_border
Constant inlined main::c_bg#0 = plus::return_bg
Successful SSA optimization Pass2ConstantInlining
Adding NOP phi() at start of main
Adding NOP phi() at start of plus
CALL GRAPH
Calls in [main] to plus:1
Created 0 initial phi equivalence classes
Coalesced down to 0 phi equivalence classes
Adding NOP phi() at start of main
Adding NOP phi() at start of plus
FINAL CONTROL FLOW GRAPH
void main()
main: scope:[main] from
[0] phi()
[1] callexecute plus
[2] *((char *)COLS) = plus::return_border
[3] *((char *)COLS+OFFSET_STRUCT_COLS_BG) = plus::return_bg
to:main::@return
main::@return: scope:[main] from main
[4] return
to:@return
__varcall struct Cols plus()
plus: scope:[plus] from
[5] phi()
to:plus::@return
plus::@return: scope:[plus] from plus
[6] return
to:@return
VARIABLE REGISTER WEIGHTS
void main()
struct Cols main::c
char main::c_bg
char main::c_border
__varcall struct Cols plus()
Initial phi equivalence classes
Complete equivalence classes
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [2] *((char *)COLS) = plus::return_border [ ] ( [ ] { } ) always clobbers reg byte a
Statement [3] *((char *)COLS+OFFSET_STRUCT_COLS_BG) = plus::return_bg [ ] ( [ ] { } ) always clobbers reg byte a
REGISTER UPLIFT SCOPES
Uplift Scope [Cols]
Uplift Scope [plus]
Uplift Scope [main]
Uplift Scope []
Uplifting [Cols] best 63 combination
Uplifting [plus] best 63 combination
Uplifting [main] best 63 combination
Uplifting [] best 63 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Test __varcall calling convention
// Struct parameter & return value - only a single call
// Upstart
// Commodore 64 PRG executable file
.file [name="varcall-7.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
// Global Constants & labels
.const OFFSET_STRUCT_COLS_BG = 1
.label COLS = $d020
.segment Code
// main
main: {
.label a_border = 1
.label a_bg = 2
.label b_border = 2
.label b_bg = 3
// [1] callexecute plus -- call_vprc1
jsr plus
// [2] *((char *)COLS) = plus::return_border -- _deref_pbuc1=vbuc2
lda #plus.return_border
sta COLS
// [3] *((char *)COLS+OFFSET_STRUCT_COLS_BG) = plus::return_bg -- _deref_pbuc1=vbuc2
lda #plus.return_bg
sta COLS+OFFSET_STRUCT_COLS_BG
jmp __breturn
// main::@return
__breturn:
// [4] return
rts
}
// plus
plus: {
.label return_border = main.a_border+main.b_border
.label return_bg = main.a_bg+main.b_bg
jmp __breturn
// plus::@return
__breturn:
// [6] return
rts
}
// File Data
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __breturn
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction __breturn:
Removing instruction __breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
__constant struct Cols * const COLS = (struct Cols *) 53280
__constant char OFFSET_STRUCT_COLS_BG = 1
void main()
__constant char main::a_bg = 2
__constant char main::a_border = 1
__constant char main::b_bg = 3
__constant char main::b_border = 2
struct Cols main::c
char main::c_bg
char main::c_border
__varcall struct Cols plus()
__constant char plus::return_bg = main::a_bg+main::b_bg
__constant char plus::return_border = main::a_border+main::b_border
FINAL ASSEMBLER
Score: 30
// File Comments
// Test __varcall calling convention
// Struct parameter & return value - only a single call
// Upstart
// Commodore 64 PRG executable file
.file [name="varcall-7.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
// Global Constants & labels
.const OFFSET_STRUCT_COLS_BG = 1
.label COLS = $d020
.segment Code
// main
main: {
.label a_border = 1
.label a_bg = 2
.label b_border = 2
.label b_bg = 3
// struct Cols c = plus(a, b)
// [1] callexecute plus -- call_vprc1
jsr plus
// *COLS = c
// [2] *((char *)COLS) = plus::return_border -- _deref_pbuc1=vbuc2
lda #plus.return_border
sta COLS
// [3] *((char *)COLS+OFFSET_STRUCT_COLS_BG) = plus::return_bg -- _deref_pbuc1=vbuc2
lda #plus.return_bg
sta COLS+OFFSET_STRUCT_COLS_BG
// main::@return
// }
// [4] return
rts
}
// plus
plus: {
.label return_border = main.a_border+main.b_border
.label return_bg = main.a_bg+main.b_bg
// plus::@return
// [6] return
rts
}
// File Data

View File

@ -0,0 +1,14 @@
__constant struct Cols * const COLS = (struct Cols *) 53280
__constant char OFFSET_STRUCT_COLS_BG = 1
void main()
__constant char main::a_bg = 2
__constant char main::a_border = 1
__constant char main::b_bg = 3
__constant char main::b_border = 2
struct Cols main::c
char main::c_bg
char main::c_border
__varcall struct Cols plus()
__constant char plus::return_bg = main::a_bg+main::b_bg
__constant char plus::return_border = main::a_border+main::b_border

102
src/test/ref/varcall-8.asm Normal file
View File

@ -0,0 +1,102 @@
// Test __varcall calling convention
// Pointer to Struct parameter & return value
// Commodore 64 PRG executable file
.file [name="varcall-8.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
.const SIZEOF_STRUCT_COLS = 2
.const OFFSET_STRUCT_COLS_BG = 1
.label COLS = $d020
.segment Code
main: {
.label a = 6
.label b = 8
.label c = $a
.label m = 2
// struct Cols a = { 1, 7 }
ldy #SIZEOF_STRUCT_COLS
!:
lda __0-1,y
sta a-1,y
dey
bne !-
// struct Cols b = { 2, 6 }
ldy #SIZEOF_STRUCT_COLS
!:
lda __1-1,y
sta b-1,y
dey
bne !-
// struct Cols c = { 3, 5 }
ldy #SIZEOF_STRUCT_COLS
!:
lda __2-1,y
sta c-1,y
dey
bne !-
// struct Cols *m = min(&a,&b)
lda #<a
sta.z min.a
lda #>a
sta.z min.a+1
lda #<b
sta.z min.b
lda #>b
sta.z min.b+1
jsr min
// *COLS = *m
ldx #SIZEOF_STRUCT_COLS
ldy #0
!:
lda (m),y
sta COLS,y
iny
dex
bne !-
// min(m,&c)
lda #<c
sta.z min.b
lda #>c
sta.z min.b+1
jsr min
// m = min(m,&c)
// *COLS = *m
ldx #SIZEOF_STRUCT_COLS
ldy #0
!:
lda (m),y
sta COLS,y
iny
dex
bne !-
// }
rts
}
// __zp(2) struct Cols * min(__zp(2) struct Cols *a, __zp(4) struct Cols *b)
min: {
.label a = 2
.label b = 4
.label return = 2
// if(a->bg < b->bg)
ldy #OFFSET_STRUCT_COLS_BG
lda (b),y
cmp (a),y
bcc __breturn
// return b;
lda.z b
sta.z return
lda.z b+1
sta.z return+1
__breturn:
// }
rts
// return a;
}
.segment Data
__0: .byte 1, 7
__1: .byte 2, 6
__2: .byte 3, 5

View File

@ -0,0 +1,34 @@
void main()
main: scope:[main] from
[0] *(&main::a) = memcpy(*(&$0), struct Cols, SIZEOF_STRUCT_COLS)
[1] *(&main::b) = memcpy(*(&$1), struct Cols, SIZEOF_STRUCT_COLS)
[2] *(&main::c) = memcpy(*(&$2), struct Cols, SIZEOF_STRUCT_COLS)
[3] min::a = &main::a
[4] min::b = &main::b
[5] callexecute min
[6] main::m#0 = min::return
[7] *COLS = memcpy(*main::m#0, struct Cols, SIZEOF_STRUCT_COLS)
[8] min::a = main::m#0
[9] min::b = &main::c
[10] callexecute min
[11] main::m#1 = min::return
[12] *COLS = memcpy(*main::m#1, struct Cols, SIZEOF_STRUCT_COLS)
to:main::@return
main::@return: scope:[main] from main
[13] return
to:@return
__varcall struct Cols * min(struct Cols *a , struct Cols *b)
min: scope:[min] from
[14] if(((char *)min::a)[OFFSET_STRUCT_COLS_BG]<((char *)min::b)[OFFSET_STRUCT_COLS_BG]) goto min::@1
to:min::@2
min::@2: scope:[min] from min
[15] min::return = min::b
to:min::@return
min::@return: scope:[min] from min::@1 min::@2
[16] return
to:@return
min::@1: scope:[min] from min
[17] min::return = min::a
to:min::@return

539
src/test/ref/varcall-8.log Normal file
View File

@ -0,0 +1,539 @@
Setting struct to load/store in variable affected by address-of main::m = call min(&main::a, &main::b)
Setting struct to load/store in variable affected by address-of main::m = call min(&main::a, &main::b)
Setting struct to load/store in variable affected by address-of main::$1 = call min(main::m, &main::c)
Converting parameter in __varcall procedure to load/store min::a
Converting parameter in __varcall procedure to load/store min::b
Converting return in __varcall procedure to load/store min::return
Eliminating unused variable with no statement main::$0
Calling convention __varcall adding prepare/execute/finalize for main::m = call min(&main::a, &main::b)
Calling convention __varcall adding prepare/execute/finalize for main::$1 = call min(main::m, &main::c)
Calling convention VAR_CALL adding return value assignment main::m = min::return
Calling convention VAR_CALL adding return value assignment main::$1 = min::return
Removing C-classic struct-unwound assignment main::a = struct-unwound {*(&main::a)}
Removing C-classic struct-unwound assignment main::b = struct-unwound {*(&main::b)}
Removing C-classic struct-unwound assignment main::c = struct-unwound {*(&main::c)}
CONTROL FLOW GRAPH SSA
__varcall struct Cols * min(struct Cols *a , struct Cols *b)
min: scope:[min] from
min::$3 = (char *)min::a
min::$1 = min::$3 + OFFSET_STRUCT_COLS_BG
min::$4 = (char *)min::b
min::$2 = min::$4 + OFFSET_STRUCT_COLS_BG
min::$0 = *min::$1 < *min::$2
if(min::$0) goto min::@1
to:min::@2
min::@1: scope:[min] from min
min::return = min::a
to:min::@return
min::@2: scope:[min] from min
min::return = min::b
to:min::@return
min::@return: scope:[min] from min::@1 min::@2
return
to:@return
void main()
main: scope:[main] from __start
*(&main::a) = memcpy(*(&$0), struct Cols, SIZEOF_STRUCT_COLS)
*(&main::b) = memcpy(*(&$1), struct Cols, SIZEOF_STRUCT_COLS)
*(&main::c) = memcpy(*(&$2), struct Cols, SIZEOF_STRUCT_COLS)
min::a = &main::a
min::b = &main::b
callexecute min
main::m#0 = min::return
*COLS = memcpy(*main::m#0, struct Cols, SIZEOF_STRUCT_COLS)
min::a = main::m#0
min::b = &main::c
callexecute min
main::$1 = min::return
main::m#1 = main::$1
*COLS = memcpy(*main::m#1, struct Cols, SIZEOF_STRUCT_COLS)
to:main::@return
main::@return: scope:[main] from main
return
to:@return
void __start()
__start: scope:[__start] from
call main
to:__start::@1
__start::@1: scope:[__start] from __start
to:__start::@return
__start::@return: scope:[__start] from __start::@1
return
to:@return
SYMBOL TABLE SSA
__constant struct Cols $0 = { border: 1, bg: 7 }
__constant struct Cols $1 = { border: 2, bg: 6 }
__constant struct Cols $2 = { border: 3, bg: 5 }
__constant struct Cols * const COLS = (struct Cols *)$d020
__constant char OFFSET_STRUCT_COLS_BG = 1
__constant char SIZEOF_STRUCT_COLS = 2
void __start()
void main()
struct Cols *main::$1
__loadstore volatile struct Cols main::a
__loadstore volatile struct Cols main::b
__loadstore volatile struct Cols main::c
struct Cols *main::m
struct Cols *main::m#0
struct Cols *main::m#1
__varcall struct Cols * min(struct Cols *a , struct Cols *b)
bool min::$0
char *min::$1
char *min::$2
char *min::$3
char *min::$4
__loadstore struct Cols *min::a
__loadstore struct Cols *min::b
__loadstore struct Cols *min::return
Simplifying constant pointer cast (struct Cols *) 53280
Successful SSA optimization PassNCastSimplification
Alias main::m#1 = main::$1
Successful SSA optimization Pass2AliasElimination
Simple Condition min::$0 [5] if(*min::$1<*min::$2) goto min::@1
Successful SSA optimization Pass2ConditionalJumpSimplification
Converting *(pointer+n) to pointer[n] [5] if(*min::$1<*min::$2) goto min::@1 -- min::$3[OFFSET_STRUCT_COLS_BG]
Converting *(pointer+n) to pointer[n] [5] if(min::$3[OFFSET_STRUCT_COLS_BG]<*min::$2) goto min::@1 -- min::$4[OFFSET_STRUCT_COLS_BG]
Successful SSA optimization Pass2InlineDerefIdx
Eliminating unused variable min::$1 and assignment [1] min::$1 = min::$3 + OFFSET_STRUCT_COLS_BG
Eliminating unused variable min::$2 and assignment [3] min::$2 = min::$4 + OFFSET_STRUCT_COLS_BG
Successful SSA optimization PassNEliminateUnusedVars
Removing unused procedure __start
Removing unused procedure block __start
Removing unused procedure block __start::@1
Removing unused procedure block __start::@return
Successful SSA optimization PassNEliminateEmptyStart
Inlining Noop Cast [0] min::$3 = (char *)min::a keeping min::a
Inlining Noop Cast [1] min::$4 = (char *)min::b keeping min::b
Successful SSA optimization Pass2NopCastInlining
CALL GRAPH
Calls in [main] to min:5 min:10
Created 0 initial phi equivalence classes
Coalesced down to 0 phi equivalence classes
FINAL CONTROL FLOW GRAPH
void main()
main: scope:[main] from
[0] *(&main::a) = memcpy(*(&$0), struct Cols, SIZEOF_STRUCT_COLS)
[1] *(&main::b) = memcpy(*(&$1), struct Cols, SIZEOF_STRUCT_COLS)
[2] *(&main::c) = memcpy(*(&$2), struct Cols, SIZEOF_STRUCT_COLS)
[3] min::a = &main::a
[4] min::b = &main::b
[5] callexecute min
[6] main::m#0 = min::return
[7] *COLS = memcpy(*main::m#0, struct Cols, SIZEOF_STRUCT_COLS)
[8] min::a = main::m#0
[9] min::b = &main::c
[10] callexecute min
[11] main::m#1 = min::return
[12] *COLS = memcpy(*main::m#1, struct Cols, SIZEOF_STRUCT_COLS)
to:main::@return
main::@return: scope:[main] from main
[13] return
to:@return
__varcall struct Cols * min(struct Cols *a , struct Cols *b)
min: scope:[min] from
[14] if(((char *)min::a)[OFFSET_STRUCT_COLS_BG]<((char *)min::b)[OFFSET_STRUCT_COLS_BG]) goto min::@1
to:min::@2
min::@2: scope:[min] from min
[15] min::return = min::b
to:min::@return
min::@return: scope:[min] from min::@1 min::@2
[16] return
to:@return
min::@1: scope:[min] from min
[17] min::return = min::a
to:min::@return
VARIABLE REGISTER WEIGHTS
void main()
__loadstore volatile struct Cols main::a
__loadstore volatile struct Cols main::b
__loadstore volatile struct Cols main::c
struct Cols *main::m
struct Cols *main::m#0 // 2.0
struct Cols *main::m#1 // 2.0
__varcall struct Cols * min(struct Cols *a , struct Cols *b)
__loadstore struct Cols *min::a // 3.0
__loadstore struct Cols *min::b // 5.0
__loadstore struct Cols *min::return // 5.2
Initial phi equivalence classes
Added variable min::a to live range equivalence class [ min::a ]
Added variable min::b to live range equivalence class [ min::b ]
Added variable main::m#0 to live range equivalence class [ main::m#0 ]
Added variable main::m#1 to live range equivalence class [ main::m#1 ]
Added variable min::return to live range equivalence class [ min::return ]
Added variable main::a to live range equivalence class [ main::a ]
Added variable main::b to live range equivalence class [ main::b ]
Added variable main::c to live range equivalence class [ main::c ]
Complete equivalence classes
[ min::a ]
[ min::b ]
[ main::m#0 ]
[ main::m#1 ]
[ min::return ]
[ main::a ]
[ main::b ]
[ main::c ]
Allocated zp[2]:2 [ min::return ]
Allocated zp[2]:4 [ min::b ]
Allocated zp[2]:6 [ min::a ]
Allocated zp[2]:8 [ main::m#0 ]
Allocated zp[2]:10 [ main::m#1 ]
Allocated zp[2]:12 [ main::a ]
Allocated zp[2]:14 [ main::b ]
Allocated zp[2]:16 [ main::c ]
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [0] *(&main::a) = memcpy(*(&$0), struct Cols, SIZEOF_STRUCT_COLS) [ main::b main::c main::a ] ( [ main::b main::c main::a ] { } ) always clobbers reg byte a reg byte y
Statement [1] *(&main::b) = memcpy(*(&$1), struct Cols, SIZEOF_STRUCT_COLS) [ main::b main::c main::a ] ( [ main::b main::c main::a ] { } ) always clobbers reg byte a reg byte y
Statement [2] *(&main::c) = memcpy(*(&$2), struct Cols, SIZEOF_STRUCT_COLS) [ main::b main::c main::a ] ( [ main::b main::c main::a ] { } ) always clobbers reg byte a reg byte y
Statement [3] min::a = &main::a [ main::b main::c min::a ] ( [ main::b main::c min::a ] { } ) always clobbers reg byte a
Statement [4] min::b = &main::b [ main::c min::a min::b ] ( [ main::c min::a min::b ] { } ) always clobbers reg byte a
Statement [6] main::m#0 = min::return [ main::c main::m#0 ] ( [ main::c main::m#0 ] { } ) always clobbers reg byte a
Statement [7] *COLS = memcpy(*main::m#0, struct Cols, SIZEOF_STRUCT_COLS) [ main::c main::m#0 ] ( [ main::c main::m#0 ] { } ) always clobbers reg byte a reg byte x reg byte y
Statement [8] min::a = main::m#0 [ main::c min::a ] ( [ main::c min::a ] { } ) always clobbers reg byte a
Statement [9] min::b = &main::c [ min::a min::b ] ( [ min::a min::b ] { } ) always clobbers reg byte a
Statement [11] main::m#1 = min::return [ main::m#1 ] ( [ main::m#1 ] { } ) always clobbers reg byte a
Statement [12] *COLS = memcpy(*main::m#1, struct Cols, SIZEOF_STRUCT_COLS) [ ] ( [ ] { } ) always clobbers reg byte a reg byte x reg byte y
Statement [14] if(((char *)min::a)[OFFSET_STRUCT_COLS_BG]<((char *)min::b)[OFFSET_STRUCT_COLS_BG]) goto min::@1 [ min::a min::b ] ( min:5 [ main::c min::a min::b ] { { main::m#0 = min::a } } min:10 [ min::a min::b ] { { main::m#0 = min::a } } ) always clobbers reg byte a reg byte y
Statement [15] min::return = min::b [ min::return ] ( min:5 [ main::c min::return ] { { main::m#0 = min::a } } min:10 [ min::return ] { { main::m#0 = min::a } } ) always clobbers reg byte a
Statement [17] min::return = min::a [ min::return ] ( min:5 [ main::c min::return ] { { main::m#0 = min::a } } min:10 [ min::return ] { { main::m#0 = min::a } } ) always clobbers reg byte a
Potential registers zp[2]:6 [ min::a ] : zp[2]:6 ,
Potential registers zp[2]:4 [ min::b ] : zp[2]:4 ,
Potential registers zp[2]:8 [ main::m#0 ] : zp[2]:8 ,
Potential registers zp[2]:10 [ main::m#1 ] : zp[2]:10 ,
Potential registers zp[2]:2 [ min::return ] : zp[2]:2 ,
Potential registers zp[2]:12 [ main::a ] : zp[2]:12 ,
Potential registers zp[2]:14 [ main::b ] : zp[2]:14 ,
Potential registers zp[2]:16 [ main::c ] : zp[2]:16 ,
REGISTER UPLIFT SCOPES
Uplift Scope [min] 5.2: zp[2]:2 [ min::return ] 5: zp[2]:4 [ min::b ] 3: zp[2]:6 [ min::a ]
Uplift Scope [main] 2: zp[2]:8 [ main::m#0 ] 2: zp[2]:10 [ main::m#1 ] 0: zp[2]:12 [ main::a ] 0: zp[2]:14 [ main::b ] 0: zp[2]:16 [ main::c ]
Uplift Scope [Cols]
Uplift Scope []
Uplifting [min] best 231 combination zp[2]:2 [ min::return ] zp[2]:4 [ min::b ] zp[2]:6 [ min::a ]
Uplifting [main] best 231 combination zp[2]:8 [ main::m#0 ] zp[2]:10 [ main::m#1 ] zp[2]:12 [ main::a ] zp[2]:14 [ main::b ] zp[2]:16 [ main::c ]
Uplifting [Cols] best 231 combination
Uplifting [] best 231 combination
Coalescing zero page register [ zp[2]:6 [ min::a ] ] with [ zp[2]:8 [ main::m#0 ] ] - score: 1
Coalescing zero page register [ zp[2]:6 [ min::a main::m#0 ] ] with [ zp[2]:2 [ min::return ] ] - score: 1
Coalescing zero page register [ zp[2]:6 [ min::a main::m#0 min::return ] ] with [ zp[2]:10 [ main::m#1 ] ] - score: 1
Allocated (was zp[2]:6) zp[2]:2 [ min::a main::m#0 min::return main::m#1 ]
Allocated (was zp[2]:12) zp[2]:6 [ main::a ]
Allocated (was zp[2]:14) zp[2]:8 [ main::b ]
Allocated (was zp[2]:16) zp[2]:10 [ main::c ]
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Test __varcall calling convention
// Pointer to Struct parameter & return value
// Upstart
// Commodore 64 PRG executable file
.file [name="varcall-8.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
// Global Constants & labels
.const SIZEOF_STRUCT_COLS = 2
.const OFFSET_STRUCT_COLS_BG = 1
.label COLS = $d020
.segment Code
// main
main: {
.label a = 6
.label b = 8
.label c = $a
.label m = 2
// [0] *(&main::a) = memcpy(*(&$0), struct Cols, SIZEOF_STRUCT_COLS) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3
ldy #SIZEOF_STRUCT_COLS
!:
lda __0-1,y
sta a-1,y
dey
bne !-
// [1] *(&main::b) = memcpy(*(&$1), struct Cols, SIZEOF_STRUCT_COLS) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3
ldy #SIZEOF_STRUCT_COLS
!:
lda __1-1,y
sta b-1,y
dey
bne !-
// [2] *(&main::c) = memcpy(*(&$2), struct Cols, SIZEOF_STRUCT_COLS) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3
ldy #SIZEOF_STRUCT_COLS
!:
lda __2-1,y
sta c-1,y
dey
bne !-
// [3] min::a = &main::a -- pssz1=pssc1
lda #<a
sta.z min.a
lda #>a
sta.z min.a+1
// [4] min::b = &main::b -- pssz1=pssc1
lda #<b
sta.z min.b
lda #>b
sta.z min.b+1
// [5] callexecute min -- call_vprc1
jsr min
// [6] main::m#0 = min::return
// [7] *COLS = memcpy(*main::m#0, struct Cols, SIZEOF_STRUCT_COLS) -- _deref_pssc1=_deref_pssz1_memcpy_vbuc2
ldx #SIZEOF_STRUCT_COLS
ldy #0
!:
lda (m),y
sta COLS,y
iny
dex
bne !-
// [8] min::a = main::m#0
// [9] min::b = &main::c -- pssz1=pssc1
lda #<c
sta.z min.b
lda #>c
sta.z min.b+1
// [10] callexecute min -- call_vprc1
jsr min
// [11] main::m#1 = min::return
// [12] *COLS = memcpy(*main::m#1, struct Cols, SIZEOF_STRUCT_COLS) -- _deref_pssc1=_deref_pssz1_memcpy_vbuc2
ldx #SIZEOF_STRUCT_COLS
ldy #0
!:
lda (m),y
sta COLS,y
iny
dex
bne !-
jmp __breturn
// main::@return
__breturn:
// [13] return
rts
}
// min
// __zp(2) struct Cols * min(__zp(2) struct Cols *a, __zp(4) struct Cols *b)
min: {
.label a = 2
.label b = 4
.label return = 2
// [14] if(((char *)min::a)[OFFSET_STRUCT_COLS_BG]<((char *)min::b)[OFFSET_STRUCT_COLS_BG]) goto min::@1 -- pbuz1_derefidx_vbuc1_lt_pbuz2_derefidx_vbuc1_then_la1
ldy #OFFSET_STRUCT_COLS_BG
lda (b),y
cmp (a),y
bcc __b1
jmp __b2
// min::@2
__b2:
// [15] min::return = min::b -- pssz1=pssz2
lda.z b
sta.z return
lda.z b+1
sta.z return+1
jmp __breturn
// min::@return
__breturn:
// [16] return
rts
// min::@1
__b1:
// [17] min::return = min::a
jmp __breturn
}
// File Data
.segment Data
__0: .byte 1, 7
__1: .byte 2, 6
__2: .byte 3, 5
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __breturn
Removing instruction jmp __b2
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction __breturn:
Removing instruction __b2:
Succesful ASM optimization Pass5UnusedLabelElimination
Skipping double jump to __breturn in bcc __b1
Replacing jump to rts with rts in jmp __breturn
Succesful ASM optimization Pass5DoubleJumpElimination
Removing instruction __b1:
Succesful ASM optimization Pass5UnusedLabelElimination
Removing unreachable instruction rts
Succesful ASM optimization Pass5UnreachableCodeElimination
FINAL SYMBOL TABLE
__constant struct Cols $0 = { border: 1, bg: 7 }
__constant struct Cols $1 = { border: 2, bg: 6 }
__constant struct Cols $2 = { border: 3, bg: 5 }
__constant struct Cols * const COLS = (struct Cols *) 53280
__constant char OFFSET_STRUCT_COLS_BG = 1
__constant char SIZEOF_STRUCT_COLS = 2
void main()
__loadstore volatile struct Cols main::a // zp[2]:6
__loadstore volatile struct Cols main::b // zp[2]:8
__loadstore volatile struct Cols main::c // zp[2]:10
struct Cols *main::m
struct Cols *main::m#0 // m zp[2]:2 2.0
struct Cols *main::m#1 // m zp[2]:2 2.0
__varcall struct Cols * min(struct Cols *a , struct Cols *b)
__loadstore struct Cols *min::a // zp[2]:2 3.0
__loadstore struct Cols *min::b // zp[2]:4 5.0
__loadstore struct Cols *min::return // zp[2]:2 5.2
zp[2]:2 [ min::a main::m#0 min::return main::m#1 ]
zp[2]:4 [ min::b ]
zp[2]:6 [ main::a ]
zp[2]:8 [ main::b ]
zp[2]:10 [ main::c ]
FINAL ASSEMBLER
Score: 171
// File Comments
// Test __varcall calling convention
// Pointer to Struct parameter & return value
// Upstart
// Commodore 64 PRG executable file
.file [name="varcall-8.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
// Global Constants & labels
.const SIZEOF_STRUCT_COLS = 2
.const OFFSET_STRUCT_COLS_BG = 1
.label COLS = $d020
.segment Code
// main
main: {
.label a = 6
.label b = 8
.label c = $a
.label m = 2
// struct Cols a = { 1, 7 }
// [0] *(&main::a) = memcpy(*(&$0), struct Cols, SIZEOF_STRUCT_COLS) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3
ldy #SIZEOF_STRUCT_COLS
!:
lda __0-1,y
sta a-1,y
dey
bne !-
// struct Cols b = { 2, 6 }
// [1] *(&main::b) = memcpy(*(&$1), struct Cols, SIZEOF_STRUCT_COLS) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3
ldy #SIZEOF_STRUCT_COLS
!:
lda __1-1,y
sta b-1,y
dey
bne !-
// struct Cols c = { 3, 5 }
// [2] *(&main::c) = memcpy(*(&$2), struct Cols, SIZEOF_STRUCT_COLS) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3
ldy #SIZEOF_STRUCT_COLS
!:
lda __2-1,y
sta c-1,y
dey
bne !-
// struct Cols *m = min(&a,&b)
// [3] min::a = &main::a -- pssz1=pssc1
lda #<a
sta.z min.a
lda #>a
sta.z min.a+1
// [4] min::b = &main::b -- pssz1=pssc1
lda #<b
sta.z min.b
lda #>b
sta.z min.b+1
// [5] callexecute min -- call_vprc1
jsr min
// [6] main::m#0 = min::return
// *COLS = *m
// [7] *COLS = memcpy(*main::m#0, struct Cols, SIZEOF_STRUCT_COLS) -- _deref_pssc1=_deref_pssz1_memcpy_vbuc2
ldx #SIZEOF_STRUCT_COLS
ldy #0
!:
lda (m),y
sta COLS,y
iny
dex
bne !-
// min(m,&c)
// [8] min::a = main::m#0
// [9] min::b = &main::c -- pssz1=pssc1
lda #<c
sta.z min.b
lda #>c
sta.z min.b+1
// [10] callexecute min -- call_vprc1
jsr min
// m = min(m,&c)
// [11] main::m#1 = min::return
// *COLS = *m
// [12] *COLS = memcpy(*main::m#1, struct Cols, SIZEOF_STRUCT_COLS) -- _deref_pssc1=_deref_pssz1_memcpy_vbuc2
ldx #SIZEOF_STRUCT_COLS
ldy #0
!:
lda (m),y
sta COLS,y
iny
dex
bne !-
// main::@return
// }
// [13] return
rts
}
// min
// __zp(2) struct Cols * min(__zp(2) struct Cols *a, __zp(4) struct Cols *b)
min: {
.label a = 2
.label b = 4
.label return = 2
// if(a->bg < b->bg)
// [14] if(((char *)min::a)[OFFSET_STRUCT_COLS_BG]<((char *)min::b)[OFFSET_STRUCT_COLS_BG]) goto min::@1 -- pbuz1_derefidx_vbuc1_lt_pbuz2_derefidx_vbuc1_then_la1
ldy #OFFSET_STRUCT_COLS_BG
lda (b),y
cmp (a),y
bcc __breturn
// min::@2
// return b;
// [15] min::return = min::b -- pssz1=pssz2
lda.z b
sta.z return
lda.z b+1
sta.z return+1
// min::@return
__breturn:
// }
// [16] return
rts
// min::@1
// return a;
// [17] min::return = min::a
}
// File Data
.segment Data
__0: .byte 1, 7
__1: .byte 2, 6
__2: .byte 3, 5

View File

@ -0,0 +1,23 @@
__constant struct Cols $0 = { border: 1, bg: 7 }
__constant struct Cols $1 = { border: 2, bg: 6 }
__constant struct Cols $2 = { border: 3, bg: 5 }
__constant struct Cols * const COLS = (struct Cols *) 53280
__constant char OFFSET_STRUCT_COLS_BG = 1
__constant char SIZEOF_STRUCT_COLS = 2
void main()
__loadstore volatile struct Cols main::a // zp[2]:6
__loadstore volatile struct Cols main::b // zp[2]:8
__loadstore volatile struct Cols main::c // zp[2]:10
struct Cols *main::m
struct Cols *main::m#0 // m zp[2]:2 2.0
struct Cols *main::m#1 // m zp[2]:2 2.0
__varcall struct Cols * min(struct Cols *a , struct Cols *b)
__loadstore struct Cols *min::a // zp[2]:2 3.0
__loadstore struct Cols *min::b // zp[2]:4 5.0
__loadstore struct Cols *min::return // zp[2]:2 5.2
zp[2]:2 [ min::a main::m#0 min::return main::m#1 ]
zp[2]:4 [ min::b ]
zp[2]:6 [ main::a ]
zp[2]:8 [ main::b ]
zp[2]:10 [ main::c ]

108
src/test/ref/varcall-9.asm Normal file
View File

@ -0,0 +1,108 @@
// Test __varcall calling convention
// Struct of struct parameter value
// Commodore 64 PRG executable file
.file [name="varcall-9.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
.label COLS = $d020
.segment Code
main: {
.const a_normal_border = 1
.const a_normal_bg = 2
.const a_error_border = 3
.const a_error_bg = 4
.const b_normal_border = 5
.const b_normal_bg = 6
.const b_error_border = 7
.const b_error_bg = 8
.const c_normal_border = 9
.const c_normal_bg = $a
.const c_error_border = $b
.const c_error_bg = $c
// plus(a, b)
lda #a_normal_border
sta.z plus.a_normal_border
lda #a_normal_bg
sta.z plus.a_normal_bg
lda #a_error_border
sta.z plus.a_error_border
lda #a_error_bg
sta.z plus.a_error_bg
lda #b_normal_border
sta.z plus.b_normal_border
lda #b_normal_bg
sta.z plus.b_normal_bg
lda #b_error_border
sta.z plus.b_error_border
lda #b_error_bg
sta.z plus.b_error_bg
jsr plus
lda.z plus.return
// *COLS = plus(a, b)
sta COLS
// plus(b, c)
lda #b_normal_border
sta.z plus.a_normal_border
lda #b_normal_bg
sta.z plus.a_normal_bg
lda #b_error_border
sta.z plus.a_error_border
lda #b_error_bg
sta.z plus.a_error_bg
lda #c_normal_border
sta.z plus.b_normal_border
lda #c_normal_bg
sta.z plus.b_normal_bg
lda #c_error_border
sta.z plus.b_error_border
lda #c_error_bg
sta.z plus.b_error_bg
jsr plus
lda.z plus.return
// *COLS = plus(b, c)
sta COLS
// }
rts
}
// __zp(2) char plus(__zp($a) char a_normal_border, __zp(7) char a_normal_bg, __zp(8) char a_error_border, __zp(9) char a_error_bg, __zp(3) char b_normal_border, __zp(4) char b_normal_bg, __zp(5) char b_error_border, __zp(6) char b_error_bg)
plus: {
.label return = 2
.label a_normal_border = $a
.label a_normal_bg = 7
.label a_error_border = 8
.label a_error_bg = 9
.label b_normal_border = 3
.label b_normal_bg = 4
.label b_error_border = 5
.label b_error_bg = 6
// a.normal.border + b.normal.border
lda.z a_normal_border
clc
adc.z b_normal_border
// a.normal.border + b.normal.border + a.normal.bg
clc
adc.z a_normal_bg
// a.normal.border + b.normal.border + a.normal.bg + b.normal.bg
clc
adc.z b_normal_bg
// a.normal.border + b.normal.border + a.normal.bg + b.normal.bg + a.error.border
clc
adc.z a_error_border
// a.normal.border + b.normal.border + a.normal.bg + b.normal.bg + a.error.border + b.error.border
clc
adc.z b_error_border
// a.normal.border + b.normal.border + a.normal.bg + b.normal.bg + a.error.border + b.error.border + a.error.bg
clc
adc.z a_error_bg
// a.normal.border + b.normal.border + a.normal.bg + b.normal.bg + a.error.border + b.error.border + a.error.bg + b.error.bg
clc
adc.z b_error_bg
// return a.normal.border + b.normal.border + a.normal.bg + b.normal.bg + a.error.border + b.error.border + a.error.bg + b.error.bg;
sta.z return
// }
rts
}

View File

@ -0,0 +1,44 @@
void main()
main: scope:[main] from
[0] plus::a_normal_border = main::a_normal_border
[1] plus::a_normal_bg = main::a_normal_bg
[2] plus::a_error_border = main::a_error_border
[3] plus::a_error_bg = main::a_error_bg
[4] plus::b_normal_border = main::b_normal_border
[5] plus::b_normal_bg = main::b_normal_bg
[6] plus::b_error_border = main::b_error_border
[7] plus::b_error_bg = main::b_error_bg
[8] callexecute plus
[9] main::$0 = plus::return
[10] *COLS = main::$0
[11] plus::a_normal_border = main::b_normal_border
[12] plus::a_normal_bg = main::b_normal_bg
[13] plus::a_error_border = main::b_error_border
[14] plus::a_error_bg = main::b_error_bg
[15] plus::b_normal_border = main::c_normal_border
[16] plus::b_normal_bg = main::c_normal_bg
[17] plus::b_error_border = main::c_error_border
[18] plus::b_error_bg = main::c_error_bg
[19] callexecute plus
[20] main::$1 = plus::return
[21] *COLS = main::$1
to:main::@return
main::@return: scope:[main] from main
[22] return
to:@return
__varcall char plus(char a_normal_border , char a_normal_bg , char a_error_border , char a_error_bg , char b_normal_border , char b_normal_bg , char b_error_border , char b_error_bg)
plus: scope:[plus] from
[23] plus::$0 = plus::a_normal_border + plus::b_normal_border
[24] plus::$1 = plus::$0 + plus::a_normal_bg
[25] plus::$2 = plus::$1 + plus::b_normal_bg
[26] plus::$3 = plus::$2 + plus::a_error_border
[27] plus::$4 = plus::$3 + plus::b_error_border
[28] plus::$5 = plus::$4 + plus::a_error_bg
[29] plus::$6 = plus::$5 + plus::b_error_bg
[30] plus::return = plus::$6
to:plus::@return
plus::@return: scope:[plus] from plus
[31] return
to:@return

711
src/test/ref/varcall-9.log Normal file
View File

@ -0,0 +1,711 @@
Converting parameter in __varcall procedure to load/store plus::a
Converting parameter in __varcall procedure to load/store plus::b
Converting return in __varcall procedure to load/store plus::return
Eliminating unused variable with no statement plus::a
Eliminating unused variable with no statement plus::b
Eliminating unused variable with no statement plus::a_normal
Eliminating unused variable with no statement plus::a_error
Eliminating unused variable with no statement plus::b_normal
Eliminating unused variable with no statement plus::b_error
Calling convention __varcall adding prepare/execute/finalize for main::$0 = call plus(main::a_normal_border, main::a_normal_bg, main::a_error_border, main::a_error_bg, main::b_normal_border, main::b_normal_bg, main::b_error_border, main::b_error_bg)
Calling convention __varcall adding prepare/execute/finalize for main::$1 = call plus(main::b_normal_border, main::b_normal_bg, main::b_error_border, main::b_error_bg, main::c_normal_border, main::c_normal_bg, main::c_error_border, main::c_error_bg)
Calling convention VAR_CALL adding return value assignment main::$0 = plus::return
Calling convention VAR_CALL adding return value assignment main::$1 = plus::return
CONTROL FLOW GRAPH SSA
__varcall char plus(char a_normal_border , char a_normal_bg , char a_error_border , char a_error_bg , char b_normal_border , char b_normal_bg , char b_error_border , char b_error_bg)
plus: scope:[plus] from
plus::$0 = plus::a_normal_border + plus::b_normal_border
plus::$1 = plus::$0 + plus::a_normal_bg
plus::$2 = plus::$1 + plus::b_normal_bg
plus::$3 = plus::$2 + plus::a_error_border
plus::$4 = plus::$3 + plus::b_error_border
plus::$5 = plus::$4 + plus::a_error_bg
plus::$6 = plus::$5 + plus::b_error_bg
plus::return = plus::$6
to:plus::@return
plus::@return: scope:[plus] from plus
return
to:@return
void main()
main: scope:[main] from __start
plus::a_normal_border = main::a_normal_border
plus::a_normal_bg = main::a_normal_bg
plus::a_error_border = main::a_error_border
plus::a_error_bg = main::a_error_bg
plus::b_normal_border = main::b_normal_border
plus::b_normal_bg = main::b_normal_bg
plus::b_error_border = main::b_error_border
plus::b_error_bg = main::b_error_bg
callexecute plus
main::$0 = plus::return
*COLS = main::$0
plus::a_normal_border = main::b_normal_border
plus::a_normal_bg = main::b_normal_bg
plus::a_error_border = main::b_error_border
plus::a_error_bg = main::b_error_bg
plus::b_normal_border = main::c_normal_border
plus::b_normal_bg = main::c_normal_bg
plus::b_error_border = main::c_error_border
plus::b_error_bg = main::c_error_bg
callexecute plus
main::$1 = plus::return
*COLS = main::$1
to:main::@return
main::@return: scope:[main] from main
return
to:@return
void __start()
__start: scope:[__start] from
call main
to:__start::@1
__start::@1: scope:[__start] from __start
to:__start::@return
__start::@return: scope:[__start] from __start::@1
return
to:@return
SYMBOL TABLE SSA
__constant char * const COLS = (char *)$d020
void __start()
void main()
char main::$0
char main::$1
struct Col main::a_error
__constant char main::a_error_bg = 4
__constant char main::a_error_border = 3
struct Col main::a_normal
__constant char main::a_normal_bg = 2
__constant char main::a_normal_border = 1
struct Col main::b_error
__constant char main::b_error_bg = 8
__constant char main::b_error_border = 7
struct Col main::b_normal
__constant char main::b_normal_bg = 6
__constant char main::b_normal_border = 5
struct Col main::c_error
__constant char main::c_error_bg = $c
__constant char main::c_error_border = $b
struct Col main::c_normal
__constant char main::c_normal_bg = $a
__constant char main::c_normal_border = 9
__varcall char plus(char a_normal_border , char a_normal_bg , char a_error_border , char a_error_bg , char b_normal_border , char b_normal_bg , char b_error_border , char b_error_bg)
char plus::$0
char plus::$1
char plus::$2
char plus::$3
char plus::$4
char plus::$5
char plus::$6
__loadstore char plus::a_error_bg
__loadstore char plus::a_error_border
__loadstore char plus::a_normal_bg
__loadstore char plus::a_normal_border
__loadstore char plus::b_error_bg
__loadstore char plus::b_error_border
__loadstore char plus::b_normal_bg
__loadstore char plus::b_normal_border
__loadstore char plus::return
Simplifying constant pointer cast (char *) 53280
Successful SSA optimization PassNCastSimplification
Alias candidate removed (volatile)plus::return = plus::$6
Removing unused procedure __start
Removing unused procedure block __start
Removing unused procedure block __start::@1
Removing unused procedure block __start::@return
Successful SSA optimization PassNEliminateEmptyStart
Alias candidate removed (volatile)plus::return = plus::$6
Alias candidate removed (volatile)plus::return = plus::$6
Alias candidate removed (volatile)plus::return = plus::$6
CALL GRAPH
Calls in [main] to plus:8 plus:19
Created 0 initial phi equivalence classes
Coalesced down to 0 phi equivalence classes
FINAL CONTROL FLOW GRAPH
void main()
main: scope:[main] from
[0] plus::a_normal_border = main::a_normal_border
[1] plus::a_normal_bg = main::a_normal_bg
[2] plus::a_error_border = main::a_error_border
[3] plus::a_error_bg = main::a_error_bg
[4] plus::b_normal_border = main::b_normal_border
[5] plus::b_normal_bg = main::b_normal_bg
[6] plus::b_error_border = main::b_error_border
[7] plus::b_error_bg = main::b_error_bg
[8] callexecute plus
[9] main::$0 = plus::return
[10] *COLS = main::$0
[11] plus::a_normal_border = main::b_normal_border
[12] plus::a_normal_bg = main::b_normal_bg
[13] plus::a_error_border = main::b_error_border
[14] plus::a_error_bg = main::b_error_bg
[15] plus::b_normal_border = main::c_normal_border
[16] plus::b_normal_bg = main::c_normal_bg
[17] plus::b_error_border = main::c_error_border
[18] plus::b_error_bg = main::c_error_bg
[19] callexecute plus
[20] main::$1 = plus::return
[21] *COLS = main::$1
to:main::@return
main::@return: scope:[main] from main
[22] return
to:@return
__varcall char plus(char a_normal_border , char a_normal_bg , char a_error_border , char a_error_bg , char b_normal_border , char b_normal_bg , char b_error_border , char b_error_bg)
plus: scope:[plus] from
[23] plus::$0 = plus::a_normal_border + plus::b_normal_border
[24] plus::$1 = plus::$0 + plus::a_normal_bg
[25] plus::$2 = plus::$1 + plus::b_normal_bg
[26] plus::$3 = plus::$2 + plus::a_error_border
[27] plus::$4 = plus::$3 + plus::b_error_border
[28] plus::$5 = plus::$4 + plus::a_error_bg
[29] plus::$6 = plus::$5 + plus::b_error_bg
[30] plus::return = plus::$6
to:plus::@return
plus::@return: scope:[plus] from plus
[31] return
to:@return
VARIABLE REGISTER WEIGHTS
void main()
char main::$0 // 4.0
char main::$1 // 4.0
struct Col main::a_error
struct Col main::a_normal
struct Col main::b_error
struct Col main::b_normal
struct Col main::c_error
struct Col main::c_normal
__varcall char plus(char a_normal_border , char a_normal_bg , char a_error_border , char a_error_bg , char b_normal_border , char b_normal_bg , char b_error_border , char b_error_bg)
char plus::$0 // 22.0
char plus::$1 // 22.0
char plus::$2 // 22.0
char plus::$3 // 22.0
char plus::$4 // 22.0
char plus::$5 // 22.0
char plus::$6 // 22.0
__loadstore char plus::a_error_bg // 1.0
__loadstore char plus::a_error_border // 1.0
__loadstore char plus::a_normal_bg // 1.0
__loadstore char plus::a_normal_border // 0.9375
__loadstore char plus::b_error_bg // 1.875
__loadstore char plus::b_error_border // 1.875
__loadstore char plus::b_normal_bg // 1.875
__loadstore char plus::b_normal_border // 1.875
__loadstore char plus::return // 3.75
Initial phi equivalence classes
Added variable plus::a_normal_border to live range equivalence class [ plus::a_normal_border ]
Added variable plus::a_normal_bg to live range equivalence class [ plus::a_normal_bg ]
Added variable plus::a_error_border to live range equivalence class [ plus::a_error_border ]
Added variable plus::a_error_bg to live range equivalence class [ plus::a_error_bg ]
Added variable plus::b_normal_border to live range equivalence class [ plus::b_normal_border ]
Added variable plus::b_normal_bg to live range equivalence class [ plus::b_normal_bg ]
Added variable plus::b_error_border to live range equivalence class [ plus::b_error_border ]
Added variable plus::b_error_bg to live range equivalence class [ plus::b_error_bg ]
Added variable main::$0 to live range equivalence class [ main::$0 ]
Added variable main::$1 to live range equivalence class [ main::$1 ]
Added variable plus::$0 to live range equivalence class [ plus::$0 ]
Added variable plus::$1 to live range equivalence class [ plus::$1 ]
Added variable plus::$2 to live range equivalence class [ plus::$2 ]
Added variable plus::$3 to live range equivalence class [ plus::$3 ]
Added variable plus::$4 to live range equivalence class [ plus::$4 ]
Added variable plus::$5 to live range equivalence class [ plus::$5 ]
Added variable plus::$6 to live range equivalence class [ plus::$6 ]
Added variable plus::return to live range equivalence class [ plus::return ]
Complete equivalence classes
[ plus::a_normal_border ]
[ plus::a_normal_bg ]
[ plus::a_error_border ]
[ plus::a_error_bg ]
[ plus::b_normal_border ]
[ plus::b_normal_bg ]
[ plus::b_error_border ]
[ plus::b_error_bg ]
[ main::$0 ]
[ main::$1 ]
[ plus::$0 ]
[ plus::$1 ]
[ plus::$2 ]
[ plus::$3 ]
[ plus::$4 ]
[ plus::$5 ]
[ plus::$6 ]
[ plus::return ]
Allocated zp[1]:2 [ plus::$0 ]
Allocated zp[1]:3 [ plus::$1 ]
Allocated zp[1]:4 [ plus::$2 ]
Allocated zp[1]:5 [ plus::$3 ]
Allocated zp[1]:6 [ plus::$4 ]
Allocated zp[1]:7 [ plus::$5 ]
Allocated zp[1]:8 [ plus::$6 ]
Allocated zp[1]:9 [ main::$0 ]
Allocated zp[1]:10 [ main::$1 ]
Allocated zp[1]:11 [ plus::return ]
Allocated zp[1]:12 [ plus::b_normal_border ]
Allocated zp[1]:13 [ plus::b_normal_bg ]
Allocated zp[1]:14 [ plus::b_error_border ]
Allocated zp[1]:15 [ plus::b_error_bg ]
Allocated zp[1]:16 [ plus::a_normal_bg ]
Allocated zp[1]:17 [ plus::a_error_border ]
Allocated zp[1]:18 [ plus::a_error_bg ]
Allocated zp[1]:19 [ plus::a_normal_border ]
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [0] plus::a_normal_border = main::a_normal_border [ plus::a_normal_border ] ( [ plus::a_normal_border ] { } ) always clobbers reg byte a
Statement [1] plus::a_normal_bg = main::a_normal_bg [ plus::a_normal_border plus::a_normal_bg ] ( [ plus::a_normal_border plus::a_normal_bg ] { } ) always clobbers reg byte a
Statement [2] plus::a_error_border = main::a_error_border [ plus::a_normal_border plus::a_normal_bg plus::a_error_border ] ( [ plus::a_normal_border plus::a_normal_bg plus::a_error_border ] { } ) always clobbers reg byte a
Statement [3] plus::a_error_bg = main::a_error_bg [ plus::a_normal_border plus::a_normal_bg plus::a_error_border plus::a_error_bg ] ( [ plus::a_normal_border plus::a_normal_bg plus::a_error_border plus::a_error_bg ] { } ) always clobbers reg byte a
Statement [4] plus::b_normal_border = main::b_normal_border [ plus::a_normal_border plus::a_normal_bg plus::a_error_border plus::a_error_bg plus::b_normal_border ] ( [ plus::a_normal_border plus::a_normal_bg plus::a_error_border plus::a_error_bg plus::b_normal_border ] { } ) always clobbers reg byte a
Statement [5] plus::b_normal_bg = main::b_normal_bg [ plus::a_normal_border plus::a_normal_bg plus::a_error_border plus::a_error_bg plus::b_normal_border plus::b_normal_bg ] ( [ plus::a_normal_border plus::a_normal_bg plus::a_error_border plus::a_error_bg plus::b_normal_border plus::b_normal_bg ] { } ) always clobbers reg byte a
Statement [6] plus::b_error_border = main::b_error_border [ plus::a_normal_border plus::a_normal_bg plus::a_error_border plus::a_error_bg plus::b_normal_border plus::b_normal_bg plus::b_error_border ] ( [ plus::a_normal_border plus::a_normal_bg plus::a_error_border plus::a_error_bg plus::b_normal_border plus::b_normal_bg plus::b_error_border ] { } ) always clobbers reg byte a
Statement [7] plus::b_error_bg = main::b_error_bg [ plus::a_normal_border plus::a_normal_bg plus::a_error_border plus::a_error_bg plus::b_normal_border plus::b_normal_bg plus::b_error_border plus::b_error_bg ] ( [ plus::a_normal_border plus::a_normal_bg plus::a_error_border plus::a_error_bg plus::b_normal_border plus::b_normal_bg plus::b_error_border plus::b_error_bg ] { } ) always clobbers reg byte a
Statement [11] plus::a_normal_border = main::b_normal_border [ plus::a_normal_border ] ( [ plus::a_normal_border ] { } ) always clobbers reg byte a
Statement [12] plus::a_normal_bg = main::b_normal_bg [ plus::a_normal_border plus::a_normal_bg ] ( [ plus::a_normal_border plus::a_normal_bg ] { } ) always clobbers reg byte a
Statement [13] plus::a_error_border = main::b_error_border [ plus::a_normal_border plus::a_normal_bg plus::a_error_border ] ( [ plus::a_normal_border plus::a_normal_bg plus::a_error_border ] { } ) always clobbers reg byte a
Statement [14] plus::a_error_bg = main::b_error_bg [ plus::a_normal_border plus::a_normal_bg plus::a_error_border plus::a_error_bg ] ( [ plus::a_normal_border plus::a_normal_bg plus::a_error_border plus::a_error_bg ] { } ) always clobbers reg byte a
Statement [15] plus::b_normal_border = main::c_normal_border [ plus::a_normal_border plus::a_normal_bg plus::a_error_border plus::a_error_bg plus::b_normal_border ] ( [ plus::a_normal_border plus::a_normal_bg plus::a_error_border plus::a_error_bg plus::b_normal_border ] { } ) always clobbers reg byte a
Statement [16] plus::b_normal_bg = main::c_normal_bg [ plus::a_normal_border plus::a_normal_bg plus::a_error_border plus::a_error_bg plus::b_normal_border plus::b_normal_bg ] ( [ plus::a_normal_border plus::a_normal_bg plus::a_error_border plus::a_error_bg plus::b_normal_border plus::b_normal_bg ] { } ) always clobbers reg byte a
Statement [17] plus::b_error_border = main::c_error_border [ plus::a_normal_border plus::a_normal_bg plus::a_error_border plus::a_error_bg plus::b_normal_border plus::b_normal_bg plus::b_error_border ] ( [ plus::a_normal_border plus::a_normal_bg plus::a_error_border plus::a_error_bg plus::b_normal_border plus::b_normal_bg plus::b_error_border ] { } ) always clobbers reg byte a
Statement [18] plus::b_error_bg = main::c_error_bg [ plus::a_normal_border plus::a_normal_bg plus::a_error_border plus::a_error_bg plus::b_normal_border plus::b_normal_bg plus::b_error_border plus::b_error_bg ] ( [ plus::a_normal_border plus::a_normal_bg plus::a_error_border plus::a_error_bg plus::b_normal_border plus::b_normal_bg plus::b_error_border plus::b_error_bg ] { } ) always clobbers reg byte a
Statement [23] plus::$0 = plus::a_normal_border + plus::b_normal_border [ plus::a_normal_bg plus::a_error_border plus::a_error_bg plus::b_normal_bg plus::b_error_border plus::b_error_bg plus::$0 ] ( plus:8 [ plus::a_normal_bg plus::a_error_border plus::a_error_bg plus::b_normal_bg plus::b_error_border plus::b_error_bg plus::$0 ] { } plus:19 [ plus::a_normal_bg plus::a_error_border plus::a_error_bg plus::b_normal_bg plus::b_error_border plus::b_error_bg plus::$0 ] { } ) always clobbers reg byte a
Statement [24] plus::$1 = plus::$0 + plus::a_normal_bg [ plus::a_error_border plus::a_error_bg plus::b_normal_bg plus::b_error_border plus::b_error_bg plus::$1 ] ( plus:8 [ plus::a_error_border plus::a_error_bg plus::b_normal_bg plus::b_error_border plus::b_error_bg plus::$1 ] { } plus:19 [ plus::a_error_border plus::a_error_bg plus::b_normal_bg plus::b_error_border plus::b_error_bg plus::$1 ] { } ) always clobbers reg byte a
Statement [25] plus::$2 = plus::$1 + plus::b_normal_bg [ plus::a_error_border plus::a_error_bg plus::b_error_border plus::b_error_bg plus::$2 ] ( plus:8 [ plus::a_error_border plus::a_error_bg plus::b_error_border plus::b_error_bg plus::$2 ] { } plus:19 [ plus::a_error_border plus::a_error_bg plus::b_error_border plus::b_error_bg plus::$2 ] { } ) always clobbers reg byte a
Statement [26] plus::$3 = plus::$2 + plus::a_error_border [ plus::a_error_bg plus::b_error_border plus::b_error_bg plus::$3 ] ( plus:8 [ plus::a_error_bg plus::b_error_border plus::b_error_bg plus::$3 ] { } plus:19 [ plus::a_error_bg plus::b_error_border plus::b_error_bg plus::$3 ] { } ) always clobbers reg byte a
Statement [27] plus::$4 = plus::$3 + plus::b_error_border [ plus::a_error_bg plus::b_error_bg plus::$4 ] ( plus:8 [ plus::a_error_bg plus::b_error_bg plus::$4 ] { } plus:19 [ plus::a_error_bg plus::b_error_bg plus::$4 ] { } ) always clobbers reg byte a
Statement [28] plus::$5 = plus::$4 + plus::a_error_bg [ plus::b_error_bg plus::$5 ] ( plus:8 [ plus::b_error_bg plus::$5 ] { } plus:19 [ plus::b_error_bg plus::$5 ] { } ) always clobbers reg byte a
Statement [29] plus::$6 = plus::$5 + plus::b_error_bg [ plus::$6 ] ( plus:8 [ plus::$6 ] { } plus:19 [ plus::$6 ] { } ) always clobbers reg byte a
Potential registers zp[1]:19 [ plus::a_normal_border ] : zp[1]:19 ,
Potential registers zp[1]:16 [ plus::a_normal_bg ] : zp[1]:16 ,
Potential registers zp[1]:17 [ plus::a_error_border ] : zp[1]:17 ,
Potential registers zp[1]:18 [ plus::a_error_bg ] : zp[1]:18 ,
Potential registers zp[1]:12 [ plus::b_normal_border ] : zp[1]:12 ,
Potential registers zp[1]:13 [ plus::b_normal_bg ] : zp[1]:13 ,
Potential registers zp[1]:14 [ plus::b_error_border ] : zp[1]:14 ,
Potential registers zp[1]:15 [ plus::b_error_bg ] : zp[1]:15 ,
Potential registers zp[1]:9 [ main::$0 ] : zp[1]:9 , reg byte a , reg byte x , reg byte y ,
Potential registers zp[1]:10 [ main::$1 ] : zp[1]:10 , reg byte a , reg byte x , reg byte y ,
Potential registers zp[1]:2 [ plus::$0 ] : zp[1]:2 , reg byte a , reg byte x , reg byte y ,
Potential registers zp[1]:3 [ plus::$1 ] : zp[1]:3 , reg byte a , reg byte x , reg byte y ,
Potential registers zp[1]:4 [ plus::$2 ] : zp[1]:4 , reg byte a , reg byte x , reg byte y ,
Potential registers zp[1]:5 [ plus::$3 ] : zp[1]:5 , reg byte a , reg byte x , reg byte y ,
Potential registers zp[1]:6 [ plus::$4 ] : zp[1]:6 , reg byte a , reg byte x , reg byte y ,
Potential registers zp[1]:7 [ plus::$5 ] : zp[1]:7 , reg byte a , reg byte x , reg byte y ,
Potential registers zp[1]:8 [ plus::$6 ] : zp[1]:8 , reg byte a , reg byte x , reg byte y ,
Potential registers zp[1]:11 [ plus::return ] : zp[1]:11 ,
REGISTER UPLIFT SCOPES
Uplift Scope [plus] 22: zp[1]:2 [ plus::$0 ] 22: zp[1]:3 [ plus::$1 ] 22: zp[1]:4 [ plus::$2 ] 22: zp[1]:5 [ plus::$3 ] 22: zp[1]:6 [ plus::$4 ] 22: zp[1]:7 [ plus::$5 ] 22: zp[1]:8 [ plus::$6 ] 3.75: zp[1]:11 [ plus::return ] 1.88: zp[1]:12 [ plus::b_normal_border ] 1.88: zp[1]:13 [ plus::b_normal_bg ] 1.88: zp[1]:14 [ plus::b_error_border ] 1.88: zp[1]:15 [ plus::b_error_bg ] 1: zp[1]:16 [ plus::a_normal_bg ] 1: zp[1]:17 [ plus::a_error_border ] 1: zp[1]:18 [ plus::a_error_bg ] 0.94: zp[1]:19 [ plus::a_normal_border ]
Uplift Scope [main] 4: zp[1]:9 [ main::$0 ] 4: zp[1]:10 [ main::$1 ]
Uplift Scope [Col]
Uplift Scope [Cols]
Uplift Scope []
Uplifting [plus] best 195 combination reg byte a [ plus::$0 ] reg byte a [ plus::$1 ] reg byte a [ plus::$2 ] reg byte a [ plus::$3 ] zp[1]:6 [ plus::$4 ] zp[1]:7 [ plus::$5 ] zp[1]:8 [ plus::$6 ] zp[1]:11 [ plus::return ] zp[1]:12 [ plus::b_normal_border ] zp[1]:13 [ plus::b_normal_bg ] zp[1]:14 [ plus::b_error_border ] zp[1]:15 [ plus::b_error_bg ] zp[1]:16 [ plus::a_normal_bg ] zp[1]:17 [ plus::a_error_border ] zp[1]:18 [ plus::a_error_bg ] zp[1]:19 [ plus::a_normal_border ]
Limited combination testing to 100 combinations of 16384 possible.
Uplifting [main] best 183 combination reg byte a [ main::$0 ] reg byte a [ main::$1 ]
Uplifting [Col] best 183 combination
Uplifting [Cols] best 183 combination
Uplifting [] best 183 combination
Attempting to uplift remaining variables inzp[1]:6 [ plus::$4 ]
Uplifting [plus] best 177 combination reg byte a [ plus::$4 ]
Attempting to uplift remaining variables inzp[1]:7 [ plus::$5 ]
Uplifting [plus] best 171 combination reg byte a [ plus::$5 ]
Attempting to uplift remaining variables inzp[1]:8 [ plus::$6 ]
Uplifting [plus] best 165 combination reg byte a [ plus::$6 ]
Attempting to uplift remaining variables inzp[1]:11 [ plus::return ]
Uplifting [plus] best 165 combination zp[1]:11 [ plus::return ]
Attempting to uplift remaining variables inzp[1]:12 [ plus::b_normal_border ]
Uplifting [plus] best 165 combination zp[1]:12 [ plus::b_normal_border ]
Attempting to uplift remaining variables inzp[1]:13 [ plus::b_normal_bg ]
Uplifting [plus] best 165 combination zp[1]:13 [ plus::b_normal_bg ]
Attempting to uplift remaining variables inzp[1]:14 [ plus::b_error_border ]
Uplifting [plus] best 165 combination zp[1]:14 [ plus::b_error_border ]
Attempting to uplift remaining variables inzp[1]:15 [ plus::b_error_bg ]
Uplifting [plus] best 165 combination zp[1]:15 [ plus::b_error_bg ]
Attempting to uplift remaining variables inzp[1]:16 [ plus::a_normal_bg ]
Uplifting [plus] best 165 combination zp[1]:16 [ plus::a_normal_bg ]
Attempting to uplift remaining variables inzp[1]:17 [ plus::a_error_border ]
Uplifting [plus] best 165 combination zp[1]:17 [ plus::a_error_border ]
Attempting to uplift remaining variables inzp[1]:18 [ plus::a_error_bg ]
Uplifting [plus] best 165 combination zp[1]:18 [ plus::a_error_bg ]
Attempting to uplift remaining variables inzp[1]:19 [ plus::a_normal_border ]
Uplifting [plus] best 165 combination zp[1]:19 [ plus::a_normal_border ]
Allocated (was zp[1]:11) zp[1]:2 [ plus::return ]
Allocated (was zp[1]:12) zp[1]:3 [ plus::b_normal_border ]
Allocated (was zp[1]:13) zp[1]:4 [ plus::b_normal_bg ]
Allocated (was zp[1]:14) zp[1]:5 [ plus::b_error_border ]
Allocated (was zp[1]:15) zp[1]:6 [ plus::b_error_bg ]
Allocated (was zp[1]:16) zp[1]:7 [ plus::a_normal_bg ]
Allocated (was zp[1]:17) zp[1]:8 [ plus::a_error_border ]
Allocated (was zp[1]:18) zp[1]:9 [ plus::a_error_bg ]
Allocated (was zp[1]:19) zp[1]:10 [ plus::a_normal_border ]
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Test __varcall calling convention
// Struct of struct parameter value
// Upstart
// Commodore 64 PRG executable file
.file [name="varcall-9.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
// Global Constants & labels
.label COLS = $d020
.segment Code
// main
main: {
.const a_normal_border = 1
.const a_normal_bg = 2
.const a_error_border = 3
.const a_error_bg = 4
.const b_normal_border = 5
.const b_normal_bg = 6
.const b_error_border = 7
.const b_error_bg = 8
.const c_normal_border = 9
.const c_normal_bg = $a
.const c_error_border = $b
.const c_error_bg = $c
// [0] plus::a_normal_border = main::a_normal_border -- vbuz1=vbuc1
lda #a_normal_border
sta.z plus.a_normal_border
// [1] plus::a_normal_bg = main::a_normal_bg -- vbuz1=vbuc1
lda #a_normal_bg
sta.z plus.a_normal_bg
// [2] plus::a_error_border = main::a_error_border -- vbuz1=vbuc1
lda #a_error_border
sta.z plus.a_error_border
// [3] plus::a_error_bg = main::a_error_bg -- vbuz1=vbuc1
lda #a_error_bg
sta.z plus.a_error_bg
// [4] plus::b_normal_border = main::b_normal_border -- vbuz1=vbuc1
lda #b_normal_border
sta.z plus.b_normal_border
// [5] plus::b_normal_bg = main::b_normal_bg -- vbuz1=vbuc1
lda #b_normal_bg
sta.z plus.b_normal_bg
// [6] plus::b_error_border = main::b_error_border -- vbuz1=vbuc1
lda #b_error_border
sta.z plus.b_error_border
// [7] plus::b_error_bg = main::b_error_bg -- vbuz1=vbuc1
lda #b_error_bg
sta.z plus.b_error_bg
// [8] callexecute plus -- call_vprc1
jsr plus
// [9] main::$0 = plus::return -- vbuaa=vbuz1
lda.z plus.return
// [10] *COLS = main::$0 -- _deref_pbuc1=vbuaa
sta COLS
// [11] plus::a_normal_border = main::b_normal_border -- vbuz1=vbuc1
lda #b_normal_border
sta.z plus.a_normal_border
// [12] plus::a_normal_bg = main::b_normal_bg -- vbuz1=vbuc1
lda #b_normal_bg
sta.z plus.a_normal_bg
// [13] plus::a_error_border = main::b_error_border -- vbuz1=vbuc1
lda #b_error_border
sta.z plus.a_error_border
// [14] plus::a_error_bg = main::b_error_bg -- vbuz1=vbuc1
lda #b_error_bg
sta.z plus.a_error_bg
// [15] plus::b_normal_border = main::c_normal_border -- vbuz1=vbuc1
lda #c_normal_border
sta.z plus.b_normal_border
// [16] plus::b_normal_bg = main::c_normal_bg -- vbuz1=vbuc1
lda #c_normal_bg
sta.z plus.b_normal_bg
// [17] plus::b_error_border = main::c_error_border -- vbuz1=vbuc1
lda #c_error_border
sta.z plus.b_error_border
// [18] plus::b_error_bg = main::c_error_bg -- vbuz1=vbuc1
lda #c_error_bg
sta.z plus.b_error_bg
// [19] callexecute plus -- call_vprc1
jsr plus
// [20] main::$1 = plus::return -- vbuaa=vbuz1
lda.z plus.return
// [21] *COLS = main::$1 -- _deref_pbuc1=vbuaa
sta COLS
jmp __breturn
// main::@return
__breturn:
// [22] return
rts
}
// plus
// __zp(2) char plus(__zp($a) char a_normal_border, __zp(7) char a_normal_bg, __zp(8) char a_error_border, __zp(9) char a_error_bg, __zp(3) char b_normal_border, __zp(4) char b_normal_bg, __zp(5) char b_error_border, __zp(6) char b_error_bg)
plus: {
.label return = 2
.label a_normal_border = $a
.label a_normal_bg = 7
.label a_error_border = 8
.label a_error_bg = 9
.label b_normal_border = 3
.label b_normal_bg = 4
.label b_error_border = 5
.label b_error_bg = 6
// [23] plus::$0 = plus::a_normal_border + plus::b_normal_border -- vbuaa=vbuz1_plus_vbuz2
lda.z a_normal_border
clc
adc.z b_normal_border
// [24] plus::$1 = plus::$0 + plus::a_normal_bg -- vbuaa=vbuaa_plus_vbuz1
clc
adc.z a_normal_bg
// [25] plus::$2 = plus::$1 + plus::b_normal_bg -- vbuaa=vbuaa_plus_vbuz1
clc
adc.z b_normal_bg
// [26] plus::$3 = plus::$2 + plus::a_error_border -- vbuaa=vbuaa_plus_vbuz1
clc
adc.z a_error_border
// [27] plus::$4 = plus::$3 + plus::b_error_border -- vbuaa=vbuaa_plus_vbuz1
clc
adc.z b_error_border
// [28] plus::$5 = plus::$4 + plus::a_error_bg -- vbuaa=vbuaa_plus_vbuz1
clc
adc.z a_error_bg
// [29] plus::$6 = plus::$5 + plus::b_error_bg -- vbuaa=vbuaa_plus_vbuz1
clc
adc.z b_error_bg
// [30] plus::return = plus::$6 -- vbuz1=vbuaa
sta.z return
jmp __breturn
// plus::@return
__breturn:
// [31] return
rts
}
// File Data
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __breturn
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction __breturn:
Removing instruction __breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
__constant char * const COLS = (char *) 53280
void main()
char main::$0 // reg byte a 4.0
char main::$1 // reg byte a 4.0
struct Col main::a_error
__constant char main::a_error_bg = 4
__constant char main::a_error_border = 3
struct Col main::a_normal
__constant char main::a_normal_bg = 2
__constant char main::a_normal_border = 1
struct Col main::b_error
__constant char main::b_error_bg = 8
__constant char main::b_error_border = 7
struct Col main::b_normal
__constant char main::b_normal_bg = 6
__constant char main::b_normal_border = 5
struct Col main::c_error
__constant char main::c_error_bg = $c
__constant char main::c_error_border = $b
struct Col main::c_normal
__constant char main::c_normal_bg = $a
__constant char main::c_normal_border = 9
__varcall char plus(char a_normal_border , char a_normal_bg , char a_error_border , char a_error_bg , char b_normal_border , char b_normal_bg , char b_error_border , char b_error_bg)
char plus::$0 // reg byte a 22.0
char plus::$1 // reg byte a 22.0
char plus::$2 // reg byte a 22.0
char plus::$3 // reg byte a 22.0
char plus::$4 // reg byte a 22.0
char plus::$5 // reg byte a 22.0
char plus::$6 // reg byte a 22.0
__loadstore char plus::a_error_bg // zp[1]:9 1.0
__loadstore char plus::a_error_border // zp[1]:8 1.0
__loadstore char plus::a_normal_bg // zp[1]:7 1.0
__loadstore char plus::a_normal_border // zp[1]:10 0.9375
__loadstore char plus::b_error_bg // zp[1]:6 1.875
__loadstore char plus::b_error_border // zp[1]:5 1.875
__loadstore char plus::b_normal_bg // zp[1]:4 1.875
__loadstore char plus::b_normal_border // zp[1]:3 1.875
__loadstore char plus::return // zp[1]:2 3.75
zp[1]:10 [ plus::a_normal_border ]
zp[1]:7 [ plus::a_normal_bg ]
zp[1]:8 [ plus::a_error_border ]
zp[1]:9 [ plus::a_error_bg ]
zp[1]:3 [ plus::b_normal_border ]
zp[1]:4 [ plus::b_normal_bg ]
zp[1]:5 [ plus::b_error_border ]
zp[1]:6 [ plus::b_error_bg ]
reg byte a [ main::$0 ]
reg byte a [ main::$1 ]
reg byte a [ plus::$0 ]
reg byte a [ plus::$1 ]
reg byte a [ plus::$2 ]
reg byte a [ plus::$3 ]
reg byte a [ plus::$4 ]
reg byte a [ plus::$5 ]
reg byte a [ plus::$6 ]
zp[1]:2 [ plus::return ]
FINAL ASSEMBLER
Score: 159
// File Comments
// Test __varcall calling convention
// Struct of struct parameter value
// Upstart
// Commodore 64 PRG executable file
.file [name="varcall-9.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
// Global Constants & labels
.label COLS = $d020
.segment Code
// main
main: {
.const a_normal_border = 1
.const a_normal_bg = 2
.const a_error_border = 3
.const a_error_bg = 4
.const b_normal_border = 5
.const b_normal_bg = 6
.const b_error_border = 7
.const b_error_bg = 8
.const c_normal_border = 9
.const c_normal_bg = $a
.const c_error_border = $b
.const c_error_bg = $c
// plus(a, b)
// [0] plus::a_normal_border = main::a_normal_border -- vbuz1=vbuc1
lda #a_normal_border
sta.z plus.a_normal_border
// [1] plus::a_normal_bg = main::a_normal_bg -- vbuz1=vbuc1
lda #a_normal_bg
sta.z plus.a_normal_bg
// [2] plus::a_error_border = main::a_error_border -- vbuz1=vbuc1
lda #a_error_border
sta.z plus.a_error_border
// [3] plus::a_error_bg = main::a_error_bg -- vbuz1=vbuc1
lda #a_error_bg
sta.z plus.a_error_bg
// [4] plus::b_normal_border = main::b_normal_border -- vbuz1=vbuc1
lda #b_normal_border
sta.z plus.b_normal_border
// [5] plus::b_normal_bg = main::b_normal_bg -- vbuz1=vbuc1
lda #b_normal_bg
sta.z plus.b_normal_bg
// [6] plus::b_error_border = main::b_error_border -- vbuz1=vbuc1
lda #b_error_border
sta.z plus.b_error_border
// [7] plus::b_error_bg = main::b_error_bg -- vbuz1=vbuc1
lda #b_error_bg
sta.z plus.b_error_bg
// [8] callexecute plus -- call_vprc1
jsr plus
// [9] main::$0 = plus::return -- vbuaa=vbuz1
lda.z plus.return
// *COLS = plus(a, b)
// [10] *COLS = main::$0 -- _deref_pbuc1=vbuaa
sta COLS
// plus(b, c)
// [11] plus::a_normal_border = main::b_normal_border -- vbuz1=vbuc1
lda #b_normal_border
sta.z plus.a_normal_border
// [12] plus::a_normal_bg = main::b_normal_bg -- vbuz1=vbuc1
lda #b_normal_bg
sta.z plus.a_normal_bg
// [13] plus::a_error_border = main::b_error_border -- vbuz1=vbuc1
lda #b_error_border
sta.z plus.a_error_border
// [14] plus::a_error_bg = main::b_error_bg -- vbuz1=vbuc1
lda #b_error_bg
sta.z plus.a_error_bg
// [15] plus::b_normal_border = main::c_normal_border -- vbuz1=vbuc1
lda #c_normal_border
sta.z plus.b_normal_border
// [16] plus::b_normal_bg = main::c_normal_bg -- vbuz1=vbuc1
lda #c_normal_bg
sta.z plus.b_normal_bg
// [17] plus::b_error_border = main::c_error_border -- vbuz1=vbuc1
lda #c_error_border
sta.z plus.b_error_border
// [18] plus::b_error_bg = main::c_error_bg -- vbuz1=vbuc1
lda #c_error_bg
sta.z plus.b_error_bg
// [19] callexecute plus -- call_vprc1
jsr plus
// [20] main::$1 = plus::return -- vbuaa=vbuz1
lda.z plus.return
// *COLS = plus(b, c)
// [21] *COLS = main::$1 -- _deref_pbuc1=vbuaa
sta COLS
// main::@return
// }
// [22] return
rts
}
// plus
// __zp(2) char plus(__zp($a) char a_normal_border, __zp(7) char a_normal_bg, __zp(8) char a_error_border, __zp(9) char a_error_bg, __zp(3) char b_normal_border, __zp(4) char b_normal_bg, __zp(5) char b_error_border, __zp(6) char b_error_bg)
plus: {
.label return = 2
.label a_normal_border = $a
.label a_normal_bg = 7
.label a_error_border = 8
.label a_error_bg = 9
.label b_normal_border = 3
.label b_normal_bg = 4
.label b_error_border = 5
.label b_error_bg = 6
// a.normal.border + b.normal.border
// [23] plus::$0 = plus::a_normal_border + plus::b_normal_border -- vbuaa=vbuz1_plus_vbuz2
lda.z a_normal_border
clc
adc.z b_normal_border
// a.normal.border + b.normal.border + a.normal.bg
// [24] plus::$1 = plus::$0 + plus::a_normal_bg -- vbuaa=vbuaa_plus_vbuz1
clc
adc.z a_normal_bg
// a.normal.border + b.normal.border + a.normal.bg + b.normal.bg
// [25] plus::$2 = plus::$1 + plus::b_normal_bg -- vbuaa=vbuaa_plus_vbuz1
clc
adc.z b_normal_bg
// a.normal.border + b.normal.border + a.normal.bg + b.normal.bg + a.error.border
// [26] plus::$3 = plus::$2 + plus::a_error_border -- vbuaa=vbuaa_plus_vbuz1
clc
adc.z a_error_border
// a.normal.border + b.normal.border + a.normal.bg + b.normal.bg + a.error.border + b.error.border
// [27] plus::$4 = plus::$3 + plus::b_error_border -- vbuaa=vbuaa_plus_vbuz1
clc
adc.z b_error_border
// a.normal.border + b.normal.border + a.normal.bg + b.normal.bg + a.error.border + b.error.border + a.error.bg
// [28] plus::$5 = plus::$4 + plus::a_error_bg -- vbuaa=vbuaa_plus_vbuz1
clc
adc.z a_error_bg
// a.normal.border + b.normal.border + a.normal.bg + b.normal.bg + a.error.border + b.error.border + a.error.bg + b.error.bg
// [29] plus::$6 = plus::$5 + plus::b_error_bg -- vbuaa=vbuaa_plus_vbuz1
clc
adc.z b_error_bg
// return a.normal.border + b.normal.border + a.normal.bg + b.normal.bg + a.error.border + b.error.border + a.error.bg + b.error.bg;
// [30] plus::return = plus::$6 -- vbuz1=vbuaa
sta.z return
// plus::@return
// }
// [31] return
rts
}
// File Data

View File

@ -0,0 +1,58 @@
__constant char * const COLS = (char *) 53280
void main()
char main::$0 // reg byte a 4.0
char main::$1 // reg byte a 4.0
struct Col main::a_error
__constant char main::a_error_bg = 4
__constant char main::a_error_border = 3
struct Col main::a_normal
__constant char main::a_normal_bg = 2
__constant char main::a_normal_border = 1
struct Col main::b_error
__constant char main::b_error_bg = 8
__constant char main::b_error_border = 7
struct Col main::b_normal
__constant char main::b_normal_bg = 6
__constant char main::b_normal_border = 5
struct Col main::c_error
__constant char main::c_error_bg = $c
__constant char main::c_error_border = $b
struct Col main::c_normal
__constant char main::c_normal_bg = $a
__constant char main::c_normal_border = 9
__varcall char plus(char a_normal_border , char a_normal_bg , char a_error_border , char a_error_bg , char b_normal_border , char b_normal_bg , char b_error_border , char b_error_bg)
char plus::$0 // reg byte a 22.0
char plus::$1 // reg byte a 22.0
char plus::$2 // reg byte a 22.0
char plus::$3 // reg byte a 22.0
char plus::$4 // reg byte a 22.0
char plus::$5 // reg byte a 22.0
char plus::$6 // reg byte a 22.0
__loadstore char plus::a_error_bg // zp[1]:9 1.0
__loadstore char plus::a_error_border // zp[1]:8 1.0
__loadstore char plus::a_normal_bg // zp[1]:7 1.0
__loadstore char plus::a_normal_border // zp[1]:10 0.9375
__loadstore char plus::b_error_bg // zp[1]:6 1.875
__loadstore char plus::b_error_border // zp[1]:5 1.875
__loadstore char plus::b_normal_bg // zp[1]:4 1.875
__loadstore char plus::b_normal_border // zp[1]:3 1.875
__loadstore char plus::return // zp[1]:2 3.75
zp[1]:10 [ plus::a_normal_border ]
zp[1]:7 [ plus::a_normal_bg ]
zp[1]:8 [ plus::a_error_border ]
zp[1]:9 [ plus::a_error_bg ]
zp[1]:3 [ plus::b_normal_border ]
zp[1]:4 [ plus::b_normal_bg ]
zp[1]:5 [ plus::b_error_border ]
zp[1]:6 [ plus::b_error_bg ]
reg byte a [ main::$0 ]
reg byte a [ main::$1 ]
reg byte a [ plus::$0 ]
reg byte a [ plus::$1 ]
reg byte a [ plus::$2 ]
reg byte a [ plus::$3 ]
reg byte a [ plus::$4 ]
reg byte a [ plus::$5 ]
reg byte a [ plus::$6 ]
zp[1]:2 [ plus::return ]