From 8736da1a2119627a22f06a1a4a17348e40715a2d Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Wed, 5 May 2021 23:01:04 +0200 Subject: [PATCH] strings of 1 and 2 length no longer optimized into one call to CHROUT - also upgrade to kotlin 1.5.0 --- compiler/build.gradle | 2 +- compiler/src/prog8/compiler/Compiler.kt | 51 +++---- .../compiler/astprocessing/AstChecker.kt | 12 +- .../compiler/functions/BuiltinFunctions.kt | 2 +- .../src/prog8/compiler/target/cbm/Petscii.kt | 8 +- .../compiler/target/cpu6502/codegen/AsmGen.kt | 70 +++++---- .../cpu6502/codegen/BuiltinFunctionsAsmGen.kt | 9 +- .../cpu6502/codegen/ExpressionsAsmGen.kt | 7 +- .../cpu6502/codegen/FunctionCallAsmGen.kt | 24 +++- .../codegen/assignment/AsmAssignment.kt | 6 +- .../codegen/assignment/AssignmentAsmGen.kt | 135 +++++++++++------- compiler/src/prog8/optimizer/CallGraph.kt | 1 - .../src/prog8/optimizer/StatementOptimizer.kt | 42 ------ compilerAst/build.gradle | 2 +- compilerAst/src/prog8/ast/AstToSourceCode.kt | 9 +- .../src/prog8/ast/antlr/Antr2Kotlin.kt | 7 +- dbusCompilerService/build.gradle | 2 +- docs/source/todo.rst | 2 + examples/test.p8 | 40 ++---- httpCompilerService/build.gradle | 2 +- 20 files changed, 222 insertions(+), 211 deletions(-) diff --git a/compiler/build.gradle b/compiler/build.gradle index 0b3a9c1d5..46057c48a 100644 --- a/compiler/build.gradle +++ b/compiler/build.gradle @@ -1,7 +1,7 @@ plugins { id 'java' id 'application' - id "org.jetbrains.kotlin.jvm" version "1.4.32" + id "org.jetbrains.kotlin.jvm" version "1.5.0" id 'com.github.johnrengelman.shadow' version '6.1.0' } diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index d133dc3d7..f03010f59 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -196,51 +196,52 @@ private fun parseImports(filepath: Path, errors: IErrorReporter, compTarget: ICo private fun determineCompilationOptions(program: Program, compTarget: ICompilationTarget): CompilationOptions { val mainModule = program.mainModule val outputType = (mainModule.statements.singleOrNull { it is Directive && it.directive == "%output" } - as? Directive)?.args?.single()?.name?.toUpperCase() + as? Directive)?.args?.single()?.name?.uppercase() val launcherType = (mainModule.statements.singleOrNull { it is Directive && it.directive == "%launcher" } - as? Directive)?.args?.single()?.name?.toUpperCase() + as? Directive)?.args?.single()?.name?.uppercase() val zpoption: String? = (mainModule.statements.singleOrNull { it is Directive && it.directive == "%zeropage" } - as? Directive)?.args?.single()?.name?.toUpperCase() - val allOptions = program.modules.flatMap { it.statements }.filter { it is Directive && it.directive == "%option" }.flatMap { (it as Directive).args }.toSet() + as? Directive)?.args?.single()?.name?.uppercase() + val allOptions = program.modules.flatMap { it.statements }.filter { it is Directive && it.directive == "%option" } + .flatMap { (it as Directive).args }.toSet() val floatsEnabled = allOptions.any { it.name == "enable_floats" } val noSysInit = allOptions.any { it.name == "no_sysinit" } var zpType: ZeropageType = - if (zpoption == null) - if(floatsEnabled) ZeropageType.FLOATSAFE else ZeropageType.KERNALSAFE - else - try { - ZeropageType.valueOf(zpoption) - } catch (x: IllegalArgumentException) { - ZeropageType.KERNALSAFE - // error will be printed by the astchecker - } + if (zpoption == null) + if (floatsEnabled) ZeropageType.FLOATSAFE else ZeropageType.KERNALSAFE + else + try { + ZeropageType.valueOf(zpoption) + } catch (x: IllegalArgumentException) { + ZeropageType.KERNALSAFE + // error will be printed by the astchecker + } - if (zpType==ZeropageType.FLOATSAFE && compTarget.name == Cx16Target.name) { + if (zpType == ZeropageType.FLOATSAFE && compTarget.name == Cx16Target.name) { System.err.println("Warning: zp option floatsafe changed to basicsafe for cx16 target") zpType = ZeropageType.BASICSAFE } val zpReserved = mainModule.statements - .asSequence() - .filter { it is Directive && it.directive == "%zpreserved" } - .map { (it as Directive).args } - .map { it[0].int!!..it[1].int!! } - .toList() + .asSequence() + .filter { it is Directive && it.directive == "%zpreserved" } + .map { (it as Directive).args } + .map { it[0].int!!..it[1].int!! } + .toList() - if(outputType!=null && !OutputType.values().any {it.name==outputType}) { + if (outputType != null && !OutputType.values().any { it.name == outputType }) { System.err.println("invalid output type $outputType") exitProcess(1) } - if(launcherType!=null && !LauncherType.values().any {it.name==launcherType}) { + if (launcherType != null && !LauncherType.values().any { it.name == launcherType }) { System.err.println("invalid launcher type $launcherType") exitProcess(1) } return CompilationOptions( - if (outputType == null) OutputType.PRG else OutputType.valueOf(outputType), - if (launcherType == null) LauncherType.BASIC else LauncherType.valueOf(launcherType), - zpType, zpReserved, floatsEnabled, noSysInit, - compTarget + if (outputType == null) OutputType.PRG else OutputType.valueOf(outputType), + if (launcherType == null) LauncherType.BASIC else LauncherType.valueOf(launcherType), + zpType, zpReserved, floatsEnabled, noSysInit, + compTarget ) } diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index 8c0322d50..f1538df5c 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -16,6 +16,7 @@ import prog8.compiler.target.C64Target import prog8.compiler.target.Cx16Target import prog8.compiler.target.ICompilationTarget import java.io.File +import java.util.* internal class AstChecker(private val program: Program, private val compilerOptions: CompilationOptions, @@ -1029,7 +1030,7 @@ internal class AstChecker(private val program: Program, ident = fcall.args[0] as? IdentifierReference } if(ident!=null && ident.nameInSource[0] == "cx16" && ident.nameInSource[1].startsWith("r")) { - val reg = RegisterOrPair.valueOf(ident.nameInSource[1].toUpperCase()) + val reg = RegisterOrPair.valueOf(ident.nameInSource[1].uppercase()) val same = params.filter { it.value.registerOrPair==reg } for(s in same) { if(s.index!=arg.index) { @@ -1355,10 +1356,15 @@ internal class AstChecker(private val program: Program, errors.err("cannot assign word to byte, use msb() or lsb()?", position) } else if(sourceDatatype== DataType.FLOAT && targetDatatype in IntegerDatatypes) - errors.err("cannot assign float to ${targetDatatype.name.toLowerCase()}; possible loss of precision. Suggestion: round the value or revert to integer arithmetic", position) + errors.err("cannot assign float to ${targetDatatype.name.lowercase()}; possible loss of precision. Suggestion: round the value or revert to integer arithmetic", position) else { if(targetDatatype!=DataType.UWORD && sourceDatatype !in PassByReferenceDatatypes) - errors.err("cannot assign ${sourceDatatype.name.toLowerCase()} to ${targetDatatype.name.toLowerCase()}", position) + errors.err( + "cannot assign ${sourceDatatype.name.lowercase()} to ${ + targetDatatype.name.lowercase( + Locale.getDefault() + ) + }", position) } diff --git a/compiler/src/prog8/compiler/functions/BuiltinFunctions.kt b/compiler/src/prog8/compiler/functions/BuiltinFunctions.kt index e32011398..17e60f8f3 100644 --- a/compiler/src/prog8/compiler/functions/BuiltinFunctions.kt +++ b/compiler/src/prog8/compiler/functions/BuiltinFunctions.kt @@ -153,7 +153,7 @@ fun builtinMax(array: List): Number = array.maxByOrNull { it.toDouble() fun builtinMin(array: List): Number = array.minByOrNull { it.toDouble() }!! -fun builtinSum(array: List): Number = array.sumByDouble { it.toDouble() } +fun builtinSum(array: List): Number = array.sumOf { it.toDouble() } fun builtinAny(array: List): Number = if(array.any { it.toDouble()!=0.0 }) 1 else 0 diff --git a/compiler/src/prog8/compiler/target/cbm/Petscii.kt b/compiler/src/prog8/compiler/target/cbm/Petscii.kt index 0e4d12556..04dc4d325 100644 --- a/compiler/src/prog8/compiler/target/cbm/Petscii.kt +++ b/compiler/src/prog8/compiler/target/cbm/Petscii.kt @@ -1069,11 +1069,11 @@ object Petscii { '\u0000' -> 0.toShort() in '\u8000'..'\u80ff' -> { // special case: take the lower 8 bit hex value directly - (chr.toInt() - 0x8000).toShort() + (chr.code - 0x8000).toShort() } else -> { val case = if (lowercase) "lower" else "upper" - throw CharConversionException("no ${case}Petscii character for '$chr' (${chr.toShort()})") + throw CharConversionException("no ${case}Petscii character for '$chr' (${chr.code})") } } } @@ -1106,11 +1106,11 @@ object Petscii { '\u0000' -> 0.toShort() in '\u8000'..'\u80ff' -> { // special case: take the lower 8 bit hex value directly - (chr.toInt() - 0x8000).toShort() + (chr.code - 0x8000).toShort() } else -> { val case = if (lowercase) "lower" else "upper" - throw CharConversionException("no ${case}Screencode character for '$chr' (${chr.toShort()})") + throw CharConversionException("no ${case}Screencode character for '$chr' (${chr.code})") } } } diff --git a/compiler/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt b/compiler/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt index 5c66c2502..9229f96df 100644 --- a/compiler/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt @@ -351,6 +351,9 @@ internal class AsmGen(private val program: Program, for (f in array.zip(floatFills)) out(" .byte ${f.second} ; float ${f.first}") } + else -> { + throw AssemblyError("weird dt") + } } } @@ -498,8 +501,8 @@ internal class AsmGen(private val program: Program, fixNameSymbols(identifier.nameInSource.joinToString(".")) internal fun asmSymbolName(regs: RegisterOrPair): String = - if(regs in Cx16VirtualRegisters) - "cx16." + regs.toString().toLowerCase() + if (regs in Cx16VirtualRegisters) + "cx16." + regs.toString().lowercase() else throw AssemblyError("no symbol name for register $regs") @@ -689,14 +692,16 @@ internal class AsmGen(private val program: Program, } } - internal fun loadScaledArrayIndexIntoRegister(expr: ArrayIndexedExpression, - elementDt: DataType, - register: CpuRegister, - addOneExtra: Boolean=false) { - val reg = register.toString().toLowerCase() + internal fun loadScaledArrayIndexIntoRegister( + expr: ArrayIndexedExpression, + elementDt: DataType, + register: CpuRegister, + addOneExtra: Boolean = false + ) { + val reg = register.toString().lowercase() val indexnum = expr.indexer.constIndex() - if(indexnum!=null) { - val indexValue = indexnum * compTarget.memorySize(elementDt) + if(addOneExtra) 1 else 0 + if (indexnum != null) { + val indexValue = indexnum * compTarget.memorySize(elementDt) + if (addOneExtra) 1 else 0 out(" ld$reg #$indexValue") return } @@ -705,35 +710,40 @@ internal class AsmGen(private val program: Program, ?: throw AssemblyError("array indexer should have been replaced with a temp var @ ${expr.indexer.position}") val indexName = asmVariableName(indexVar) - if(addOneExtra) { + if (addOneExtra) { // add 1 to the result - when(elementDt) { + when (elementDt) { in ByteDatatypes -> { out(" ldy $indexName | iny") - when(register) { + when (register) { CpuRegister.A -> out(" tya") CpuRegister.X -> out(" tyx") - CpuRegister.Y -> {} + CpuRegister.Y -> { + } } } in WordDatatypes -> { out(" lda $indexName | sec | rol a") - when(register) { - CpuRegister.A -> {} + when (register) { + CpuRegister.A -> { + } CpuRegister.X -> out(" tax") CpuRegister.Y -> out(" tay") } } DataType.FLOAT -> { - require(compTarget.memorySize(DataType.FLOAT)==5) - out(""" + require(compTarget.memorySize(DataType.FLOAT) == 5) + out( + """ lda $indexName asl a asl a sec - adc $indexName""") - when(register) { - CpuRegister.A -> {} + adc $indexName""" + ) + when (register) { + CpuRegister.A -> { + } CpuRegister.X -> out(" tax") CpuRegister.Y -> out(" tay") } @@ -741,26 +751,30 @@ internal class AsmGen(private val program: Program, else -> throw AssemblyError("weird dt") } } else { - when(elementDt) { + when (elementDt) { in ByteDatatypes -> out(" ld$reg $indexName") in WordDatatypes -> { out(" lda $indexName | asl a") - when(register) { - CpuRegister.A -> {} + when (register) { + CpuRegister.A -> { + } CpuRegister.X -> out(" tax") CpuRegister.Y -> out(" tay") } } DataType.FLOAT -> { - require(compTarget.memorySize(DataType.FLOAT)==5) - out(""" + require(compTarget.memorySize(DataType.FLOAT) == 5) + out( + """ lda $indexName asl a asl a clc - adc $indexName""") - when(register) { - CpuRegister.A -> {} + adc $indexName""" + ) + when (register) { + CpuRegister.A -> { + } CpuRegister.X -> out(" tax") CpuRegister.Y -> out(" tay") } diff --git a/compiler/src/prog8/compiler/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt b/compiler/src/prog8/compiler/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt index bd17c271a..196b1f656 100644 --- a/compiler/src/prog8/compiler/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt @@ -1260,7 +1260,10 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val RegisterOrPair.AY -> {} RegisterOrPair.AX -> asmgen.out(" sty P8ZP_SCRATCH_REG | ldx P8ZP_SCRATCH_REG") RegisterOrPair.XY -> asmgen.out(" tax") - in Cx16VirtualRegisters -> asmgen.out(" sta cx16.${resultRegister.toString().toLowerCase()} | sty cx16.${resultRegister.toString().toLowerCase()}+1") + in Cx16VirtualRegisters -> asmgen.out( + " sta cx16.${ + resultRegister.toString().lowercase() + } | sty cx16.${resultRegister.toString().lowercase()}+1") else -> throw AssemblyError("invalid reg") } } @@ -1310,9 +1313,9 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val } in Cx16VirtualRegisters -> { asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.A) // lsb - asmgen.out(" sta cx16.${reg.toString().toLowerCase()}") + asmgen.out(" sta cx16.${reg.toString().lowercase()}") asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.A) // msb - asmgen.out(" sta cx16.${reg.toString().toLowerCase()}+1") + asmgen.out(" sta cx16.${reg.toString().lowercase()}+1") } else -> throw AssemblyError("invalid mkword target reg") } diff --git a/compiler/src/prog8/compiler/target/cpu6502/codegen/ExpressionsAsmGen.kt b/compiler/src/prog8/compiler/target/cpu6502/codegen/ExpressionsAsmGen.kt index 3046c8c9c..2a5c22c1c 100644 --- a/compiler/src/prog8/compiler/target/cpu6502/codegen/ExpressionsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/cpu6502/codegen/ExpressionsAsmGen.kt @@ -1573,10 +1573,11 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge RegisterOrPair.R13, RegisterOrPair.R14, RegisterOrPair.R15 -> { - asmgen.out(""" - lda cx16.${reg.registerOrPair.toString().toLowerCase()} + asmgen.out( + """ + lda cx16.${reg.registerOrPair.toString().lowercase()} sta P8ESTACK_LO,x - lda cx16.${reg.registerOrPair.toString().toLowerCase()}+1 + lda cx16.${reg.registerOrPair.toString().lowercase()}+1 sta P8ESTACK_HI,x dex """) diff --git a/compiler/src/prog8/compiler/target/cpu6502/codegen/FunctionCallAsmGen.kt b/compiler/src/prog8/compiler/target/cpu6502/codegen/FunctionCallAsmGen.kt index 0ced5d947..c0b877803 100644 --- a/compiler/src/prog8/compiler/target/cpu6502/codegen/FunctionCallAsmGen.kt +++ b/compiler/src/prog8/compiler/target/cpu6502/codegen/FunctionCallAsmGen.kt @@ -175,21 +175,31 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg when (sub.parameters[argi.index].type) { in ByteDatatypes -> { // only load the lsb of the virtual register - asmgen.out(""" + asmgen.out( + """ lda P8ESTACK_LO$plusIdxStr,x - sta cx16.${argi.value.second.registerOrPair.toString().toLowerCase()} + sta cx16.${argi.value.second.registerOrPair.toString().lowercase()} """) if (asmgen.isTargetCpu(CpuType.CPU65c02)) - asmgen.out(" stz cx16.${argi.value.second.registerOrPair.toString().toLowerCase()}+1") + asmgen.out( + " stz cx16.${ + argi.value.second.registerOrPair.toString().lowercase() + }+1") else - asmgen.out(" lda #0 | sta cx16.${argi.value.second.registerOrPair.toString().toLowerCase()}+1") + asmgen.out( + " lda #0 | sta cx16.${ + argi.value.second.registerOrPair.toString().lowercase() + }+1") } in WordDatatypes, in IterableDatatypes -> - asmgen.out(""" + asmgen.out( + """ lda P8ESTACK_LO$plusIdxStr,x - sta cx16.${argi.value.second.registerOrPair.toString().toLowerCase()} + sta cx16.${argi.value.second.registerOrPair.toString().lowercase()} lda P8ESTACK_HI$plusIdxStr,x - sta cx16.${argi.value.second.registerOrPair.toString().toLowerCase()}+1 + sta cx16.${ + argi.value.second.registerOrPair.toString().lowercase() + }+1 """) else -> throw AssemblyError("weird dt") } diff --git a/compiler/src/prog8/compiler/target/cpu6502/codegen/assignment/AsmAssignment.kt b/compiler/src/prog8/compiler/target/cpu6502/codegen/assignment/AsmAssignment.kt index 38a1c0dd8..30c71bb7b 100644 --- a/compiler/src/prog8/compiler/target/cpu6502/codegen/assignment/AsmAssignment.kt +++ b/compiler/src/prog8/compiler/target/cpu6502/codegen/assignment/AsmAssignment.kt @@ -135,9 +135,9 @@ internal class AsmAssignSource(val kind: SourceStorageKind, val dt = value.inferType(program).typeOrElse(DataType.UNDEFINED) val varName=asmgen.asmVariableName(value) // special case: "cx16.r[0-15]" are 16-bits virtual registers of the commander X16 system - if(dt==DataType.UWORD && varName.toLowerCase().startsWith("cx16.r")) { - val regStr = varName.toLowerCase().substring(5) - val reg = RegisterOrPair.valueOf(regStr.toUpperCase()) + if(dt == DataType.UWORD && varName.lowercase().startsWith("cx16.r")) { + val regStr = varName.lowercase().substring(5) + val reg = RegisterOrPair.valueOf(regStr.uppercase()) AsmAssignSource(SourceStorageKind.REGISTER, program, asmgen, dt, register = reg) } else { AsmAssignSource(SourceStorageKind.VARIABLE, program, asmgen, dt, variableAsmName = varName) diff --git a/compiler/src/prog8/compiler/target/cpu6502/codegen/assignment/AssignmentAsmGen.kt b/compiler/src/prog8/compiler/target/cpu6502/codegen/assignment/AssignmentAsmGen.kt index 2375dd588..37bc82b7c 100644 --- a/compiler/src/prog8/compiler/target/cpu6502/codegen/assignment/AssignmentAsmGen.kt +++ b/compiler/src/prog8/compiler/target/cpu6502/codegen/assignment/AssignmentAsmGen.kt @@ -587,13 +587,19 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen DataType.UBYTE -> { when(targetDt) { DataType.UBYTE, DataType.BYTE -> { - asmgen.out(" st${regs.toString().toLowerCase()} $targetAsmVarName") + asmgen.out(" st${regs.toString().lowercase()} $targetAsmVarName") } DataType.UWORD, DataType.WORD -> { if(asmgen.isTargetCpu(CpuType.CPU65c02)) - asmgen.out(" st${regs.toString().toLowerCase()} $targetAsmVarName | stz $targetAsmVarName+1") + asmgen.out( + " st${ + regs.toString().lowercase() + } $targetAsmVarName | stz $targetAsmVarName+1") else - asmgen.out(" st${regs.toString().toLowerCase()} $targetAsmVarName | lda #0 | sta $targetAsmVarName+1") + asmgen.out( + " st${ + regs.toString().lowercase() + } $targetAsmVarName | lda #0 | sta $targetAsmVarName+1") } DataType.FLOAT -> { when(regs) { @@ -615,13 +621,19 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen DataType.BYTE -> { when(targetDt) { DataType.UBYTE, DataType.BYTE -> { - asmgen.out(" st${regs.toString().toLowerCase()} $targetAsmVarName") + asmgen.out(" st${regs.toString().lowercase()} $targetAsmVarName") } DataType.UWORD -> { if(asmgen.isTargetCpu(CpuType.CPU65c02)) - asmgen.out(" st${regs.toString().toLowerCase()} $targetAsmVarName | stz $targetAsmVarName+1") + asmgen.out( + " st${ + regs.toString().lowercase() + } $targetAsmVarName | stz $targetAsmVarName+1") else - asmgen.out(" st${regs.toString().toLowerCase()} $targetAsmVarName | lda #0 | sta $targetAsmVarName+1") + asmgen.out( + " st${ + regs.toString().lowercase() + } $targetAsmVarName | lda #0 | sta $targetAsmVarName+1") } DataType.WORD -> { when(regs) { @@ -653,7 +665,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen DataType.UWORD -> { when(targetDt) { DataType.BYTE, DataType.UBYTE -> { - asmgen.out(" st${regs.toString().toLowerCase().first()} $targetAsmVarName") + asmgen.out(" st${regs.toString().lowercase().first()} $targetAsmVarName") } DataType.WORD, DataType.UWORD -> { when(regs) { @@ -681,7 +693,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen DataType.WORD -> { when(targetDt) { DataType.BYTE, DataType.UBYTE -> { - asmgen.out(" st${regs.toString().toLowerCase().first()} $targetAsmVarName") + asmgen.out(" st${regs.toString().lowercase().first()} $targetAsmVarName") } DataType.WORD, DataType.UWORD -> { when(regs) { @@ -822,12 +834,13 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen RegisterOrPair.AX -> asmgen.out(" inx | txy | ldx #0 | lda P8ESTACK_LO,y") RegisterOrPair.AY -> asmgen.out(" inx | ldy #0 | lda P8ESTACK_LO,x") in Cx16VirtualRegisters -> { - asmgen.out(""" + asmgen.out( + """ inx lda P8ESTACK_LO,x - sta cx16.${target.register.toString().toLowerCase()} + sta cx16.${target.register.toString().lowercase()} lda #0 - sta cx16.${target.register.toString().toLowerCase()}+1 + sta cx16.${target.register.toString().lowercase()}+1 """) } else -> throw AssemblyError("can't assign byte from stack to register pair XY") @@ -839,12 +852,13 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen RegisterOrPair.AY-> asmgen.out(" inx | ldy P8ESTACK_HI,x | lda P8ESTACK_LO,x") RegisterOrPair.XY-> throw AssemblyError("can't load X from stack here - use intermediary var? ${target.origAstTarget?.position}") in Cx16VirtualRegisters -> { - asmgen.out(""" + asmgen.out( + """ inx lda P8ESTACK_LO,x - sta cx16.${target.register.toString().toLowerCase()} + sta cx16.${target.register.toString().lowercase()} lda P8ESTACK_HI,x - sta cx16.${target.register.toString().toLowerCase()}+1 + sta cx16.${target.register.toString().lowercase()}+1 """) } else -> throw AssemblyError("can't assign word to single byte register") @@ -888,11 +902,12 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen RegisterOrPair.AY -> asmgen.out(" ldy #>$sourceName | lda #<$sourceName") RegisterOrPair.XY -> asmgen.out(" ldy #>$sourceName | ldx #<$sourceName") in Cx16VirtualRegisters -> { - asmgen.out(""" + asmgen.out( + """ lda #<$sourceName - sta cx16.${target.register.toString().toLowerCase()} + sta cx16.${target.register.toString().lowercase()} lda #>$sourceName - sta cx16.${target.register.toString().toLowerCase()}+1 + sta cx16.${target.register.toString().lowercase()}+1 """) } else -> throw AssemblyError("can't load address in a single 8-bit register") @@ -1029,11 +1044,12 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen RegisterOrPair.AY -> asmgen.out(" ldy $sourceName+1 | lda $sourceName") RegisterOrPair.XY -> asmgen.out(" ldy $sourceName+1 | ldx $sourceName") in Cx16VirtualRegisters -> { - asmgen.out(""" + asmgen.out( + """ lda $sourceName - sta cx16.${target.register.toString().toLowerCase()} + sta cx16.${target.register.toString().lowercase()} lda $sourceName+1 - sta cx16.${target.register.toString().toLowerCase()}+1 + sta cx16.${target.register.toString().lowercase()}+1 """) } else -> throw AssemblyError("can't load word in a single 8-bit register") @@ -1203,11 +1219,12 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen RegisterOrPair.XY -> asmgen.out(" ldy #0 | ldx $sourceName") RegisterOrPair.FAC1, RegisterOrPair.FAC2 -> throw AssemblyError("expected typecasted byte to float") in Cx16VirtualRegisters -> { - asmgen.out(""" + asmgen.out( + """ lda $sourceName - sta cx16.${target.register.toString().toLowerCase()} + sta cx16.${target.register.toString().lowercase()} lda #0 - sta cx16.${target.register.toString().toLowerCase()}+1 + sta cx16.${target.register.toString().lowercase()}+1 """) } else -> throw AssemblyError("weird register") @@ -1355,7 +1372,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen when(target.kind) { TargetStorageKind.VARIABLE -> { - asmgen.out(" st${register.name.toLowerCase()} ${target.asmVarname}") + asmgen.out(" st${register.name.lowercase()} ${target.asmVarname}") } TargetStorageKind.MEMORY -> { when(register) { @@ -1395,7 +1412,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen RegisterOrPair.FAC1, RegisterOrPair.FAC2 -> throw AssemblyError("expected type cast to float") in Cx16VirtualRegisters -> { // only assign a single byte to the virtual register's Lsb - asmgen.out(" sta cx16.${target.register.toString().toLowerCase()}") + asmgen.out(" sta cx16.${target.register.toString().lowercase()}") } else -> throw AssemblyError("weird register") } @@ -1409,7 +1426,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen RegisterOrPair.FAC1, RegisterOrPair.FAC2 -> throw AssemblyError("expected type cast to float") in Cx16VirtualRegisters -> { // only assign a single byte to the virtual register's Lsb - asmgen.out(" stx cx16.${target.register.toString().toLowerCase()}") + asmgen.out(" stx cx16.${target.register.toString().lowercase()}") } else -> throw AssemblyError("weird register") } @@ -1423,7 +1440,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen RegisterOrPair.FAC1, RegisterOrPair.FAC2 -> throw AssemblyError("expected type cast to float") in Cx16VirtualRegisters -> { // only assign a single byte to the virtual register's Lsb - asmgen.out(" sty cx16.${target.register.toString().toLowerCase()}") + asmgen.out(" sty cx16.${target.register.toString().lowercase()}") } else -> throw AssemblyError("weird register") } @@ -1513,9 +1530,10 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen RegisterOrPair.AX -> { } RegisterOrPair.XY -> { asmgen.out(" stx P8ZP_SCRATCH_REG | ldy P8ZP_SCRATCH_REG | tax") } in Cx16VirtualRegisters -> { - asmgen.out(""" - sta cx16.${target.register.toString().toLowerCase()} - stx cx16.${target.register.toString().toLowerCase()}+1 + asmgen.out( + """ + sta cx16.${target.register.toString().lowercase()} + stx cx16.${target.register.toString().lowercase()}+1 """) } else -> throw AssemblyError("expected reg pair or cx16 virtual 16-bit register") @@ -1525,9 +1543,10 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen RegisterOrPair.AX -> { asmgen.out(" sty P8ZP_SCRATCH_REG | ldx P8ZP_SCRATCH_REG") } RegisterOrPair.XY -> { asmgen.out(" tax") } in Cx16VirtualRegisters -> { - asmgen.out(""" - sta cx16.${target.register.toString().toLowerCase()} - sty cx16.${target.register.toString().toLowerCase()}+1 + asmgen.out( + """ + sta cx16.${target.register.toString().lowercase()} + sty cx16.${target.register.toString().lowercase()}+1 """) } else -> throw AssemblyError("expected reg pair or cx16 virtual 16-bit register") @@ -1537,9 +1556,10 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen RegisterOrPair.AX -> { asmgen.out(" txa | sty P8ZP_SCRATCH_REG | ldx P8ZP_SCRATCH_REG") } RegisterOrPair.XY -> { } in Cx16VirtualRegisters -> { - asmgen.out(""" - stx cx16.${target.register.toString().toLowerCase()} - sty cx16.${target.register.toString().toLowerCase()}+1 + asmgen.out( + """ + stx cx16.${target.register.toString().lowercase()} + sty cx16.${target.register.toString().lowercase()}+1 """) } else -> throw AssemblyError("expected reg pair or cx16 virtual 16-bit register") @@ -1606,7 +1626,10 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen RegisterOrPair.AY -> asmgen.out(" lda #0 | tay") RegisterOrPair.XY -> asmgen.out(" ldx #0 | ldy #0") in Cx16VirtualRegisters -> { - asmgen.out(" stz cx16.${target.register.toString().toLowerCase()} | stz cx16.${target.register.toString().toLowerCase()}+1") + asmgen.out( + " stz cx16.${ + target.register.toString().lowercase() + } | stz cx16.${target.register.toString().lowercase()}+1") } else -> throw AssemblyError("invalid register for word value") } @@ -1656,11 +1679,12 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen RegisterOrPair.AY -> asmgen.out(" ldy #>${word.toHex()} | lda #<${word.toHex()}") RegisterOrPair.XY -> asmgen.out(" ldy #>${word.toHex()} | ldx #<${word.toHex()}") in Cx16VirtualRegisters -> { - asmgen.out(""" + asmgen.out( + """ lda #<${word.toHex()} - sta cx16.${target.register.toString().toLowerCase()} + sta cx16.${target.register.toString().lowercase()} lda #>${word.toHex()} - sta cx16.${target.register.toString().toLowerCase()}+1 + sta cx16.${target.register.toString().lowercase()}+1 """) } else -> throw AssemblyError("invalid register for word value") @@ -1707,7 +1731,10 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen RegisterOrPair.XY -> asmgen.out(" ldx #0 | ldy #0") RegisterOrPair.FAC1, RegisterOrPair.FAC2 -> throw AssemblyError("expected typecasted byte to float") in Cx16VirtualRegisters -> { - asmgen.out(" stz cx16.${target.register.toString().toLowerCase()} | stz cx16.${target.register.toString().toLowerCase()}+1") + asmgen.out( + " stz cx16.${ + target.register.toString().lowercase() + } | stz cx16.${target.register.toString().lowercase()}+1") } else -> throw AssemblyError("weird register") } @@ -1747,11 +1774,17 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen RegisterOrPair.XY -> asmgen.out(" ldy #0 | ldx #${byte.toHex()}") RegisterOrPair.FAC1, RegisterOrPair.FAC2 -> throw AssemblyError("expected typecasted byte to float") in Cx16VirtualRegisters -> { - asmgen.out(" lda #${byte.toHex()} | sta cx16.${target.register.toString().toLowerCase()}") + asmgen.out( + " lda #${byte.toHex()} | sta cx16.${ + target.register.toString().lowercase() + }") if(asmgen.isTargetCpu(CpuType.CPU65c02)) - asmgen.out(" stz cx16.${target.register.toString().toLowerCase()}+1\n") + asmgen.out(" stz cx16.${target.register.toString().lowercase()}+1\n") else - asmgen.out(" lda #0 | sta cx16.${target.register.toString().toLowerCase()}+1\n") + asmgen.out( + " lda #0 | sta cx16.${ + target.register.toString().lowercase() + }+1\n") } else -> throw AssemblyError("weird register") } @@ -1927,11 +1960,12 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen RegisterOrPair.XY -> asmgen.out(" ldy #0 | ldy ${address.toHex()}") RegisterOrPair.FAC1, RegisterOrPair.FAC2 -> throw AssemblyError("expected typecasted byte to float") in Cx16VirtualRegisters -> { - asmgen.out(""" + asmgen.out( + """ lda ${address.toHex()} - sta cx16.${target.register.toString().toLowerCase()} + sta cx16.${target.register.toString().lowercase()} lda #0 - sta cx16.${target.register.toString().toLowerCase()}+1 + sta cx16.${target.register.toString().lowercase()}+1 """) } else -> throw AssemblyError("weird register") @@ -1967,10 +2001,11 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen RegisterOrPair.XY -> asmgen.out(" tax | ldy #0") RegisterOrPair.FAC1, RegisterOrPair.FAC2 -> throw AssemblyError("expected typecasted byte to float") in Cx16VirtualRegisters -> { - asmgen.out(""" - sta cx16.${target.register.toString().toLowerCase()} + asmgen.out( + """ + sta cx16.${target.register.toString().lowercase()} lda #0 - sta cx16.${target.register.toString().toLowerCase()}+1 + sta cx16.${target.register.toString().lowercase()}+1 """) } else -> throw AssemblyError("weird register") diff --git a/compiler/src/prog8/optimizer/CallGraph.kt b/compiler/src/prog8/optimizer/CallGraph.kt index 58b71c242..31b639168 100644 --- a/compiler/src/prog8/optimizer/CallGraph.kt +++ b/compiler/src/prog8/optimizer/CallGraph.kt @@ -3,7 +3,6 @@ package prog8.optimizer import prog8.ast.Module import prog8.ast.Node import prog8.ast.Program -import prog8.ast.base.DataType import prog8.ast.base.Position import prog8.ast.base.VarDeclType import prog8.ast.expressions.AddressOf diff --git a/compiler/src/prog8/optimizer/StatementOptimizer.kt b/compiler/src/prog8/optimizer/StatementOptimizer.kt index fb26690c4..50703d8dc 100644 --- a/compiler/src/prog8/optimizer/StatementOptimizer.kt +++ b/compiler/src/prog8/optimizer/StatementOptimizer.kt @@ -43,48 +43,6 @@ internal class StatementOptimizer(private val program: Program, } } - // printing a literal string of just 2 or 1 characters is replaced by directly outputting those characters - if(functionCallStatement.target.nameInSource==listOf("txt", "print")) { - val arg = functionCallStatement.args.single() - val stringVar: IdentifierReference? = if(arg is AddressOf) { - arg.identifier - } else { - arg as? IdentifierReference - } - if(stringVar!=null) { - val vardecl = stringVar.targetVarDecl(program)!! - val string = vardecl.value as? StringLiteralValue - if(string!=null) { - val pos = functionCallStatement.position - if (string.value.length == 1) { - val firstCharEncoded = compTarget.encodeString(string.value, string.altEncoding)[0] - val chrout = FunctionCallStatement( - IdentifierReference(listOf("txt", "chrout"), pos), - mutableListOf(NumericLiteralValue(DataType.UBYTE, firstCharEncoded.toInt(), pos)), - functionCallStatement.void, pos - ) - return listOf(IAstModification.ReplaceNode(functionCallStatement, chrout, parent)) - } else if (string.value.length == 2) { - val firstTwoCharsEncoded = compTarget.encodeString(string.value.take(2), string.altEncoding) - val chrout1 = FunctionCallStatement( - IdentifierReference(listOf("txt", "chrout"), pos), - mutableListOf(NumericLiteralValue(DataType.UBYTE, firstTwoCharsEncoded[0].toInt(), pos)), - functionCallStatement.void, pos - ) - val chrout2 = FunctionCallStatement( - IdentifierReference(listOf("txt", "chrout"), pos), - mutableListOf(NumericLiteralValue(DataType.UBYTE, firstTwoCharsEncoded[1].toInt(), pos)), - functionCallStatement.void, pos - ) - return listOf( - IAstModification.InsertBefore(functionCallStatement, chrout1, parent as INameScope), - IAstModification.ReplaceNode(functionCallStatement, chrout2, parent) - ) - } - } - } - } - // if the first instruction in the called subroutine is a return statement, remove the jump altogeter val subroutine = functionCallStatement.target.targetSubroutine(program) if(subroutine!=null) { diff --git a/compilerAst/build.gradle b/compilerAst/build.gradle index 821f91637..d8d78ba13 100644 --- a/compilerAst/build.gradle +++ b/compilerAst/build.gradle @@ -1,7 +1,7 @@ plugins { id 'antlr' id 'java' - id "org.jetbrains.kotlin.jvm" version "1.4.32" + id "org.jetbrains.kotlin.jvm" version "1.5.0" } targetCompatibility = 11 diff --git a/compilerAst/src/prog8/ast/AstToSourceCode.kt b/compilerAst/src/prog8/ast/AstToSourceCode.kt index 640c78ab2..56dfa52d9 100644 --- a/compilerAst/src/prog8/ast/AstToSourceCode.kt +++ b/compilerAst/src/prog8/ast/AstToSourceCode.kt @@ -7,6 +7,7 @@ import prog8.ast.base.VarDeclType import prog8.ast.expressions.* import prog8.ast.statements.* import prog8.ast.walk.IAstVisitor +import java.util.* class AstToSourceCode(val output: (text: String) -> Unit, val program: Program): IAstVisitor { @@ -78,9 +79,9 @@ class AstToSourceCode(val output: (text: String) -> Unit, val program: Program): } private fun datatypeString(dt: DataType): String { - return when(dt) { - in NumericDatatypes -> dt.toString().toLowerCase() - DataType.STR -> dt.toString().toLowerCase() + return when (dt) { + in NumericDatatypes -> dt.toString().lowercase() + DataType.STR -> dt.toString().lowercase() DataType.ARRAY_UB -> "ubyte[" DataType.ARRAY_B -> "byte[" DataType.ARRAY_UW -> "uword[" @@ -235,7 +236,7 @@ class AstToSourceCode(val output: (text: String) -> Unit, val program: Program): } override fun visit(branchStatement: BranchStatement) { - output("if_${branchStatement.condition.toString().toLowerCase()} ") + output("if_${branchStatement.condition.toString().lowercase()} ") branchStatement.truepart.accept(this) if(branchStatement.elsepart.statements.isNotEmpty()) { output(" else ") diff --git a/compilerAst/src/prog8/ast/antlr/Antr2Kotlin.kt b/compilerAst/src/prog8/ast/antlr/Antr2Kotlin.kt index b721a78c1..30c64e6a3 100644 --- a/compilerAst/src/prog8/ast/antlr/Antr2Kotlin.kt +++ b/compilerAst/src/prog8/ast/antlr/Antr2Kotlin.kt @@ -13,6 +13,7 @@ import prog8.parser.prog8Parser import java.io.CharConversionException import java.io.File import java.nio.file.Path +import java.util.* /***************** Antlr Extension methods to create AST ****************/ @@ -340,7 +341,7 @@ private fun prog8Parser.ClobberContext.toAst() : Set { return names.map { CpuRegister.valueOf(it) }.toSet() } -private fun prog8Parser.DatatypeContext.toAst() = DataType.valueOf(text.toUpperCase()) +private fun prog8Parser.DatatypeContext.toAst() = DataType.valueOf(text.uppercase()) private fun prog8Parser.ArrayindexContext.toAst(encoding: IStringEncoding) : ArrayIndex = ArrayIndex(expression().toAst(encoding), toPosition()) @@ -536,7 +537,9 @@ private fun prog8Parser.Branch_stmtContext.toAst(encoding: IStringEncoding): Bra return BranchStatement(branchcondition, trueScope, elseScope, toPosition()) } -private fun prog8Parser.BranchconditionContext.toAst() = BranchCondition.valueOf(text.substringAfter('_').toUpperCase()) +private fun prog8Parser.BranchconditionContext.toAst() = BranchCondition.valueOf( + text.substringAfter('_').uppercase() +) private fun prog8Parser.ForloopContext.toAst(encoding: IStringEncoding): ForLoop { val loopvar = identifier().toAst() diff --git a/dbusCompilerService/build.gradle b/dbusCompilerService/build.gradle index 3719a1f50..272a2f058 100644 --- a/dbusCompilerService/build.gradle +++ b/dbusCompilerService/build.gradle @@ -2,7 +2,7 @@ plugins { id 'java' id 'application' - id "org.jetbrains.kotlin.jvm" version "1.4.32" + id "org.jetbrains.kotlin.jvm" version "1.5.0" id 'com.github.johnrengelman.shadow' version '6.1.0' } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index d383dbc04..54c6e1906 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -2,6 +2,8 @@ TODO ==== +- mark vardecls 'shared' to indicate they should not be optimized away because they're shared with assembly code?? +- github issue: make strings no longer immutable? fixes weird optimization issue. Deduplication via command line switch? - test all examples before release of the new version - simplify cx16.joystick_get2() once this cx16 rom issue is resolved: https://github.com/commanderx16/x16-rom/issues/203 diff --git a/examples/test.p8 b/examples/test.p8 index cde5dbacc..88b74163b 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,37 +1,15 @@ %import textio -%import diskio %zeropage basicsafe +%option no_sysinit main { + sub start() { + str message = "a" - sub start() { - - txt.print(diskio.status(8)) - txt.nl() - txt.print(diskio.status(9)) - txt.nl() -; txt.print(diskio.status(10)) -; txt.nl() -; txt.print(diskio.status(11)) -; txt.nl() - - uword x=22 - x*=320 - txt.print_uw(x) - txt.nl() - - x=22 - x*=640 - txt.print_uw(x) - txt.nl() - - ubyte a=1 - ubyte b=22 - - x = (a*b)*640*a - txt.print_uw(x) - txt.nl() - - - } + txt.print(message) + txt.nl() + message[0] = '@' + txt.print(message) + txt.nl() + } } diff --git a/httpCompilerService/build.gradle b/httpCompilerService/build.gradle index e67ecebe0..8c13dc2d5 100644 --- a/httpCompilerService/build.gradle +++ b/httpCompilerService/build.gradle @@ -2,7 +2,7 @@ plugins { id 'java' id 'application' - id "org.jetbrains.kotlin.jvm" version "1.4.32" + id "org.jetbrains.kotlin.jvm" version "1.5.0" id 'com.github.johnrengelman.shadow' version '6.1.0' }