optimize RPN

This commit is contained in:
Irmen de Jong 2023-03-21 00:05:32 +01:00
parent c66734bab0
commit 2afd283582
2 changed files with 274 additions and 9 deletions

View File

@ -373,11 +373,16 @@ internal class AssignmentAsmGen(private val program: PtProgram,
return true
}
if(value.children.size==3 && left is PtExpression && right is PtExpression)
if(simpleLogicalExprRPN(left, oper.operator, right, assign.target))
if(value.children.size==3 && left is PtExpression && right is PtExpression) {
if (simpleEqualityExprRPN(left, oper.operator, right, assign.target))
return true
// TODO RPN add +,-,<<,>> and perhaps even == and != special behaviors of BinExpr
if (simpleLogicalExprRPN(left, oper.operator, right, assign.target))
return true
if (simplePlusOrMinusExprRPN(left, oper.operator, right, assign.target))
return true
if (simpleBitshiftExprRPN(left, oper.operator, right, assign.target))
return true
}
val asmExtra = asmgen.subroutineExtra(scope)
val evalVars = mutableMapOf (
@ -554,6 +559,264 @@ internal class AssignmentAsmGen(private val program: PtProgram,
return false
}
private fun simpleEqualityExprRPN(left: PtExpression, operator: String, right: PtExpression, target: AsmAssignTarget): Boolean {
if(operator!="==" && operator!="!=")
return false
// expression datatype is BOOL (ubyte) but operands can be anything
if(left.type in ByteDatatypes && right.type in ByteDatatypes &&
left.isSimple() && right.isSimple()) {
assignExpressionToRegister(left, RegisterOrPair.A, false)
asmgen.saveRegisterStack(CpuRegister.A, false)
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
asmgen.restoreRegisterStack(CpuRegister.A, false)
if(operator=="==") {
asmgen.out("""
cmp P8ZP_SCRATCH_B1
bne +
lda #1
bne ++
+ lda #0
+""")
} else {
asmgen.out("""
cmp P8ZP_SCRATCH_B1
beq +
lda #1
bne ++
+ lda #0
+""")
}
assignRegisterByte(target, CpuRegister.A)
return true
} else if(left.type in WordDatatypes && right.type in WordDatatypes &&
left.isSimple() && right.isSimple()) {
assignExpressionToRegister(left, RegisterOrPair.AY, false)
asmgen.saveRegisterStack(CpuRegister.A, false)
asmgen.saveRegisterStack(CpuRegister.Y, false)
assignExpressionToVariable(right, "P8ZP_SCRATCH_W1", DataType.UWORD)
asmgen.restoreRegisterStack(CpuRegister.Y, false)
asmgen.restoreRegisterStack(CpuRegister.A, false)
if(operator=="==") {
asmgen.out("""
cmp P8ZP_SCRATCH_W1
bne +
cpy P8ZP_SCRATCH_W1+1
bne +
lda #1
bne ++
+ lda #0
+""")
} else {
asmgen.out("""
cmp P8ZP_SCRATCH_W1
bne +
cpy P8ZP_SCRATCH_W1+1
bne +
lda #0
bne ++
+ lda #1
+""")
}
assignRegisterByte(target, CpuRegister.A)
return true
}
return false
}
private fun simplePlusOrMinusExprRPN(left: PtExpression, operator: String, right: PtExpression, target: AsmAssignTarget): Boolean {
if(operator!="+" && operator!="!-")
return false
val dt = target.datatype
if(dt in ByteDatatypes) {
when (right) {
is PtIdentifier -> {
assignExpressionToRegister(left, RegisterOrPair.A, dt==DataType.BYTE)
val symname = asmgen.asmVariableName(right)
if(operator=="+")
asmgen.out(" clc | adc $symname")
else
asmgen.out(" sec | sbc $symname")
assignRegisterByte(target, CpuRegister.A)
return true
}
is PtNumber -> {
assignExpressionToRegister(left, RegisterOrPair.A, dt==DataType.BYTE)
if(operator=="+")
asmgen.out(" clc | adc #${right.number.toHex()}")
else
asmgen.out(" sec | sbc #${right.number.toHex()}")
assignRegisterByte(target, CpuRegister.A)
return true
}
else -> return false
}
} else if(dt in WordDatatypes) {
when (right) {
is PtAddressOf -> {
assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD)
val symbol = asmgen.asmVariableName(right.identifier)
if(operator=="+")
asmgen.out("""
clc
adc #<$symbol
pha
tya
adc #>$symbol
tay
pla""")
else
asmgen.out("""
sec
sbc #<$symbol
pha
tya
sbc #>$symbol
tay
pla""")
assignRegisterpairWord(target, RegisterOrPair.AY)
return true
}
is PtIdentifier -> {
val symname = asmgen.asmVariableName(right)
assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD)
if(operator=="+")
asmgen.out("""
clc
adc $symname
pha
tya
adc $symname+1
tay
pla""")
else
asmgen.out("""
sec
sbc $symname
pha
tya
sbc $symname+1
tay
pla""")
assignRegisterpairWord(target, RegisterOrPair.AY)
return true
}
is PtNumber -> {
assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD)
if(operator=="+") {
asmgen.out("""
clc
adc #<${right.number.toHex()}
pha
tya
adc #>${right.number.toHex()}
tay
pla""")
} else if(operator=="-") {
asmgen.out("""
sec
sbc #<${right.number.toHex()}
pha
tya
sbc #>${right.number.toHex()}
tay
pla""")
}
assignRegisterpairWord(target, RegisterOrPair.AY)
return true
}
is PtTypeCast -> {
val castedValue = right.value
if(right.type in WordDatatypes && castedValue.type in ByteDatatypes) {
if(castedValue is PtIdentifier) {
val castedSymname = asmgen.asmVariableName(castedValue)
assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD)
if(operator=="+")
asmgen.out("""
clc
adc $castedSymname
bcc +
iny
+""")
else
asmgen.out("""
sec
sbc $castedSymname
bcs +
dey
+""")
assignRegisterpairWord(target, RegisterOrPair.AY)
return true
}
}
}
else -> return false
}
}
return false
}
private fun simpleBitshiftExprRPN(left: PtExpression, operator: String, right: PtExpression, target: AsmAssignTarget): Boolean {
if(operator!="<<" && operator!=">>")
return false
val shifts = right.asConstInteger()
if(shifts!=null) {
val dt = left.type
if(dt in ByteDatatypes && shifts in 0..7) {
val signed = dt == DataType.BYTE
assignExpressionToRegister(left, RegisterOrPair.A, signed)
if(operator=="<<") {
repeat(shifts) {
asmgen.out(" asl a")
}
} else {
if(signed && shifts>0) {
asmgen.out(" ldy #$shifts | jsr math.lsr_byte_A")
} else {
repeat(shifts) {
asmgen.out(" lsr a")
}
}
}
assignRegisterByte(target, CpuRegister.A)
return true
} else if(dt in WordDatatypes && shifts in 0..7) {
val signed = dt == DataType.WORD
assignExpressionToRegister(left, RegisterOrPair.AY, signed)
if(operator=="<<") {
if(shifts>0) {
asmgen.out(" sty P8ZP_SCRATCH_B1")
repeat(shifts) {
asmgen.out(" asl a | rol P8ZP_SCRATCH_B1")
}
asmgen.out(" ldy P8ZP_SCRATCH_B1")
}
} else {
if(signed) {
// TODO("shift AY >> $shifts signed")
return false
} else {
if(shifts>0) {
asmgen.out(" sty P8ZP_SCRATCH_B1")
repeat(shifts) {
asmgen.out(" lsr P8ZP_SCRATCH_B1 | ror a")
}
asmgen.out(" ldy P8ZP_SCRATCH_B1")
}
}
}
assignRegisterpairWord(target, RegisterOrPair.AY)
return true
}
}
return false
}
private fun assignRPNComparison(assign: AsmAssignment, comparison: PtRpn) {
val (leftRpn, oper, right) = comparison.finalOperation()
val constRight = (right as PtExpression).asConstInteger()

View File

@ -1,11 +1,13 @@
TODO
====
RPN: Fix the TODO RPN routines to be optimized assembly in RpnExpressionAsmGen.kt
then:
RPN: examples/bsieve,charset compilation crash (bit shift expression)
RPN: cube3d-sprites compiler crash (bit shift too large)
RPN: swirl is bigger and MUCH slower
RPN: wizzine is slower but about equal size
RPN: charset is larger
RPN: cube3d is much larger, but a bit faster
RPN: cube3d-float is massive and slow
RPN: mandelbrot is big, but seems faster
RPN: swirl is MUCH slower, wizzine is slower
RPN: mandelbrot is bigger, but seems faster
then:
RPN: Implement RPN codegen for IR.