fix typecasted byte-to-word pointer assignment, some more asm optimizations

This commit is contained in:
Irmen de Jong
2025-09-09 05:24:04 +02:00
parent 6c3277e3e3
commit 0b9384b556
7 changed files with 151 additions and 49 deletions
@@ -831,6 +831,10 @@ class AsmGen6502Internal (
assignExpressionToRegister(zero, target.register!!)
return
}
TargetStorageKind.POINTER -> {
TODO("assign to pointer ${target.position}")
return
}
else -> { }
}
}
@@ -73,7 +73,7 @@ internal fun optimizeAssembly(lines: MutableList<String>, machine: ICompilationT
numberOfOptimizations++
}
mods = optimizeAddWordToSameVariable(linesByFourteen)
mods = optimizeAddWordToSameVariableOrExtraRegisterLoadInWordStore(linesByFourteen)
if(mods.isNotEmpty()) {
apply(mods, lines)
linesByFourteen = getLinesBy(lines, 14)
@@ -453,15 +453,26 @@ private fun optimizeStoreLoadSame(
// lda X + sta X, ldy X + sty X, ldx X + stx X -> the second instruction can be eliminated
if ((first.startsWith("lda ") && second.startsWith("sta ")) ||
(first.startsWith("ldx ") && second.startsWith("stx ")) ||
(first.startsWith("ldy ") && second.startsWith("sty "))
if (first.startsWith("lda ") && second.startsWith("sta ") ||
first.startsWith("ldx ") && second.startsWith("stx ") ||
first.startsWith("ldy ") && second.startsWith("sty ")
) {
val firstLoc = first.substring(4).trimStart()
val secondLoc = second.substring(4).trimStart()
if (firstLoc == secondLoc)
mods.add(Modification(lines[2].index, true, null))
}
// all 3 registers: lda VALUE + sta SOMEWHERE + lda VALUE -> last load can be eliminated
if (first.startsWith("lda ") && second.startsWith("sta ") && third.startsWith("lda ") ||
first.startsWith("ldx ") && second.startsWith("stx ") && third.startsWith("ldx ") ||
first.startsWith("ldy ") && second.startsWith("sty ") && third.startsWith("ldy ")
) {
val firstVal = first.substring(4).trimStart()
val thirdVal = third.substring(4).trimStart()
if (firstVal == thirdVal)
mods.add(Modification(lines[3].index, true, null))
}
}
return mods
}
@@ -701,23 +712,32 @@ private fun optimizeUselessPushPopStack(linesByFour: Sequence<List<IndexedValue<
optimize('x', lines)
optimize('y', lines)
val first = lines[1].value.trimStart()
val second = lines[2].value.trimStart()
val third = lines[3].value.trimStart()
val first = lines[0].value.trimStart()
val second = lines[1].value.trimStart()
val third = lines[2].value.trimStart()
val fourth = lines[3].value.trimStart()
// phy + ldy + pla -> tya + ldy
// phx + ldx + pla -> txa + ldx
// pha + lda + pla -> nop
// pha + tya + tay + pla -> nop
// pha + txa + tax + pla -> nop
when (first) {
"phy" if second.startsWith("ldy ") && third=="pla" -> {
mods.add(Modification(lines[3].index, true, null))
mods.add(Modification(lines[1].index, false, " tya"))
mods.add(Modification(lines[2].index, true, null))
mods.add(Modification(lines[0].index, false, " tya"))
}
"phx" if second.startsWith("ldx ") && third=="pla" -> {
mods.add(Modification(lines[3].index, true, null))
mods.add(Modification(lines[1].index, false, " txa"))
mods.add(Modification(lines[2].index, true, null))
mods.add(Modification(lines[0].index, false, " txa"))
}
"pha" if second.startsWith("lda ") && third=="pla" -> {
mods.add(Modification(lines[0].index, true, null))
mods.add(Modification(lines[1].index, true, null))
mods.add(Modification(lines[2].index, true, null))
}
"pha" if ((second=="tya" && third=="tay") || (second=="txa" && third=="tax")) && fourth=="pla" -> {
mods.add(Modification(lines[0].index, true, null))
mods.add(Modification(lines[1].index, true, null))
mods.add(Modification(lines[2].index, true, null))
mods.add(Modification(lines[3].index, true, null))
@@ -729,7 +749,6 @@ private fun optimizeUselessPushPopStack(linesByFour: Sequence<List<IndexedValue<
return mods
}
private fun optimizeTSBtoRegularOr(linesByFour: Sequence<List<IndexedValue<String>>>): List<Modification> {
// Asm peephole: lda var2 / tsb var1 / lda var1 Replace this with this to save 1 cycle: lda var1 / ora var2 / sta var1
val mods = mutableListOf<Modification>()
@@ -775,9 +794,9 @@ private fun optimizeUnneededTempvarInAdd(linesByFour: Sequence<List<IndexedValue
return mods
}
private fun optimizeAddWordToSameVariable(linesByFourteen: Sequence<List<IndexedValue<String>>>): List<Modification> {
private fun optimizeAddWordToSameVariableOrExtraRegisterLoadInWordStore(linesByFourteen: Sequence<List<IndexedValue<String>>>): List<Modification> {
/*
; P8ZP_SCRATCH_PTR += AY :
; FIRST SEQUYENCE: P8ZP_SCRATCH_PTR += AY :
clc
adc P8ZP_SCRATCH_PTR
pha
@@ -796,7 +815,37 @@ private fun optimizeAddWordToSameVariable(linesByFourteen: Sequence<List<Indexed
tya
adc P8ZP_SCRATCH_PTR+1
sta P8ZP_SCRATCH_PTR+1
*/
also SECOND SEQUENCE:
ldx VALUE/ ldy VALUE
sta SOMEWHERE_WITHOUT_,x_OR_,y
txa / tya
ldy #1
sta SOMEWHERE
-->
sta SOMEWHERE_WITHOUT_,x_OR_,y
lda VALUE
ldy #1
sta SOMEWHERE
also THIRD SEQUENCE:
ldx VALUE
ldy #0
sta SOMEWHERE_WITHOUT_,x
txa
iny
sta SOMEWHERE
-->
ldy #0
sta SOMEWHERE_WITHOUT_,x
lda VALUE
iny
sta SOMEWHERE
*/
val mods = mutableListOf<Modification>()
for (lines in linesByFourteen) {
val first = lines[0].value.trimStart()
@@ -809,6 +858,7 @@ private fun optimizeAddWordToSameVariable(linesByFourteen: Sequence<List<Indexed
val eight = lines[7].value.trimStart()
val ninth = lines[8].value.trimStart()
// FIRST SEQUENCE
if(first=="clc" && second.startsWith("adc") && third=="pha" && fourth=="tya" &&
fifth.startsWith("adc") && sixth=="tay" && seventh=="pla" && eight.startsWith("sta") && ninth.startsWith("sty")) {
val var2 = second.substring(4)
@@ -825,6 +875,38 @@ private fun optimizeAddWordToSameVariable(linesByFourteen: Sequence<List<Indexed
}
}
}
// SECOND SEQUENCE
if(first.startsWith("ldx ") && second.startsWith("sta ") &&
third=="txa" && fourth.startsWith("ldy ") && fifth.startsWith("sta ")
) {
if(",x" !in second) {
val value = first.substring(4)
mods.add(Modification(lines[0].index, true, null))
mods.add(Modification(lines[2].index, false, " lda $value"))
}
}
if(first.startsWith("ldy ") && second.startsWith("sta ") &&
third=="tya" && fourth.startsWith("ldy ") && fifth.startsWith("sta ")
) {
if(",y" !in second) {
val value = first.substring(4)
mods.add(Modification(lines[0].index, true, null))
mods.add(Modification(lines[2].index, false, " lda $value"))
}
}
// THIRD SEQUENCE
if(first.startsWith("ldx ") && second.startsWith("ldy ") && third.startsWith("sta ") &&
fourth=="txa" && fifth=="iny" && sixth.startsWith("sta ")
) {
if(",x" !in third) {
val value = first.substring(4)
mods.add(Modification(lines[0].index, true, null))
mods.add(Modification(lines[3].index, false, " lda $value"))
}
}
}
return mods
}
@@ -2411,7 +2411,11 @@ $endLabel""")
assignExpressionToRegister(value, target.register!!, targetDt.isSigned)
return
}
else -> throw AssemblyError("weird target")
TargetStorageKind.POINTER -> {
pointergen.assignByteToWord(PtrTarget(target), value)
return
}
else -> throw AssemblyError("weird target at ${target.position}")
}
}
@@ -2435,7 +2439,7 @@ $endLabel""")
assignExpressionToRegister(value, RegisterOrPair.AY, true)
asmgen.out(" jsr floats.GIVAYFAY")
}
else -> throw AssemblyError("invalid dt")
else -> throw AssemblyError("invalid dt at ${target.position}")
}
if(target.register==RegisterOrPair.FAC2) {
asmgen.out(" jsr floats.MOVEF")
@@ -3257,7 +3261,7 @@ $endLabel""")
else -> throw AssemblyError("weird register")
}
}
TargetStorageKind.POINTER -> pointergen.assignByteVar(PtrTarget(target), varName)
TargetStorageKind.POINTER -> pointergen.assignByteVar(PtrTarget(target), varName, false, false)
TargetStorageKind.VOID -> { /* do nothing */ }
}
}
@@ -3347,6 +3351,7 @@ $endLabel""")
else -> throw AssemblyError("only reg pairs allowed as word target ${wordtarget.register}")
}
}
TargetStorageKind.POINTER -> pointergen.assignByteVar(PtrTarget(wordtarget), sourceName, extendToWord=true, signed=true)
else -> throw AssemblyError("target type isn't word")
}
}
@@ -3419,6 +3424,7 @@ $endLabel""")
else -> throw AssemblyError("only reg pairs allowed as word target")
}
}
TargetStorageKind.POINTER -> pointergen.assignByteVar(PtrTarget(wordtarget), sourceName, extendToWord=true, signed=false)
else -> throw AssemblyError("target type isn't word")
}
}
@@ -4293,6 +4299,7 @@ $endLabel""")
}
else -> throw AssemblyError("word regs can only be pair")
}
TargetStorageKind.POINTER -> TODO("assign membyte into word pointer target ${wordtarget.position}")
else -> throw AssemblyError("other types aren't word")
}
} else if (identifier != null) {
@@ -4326,6 +4333,7 @@ $endLabel""")
else -> throw AssemblyError("word regs can only be pair")
}
}
TargetStorageKind.POINTER -> TODO("assign membyte into word pointer ${wordtarget.position}")
else -> throw AssemblyError("other types aren't word")
}
}
@@ -4603,6 +4611,7 @@ $endLabel""")
sta ${target.asmVarname}+1""")
}
TargetStorageKind.ARRAY -> assignPrefixedExpressionToArrayElt(makePrefixedExprFromArrayExprAssign("-", assign), scope)
TargetStorageKind.POINTER -> pointergen.inplaceFloatNegate(PtrTarget(target), scope)
else -> throw AssemblyError("weird target for in-place float negation")
}
}
@@ -52,9 +52,13 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
asmgen.storeIndirectFloatVar(varName, zpPtrVar, offset)
}
internal fun assignByteVar(target: PtrTarget, varName: String) {
internal fun assignByteVar(target: PtrTarget, varName: String, extendToWord: Boolean, signed: Boolean) {
val (zpPtrVar, offset) = deref(target.pointer)
asmgen.storeIndirectByteVar(varName, zpPtrVar, offset)
if(extendToWord) {
TODO("assign byte var to word pointer ${target.position} signed=$signed")
} else {
asmgen.storeIndirectByteVar(varName, zpPtrVar, offset)
}
}
internal fun assignByteReg(target: PtrTarget, register: CpuRegister, signed: Boolean, extendWord: Boolean) {
@@ -64,6 +68,11 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
asmgen.storeIndirectByteReg(register, zpPtrVar, offset, signed, extendWord && target.dt.isWord)
}
internal fun assignByteToWord(target: PtrTarget, value: PtExpression) {
asmgen.assignExpressionToRegister(value, RegisterOrPair.AX, target.dt.isSigned)
assignWordReg(target, RegisterOrPair.AX)
}
internal fun assignWordReg(target: PtrTarget, regs: RegisterOrPair) {
saveOnStack(regs)
val (zpPtrVar, offset) = deref(target.pointer)
@@ -110,6 +119,10 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
TODO("inplace word negate pointer deref ${target.position}")
}
internal fun inplaceFloatNegate(target: PtrTarget, scope: IPtSubroutine?) {
TODO("inplace float negate pointer deref ${target.position}")
}
internal fun deref(pointer: PtPointerDeref, forceTemporary: Boolean=false, addOffsetToPointer: Boolean=false): Pair<String, UByte> {
// walk the pointer deref chain and leaves the final pointer value in a ZP var