optimization in + or - assignment to word array

This commit is contained in:
Irmen de Jong 2023-08-05 21:20:30 +02:00
parent c36afd872e
commit 77fa2e2722
4 changed files with 167 additions and 37 deletions

View File

@ -996,6 +996,8 @@ internal class AssignmentAsmGen(private val program: PtProgram,
private fun assignOptimizedComparisonBytes(expr: PtBinaryExpression, assign: AsmAssignment): Boolean { private fun assignOptimizedComparisonBytes(expr: PtBinaryExpression, assign: AsmAssignment): Boolean {
val signed = expr.left.type == DataType.BYTE || expr.right.type == DataType.BYTE val signed = expr.left.type == DataType.BYTE || expr.right.type == DataType.BYTE
// TODO no need to use a temporary variable if the right expression is a literal number or a variable name (or register name)
when(expr.operator) { when(expr.operator) {
"==" -> { "==" -> {
asmgen.assignByteOperandsToAAndVar(expr.right, expr.left, "P8ZP_SCRATCH_B1") asmgen.assignByteOperandsToAAndVar(expr.right, expr.left, "P8ZP_SCRATCH_B1")

View File

@ -320,44 +320,69 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
&& tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator)) && tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator))
return return
asmgen.loadScaledArrayIndexIntoRegister(target.array, DataType.UWORD, CpuRegister.Y) asmgen.loadScaledArrayIndexIntoRegister(target.array, DataType.UWORD, CpuRegister.Y)
if(target.array.splitWords) {
asmgen.out(" lda ${target.array.variable.name}_lsb,y | sta P8ZP_SCRATCH_W1")
asmgen.out(" lda ${target.array.variable.name}_msb,y | sta P8ZP_SCRATCH_W1+1")
} else {
asmgen.out(" lda ${target.array.variable.name},y | sta P8ZP_SCRATCH_W1")
asmgen.out(" lda ${target.array.variable.name}+1,y | sta P8ZP_SCRATCH_W1+1")
}
asmgen.saveRegisterStack(CpuRegister.Y, false) asmgen.saveRegisterStack(CpuRegister.Y, false)
if(target.array.splitWords) {
asmgen.out(" lda ${target.array.variable.name}_lsb,y")
asmgen.out(" ldx ${target.array.variable.name}_msb,y")
} else {
asmgen.out(" lda ${target.array.variable.name},y")
asmgen.out(" ldx ${target.array.variable.name}+1,y")
}
when(value.kind) { when(value.kind) {
SourceStorageKind.LITERALNUMBER -> { SourceStorageKind.LITERALNUMBER -> {
// TODO optimize the stuff below to not use temp variables?? val number = value.number!!.number.toInt()
inplacemodificationWordWithLiteralval("P8ZP_SCRATCH_W1", target.datatype, operator, value.number!!.number.toInt()) if(!inplacemodificationRegisterAXwithLiteralval(operator, number)) {
asmgen.out(" sta P8ZP_SCRATCH_W1 | stx P8ZP_SCRATCH_W1+1")
inplacemodificationWordWithLiteralval("P8ZP_SCRATCH_W1", target.datatype, operator, number)
asmgen.out(" lda P8ZP_SCRATCH_W1 | ldx P8ZP_SCRATCH_W1+1")
}
} }
SourceStorageKind.VARIABLE -> { SourceStorageKind.VARIABLE -> {
// TODO optimize the stuff below to not use temp variables?? if(!inplacemodificationRegisterAXwithVariable(
operator,
value.asmVarname,
value.datatype
)) {
asmgen.out(" sta P8ZP_SCRATCH_W1 | stx P8ZP_SCRATCH_W1+1")
inplacemodificationWordWithVariable("P8ZP_SCRATCH_W1", target.datatype, operator, value.asmVarname, value.datatype) inplacemodificationWordWithVariable("P8ZP_SCRATCH_W1", target.datatype, operator, value.asmVarname, value.datatype)
asmgen.out(" lda P8ZP_SCRATCH_W1 | ldx P8ZP_SCRATCH_W1+1")
}
} }
SourceStorageKind.REGISTER -> { SourceStorageKind.REGISTER -> {
// TODO optimize the stuff below to not use temp variables?? if(!inplacemodificationRegisterAXwithVariable(
operator,
regName(value),
value.datatype
)) {
asmgen.out(" sta P8ZP_SCRATCH_W1 | stx P8ZP_SCRATCH_W1+1")
inplacemodificationWordWithVariable("P8ZP_SCRATCH_W1", target.datatype, operator, regName(value), value.datatype) inplacemodificationWordWithVariable("P8ZP_SCRATCH_W1", target.datatype, operator, regName(value), value.datatype)
asmgen.out(" lda P8ZP_SCRATCH_W1 | ldx P8ZP_SCRATCH_W1+1")
}
}
SourceStorageKind.MEMORY -> {
asmgen.out(" sta P8ZP_SCRATCH_W1 | stx P8ZP_SCRATCH_W1+1")
inplacemodificationWordWithMemread("P8ZP_SCRATCH_W1", target.datatype, operator, value.memory!!)
asmgen.out(" lda P8ZP_SCRATCH_W1 | ldx P8ZP_SCRATCH_W1+1")
}
SourceStorageKind.ARRAY -> {
asmgen.out(" sta P8ZP_SCRATCH_W1 | stx P8ZP_SCRATCH_W1+1")
inplacemodificationWordWithValue("P8ZP_SCRATCH_W1", target.datatype, operator, value.array!!)
asmgen.out(" lda P8ZP_SCRATCH_W1 | ldx P8ZP_SCRATCH_W1+1")
} }
SourceStorageKind.MEMORY -> inplacemodificationWordWithMemread("P8ZP_SCRATCH_W1", target.datatype, operator, value.memory!!)
SourceStorageKind.ARRAY -> inplacemodificationWordWithValue("P8ZP_SCRATCH_W1", target.datatype, operator, value.array!!)
SourceStorageKind.EXPRESSION -> { SourceStorageKind.EXPRESSION -> {
asmgen.out(" sta P8ZP_SCRATCH_W1 | stx P8ZP_SCRATCH_W1+1")
if(value.expression is PtTypeCast) if(value.expression is PtTypeCast)
inplacemodificationWordWithValue("P8ZP_SCRATCH_W1", target.datatype, operator, value.expression) inplacemodificationWordWithValue("P8ZP_SCRATCH_W1", target.datatype, operator, value.expression)
else else
inplacemodificationWordWithValue("P8ZP_SCRATCH_W1", target.datatype, operator, value.expression!!) inplacemodificationWordWithValue("P8ZP_SCRATCH_W1", target.datatype, operator, value.expression!!)
asmgen.out(" lda P8ZP_SCRATCH_W1 | ldx P8ZP_SCRATCH_W1+1")
} }
} }
asmgen.restoreRegisterStack(CpuRegister.Y, false) asmgen.restoreRegisterStack(CpuRegister.Y, true)
if(target.array.splitWords) { if(target.array.splitWords)
asmgen.out(" lda P8ZP_SCRATCH_W1 | sta ${target.array.variable.name}_lsb,y") asmgen.out(" sta ${target.array.variable.name}_lsb,y | txa | sta ${target.array.variable.name}_msb,y")
asmgen.out(" lda P8ZP_SCRATCH_W1+1 | sta ${target.array.variable.name}_msb,y") else
} else { asmgen.out(" sta ${target.array.variable.name},y | txa | sta ${target.array.variable.name}+1,y")
asmgen.out(" lda P8ZP_SCRATCH_W1 | sta ${target.array.variable.name},y")
asmgen.out(" lda P8ZP_SCRATCH_W1+1 | sta ${target.array.variable.name}+1,y")
}
} }
DataType.FLOAT -> { DataType.FLOAT -> {
asmgen.loadScaledArrayIndexIntoRegister(target.array, DataType.FLOAT, CpuRegister.A) asmgen.loadScaledArrayIndexIntoRegister(target.array, DataType.FLOAT, CpuRegister.A)
@ -412,6 +437,110 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
} }
} }
private fun inplacemodificationRegisterAXwithVariable(operator: String, variable: String, varDt: DataType): Boolean {
// note: we only optimize addition and subtraction, and these are the same for unsigned or signed.
when(operator) {
"+" -> {
return if(varDt in WordDatatypes) {
asmgen.out("""
clc
adc $variable
pha
txa
adc $variable+1
tax
pla""")
true
} else {
asmgen.out("""
ldy $variable
bpl +
dex ; sign extend
+ clc
adc $variable
bcc +
inx
+""")
true
}
}
"-" -> {
return if(varDt in WordDatatypes) {
asmgen.out("""
sec
sbc $variable
pha
txa
sbc $variable+1
tax
pla""")
true
} else {
asmgen.out("""
ldy $variable
bpl +
inx ; sign extend
+ sec
sbc $variable
bcs +
dex
+""")
true
}
}
else -> return false // TODO optimize more operators, such as the bitwise logical ones? Might need to know if signed
}
}
private fun inplacemodificationRegisterAXwithLiteralval(operator: String, number: Int): Boolean {
// note: we only optimize addition and subtraction, and these are the same for unsigned or signed.
when(operator) {
"+" -> {
return if(number in -128..255) {
asmgen.out("""
clc
adc #$number
bcc +
inx
+""")
true
} else {
asmgen.out("""
clc
adc #<$number
pha
txa
adc #>$number
tax
pla""")
true
}
}
"-" -> {
return if(number in -128..255) {
asmgen.out("""
sec
sbc #$number
bcs +
dex
+""")
true
} else {
asmgen.out("""
sec
sbc #<$number
pha
txa
sbc #>$number
tax
pla""")
true
}
}
else -> return false // TODO optimize more operators, such as the bitwise logical ones? Might need to know if signed
}
}
private fun tryInplaceModifyWithRemovedRedundantCast(value: PtTypeCast, target: AsmAssignTarget, operator: String): Boolean { private fun tryInplaceModifyWithRemovedRedundantCast(value: PtTypeCast, target: AsmAssignTarget, operator: String): Boolean {
if (target.datatype == value.type) { if (target.datatype == value.type) {
val childDt = value.value.type val childDt = value.value.type
@ -579,7 +708,6 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
} }
private fun inplacemodificationByteVariableWithValue(name: String, dt: DataType, operator: String, value: PtExpression) { private fun inplacemodificationByteVariableWithValue(name: String, dt: DataType, operator: String, value: PtExpression) {
// TODO optimize the stuff below to not use temp variables??
val tmpVar = if(name!="P8ZP_SCRATCH_B1") "P8ZP_SCRATCH_B1" else "P8ZP_SCRATCH_REG" val tmpVar = if(name!="P8ZP_SCRATCH_B1") "P8ZP_SCRATCH_B1" else "P8ZP_SCRATCH_REG"
asmgen.assignExpressionToVariable(value, tmpVar, value.type) asmgen.assignExpressionToVariable(value, tmpVar, value.type)
asmgen.out(" lda $name") asmgen.out(" lda $name")
@ -1932,21 +2060,21 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
sta $name+1""") sta $name+1""")
} }
"*" -> { "*" -> {
// stack contains (u) byte value, sign extend that and proceed with regular 16 bit operation // value is (u) byte value, sign extend that and proceed with regular 16 bit operation
// TODO use an optimized word * byte multiplication routine? // TODO use an optimized word * byte multiplication routine?
asmgen.assignExpressionToRegister(value, RegisterOrPair.A) asmgen.assignExpressionToRegister(value, RegisterOrPair.A)
asmgen.signExtendAYlsb(valueDt) asmgen.signExtendAYlsb(valueDt)
multiplyVarByWordInAY() multiplyVarByWordInAY()
} }
"/" -> { "/" -> {
// stack contains (u) byte value, sign extend that and proceed with regular 16 bit operation // value is (u) byte value, sign extend that and proceed with regular 16 bit operation
// TODO use an optimized word / byte divmod routine? // TODO use an optimized word / byte divmod routine?
asmgen.assignExpressionToRegister(value, RegisterOrPair.A) asmgen.assignExpressionToRegister(value, RegisterOrPair.A)
asmgen.signExtendAYlsb(valueDt) asmgen.signExtendAYlsb(valueDt)
divideVarByWordInAY() divideVarByWordInAY()
} }
"%" -> { "%" -> {
// stack contains (u) byte value, sign extend that and proceed with regular 16 bit operation // value is (u) byte value, sign extend that and proceed with regular 16 bit operation
// TODO use an optimized word / byte divmod routine? // TODO use an optimized word / byte divmod routine?
asmgen.assignExpressionToRegister(value, RegisterOrPair.A) asmgen.assignExpressionToRegister(value, RegisterOrPair.A)
asmgen.signExtendAYlsb(valueDt) asmgen.signExtendAYlsb(valueDt)

View File

@ -1,8 +1,8 @@
TODO TODO
==== ====
- try to reduce the number of uses of temp variables for example in array[idx] -= amount see AugmentableAssignmentAsmGen - try to reduce the number of temp variables in comparison expressions like if a>4 or a<2 .... See assignOptimizedComparisonBytes().
- investigate McCarthy evaluation again? this may also reduce code size perhaps for things like if a>4 or a<2 .... / - investigate McCarthy evaluation again? this may also reduce code size perhaps for things like if a>4 or a<2 .... - investigate McCarthy evaluation again? this may also reduce code size perhaps for things like if a>4 or a<2 ....
- IR: reduce the number of branch instructions such as BEQ, BEQR, etc (gradually), replace with CMP(I) + status branch instruction - IR: reduce the number of branch instructions such as BEQ, BEQR, etc (gradually), replace with CMP(I) + status branch instruction
- IR: reduce amount of CMP/CMPI after instructions that set the status bits correctly (LOADs? INC? etc), but only after setting the status bits is verified! - IR: reduce amount of CMP/CMPI after instructions that set the status bits correctly (LOADs? INC? etc), but only after setting the status bits is verified!

View File

@ -3,16 +3,16 @@
main { main {
sub start() { sub start() {
uword[4] array = [1,2,3,4] ubyte a = 1
ubyte index = 2
cx16.r0 = 99 if a>4 or a<2 {
array[index] += 12345 a++
array[index] += cx16.r0 }
array[index] += index
txt.print_uw(array[index]) ; prints 12449
; code size = $0249 if a>=2 and a<4 {
a++
}
txt.print_ub(a) ; 3
} }
} }