byte/word typecasts optimized even further to just use cpu registers (and fixed sign extending AY)

This commit is contained in:
Irmen de Jong 2020-11-26 01:11:31 +01:00
parent 53a600d87b
commit 238d8197f5
3 changed files with 175 additions and 104 deletions

View File

@ -1081,7 +1081,6 @@ sign_extend_stack_byte .proc
sign_extend_AY_byte .proc sign_extend_AY_byte .proc
; -- sign extend the (signed) byte in AY to full 16 bits ; -- sign extend the (signed) byte in AY to full 16 bits
pha pha
tya
and #$80 and #$80
beq + beq +
ldy #$ff ldy #$ff

View File

@ -122,7 +122,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
assignMemoryByte(assign.target, null, value.addressExpression as IdentifierReference) assignMemoryByte(assign.target, null, value.addressExpression as IdentifierReference)
} }
else -> { else -> {
asmgen.assignExpressionToVariable(value.addressExpression, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, assign.target.scope) assignExpressionToVariable(value.addressExpression, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, assign.target.scope)
asmgen.out(" ldy #0 | lda (P8ZP_SCRATCH_W2),y") asmgen.out(" ldy #0 | lda (P8ZP_SCRATCH_W2),y")
assignRegisterByte(assign.target, CpuRegister.A) assignRegisterByte(assign.target, CpuRegister.A)
} }
@ -272,18 +272,26 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
return assignTypeCastedIdentifier(target.asmVarname, targetDt, asmgen.asmVariableName(value), valueDt) return assignTypeCastedIdentifier(target.asmVarname, targetDt, asmgen.asmVariableName(value), valueDt)
when (valueDt) { when (valueDt) {
in ByteDatatypes, in WordDatatypes -> { in ByteDatatypes -> {
// TODO optimize byte/word typecasts even more by only using registers assignExpressionToRegister(value, RegisterOrPair.A)
asmgen.assignExpressionToVariable(value, "P8ZP_SCRATCH_W1", valueDt, null) return assignTypeCastedRegisters(target.asmVarname, targetDt, RegisterOrPair.A, valueDt)
return assignTypeCastedIdentifier(target.asmVarname, targetDt, "P8ZP_SCRATCH_W1", valueDt) }
in WordDatatypes -> {
assignExpressionToRegister(value, RegisterOrPair.AY)
return assignTypeCastedRegisters(target.asmVarname, targetDt, RegisterOrPair.AY, valueDt)
} }
DataType.FLOAT -> { DataType.FLOAT -> {
// float value cast, fall through and do it via stack for now // float value cast, fall through and do it via stack for now
// TODO optimize float casts to not use stack // because doing it with an intermediate variable uses up quite a few extra instructions at this point..
// TODO re-enable float cast via var once expression code generation is more efficent? Or do it via FAC1 directly?
// val scope = value.definingSubroutine()!!
// scope.asmGenInfo.usedFloatEvalResultVar = true
// assignExpressionToVariable(value, subroutineFloatEvalResultVar, valueDt, scope)
// return assignTypeCastedIdentifier(target.asmVarname, targetDt, subroutineFloatEvalResultVar, valueDt)
} }
in PassByReferenceDatatypes -> { in PassByReferenceDatatypes -> {
// str/array value cast (most likely to UWORD, take address-of) // str/array value cast (most likely to UWORD, take address-of)
return asmgen.assignExpressionToVariable(value, target.asmVarname, targetDt, null) // TODO test this cast return assignExpressionToVariable(value, target.asmVarname, targetDt, null) // TODO test this cast
} }
else -> throw AssemblyError("strange dt in typecast assign to var: $valueDt --> $targetDt") else -> throw AssemblyError("strange dt in typecast assign to var: $valueDt --> $targetDt")
} }
@ -398,6 +406,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
} }
} }
DataType.FLOAT -> { DataType.FLOAT -> {
// TODO loading targetasmname in SCRATCH_W2 no longer needed???????
asmgen.out(""" asmgen.out("""
lda #<$targetAsmVarName lda #<$targetAsmVarName
ldy #>$targetAsmVarName ldy #>$targetAsmVarName
@ -423,6 +432,145 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
} }
private fun assignTypeCastedRegisters(targetAsmVarName: String, targetDt: DataType,
regs: RegisterOrPair, sourceDt: DataType) {
if(sourceDt == targetDt)
throw AssemblyError("typecast to identical value")
// also see: ExpressionAsmGen, fun translateExpression(typecast: TypecastExpression)
when(sourceDt) {
DataType.UBYTE -> {
when(targetDt) {
DataType.UBYTE, DataType.BYTE -> {
asmgen.out(" st${regs.toString().toLowerCase()} $targetAsmVarName")
}
DataType.UWORD, DataType.WORD -> {
if(CompilationTarget.instance.machine.cpu==CpuType.CPU65c02)
asmgen.out(" st${regs.toString().toLowerCase()} $targetAsmVarName | stz $targetAsmVarName+1")
else
asmgen.out(" st${regs.toString().toLowerCase()} $targetAsmVarName | lda #0 | sta $targetAsmVarName+1")
}
DataType.FLOAT -> {
when(regs) {
RegisterOrPair.A -> asmgen.out(" tay")
RegisterOrPair.X -> asmgen.out(" txa | tay")
RegisterOrPair.Y -> {}
else -> throw AssemblyError("non-byte regs")
}
asmgen.out("""
lda #<$targetAsmVarName
sta P8ZP_SCRATCH_W2
lda #>$targetAsmVarName
sta P8ZP_SCRATCH_W2+1
jsr floats.cast_from_ub""")
}
else -> throw AssemblyError("weird type")
}
}
DataType.BYTE -> {
when(targetDt) {
DataType.UBYTE, DataType.BYTE -> {
asmgen.out(" st${regs.toString().toLowerCase()} $targetAsmVarName")
}
DataType.UWORD -> {
if(CompilationTarget.instance.machine.cpu==CpuType.CPU65c02)
asmgen.out(" st${regs.toString().toLowerCase()} $targetAsmVarName | stz $targetAsmVarName+1")
else
asmgen.out(" st${regs.toString().toLowerCase()} $targetAsmVarName | lda #0 | sta $targetAsmVarName+1")
}
DataType.WORD -> {
when(regs) {
RegisterOrPair.A -> {}
RegisterOrPair.X -> asmgen.out(" txa")
RegisterOrPair.Y -> asmgen.out(" tya")
else -> throw AssemblyError("non-byte regs")
}
asmgen.signExtendAYlsb(sourceDt)
asmgen.out(" sta $targetAsmVarName | sty $targetAsmVarName+1")
}
DataType.FLOAT -> {
when(regs) {
RegisterOrPair.A -> {}
RegisterOrPair.X -> asmgen.out(" txa")
RegisterOrPair.Y -> asmgen.out(" tya")
else -> throw AssemblyError("non-byte regs")
}
asmgen.out("""
ldy #<$targetAsmVarName
sty P8ZP_SCRATCH_W2
ldy #>$targetAsmVarName
sty P8ZP_SCRATCH_W2+1
jsr floats.cast_from_b""")
}
else -> throw AssemblyError("weird type")
}
}
DataType.UWORD -> {
when(targetDt) {
DataType.BYTE, DataType.UBYTE -> {
asmgen.out(" st${regs.toString().toLowerCase().first()} $targetAsmVarName")
}
DataType.WORD, DataType.UWORD -> {
when(regs) {
RegisterOrPair.AX -> asmgen.out(" sta $targetAsmVarName | stx $targetAsmVarName+1")
RegisterOrPair.AY -> asmgen.out(" sta $targetAsmVarName | sty $targetAsmVarName+1")
RegisterOrPair.XY -> asmgen.out(" stx $targetAsmVarName | sty $targetAsmVarName+1")
else -> throw AssemblyError("non-word regs")
}
}
DataType.FLOAT -> {
if(regs!=RegisterOrPair.AY)
throw AssemblyError("only supports AY here")
asmgen.out("""
pha
lda #<$targetAsmVarName
sta P8ZP_SCRATCH_W2
lda #>$targetAsmVarName
sta P8ZP_SCRATCH_W2+1
pla
jsr floats.cast_from_uw""")
}
else -> throw AssemblyError("weird type")
}
}
DataType.WORD -> {
when(targetDt) {
DataType.BYTE, DataType.UBYTE -> {
asmgen.out(" st${regs.toString().toLowerCase().first()} $targetAsmVarName")
}
DataType.WORD, DataType.UWORD -> {
when(regs) {
RegisterOrPair.AX -> asmgen.out(" sta $targetAsmVarName | stx $targetAsmVarName+1")
RegisterOrPair.AY -> asmgen.out(" sta $targetAsmVarName | sty $targetAsmVarName+1")
RegisterOrPair.XY -> asmgen.out(" stx $targetAsmVarName | sty $targetAsmVarName+1")
else -> throw AssemblyError("non-word regs")
}
}
DataType.FLOAT -> {
if(regs!=RegisterOrPair.AY)
throw AssemblyError("only supports AY here")
asmgen.out("""
pha
lda #<$targetAsmVarName
sta P8ZP_SCRATCH_W2
lda #>$targetAsmVarName
sta P8ZP_SCRATCH_W2+1
pla
jsr floats.cast_from_w""")
}
else -> throw AssemblyError("weird type")
}
}
DataType.STR -> {
if (targetDt != DataType.UWORD && targetDt == DataType.STR)
throw AssemblyError("cannot typecast a string into another incompatitble type")
TODO("assign typecasted string into target var")
}
else -> throw AssemblyError("weird type")
}
}
private fun assignStackValue(target: AsmAssignTarget) { private fun assignStackValue(target: AsmAssignTarget) {
when(target.kind) { when(target.kind) {
TargetStorageKind.VARIABLE -> { TargetStorageKind.VARIABLE -> {
@ -1469,7 +1617,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
asmgen.storeByteIntoPointer(addressExpr, ldaInstructionArg) asmgen.storeByteIntoPointer(addressExpr, ldaInstructionArg)
} }
else -> { else -> {
asmgen.assignExpressionToVariable(addressExpr, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null) assignExpressionToVariable(addressExpr, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null)
asmgen.out(" ldy #0 | lda $ldaInstructionArg | sta (P8ZP_SCRATCH_W2),y") asmgen.out(" ldy #0 | lda $ldaInstructionArg | sta (P8ZP_SCRATCH_W2),y")
} }
} }
@ -1494,7 +1642,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
} }
else -> { else -> {
asmgen.saveRegister(register, false, memoryAddress.definingSubroutine()!!) asmgen.saveRegister(register, false, memoryAddress.definingSubroutine()!!)
asmgen.assignExpressionToVariable(addressExpr, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null) assignExpressionToVariable(addressExpr, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null)
asmgen.restoreRegister(CpuRegister.A, false) asmgen.restoreRegister(CpuRegister.A, false)
asmgen.out(" ldy #0 | sta (P8ZP_SCRATCH_W2),y") asmgen.out(" ldy #0 | sta (P8ZP_SCRATCH_W2),y")
} }

View File

@ -7,105 +7,29 @@ main {
sub start() { sub start() {
uword uw = $c000 float fl
ubyte ub = 1 word ww
ubyte ub2 = 1 uword uw
uword uv1 = 1 byte bb
uword uv2 = 1 ubyte ub
uw = 1000
uw += ub+ub2 fl = 9997.999
ww = (fl+1.1) as word
uw = (fl+1.1) as uword
fl = 97.999
bb = (fl+1.1) as byte
ub = (fl+1.1) as ubyte
txt.print_w(ww)
txt.chrout('\n')
txt.print_uw(uw) txt.print_uw(uw)
txt.chrout('\n') txt.chrout('\n')
txt.print_b(bb)
uw = 1000 txt.chrout('\n')
uw -= ub+ub2 txt.print_ub(ub)
txt.print_uw(uw)
txt.chrout('\n') txt.chrout('\n')
uw = 1000
uw *= ub+ub2
txt.print_uw(uw)
txt.chrout('\n')
uw = 1000
uw /= ub+ub2
txt.print_uw(uw)
txt.chrout('\n')
uw = 1000
uw %= 5*ub+ub2+ub2
txt.print_uw(uw)
txt.chrout('\n')
uw = 1000
uw <<= ub+ub2
txt.print_uw(uw)
txt.chrout('\n')
uw = 1000
uw >>= ub+ub2
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() test_stack.test()