strings of 1 and 2 length no longer optimized into one call to CHROUT - also upgrade to kotlin 1.5.0

This commit is contained in:
Irmen de Jong 2021-05-05 23:01:04 +02:00
parent 09a1de69e7
commit 8736da1a21
20 changed files with 222 additions and 211 deletions

View File

@ -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'
}

View File

@ -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
)
}

View File

@ -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)
}

View File

@ -153,7 +153,7 @@ fun builtinMax(array: List<Number>): Number = array.maxByOrNull { it.toDouble()
fun builtinMin(array: List<Number>): Number = array.minByOrNull { it.toDouble() }!!
fun builtinSum(array: List<Number>): Number = array.sumByDouble { it.toDouble() }
fun builtinSum(array: List<Number>): Number = array.sumOf { it.toDouble() }
fun builtinAny(array: List<Number>): Number = if(array.any { it.toDouble()!=0.0 }) 1 else 0

View File

@ -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})")
}
}
}

View File

@ -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")
}

View File

@ -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")
}

View File

@ -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
""")

View File

@ -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")
}

View File

@ -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)

View File

@ -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")

View File

@ -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

View File

@ -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) {

View File

@ -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

View File

@ -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 ")

View File

@ -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<CpuRegister> {
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()

View File

@ -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'
}

View File

@ -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

View File

@ -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()
}
}

View File

@ -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'
}