working on vm

This commit is contained in:
Irmen de Jong 2022-03-28 00:18:56 +02:00
parent 30cbb6c9a8
commit bb1bf6a88c
12 changed files with 121 additions and 81 deletions

View File

@ -119,7 +119,7 @@ open class StNode(val name: String,
}
}
protected fun printIndented(indent: Int) {
fun printIndented(indent: Int) {
print(" ".repeat(indent))
when(type) {
StNodeType.GLOBAL -> print("SYMBOL-TABLE:")
@ -152,21 +152,24 @@ class StStaticVariable(name: String,
val initialNumericValue: Double?,
val initialStringValue: StString?,
val initialArrayValue: StArray?,
val arraysize: Int?,
val length: Int?, // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte
val zpwish: ZeropageWish,
position: Position) : StNode(name, StNodeType.STATICVAR, position) {
init {
if(arraysize!=null && initialArrayValue!=null)
require(arraysize == initialArrayValue.size)
if(arraysize!=null || initialArrayValue!=null)
require(initialStringValue==null && initialNumericValue==null)
if(length!=null) {
require(initialNumericValue == null)
if(initialArrayValue!=null)
require(length == initialArrayValue.size)
}
if(initialNumericValue!=null)
require(dt in NumericDatatypes)
if(initialArrayValue!=null || arraysize!=null)
if(initialArrayValue!=null)
require(dt in ArrayDatatypes)
if(initialStringValue!=null)
if(initialStringValue!=null) {
require(dt == DataType.STR)
require(length == initialStringValue.first.length+1)
}
}
override fun printProperties() {

View File

@ -11,7 +11,7 @@ sealed class PtNode(val position: Position) {
val children = mutableListOf<PtNode>()
lateinit var parent: PtNode
protected fun printIndented(indent: Int) {
fun printIndented(indent: Int) {
print(" ".repeat(indent))
print("${this.javaClass.simpleName} ")
printProperties()

View File

@ -480,7 +480,7 @@ internal class ProgramAndVarsGen(
DataType.STR -> {
throw AssemblyError("all string vars should have been interned into prog")
}
in ArrayDatatypes -> arrayVariable2asm(name, variable.dt, variable.initialArrayValue, variable.arraysize)
in ArrayDatatypes -> arrayVariable2asm(name, variable.dt, variable.initialArrayValue, variable.length)
else -> {
throw AssemblyError("weird dt")
}

View File

@ -63,11 +63,10 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
var numberOfNonIntegerVariables = 0
varsRequiringZp.forEach { variable ->
val numElements = numArrayElements(variable)
val result = zeropage.allocate(
variable.scopedName,
variable.dt,
numElements,
variable.length,
variable.position,
errors
)
@ -83,11 +82,10 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
if(errors.noErrors()) {
varsPreferringZp.forEach { variable ->
val numElements = numArrayElements(variable)
val result = zeropage.allocate(
variable.scopedName,
variable.dt,
numElements,
variable.length,
variable.position,
errors
)
@ -103,11 +101,10 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
if(zeropage.free.isEmpty()) {
break
} else {
val numElements = numArrayElements(variable)
val result = zeropage.allocate(
variable.scopedName,
variable.dt,
numElements,
variable.length,
variable.position,
errors
)
@ -137,11 +134,4 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
collect(st)
return vars
}
private fun numArrayElements(variable: StStaticVariable) =
when(variable.dt) {
DataType.STR -> variable.initialStringValue!!.first.length+1 // 1 extra because of 0 termination char
in ArrayDatatypes -> variable.arraysize!!
else -> null
}
}

View File

@ -73,8 +73,8 @@ class AstToXmlConverter(internal val program: PtProgram,
xml.elt("var")
xml.attr("type", node.dt.name)
xml.attr("zpwish", node.zpwish.name)
if(node.arraysize!=null)
xml.attr("arraysize", node.arraysize.toString())
if(node.length!=null)
xml.attr("length", node.length.toString())
if(node.initialNumericValue!=null || node.initialArrayValue!=null || node.initialStringValue!=null) {
xml.startChildren()
if(node.initialNumericValue!=null) {

View File

@ -1,5 +1,6 @@
package prog8.codegen.virtual
import prog8.code.StStaticVariable
import prog8.code.SymbolTable
import prog8.code.ast.*
import prog8.code.core.*
@ -58,7 +59,7 @@ class CodeGen(internal val program: PtProgram,
is PtJump -> translate(node)
is PtWhen -> TODO("when")
is PtPipe -> expressionEval.translate(node, regUsage.nextFree(), regUsage)
is PtForLoop -> TODO("for-loop")
is PtForLoop -> translate(node, regUsage)
is PtIfElse -> translate(node, regUsage)
is PtPostIncrDecr -> translate(node, regUsage)
is PtRepeatLoop -> translate(node, regUsage)
@ -90,6 +91,30 @@ class CodeGen(internal val program: PtProgram,
return code
}
private fun translate(forLoop: PtForLoop, regUsage: RegisterUsage): VmCodeChunk {
val loopvar = symbolTable.lookup(forLoop.variable.targetName) as StStaticVariable
val iterable = forLoop.iterable
val code = VmCodeChunk()
when(iterable) {
is PtRange -> {
println("forloop ${loopvar.dt} ${loopvar.scopedName} in range ${iterable} ")
iterable.printIndented(0)
TODO()
}
is PtIdentifier -> {
val address = allocations.get(iterable.targetName)
val variable = symbolTable.lookup(iterable.targetName) as StStaticVariable
val length = variable.length!!
println("forloop ${loopvar.dt} ${loopvar.scopedName} in $iterable @${address.toHex()} ${length}")
val indexReg = regUsage.nextFree()
val loopvarReg = regUsage.nextFree()
TODO()
}
else -> throw AssemblyError("weird for iterable")
}
return code
}
private fun translate(ifElse: PtIfElse, regUsage: RegisterUsage): VmCodeChunk {
var branch = Opcode.BZ
var condition = ifElse.condition

View File

@ -83,14 +83,14 @@ internal class ExpressionGen(val codeGen: CodeGen) {
val call = PtFunctionCall(listOf("prog8_lib", "bytearray_contains"), false, DataType.UBYTE, check.position)
call.children.add(check.element)
call.children.add(check.iterable)
call.children.add(PtNumber(DataType.UBYTE, iterable.arraysize!!.toDouble(), iterable.position))
call.children.add(PtNumber(DataType.UBYTE, iterable.length!!.toDouble(), iterable.position))
code += translate(call, resultRegister, regUsage)
}
DataType.ARRAY_UW, DataType.ARRAY_W -> {
val call = PtFunctionCall(listOf("prog8_lib", "wordarray_contains"), false, DataType.UBYTE, check.position)
call.children.add(check.element)
call.children.add(check.iterable)
call.children.add(PtNumber(DataType.UBYTE, iterable.arraysize!!.toDouble(), iterable.position))
call.children.add(PtNumber(DataType.UBYTE, iterable.length!!.toDouble(), iterable.position))
code += translate(call, resultRegister, regUsage)
}
DataType.ARRAY_F -> TODO("containment check in float-array")
@ -204,21 +204,17 @@ internal class ExpressionGen(val codeGen: CodeGen) {
}
DataType.FLOAT -> {
TODO("floating point not yet supported")
when(cast.value.type) {
DataType.BYTE -> {
// TODO("byte -> float")
}
DataType.UBYTE -> {
// TODO("ubyte -> float")
}
DataType.WORD -> {
// TODO("word -> float")
}
DataType.UWORD -> {
// TODO("uword -> float")
}
else -> throw AssemblyError("weird cast value type")
}
// when(cast.value.type) {
// DataType.BYTE -> {
// }
// DataType.UBYTE -> {
// }
// DataType.WORD -> {
// }
// DataType.UWORD -> {
// }
// else -> throw AssemblyError("weird cast value type")
// }
}
else -> throw AssemblyError("weird cast type")
}
@ -229,7 +225,8 @@ internal class ExpressionGen(val codeGen: CodeGen) {
val code = VmCodeChunk()
val leftResultReg = regUsage.nextFree()
val rightResultReg = regUsage.nextFree()
// TODO: optimized codegen when left or right operand is known 0 or 1 or whatever.
// TODO: optimized codegen when left or right operand is known 0 or 1 or whatever. But only if this would result in a different opcode such as ADD 1 -> INC, MUL 1 -> NOP
// actually optimizing the code should not be done here but in a tailored code optimizer step.
val leftCode = translateExpression(binExpr.left, leftResultReg, regUsage)
val rightCode = translateExpression(binExpr.right, rightResultReg, regUsage)
code += leftCode
@ -288,7 +285,7 @@ internal class ExpressionGen(val codeGen: CodeGen) {
val ins = if(binExpr.type in SignedDatatypes) Opcode.SGES else Opcode.SGE
code += VmCodeInstruction(Instruction(ins, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
}
else -> TODO("operator ${binExpr.operator}")
else -> throw AssemblyError("weird operator ${binExpr.operator}")
}
return code
}
@ -357,9 +354,11 @@ internal class ExpressionGen(val codeGen: CodeGen) {
"msb" -> {
code += translateExpression(call.args.single(), resultRegister, regUsage)
code += VmCodeInstruction(Instruction(Opcode.SWAP, VmDataType.BYTE, reg1 = resultRegister, reg2=resultRegister))
// note: if a word result is needed, the upper byte is cleared by the typecast that follows. No need to do it here.
}
"lsb" -> {
code += translateExpression(call.args.single(), resultRegister, regUsage)
// note: if a word result is needed, the upper byte is cleared by the typecast that follows. No need to do it here.
}
"memory" -> {
val name = (call.args[0] as PtString).value
@ -391,12 +390,6 @@ internal class ExpressionGen(val codeGen: CodeGen) {
code += translateExpression(call.args.single(), addressReg, regUsage)
code += VmCodeInstruction(Instruction(Opcode.LOADI, VmDataType.WORD, reg1 = resultRegister, reg2=addressReg))
}
"memory" -> {
val memname = (call.args[0] as PtString).value
val size = (call.args[1] as PtNumber).number.toInt()
val align = (call.args[2] as PtNumber).number.toInt()
TODO("memory '$memname', $size, $align")
}
else -> {
TODO("builtinfunc ${call.name}")
// code += VmCodeInstruction(Instruction(Opcode.NOP))

View File

@ -19,7 +19,7 @@ class VariableAllocator(private val st: SymbolTable, private val program: PtProg
when (variable.dt) {
DataType.STR -> variable.initialStringValue!!.first.length + 1 // include the zero byte
in NumericDatatypes -> program.memsizer.memorySize(variable.dt)
in ArrayDatatypes -> program.memsizer.memorySize(variable.dt, variable.arraysize!!)
in ArrayDatatypes -> program.memsizer.memorySize(variable.dt, variable.length!!)
else -> throw InternalCompilerException("weird dt")
}
@ -55,14 +55,14 @@ class VariableAllocator(private val st: SymbolTable, private val program: PtProg
if(variable.initialArrayValue!=null) {
variable.initialArrayValue!!.joinToString(",") { it.number!!.toString() }
} else {
(1..variable.arraysize!!).joinToString(",") { "0" }
(1..variable.length!!).joinToString(",") { "0" }
}
}
in ArrayDatatypes -> {
if(variable.initialArrayValue!==null) {
variable.initialArrayValue!!.joinToString(",") { it.number!!.toHex() }
} else {
(1..variable.arraysize!!).joinToString(",") { "0" }
(1..variable.length!!).joinToString(",") { "0" }
}
}
else -> throw InternalCompilerException("weird dt")

View File

@ -63,7 +63,14 @@ internal class SymbolTableMaker: IAstVisitor {
val initialArray = makeInitialArray(initialArrayLit)
if(decl.isArray && decl.datatype !in ArrayDatatypes)
throw FatalAstException("array vardecl has mismatched dt ${decl.datatype}")
StStaticVariable(decl.name, decl.datatype, initialNumeric, initialString, initialArray, decl.arraysize?.constIndex(), decl.zeropage, decl.position)
val numElements =
if(decl.isArray)
decl.arraysize!!.constIndex()
else if(initialStringLit!=null)
initialStringLit.value.length+1 // include the terminating 0-byte
else
null
StStaticVariable(decl.name, decl.datatype, initialNumeric, initialString, initialArray, numElements, decl.zeropage, decl.position)
}
VarDeclType.CONST -> StConstant(decl.name, decl.datatype, (decl.value as NumericLiteral).number, decl.position)
VarDeclType.MEMORY -> StMemVar(decl.name, decl.datatype, (decl.value as NumericLiteral).number.toUInt(), decl.position)

View File

@ -3,6 +3,21 @@ TODO
For next release
^^^^^^^^^^^^^^^^
- vm codegen: ForLoop
- vm codegen: fix primes endless loop stuck on '2'
- x16: screen_set_mode -> screen_mode + other api https://github.com/commanderx16/x16-docs/blob/master/Commander%20X16%20Programmer's%20Reference%20Guide.md#function-name-screen_mode
- optimize diskio load_raw on X16 because headerless files are now supported https://github.com/commanderx16/x16-rom/pull/216
note: must still work on c64/c128 that don't have this!
- major version bump once X16 r39 rom is officially finalized
- vm codegen: When
- vm codegen: Pipe expression
- vm codegen: validate that PtFunctionCall translation works okay with resultregister
- vm: support no globals re-init option
- vm codegen/assembler: variable memory locations should also be referenced by the variable name instead of just the address
- when the vm is stable and *if* its language can get promoted to prog8 IL, the variable allocation should be changed.
It's now done before the vm code generation, but the IL should probably not depend on the allocations already performed.
So the CodeGen doesn't do VariableAlloc *before* the codegen, but as a last step.
...
@ -62,10 +77,8 @@ Expressions:
Optimizations:
- various optimizers skip stuff if compTarget.name==VMTarget.NAME. Once (if?) 6502-codegen is no longer done from
- various optimizers should/do skip stuff if compTarget.name==VMTarget.NAME. Once (if?) 6502-codegen is no longer done from
the old CompilerAst, those checks should probably be removed.
(most of them avoid the case where extra temporary variables are introduced in an attempt to simplify
the expression code generation)
- VariableAllocator: can we think of a smarter strategy for allocating variables into zeropage, rather than first-come-first-served
- translateUnaryFunctioncall() in BuiltinFunctionsAsmGen: should be able to assign parameters to a builtin function directly from register(s), this will make the use of a builtin function in a pipe expression more efficient without using a temporary variable
compare ``aa = startvalue(1) |> sin8u() |> cos8u() |> sin8u() |> cos8u()``

View File

@ -7,32 +7,40 @@ main {
txt.clear_screen()
txt.print("Welcome to a prog8 pixel shader :-)\n")
uword @shared chunk = memory("irmen", 4000, 256)
txt.print_uwhex(chunk,true)
uword ww = 0
ubyte bc
uword wc
for bc in "irmen" {
; +5 -> 17
txt.chrout(bc)
ww++
}
txt.print_uw(ww)
txt.nl()
ubyte bb = 4
ubyte[] array = [1,2,3,4,5,6]
uword[] warray = [1111,2222,3333]
str tekst = "test"
uword ww = 19
bb = bb in "teststring"
bb++
bb = bb in [1,2,3,4,5,6]
bb++
bb = bb in array
bb++
bb = bb in tekst
bb++
bb = ww in warray
bb++
bb = 666 in warray
bb ++
bb = '?' in tekst
bb++
txt.print("bb=")
txt.print_ub(bb)
for wc in [1000,1111,1222] {
txt.print_uw(wc)
txt.spc()
ww++ ; +3 -> 20
}
txt.print_uw(ww)
txt.nl()
for bc in 10 to 20 step 3 {
; 10,13,16,19 -> 4
ww++
}
txt.print_uw(ww)
txt.nl()
for bc in 30 to 10 step -4 {
; 30,26,22,18,14,10,6,2 -> +8 -> 12
ww++
}
txt.print_uw(ww)
txt.nl()
sys.exit(99)

View File

@ -220,6 +220,7 @@ data class Instruction(
val reg2: Int?=null, // 0-$ffff
val reg3: Int?=null, // 0-$ffff
val value: Int?=null, // 0-$ffff
// TODO add string symbol here as alternative to value
) {
override fun toString(): String {
val result = mutableListOf(opcode.name.lowercase())