mirror of
https://github.com/irmen/prog8.git
synced 2024-11-26 11:49:22 +00:00
optimization in + or - assignment to word array
This commit is contained in:
parent
c36afd872e
commit
77fa2e2722
@ -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")
|
||||||
|
@ -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)
|
||||||
|
@ -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!
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user