From 3718b9d76849c66b9e82d06f4b7d60583ad6c371 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Mon, 2 Jan 2023 01:14:11 +0100 Subject: [PATCH] less joins --- codeCore/src/prog8/code/core/MemoryRegions.kt | 10 +-- .../src/prog8/code/target/c64/C64Zeropage.kt | 12 +-- .../prog8/code/target/cx16/CX16Zeropage.kt | 12 +-- .../src/prog8/codegen/cpu6502/AsmGen.kt | 22 ++--- .../prog8/codegen/cpu6502/ForLoopsAsmGen.kt | 4 +- .../codegen/cpu6502/ProgramAndVarsGen.kt | 22 ++--- .../codegen/cpu6502/VariableAllocator.kt | 10 +-- .../cpu6502/assignment/AssignmentAsmGen.kt | 2 +- compiler/test/TestGoldenRam.kt | 14 ++-- compiler/test/TestZeropage.kt | 82 +++++++++---------- docs/source/todo.rst | 3 +- 11 files changed, 98 insertions(+), 95 deletions(-) diff --git a/codeCore/src/prog8/code/core/MemoryRegions.kt b/codeCore/src/prog8/code/core/MemoryRegions.kt index dab32a398..bce35d672 100644 --- a/codeCore/src/prog8/code/core/MemoryRegions.kt +++ b/codeCore/src/prog8/code/core/MemoryRegions.kt @@ -11,7 +11,7 @@ class MemAllocationError(message: String) : Exception(message) abstract class MemoryAllocator(protected val options: CompilationOptions) { data class VarAllocation(val address: UInt, val dt: DataType, val size: Int) - abstract fun allocate(name: String, + abstract fun allocate(name: List, datatype: DataType, numElements: Int?, position: Position?, @@ -29,7 +29,7 @@ abstract class Zeropage(options: CompilationOptions): MemoryAllocator(options) { // the variables allocated into Zeropage. // name (scoped) ==> pair of address to (Datatype + bytesize) - val allocatedVariables = mutableMapOf() + val allocatedVariables = mutableMapOf, VarAllocation>() val free = mutableListOf() // subclasses must set this to the appropriate free locations. @@ -51,7 +51,7 @@ abstract class Zeropage(options: CompilationOptions): MemoryAllocator(options) { return free.windowed(2).any { it[0] == it[1] - 1u } } - override fun allocate(name: String, + override fun allocate(name: List, datatype: DataType, numElements: Int?, position: Position?, @@ -107,7 +107,7 @@ abstract class Zeropage(options: CompilationOptions): MemoryAllocator(options) { private fun reserve(range: UIntRange) = free.removeAll(range) - private fun makeAllocation(address: UInt, size: Int, datatype: DataType, name: String): UInt { + private fun makeAllocation(address: UInt, size: Int, datatype: DataType, name: List): UInt { require(size>=0) free.removeAll(address until address+size.toUInt()) if(name.isNotEmpty()) { @@ -135,7 +135,7 @@ class GoldenRam(options: CompilationOptions, val region: UIntRange): MemoryAlloc private var nextLocation: UInt = region.first override fun allocate( - name: String, + name: List, datatype: DataType, numElements: Int?, position: Position?, diff --git a/codeCore/src/prog8/code/target/c64/C64Zeropage.kt b/codeCore/src/prog8/code/target/c64/C64Zeropage.kt index 7fdf9adb9..42eaf7ba5 100644 --- a/codeCore/src/prog8/code/target/c64/C64Zeropage.kt +++ b/codeCore/src/prog8/code/target/c64/C64Zeropage.kt @@ -83,12 +83,12 @@ class C64Zeropage(options: CompilationOptions) : Zeropage(options) { // This is important because the compiler sometimes treats ZP variables more efficiently (for example if it's a pointer) // The base addres is $04. Unfortunately it cannot be the same as on the Commander X16 ($02). for(reg in 0..15) { - allocatedVariables["cx16.r${reg}"] = VarAllocation((4+reg*2).toUInt(), DataType.UWORD, 2) // cx16.r0 .. cx16.r15 - allocatedVariables["cx16.r${reg}s"] = VarAllocation((4+reg*2).toUInt(), DataType.WORD, 2) // cx16.r0s .. cx16.r15s - allocatedVariables["cx16.r${reg}L"] = VarAllocation((4+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0L .. cx16.r15L - allocatedVariables["cx16.r${reg}H"] = VarAllocation((5+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0H .. cx16.r15H - allocatedVariables["cx16.r${reg}sL"] = VarAllocation((4+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sL .. cx16.r15sL - allocatedVariables["cx16.r${reg}sH"] = VarAllocation((5+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sH .. cx16.r15sH + allocatedVariables[listOf("cx16", "r${reg}")] = VarAllocation((4+reg*2).toUInt(), DataType.UWORD, 2) // cx16.r0 .. cx16.r15 + allocatedVariables[listOf("cx16", "r${reg}s")] = VarAllocation((4+reg*2).toUInt(), DataType.WORD, 2) // cx16.r0s .. cx16.r15s + allocatedVariables[listOf("cx16", "r${reg}L")] = VarAllocation((4+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0L .. cx16.r15L + allocatedVariables[listOf("cx16", "r${reg}H")] = VarAllocation((5+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0H .. cx16.r15H + allocatedVariables[listOf("cx16", "r${reg}sL")] = VarAllocation((4+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sL .. cx16.r15sL + allocatedVariables[listOf("cx16", "r${reg}sH")] = VarAllocation((5+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sH .. cx16.r15sH free.remove((4+reg*2).toUInt()) free.remove((5+reg*2).toUInt()) } diff --git a/codeCore/src/prog8/code/target/cx16/CX16Zeropage.kt b/codeCore/src/prog8/code/target/cx16/CX16Zeropage.kt index 55b90368c..50dfa10df 100644 --- a/codeCore/src/prog8/code/target/cx16/CX16Zeropage.kt +++ b/codeCore/src/prog8/code/target/cx16/CX16Zeropage.kt @@ -58,12 +58,12 @@ class CX16Zeropage(options: CompilationOptions) : Zeropage(options) { // However, to be able for the compiler to "see" them as zero page variables, we have to register them here as well. // This is important because the compiler sometimes treats ZP variables more efficiently (for example if it's a pointer) for(reg in 0..15) { - allocatedVariables["cx16.r${reg}"] = VarAllocation((2+reg*2).toUInt(), DataType.UWORD, 2) // cx16.r0 .. cx16.r15 - allocatedVariables["cx16.r${reg}s"] = VarAllocation((2+reg*2).toUInt(), DataType.WORD, 2) // cx16.r0s .. cx16.r15s - allocatedVariables["cx16.r${reg}L"] = VarAllocation((2+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0L .. cx16.r15L - allocatedVariables["cx16.r${reg}H"] = VarAllocation((3+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0H .. cx16.r15H - allocatedVariables["cx16.r${reg}sL"] = VarAllocation((2+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sL .. cx16.r15sL - allocatedVariables["cx16.r${reg}sH"] = VarAllocation((3+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sH .. cx16.r15sH + allocatedVariables[listOf("cx16", "r${reg}")] = VarAllocation((2+reg*2).toUInt(), DataType.UWORD, 2) // cx16.r0 .. cx16.r15 + allocatedVariables[listOf("cx16", "r${reg}s")] = VarAllocation((2+reg*2).toUInt(), DataType.WORD, 2) // cx16.r0s .. cx16.r15s + allocatedVariables[listOf("cx16", "r${reg}L")] = VarAllocation((2+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0L .. cx16.r15L + allocatedVariables[listOf("cx16", "r${reg}H")] = VarAllocation((3+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0H .. cx16.r15H + allocatedVariables[listOf("cx16", "r${reg}sL")] = VarAllocation((2+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sL .. cx16.r15sL + allocatedVariables[listOf("cx16", "r${reg}sH")] = VarAllocation((3+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sH .. cx16.r15sH } } } \ No newline at end of file diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt index a7a7cd226..fe9bf79fd 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt @@ -100,12 +100,12 @@ class AsmGen(internal val program: Program, fun asmSymbolName(identifier: IdentifierReference) = asmSymbolName(identifier.nameInSource) fun asmVariableName(identifier: IdentifierReference) = asmVariableName(identifier.nameInSource) - internal fun getTempVarName(dt: DataType): List { + internal fun getTempVarName(dt: DataType): String { return when(dt) { - DataType.UBYTE -> listOf("cx16", "r9L") - DataType.BYTE -> listOf("cx16", "r9sL") - DataType.UWORD -> listOf("cx16", "r9") - DataType.WORD -> listOf("cx16", "r9s") + DataType.UBYTE -> "cx16.r9L" + DataType.BYTE -> "cx16.r9sL" + DataType.UWORD -> "cx16.r9" + DataType.WORD -> "cx16.r9s" DataType.FLOAT -> TODO("no temporary float var available") else -> throw FatalAstException("invalid dt $dt") } @@ -123,7 +123,7 @@ class AsmGen(internal val program: Program, is VarDecl -> { val sourceName = asmVariableName(pointervar) if (isTargetCpu(CpuType.CPU65c02)) { - return if (allocator.isZpVar(target.scopedName.joinToString("."))) { + return if (allocator.isZpVar(target.scopedName)) { // pointervar is already in the zero page, no need to copy out(" lda ($sourceName)") sourceName @@ -137,7 +137,7 @@ class AsmGen(internal val program: Program, "P8ZP_SCRATCH_W1" } } else { - return if (allocator.isZpVar(target.scopedName.joinToString("."))) { + return if (allocator.isZpVar(target.scopedName)) { // pointervar is already in the zero page, no need to copy out(" ldy #0 | lda ($sourceName),y") sourceName @@ -161,7 +161,7 @@ class AsmGen(internal val program: Program, val sourceName = asmVariableName(pointervar) val vardecl = pointervar.targetVarDecl(program)!! if (isTargetCpu(CpuType.CPU65c02)) { - if (allocator.isZpVar(vardecl.scopedName.joinToString("."))) { + if (allocator.isZpVar(vardecl.scopedName)) { // pointervar is already in the zero page, no need to copy out(" sta ($sourceName)") } else { @@ -173,7 +173,7 @@ class AsmGen(internal val program: Program, sta (P8ZP_SCRATCH_W2)""") } } else { - if (allocator.isZpVar(vardecl.scopedName.joinToString("."))) { + if (allocator.isZpVar(vardecl.scopedName)) { // pointervar is already in the zero page, no need to copy out(" ldy #0 | sta ($sourceName),y") } else { @@ -726,7 +726,7 @@ $repeatLabel lda $counterVar val counterVar = program.makeLabel("counter") when(dt) { DataType.UBYTE, DataType.UWORD -> { - val result = zeropage.allocate(counterVar, dt, null, stmt.position, errors) + val result = zeropage.allocate(listOf(counterVar), dt, null, stmt.position, errors) result.fold( success = { (address, _) -> asmInfo.extraVars.add(Triple(dt, counterVar, address)) }, failure = { asmInfo.extraVars.add(Triple(dt, counterVar, null)) } // allocate normally @@ -988,7 +988,7 @@ $repeatLabel lda $counterVar } internal fun isZpVar(variable: IdentifierReference): Boolean = - allocator.isZpVar(variable.targetVarDecl(program)!!.scopedName.joinToString(".")) + allocator.isZpVar(variable.targetVarDecl(program)!!.scopedName) internal fun jmp(asmLabel: String, indirect: Boolean=false) { if(indirect) { diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt index f9bb878be..f3cdb6084 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt @@ -287,7 +287,7 @@ $loopLabel sty $indexVar } if(length>=16) { // allocate index var on ZP if possible - val result = zeropage.allocate(indexVar, DataType.UBYTE, null, stmt.position, asmgen.errors) + val result = zeropage.allocate(listOf(indexVar), DataType.UBYTE, null, stmt.position, asmgen.errors) result.fold( success = { (address,_)-> asmgen.out("""$indexVar = $address ; auto zp UBYTE""") }, failure = { asmgen.out("$indexVar .byte 0") } @@ -328,7 +328,7 @@ $loopLabel sty $indexVar } if(length>=16) { // allocate index var on ZP if possible - val result = zeropage.allocate(indexVar, DataType.UBYTE, null, stmt.position, asmgen.errors) + val result = zeropage.allocate(listOf(indexVar), DataType.UBYTE, null, stmt.position, asmgen.errors) result.fold( success = { (address,_)-> asmgen.out("""$indexVar = $address ; auto zp UBYTE""") }, failure = { asmgen.out("$indexVar .byte 0") } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt index d074da5d6..4e69dc90b 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt @@ -242,7 +242,7 @@ internal class ProgramAndVarsGen( // normal statically allocated variables val variables = varsInBlock - .filter { it.value.type==StNodeType.STATICVAR && !allocator.isZpVar(it.value.scopedName) } + .filter { it.value.type==StNodeType.STATICVAR && !allocator.isZpVar(it.value.scopedName.split('.')) } .map { it.value as StStaticVariable } nonZpVariables2asm(variables) } @@ -357,7 +357,7 @@ internal class ProgramAndVarsGen( // normal statically allocated variables val variables = varsInSubroutine - .filter { it.value.type==StNodeType.STATICVAR && !allocator.isZpVar(it.value.scopedName) } + .filter { it.value.type==StNodeType.STATICVAR && !allocator.isZpVar(it.value.scopedName.split('.')) } .map { it.value as StStaticVariable } nonZpVariables2asm(variables) @@ -443,9 +443,10 @@ internal class ProgramAndVarsGen( val result = mutableListOf() val vars = allocator.zeropageVars.filter { it.value.dt==DataType.STR } for (variable in vars) { - val svar = symboltable.flat.getValue(variable.key) as StStaticVariable + val scopedName = variable.key.joinToString(".") + val svar = symboltable.flat.getValue(scopedName) as StStaticVariable if(svar.onetimeInitializationStringValue!=null) - result.add(ZpStringWithInitial(variable.key, variable.value, svar.onetimeInitializationStringValue!!)) + result.add(ZpStringWithInitial(scopedName, variable.value, svar.onetimeInitializationStringValue!!)) } return result } @@ -454,20 +455,21 @@ internal class ProgramAndVarsGen( val result = mutableListOf() val vars = allocator.zeropageVars.filter { it.value.dt in ArrayDatatypes } for (variable in vars) { - val svar = symboltable.flat.getValue(variable.key) as StStaticVariable + val scopedName = variable.key.joinToString(".") + val svar = symboltable.flat.getValue(scopedName) as StStaticVariable if(svar.onetimeInitializationArrayValue!=null) - result.add(ZpArrayWithInitial(variable.key, variable.value, svar.onetimeInitializationArrayValue!!)) + result.add(ZpArrayWithInitial(scopedName, variable.value, svar.onetimeInitializationArrayValue!!)) } return result } private fun zeropagevars2asm(varNames: Set) { - val zpVariables = allocator.zeropageVars.filter { it.key in varNames } + val namesLists = varNames.map { it.split('.') }.toSet() + val zpVariables = allocator.zeropageVars.filter { it.key in namesLists } for ((scopedName, zpvar) in zpVariables) { - val parts = scopedName.split('.') - if (parts.size == 2 && parts[0] == "cx16" && parts[1][0] == 'r' && parts[1][1].isDigit()) + if (scopedName.size == 2 && scopedName[0] == "cx16" && scopedName[1][0] == 'r' && scopedName[1][1].isDigit()) continue // The 16 virtual registers of the cx16 are not actual variables in zp, they're memory mapped - asmgen.out("${parts.last()} \t= ${zpvar.address} \t; zp ${zpvar.dt}") + asmgen.out("${scopedName.last()} \t= ${zpvar.address} \t; zp ${zpvar.dt}") } } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt index f6ba9f801..ae1e60702 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt @@ -16,13 +16,13 @@ internal class VariableAllocator(private val symboltable: SymbolTable, private val zeropage = options.compTarget.machine.zeropage internal val globalFloatConsts = mutableMapOf() // all float values in the entire program (value -> varname) - internal val zeropageVars: Map = zeropage.allocatedVariables + internal val zeropageVars: Map, MemoryAllocator.VarAllocation> = zeropage.allocatedVariables init { allocateZeropageVariables() } - internal fun isZpVar(scopedName: String) = scopedName in zeropageVars + internal fun isZpVar(scopedName: List) = scopedName in zeropageVars internal fun getFloatAsmConst(number: Double): String { val asmName = globalFloatConsts[number] @@ -56,7 +56,7 @@ internal class VariableAllocator(private val symboltable: SymbolTable, varsRequiringZp.forEach { variable -> val result = zeropage.allocate( - variable.scopedName, + variable.scopedName.split('.'), variable.dt, variable.length, variable.position, @@ -75,7 +75,7 @@ internal class VariableAllocator(private val symboltable: SymbolTable, if(errors.noErrors()) { varsPreferringZp.forEach { variable -> val result = zeropage.allocate( - variable.scopedName, + variable.scopedName.split('.'), variable.dt, variable.length, variable.position, @@ -94,7 +94,7 @@ internal class VariableAllocator(private val symboltable: SymbolTable, break } else { val result = zeropage.allocate( - variable.scopedName, + variable.scopedName.split('.'), variable.dt, variable.length, variable.position, diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index 4d3d1d528..5deb3deef 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -325,7 +325,7 @@ internal class AssignmentAsmGen(private val program: Program, assignFAC1float(assign.target) } else { // array[x] = -value ... use a tempvar then store that back into the array. - val tempvar = asmgen.getTempVarName(assign.target.datatype).joinToString(".") + val tempvar = asmgen.getTempVarName(assign.target.datatype) val assignToTempvar = AsmAssignment(assign.source, AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, assign.target.datatype, assign.target.scope, variableAsmName=tempvar, origAstTarget = assign.target.origAstTarget), false, program.memsizer, assign.position) diff --git a/compiler/test/TestGoldenRam.kt b/compiler/test/TestGoldenRam.kt index 98bed12a9..9f290fb2d 100644 --- a/compiler/test/TestGoldenRam.kt +++ b/compiler/test/TestGoldenRam.kt @@ -25,7 +25,7 @@ class TestGoldenRam: FunSpec({ test("empty golden ram allocations") { val errors = ErrorReporterForTests() val golden = GoldenRam(options, UIntRange.EMPTY) - val result = golden.allocate("test", DataType.UBYTE, null, null, errors) + val result = golden.allocate(listOf("test"), DataType.UBYTE, null, null, errors) result.expectError { "should not be able to allocate anything" } } @@ -33,28 +33,28 @@ class TestGoldenRam: FunSpec({ val errors = ErrorReporterForTests() val golden = GoldenRam(options, 0x400u until 0x800u) - var result = golden.allocate("test", DataType.UBYTE, null, null, errors) + var result = golden.allocate(listOf("test"), DataType.UBYTE, null, null, errors) var alloc = result.getOrThrow() alloc.size shouldBe 1 alloc.address shouldBe 0x400u - result = golden.allocate("test", DataType.STR, 100, null, errors) + result = golden.allocate(listOf("test"), DataType.STR, 100, null, errors) alloc = result.getOrThrow() alloc.size shouldBe 100 alloc.address shouldBe 0x401u repeat(461) { - result = golden.allocate("test", DataType.UWORD, null, null, errors) + result = golden.allocate(listOf("test"), DataType.UWORD, null, null, errors) alloc = result.getOrThrow() alloc.size shouldBe 2 } - result = golden.allocate("test", DataType.UWORD, null, null, errors) + result = golden.allocate(listOf("test"), DataType.UWORD, null, null, errors) result.expectError { "just 1 more byte available" } - result = golden.allocate("test", DataType.UBYTE, null, null, errors) + result = golden.allocate(listOf("test"), DataType.UBYTE, null, null, errors) alloc = result.getOrThrow() alloc.size shouldBe 1 alloc.address shouldBe golden.region.last - result = golden.allocate("test", DataType.UBYTE, null, null, errors) + result = golden.allocate(listOf("test"), DataType.UBYTE, null, null, errors) result.expectError { "nothing more available" } } diff --git a/compiler/test/TestZeropage.kt b/compiler/test/TestZeropage.kt index 5325ad795..9f6ff143e 100644 --- a/compiler/test/TestZeropage.kt +++ b/compiler/test/TestZeropage.kt @@ -71,26 +71,26 @@ class TestC64Zeropage: FunSpec({ compTarget = c64target, loadAddress = 999u )) - var result = zp.allocate("", DataType.UBYTE, null, null, errors) + var result = zp.allocate(emptyList(), DataType.UBYTE, null, null, errors) result.onFailure { fail(it.toString()) } - result = zp.allocate("", DataType.UBYTE, null, null, errors) + result = zp.allocate(emptyList(), DataType.UBYTE, null, null, errors) result.onFailure { fail(it.toString()) } - result = zp.allocate("varname", DataType.UBYTE, null, null, errors) + result = zp.allocate(listOf("varname"), DataType.UBYTE, null, null, errors) result.onFailure { fail(it.toString()) } - shouldThrow { zp.allocate("varname", DataType.UBYTE,null, null, errors) } - result = zp.allocate("varname2", DataType.UBYTE, null, null, errors) + shouldThrow { zp.allocate(listOf("varname"), DataType.UBYTE,null, null, errors) } + result = zp.allocate(listOf("varname2"), DataType.UBYTE, null, null, errors) result.onFailure { fail(it.toString()) } } test("testZpFloatEnable") { val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, c64target, 999u)) - var result = zp.allocate("", DataType.FLOAT, null, null, errors) + var result = zp.allocate(emptyList(), DataType.FLOAT, null, null, errors) result.expectError { "should be allocation error due to disabled floats" } val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.DONTUSE, emptyList(), true, false, c64target, 999u)) - result = zp2.allocate("", DataType.FLOAT, null, null, errors) + result = zp2.allocate(emptyList(), DataType.FLOAT, null, null, errors) result.expectError { "should be allocation error due to disabled ZP use" } val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), true, false, c64target, 999u)) - zp3.allocate("", DataType.FLOAT, null, null, errors) + zp3.allocate(emptyList(), DataType.FLOAT, null, null, errors) } test("testZpModesWithFloats") { @@ -112,7 +112,7 @@ class TestC64Zeropage: FunSpec({ val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.DONTUSE, emptyList(), false, false, c64target, 999u)) println(zp.free) zp.availableBytes() shouldBe 0 - val result = zp.allocate("", DataType.BYTE, null, null, errors) + val result = zp.allocate(emptyList(), DataType.BYTE, null, null, errors) result.expectError { "expected error due to disabled ZP use" } } @@ -125,9 +125,9 @@ class TestC64Zeropage: FunSpec({ zp3.availableBytes() shouldBe 97 val zp4 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, c64target, 999u)) zp4.availableBytes() shouldBe 207 - zp4.allocate("test", DataType.UBYTE, null, null, errors) + zp4.allocate(listOf("test"), DataType.UBYTE, null, null, errors) zp4.availableBytes() shouldBe 206 - zp4.allocate("test2", DataType.UBYTE, null, null, errors) + zp4.allocate(listOf("test2"), DataType.UBYTE, null, null, errors) zp4.availableBytes() shouldBe 205 } @@ -166,19 +166,19 @@ class TestC64Zeropage: FunSpec({ zp.hasByteAvailable() shouldBe true zp.hasWordAvailable() shouldBe true - var result = zp.allocate("", DataType.FLOAT, null, null, errors) + var result = zp.allocate(emptyList(), DataType.FLOAT, null, null, errors) result.expectError { "expect allocation error: in regular zp there aren't 5 sequential bytes free" } for (i in 0 until zp.availableBytes()) { - val alloc = zp.allocate("", DataType.UBYTE, null, null, errors) + val alloc = zp.allocate(emptyList(), DataType.UBYTE, null, null, errors) alloc.getOrElse { throw it } } zp.availableBytes() shouldBe 0 zp.hasByteAvailable() shouldBe false zp.hasWordAvailable() shouldBe false - result = zp.allocate("", DataType.UBYTE, null, null, errors) + result = zp.allocate(emptyList(), DataType.UBYTE, null, null, errors) result.expectError { "expected allocation error" } - result = zp.allocate("", DataType.UWORD, null, null, errors) + result = zp.allocate(emptyList(), DataType.UWORD, null, null, errors) result.expectError { "expected allocation error" } } @@ -187,47 +187,47 @@ class TestC64Zeropage: FunSpec({ zp.availableBytes() shouldBe 207 zp.hasByteAvailable() shouldBe true zp.hasWordAvailable() shouldBe true - var result = zp.allocate("", DataType.UWORD, null, null, errors) + var result = zp.allocate(emptyList(), DataType.UWORD, null, null, errors) val loc = result.getOrElse { throw it } .address loc shouldBeGreaterThan 3u loc shouldNotBeIn zp.free val num = zp.availableBytes() / 2 for(i in 0..num-3) { - zp.allocate("", DataType.UWORD, null, null, errors) + zp.allocate(emptyList(), DataType.UWORD, null, null, errors) } zp.availableBytes() shouldBe 5 // can't allocate because no more sequential bytes, only fragmented - result = zp.allocate("", DataType.UWORD, null, null, errors) + result = zp.allocate(emptyList(), DataType.UWORD, null, null, errors) result.expectError { "should give allocation error" } for(i in 0..4) { - zp.allocate("", DataType.UBYTE, null, null, errors) + zp.allocate(emptyList(), DataType.UBYTE, null, null, errors) } zp.availableBytes() shouldBe 0 zp.hasByteAvailable() shouldBe false zp.hasWordAvailable() shouldBe false - result = zp.allocate("", DataType.UBYTE, null, null, errors) + result = zp.allocate(emptyList(), DataType.UBYTE, null, null, errors) result.expectError { "should give allocation error" } } test("testEfficientAllocation") { val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false, c64target, 999u)) zp.availableBytes() shouldBe 18 - zp.allocate("", DataType.WORD, null, null, errors).getOrElse{throw it}.address shouldBe 0x04u - zp.allocate("", DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0x06u - zp.allocate("", DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0x0au - zp.allocate("", DataType.UWORD, null, null, errors).getOrElse{throw it}.address shouldBe 0x9bu - zp.allocate("", DataType.UWORD, null, null, errors).getOrElse{throw it}.address shouldBe 0x9eu - zp.allocate("", DataType.UWORD, null, null, errors).getOrElse{throw it}.address shouldBe 0xa5u - zp.allocate("", DataType.UWORD, null, null, errors).getOrElse{throw it}.address shouldBe 0xb0u - zp.allocate("", DataType.UWORD, null, null, errors).getOrElse{throw it}.address shouldBe 0xbeu - zp.allocate("", DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0x0eu - zp.allocate("", DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0x92u - zp.allocate("", DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0x96u - zp.allocate("", DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0xf9u + zp.allocate(emptyList(), DataType.WORD, null, null, errors).getOrElse{throw it}.address shouldBe 0x04u + zp.allocate(emptyList(), DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0x06u + zp.allocate(emptyList(), DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0x0au + zp.allocate(emptyList(), DataType.UWORD, null, null, errors).getOrElse{throw it}.address shouldBe 0x9bu + zp.allocate(emptyList(), DataType.UWORD, null, null, errors).getOrElse{throw it}.address shouldBe 0x9eu + zp.allocate(emptyList(), DataType.UWORD, null, null, errors).getOrElse{throw it}.address shouldBe 0xa5u + zp.allocate(emptyList(), DataType.UWORD, null, null, errors).getOrElse{throw it}.address shouldBe 0xb0u + zp.allocate(emptyList(), DataType.UWORD, null, null, errors).getOrElse{throw it}.address shouldBe 0xbeu + zp.allocate(emptyList(), DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0x0eu + zp.allocate(emptyList(), DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0x92u + zp.allocate(emptyList(), DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0x96u + zp.allocate(emptyList(), DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0xf9u zp.availableBytes() shouldBe 0 } @@ -258,9 +258,9 @@ class TestCx16Zeropage: FunSpec({ zp2.availableBytes() shouldBe 175 val zp3 = CX16Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, cx16target, 999u)) zp3.availableBytes() shouldBe 216 - zp3.allocate("test", DataType.UBYTE, null, null, errors) + zp3.allocate(listOf("test"), DataType.UBYTE, null, null, errors) zp3.availableBytes() shouldBe 215 - zp3.allocate("test2", DataType.UBYTE, null, null, errors) + zp3.allocate(listOf("test2"), DataType.UBYTE, null, null, errors) zp3.availableBytes() shouldBe 214 } @@ -276,12 +276,12 @@ class TestCx16Zeropage: FunSpec({ test("preallocated zp vars") { val zp1 = CX16Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, cx16target, 999u)) - zp1.allocatedVariables["test"] shouldBe null - zp1.allocatedVariables["cx16.r0"] shouldNotBe null - zp1.allocatedVariables["cx16.r15"] shouldNotBe null - zp1.allocatedVariables["cx16.r0L"] shouldNotBe null - zp1.allocatedVariables["cx16.r15L"] shouldNotBe null - zp1.allocatedVariables["cx16.r0sH"] shouldNotBe null - zp1.allocatedVariables["cx16.r15sH"] shouldNotBe null + zp1.allocatedVariables[listOf("test")] shouldBe null + zp1.allocatedVariables[listOf("cx16", "r0")] shouldNotBe null + zp1.allocatedVariables[listOf("cx16", "r15")] shouldNotBe null + zp1.allocatedVariables[listOf("cx16", "r0L")] shouldNotBe null + zp1.allocatedVariables[listOf("cx16", "r15L")] shouldNotBe null + zp1.allocatedVariables[listOf("cx16", "r0sH")] shouldNotBe null + zp1.allocatedVariables[listOf("cx16", "r15sH")] shouldNotBe null } }) diff --git a/docs/source/todo.rst b/docs/source/todo.rst index c72f70645..9b8502bc0 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,7 +3,7 @@ TODO For next release ^^^^^^^^^^^^^^^^ -- optimize scoped symbols: .split('.') / .joinToString(".") +- optimize array1[index] += / -= array2[index] to not use slow stackeval (attemptAssignOptimizedBinexpr) ... @@ -28,6 +28,7 @@ Compiler: - ir: peephole opt: renumber registers in chunks to start with 1 again every time (but keep entry values in mind!) - ir: peephole opt: reuse registers in chunks (but keep result registers in mind that pass values out! and don't renumber registers above SyscallRegisterBase!) - ir: add more optimizations in IRPeepholeOptimizer +- ir: for expressions with array indexes that occur multiple times, can we avoid loading them into new virtualregs everytime and just reuse a single virtualreg as indexer? - vm: somehow be able to load a label address as value? (VmProgramLoader) - 6502 codegen: see if we can let for loops skip the loop if startvar>endvar, without adding a lot of code size/duplicating the loop condition. It is documented behavior to now loop 'around' $00 but it's too easy to forget about!