From 9317cf8a351d583c20db2a961a7b67f1f9ae5b54 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sat, 26 Oct 2024 18:33:51 +0200 Subject: [PATCH] sorting aligned vars to shrink prg size --- .../codegen/cpu6502/ProgramAndVarsGen.kt | 49 ++++++++++++++++-- docs/source/todo.rst | 4 +- examples/test.p8 | 51 ++++++++++++++----- .../src/prog8/intermediate/IRFileWriter.kt | 49 +++++++++++++----- 4 files changed, 122 insertions(+), 31 deletions(-) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt index e75a1681b..f885685a6 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt @@ -587,7 +587,16 @@ internal class ProgramAndVarsGen( if(varsNoInit.isNotEmpty()) { asmgen.out("; non-zeropage variables") asmgen.out(" .section BSS") - varsNoInit.sortedWith(compareBy { it.name }.thenBy { it.dt }).forEach { + val wordAligned = varsNoInit.filter { it.align==PtVariable.Alignment.WORD } + val pageAligned = varsNoInit.filter { it.align==PtVariable.Alignment.PAGE } + val notAligned = varsNoInit.filter { it.align==PtVariable.Alignment.NONE } + notAligned.sortedWith(compareBy { it.name }.thenBy { it.dt }).forEach { + uninitializedVariable2asm(it) + } + wordAligned.sortedWith(compareBy { it.name }.thenBy { it.dt }).forEach { + uninitializedVariable2asm(it) + } + pageAligned.sortedWith(compareBy { it.name }.thenBy { it.dt }).forEach { uninitializedVariable2asm(it) } asmgen.out(" .send BSS") @@ -596,7 +605,11 @@ internal class ProgramAndVarsGen( if(varsWithInit.isNotEmpty()) { asmgen.out("; non-zeropage variables with init value") val (stringvars, othervars) = varsWithInit.sortedBy { it.name }.partition { it.dt == DataType.STR } - stringvars.forEach { + + val stringsWordAligned = stringvars.filter { it.align==PtVariable.Alignment.WORD } + val stringsPageAligned = stringvars.filter { it.align==PtVariable.Alignment.PAGE } + val stringsNotAligned = stringvars.filter { it.align==PtVariable.Alignment.NONE } + stringsNotAligned.forEach { outputStringvar( it.name, it.align, @@ -604,7 +617,33 @@ internal class ProgramAndVarsGen( it.initializationStringValue!!.first ) } - othervars.sortedBy { it.type }.forEach { + stringsWordAligned.forEach { + outputStringvar( + it.name, + it.align, + it.initializationStringValue!!.second, + it.initializationStringValue!!.first + ) + } + stringsPageAligned.forEach { + outputStringvar( + it.name, + it.align, + it.initializationStringValue!!.second, + it.initializationStringValue!!.first + ) + } + + val wordAligned = othervars.filter { it.align==PtVariable.Alignment.WORD } + val pageAligned = othervars.filter { it.align==PtVariable.Alignment.PAGE } + val notAligned = othervars.filter { it.align==PtVariable.Alignment.NONE } + notAligned.sortedBy { it.type }.forEach { + staticVariable2asm(it) + } + wordAligned.sortedBy { it.type }.forEach { + staticVariable2asm(it) + } + pageAligned.sortedBy { it.type }.forEach { staticVariable2asm(it) } } @@ -667,7 +706,9 @@ internal class ProgramAndVarsGen( DataType.STR -> { throw AssemblyError("all string vars should have been interned into prog") } - in ArrayDatatypes -> arrayVariable2asm(variable.name, variable.dt, variable.align, variable.initializationArrayValue, variable.length) + in ArrayDatatypes -> { + arrayVariable2asm(variable.name, variable.dt, variable.align, variable.initializationArrayValue, variable.length) + } else -> { throw AssemblyError("weird dt") } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 407d88375..3909dce3a 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,8 +1,7 @@ TODO ==== -- are uninitialized (bss) variables correctly @aligned now? (%option align docs say they're not, but maybe the new @align tag fixes this too) -- aligned vars codegen: sort to do all word alignments first then the page alignments +- add docs for @align. Note: uninitialized (bss) variables are also correctly aligned (%option align docs say they're not, but that is fixed) - what to use to align a label ? (%align $100 ?) to support aligned asmincludes for example. - remove %option align_xxx ? (block level alignment, as we now have individual variable alignments) @@ -44,6 +43,7 @@ Future Things and Ideas - ir: add more optimizations in IRPeepholeOptimizer - ir: the @split arrays are currently also split in _lsb/_msb arrays in the IR, and operations take multiple (byte) instructions that may lead to verbose and slow operation and machine code generation down the line. maybe another representation is needed once actual codegeneration is done from the IR...? +- ir: split word arrays, both _msb and _lsb arrays are tagged with an alignment. This is not what's intended; only the one put in memory first should be aligned (the other one should follow straight after it) - ir: getting it in shape for code generation... - ir: make optimizeBitTest work for IR too to use the BIT instruction? - ir: make sure that a 6502 codegen based off the IR, still generates BIT instructions when testing bit 7 or 6 of a byte var. diff --git a/examples/test.p8 b/examples/test.p8 index 908e81d79..9b7610a29 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,20 +1,45 @@ %option no_sysinit -%zeropage basicsafe +%zeropage dontuse main { sub start() { - str @alignword @shared name = "wordaligned" - str @alignpage @shared @nozp name2 = "pagealigned" - ubyte[20] @alignword @shared array1 - ubyte[20] @alignword @shared array2 - ubyte[20] @alignpage @shared array3 - ubyte[20] @alignpage @shared array4 - ubyte[] @alignword @shared array5 = [1,2,3,4] - ubyte[] @alignword @shared array6 = [1,2,3,4] - ubyte[] @alignpage @shared array7 = [1,2,3,4] - ubyte[] @alignpage @shared array8 = [1,2,3,4] - uword[20] @alignword @split @shared array9 - uword[] @alignword @split @shared array10 = [1111,2222,3333,4444] + str @alignword @shared name1 = "abc123456789" + str @alignpage @shared name2 = "def123456789" + str @alignword @shared @nozp name3 = "ghi123456789" + str @alignword @shared @nozp name4 = "jkl123456789" + ubyte[9] @alignword @shared array1 + ubyte[9] @alignword @shared array2 + ubyte[9] @alignpage @shared array3 + ubyte[9] @alignword @shared array4 + ubyte[9] @alignword @shared array5 + ubyte[9] @alignword @shared array6 + ubyte[9] @alignword @shared array7 + ubyte[9] @alignword @shared array8 + ubyte[] @alignword @shared array9 = [1,2,3] + ubyte[] @alignword @shared array10 = [1,2,3] + ubyte[] @alignpage @shared array11 = [1,2,3] + ubyte[] @alignpage @shared array12 = [1,2,3] + ubyte[] @alignword @shared array13 = [1,2,3] + ubyte[] @alignword @shared array14 = [1,2,3] + ubyte[] @alignpage @shared array15 = [1,2,3] + ubyte[] @alignpage @shared array16 = [1,2,3] + uword[3] @alignword @split @shared array17 + uword[] @alignword @split @shared array18 = [1111,2222,3333] + + array9[2]++ + array10[2]++ + array11[2]++ + array12[2]++ + array13[2]++ + array14[2]++ + array15[2]++ + array16[2]++ + array17[2]++ + array18[2]++ + name1[2]++ + name2[2]++ + name3[2]++ + name4[2]++ } } diff --git a/intermediate/src/prog8/intermediate/IRFileWriter.kt b/intermediate/src/prog8/intermediate/IRFileWriter.kt index f2477fafd..bf9025f4d 100644 --- a/intermediate/src/prog8/intermediate/IRFileWriter.kt +++ b/intermediate/src/prog8/intermediate/IRFileWriter.kt @@ -202,12 +202,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) { } private fun writeVariables() { - - val (variablesNoInit, variablesWithInit) = irProgram.st.allVariables().partition { it.uninitialized } - - xml.writeStartElement("VARIABLESNOINIT") - xml.writeCharacters("\n") - for (variable in variablesNoInit) { + fun writeNoInitVar(variable: IRStStaticVariable) { if(variable.dt in SplitWordArrayTypes) { // split into 2 ubyte arrays lsb+msb xml.writeCharacters("ubyte[${variable.length}] ${variable.name}_lsb zp=${variable.zpwish} align=${variable.align}\n") @@ -217,12 +212,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) { } } - xml.writeEndElement() - xml.writeCharacters("\n") - xml.writeStartElement("VARIABLESWITHINIT") - xml.writeCharacters("\n") - - for (variable in variablesWithInit) { + fun writeVarWithInit(variable: IRStStaticVariable) { if(variable.dt in SplitWordArrayTypes) { val lsbValue: String val msbValue: String @@ -282,6 +272,41 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) { xml.writeCharacters("${variable.typeString} ${variable.name}=$value zp=${variable.zpwish} align=${variable.align}\n") } } + + val (variablesNoInit, variablesWithInit) = irProgram.st.allVariables().partition { it.uninitialized } + + xml.writeStartElement("VARIABLESNOINIT") + xml.writeCharacters("\n") + val noinitNotAligned = variablesNoInit.filter { it.align==IRStStaticVariable.Alignment.NONE } + val noinitWordAligned = variablesNoInit.filter { it.align==IRStStaticVariable.Alignment.WORD } + val noinitPageAligned = variablesNoInit.filter { it.align==IRStStaticVariable.Alignment.PAGE } + for (variable in noinitNotAligned) { + writeNoInitVar(variable) + } + for (variable in noinitWordAligned) { + writeNoInitVar(variable) + } + for (variable in noinitPageAligned) { + writeNoInitVar(variable) + } + + xml.writeEndElement() + xml.writeCharacters("\n") + xml.writeStartElement("VARIABLESWITHINIT") + xml.writeCharacters("\n") + + val initNotAligned = variablesWithInit.filter { it.align==IRStStaticVariable.Alignment.NONE } + val initWordAligned = variablesWithInit.filter { it.align==IRStStaticVariable.Alignment.WORD } + val initPageAligned = variablesWithInit.filter { it.align==IRStStaticVariable.Alignment.PAGE } + for (variable in initNotAligned) { + writeVarWithInit(variable) + } + for (variable in initWordAligned) { + writeVarWithInit(variable) + } + for (variable in initPageAligned) { + writeVarWithInit(variable) + } xml.writeEndElement() xml.writeCharacters("\n")