vm: fix expression codegen for pointer indexing

This commit is contained in:
Irmen de Jong 2022-06-04 19:32:35 +02:00
parent 8618ba1b60
commit 1e61d84fd1
6 changed files with 49 additions and 137 deletions

View File

@ -159,6 +159,19 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
val variable = array.variable.targetName
var variableAddr = codeGen.allocations.get(variable)
val itemsize = codeGen.program.memsizer.memorySize(array.type)
if(array.variable.type==DataType.UWORD) {
// indexing a pointer var instead of a real array or string
if(itemsize!=1)
throw AssemblyError("non-array var indexing requires bytes dt")
if(array.index.type!=DataType.UBYTE)
throw AssemblyError("non-array var indexing requires bytes index")
val idxReg = codeGen.vmRegisters.nextFree()
code += expressionEval.translateExpression(array.index, idxReg, -1)
code += VmCodeInstruction(Opcode.LOADIX, vmDt, reg1=resultRegister, reg2=idxReg, value = variableAddr)
return code
}
val fixedIndex = constIntValue(array.index)
if(zero) {
if(fixedIndex!=null) {

View File

@ -154,6 +154,8 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
// indexing a pointer var instead of a real array or string
if(eltSize!=1)
throw AssemblyError("non-array var indexing requires bytes dt")
if(arrayIx.index.type!=DataType.UBYTE)
throw AssemblyError("non-array var indexing requires bytes index")
code += translateExpression(arrayIx.index, idxReg, -1)
code += VmCodeInstruction(Opcode.LOADIX, vmDt, reg1=resultRegister, reg2=idxReg, value = arrayLocation)
return code

View File

@ -45,17 +45,19 @@ internal class AstOnetimeTransforms(private val program: Program, private val op
} else {
val fcall = parent as? IFunctionCall
if(fcall!=null) {
if(fcall.target.nameInSource.size==1 && fcall.target.nameInSource[0] in InplaceModifyingBuiltinFunctions) {
// TODO for now, swap() etc don't work on pointer var indexed args, so still replace this
if(options.compTarget.name != VMTarget.NAME) {
// TODO for now, 6502 codegen seems wrong when using pointer indexed args to any function.
val memread = DirectMemoryRead(add, arrayIndexedExpression.position)
return listOf(IAstModification.ReplaceNode(arrayIndexedExpression, memread, parent))
} else if(fcall.target.nameInSource.size==1 && fcall.target.nameInSource[0] in InplaceModifyingBuiltinFunctions) {
// TODO for now, vm codegen seems wrong when using pointer indexed args to an in-place modifying function.
val memread = DirectMemoryRead(add, arrayIndexedExpression.position)
return listOf(IAstModification.ReplaceNode(arrayIndexedExpression, memread, parent))
} else {
println("PTR INDEX 1: $arrayIndexedExpression PARENT=${parent.javaClass}") // TODO
return noModifications
}
}
else {
println("PTR INDEX 2: $arrayIndexedExpression PARENT=${parent.javaClass}") // TODO
return noModifications
}
}

View File

@ -3,13 +3,9 @@ package prog8tests
import io.kotest.assertions.withClue
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe
import io.kotest.matchers.string.shouldContain
import io.kotest.matchers.types.instanceOf
import prog8.ast.expressions.BinaryExpression
import prog8.ast.expressions.DirectMemoryRead
import prog8.ast.expressions.IdentifierReference
import prog8.ast.expressions.NumericLiteral
import prog8.ast.statements.*
import prog8.code.core.DataType
import prog8.code.target.C64Target
@ -192,81 +188,6 @@ class TestSubroutines: FunSpec({
errors.errors[1] shouldContain "pass-by-reference type can't be used"
}
test("uword param and normal varindexed as array work as DirectMemoryRead") {
val text="""
main {
sub thing(uword rr) {
ubyte @shared xx = rr[1] ; should still work as var initializer that will be rewritten
ubyte @shared yy
yy = rr[2]
uword @shared other
ubyte zz = other[3]
}
sub start() {
ubyte[] array=[1,2,3]
thing(array)
}
}
"""
val result = compileText(C64Target(), false, text, writeAssembly = true)!!
val module = result.program.toplevelModule
val block = module.statements.single() as Block
val thing = block.statements.filterIsInstance<Subroutine>().single {it.name=="thing"}
block.name shouldBe "main"
thing.statements.size shouldBe 10 // rr paramdecl, xx, xx assign, yy decl, yy assign, other, other assign 0, zz, zz assign, return
val xx = thing.statements[1] as VarDecl
withClue("vardecl init values must have been moved to separate assignments") {
xx.value shouldBe null
}
val assignXX = thing.statements[2] as Assignment
val assignYY = thing.statements[4] as Assignment
val assignZZ = thing.statements[8] as Assignment
assignXX.target.identifier!!.nameInSource shouldBe listOf("xx")
assignYY.target.identifier!!.nameInSource shouldBe listOf("yy")
assignZZ.target.identifier!!.nameInSource shouldBe listOf("zz")
val valueXXexpr = (assignXX.value as DirectMemoryRead).addressExpression as BinaryExpression
val valueYYexpr = (assignYY.value as DirectMemoryRead).addressExpression as BinaryExpression
val valueZZexpr = (assignZZ.value as DirectMemoryRead).addressExpression as BinaryExpression
(valueXXexpr.left as IdentifierReference).nameInSource shouldBe listOf("rr")
(valueYYexpr.left as IdentifierReference).nameInSource shouldBe listOf("rr")
(valueZZexpr.left as IdentifierReference).nameInSource shouldBe listOf("other")
(valueXXexpr.right as NumericLiteral).number.toInt() shouldBe 1
(valueYYexpr.right as NumericLiteral).number.toInt() shouldBe 2
(valueZZexpr.right as NumericLiteral).number.toInt() shouldBe 3
}
test("uword param and normal varindexed as array work as MemoryWrite") {
val text="""
main {
sub thing(uword rr) {
rr[10] = 42
}
sub start() {
ubyte[] array=[1,2,3]
thing(array)
}
}
"""
val result = compileText(C64Target(), false, text, writeAssembly = true)!!
val module = result.program.toplevelModule
val block = module.statements.single() as Block
val thing = block.statements.filterIsInstance<Subroutine>().single {it.name=="thing"}
block.name shouldBe "main"
thing.statements.size shouldBe 3 // "rr, rr assign, return void"
val assignRR = thing.statements[1] as Assignment
(assignRR.value as NumericLiteral).number.toInt() shouldBe 42
val memwrite = assignRR.target.memoryAddress
memwrite shouldNotBe null
val addressExpr = memwrite!!.addressExpression as BinaryExpression
(addressExpr.left as IdentifierReference).nameInSource shouldBe listOf("rr")
addressExpr.operator shouldBe "+"
(addressExpr.right as NumericLiteral).number.toInt() shouldBe 10
}
test("invalid number of args check on normal subroutine") {
val text="""
main {

View File

@ -3,18 +3,7 @@ TODO
For next release
^^^^^^^^^^^^^^^^
- fix pointervar indexing 6502 codegen (AssignmentAsmGen translateNormalAssignment) -> gridcommander worm doesn't move
- is this code still so much larger:
uword xx
for xx in 0 to size-1 {
gfx2.next_pixel(bitmapbuf[xx])
}
than this loop:
uword srcptr = bitmapbuf
repeat size {
gfx2.next_pixel(@(srcptr))
srcptr++
}
- BUG in 6502 codegen: ubyte one = 1 | value = one+one+one+one+one is not 5
- optimize pointervar indexing codegen: writing (all sorts of things)
- pipe operator: (targets other than 'Virtual'): allow non-unary function calls in the pipe that specify the other argument(s) in the calls. Already working for VM target.

View File

@ -39,31 +39,34 @@ main {
txt.print_ub(value) ;; 33
txt.nl()
; ; 11 22 33
; txt.print_ub(bitmapbuf[0])
; txt.spc()
; txt.print_ub(bitmapbuf[1])
; txt.spc()
; txt.print_ub(bitmapbuf[2])
; txt.nl()
; rol(bitmapbuf[0])
; rol(bitmapbuf[0])
; txt.print_ub(bitmapbuf[0]) ; 44
; txt.spc()
; ror(bitmapbuf[0])
; ror(bitmapbuf[0])
; txt.print_ub(bitmapbuf[0]) ; 11
; txt.nl()
;
; ; 22 44 66
; txt.print_ub(bitmapbuf[0]*2)
; txt.spc()
; txt.print_ub(bitmapbuf[1]*2)
; txt.spc()
; txt.print_ub(bitmapbuf[2]*2)
; txt.nl()
; 11 22 33
txt.print_ub(bitmapbuf[0])
txt.spc()
txt.print_ub(bitmapbuf[1])
txt.spc()
txt.print_ub(bitmapbuf[2])
txt.nl()
rol(bitmapbuf[0])
rol(bitmapbuf[0])
txt.print_ub(bitmapbuf[0]) ; 44
txt.spc()
ror(bitmapbuf[0])
ror(bitmapbuf[0])
txt.print_ub(bitmapbuf[0]) ; 11
txt.nl()
; 22 44 66
txt.print_ub(bitmapbuf[0]*2)
txt.spc()
txt.print_ub(bitmapbuf[1]*2)
txt.spc()
txt.print_ub(bitmapbuf[2]*2)
txt.nl()
ubyte one = 1
value = one+one+one+one+one
txt.print_ub(value) ; 5
txt.nl()
bitmapbuf[0] = one
bitmapbuf[1] = one+one
@ -73,7 +76,7 @@ main {
bitmapbuf[2] -= 2
swap(bitmapbuf[0], bitmapbuf[1])
; 1 2 3
; 2 1 3
txt.print_ub(bitmapbuf[0])
txt.spc()
txt.print_ub(bitmapbuf[1])
@ -87,24 +90,6 @@ main {
}
txt.nl()
; TODO why is this loop much larger in code than the one below.
value = 0
ubyte xx
for xx in 0 to size-1 {
value += bitmapbuf[xx]
}
txt.print_ub(value) ; 45
txt.nl()
; TODO this one is much more compact
value = 0
uword srcptr = bitmapbuf
repeat size {
value += @(srcptr)
srcptr++
}
txt.print_ub(value) ; 45
txt.nl()
; ; a "pixelshader":
; sys.gfx_enable(0) ; enable lo res screen