From 11c86793d3afbb22822b1acc5c3ba8c1597e98c8 Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Sun, 23 Apr 2023 23:25:28 +0200 Subject: [PATCH] Ensured we do not coalesce across segments. --- .../kickc/passes/Pass4CodeGeneration.java | 50 +++++++++---------- .../kickc/passes/Pass4MemoryCoalesce.java | 16 ++++++ .../kickc/test/TestProgramsFast.java | 6 +++ src/test/kc/call-banked-phi-memvars.c | 30 +++++++++++ 4 files changed, 77 insertions(+), 25 deletions(-) create mode 100644 src/test/kc/call-banked-phi-memvars.c diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java b/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java index 0246ab25e..8d7426a3b 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java @@ -583,30 +583,30 @@ 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()); -// } -// } + // 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()); @@ -925,7 +925,7 @@ public class Pass4CodeGeneration { if(Bank.CallingDistance.NEAR.equals(callingDistance)) { AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.call(call, indirectCallCount++, program), program); } else { - throw new CompileError("Call procedure not supported in banked mode " + toProcedure.toString(program)); + throw new CompileError("Stack Call procedure not supported in banked mode " + toProcedure.toString(program)); } RValue procedureRVal = call.getProcedureRVal(); if (!(procedureRVal instanceof ProcedureRef)) { diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass4MemoryCoalesce.java b/src/main/java/dk/camelot64/kickc/passes/Pass4MemoryCoalesce.java index c229e98fe..03c531702 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass4MemoryCoalesce.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass4MemoryCoalesce.java @@ -53,6 +53,7 @@ public abstract class Pass4MemoryCoalesce extends Pass2Base { return canCoalesceNotEqual(ec1, ec2) && canCoalesceCompatible(ec1, ec2, program) && + canCoalesceSegments(ec1, ec2, program) && canCoalesceVolatile(ec1, ec2, program) && canCoalesceThreads(ec1, ec2, threadHeads, program) && canCoalesceClobber(ec1, ec2, unknownFragments, program); @@ -69,6 +70,21 @@ public abstract class Pass4MemoryCoalesce extends Pass2Base { return !ec1.equals(ec2); } + /** + * Determines if two live range equivalence classes are candidates for coalescing by ensuring they are not from different data segments. + * @param ec1 One equivalence class + * @param ec2 Another equivalence class + * @param program The program + * @return True if the two equivalence classes can be coalesced into one without problems. + */ + private static boolean canCoalesceSegments(LiveRangeEquivalenceClass ec1, LiveRangeEquivalenceClass ec2, Program program) { + final VariableRef variableRef1 = ec1.getVariables().get(0); + final String dataSegment1 = program.getScope().getVar(variableRef1).getDataSegment(); + final VariableRef variableRef2 = ec2.getVariables().get(0); + final String dataSegment2 = program.getScope().getVar(variableRef2).getDataSegment(); + return dataSegment1.equals(dataSegment2); + } + /** * Determines if two live range equivalence classes can be coalesced without cross-thread clobber. * This is possible if they are both only called from the same thread head. diff --git a/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java b/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java index 7b2bc53a8..f85993677 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java +++ b/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java @@ -1581,6 +1581,12 @@ public class TestProgramsFast extends TestPrograms { compileAndCompare("call-banked-phi-case-6-close-1.c"); } + @Test + public void testBankedPhiMemvars() throws IOException { + compileAndCompare("call-banked-phi-memvars.c", log()); + } + + @Test public void testBankedStackCase2Close0() throws IOException { assertError("call-banked-stack-case-2-close-0.c", "Stack Call procedure not supported in banked mode"); diff --git a/src/test/kc/call-banked-phi-memvars.c b/src/test/kc/call-banked-phi-memvars.c new file mode 100644 index 000000000..420b2796f --- /dev/null +++ b/src/test/kc/call-banked-phi-memvars.c @@ -0,0 +1,30 @@ +/** + * Test banked calls with memory variables. + * The parameters & return should end up in the shared/common bank. + */ + +#pragma link("call-banked-phi.ld") +#pragma var_model(mem) + +int* const SCREEN = (int*)0x0400; + +#pragma code_seg(Code) +#pragma nobank +void main(void) { + for(char i=0;i<5; i++) { + SCREEN[i] = plus(100, (int)i); + SCREEN[10+i] = plus(200, (int)i); + } +} + +#pragma code_seg(RAM_Bank1) +#pragma data_seg(RAM_Bank1) +#pragma bank(cx16_ram, 1) +int plus(int a, int b) { + int r = 2; + r += a; + r += b; + r += a; + r += b; + return r; +}