1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-06-03 07:29:37 +00:00

Working on #372 varcall. Fixed struct in/out by value - also when only called once.

This commit is contained in:
jespergravgaard 2023-04-02 11:17:57 +02:00
parent c9720722ad
commit 9a85048003
8 changed files with 439 additions and 15 deletions

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

@ -380,6 +380,16 @@ public class TestProgramsFast extends TestPrograms {
compileAndCompare("struct-unwinding-1.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");

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;
}

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