assignment source now also treats cx16.r[0-15] as registers

no longer create useless assignment code for r0=r0
This commit is contained in:
Irmen de Jong 2021-02-06 13:01:45 +01:00
parent 49ea31c0a4
commit cc96ab7a9b
6 changed files with 108 additions and 43 deletions

View File

@ -91,6 +91,13 @@ enum class RegisterOrPair {
val names by lazy { values().map { it.toString()} }
}
fun asCpuRegister(): CpuRegister = when(this) {
A -> CpuRegister.A
X -> CpuRegister.X
Y -> CpuRegister.Y
else -> throw IllegalArgumentException("no cpu hardware register for $this")
}
} // only used in parameter and return value specs in asm subroutines
enum class Statusflag {

View File

@ -506,6 +506,12 @@ internal class AsmGen(private val program: Program,
}
}
internal fun asmSymbolName(regs: RegisterOrPair): String =
if(regs in Cx16VirtualRegisters)
"cx16." + regs.toString().toLowerCase()
else
throw AssemblyError("no symbol name for register $regs")
internal fun asmVariableName(identifier: IdentifierReference): String {
return if(identifier.memberOfStruct(program.namespace)!=null) {
val name = identifier.targetVarDecl(program.namespace)!!.name
@ -1442,5 +1448,4 @@ $label nop""")
}
return false
}
}

View File

@ -104,7 +104,7 @@ internal class AsmAssignSource(val kind: SourceStorageKind,
private val variableAsmName: String? = null,
val array: ArrayIndexedExpression? = null,
val memory: DirectMemoryRead? = null,
val register: CpuRegister? = null,
val register: RegisterOrPair? = null,
val number: NumericLiteralValue? = null,
val expression: Expression? = null
)
@ -138,7 +138,15 @@ internal class AsmAssignSource(val kind: SourceStorageKind,
is ArrayLiteralValue -> throw AssemblyError("array literal value should not occur anymore for asm generation")
is IdentifierReference -> {
val dt = value.inferType(program).typeOrElse(DataType.STRUCT)
AsmAssignSource(SourceStorageKind.VARIABLE, program, asmgen, dt, variableAsmName = asmgen.asmVariableName(value))
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())
AsmAssignSource(SourceStorageKind.REGISTER, program, asmgen, dt, register = reg)
} else {
AsmAssignSource(SourceStorageKind.VARIABLE, program, asmgen, dt, variableAsmName = varName)
}
}
is DirectMemoryRead -> {
AsmAssignSource(SourceStorageKind.MEMORY, program, asmgen, DataType.UBYTE, memory = value)

View File

@ -263,7 +263,11 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
}
}
SourceStorageKind.REGISTER -> {
assignRegisterByte(assign.target, assign.source.register!!)
when(assign.source.datatype) {
DataType.UBYTE -> assignRegisterByte(assign.target, assign.source.register!!.asCpuRegister())
DataType.UWORD -> assignRegisterpairWord(assign.target, assign.source.register!!)
else -> throw AssemblyError("invalid register dt")
}
}
SourceStorageKind.STACK -> {
assignStackValue(assign.target)
@ -1434,7 +1438,15 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
RegisterOrPair.AX -> asmgen.out(" sta ${target.asmVarname} | stx ${target.asmVarname}+1")
RegisterOrPair.AY -> asmgen.out(" sta ${target.asmVarname} | sty ${target.asmVarname}+1")
RegisterOrPair.XY -> asmgen.out(" stx ${target.asmVarname} | sty ${target.asmVarname}+1")
else -> throw AssemblyError("expected reg pair")
in Cx16VirtualRegisters -> {
val srcReg = asmgen.asmSymbolName(regs)
asmgen.out("""
lda $srcReg
sta ${target.asmVarname}
lda $srcReg+1
sta ${target.asmVarname}+1""")
}
else -> throw AssemblyError("expected reg pair or cx16 virtual 16-bit register")
}
}
TargetStorageKind.ARRAY -> {
@ -1444,24 +1456,43 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
RegisterOrPair.AX -> asmgen.out(" sta ${target.asmVarname}+$idx | stx ${target.asmVarname}+$idx+1")
RegisterOrPair.AY -> asmgen.out(" sta ${target.asmVarname}+$idx | sty ${target.asmVarname}+$idx+1")
RegisterOrPair.XY -> asmgen.out(" stx ${target.asmVarname}+$idx | sty ${target.asmVarname}+$idx+1")
else -> throw AssemblyError("expected reg pair")
in Cx16VirtualRegisters -> {
val srcReg = asmgen.asmSymbolName(regs)
asmgen.out("""
lda $srcReg
sta ${target.asmVarname}+$idx
lda $srcReg+1
sta ${target.asmVarname}+$idx+1""")
}
else -> throw AssemblyError("expected reg pair or cx16 virtual 16-bit register")
}
}
else {
when(regs) {
RegisterOrPair.AX -> asmgen.out(" pha | txa | pha")
RegisterOrPair.AY -> asmgen.out(" pha | tya | pha")
RegisterOrPair.XY -> asmgen.out(" txa | pha | tya | pha")
else -> throw AssemblyError("expected reg pair")
}
asmgen.loadScaledArrayIndexIntoRegister(target.array!!, DataType.UWORD, CpuRegister.Y, true)
asmgen.out("""
pla
sta ${target.asmVarname},y
dey
pla
sta ${target.asmVarname},y""")
if (regs !in Cx16VirtualRegisters) {
when (regs) {
RegisterOrPair.AX -> asmgen.out(" pha | txa | pha")
RegisterOrPair.AY -> asmgen.out(" pha | tya | pha")
RegisterOrPair.XY -> asmgen.out(" txa | pha | tya | pha")
else -> throw AssemblyError("expected reg pair")
}
asmgen.loadScaledArrayIndexIntoRegister(target.array!!, DataType.UWORD, CpuRegister.Y, true)
asmgen.out("""
pla
sta ${target.asmVarname},y
dey
pla
sta ${target.asmVarname},y""")
} else {
val srcReg = asmgen.asmSymbolName(regs)
asmgen.loadScaledArrayIndexIntoRegister(target.array!!, DataType.UWORD, CpuRegister.Y, true)
asmgen.out("""
lda $srcReg+1
sta ${target.asmVarname},y
dey
lda $srcReg
sta ${target.asmVarname},y""")
}
}
}
TargetStorageKind.REGISTER -> {
when(regs) {
@ -1475,7 +1506,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
stx cx16.${target.register.toString().toLowerCase()}+1
""")
}
else -> throw AssemblyError("expected reg pair")
else -> throw AssemblyError("expected reg pair or cx16 virtual 16-bit register")
}
RegisterOrPair.AY -> when(target.register!!) {
RegisterOrPair.AY -> { }
@ -1487,7 +1518,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
sty cx16.${target.register.toString().toLowerCase()}+1
""")
}
else -> throw AssemblyError("expected reg pair")
else -> throw AssemblyError("expected reg pair or cx16 virtual 16-bit register")
}
RegisterOrPair.XY -> when(target.register!!) {
RegisterOrPair.AY -> { asmgen.out(" txa") }
@ -1499,16 +1530,40 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
sty cx16.${target.register.toString().toLowerCase()}+1
""")
}
else -> throw AssemblyError("expected reg pair")
else -> throw AssemblyError("expected reg pair or cx16 virtual 16-bit register")
}
else -> throw AssemblyError("expected reg pair")
in Cx16VirtualRegisters -> {
val srcReg = asmgen.asmSymbolName(regs)
if(regs!=target.register) {
when(target.register) {
RegisterOrPair.AX -> asmgen.out(" lda $srcReg | ldx $srcReg+1")
RegisterOrPair.AY -> asmgen.out(" lda $srcReg | ldy $srcReg+1")
RegisterOrPair.XY -> asmgen.out(" ldx $srcReg | ldy $srcReg+1")
in Cx16VirtualRegisters -> {
val targetReg = asmgen.asmSymbolName(target.register!!)
asmgen.out(" lda $srcReg | sta $targetReg | lda $srcReg+1 | sta $targetReg+1")
}
else -> throw AssemblyError("invalid reg")
}
}
}
else -> throw AssemblyError("expected reg pair or cx16 virtual 16-bit register")
}
}
TargetStorageKind.STACK -> {
when(regs) {
RegisterOrPair.AY -> asmgen.out(" sta P8ESTACK_LO,x | sty P8ESTACK_HI,x | dex")
RegisterOrPair.AY -> asmgen.out(" sta P8ESTACK_LO,x | sty P8ESTACK_HI,x | dex")
RegisterOrPair.AX, RegisterOrPair.XY -> throw AssemblyError("can't use X here")
else -> throw AssemblyError("expected reg pair")
in Cx16VirtualRegisters -> {
val srcReg = asmgen.asmSymbolName(regs)
asmgen.out("""
lda $srcReg
sta P8ESTACK_LO,x
lda $srcReg+1
sta P8ESTACK_HI,x
dex""")
}
else -> throw AssemblyError("expected reg pair or cx16 virtual 16-bit register")
}
}
TargetStorageKind.MEMORY -> throw AssemblyError("can't store word into memory byte")

