optimize word [operator] byte, without translateExpression()

This commit is contained in:
Irmen de Jong 2020-11-24 22:26:11 +01:00
parent 378dcfe351
commit 936b046ed9
5 changed files with 169 additions and 137 deletions

View File

@ -1065,3 +1065,29 @@ _return_minusone
lda #-1
rts
.pend
sign_extend_stack_byte .proc
; -- sign extend the (signed) byte on the stack to full 16 bits
lda P8ESTACK_LO+1,x
ora #$7f
bmi +
lda #0
+ sta P8ESTACK_HI+1,x
rts
.pend
sign_extend_AY_byte .proc
; -- sign extend the (signed) byte in AY to full 16 bits
pha
tya
and #$80
beq +
ldy #$ff
pla
rts
+ ldy #0
pla
rts
.pend

View File

@ -1192,20 +1192,20 @@ $label nop""")
assemblyLines.add(assembly)
}
internal fun signExtendAYlsb(valueDt: DataType) {
// sign extend signed byte in AY to full word in AY
when(valueDt) {
DataType.UBYTE -> out(" ldy #0")
DataType.BYTE -> out(" jsr prog8_lib.sign_extend_AY_byte")
else -> throw AssemblyError("need byte type")
}
}
internal fun signExtendStackLsb(valueDt: DataType) {
// sign extend signed byte on stack to signed word
when(valueDt) {
DataType.UBYTE -> {
out(" lda #0 | sta P8ESTACK_HI+1,x")
}
DataType.BYTE -> {
out("""
lda P8ESTACK_LO+1,x
ora #$7f
bmi +
lda #0
+ sta P8ESTACK_HI+1,x""")
}
DataType.UBYTE -> out(" lda #0 | sta P8ESTACK_HI+1,x")
DataType.BYTE -> out(" jsr prog8_lib.sign_extend_stack_byte")
else -> throw AssemblyError("need byte type")
}
}

View File

@ -138,7 +138,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
is IdentifierReference -> throw AssemblyError("source kind should have been variable")
is ArrayIndexedExpression -> throw AssemblyError("source kind should have been array")
is DirectMemoryRead -> throw AssemblyError("source kind should have been memory")
is TypecastExpression -> assignTypeCastedValue(assign.target, value.type, value.expression, assign)
is TypecastExpression -> assignTypeCastedValue(assign.target, value.type, value.expression, value)
is FunctionCall -> {
when (val sub = value.target.targetStatement(program.namespace)) {
is Subroutine -> {
@ -227,11 +227,14 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
}
}
private fun assignTypeCastedValue(target: AsmAssignTarget, targetDt: DataType, value: Expression, origAssign: AsmAssignment) {
private fun assignTypeCastedValue(target: AsmAssignTarget, targetDt: DataType, value: Expression, origTypeCastExpression: TypecastExpression) {
val valueIDt = value.inferType(program)
if(!valueIDt.isKnown)
throw AssemblyError("unknown dt")
val valueDt = valueIDt.typeOrElse(DataType.STRUCT)
if(valueDt==targetDt)
throw AssemblyError("type cast to identical dt should have been removed")
when(value) {
is IdentifierReference -> {
if(targetDt in WordDatatypes) {
@ -262,35 +265,26 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
else -> {}
}
when(value) {
is IdentifierReference -> {
if(target.kind==TargetStorageKind.VARIABLE) {
val sourceDt = value.inferType(program).typeOrElse(DataType.STRUCT)
if (sourceDt != DataType.STRUCT)
return assignTypeCastedIdentifier(target.asmVarname, targetDt, asmgen.asmVariableName(value), sourceDt, origAssign.source.expression!!)
}
}
is PrefixExpression -> {}
is BinaryExpression -> {}
is ArrayIndexedExpression -> {}
is TypecastExpression -> {}
is RangeExpr -> {}
is FunctionCall -> {}
else -> {
// TODO optimize the others further?
if(this.asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used for typecast: $value into $targetDt at ${value.position}")
// special case optimizations
if (value is IdentifierReference) {
if(target.kind==TargetStorageKind.VARIABLE) {
if (valueDt != DataType.STRUCT)
return assignTypeCastedIdentifier(target.asmVarname, targetDt, asmgen.asmVariableName(value), valueDt)
}
}
// give up, do it via eval stack
asmgen.translateExpression(origAssign.source.expression!!)
// TODO optimize typecasts for more special cases?
// note: cannot use assignTypeCastedValue because that is ourselves :P
if(this.asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used for typecast: $value into $targetDt at ${value.position}")
asmgen.translateExpression(origTypeCastExpression) // this performs the actual type cast in translateExpression(Typecast)
assignStackValue(target)
}
private fun assignTypeCastedIdentifier(targetAsmVarName: String, targetDt: DataType,
sourceAsmVarName: String, sourceDt: DataType,
origExpr: Expression) {
sourceAsmVarName: String, sourceDt: DataType) {
if(sourceDt == targetDt)
throw AssemblyError("typecast to identical value")

View File

@ -1100,11 +1100,8 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
throw AssemblyError("unknown dt")
val valueDt = valueiDt.typeOrElse(DataType.STRUCT)
// TODO can use registers instead of stack value?
fun multiplyWord() {
fun multiplyVarByWordInAY() {
asmgen.out("""
lda P8ESTACK_LO+1,x
ldy P8ESTACK_HI+1,x
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda $name
@ -1117,51 +1114,36 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
""")
}
// TODO can use registers instead of stack value?
fun divideWord() {
if (dt == DataType.WORD) {
asmgen.out("""
fun divideVarByWordInAY() {
asmgen.out("""
pha
lda $name
ldy $name+1
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda P8ESTACK_LO+1,x
ldy P8ESTACK_HI+1,x
jsr math.divmod_w_asm
sta $name
sty $name+1
""")
} else {
asmgen.out("""
lda $name
ldy $name+1
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda P8ESTACK_LO+1,x
ldy P8ESTACK_HI+1,x
jsr math.divmod_uw_asm
sta $name
sty $name+1
""")
}
lda $name+1
sta P8ZP_SCRATCH_W1+1
pla""")
if (dt == DataType.WORD)
asmgen.out(" jsr math.divmod_w_asm")
else
asmgen.out(" jsr math.divmod_uw_asm")
asmgen.out(" sta $name | sty $name+1")
}
// TODO can use registers instead of stack value?
fun remainderWord() {
fun remainderVarByWordInAY() {
if(dt==DataType.WORD)
throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
asmgen.out("""
pha
lda $name
ldy $name+1
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda P8ESTACK_LO+1,x
ldy P8ESTACK_HI+1,x
lda $name+1
sta P8ZP_SCRATCH_W1+1
pla
jsr math.divmod_uw_asm
lda P8ZP_SCRATCH_W2
ldy P8ZP_SCRATCH_W2+1
sta $name
lda P8ZP_SCRATCH_W2+1
sta $name+1
sty $name+1
""")
}
@ -1171,14 +1153,12 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
when (operator) {
// note: ** (power) operator requires floats.
"+" -> {
if(asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (4): $name += ${value::class.simpleName} at ${value.position}") // TODO
asmgen.translateExpression(value)
asmgen.assignExpressionToVariable(value, "P8ZP_SCRATCH_B1", valueDt, null)
if(valueDt==DataType.UBYTE)
asmgen.out("""
lda $name
clc
adc P8ESTACK_LO+1,x
adc P8ZP_SCRATCH_B1
sta $name
bcc +
inc $name+1
@ -1186,7 +1166,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
else
asmgen.out("""
ldy #0
lda P8ESTACK_LO+1,x
lda P8ZP_SCRATCH_B1
bpl +
dey ; sign extend
+ clc
@ -1195,17 +1175,14 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
tya
adc $name+1
sta $name+1""")
asmgen.out(" inx")
}
"-" -> {
if(asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (4): $name -= ${value::class.simpleName} at ${value.position}") // TODO
asmgen.translateExpression(value)
asmgen.assignExpressionToVariable(value, "P8ZP_SCRATCH_REG", valueDt, null)
if(valueDt==DataType.UBYTE)
asmgen.out("""
lda $name
sec
sbc P8ESTACK_LO+1,x
sbc P8ZP_SCRATCH_REG
sta $name
bcs +
dec $name+1
@ -1213,45 +1190,38 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
else
asmgen.out("""
ldy #0
lda P8ESTACK_LO+1,x
lda P8ZP_SCRATCH_REG
bpl +
dey ; sign extend
+ sty P8ZP_SCRATCH_B1
lda $name
sec
sbc P8ESTACK_LO+1,x
sbc P8ZP_SCRATCH_REG
sta $name
lda $name+1
sbc P8ZP_SCRATCH_B1
sta $name+1""")
asmgen.out(" inx")
}
"*" -> {
// stack contains (u) byte value, sign extend that and proceed with regular 16 bit operation
if(asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (4): $name *= ${value::class.simpleName} at ${value.position}") // TODO
asmgen.translateExpression(value)
asmgen.signExtendStackLsb(valueDt)
multiplyWord()
asmgen.out(" inx")
// TODO use an optimized word * byte multiplication routine
asmgen.assignExpressionToRegister(value, RegisterOrPair.A)
asmgen.signExtendAYlsb(valueDt)
multiplyVarByWordInAY()
}
"/" -> {
// stack contains (u) byte value, sign extend that and proceed with regular 16 bit operation
if(asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (4): $name /= ${value::class.simpleName} at ${value.position}") // TODO
asmgen.translateExpression(value)
asmgen.signExtendStackLsb(valueDt)
divideWord()
asmgen.out(" inx")
// TODO use an optimized word / byte divmod routine
asmgen.assignExpressionToRegister(value, RegisterOrPair.A)
asmgen.signExtendAYlsb(valueDt)
divideVarByWordInAY()
}
"%" -> {
// stack contains (u) byte value, sign extend that and proceed with regular 16 bit operation
if(asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (4): $name %= ${value::class.simpleName} at ${value.position}") // TODO
asmgen.translateExpression(value)
asmgen.signExtendStackLsb(valueDt)
remainderWord()
asmgen.out(" inx")
// TODO use an optimized word / byte divmod routine
asmgen.assignExpressionToRegister(value, RegisterOrPair.A)
asmgen.signExtendAYlsb(valueDt)
remainderVarByWordInAY()
}
"<<" -> {
asmgen.assignExpressionToRegister(value, RegisterOrPair.Y)
@ -1306,56 +1276,37 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
when (operator) {
// note: ** (power) operator requires floats.
"+" -> {
if(asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (4w): $name += ${value::class.simpleName} at ${value.position}") // TODO
asmgen.translateExpression(value)
asmgen.out(" lda $name | clc | adc P8ESTACK_LO+1,x | sta $name | lda $name+1 | adc P8ESTACK_HI+1,x | sta $name+1 | inx")
asmgen.assignExpressionToRegister(value, RegisterOrPair.AY)
asmgen.out(" clc | adc $name | sta $name | tya | adc $name+1 | sta $name+1")
}
"-" -> {
if(asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (4w): $name -= ${value::class.simpleName} at ${value.position}") // TODO
asmgen.translateExpression(value)
asmgen.out(" lda $name | sec | sbc P8ESTACK_LO+1,x | sta $name | lda $name+1 | sbc P8ESTACK_HI+1,x | sta $name+1 | inx")
asmgen.assignExpressionToVariable(value, "P8ZP_SCRATCH_W1", valueDt, null)
asmgen.out(" lda $name | sec | sbc P8ZP_SCRATCH_W1 | sta $name | lda $name+1 | sbc P8ZP_SCRATCH_W1+1 | sta $name+1")
}
"*" -> {
if(asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (4w): $name *= ${value::class.simpleName} at ${value.position}") // TODO
asmgen.translateExpression(value)
multiplyWord()
asmgen.out(" inx")
asmgen.assignExpressionToRegister(value, RegisterOrPair.AY)
multiplyVarByWordInAY()
}
"/" -> {
if(asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (4w): $name /= ${value::class.simpleName} at ${value.position}") // TODO
asmgen.translateExpression(value)
divideWord()
asmgen.out(" inx")
asmgen.assignExpressionToRegister(value, RegisterOrPair.AY)
divideVarByWordInAY()
}
"%" -> {
if(asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (4w): $name %= ${value::class.simpleName} at ${value.position}") // TODO
asmgen.translateExpression(value)
remainderWord()
asmgen.out(" inx")
asmgen.assignExpressionToRegister(value, RegisterOrPair.AY)
remainderVarByWordInAY()
}
"<<", ">>" -> throw AssemblyError("shift by a word value not supported, max is a byte")
"&" -> {
if(asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (4w): $name &= ${value::class.simpleName} at ${value.position}") // TODO
asmgen.translateExpression(value)
asmgen.out(" lda $name | and P8ESTACK_LO+1,x | sta $name | lda $name+1 | and P8ESTACK_HI+1,x | sta $name+1 | inx")
asmgen.assignExpressionToRegister(value, RegisterOrPair.AY)
asmgen.out(" and $name | sta $name | tya | and $name+1 | sta $name+1")
}
"^" -> {
if(asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (4w): $name ^= ${value::class.simpleName} at ${value.position}") // TODO
asmgen.translateExpression(value)
asmgen.out(" lda $name | eor P8ESTACK_LO+1,x | sta $name | lda $name+1 | eor P8ESTACK_HI+1,x | sta $name+1 | inx")
asmgen.assignExpressionToRegister(value, RegisterOrPair.AY)
asmgen.out(" eor $name | sta $name | tya | eor $name+1 | sta $name+1")
}
"|" -> {
if(asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (4w): $name |r= ${value::class.simpleName} at ${value.position}") // TODO
asmgen.translateExpression(value)
asmgen.out(" lda $name | ora P8ESTACK_LO+1,x | sta $name | lda $name+1 | ora P8ESTACK_HI+1,x | sta $name+1 | inx")
asmgen.assignExpressionToRegister(value, RegisterOrPair.AY)
asmgen.out(" ora $name | sta $name | tya | ora $name+1 | sta $name+1")
}
else -> throw AssemblyError("invalid operator for in-place modification $operator")
}

View File

@ -10,6 +10,8 @@ main {
uword uw = $c000
ubyte ub = 1
ubyte ub2 = 1
uword uv1 = 1
uword uv2 = 1
uw = 1000
uw += ub+ub2
@ -46,6 +48,65 @@ main {
txt.print_uw(uw)
txt.chrout('\n')
uw = $1111
uw &= (ub+ub2) | 15
txt.print_uwhex(uw, 1)
txt.chrout('\n')
uw = $1111
uw |= (ub+ub2) | 15
txt.print_uwhex(uw, 1)
txt.chrout('\n')
uw = $1111
uw ^= (ub+ub2) | 15
txt.print_uwhex(uw, 1)
txt.chrout('\n')
txt.chrout('\n')
uw = 1000
uw += uv1+uv2
txt.print_uw(uw)
txt.chrout('\n')
uw = 1000
uw -= uv1+uv2
txt.print_uw(uw)
txt.chrout('\n')
uw = 1000
uw *= uv1+uv2
txt.print_uw(uw)
txt.chrout('\n')
uw = 1000
uw /= uv1+uv2
txt.print_uw(uw)
txt.chrout('\n')
uw = 1000
uw %= 5*uv1+uv2+uv2
txt.print_uw(uw)
txt.chrout('\n')
uw = $1111
uw &= (uv1+uv2) | 1023
txt.print_uwhex(uw, 1)
txt.chrout('\n')
uw = $1111
uw |= (uv1+uv2) | 32768
txt.print_uwhex(uw, 1)
txt.chrout('\n')
uw = $1111
uw ^= (uv1+uv2) | 32768
txt.print_uwhex(uw, 1)
txt.chrout('\n')
test_stack.test()
}