mirror of
https://github.com/irmen/prog8.git
synced 2024-12-25 23:29:55 +00:00
optimize word [operator] byte, without translateExpression()
This commit is contained in:
parent
378dcfe351
commit
936b046ed9
@ -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
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
@ -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")
|
||||
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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()
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user