mirror of
https://github.com/irmen/prog8.git
synced 2024-12-23 09:32:43 +00:00
Fix some FP related assignment issues in 6502 codegen.
This commit is contained in:
parent
f2273c0acc
commit
a82b2da16e
@ -27,13 +27,6 @@ internal class AssignmentAsmGen(private val program: Program,
|
||||
translateNormalAssignment(assign)
|
||||
}
|
||||
|
||||
internal fun virtualRegsToVariables(origtarget: AsmAssignTarget): AsmAssignTarget {
|
||||
return if(origtarget.kind==TargetStorageKind.REGISTER && origtarget.register in Cx16VirtualRegisters) {
|
||||
AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, origtarget.datatype, origtarget.scope,
|
||||
variableAsmName = "cx16.${origtarget.register!!.name.lowercase()}", origAstTarget = origtarget.origAstTarget)
|
||||
} else origtarget
|
||||
}
|
||||
|
||||
fun translateNormalAssignment(assign: AsmAssignment) {
|
||||
if(assign.isAugmentable) {
|
||||
augmentableAsmGen.translate(assign)
|
||||
@ -940,11 +933,9 @@ internal class AssignmentAsmGen(private val program: Program,
|
||||
is NumericLiteral -> {
|
||||
val address = (value.addressExpression as NumericLiteral).number.toUInt()
|
||||
assignMemoryByteIntoWord(target, address, null)
|
||||
return
|
||||
}
|
||||
is IdentifierReference -> {
|
||||
assignMemoryByteIntoWord(target, null, value.addressExpression as IdentifierReference)
|
||||
return
|
||||
}
|
||||
is BinaryExpression -> {
|
||||
if(asmgen.tryOptimizedPointerAccessWithA(value.addressExpression as BinaryExpression, false)) {
|
||||
@ -958,6 +949,7 @@ internal class AssignmentAsmGen(private val program: Program,
|
||||
assignViaExprEval(value.addressExpression)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
is NumericLiteral -> throw AssemblyError("a cast of a literal value should have been const-folded away")
|
||||
@ -966,7 +958,7 @@ internal class AssignmentAsmGen(private val program: Program,
|
||||
|
||||
|
||||
// special case optimizations
|
||||
if(target.kind== TargetStorageKind.VARIABLE) {
|
||||
if(target.kind == TargetStorageKind.VARIABLE) {
|
||||
if(value is IdentifierReference && valueDt != DataType.UNDEFINED)
|
||||
return assignTypeCastedIdentifier(target.asmVarname, targetDt, asmgen.asmVariableName(value), valueDt)
|
||||
|
||||
@ -1044,11 +1036,12 @@ internal class AssignmentAsmGen(private val program: Program,
|
||||
assignExpressionToRegister(value, RegisterOrPair.FAC1, target.datatype in SignedDatatypes)
|
||||
assignTypeCastedFloatFAC1("P8ZP_SCRATCH_W1", target.datatype)
|
||||
assignVariableToRegister("P8ZP_SCRATCH_W1", target.register!!, target.datatype in SignedDatatypes)
|
||||
return
|
||||
} else {
|
||||
if(!(valueDt isAssignableTo targetDt)) {
|
||||
if(valueDt in WordDatatypes && targetDt in ByteDatatypes) {
|
||||
return if(valueDt in WordDatatypes && targetDt in ByteDatatypes) {
|
||||
// word to byte, just take the lsb
|
||||
return assignCastViaLsbFunc(value, target)
|
||||
assignCastViaLsbFunc(value, target)
|
||||
} else if(valueDt in WordDatatypes && targetDt in WordDatatypes) {
|
||||
// word to word, just assign
|
||||
assignExpressionToRegister(value, target.register!!, targetDt==DataType.BYTE || targetDt==DataType.WORD)
|
||||
@ -1058,43 +1051,85 @@ internal class AssignmentAsmGen(private val program: Program,
|
||||
} else if(valueDt in ByteDatatypes && targetDt in WordDatatypes) {
|
||||
// byte to word, just assign
|
||||
assignExpressionToRegister(value, target.register!!, targetDt==DataType.WORD)
|
||||
}
|
||||
else
|
||||
} else
|
||||
throw AssemblyError("can't cast $valueDt to $targetDt, this should have been checked in the astchecker")
|
||||
}
|
||||
assignExpressionToRegister(value, target.register!!, targetDt==DataType.BYTE || targetDt==DataType.WORD)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if(targetDt in IntegerDatatypes && valueDt in IntegerDatatypes && valueDt.isAssignableTo(targetDt)) {
|
||||
require(targetDt in WordDatatypes && valueDt in ByteDatatypes) { "should be byte to word assignment ${origTypeCastExpression.position}"}
|
||||
when(target.kind) {
|
||||
// TargetStorageKind.VARIABLE -> {
|
||||
// This has been handled already earlier on line 961.
|
||||
// // byte to word, just assign to registers first, then assign to variable
|
||||
// assignExpressionToRegister(value, RegisterOrPair.AY, targetDt==DataType.WORD)
|
||||
// assignTypeCastedRegisters(target.asmVarname, targetDt, RegisterOrPair.AY, targetDt)
|
||||
// return
|
||||
// }
|
||||
TargetStorageKind.ARRAY -> {
|
||||
// byte to word, just assign to registers first, then assign into array
|
||||
assignExpressionToRegister(value, RegisterOrPair.AY, targetDt==DataType.WORD)
|
||||
assignRegisterpairWord(target, RegisterOrPair.AY)
|
||||
return
|
||||
}
|
||||
TargetStorageKind.REGISTER -> {
|
||||
// byte to word, just assign to registers
|
||||
assignExpressionToRegister(value, target.register!!, targetDt==DataType.WORD)
|
||||
return
|
||||
}
|
||||
TargetStorageKind.STACK -> {
|
||||
// byte to word, just assign to registers first, then push onto stack
|
||||
assignExpressionToRegister(value, RegisterOrPair.AY, targetDt==DataType.WORD)
|
||||
asmgen.out("""
|
||||
sta P8ESTACK_LO,x
|
||||
tya
|
||||
sta P8ESTACK_HI,x
|
||||
dex""")
|
||||
return
|
||||
}
|
||||
else -> throw AssemblyError("weird target")
|
||||
}
|
||||
}
|
||||
|
||||
if(targetDt==DataType.FLOAT && (target.register==RegisterOrPair.FAC1 || target.register==RegisterOrPair.FAC2)) {
|
||||
when(valueDt) {
|
||||
DataType.UBYTE -> {
|
||||
assignExpressionToRegister(value, RegisterOrPair.Y, false)
|
||||
asmgen.saveRegisterLocal(CpuRegister.X, origTypeCastExpression.definingSubroutine!!)
|
||||
asmgen.out(" jsr floats.FREADUY")
|
||||
asmgen.restoreRegisterLocal(CpuRegister.X)
|
||||
}
|
||||
DataType.BYTE -> {
|
||||
assignExpressionToRegister(value, RegisterOrPair.A, true)
|
||||
asmgen.saveRegisterLocal(CpuRegister.X, origTypeCastExpression.definingSubroutine!!)
|
||||
asmgen.out(" jsr floats.FREADSA")
|
||||
asmgen.restoreRegisterLocal(CpuRegister.X)
|
||||
}
|
||||
DataType.UWORD -> {
|
||||
assignExpressionToRegister(value, RegisterOrPair.AY, false)
|
||||
asmgen.saveRegisterLocal(CpuRegister.X, origTypeCastExpression.definingSubroutine!!)
|
||||
asmgen.out(" jsr floats.GIVUAYFAY")
|
||||
asmgen.restoreRegisterLocal(CpuRegister.X)
|
||||
}
|
||||
DataType.WORD -> {
|
||||
assignExpressionToRegister(value, RegisterOrPair.AY, true)
|
||||
asmgen.saveRegisterLocal(CpuRegister.X, origTypeCastExpression.definingSubroutine!!)
|
||||
asmgen.out(" jsr floats.GIVAYFAY")
|
||||
asmgen.restoreRegisterLocal(CpuRegister.X)
|
||||
}
|
||||
else -> throw AssemblyError("invalid dt")
|
||||
}
|
||||
if(target.register==RegisterOrPair.FAC2) {
|
||||
asmgen.out(" jsr floats.MOVEF")
|
||||
}
|
||||
return
|
||||
} else {
|
||||
// No more special optmized cases yet. Do the rest via more complex evaluation
|
||||
// note: cannot use assignTypeCastedValue because that is ourselves :P
|
||||
// NOTE: THIS MAY TURN INTO A STACK OVERFLOW ERROR IF IT CAN'T SIMPLIFY THE TYPECAST..... :-/
|
||||
asmgen.assignExpressionTo(origTypeCastExpression, target)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@ -1251,14 +1286,10 @@ internal class AssignmentAsmGen(private val program: Program,
|
||||
DataType.UWORD, DataType.WORD -> {
|
||||
if(asmgen.isTargetCpu(CpuType.CPU65c02))
|
||||
asmgen.out(
|
||||
" st${
|
||||
regs.toString().lowercase()
|
||||
} $targetAsmVarName | stz $targetAsmVarName+1")
|
||||
" st${regs.toString().lowercase()} $targetAsmVarName | stz $targetAsmVarName+1")
|
||||
else
|
||||
asmgen.out(
|
||||
" st${
|
||||
regs.toString().lowercase()
|
||||
} $targetAsmVarName | lda #0 | sta $targetAsmVarName+1")
|
||||
" st${regs.toString().lowercase()} $targetAsmVarName | lda #0 | sta $targetAsmVarName+1")
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
when(regs) {
|
||||
|
@ -44,7 +44,7 @@ private fun compileMain(args: Array<String>): Boolean {
|
||||
val keepIR by cli.option(ArgType.Boolean, fullName = "keepIR", description = "keep the IR code file (for targets that use it)")
|
||||
val dontWriteAssembly by cli.option(ArgType.Boolean, fullName = "noasm", description="don't create assembly code")
|
||||
val dontOptimize by cli.option(ArgType.Boolean, fullName = "noopt", description = "don't perform any optimizations")
|
||||
val dontReinitGlobals by cli.option(ArgType.Boolean, fullName = "noreinit", description = "don't create code to reinitialize globals on multiple runs of the program (experimental!)")
|
||||
val dontReinitGlobals by cli.option(ArgType.Boolean, fullName = "noreinit", description = "don't create code to reinitialize globals on multiple runs of the program (experimental)")
|
||||
val outputDir by cli.option(ArgType.String, fullName = "out", description = "directory for output files instead of current directory").default(".")
|
||||
val optimizeFloatExpressions by cli.option(ArgType.Boolean, fullName = "optfloatx", description = "optimize float expressions (warning: can increase program size)")
|
||||
val quietAssembler by cli.option(ArgType.Boolean, fullName = "quietasm", description = "don't print assembler output results")
|
||||
|
@ -14,6 +14,7 @@ import prog8.ast.statements.VarDecl
|
||||
import prog8.code.core.DataType
|
||||
import prog8.code.core.Position
|
||||
import prog8.code.target.C64Target
|
||||
import prog8.code.target.VMTarget
|
||||
import prog8tests.helpers.ErrorReporterForTests
|
||||
import prog8tests.helpers.compileText
|
||||
|
||||
@ -934,4 +935,34 @@ main {
|
||||
}"""
|
||||
compileText(C64Target(), false, text, writeAssembly = true) shouldNotBe null
|
||||
}
|
||||
|
||||
test("various floating point casts don't crash the compiler") {
|
||||
val text="""
|
||||
%import floats
|
||||
|
||||
main {
|
||||
sub score() -> ubyte {
|
||||
cx16.r15++
|
||||
return 5
|
||||
}
|
||||
|
||||
sub start() {
|
||||
float @shared total = 0
|
||||
ubyte bb = 5
|
||||
|
||||
cx16.r0 = 5
|
||||
total += cx16.r0 as float
|
||||
total += score() as float
|
||||
uword ww = 5
|
||||
total += ww as float
|
||||
total += bb as float
|
||||
float result = score() as float
|
||||
total += result
|
||||
}
|
||||
}"""
|
||||
compileText(C64Target(), false, text, writeAssembly = true) shouldNotBe null
|
||||
compileText(C64Target(), true, text, writeAssembly = true) shouldNotBe null
|
||||
compileText(VMTarget(), false, text, writeAssembly = true) shouldNotBe null
|
||||
compileText(VMTarget(), true, text, writeAssembly = true) shouldNotBe null
|
||||
}
|
||||
})
|
||||
|
@ -140,8 +140,8 @@ One or more .p8 module files
|
||||
Don't create code to reinitialize the global (block level) variables on every run of the program.
|
||||
Also means that all such variables are no longer placed in the zeropage.
|
||||
Sometimes the program will be a lot shorter when using this, but sometimes the opposite happens.
|
||||
When using this option, it is no longer be possible to run the program correctly more than once!
|
||||
*Experimental feature*: still has some problems!
|
||||
When using this option, it may no longer be possible to run the program correctly more than once!
|
||||
*Experimental feature*: this feature has not been tested much yet.
|
||||
|
||||
``-optfloatx``
|
||||
Also optimize float expressions if optimizations are enabled.
|
||||
|
@ -3,6 +3,8 @@ TODO
|
||||
|
||||
For next release
|
||||
^^^^^^^^^^^^^^^^
|
||||
- fix compiler crash when compiling %import test_stack on virtual target.
|
||||
- bss in IR: with -noreinit, variables that have init value 0 should still be bss.
|
||||
- 6502 codegen: create BSS section in output assembly code and put StStaticVariables in there with bss=true.
|
||||
Don't forget to add init code to zero out everything that was put in bss. If array in bss->only zero ONCE if possible.
|
||||
Note that bss can still contain variables that have @zp tag and those are already dealt with differently
|
||||
|
117
examples/test.p8
117
examples/test.p8
@ -1,54 +1,79 @@
|
||||
%import textio
|
||||
%zeropage basicsafe
|
||||
%option no_sysinit
|
||||
%import floats
|
||||
|
||||
main {
|
||||
sub score() -> ubyte {
|
||||
cx16.r15++
|
||||
return 5
|
||||
}
|
||||
|
||||
sub start() {
|
||||
; TODO ALSO TEST AS GLOBALS
|
||||
ubyte @requirezp zpvar = 10
|
||||
ubyte @zp zpvar2 = 20
|
||||
uword empty
|
||||
ubyte[10] bssarray
|
||||
uword[10] bsswordarray
|
||||
ubyte[10] nonbssarray = 99
|
||||
str name="irmen"
|
||||
float @shared total = 0
|
||||
ubyte bb = 5
|
||||
|
||||
txt.print("10 ")
|
||||
txt.print_ub(zpvar)
|
||||
txt.nl()
|
||||
zpvar++
|
||||
|
||||
txt.print("20 ")
|
||||
txt.print_ub(zpvar2)
|
||||
txt.nl()
|
||||
zpvar2++
|
||||
|
||||
txt.print("0 ")
|
||||
txt.print_uw(empty)
|
||||
txt.nl()
|
||||
empty++
|
||||
|
||||
txt.print("0 ")
|
||||
txt.print_ub(bssarray[1])
|
||||
txt.nl()
|
||||
bssarray[1]++
|
||||
|
||||
txt.print("0 ")
|
||||
txt.print_uw(bsswordarray[1])
|
||||
txt.nl()
|
||||
bsswordarray[1]++
|
||||
|
||||
txt.print("99 ")
|
||||
txt.print_ub(nonbssarray[1])
|
||||
txt.nl()
|
||||
nonbssarray[1]++
|
||||
|
||||
txt.print("r ")
|
||||
txt.chrout(name[1])
|
||||
txt.nl()
|
||||
name[1] = (name[1] as ubyte +1)
|
||||
|
||||
txt.print("try running again.\n")
|
||||
cx16.r0 = 5
|
||||
total += cx16.r0 as float
|
||||
total += score() as float
|
||||
uword ww = 5
|
||||
total += ww as float
|
||||
total += bb as float
|
||||
float result = score() as float
|
||||
total += result
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
;%import textio
|
||||
;%zeropage basicsafe
|
||||
;%option no_sysinit
|
||||
;
|
||||
;main {
|
||||
;
|
||||
; sub start() {
|
||||
; ; TODO ALSO TEST AS GLOBALS
|
||||
; ubyte @requirezp zpvar = 10
|
||||
; ubyte @zp zpvar2 = 20
|
||||
; uword empty
|
||||
; ubyte[10] bssarray
|
||||
; uword[10] bsswordarray
|
||||
; ubyte[10] nonbssarray = 99
|
||||
; str name="irmen"
|
||||
;
|
||||
; txt.print("10 ")
|
||||
; txt.print_ub(zpvar)
|
||||
; txt.nl()
|
||||
; zpvar++
|
||||
;
|
||||
; txt.print("20 ")
|
||||
; txt.print_ub(zpvar2)
|
||||
; txt.nl()
|
||||
; zpvar2++
|
||||
;
|
||||
; txt.print("0 ")
|
||||
; txt.print_uw(empty)
|
||||
; txt.nl()
|
||||
; empty++
|
||||
;
|
||||
; txt.print("0 ")
|
||||
; txt.print_ub(bssarray[1])
|
||||
; txt.nl()
|
||||
; bssarray[1]++
|
||||
;
|
||||
; txt.print("0 ")
|
||||
; txt.print_uw(bsswordarray[1])
|
||||
; txt.nl()
|
||||
; bsswordarray[1]++
|
||||
;
|
||||
; txt.print("99 ")
|
||||
; txt.print_ub(nonbssarray[1])
|
||||
; txt.nl()
|
||||
; nonbssarray[1]++
|
||||
;
|
||||
; txt.print("r ")
|
||||
; txt.chrout(name[1])
|
||||
; txt.nl()
|
||||
; name[1] = (name[1] as ubyte +1)
|
||||
;
|
||||
; txt.print("try running again.\n")
|
||||
; }
|
||||
;}
|
||||
|
Loading…
Reference in New Issue
Block a user