mirror of
https://github.com/irmen/prog8.git
synced 2025-02-27 03:29:22 +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")
|
throw AssemblyError("containment check of floats not supported")
|
||||||
}
|
}
|
||||||
DataType.ARRAY_B, DataType.ARRAY_UB -> {
|
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)
|
assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt istype DataType.BYTE)
|
||||||
asmgen.saveRegisterLocal(CpuRegister.A, containment.definingSubroutine!!)
|
asmgen.saveRegisterLocal(CpuRegister.A, containment.definingSubroutine!!)
|
||||||
assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingSubroutine, "P8ZP_SCRATCH_W1"), varname)
|
assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingSubroutine, "P8ZP_SCRATCH_W1"), varname)
|
||||||
asmgen.restoreRegisterLocal(CpuRegister.A)
|
asmgen.restoreRegisterLocal(CpuRegister.A)
|
||||||
asmgen.out(" ldy #${arrayVal.value.size}")
|
asmgen.out(" ldy #$numElements")
|
||||||
asmgen.out(" jsr prog8_lib.containment_bytearray")
|
asmgen.out(" jsr prog8_lib.containment_bytearray")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
DataType.ARRAY_W, DataType.ARRAY_UW -> {
|
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)
|
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)
|
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")
|
asmgen.out(" jsr prog8_lib.containment_wordarray")
|
||||||
return
|
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) {
|
when(target.register) {
|
||||||
RegisterOrPair.A,
|
RegisterOrPair.A,
|
||||||
RegisterOrPair.X,
|
RegisterOrPair.X,
|
||||||
@ -1069,8 +1069,10 @@ internal class AssignmentAsmGen(private val program: Program,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(targetDt in IntegerDatatypes && valueDt in IntegerDatatypes && valueDt.isAssignableTo(targetDt)) {
|
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}"}
|
require(targetDt in WordDatatypes && valueDt in ByteDatatypes) {
|
||||||
|
"should be byte to word assignment ${origTypeCastExpression.position}"
|
||||||
|
}
|
||||||
when(target.kind) {
|
when(target.kind) {
|
||||||
// TargetStorageKind.VARIABLE -> {
|
// TargetStorageKind.VARIABLE -> {
|
||||||
// This has been handled already earlier on line 961.
|
// 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")
|
asmgen.out(" jsr floats.MOVEF")
|
||||||
}
|
}
|
||||||
return
|
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) {
|
private fun assignCastViaLsbFunc(value: Expression, target: AsmAssignTarget) {
|
||||||
|
@ -7,6 +7,7 @@ import prog8.ast.expressions.*
|
|||||||
import prog8.ast.statements.*
|
import prog8.ast.statements.*
|
||||||
import prog8.ast.walk.IAstVisitor
|
import prog8.ast.walk.IAstVisitor
|
||||||
import prog8.code.core.*
|
import prog8.code.core.*
|
||||||
|
import prog8.code.target.VMTarget
|
||||||
import prog8.compiler.BuiltinFunctions
|
import prog8.compiler.BuiltinFunctions
|
||||||
import prog8.compiler.InplaceModifyingBuiltinFunctions
|
import prog8.compiler.InplaceModifyingBuiltinFunctions
|
||||||
import prog8.compiler.builtinFunctionReturnType
|
import prog8.compiler.builtinFunctionReturnType
|
||||||
@ -1259,8 +1260,14 @@ internal class AstChecker(private val program: Program,
|
|||||||
val elementDt = containment.element.inferType(program)
|
val elementDt = containment.element.inferType(program)
|
||||||
val iterableDt = containment.iterable.inferType(program)
|
val iterableDt = containment.iterable.inferType(program)
|
||||||
|
|
||||||
if(containment.parent is BinaryExpression)
|
if(compilerOptions.compTarget.name!=VMTarget.NAME) {
|
||||||
errors.err("containment check is currently not supported inside complex expressions", containment.position)
|
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) {
|
if(iterableDt.isIterable && containment.iterable !is RangeExpression) {
|
||||||
val iterableEltDt = ArrayToElementTypes.getValue(iterableDt.getOr(DataType.UNDEFINED))
|
val iterableEltDt = ArrayToElementTypes.getValue(iterableDt.getOr(DataType.UNDEFINED))
|
||||||
|
@ -6,10 +6,7 @@ import prog8.ast.Node
|
|||||||
import prog8.ast.Program
|
import prog8.ast.Program
|
||||||
import prog8.ast.base.FatalAstException
|
import prog8.ast.base.FatalAstException
|
||||||
import prog8.ast.expressions.*
|
import prog8.ast.expressions.*
|
||||||
import prog8.ast.statements.AnonymousScope
|
import prog8.ast.statements.*
|
||||||
import prog8.ast.statements.Assignment
|
|
||||||
import prog8.ast.statements.ConditionalBranch
|
|
||||||
import prog8.ast.statements.IfElse
|
|
||||||
import prog8.ast.walk.AstWalker
|
import prog8.ast.walk.AstWalker
|
||||||
import prog8.ast.walk.IAstModification
|
import prog8.ast.walk.IAstModification
|
||||||
import prog8.code.core.*
|
import prog8.code.core.*
|
||||||
@ -175,6 +172,19 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
|
|||||||
return noModifications
|
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> {
|
fun checkString(stringVal: StringLiteral): Iterable<IAstModification> {
|
||||||
if(stringVal.value.isEmpty())
|
if(stringVal.value.isEmpty())
|
||||||
return replaceWithFalse()
|
return replaceWithFalse()
|
||||||
@ -198,8 +208,7 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
|
|||||||
return checkString(stringVal)
|
return checkString(stringVal)
|
||||||
}
|
}
|
||||||
in ArrayDatatypes -> {
|
in ArrayDatatypes -> {
|
||||||
val array = (variable.value as ArrayLiteral).value
|
return checkArray(variable)
|
||||||
return checkArray(array)
|
|
||||||
}
|
}
|
||||||
else -> {}
|
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.size shouldBe 18
|
||||||
instructions.last().opcode shouldBe Opcode.RETURN
|
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
|
For next release
|
||||||
^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^
|
||||||
- bool bb = not bb -> larger code than bool bb ^= 1
|
- allow "xx not in array" and rewrite it into "not xx in array"
|
||||||
- bool xx = ~xx -> larger code than xx ^= 1
|
- make sure bool value is always 0 or 1 (all casts should convert), then:
|
||||||
- ubyte xx = not xx -> much larger code than xx ^= 1
|
- rewrite bool=bool^1 into bool=not bool
|
||||||
- try to support "not (xx in array)" or maybe even "xx not in array"
|
- should solve: bool bb = not bb -> larger code than bool bb ^= 1
|
||||||
- astchecker: "containment check is currently not supported inside complex expressions" fix this?
|
- should solve: bool xx = ~xx -> larger code than xx ^= 1
|
||||||
or at least disable this check for virtual target?
|
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user