mirror of
https://github.com/irmen/prog8.git
synced 2024-12-23 09:32:43 +00:00
fix signed byte to word sign extension in assignment
This commit is contained in:
parent
dd7c9d62e6
commit
893b383bdf
@ -913,10 +913,34 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
is PtTypeCast -> {
|
||||
val castedValue = right.value
|
||||
if(right.type in WordDatatypes && castedValue.type in ByteDatatypes && castedValue is PtIdentifier) {
|
||||
val castedSymname = asmgen.asmVariableName(castedValue)
|
||||
assignExpressionToRegister(left, RegisterOrPair.AY, dt == DataType.WORD)
|
||||
if (expr.operator == "+")
|
||||
asmgen.out(
|
||||
if(right.type in SignedDatatypes) {
|
||||
// we need to sign extend, do this via temporary word variable
|
||||
asmgen.assignExpressionToVariable(right, "P8ZP_SCRATCH_W1", DataType.WORD)
|
||||
assignExpressionToRegister(left, RegisterOrPair.AY, dt == DataType.WORD)
|
||||
if(expr.operator=="+") {
|
||||
asmgen.out("""
|
||||
clc
|
||||
adc P8ZP_SCRATCH_W1
|
||||
tax
|
||||
tya
|
||||
adc P8ZP_SCRATCH_W1+1
|
||||
tay
|
||||
txa""")
|
||||
} else if(expr.operator=="-") {
|
||||
asmgen.out("""
|
||||
sec
|
||||
sbc P8ZP_SCRATCH_W1
|
||||
tax
|
||||
tya
|
||||
sbc P8ZP_SCRATCH_W1+1
|
||||
tay
|
||||
txa""")
|
||||
}
|
||||
} else {
|
||||
assignExpressionToRegister(left, RegisterOrPair.AY, dt == DataType.WORD)
|
||||
val castedSymname = asmgen.asmVariableName(castedValue)
|
||||
if (expr.operator == "+")
|
||||
asmgen.out(
|
||||
"""
|
||||
clc
|
||||
adc $castedSymname
|
||||
@ -924,8 +948,8 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
iny
|
||||
+"""
|
||||
)
|
||||
else
|
||||
asmgen.out(
|
||||
else
|
||||
asmgen.out(
|
||||
"""
|
||||
sec
|
||||
sbc $castedSymname
|
||||
@ -933,6 +957,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
dey
|
||||
+"""
|
||||
)
|
||||
}
|
||||
assignRegisterpairWord(target, RegisterOrPair.AY)
|
||||
return true
|
||||
}
|
||||
@ -1844,13 +1869,13 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
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)
|
||||
assignExpressionToRegister(value, target.register!!, valueDt in SignedDatatypes)
|
||||
} else if(valueDt in ByteDatatypes && targetDt in ByteDatatypes) {
|
||||
// byte to byte, just assign
|
||||
assignExpressionToRegister(value, target.register!!, targetDt==DataType.BYTE || targetDt==DataType.WORD)
|
||||
assignExpressionToRegister(value, target.register!!, valueDt in SignedDatatypes)
|
||||
} else if(valueDt in ByteDatatypes && targetDt in WordDatatypes) {
|
||||
// byte to word, just assign
|
||||
assignExpressionToRegister(value, target.register!!, targetDt==DataType.WORD)
|
||||
assignExpressionToRegister(value, target.register!!, valueDt==DataType.WORD)
|
||||
} else
|
||||
throw AssemblyError("can't cast $valueDt to $targetDt, this should have been checked in the astchecker")
|
||||
}
|
||||
@ -2299,6 +2324,13 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
}
|
||||
|
||||
private fun assignVariableWord(target: AsmAssignTarget, sourceName: String, sourceDt: DataType) {
|
||||
if(sourceDt==DataType.BYTE) {
|
||||
// need to sign extend
|
||||
asmgen.out(" lda $sourceName")
|
||||
asmgen.signExtendAYlsb(DataType.BYTE)
|
||||
assignRegisterpairWord(target, RegisterOrPair.AY)
|
||||
return
|
||||
}
|
||||
require(sourceDt in WordDatatypes || sourceDt==DataType.UBYTE)
|
||||
when(target.kind) {
|
||||
TargetStorageKind.VARIABLE -> {
|
||||
@ -2342,16 +2374,6 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
lda $sourceName+1
|
||||
sta ${target.asmVarname}+$scaledIdx+1""")
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
asmgen.out("""
|
||||
lda #<$sourceName
|
||||
ldy #>$sourceName
|
||||
sta P8ZP_SCRATCH_W1
|
||||
sty P8ZP_SCRATCH_W1+1
|
||||
lda #<(${target.asmVarname}+$scaledIdx)
|
||||
ldy #>(${target.asmVarname}+$scaledIdx)
|
||||
jsr floats.copy_float""")
|
||||
}
|
||||
else -> throw AssemblyError("weird target variable type ${target.datatype}")
|
||||
}
|
||||
}
|
||||
@ -2377,20 +2399,6 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
lda $sourceName+1
|
||||
sta ${target.asmVarname}+1,y""")
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
asmgen.loadScaledArrayIndexIntoRegister(target.array, target.datatype, CpuRegister.A)
|
||||
asmgen.out("""
|
||||
ldy #<$sourceName
|
||||
sty P8ZP_SCRATCH_W1
|
||||
ldy #>$sourceName
|
||||
sty P8ZP_SCRATCH_W1+1
|
||||
ldy #>${target.asmVarname}
|
||||
clc
|
||||
adc #<${target.asmVarname}
|
||||
bcc +
|
||||
iny
|
||||
+ jsr floats.copy_float""")
|
||||
}
|
||||
else -> throw AssemblyError("weird dt")
|
||||
}
|
||||
}
|
||||
|
@ -39,74 +39,6 @@ internal class BeforeAsmAstChanger(val program: Program, private val options: Co
|
||||
return noModifications
|
||||
}
|
||||
|
||||
/* TODO remove permanently:
|
||||
override fun after(assignment: Assignment, parent: Node): Iterable<IAstModification> {
|
||||
// Try to replace A = B <operator> Something by A= B, A = A <operator> Something
|
||||
// this triggers the more efficent augmented assignment code generation more often.
|
||||
// But it can only be done if the target variable IS NOT OCCURRING AS AN OPERAND ITSELF.
|
||||
|
||||
if(options.compTarget.name==VMTarget.NAME) // don't apply this optimization for Vm target
|
||||
return noModifications
|
||||
|
||||
if(!assignment.isAugmentable
|
||||
&& assignment.target.identifier != null
|
||||
&& !assignment.target.isIOAddress(options.compTarget.machine)) {
|
||||
val binExpr = assignment.value as? BinaryExpression
|
||||
|
||||
if (binExpr != null && binExpr.operator !in ComparisonOperators) {
|
||||
if (binExpr.left !is BinaryExpression) {
|
||||
if (binExpr.right.referencesIdentifier(assignment.target.identifier!!.nameInSource)) {
|
||||
// the right part of the expression contains the target variable itself.
|
||||
// we can't 'split' it trivially because the variable will be changed halfway through.
|
||||
if(binExpr.operator in AssociativeOperators) {
|
||||
// A = <something-without-A> <associativeoperator> <otherthing-with-A>
|
||||
// use the other part of the expression to split.
|
||||
val sourceDt = binExpr.right.inferType(program).getOrElse { throw AssemblyError("unknown dt") }
|
||||
val (_, right) = binExpr.right.typecastTo(assignment.target.inferType(program).getOrElse { throw AssemblyError(
|
||||
"unknown dt"
|
||||
)
|
||||
}, sourceDt, implicit=true)
|
||||
val assignRight = Assignment(assignment.target, right, AssignmentOrigin.ASMGEN, assignment.position)
|
||||
return listOf(
|
||||
IAstModification.InsertBefore(assignment, assignRight, parent as IStatementContainer),
|
||||
IAstModification.ReplaceNode(binExpr.right, binExpr.left, binExpr),
|
||||
IAstModification.ReplaceNode(binExpr.left, assignment.target.toExpression(), binExpr)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
if(binExpr.left isSameAs assignment.target)
|
||||
return noModifications
|
||||
val typeCast = binExpr.left as? TypecastExpression
|
||||
if(typeCast!=null && typeCast.expression isSameAs assignment.target)
|
||||
return noModifications
|
||||
|
||||
if(binExpr.operator in "+-") {
|
||||
val leftDt = binExpr.left.inferType(program)
|
||||
val rightDt = binExpr.right.inferType(program)
|
||||
if(leftDt==rightDt && leftDt.isInteger && rightDt.isInteger && binExpr.right is ArrayIndexedExpression) {
|
||||
// don't split array[i] +/- array[i] (the codegen has an optimized path for this)
|
||||
return noModifications
|
||||
}
|
||||
}
|
||||
|
||||
val sourceDt = binExpr.left.inferType(program).getOrElse { throw AssemblyError("unknown dt") }
|
||||
val (_, left) = binExpr.left.typecastTo(assignment.target.inferType(program).getOrElse { throw AssemblyError(
|
||||
"unknown dt"
|
||||
)
|
||||
}, sourceDt, implicit=true)
|
||||
val assignLeft = Assignment(assignment.target, left, AssignmentOrigin.ASMGEN, assignment.position)
|
||||
return listOf(
|
||||
IAstModification.InsertBefore(assignment, assignLeft, parent as IStatementContainer),
|
||||
IAstModification.ReplaceNode(binExpr.left, assignment.target.toExpression(), binExpr)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return noModifications
|
||||
}
|
||||
*/
|
||||
|
||||
override fun after(scope: AnonymousScope, parent: Node): Iterable<IAstModification> {
|
||||
if(scope.statements.any { it is VarDecl || it is IStatementContainer })
|
||||
throw FatalAstException("anonymousscope may no longer contain any vardecls or subscopes")
|
||||
|
@ -58,11 +58,10 @@ class TestTypecasts: FunSpec({
|
||||
|
||||
val result2 = compileText(C64Target(), true, text, writeAssembly = true)!!
|
||||
val stmts2 = result2.compilerAst.entrypoint.statements
|
||||
stmts2.size shouldBe 6
|
||||
val expr2 = (stmts2[4] as Assignment).value as BinaryExpression
|
||||
stmts2.size shouldBe 5
|
||||
val expr2 = (stmts2[3] as Assignment).value as BinaryExpression
|
||||
expr2.operator shouldBe "&"
|
||||
expr2.right shouldBe NumericLiteral(DataType.UBYTE, 1.0, Position.DUMMY)
|
||||
(expr2.left as IdentifierReference).nameInSource shouldBe listOf("bb")
|
||||
}
|
||||
|
||||
test("bool expressions with functioncalls") {
|
||||
@ -740,7 +739,7 @@ main {
|
||||
}
|
||||
"""
|
||||
val result = compileText(C64Target(), false, text, writeAssembly = true)!!
|
||||
result.compilerAst.entrypoint.statements.size shouldBe 15
|
||||
result.compilerAst.entrypoint.statements.size shouldBe 14
|
||||
}
|
||||
|
||||
test("invalid typecasts of numbers") {
|
||||
|
@ -9,6 +9,7 @@ import io.kotest.matchers.string.shouldStartWith
|
||||
import io.kotest.matchers.types.instanceOf
|
||||
import prog8.code.ast.PtArrayIndexer
|
||||
import prog8.code.ast.PtAssignment
|
||||
import prog8.code.ast.PtBinaryExpression
|
||||
import prog8.code.ast.PtVariable
|
||||
import prog8.code.core.DataType
|
||||
import prog8.code.target.C64Target
|
||||
@ -93,7 +94,7 @@ main {
|
||||
seed.type shouldBe DataType.ARRAY_UW
|
||||
val assign = start.children[1] as PtAssignment
|
||||
assign.target.identifier!!.name shouldBe "cx16.r0"
|
||||
assign.value shouldBe instanceOf<PtArrayIndexer>()
|
||||
assign.value shouldBe instanceOf<PtBinaryExpression>()
|
||||
}
|
||||
|
||||
test("peek and poke argument types") {
|
||||
|
@ -1,8 +1,7 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
- monogfx/gfx2 flood fill is broken after removing the after(assignment: Assignment) from BeforeAsmAstChanger that splits assignments
|
||||
also other things broken? rectangle? not sure
|
||||
- fix codegen signed byte to word casting issue uw = 8888 + (bb as ubyte)
|
||||
|
||||
- remove after(assignment from BeforeAsmAstChanger permanently once issues above fixed
|
||||
- gfx2/monogfx: use vera auto in/decrement in the flood fill routine (getpixels)
|
||||
|
@ -1,10 +1,18 @@
|
||||
%import textio
|
||||
%option no_sysinit
|
||||
%zeropage basicsafe
|
||||
|
||||
main {
|
||||
|
||||
sub start() {
|
||||
uword xx
|
||||
cx16.r1L = lsb(xx) & 3
|
||||
uword @shared uw = 5555
|
||||
byte @shared bb = -44
|
||||
|
||||
uw = (bb as ubyte) as uword
|
||||
txt.print_uw(uw) ; 212
|
||||
txt.nl()
|
||||
|
||||
uw = 8888 + (bb as ubyte) ; TODO fix 6502 codegen
|
||||
txt.print_uw(uw) ; 9100
|
||||
txt.nl()
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user