This commit is contained in:
Irmen de Jong 2022-08-27 13:22:38 +02:00
parent 101b33c381
commit 12ed07a607
7 changed files with 114 additions and 18 deletions

View File

@ -47,6 +47,9 @@ class CodeGen(internal val program: PtProgram,
internal val vmRegisters = VmRegisterPool()
override fun compileToAssembly(): IAssemblyProgram? {
flattenNestedSubroutines()
val irProg = IRProgram(program.name, symbolTable, options, program.encoding)
if(!options.dontReinitGlobals) {
@ -80,6 +83,56 @@ class CodeGen(internal val program: PtProgram,
return DummyAssemblyProgram(irProg.name)
}
private fun flattenNestedSubroutines() {
// this moves all nested subroutines up to the block scope.
val flattenedSubs = mutableListOf<Pair<PtBlock, PtSub>>()
val flattenedAsmSubs = mutableListOf<Pair<PtBlock, PtAsmSub>>()
val removalsSubs = mutableListOf<Pair<PtSub, PtSub>>()
val removalsAsmSubs = mutableListOf<Pair<PtSub, PtAsmSub>>()
fun flattenNestedAsm(block: PtBlock, parentSub: PtSub, asmsub: PtAsmSub) {
val flattened = PtAsmSub(asmsub.scopedName.joinToString("."),
asmsub.address,
asmsub.clobbers,
asmsub.parameters,
asmsub.returnTypes,
asmsub.retvalRegisters,
asmsub.inline,
asmsub.position)
asmsub.children.forEach { flattened.add(it) }
flattenedAsmSubs += Pair(block, flattened)
removalsAsmSubs += Pair(parentSub, asmsub)
}
fun flattenNested(block: PtBlock, parentSub: PtSub, sub: PtSub) {
sub.children.filterIsInstance<PtSub>().forEach { subsub->flattenNested(block, sub, subsub) }
sub.children.filterIsInstance<PtAsmSub>().forEach { asmsubsub->flattenNestedAsm(block, sub, asmsubsub) }
val flattened = PtSub(sub.scopedName.joinToString("."),
sub.parameters,
sub.returntype,
sub.inline,
sub.position)
sub.children.forEach { if(it !is PtSub) flattened.add(it) }
flattenedSubs += Pair(block, flattened)
removalsSubs += Pair(parentSub, sub)
}
program.allBlocks().forEach { block ->
block.children.forEach {
if(it is PtSub) {
// Only regular subroutines can have nested subroutines.
it.children.filterIsInstance<PtSub>().forEach { subsub->flattenNested(block, it, subsub)}
it.children.filterIsInstance<PtAsmSub>().forEach { asmsubsub->flattenNestedAsm(block, it, asmsubsub)}
}
}
}
removalsSubs.forEach { (parent, sub) -> parent.children.remove(sub) }
removalsAsmSubs.forEach { (parent, asmsub) -> parent.children.remove(asmsub) }
flattenedSubs.forEach { (block, sub) -> block.add(sub) }
flattenedAsmSubs.forEach { (block, asmsub) -> block.add(asmsub) }
}
internal fun translateNode(node: PtNode): IRCodeChunk {
val code = when(node) {
@ -651,7 +704,6 @@ class CodeGen(internal val program: PtProgram,
translateNonZeroComparison()
}
private fun translate(postIncrDecr: PtPostIncrDecr): IRCodeChunk {
val code = IRCodeChunk(postIncrDecr.position)
val operationMem: Opcode
@ -771,7 +823,7 @@ class CodeGen(internal val program: PtProgram,
is PtAssignment -> { /* global variable initialization is done elsewhere */ }
is PtScopeVarsDecls -> { /* vars should be looked up via symbol table */ }
is PtSub -> {
val vmsub = IRSubroutine(child.scopedName, child.returntype, child.position)
val vmsub = IRSubroutine(child.name, child.returntype, child.position)
for (line in child.children) {
vmsub += translateNode(line)
}
@ -823,4 +875,3 @@ class CodeGen(internal val program: PtProgram,
return scopedName
}
}

View File

@ -20,11 +20,19 @@ main {
qq=global1
qq=other.global2
; nested()
nested()
main.start.nested.nested2()
; TODO flatten nested subroutines in codegen
sub nested() {
qq++
txt.print("zzz")
nested2()
sub nested2() {
txt.print("zzz2")
qq++
}
}
}
}

View File

@ -5,6 +5,7 @@
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />

View File

@ -37,7 +37,7 @@ class IRFileWriter(private val irProgram: IRProgram) {
out.write("</INLINEASM>\n")
}
block.subroutines.forEach {
out.write("<SUB SCOPEDNAME=${it.scopedName.joinToString(".")} RETURNTYPE=${it.returnType} POS=${it.position}>\n")
out.write("<SUB NAME=${it.name} RETURNTYPE=${it.returnType} POS=${it.position}>\n")
it.lines.forEach { line -> out.writeLine(line) }
out.write("</SUB>\n")
}

View File

@ -8,7 +8,33 @@ import prog8.code.core.IStringEncoding
import prog8.code.core.Position
import java.nio.file.Path
// TODO: move this Intermedate Representation into the actual compiler core, code gen modules can receive it as input rather than an Ast.
/*
PROGRAM:
OPTIONS (from CompilationOptions)
VARIABLES (from Symboltable)
MEMORYMAPPEDVARIABLES (from Symboltable)
MEMORYSLABS (from Symboltable)
GLOBALINITS
CODE-LINE (assignment to initialize a variable)
CODE-LINE (assignment to initialize a variable)
...
BLOCK
INLINEASM
INLINEASM
SUB
CODE-LINE (label, instruction, comment, inlinebinary)
CODE-LINE
CODE-LINE
...
SUB
SUB
ASMSUB
ASMSUB
...
BLOCK
BLOCK
...
*/
class IRProgram(val name: String,
val st: SymbolTable,
@ -35,22 +61,16 @@ class IRBlock(
operator fun plusAssign(sub: IRSubroutine) {
subroutines += sub
}
operator fun plusAssign(sub: IRAsmSubroutine) {
asmSubroutines += sub
}
operator fun plusAssign(asm: IRInlineAsmChunk) {
inlineAssembly += asm
}
operator fun plusAssign(sub: IRAsmSubroutine) { asmSubroutines += sub }
operator fun plusAssign(asm: IRInlineAsmChunk) { inlineAssembly += asm }
}
class IRSubroutine(val scopedName: List<String>,
class IRSubroutine(val name: String,
val returnType: DataType?,
val position: Position) {
val lines = mutableListOf<IRCodeLine>()
operator fun plusAssign(chunk: IRCodeChunk) {
lines += chunk.lines
}
operator fun plusAssign(chunk: IRCodeChunk) { lines += chunk.lines }
}
class IRAsmSubroutine(val scopedName: List<String>,

View File

@ -2,15 +2,18 @@ package prog8.intermediate
/*
Virtual machine:
Intermediate Representation instructions for the IR Virtual machine.
--------------------------------------------------------------------
Specs of the virtual machine this will run on:
Program to execute is not stored in the system memory, it's just a separate list of instructions.
65536 virtual registers, 16 bits wide, can also be used as 8 bits. r0-r65535
65536 virtual floating point registers (32 bits single precision floats) fr0-fr65535
65536 bytes of memory. Thus memory pointers (addresses) are limited to 16 bits.
Value stack, max 128 entries of 1 byte each.
Status flags: Carry, Zero, Negative. NOTE: status flags are only affected by the CMP instruction or explicit CLC/SEC!!!
logical or arithmetic operations DO NOT AFFECT THE STATUS FLAGS UNLESS EXPLICITLY NOTED!
Program to execute is not stored in this memory, it's just a separate list of instructions.
Most instructions have an associated data type 'b','w','f'. (omitting it means 'b'/byte).
Currently NO support for 24 or 32 bits integers.
Floating point operations are just 'f' typed regular instructions, and additionally there are a few fp conversion instructions

View File

@ -10,6 +10,19 @@ import java.util.*
import kotlin.math.*
import kotlin.random.Random
/*
Virtual machine specs:
Program to execute is not stored in the system memory, it's just a separate list of instructions.
65536 virtual registers, 16 bits wide, can also be used as 8 bits. r0-r65535
65536 virtual floating point registers (32 bits single precision floats) fr0-fr65535
65536 bytes of memory. Thus memory pointers (addresses) are limited to 16 bits.
Value stack, max 128 entries of 1 byte each.
Status flags: Carry, Zero, Negative. NOTE: status flags are only affected by the CMP instruction or explicit CLC/SEC!!!
logical or arithmetic operations DO NOT AFFECT THE STATUS FLAGS UNLESS EXPLICITLY NOTED!
*/
class ProgramExitException(val status: Int): Exception()