diff --git a/src/main/java/dk/camelot64/kickc/Compiler.java b/src/main/java/dk/camelot64/kickc/Compiler.java index cc8b197cd..f5a16b1d9 100644 --- a/src/main/java/dk/camelot64/kickc/Compiler.java +++ b/src/main/java/dk/camelot64/kickc/Compiler.java @@ -224,6 +224,7 @@ public class Compiler { new Pass1Procedures(program).execute(); new PassNTypeInference(program).execute(); new PassNFixIntermediateMemoryArea(program).execute(); + new Pass1FixProcedureParamSegment(program).execute(); new PassNTypeIdSimplification(program).execute(); new Pass1StructTypeSizeFix(program).execute(); new Pass1PrintfIntrinsicRewrite(program).execute(); diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass1FixProcedureParamSegment.java b/src/main/java/dk/camelot64/kickc/passes/Pass1FixProcedureParamSegment.java new file mode 100644 index 000000000..3935b5729 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/passes/Pass1FixProcedureParamSegment.java @@ -0,0 +1,46 @@ +package dk.camelot64.kickc.passes; + +import dk.camelot64.kickc.model.Program; +import dk.camelot64.kickc.model.Registers; +import dk.camelot64.kickc.model.symbols.Procedure; +import dk.camelot64.kickc.model.symbols.Scope; +import dk.camelot64.kickc.model.symbols.Variable; + +import java.util.Collection; +import java.util.List; + +/** + * Ensure banked procedure parameters/return values in main memory are placed in the default data segment. + * This is needed to support banking, since it is otherwise impossible to access them across bank boundaries during calls. + */ +public class Pass1FixProcedureParamSegment extends Pass2SsaOptimization { + + public Pass1FixProcedureParamSegment(Program program) { + super(program); + } + + @Override + public boolean step() { + final Collection allVariables = getScope().getAllVariables(true); + for(Variable variable : allVariables) { + if(variable.isKindLoadStore() || variable.isKindPhiMaster() || variable.isKindIntermediate()) { + if(variable.getRegister() instanceof Registers.RegisterMainMem registerMainMem && registerMainMem.isAddressHardcoded()) + continue; + if(variable.getDataSegment().equals(Scope.SEGMENT_DATA_DEFAULT)) + continue; + + final Scope scope = variable.getScope(); + if(scope instanceof Procedure procedure) { + if(!procedure.getBank().isCommon()) { + List parameters = procedure.getParameters(); + if(parameters.contains(variable) || variable.getLocalName().equals("return")) { + variable.setDataSegment(Scope.SEGMENT_DATA_DEFAULT); + getLog().append("Fixing banked procedure parameter/return value to default segment " + variable.getFullName()); + } + } + } + } + } + return false; + } +} diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java b/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java index 8d7426a3b..29000ba0b 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java @@ -583,30 +583,6 @@ public class Pass4CodeGeneration { if (registerMainMem.getAddress() == null) { // Generate into the data segment // Set segment - // We check first the bank of the variable. Only local variables can be stored in the bank. - // Parameters must be stored in main memory. - if(!variable.getDataSegment().equals(Scope.SEGMENT_DATA_DEFAULT)) { - if(scope instanceof Procedure) { - Procedure procedure = (Procedure) scope; - List parameters = procedure.getParameters(); - if (variable.isKindPhiVersion()) { - Variable master = variable.getPhiMaster(); - if (master != null) { - if (parameters.contains(master) || master.getLocalName().equals("return")) { - variable.setDataSegment(Scope.SEGMENT_DATA_DEFAULT); - } - } - } - } - } - - // Intermediate variables are placed at the banked data segment, but parameters and return values are kept untouched. - if (variable.isKindIntermediate()) { - if (scope instanceof Procedure) { - Procedure procedure = (Procedure) scope; - variable.setDataSegment(procedure.getSegmentData()); - } - } setCurrentSegment(variable.getDataSegment(), asm); // Add any comments generateComments(asm, variable.getComments()); diff --git a/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java b/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java index f85993677..df4514641 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java +++ b/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java @@ -1583,7 +1583,7 @@ public class TestProgramsFast extends TestPrograms { @Test public void testBankedPhiMemvars() throws IOException { - compileAndCompare("call-banked-phi-memvars.c", log()); + compileAndCompare("call-banked-phi-memvars.c"); } diff --git a/src/test/ref/call-banked-phi-memvars.asm b/src/test/ref/call-banked-phi-memvars.asm index 1a15757b6..bd4556180 100644 --- a/src/test/ref/call-banked-phi-memvars.asm +++ b/src/test/ref/call-banked-phi-memvars.asm @@ -93,8 +93,8 @@ main: { iny jmp __b1 .segment Data - .label __1 = plus.return - .label __3 = plus.return + .label __1 = plus.b + .label __3 = plus.b } .segment RAM_Bank1 // __mem() int plus(__mem() int a, __mem() int b) @@ -125,18 +125,18 @@ plus: { adc a+1 sta r+1 // r += b - lda r clc - adc b + lda return + adc r sta return - lda r+1 - adc b+1 + lda return+1 + adc r+1 sta return+1 // } rts .segment Data b: .word 0 - return: .word 0 + .label return = b .segment RAM_Bank1 r: .word 0 .segment Data diff --git a/src/test/ref/call-banked-phi-memvars.log b/src/test/ref/call-banked-phi-memvars.log index ad6a75b41..6aea5faca 100644 --- a/src/test/ref/call-banked-phi-memvars.log +++ b/src/test/ref/call-banked-phi-memvars.log @@ -3,6 +3,9 @@ Updating intermediate variable memory area to MAIN_MEMORY main::$0 Updating intermediate variable memory area to MAIN_MEMORY main::$1 Updating intermediate variable memory area to MAIN_MEMORY main::$2 Updating intermediate variable memory area to MAIN_MEMORY main::$3 +Fixing banked procedure parameter/return value to default segment plus::a +Fixing banked procedure parameter/return value to default segment plus::b +Fixing banked procedure parameter/return value to default segment plus::return CONTROL FLOW GRAPH SSA @@ -359,11 +362,12 @@ Uplifting [plus] best 2226 combination mem[2] [ plus::r#1 ] mem[2] [ plus::r#2 ] Uplifting [main] best 1866 combination reg byte y [ main::i#2 main::i#1 ] reg byte x [ main::$4 ] reg byte x [ main::$5 ] mem[2] [ main::$1 ] mem[2] [ main::$3 ] reg byte x [ main::$2 ] Limited combination testing to 100 combinations of 144 possible. Uplifting [] best 1866 combination +Coalescing zero page register [ mem[2] [ plus::b#2 plus::b#0 plus::b#1 ] ] with [ mem[2] [ plus::return#2 ] ] - score: 1 Coalescing zero page register [ mem[2] [ plus::return#0 ] ] with [ mem[2] [ main::$1 ] ] - score: 1 -Coalescing zero page register [ mem[2] [ plus::return#0 main::$1 ] ] with [ mem[2] [ plus::return#2 ] ] - score: 1 Coalescing zero page register [ mem[2] [ plus::return#1 ] ] with [ mem[2] [ main::$3 ] ] - score: 1 Coalescing zero page register [ mem[2] [ plus::r#1 ] ] with [ mem[2] [ plus::r#2 ] ] - score: 1 -Coalescing zero page register [ mem[2] [ plus::return#0 main::$1 plus::return#2 ] ] with [ mem[2] [ plus::return#1 main::$3 ] ] - score: 1 +Coalescing zero page register [ mem[2] [ plus::b#2 plus::b#0 plus::b#1 plus::return#2 ] ] with [ mem[2] [ plus::return#0 main::$1 ] ] - score: 1 +Coalescing zero page register [ mem[2] [ plus::b#2 plus::b#0 plus::b#1 plus::return#2 plus::return#0 main::$1 ] ] with [ mem[2] [ plus::return#1 main::$3 ] ] - score: 1 Coalescing zero page register [ mem[2] [ plus::r#1 plus::r#2 ] ] with [ mem[2] [ plus::r#3 ] ] - score: 1 ASSEMBLER BEFORE OPTIMIZATION @@ -498,8 +502,8 @@ main: { // [1] phi main::i#2 = main::i#1 [phi:main::@4->main::@1#0] -- register_copy jmp __b1 .segment Data - .label __1 = plus.return - .label __3 = plus.return + .label __1 = plus.b + .label __3 = plus.b } .segment RAM_Bank1 // plus @@ -530,13 +534,13 @@ plus: { lda r+1 adc a+1 sta r+1 - // [22] plus::return#2 = plus::r#3 + plus::b#2 -- vwsm1=vwsm2_plus_vwsm3 - lda r + // [22] plus::return#2 = plus::r#3 + plus::b#2 -- vwsm1=vwsm2_plus_vwsm1 clc - adc b + lda return + adc r sta return - lda r+1 - adc b+1 + lda return+1 + adc r+1 sta return+1 jmp __breturn // plus::@return @@ -545,7 +549,7 @@ plus: { rts .segment Data b: .word 0 - return: .word 0 + .label return = b .segment RAM_Bank1 r: .word 0 .segment Data @@ -599,8 +603,7 @@ int plus::return#2 // return mem[2] 30.75 reg byte y [ main::i#2 main::i#1 ] mem[2] [ plus::a#2 ] -mem[2] [ plus::b#2 plus::b#0 plus::b#1 ] -mem[2] [ plus::return#0 main::$1 plus::return#2 plus::return#1 main::$3 ] +mem[2] [ plus::b#2 plus::b#0 plus::b#1 plus::return#2 plus::return#0 main::$1 plus::return#1 main::$3 ] reg byte x [ main::$4 ] reg byte x [ main::$2 ] reg byte x [ main::$5 ] @@ -740,8 +743,8 @@ main: { // [1] phi main::i#2 = main::i#1 [phi:main::@4->main::@1#0] -- register_copy jmp __b1 .segment Data - .label __1 = plus.return - .label __3 = plus.return + .label __1 = plus.b + .label __3 = plus.b } .segment RAM_Bank1 // plus @@ -776,13 +779,13 @@ plus: { adc a+1 sta r+1 // r += b - // [22] plus::return#2 = plus::r#3 + plus::b#2 -- vwsm1=vwsm2_plus_vwsm3 - lda r + // [22] plus::return#2 = plus::r#3 + plus::b#2 -- vwsm1=vwsm2_plus_vwsm1 clc - adc b + lda return + adc r sta return - lda r+1 - adc b+1 + lda return+1 + adc r+1 sta return+1 // plus::@return // } @@ -790,7 +793,7 @@ plus: { rts .segment Data b: .word 0 - return: .word 0 + .label return = b .segment RAM_Bank1 r: .word 0 .segment Data diff --git a/src/test/ref/call-banked-phi-memvars.sym b/src/test/ref/call-banked-phi-memvars.sym index e7554762e..4300fc0bd 100644 --- a/src/test/ref/call-banked-phi-memvars.sym +++ b/src/test/ref/call-banked-phi-memvars.sym @@ -26,8 +26,7 @@ int plus::return#2 // return mem[2] 30.75 reg byte y [ main::i#2 main::i#1 ] mem[2] [ plus::a#2 ] -mem[2] [ plus::b#2 plus::b#0 plus::b#1 ] -mem[2] [ plus::return#0 main::$1 plus::return#2 plus::return#1 main::$3 ] +mem[2] [ plus::b#2 plus::b#0 plus::b#1 plus::return#2 plus::return#0 main::$1 plus::return#1 main::$3 ] reg byte x [ main::$4 ] reg byte x [ main::$2 ] reg byte x [ main::$5 ]