View File

@ -2,6 +2,7 @@
TODO
====
- refactor the project module structure: make the static ast stuff a separate module, the optimizers another one, etc.
- optimize for loop iterations better to allow proper inx, cpx #value, bne loop instructions (like repeat loop)
- implement the linked_list millfork benchmark
- optimize swap of two memread values with index, using the same pointer expression/variable, like swap(@(ptr+1), @(ptr+2))

View File

@ -5,27 +5,16 @@
main {
sub start() {
uword screencolorRGB
uword drawcolorRGB
ubyte ll
ubyte hh
ubyte lower2_x_bits=1
ubyte cbits4
ubyte operand
cx16.vpoke(1, mkword(hh, ll), lsb(screencolorRGB))
cbits4 &= operand
cbits4 |= operand
cx16.vpoke(lsb(cx16.r1), cx16.r0, cbits4) ; TODO r0 is alreay in r0, avoid bogus assignment here
cbits4 &= gfx2.plot.mask4c[lower2_x_bits] ; TODO why lda..and instead of and mask,y?
cbits4 |= colorbits[lower2_x_bits] ; TODO why lda..ora instead of ora mask,y?
;cbits4 &= gfx2.plot.mask4c[lower2_x_bits] ; TODO why lda..and instead of and mask,y?
;cbits4 |= colorbits[lower2_x_bits] ; TODO why lda..ora instead of ora mask,y?
; ubyte value
; ubyte bb1
;
; value = cx16.vpeek(lsb(cx16.r0), mkword(value, bb1))
; value = cx16.vpeek(lsb(cx16.r0), mkword(value, bb1))
;
; ubyte lx = lsb(cx16.r0)
; value = cx16.vpeek(lx, mkword(value, bb1))
; value = cx16.vpeek(lx, mkword(value, bb1))
}
}