mirror of
https://github.com/irmen/prog8.git
synced 2025-01-11 13:29:45 +00:00
fix signed byte to word sign extension in assignment
This commit is contained in:
parent
dd7c9d62e6
commit
893b383bdf
@ -913,8 +913,32 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
is PtTypeCast -> {
|
is PtTypeCast -> {
|
||||||
val castedValue = right.value
|
val castedValue = right.value
|
||||||
if(right.type in WordDatatypes && castedValue.type in ByteDatatypes && castedValue is PtIdentifier) {
|
if(right.type in WordDatatypes && castedValue.type in ByteDatatypes && castedValue is PtIdentifier) {
|
||||||
val castedSymname = asmgen.asmVariableName(castedValue)
|
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)
|
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 == "+")
|
if (expr.operator == "+")
|
||||||
asmgen.out(
|
asmgen.out(
|
||||||
"""
|
"""
|
||||||
@ -933,6 +957,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
dey
|
dey
|
||||||
+"""
|
+"""
|
||||||
)
|
)
|
||||||
|
}
|
||||||
assignRegisterpairWord(target, RegisterOrPair.AY)
|
assignRegisterpairWord(target, RegisterOrPair.AY)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -1844,13 +1869,13 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
assignCastViaLsbFunc(value, target)
|
assignCastViaLsbFunc(value, target)
|
||||||
} else if(valueDt in WordDatatypes && targetDt in WordDatatypes) {
|
} else if(valueDt in WordDatatypes && targetDt in WordDatatypes) {
|
||||||
// word to word, just assign
|
// 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) {
|
} else if(valueDt in ByteDatatypes && targetDt in ByteDatatypes) {
|
||||||
// byte to byte, just assign
|
// 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) {
|
} else if(valueDt in ByteDatatypes && targetDt in WordDatatypes) {
|
||||||
// byte to word, just assign
|
// byte to word, just assign
|
||||||
assignExpressionToRegister(value, target.register!!, targetDt==DataType.WORD)
|
assignExpressionToRegister(value, target.register!!, valueDt==DataType.WORD)
|
||||||
} else
|
} else
|
||||||
throw AssemblyError("can't cast $valueDt to $targetDt, this should have been checked in the astchecker")
|
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) {
|
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)
|
require(sourceDt in WordDatatypes || sourceDt==DataType.UBYTE)
|
||||||
when(target.kind) {
|
when(target.kind) {
|
||||||
TargetStorageKind.VARIABLE -> {
|
TargetStorageKind.VARIABLE -> {
|
||||||
@ -2342,16 +2374,6 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
lda $sourceName+1
|
lda $sourceName+1
|
||||||
sta ${target.asmVarname}+$scaledIdx+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}")
|
else -> throw AssemblyError("weird target variable type ${target.datatype}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2377,20 +2399,6 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
lda $sourceName+1
|
lda $sourceName+1
|
||||||
sta ${target.asmVarname}+1,y""")
|
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")
|
else -> throw AssemblyError("weird dt")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,74 +39,6 @@ internal class BeforeAsmAstChanger(val program: Program, private val options: Co
|
|||||||
return noModifications
|
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> {
|
override fun after(scope: AnonymousScope, parent: Node): Iterable<IAstModification> {
|
||||||
if(scope.statements.any { it is VarDecl || it is IStatementContainer })
|
if(scope.statements.any { it is VarDecl || it is IStatementContainer })
|
||||||
throw FatalAstException("anonymousscope may no longer contain any vardecls or subscopes")
|
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 result2 = compileText(C64Target(), true, text, writeAssembly = true)!!
|
||||||
val stmts2 = result2.compilerAst.entrypoint.statements
|
val stmts2 = result2.compilerAst.entrypoint.statements
|
||||||
stmts2.size shouldBe 6
|
stmts2.size shouldBe 5
|
||||||
val expr2 = (stmts2[4] as Assignment).value as BinaryExpression
|
val expr2 = (stmts2[3] as Assignment).value as BinaryExpression
|
||||||
expr2.operator shouldBe "&"
|
expr2.operator shouldBe "&"
|
||||||
expr2.right shouldBe NumericLiteral(DataType.UBYTE, 1.0, Position.DUMMY)
|
expr2.right shouldBe NumericLiteral(DataType.UBYTE, 1.0, Position.DUMMY)
|
||||||
(expr2.left as IdentifierReference).nameInSource shouldBe listOf("bb")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
test("bool expressions with functioncalls") {
|
test("bool expressions with functioncalls") {
|
||||||
@ -740,7 +739,7 @@ main {
|
|||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
val result = compileText(C64Target(), false, text, writeAssembly = true)!!
|
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") {
|
test("invalid typecasts of numbers") {
|
||||||
|
@ -9,6 +9,7 @@ import io.kotest.matchers.string.shouldStartWith
|
|||||||
import io.kotest.matchers.types.instanceOf
|
import io.kotest.matchers.types.instanceOf
|
||||||
import prog8.code.ast.PtArrayIndexer
|
import prog8.code.ast.PtArrayIndexer
|
||||||
import prog8.code.ast.PtAssignment
|
import prog8.code.ast.PtAssignment
|
||||||
|
import prog8.code.ast.PtBinaryExpression
|
||||||
import prog8.code.ast.PtVariable
|
import prog8.code.ast.PtVariable
|
||||||
import prog8.code.core.DataType
|
import prog8.code.core.DataType
|
||||||
import prog8.code.target.C64Target
|
import prog8.code.target.C64Target
|
||||||
@ -93,7 +94,7 @@ main {
|
|||||||
seed.type shouldBe DataType.ARRAY_UW
|
seed.type shouldBe DataType.ARRAY_UW
|
||||||
val assign = start.children[1] as PtAssignment
|
val assign = start.children[1] as PtAssignment
|
||||||
assign.target.identifier!!.name shouldBe "cx16.r0"
|
assign.target.identifier!!.name shouldBe "cx16.r0"
|
||||||
assign.value shouldBe instanceOf<PtArrayIndexer>()
|
assign.value shouldBe instanceOf<PtBinaryExpression>()
|
||||||
}
|
}
|
||||||
|
|
||||||
test("peek and poke argument types") {
|
test("peek and poke argument types") {
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
TODO
|
TODO
|
||||||
====
|
====
|
||||||
|
|
||||||
- monogfx/gfx2 flood fill is broken after removing the after(assignment: Assignment) from BeforeAsmAstChanger that splits assignments
|
- fix codegen signed byte to word casting issue uw = 8888 + (bb as ubyte)
|
||||||
also other things broken? rectangle? not sure
|
|
||||||
|
|
||||||
- remove after(assignment from BeforeAsmAstChanger permanently once issues above fixed
|
- remove after(assignment from BeforeAsmAstChanger permanently once issues above fixed
|
||||||
- gfx2/monogfx: use vera auto in/decrement in the flood fill routine (getpixels)
|
- gfx2/monogfx: use vera auto in/decrement in the flood fill routine (getpixels)
|
||||||
|
@ -1,10 +1,18 @@
|
|||||||
|
%import textio
|
||||||
%option no_sysinit
|
%option no_sysinit
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
|
|
||||||
main {
|
main {
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
uword xx
|
uword @shared uw = 5555
|
||||||
cx16.r1L = lsb(xx) & 3
|
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…
x
Reference in New Issue
Block a user