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() internal val vmRegisters = VmRegisterPool()
override fun compileToAssembly(): IAssemblyProgram? { override fun compileToAssembly(): IAssemblyProgram? {
flattenNestedSubroutines()
val irProg = IRProgram(program.name, symbolTable, options, program.encoding) val irProg = IRProgram(program.name, symbolTable, options, program.encoding)
if(!options.dontReinitGlobals) { if(!options.dontReinitGlobals) {
@@ -80,6 +83,56 @@ class CodeGen(internal val program: PtProgram,
return DummyAssemblyProgram(irProg.name) 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 { internal fun translateNode(node: PtNode): IRCodeChunk {
val code = when(node) { val code = when(node) {
@@ -651,7 +704,6 @@ class CodeGen(internal val program: PtProgram,
translateNonZeroComparison() translateNonZeroComparison()
} }
private fun translate(postIncrDecr: PtPostIncrDecr): IRCodeChunk { private fun translate(postIncrDecr: PtPostIncrDecr): IRCodeChunk {
val code = IRCodeChunk(postIncrDecr.position) val code = IRCodeChunk(postIncrDecr.position)
val operationMem: Opcode val operationMem: Opcode
@@ -771,7 +823,7 @@ class CodeGen(internal val program: PtProgram,
is PtAssignment -> { /* global variable initialization is done elsewhere */ } is PtAssignment -> { /* global variable initialization is done elsewhere */ }
is PtScopeVarsDecls -> { /* vars should be looked up via symbol table */ } is PtScopeVarsDecls -> { /* vars should be looked up via symbol table */ }
is PtSub -> { 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) { for (line in child.children) {
vmsub += translateNode(line) vmsub += translateNode(line)
} }
@@ -823,4 +875,3 @@ class CodeGen(internal val program: PtProgram,
return scopedName return scopedName
} }
} }

View File

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

View File

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

View File

@@ -37,7 +37,7 @@ class IRFileWriter(private val irProgram: IRProgram) {
out.write("</INLINEASM>\n") out.write("</INLINEASM>\n")
} }
block.subroutines.forEach { 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) } it.lines.forEach { line -> out.writeLine(line) }
out.write("</SUB>\n") out.write("</SUB>\n")
} }

View File

@@ -8,7 +8,33 @@ import prog8.code.core.IStringEncoding
import prog8.code.core.Position import prog8.code.core.Position
import java.nio.file.Path 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, class IRProgram(val name: String,
val st: SymbolTable, val st: SymbolTable,
@@ -35,22 +61,16 @@ class IRBlock(
operator fun plusAssign(sub: IRSubroutine) { operator fun plusAssign(sub: IRSubroutine) {
subroutines += sub subroutines += sub
} }
operator fun plusAssign(sub: IRAsmSubroutine) { operator fun plusAssign(sub: IRAsmSubroutine) { asmSubroutines += sub }
asmSubroutines += sub operator fun plusAssign(asm: IRInlineAsmChunk) { inlineAssembly += asm }
}
operator fun plusAssign(asm: IRInlineAsmChunk) {
inlineAssembly += asm
}
} }
class IRSubroutine(val scopedName: List<String>, class IRSubroutine(val name: String,
val returnType: DataType?, val returnType: DataType?,
val position: Position) { val position: Position) {
val lines = mutableListOf<IRCodeLine>() val lines = mutableListOf<IRCodeLine>()
operator fun plusAssign(chunk: IRCodeChunk) { operator fun plusAssign(chunk: IRCodeChunk) { lines += chunk.lines }
lines += chunk.lines
}
} }
class IRAsmSubroutine(val scopedName: List<String>, 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 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 virtual floating point registers (32 bits single precision floats) fr0-fr65535
65536 bytes of memory. Thus memory pointers (addresses) are limited to 16 bits. 65536 bytes of memory. Thus memory pointers (addresses) are limited to 16 bits.
Value stack, max 128 entries of 1 byte each. 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!!! 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! 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). Most instructions have an associated data type 'b','w','f'. (omitting it means 'b'/byte).
Currently NO support for 24 or 32 bits integers. 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 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.math.*
import kotlin.random.Random 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() class ProgramExitException(val status: Int): Exception()