fix: array[x] = -array[x] no longer crashes the codegen

This commit is contained in:
Irmen de Jong 2022-10-27 23:08:40 +02:00
parent b0c7bad391
commit 094f7803b7
6 changed files with 96 additions and 61 deletions

View File

@ -106,7 +106,7 @@ class AsmGen(internal val program: Program,
DataType.BYTE -> listOf("cx16", "r9sL")
DataType.UWORD -> listOf("cx16", "r9")
DataType.WORD -> listOf("cx16", "r9s")
DataType.FLOAT -> listOf("floats", "tempvar_swap_float") // defined in floats.p8
DataType.FLOAT -> TODO("no temporary float var available")
else -> throw FatalAstException("invalid dt $dt")
}
}

View File

@ -300,23 +300,12 @@ internal class AssignmentAsmGen(private val program: Program,
val target = virtualRegsToVariables(assign.target)
when (value.operator) {
"+" -> {}
"-" -> augmentableAsmGen.inplaceNegate(target, target.datatype)
"-" -> augmentableAsmGen.inplaceNegate(assign)
"~" -> augmentableAsmGen.inplaceInvert(target, target.datatype)
else -> throw AssemblyError("invalid prefix operator")
}
} else {
// array[x] = -array[x] ... use a tempvar then store that back into the array.
val tempvar = asmgen.getTempVarName(assign.target.datatype).joinToString(".")
val assignToTempvar = AsmAssignment(assign.source,
AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, assign.target.datatype, assign.target.scope, variableAsmName=tempvar, origAstTarget = assign.target.origAstTarget),
false, program.memsizer, assign.position)
asmgen.translateNormalAssignment(assignToTempvar)
when(assign.target.datatype) {
in ByteDatatypes -> assignVariableByte(assign.target, tempvar)
in WordDatatypes -> assignVariableWord(assign.target, tempvar)
DataType.FLOAT -> assignVariableFloat(assign.target, tempvar)
else -> throw AssemblyError("weird dt")
}
assignPrefixedExpressionToArrayElt(assign)
}
}
is ContainmentCheck -> {
@ -335,6 +324,22 @@ internal class AssignmentAsmGen(private val program: Program,
}
}
internal fun assignPrefixedExpressionToArrayElt(assign: AsmAssignment) {
// array[x] = -value ... use a tempvar then store that back into the array.
require(assign.source.expression is PrefixExpression)
val tempvar = asmgen.getTempVarName(assign.target.datatype).joinToString(".")
val assignToTempvar = AsmAssignment(assign.source,
AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, assign.target.datatype, assign.target.scope, variableAsmName=tempvar, origAstTarget = assign.target.origAstTarget),
false, program.memsizer, assign.position)
asmgen.translateNormalAssignment(assignToTempvar)
when(assign.target.datatype) {
in ByteDatatypes -> assignVariableByte(assign.target, tempvar)
in WordDatatypes -> assignVariableWord(assign.target, tempvar)
DataType.FLOAT -> assignVariableFloat(assign.target, tempvar)
else -> throw AssemblyError("weird dt")
}
}
private fun assignVirtualRegister(target: AsmAssignTarget, register: RegisterOrPair) {
when(target.datatype) {
in ByteDatatypes -> {

View File

@ -26,7 +26,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
val type = itype.getOrElse { throw AssemblyError("unknown dt") }
when (value.operator) {
"+" -> {}
"-" -> inplaceNegate(target, type)
"-" -> inplaceNegate(assign)
"~" -> inplaceInvert(target, type)
else -> throw AssemblyError("invalid prefix operator")
}
@ -1840,7 +1840,8 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
}
}
TargetStorageKind.STACK -> TODO("no asm gen for byte stack invert")
else -> TODO("no asm gen for in-place invert ubyte for ${target.kind}")
TargetStorageKind.ARRAY -> TODO("no asm gen for in-place invert ubyte for ${target.kind}")
else -> throw AssemblyError("weird target")
}
}
DataType.UWORD -> {
@ -1864,15 +1865,17 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
}
}
TargetStorageKind.STACK -> TODO("no asm gen for word stack invert")
else -> TODO("no asm gen for in-place invert uword for ${target.kind}")
TargetStorageKind.ARRAY -> TODO("no asm gen for in-place invert uword for ${target.kind}")
else -> throw AssemblyError("weird target")
}
}
else -> throw AssemblyError("invert of invalid type")
}
}
internal fun inplaceNegate(target: AsmAssignTarget, dt: DataType) {
when (dt) {
internal fun inplaceNegate(assign: AsmAssignment) {
val target = assign.target
when (val dt=assign.target.datatype) {
DataType.BYTE -> {
when (target.kind) {
TargetStorageKind.VARIABLE -> {
@ -1896,9 +1899,10 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
else -> throw AssemblyError("invalid reg dt for byte negate")
}
}
TargetStorageKind.MEMORY -> throw AssemblyError("memory is ubyte, can't in-place negate")
TargetStorageKind.MEMORY -> throw AssemblyError("memory is ubyte, can't negate that")
TargetStorageKind.STACK -> TODO("no asm gen for byte stack negate")
else -> TODO("no asm gen for in-place negate byte")
TargetStorageKind.ARRAY -> assignmentAsmGen.assignPrefixedExpressionToArrayElt(assign)
else -> throw AssemblyError("weird target")
}
}
DataType.WORD -> {
@ -1955,8 +1959,10 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
else -> throw AssemblyError("invalid reg dt for word neg")
}
}
TargetStorageKind.MEMORY -> throw AssemblyError("memory is ubyte, can't negate that")
TargetStorageKind.STACK -> TODO("no asm gen for word stack negate")
else -> TODO("no asm gen for in-place negate word")
TargetStorageKind.ARRAY -> assignmentAsmGen.assignPrefixedExpressionToArrayElt(assign)
else -> throw AssemblyError("weird target")
}
}
DataType.FLOAT -> {
@ -1970,7 +1976,8 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
""")
}
TargetStorageKind.STACK -> TODO("no asm gen for float stack negate")
else -> TODO("no asmgen for inplace negate float ${target.kind}")
TargetStorageKind.ARRAY -> assignmentAsmGen.assignPrefixedExpressionToArrayElt(assign)
else -> throw AssemblyError("weird target for float negation")
}
}
else -> throw AssemblyError("negate of invalid type $dt")

View File

@ -16,31 +16,6 @@ import prog8.code.target.VMTarget
internal class AstOnetimeTransforms(private val program: Program, private val options: CompilationOptions) : AstWalker() {
override fun after(assignment: Assignment, parent: Node): Iterable<IAstModification> {
if(options.compTarget.name != VMTarget.NAME) {
// The 6502 code-gen doesn't contain code to deal with arr[0] = -arr[0] and arr[0] = ~arr[0].
// Replace this by assignment, operation, assignment.
// TODO make the codegen better so this work around can be removed
// if (assignment.isAugmentable) {
// val arrayIdx = assignment.target.arrayindexed
// if (arrayIdx != null) {
// val prefixed = assignment.value as? PrefixExpression
// if (prefixed != null) {
// println("array self-assignment, operator = ${prefixed.operator}")
// if (prefixed.operator == "-") {
// TODO("array in-place -")
// } else if (prefixed.operator == "~") {
// TODO("array in-place ~")
// }
// }
// }
// }
}
return noModifications
}
override fun after(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable<IAstModification> {
if(parent !is VarDecl) {
if(options.compTarget.name == VMTarget.NAME)

View File

@ -1,20 +1,9 @@
package prog8tests.codegeneration
import io.kotest.core.spec.style.FunSpec
import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.shouldNotBe
import prog8.ast.Module
import prog8.ast.Program
import prog8.ast.expressions.AddressOf
import prog8.ast.expressions.IdentifierReference
import prog8.ast.expressions.NumericLiteral
import prog8.ast.statements.*
import prog8.code.core.*
import prog8.code.target.C64Target
import prog8.code.target.c64.C64Zeropage
import prog8.codegen.cpu6502.AsmGen
import prog8.compiler.astprocessing.SymbolTableMaker
import prog8tests.helpers.*
import prog8tests.helpers.compileText
class TestArrayInplaceAssign: FunSpec({
test("assign prefix var to array should compile fine and is not split into inplace array modification") {
@ -29,5 +18,64 @@ class TestArrayInplaceAssign: FunSpec({
"""
compileText(C64Target(), false, text, writeAssembly = true) shouldNotBe null
}
test("array in-place negation (integer types)") {
val text = """
%import floats
main {
byte[10] foo
ubyte[10] foou
word[10] foow
uword[10] foowu
float[10] flt
sub start() {
foo[1] = 42
foo[1] = -foo[1]
foow[1] = 4242
foow[1] = -foow[1]
; TODO floating point in-place negation is not yet implemented in the code generator
; flt[1] = 42.42
; flt[1] = -flt[1]
}
}"""
compileText(C64Target(), false, text, writeAssembly = true) shouldNotBe null
}
// TODO implement this in codegen and enable test
xtest("array in-place negation (float type) - ignored for now because not implemented in codegen yet") {
val text = """
%import floats
main {
float[10] flt
sub start() {
flt[1] = 42.42
flt[1] = -flt[1]
}
}"""
compileText(C64Target(), false, text, writeAssembly = true) shouldNotBe null
}
test("array in-place invert") {
val text = """
main {
ubyte[10] foo
uword[10] foow
sub start() {
foo[1] = 42
foo[1] = ~foo[1]
foow[1] = 4242
foow[1] = ~foow[1]
}
}"""
compileText(C64Target(), false, text, writeAssembly = true) shouldNotBe null
}
})

View File

@ -3,7 +3,7 @@ TODO
For next release
^^^^^^^^^^^^^^^^
- fix the array in place assignment issue, see AstOnetimeTransforms
- fix the array in place assignment issue
- ir: asmsub contents remains blank in IR file