mirror of
https://github.com/irmen/prog8.git
synced 2025-01-10 20:30:23 +00:00
allow "not xx in array" expression in 6502 codegen
fix compiler crash on certain bool to byte casts
This commit is contained in:
parent
d0e6a2eb8b
commit
ded9ada9bc
@ -873,20 +873,20 @@ internal class AssignmentAsmGen(private val program: Program,
|
||||
throw AssemblyError("containment check of floats not supported")
|
||||
}
|
||||
DataType.ARRAY_B, DataType.ARRAY_UB -> {
|
||||
val arrayVal = variable.value as ArrayLiteral
|
||||
val numElements = variable.arraysize!!.constIndex()!!
|
||||
assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt istype DataType.BYTE)
|
||||
asmgen.saveRegisterLocal(CpuRegister.A, containment.definingSubroutine!!)
|
||||
assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingSubroutine, "P8ZP_SCRATCH_W1"), varname)
|
||||
asmgen.restoreRegisterLocal(CpuRegister.A)
|
||||
asmgen.out(" ldy #${arrayVal.value.size}")
|
||||
asmgen.out(" ldy #$numElements")
|
||||
asmgen.out(" jsr prog8_lib.containment_bytearray")
|
||||
return
|
||||
}
|
||||
DataType.ARRAY_W, DataType.ARRAY_UW -> {
|
||||
val arrayVal = variable.value as ArrayLiteral
|
||||
val numElements = variable.arraysize!!.constIndex()!!
|
||||
assignExpressionToVariable(containment.element, "P8ZP_SCRATCH_W1", elementDt.getOr(DataType.UNDEFINED), containment.definingSubroutine)
|
||||
assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingSubroutine, "P8ZP_SCRATCH_W2"), varname)
|
||||
asmgen.out(" ldy #${arrayVal.value.size}")
|
||||
asmgen.out(" ldy #$numElements")
|
||||
asmgen.out(" jsr prog8_lib.containment_wordarray")
|
||||
return
|
||||
}
|
||||
@ -1005,7 +1005,7 @@ internal class AssignmentAsmGen(private val program: Program,
|
||||
}
|
||||
}
|
||||
|
||||
if(valueDt==DataType.UBYTE) {
|
||||
if(valueDt==DataType.UBYTE || valueDt==DataType.BOOL) {
|
||||
when(target.register) {
|
||||
RegisterOrPair.A,
|
||||
RegisterOrPair.X,
|
||||
@ -1069,8 +1069,10 @@ internal class AssignmentAsmGen(private val program: Program,
|
||||
}
|
||||
}
|
||||
|
||||
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}"}
|
||||
if(targetDt in IntegerDatatypes && valueDt in IntegerDatatypes && valueDt!=targetDt && 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.
|
||||
@ -1136,13 +1138,12 @@ internal class AssignmentAsmGen(private val program: Program,
|
||||
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
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
private fun assignCastViaLsbFunc(value: Expression, target: AsmAssignTarget) {
|
||||
|
@ -7,6 +7,7 @@ import prog8.ast.expressions.*
|
||||
import prog8.ast.statements.*
|
||||
import prog8.ast.walk.IAstVisitor
|
||||
import prog8.code.core.*
|
||||
import prog8.code.target.VMTarget
|
||||
import prog8.compiler.BuiltinFunctions
|
||||
import prog8.compiler.InplaceModifyingBuiltinFunctions
|
||||
import prog8.compiler.builtinFunctionReturnType
|
||||
@ -1259,8 +1260,14 @@ internal class AstChecker(private val program: Program,
|
||||
val elementDt = containment.element.inferType(program)
|
||||
val iterableDt = containment.iterable.inferType(program)
|
||||
|
||||
if(containment.parent is BinaryExpression)
|
||||
errors.err("containment check is currently not supported inside complex expressions", containment.position)
|
||||
if(compilerOptions.compTarget.name!=VMTarget.NAME) {
|
||||
val parentBinexpr = containment.parent as? BinaryExpression
|
||||
if(parentBinexpr!=null) {
|
||||
// only supported if compared to 1 or 0, more complex expressions aren't supported in the 6502 code-gen.
|
||||
if(parentBinexpr.operator!="==" || parentBinexpr.right.constValue(program)?.number !in listOf(0.0, 1.0))
|
||||
errors.err("containment check is currently not supported inside complex expressions", containment.position)
|
||||
}
|
||||
}
|
||||
|
||||
if(iterableDt.isIterable && containment.iterable !is RangeExpression) {
|
||||
val iterableEltDt = ArrayToElementTypes.getValue(iterableDt.getOr(DataType.UNDEFINED))
|
||||
|
@ -6,10 +6,7 @@ import prog8.ast.Node
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.FatalAstException
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.statements.AnonymousScope
|
||||
import prog8.ast.statements.Assignment
|
||||
import prog8.ast.statements.ConditionalBranch
|
||||
import prog8.ast.statements.IfElse
|
||||
import prog8.ast.statements.*
|
||||
import prog8.ast.walk.AstWalker
|
||||
import prog8.ast.walk.IAstModification
|
||||
import prog8.code.core.*
|
||||
@ -175,6 +172,19 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
|
||||
return noModifications
|
||||
}
|
||||
|
||||
fun checkArray(variable: VarDecl): Iterable<IAstModification> {
|
||||
return if(variable.value==null) {
|
||||
val arraySpec = variable.arraysize!!
|
||||
val size = arraySpec.indexExpr.constValue(program)?.number?.toInt() ?: throw FatalAstException("no array size")
|
||||
return if(size==0)
|
||||
replaceWithFalse()
|
||||
else
|
||||
noModifications
|
||||
}
|
||||
else
|
||||
checkArray((variable.value as ArrayLiteral).value)
|
||||
}
|
||||
|
||||
fun checkString(stringVal: StringLiteral): Iterable<IAstModification> {
|
||||
if(stringVal.value.isEmpty())
|
||||
return replaceWithFalse()
|
||||
@ -198,8 +208,7 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
|
||||
return checkString(stringVal)
|
||||
}
|
||||
in ArrayDatatypes -> {
|
||||
val array = (variable.value as ArrayLiteral).value
|
||||
return checkArray(array)
|
||||
return checkArray(variable)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
|
22
compiler/test/codegeneration/TestVarious.kt
Normal file
22
compiler/test/codegeneration/TestVarious.kt
Normal file
@ -0,0 +1,22 @@
|
||||
package prog8tests.codegeneration
|
||||
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
import io.kotest.matchers.shouldNotBe
|
||||
import prog8.code.target.C64Target
|
||||
import prog8tests.helpers.compileText
|
||||
|
||||
class TestVarious: FunSpec({
|
||||
test("bool to byte cast in expression is correct") {
|
||||
val text="""
|
||||
main {
|
||||
sub start() {
|
||||
ubyte[3] values
|
||||
func(33 + (22 in values))
|
||||
}
|
||||
sub func(ubyte arg) {
|
||||
arg++
|
||||
}
|
||||
}"""
|
||||
compileText(C64Target(), false, text, writeAssembly = true) shouldNotBe null
|
||||
}
|
||||
})
|
@ -327,4 +327,19 @@ main {
|
||||
instructions.size shouldBe 18
|
||||
instructions.last().opcode shouldBe Opcode.RETURN
|
||||
}
|
||||
|
||||
test("compile virtual: various expressions") {
|
||||
val text="""
|
||||
main {
|
||||
sub start() {
|
||||
ubyte[3] values = [1,2,3]
|
||||
func(33 + (22 in values)) ; bool cast to byte
|
||||
func(values[cx16.r0L] + (22 in values)) ; containment in complex expression
|
||||
}
|
||||
sub func(ubyte arg) {
|
||||
arg++
|
||||
}
|
||||
}"""
|
||||
compileText(VMTarget(), false, text, writeAssembly = true) shouldNotBe null
|
||||
}
|
||||
})
|
@ -3,12 +3,12 @@ TODO
|
||||
|
||||
For next release
|
||||
^^^^^^^^^^^^^^^^
|
||||
- bool bb = not bb -> larger code than bool bb ^= 1
|
||||
- bool xx = ~xx -> larger code than xx ^= 1
|
||||
- ubyte xx = not xx -> much larger code than xx ^= 1
|
||||
- try to support "not (xx in array)" or maybe even "xx not in array"
|
||||
- astchecker: "containment check is currently not supported inside complex expressions" fix this?
|
||||
or at least disable this check for virtual target?
|
||||
- allow "xx not in array" and rewrite it into "not xx in array"
|
||||
- make sure bool value is always 0 or 1 (all casts should convert), then:
|
||||
- rewrite bool=bool^1 into bool=not bool
|
||||
- should solve: bool bb = not bb -> larger code than bool bb ^= 1
|
||||
- should solve: bool xx = ~xx -> larger code than xx ^= 1
|
||||
|
||||
|
||||
...
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user