1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-06-26 19:30:00 +00:00

Working on varcall calling convention, structs and unions. #197 #372

This commit is contained in:
jespergravgaard 2021-07-24 11:33:07 +02:00
parent fa937d4874
commit 29633a2479
14 changed files with 750 additions and 51 deletions

View File

@ -312,6 +312,9 @@ public class Compiler {
new Pass1CallPhiReturn(program).execute();
new PassNUnwindLValueLists(program).execute();
new Pass1UnwindStructValues(program).execute();
getLog().append("\nCONTROL FLOW GRAPH SSA");
getLog().append(program.getGraph().toString(program));

View File

@ -1,6 +1,5 @@
package dk.camelot64.kickc.model;
import dk.camelot64.kickc.model.operators.Operators;
import dk.camelot64.kickc.model.statements.StatementSource;
import dk.camelot64.kickc.model.symbols.ArraySpec;
import dk.camelot64.kickc.model.symbols.StructDefinition;
@ -92,7 +91,7 @@ public class Initializers {
}
} else if(initValue instanceof ValueList) {
ValueList initList = (ValueList) initValue;
if(typeSpec.getType() instanceof SymbolTypePointer && ((SymbolTypePointer)typeSpec.getType()).getArraySpec() != null) {
if(typeSpec.getType() instanceof SymbolTypePointer && ((SymbolTypePointer) typeSpec.getType()).getArraySpec() != null) {
// Type is an array
initValue = constantifyArray(initList, (SymbolTypePointer) typeSpec.getType(), program, source);
} else if(typeSpec.getType() instanceof SymbolTypeStruct) {
@ -107,7 +106,7 @@ public class Initializers {
if(typeSpec.getType() instanceof SymbolTypeIntegerFixed) {
SymbolTypeIntegerFixed typeIntegerFixed = (SymbolTypeIntegerFixed) typeSpec.getType();
if(!typeIntegerFixed.contains(integer)) {
throw new CompileError( "Constant init-value has a non-matching type \n type: " + typeSpec.getType().toString() +"\n value: " + initValue.toString(), source);
throw new CompileError("Constant init-value has a non-matching type \n type: " + typeSpec.getType().toString() + "\n value: " + initValue.toString(), source);
}
}
initValue = new ConstantInteger(integer, typeSpec.getType());
@ -141,13 +140,21 @@ public class Initializers {
// Recursively cast all sub-elements
StructDefinition structDefinition = structType.getStructDefinition(program.getScope());
Collection<Variable> memberDefinitions = structDefinition.getAllVars(false);
int structInitNeedSize = structDefinition.isUnion()? 1 : memberDefinitions.size() ;
int structInitNeedSize = structDefinition.isUnion() ? 1 : memberDefinitions.size();
if(structInitNeedSize != valueList.getList().size()) {
throw new CompileError(
"Struct initializer has wrong size (" + valueList.getList().size() + "), " +
"which does not match the number of members in " + structType.getTypeName() + " (" + structInitNeedSize + " members).\n" +
" Struct initializer: " + valueList.toString(program),
source);
if(structDefinition.isUnion()) {
throw new CompileError(
"Union initializer has too many values, since only one is allowed.\n" +
" Union initializer: " + valueList.toString(program),
source);
} else {
throw new CompileError(
"Struct initializer has wrong size (" + valueList.getList().size() + "), " +
"which does not match the number of members in " + structType.getTypeName() + " (" + structInitNeedSize + " members).\n" +
" Struct initializer: " + valueList.toString(program),
source);
}
}
boolean allConst = true;

View File

@ -505,10 +505,12 @@ public class Variable implements Symbol {
* @return true if an unwinding struct
*/
public boolean isStructUnwind() {
if(getType() instanceof SymbolTypeStruct)
return isKindPhiMaster() || isKindIntermediate() || isKindPhiVersion();
else
return false;
if(getType() instanceof SymbolTypeStruct) {
final SymbolTypeStruct typeStruct = (SymbolTypeStruct) getType();
if(!typeStruct.isUnion())
return isKindPhiMaster() || isKindIntermediate() || isKindPhiVersion();
}
return false;
}
/**
@ -517,7 +519,15 @@ public class Variable implements Symbol {
* @return true if an classic struct
*/
public boolean isStructClassic() {
return getType() instanceof SymbolTypeStruct && isKindLoadStore();
if(getType() instanceof SymbolTypeStruct) {
final SymbolTypeStruct typeStruct = (SymbolTypeStruct) getType();
if(typeStruct.isUnion())
return true;
if(isKindLoadStore())
return true;
}
return false;
}
public boolean isDeclarationOnly() {

View File

@ -98,7 +98,7 @@ public class Pass1UnwindStructValues extends Pass1Base {
Variable procReturnVar = procedure.getLocalVariable("return");
// TODO: Return-variable has been unwound - detect that instead - use getProgram().getStructVariableMemberUnwinding().getUnwindingMaster() like for parameters
if(procReturnVar != null && procReturnVar.isStructUnwind()) {
if(!(call.getlValue() instanceof ValueList)) {
if(call.getlValue()!=null && !(call.getlValue() instanceof ValueList)) {
// Return value already unwound - move on
final ValueSource valueSource = ValueSourceFactory.getValueSource(call.getlValue(), getProgram(), getScope(), call, stmtIt, currentBlock);
RValue unwoundLValue = unwindValue(valueSource, call, stmtIt, currentBlock);
@ -118,30 +118,32 @@ public class Pass1UnwindStructValues extends Pass1Base {
boolean anyParameterUnwound = false;
final List<Variable> procParameters = procedure.getParameters();
final List<RValue> callParameters = call.getParameters();
for(int idx_call = 0, idx_proc = 0; idx_call < callParameters.size(); idx_call++) {
final RValue callParameter = callParameters.get(idx_call);
final Variable procParameter = procParameters.get(idx_proc);
boolean unwound = false;
final SymbolVariableRef unwindingMaster = getProgram().getStructVariableMemberUnwinding().getUnwindingMaster(procParameter.getRef());
if(unwindingMaster != null) {
// The procedure parameter is unwound
final ValueSource parameterSource = ValueSourceFactory.getValueSource(callParameter, getProgram(), getScope(), call, stmtIt, currentBlock);
if(parameterSource != null && parameterSource.isUnwindable())
// Passing an unwinding struct value
for(String memberName : parameterSource.getMemberNames(getScope())) {
ValueSource memberUnwinding = parameterSource.getMemberUnwinding(memberName, getProgram(), getScope(), call, stmtIt, currentBlock);
unwoundParameters.add(memberUnwinding.getSimpleValue(getScope()));
unwound = true;
anyParameterUnwound = true;
if(callParameters!=null && callParameters.size()>0 ){
for(int idx_call = 0, idx_proc = 0; idx_call < callParameters.size(); idx_call++) {
final RValue callParameter = callParameters.get(idx_call);
final Variable procParameter = procParameters.get(idx_proc);
boolean unwound = false;
final SymbolVariableRef unwindingMaster = getProgram().getStructVariableMemberUnwinding().getUnwindingMaster(procParameter.getRef());
if(unwindingMaster != null) {
// The procedure parameter is unwound
final ValueSource parameterSource = ValueSourceFactory.getValueSource(callParameter, getProgram(), getScope(), call, stmtIt, currentBlock);
if(parameterSource != null && parameterSource.isUnwindable())
// Passing an unwinding struct value
for(String memberName : parameterSource.getMemberNames(getScope())) {
ValueSource memberUnwinding = parameterSource.getMemberUnwinding(memberName, getProgram(), getScope(), call, stmtIt, currentBlock);
unwoundParameters.add(memberUnwinding.getSimpleValue(getScope()));
unwound = true;
anyParameterUnwound = true;
idx_proc++;
}
else
idx_proc++;
}
else
} else {
idx_proc++;
} else {
idx_proc++;
}
if(!unwound) {
unwoundParameters.add(callParameter);
}
if(!unwound) {
unwoundParameters.add(callParameter);
}
}
}

View File

@ -4,6 +4,7 @@ import dk.camelot64.kickc.model.*;
import dk.camelot64.kickc.model.statements.StatementAssignment;
import dk.camelot64.kickc.model.statements.StatementCall;
import dk.camelot64.kickc.model.statements.StatementCallFinalize;
import dk.camelot64.kickc.model.symbols.StructDefinition;
import dk.camelot64.kickc.model.symbols.Variable;
import dk.camelot64.kickc.model.values.RValue;
import dk.camelot64.kickc.model.values.ValueList;
@ -59,6 +60,8 @@ public class Pass4LiveRangeEquivalenceClassesFinalize extends Pass2Base {
// Add any load/store variables with an initializer - and load/store struct variables
for(Variable variable : getSymbols().getAllVariables(true)) {
if(variable.getScope() instanceof StructDefinition)
continue;
if(variable.isKindLoadStore() && variable.getInitValue()!=null)
addToEquivalenceClassSet(variable.getVariableRef(), new ArrayList<>(), liveRangeEquivalenceClassSet);
else if(variable.isStructClassic())

View File

@ -221,12 +221,16 @@ public class TestProgramsFast extends TestPrograms {
compileAndCompare("struct-unwinding-1.c");
}
// TODO: Fix __varcall returning structs
//@Test
//public void testVarCall4() throws IOException {
// compileAndCompare("varcall-4.c", log().verboseStructUnwind().verboseCreateSsa());
//public void testVarCall5() throws IOException {
// compileAndCompare("varcall-5.c", log().verboseCreateSsa().verboseStructUnwind());
//}
@Test
public void testVarCall4() throws IOException {
compileAndCompare("varcall-4.c");
}
@Test
public void testVarCall3() throws IOException {
compileAndCompare("varcall-3.c");
@ -2223,6 +2227,11 @@ public class TestProgramsFast extends TestPrograms {
compileAndCompare("struct-directives.c");
}
//@Test
//public void testUnion7() throws IOException {
// compileAndCompare("union-7.c", log().verboseStructUnwind());
//}
@Test
public void testUnion6() throws IOException {
compileAndCompare("union-6.c");
@ -2814,7 +2823,7 @@ public class TestProgramsFast extends TestPrograms {
@Test
public void testTypeIdPlusBytes() throws IOException {
compileAndCompare("typeid-plus-bytes.c", log());
compileAndCompare("typeid-plus-bytes.c");
}
@Test

23
src/test/kc/union-7.c Normal file
View File

@ -0,0 +1,23 @@
// Minimal union with C-Standard behavior - union parameter
union Data {
unsigned char b;
unsigned int w;
};
union Data data1 = { 0x12 };
union Data data2 = { 0x34 };
void main() {
print(data1);
print(data2);
}
char* const SCREEN = (char*)0x0400;
char idx = 0;
void print(union Data data) {
SCREEN[idx++] = BYTE1(data.w);
SCREEN[idx++] = data.b;
SCREEN[idx++] = ' ';
}

View File

@ -1,22 +1,27 @@
// Test __varcall calling convention
// Struct parameter & return value
// Struct parameter
struct Cols {
char border;
char bg;
char fg;
};
struct Cols * const COLS = (struct Cols *)0xd020;
char * const COLS = (char *)0xd020;
struct Cols a = { 1, 2, 3 };
struct Cols b = { 3, 4, 6 };
struct Cols c = { 5, 6, 7 };
struct Cols d;
void main() {
struct Cols a = { 1, 2 };
//*COLS = a;
a = plus(a, { 2, 3 } );
*COLS = a;
//a = plus(a, a);
//*COLS = a;
char sum1 = fg_sum(a, b);
*COLS = sum1;
d = b;
char sum2 = fg_sum(c, d);
*COLS = sum2;
}
__varcall struct Cols plus(struct Cols a, struct Cols b) {
return { a.border+b.border, a.bg+b.bg };
__varcall char fg_sum(struct Cols a, struct Cols b) {
return a.fg+b.fg;
}

22
src/test/kc/varcall-5.c Normal file
View File

@ -0,0 +1,22 @@
// Test __varcall calling convention
// Struct return value
struct Cols {
char border;
char bg;
};
struct Cols * const COLS = (struct Cols *)0xd020;
struct Cols a;
void main() {
a = make(1);
*COLS = a;
a = make(2);
*COLS = a;
}
__varcall struct Cols make(char v) {
return { v, v+v };
}

22
src/test/kc/varcall-6.c Normal file
View File

@ -0,0 +1,22 @@
// Test __varcall calling convention
// Struct parameter & return value
struct Cols {
char border;
char bg;
};
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 };
}

View File

@ -0,0 +1,80 @@
// Test __varcall calling convention
// Struct parameter
// Commodore 64 PRG executable file
.file [name="varcall-4.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 = 3
.const OFFSET_STRUCT_COLS_FG = 2
.label COLS = $d020
.segment Code
// fg_sum(struct Cols zp(3) a, struct Cols zp(6) b)
fg_sum: {
.label a = 3
.label b = 6
.label return = 2
// a.fg+b.fg
lda a+OFFSET_STRUCT_COLS_FG
clc
adc b+OFFSET_STRUCT_COLS_FG
// return a.fg+b.fg;
sta.z return
// }
rts
}
main: {
// fg_sum(a, b)
ldy #SIZEOF_STRUCT_COLS
!:
lda a-1,y
sta fg_sum.a-1,y
dey
bne !-
ldy #SIZEOF_STRUCT_COLS
!:
lda b-1,y
sta fg_sum.b-1,y
dey
bne !-
jsr fg_sum
// char sum1 = fg_sum(a, b)
lda.z fg_sum.return
// *COLS = sum1
sta COLS
// d = b
ldy #SIZEOF_STRUCT_COLS
!:
lda b-1,y
sta d-1,y
dey
bne !-
// fg_sum(c, d)
ldy #SIZEOF_STRUCT_COLS
!:
lda c-1,y
sta fg_sum.a-1,y
dey
bne !-
ldy #SIZEOF_STRUCT_COLS
!:
lda d-1,y
sta fg_sum.b-1,y
dey
bne !-
jsr fg_sum
// char sum2 = fg_sum(c, d)
lda.z fg_sum.return
// *COLS = sum2
sta COLS
// }
rts
}
.segment Data
a: .byte 1, 2, 3
b: .byte 3, 4, 6
c: .byte 5, 6, 7
d: .fill SIZEOF_STRUCT_COLS, 0

View File

@ -0,0 +1,27 @@
__varcall byte fg_sum(struct Cols fg_sum::a , struct Cols fg_sum::b)
fg_sum: scope:[fg_sum] from
[0] fg_sum::$0 = *((byte*)&fg_sum::a+OFFSET_STRUCT_COLS_FG) + *((byte*)&fg_sum::b+OFFSET_STRUCT_COLS_FG)
[1] fg_sum::return = fg_sum::$0
to:fg_sum::@return
fg_sum::@return: scope:[fg_sum] from fg_sum
[2] return
to:@return
void main()
main: scope:[main] from
[3] *(&fg_sum::a) = memcpy(*(&a), struct Cols, SIZEOF_STRUCT_COLS)
[4] *(&fg_sum::b) = memcpy(*(&b), struct Cols, SIZEOF_STRUCT_COLS)
[5] callexecute fg_sum
[6] main::sum1#0 = fg_sum::return
[7] *COLS = main::sum1#0
[8] *(&d) = memcpy(*(&b), struct Cols, SIZEOF_STRUCT_COLS)
[9] *(&fg_sum::a) = memcpy(*(&c), struct Cols, SIZEOF_STRUCT_COLS)
[10] *(&fg_sum::b) = memcpy(*(&d), struct Cols, SIZEOF_STRUCT_COLS)
[11] callexecute fg_sum
[12] main::sum2#0 = fg_sum::return
[13] *COLS = main::sum2#0
to:main::@return
main::@return: scope:[main] from main
[14] return
to:@return

458
src/test/ref/varcall-4.log Normal file
View File

@ -0,0 +1,458 @@
Converting parameter in __varcall procedure to load/store fg_sum::a
Converting parameter in __varcall procedure to load/store fg_sum::b
Converting return in __varcall procedure to load/store fg_sum::return
Calling convention __varcall adding prepare/execute/finalize for main::$0 = call fg_sum a b
Calling convention __varcall adding prepare/execute/finalize for main::$1 = call fg_sum c d
Calling convention VAR_CALL adding return value assignment main::$0 = fg_sum::return
Calling convention VAR_CALL adding return value assignment main::$1 = fg_sum::return
CONTROL FLOW GRAPH SSA
void main()
main: scope:[main] from __start
*(&fg_sum::a) = memcpy(*(&a), struct Cols, SIZEOF_STRUCT_COLS)
fg_sum::a = struct-unwound {*(&fg_sum::a)}
*(&fg_sum::b) = memcpy(*(&b), struct Cols, SIZEOF_STRUCT_COLS)
fg_sum::b = struct-unwound {*(&fg_sum::b)}
callexecute fg_sum
main::$0 = fg_sum::return
main::sum1#0 = main::$0
*COLS = main::sum1#0
*(&d) = memcpy(*(&b), struct Cols, SIZEOF_STRUCT_COLS)
d = struct-unwound {*(&d)}
*(&fg_sum::a) = memcpy(*(&c), struct Cols, SIZEOF_STRUCT_COLS)
fg_sum::a = struct-unwound {*(&fg_sum::a)}
*(&fg_sum::b) = memcpy(*(&d), struct Cols, SIZEOF_STRUCT_COLS)
fg_sum::b = struct-unwound {*(&fg_sum::b)}
callexecute fg_sum
main::$1 = fg_sum::return
main::sum2#0 = main::$1
*COLS = main::sum2#0
to:main::@return
main::@return: scope:[main] from main
return
to:@return
__varcall byte fg_sum(struct Cols fg_sum::a , struct Cols fg_sum::b)
fg_sum: scope:[fg_sum] from
fg_sum::$0 = *((byte*)&fg_sum::a+OFFSET_STRUCT_COLS_FG) + *((byte*)&fg_sum::b+OFFSET_STRUCT_COLS_FG)
fg_sum::return = fg_sum::$0
to:fg_sum::@return
fg_sum::@return: scope:[fg_sum] from fg_sum
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 byte* const COLS = (byte*)$d020
constant byte OFFSET_STRUCT_COLS_FG = 2
constant byte SIZEOF_STRUCT_COLS = 3
void __start()
struct Cols a loadstore = { border: 1, bg: 2, fg: 3 }
struct Cols b loadstore = { border: 3, bg: 4, fg: 6 }
struct Cols c loadstore = { border: 5, bg: 6, fg: 7 }
struct Cols d loadstore = {}
__varcall byte fg_sum(struct Cols fg_sum::a , struct Cols fg_sum::b)
byte~ fg_sum::$0
struct Cols fg_sum::a loadstore
struct Cols fg_sum::b loadstore
byte fg_sum::return loadstore
void main()
byte~ main::$0
byte~ main::$1
byte main::sum1
byte main::sum1#0
byte main::sum2
byte main::sum2#0
Simplifying constant pointer cast (byte*) 53280
Successful SSA optimization PassNCastSimplification
Alias candidate removed (volatile)fg_sum::return = fg_sum::$0
Alias main::sum1#0 = main::$0
Alias main::sum2#0 = main::$1
Successful SSA optimization Pass2AliasElimination
Alias candidate removed (volatile)fg_sum::return = fg_sum::$0
Removing C-classic struct-unwound assignment [1] fg_sum::a = struct-unwound {*(&fg_sum::a)}
Removing C-classic struct-unwound assignment [3] fg_sum::b = struct-unwound {*(&fg_sum::b)}
Removing C-classic struct-unwound assignment [8] d = struct-unwound {*(&d)}
Removing C-classic struct-unwound assignment [10] fg_sum::a = struct-unwound {*(&fg_sum::a)}
Removing C-classic struct-unwound assignment [12] fg_sum::b = struct-unwound {*(&fg_sum::b)}
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)fg_sum::return = fg_sum::$0
Alias candidate removed (volatile)fg_sum::return = fg_sum::$0
Alias candidate removed (volatile)fg_sum::return = fg_sum::$0
CALL GRAPH
Calls in [main] to fg_sum:5 fg_sum:11
Created 0 initial phi equivalence classes
Coalesced down to 0 phi equivalence classes
FINAL CONTROL FLOW GRAPH
__varcall byte fg_sum(struct Cols fg_sum::a , struct Cols fg_sum::b)
fg_sum: scope:[fg_sum] from
[0] fg_sum::$0 = *((byte*)&fg_sum::a+OFFSET_STRUCT_COLS_FG) + *((byte*)&fg_sum::b+OFFSET_STRUCT_COLS_FG)
[1] fg_sum::return = fg_sum::$0
to:fg_sum::@return
fg_sum::@return: scope:[fg_sum] from fg_sum
[2] return
to:@return
void main()
main: scope:[main] from
[3] *(&fg_sum::a) = memcpy(*(&a), struct Cols, SIZEOF_STRUCT_COLS)
[4] *(&fg_sum::b) = memcpy(*(&b), struct Cols, SIZEOF_STRUCT_COLS)
[5] callexecute fg_sum
[6] main::sum1#0 = fg_sum::return
[7] *COLS = main::sum1#0
[8] *(&d) = memcpy(*(&b), struct Cols, SIZEOF_STRUCT_COLS)
[9] *(&fg_sum::a) = memcpy(*(&c), struct Cols, SIZEOF_STRUCT_COLS)
[10] *(&fg_sum::b) = memcpy(*(&d), struct Cols, SIZEOF_STRUCT_COLS)
[11] callexecute fg_sum
[12] main::sum2#0 = fg_sum::return
[13] *COLS = main::sum2#0
to:main::@return
main::@return: scope:[main] from main
[14] return
to:@return
VARIABLE REGISTER WEIGHTS
struct Cols a loadstore = { border: 1, bg: 2, fg: 3 }
struct Cols b loadstore = { border: 3, bg: 4, fg: 6 }
struct Cols c loadstore = { border: 5, bg: 6, fg: 7 }
struct Cols d loadstore = {}
__varcall byte fg_sum(struct Cols fg_sum::a , struct Cols fg_sum::b)
byte~ fg_sum::$0 22.0
struct Cols fg_sum::a loadstore
struct Cols fg_sum::b loadstore
byte fg_sum::return loadstore 3.75
void main()
byte main::sum1
byte main::sum1#0 4.0
byte main::sum2
byte main::sum2#0 4.0
Initial phi equivalence classes
Added variable fg_sum::$0 to live range equivalence class [ fg_sum::$0 ]
Added variable fg_sum::return to live range equivalence class [ fg_sum::return ]
Added variable main::sum1#0 to live range equivalence class [ main::sum1#0 ]
Added variable main::sum2#0 to live range equivalence class [ main::sum2#0 ]
Added variable a to live range equivalence class [ a ]
Added variable b to live range equivalence class [ b ]
Added variable c to live range equivalence class [ c ]
Added variable d to live range equivalence class [ d ]
Added variable fg_sum::a to live range equivalence class [ fg_sum::a ]
Added variable fg_sum::b to live range equivalence class [ fg_sum::b ]
Complete equivalence classes
[ fg_sum::$0 ]
[ fg_sum::return ]
[ main::sum1#0 ]
[ main::sum2#0 ]
[ a ]
[ b ]
[ c ]
[ d ]
[ fg_sum::a ]
[ fg_sum::b ]
Allocated zp[1]:2 [ fg_sum::$0 ]
Allocated zp[1]:3 [ fg_sum::return ]
Allocated zp[1]:4 [ main::sum1#0 ]
Allocated zp[1]:5 [ main::sum2#0 ]
Allocated mem[3] [ a ]
Allocated mem[3] [ b ]
Allocated mem[3] [ c ]
Allocated mem[3] [ d ]
Allocated zp[3]:6 [ fg_sum::a ]
Allocated zp[3]:9 [ fg_sum::b ]
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [0] fg_sum::$0 = *((byte*)&fg_sum::a+OFFSET_STRUCT_COLS_FG) + *((byte*)&fg_sum::b+OFFSET_STRUCT_COLS_FG) [ fg_sum::$0 fg_sum::a fg_sum::b ] ( fg_sum:5 [ b d c fg_sum::$0 fg_sum::a fg_sum::b ] { } fg_sum:11 [ fg_sum::$0 fg_sum::a fg_sum::b ] { } ) always clobbers reg byte a
Statement [3] *(&fg_sum::a) = memcpy(*(&a), struct Cols, SIZEOF_STRUCT_COLS) [ fg_sum::a fg_sum::b b d c ] ( [ fg_sum::a fg_sum::b b d c ] { } ) always clobbers reg byte a reg byte y
Statement [4] *(&fg_sum::b) = memcpy(*(&b), struct Cols, SIZEOF_STRUCT_COLS) [ fg_sum::a fg_sum::b b d c ] ( [ fg_sum::a fg_sum::b b d c ] { } ) always clobbers reg byte a reg byte y
Statement [8] *(&d) = memcpy(*(&b), struct Cols, SIZEOF_STRUCT_COLS) [ fg_sum::a fg_sum::b d c ] ( [ fg_sum::a fg_sum::b d c ] { } ) always clobbers reg byte a reg byte y
Statement [9] *(&fg_sum::a) = memcpy(*(&c), struct Cols, SIZEOF_STRUCT_COLS) [ fg_sum::a fg_sum::b d ] ( [ fg_sum::a fg_sum::b d ] { } ) always clobbers reg byte a reg byte y
Statement [10] *(&fg_sum::b) = memcpy(*(&d), struct Cols, SIZEOF_STRUCT_COLS) [ fg_sum::a fg_sum::b ] ( [ fg_sum::a fg_sum::b ] { } ) always clobbers reg byte a reg byte y
Potential registers zp[1]:2 [ fg_sum::$0 ] : zp[1]:2 , reg byte a , reg byte x , reg byte y ,
Potential registers zp[1]:3 [ fg_sum::return ] : zp[1]:3 ,
Potential registers zp[1]:4 [ main::sum1#0 ] : zp[1]:4 , reg byte a , reg byte x , reg byte y ,
Potential registers zp[1]:5 [ main::sum2#0 ] : zp[1]:5 , reg byte a , reg byte x , reg byte y ,
Potential registers mem[3] [ a ] : mem[3] ,
Potential registers mem[3] [ b ] : mem[3] ,
Potential registers mem[3] [ c ] : mem[3] ,
Potential registers mem[3] [ d ] : mem[3] ,
Potential registers zp[3]:6 [ fg_sum::a ] : zp[3]:6 ,
Potential registers zp[3]:9 [ fg_sum::b ] : zp[3]:9 ,
REGISTER UPLIFT SCOPES
Uplift Scope [fg_sum] 22: zp[1]:2 [ fg_sum::$0 ] 3.75: zp[1]:3 [ fg_sum::return ] 0: zp[3]:6 [ fg_sum::a ] 0: zp[3]:9 [ fg_sum::b ]
Uplift Scope [main] 4: zp[1]:4 [ main::sum1#0 ] 4: zp[1]:5 [ main::sum2#0 ]
Uplift Scope [Cols]
Uplift Scope [] 0: mem[3] [ a ] 0: mem[3] [ b ] 0: mem[3] [ c ] 0: mem[3] [ d ]
Uplifting [fg_sum] best 149 combination reg byte a [ fg_sum::$0 ] zp[1]:3 [ fg_sum::return ] zp[3]:6 [ fg_sum::a ] zp[3]:9 [ fg_sum::b ]
Uplifting [main] best 137 combination reg byte a [ main::sum1#0 ] reg byte a [ main::sum2#0 ]
Uplifting [Cols] best 137 combination
Uplifting [] best 137 combination mem[3] [ a ] mem[3] [ b ] mem[3] [ c ] mem[3] [ d ]
Attempting to uplift remaining variables inzp[1]:3 [ fg_sum::return ]
Uplifting [fg_sum] best 137 combination zp[1]:3 [ fg_sum::return ]
Allocated (was zp[1]:3) zp[1]:2 [ fg_sum::return ]
Allocated (was zp[3]:6) zp[3]:3 [ fg_sum::a ]
Allocated (was zp[3]:9) zp[3]:6 [ fg_sum::b ]
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Test __varcall calling convention
// Struct parameter
// Upstart
// Commodore 64 PRG executable file
.file [name="varcall-4.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 = 3
.const OFFSET_STRUCT_COLS_FG = 2
.label COLS = $d020
.segment Code
// fg_sum
// fg_sum(struct Cols zp(3) a, struct Cols zp(6) b)
fg_sum: {
.label a = 3
.label b = 6
.label return = 2
// [0] fg_sum::$0 = *((byte*)&fg_sum::a+OFFSET_STRUCT_COLS_FG) + *((byte*)&fg_sum::b+OFFSET_STRUCT_COLS_FG) -- vbuaa=_deref_pbuc1_plus__deref_pbuc2
lda a+OFFSET_STRUCT_COLS_FG
clc
adc b+OFFSET_STRUCT_COLS_FG
// [1] fg_sum::return = fg_sum::$0 -- vbuz1=vbuaa
sta.z return
jmp __breturn
// fg_sum::@return
__breturn:
// [2] return
rts
}
// main
main: {
// [3] *(&fg_sum::a) = memcpy(*(&a), struct Cols, SIZEOF_STRUCT_COLS) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3
ldy #SIZEOF_STRUCT_COLS
!:
lda a-1,y
sta fg_sum.a-1,y
dey
bne !-
// [4] *(&fg_sum::b) = memcpy(*(&b), struct Cols, SIZEOF_STRUCT_COLS) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3
ldy #SIZEOF_STRUCT_COLS
!:
lda b-1,y
sta fg_sum.b-1,y
dey
bne !-
// [5] callexecute fg_sum -- jsr
jsr fg_sum
// [6] main::sum1#0 = fg_sum::return -- vbuaa=vbuz1
lda.z fg_sum.return
// [7] *COLS = main::sum1#0 -- _deref_pbuc1=vbuaa
sta COLS
// [8] *(&d) = memcpy(*(&b), struct Cols, SIZEOF_STRUCT_COLS) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3
ldy #SIZEOF_STRUCT_COLS
!:
lda b-1,y
sta d-1,y
dey
bne !-
// [9] *(&fg_sum::a) = memcpy(*(&c), struct Cols, SIZEOF_STRUCT_COLS) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3
ldy #SIZEOF_STRUCT_COLS
!:
lda c-1,y
sta fg_sum.a-1,y
dey
bne !-
// [10] *(&fg_sum::b) = memcpy(*(&d), struct Cols, SIZEOF_STRUCT_COLS) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3
ldy #SIZEOF_STRUCT_COLS
!:
lda d-1,y
sta fg_sum.b-1,y
dey
bne !-
// [11] callexecute fg_sum -- jsr
jsr fg_sum
// [12] main::sum2#0 = fg_sum::return -- vbuaa=vbuz1
lda.z fg_sum.return
// [13] *COLS = main::sum2#0 -- _deref_pbuc1=vbuaa
sta COLS
jmp __breturn
// main::@return
__breturn:
// [14] return
rts
}
// File Data
.segment Data
a: .byte 1, 2, 3
b: .byte 3, 4, 6
c: .byte 5, 6, 7
d: .fill SIZEOF_STRUCT_COLS, 0
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 byte* const COLS = (byte*) 53280
constant byte OFFSET_STRUCT_COLS_FG = 2
constant byte SIZEOF_STRUCT_COLS = 3
struct Cols a loadstore mem[3] = { border: 1, bg: 2, fg: 3 }
struct Cols b loadstore mem[3] = { border: 3, bg: 4, fg: 6 }
struct Cols c loadstore mem[3] = { border: 5, bg: 6, fg: 7 }
struct Cols d loadstore mem[3] = {}
__varcall byte fg_sum(struct Cols fg_sum::a , struct Cols fg_sum::b)
byte~ fg_sum::$0 reg byte a 22.0
struct Cols fg_sum::a loadstore zp[3]:3
struct Cols fg_sum::b loadstore zp[3]:6
byte fg_sum::return loadstore zp[1]:2 3.75
void main()
byte main::sum1
byte main::sum1#0 reg byte a 4.0
byte main::sum2
byte main::sum2#0 reg byte a 4.0
reg byte a [ fg_sum::$0 ]
zp[1]:2 [ fg_sum::return ]
reg byte a [ main::sum1#0 ]
reg byte a [ main::sum2#0 ]
mem[3] [ a ]
mem[3] [ b ]
mem[3] [ c ]
mem[3] [ d ]
zp[3]:3 [ fg_sum::a ]
zp[3]:6 [ fg_sum::b ]
FINAL ASSEMBLER
Score: 131
// File Comments
// Test __varcall calling convention
// Struct parameter
// Upstart
// Commodore 64 PRG executable file
.file [name="varcall-4.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 = 3
.const OFFSET_STRUCT_COLS_FG = 2
.label COLS = $d020
.segment Code
// fg_sum
// fg_sum(struct Cols zp(3) a, struct Cols zp(6) b)
fg_sum: {
.label a = 3
.label b = 6
.label return = 2
// a.fg+b.fg
// [0] fg_sum::$0 = *((byte*)&fg_sum::a+OFFSET_STRUCT_COLS_FG) + *((byte*)&fg_sum::b+OFFSET_STRUCT_COLS_FG) -- vbuaa=_deref_pbuc1_plus__deref_pbuc2
lda a+OFFSET_STRUCT_COLS_FG
clc
adc b+OFFSET_STRUCT_COLS_FG
// return a.fg+b.fg;
// [1] fg_sum::return = fg_sum::$0 -- vbuz1=vbuaa
sta.z return
// fg_sum::@return
// }
// [2] return
rts
}
// main
main: {
// fg_sum(a, b)
// [3] *(&fg_sum::a) = memcpy(*(&a), struct Cols, SIZEOF_STRUCT_COLS) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3
ldy #SIZEOF_STRUCT_COLS
!:
lda a-1,y
sta fg_sum.a-1,y
dey
bne !-
// [4] *(&fg_sum::b) = memcpy(*(&b), struct Cols, SIZEOF_STRUCT_COLS) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3
ldy #SIZEOF_STRUCT_COLS
!:
lda b-1,y
sta fg_sum.b-1,y
dey
bne !-
// [5] callexecute fg_sum -- jsr
jsr fg_sum
// char sum1 = fg_sum(a, b)
// [6] main::sum1#0 = fg_sum::return -- vbuaa=vbuz1
lda.z fg_sum.return
// *COLS = sum1
// [7] *COLS = main::sum1#0 -- _deref_pbuc1=vbuaa
sta COLS
// d = b
// [8] *(&d) = memcpy(*(&b), struct Cols, SIZEOF_STRUCT_COLS) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3
ldy #SIZEOF_STRUCT_COLS
!:
lda b-1,y
sta d-1,y
dey
bne !-
// fg_sum(c, d)
// [9] *(&fg_sum::a) = memcpy(*(&c), struct Cols, SIZEOF_STRUCT_COLS) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3
ldy #SIZEOF_STRUCT_COLS
!:
lda c-1,y
sta fg_sum.a-1,y
dey
bne !-
// [10] *(&fg_sum::b) = memcpy(*(&d), struct Cols, SIZEOF_STRUCT_COLS) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3
ldy #SIZEOF_STRUCT_COLS
!:
lda d-1,y
sta fg_sum.b-1,y
dey
bne !-
// [11] callexecute fg_sum -- jsr
jsr fg_sum
// char sum2 = fg_sum(c, d)
// [12] main::sum2#0 = fg_sum::return -- vbuaa=vbuz1
lda.z fg_sum.return
// *COLS = sum2
// [13] *COLS = main::sum2#0 -- _deref_pbuc1=vbuaa
sta COLS
// main::@return
// }
// [14] return
rts
}
// File Data
.segment Data
a: .byte 1, 2, 3
b: .byte 3, 4, 6
c: .byte 5, 6, 7
d: .fill SIZEOF_STRUCT_COLS, 0

View File

@ -0,0 +1,28 @@
constant byte* const COLS = (byte*) 53280
constant byte OFFSET_STRUCT_COLS_FG = 2
constant byte SIZEOF_STRUCT_COLS = 3
struct Cols a loadstore mem[3] = { border: 1, bg: 2, fg: 3 }
struct Cols b loadstore mem[3] = { border: 3, bg: 4, fg: 6 }
struct Cols c loadstore mem[3] = { border: 5, bg: 6, fg: 7 }
struct Cols d loadstore mem[3] = {}
__varcall byte fg_sum(struct Cols fg_sum::a , struct Cols fg_sum::b)
byte~ fg_sum::$0 reg byte a 22.0
struct Cols fg_sum::a loadstore zp[3]:3
struct Cols fg_sum::b loadstore zp[3]:6
byte fg_sum::return loadstore zp[1]:2 3.75
void main()
byte main::sum1
byte main::sum1#0 reg byte a 4.0
byte main::sum2
byte main::sum2#0 reg byte a 4.0
reg byte a [ fg_sum::$0 ]
zp[1]:2 [ fg_sum::return ]
reg byte a [ main::sum1#0 ]
reg byte a [ main::sum2#0 ]
mem[3] [ a ]
mem[3] [ b ]
mem[3] [ c ]
mem[3] [ d ]
zp[3]:3 [ fg_sum::a ]
zp[3]:6 [ fg_sum::b ]