got rid of bytecode based compiler and vm

This commit is contained in:
Irmen de Jong 2019-07-23 20:44:11 +02:00
parent 776c844d02
commit 9961a404ae
19 changed files with 3119 additions and 3087 deletions

1
.idea/modules.xml generated
View File

@ -2,6 +2,7 @@
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/DeprecatedStackVm/DeprecatedStackVm.iml" filepath="$PROJECT_DIR$/DeprecatedStackVm/DeprecatedStackVm.iml" />
<module fileurl="file://$PROJECT_DIR$/compiler/compiler.iml" filepath="$PROJECT_DIR$/compiler/compiler.iml" />
<module fileurl="file://$PROJECT_DIR$/docs/docs.iml" filepath="$PROJECT_DIR$/docs/docs.iml" />
<module fileurl="file://$PROJECT_DIR$/examples/examples.iml" filepath="$PROJECT_DIR$/examples/examples.iml" />

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="jdk" jdkName="1.8" jdkType="JavaSDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="KotlinJavaRuntime" level="project" />
</component>
</module>

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
package prog8.compiler.intermediate
package compiler.intermediate
import prog8.vm.RuntimeValue
import prog8.vm.stackvm.Syscall
@ -15,8 +15,8 @@ open class Instruction(val opcode: Opcode,
val argStr = arg?.toString() ?: ""
val result =
when {
opcode==Opcode.LINE -> "_line $callLabel"
opcode==Opcode.INLINE_ASSEMBLY -> {
opcode== Opcode.LINE -> "_line $callLabel"
opcode== Opcode.INLINE_ASSEMBLY -> {
// inline assembly is not written out (it can't be processed as intermediate language)
// instead, it is converted into a system call that can be intercepted by the vm
if(callLabel!=null)
@ -24,10 +24,10 @@ open class Instruction(val opcode: Opcode,
else
"inline_assembly"
}
opcode==Opcode.INCLUDE_FILE -> {
opcode== Opcode.INCLUDE_FILE -> {
"include_file \"$callLabel\" $arg $arg2"
}
opcode==Opcode.SYSCALL -> {
opcode== Opcode.SYSCALL -> {
val syscall = Syscall.values().find { it.callNr==arg!!.numericValue() }
"syscall $syscall"
}

View File

@ -1,4 +1,4 @@
package prog8.compiler.intermediate
package compiler.intermediate
import prog8.ast.antlr.escape
import prog8.ast.base.*
@ -85,7 +85,7 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
val branchOpcodes = setOf(Opcode.JZ, Opcode.JNZ, Opcode.JZW, Opcode.JNZW)
for(blk in blocks) {
val instructionsToReplace = mutableMapOf<Int, Instruction>()
blk.instructions.asSequence().withIndex().filter {it.value.opcode!=Opcode.LINE}.windowed(2).toList().forEach {
blk.instructions.asSequence().withIndex().filter {it.value.opcode!= Opcode.LINE }.windowed(2).toList().forEach {
if (it[1].value.opcode in branchOpcodes) {
if (it[0].value.opcode in pushvalue) {
val value = it[0].value.arg!!.asBoolean
@ -138,8 +138,8 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
for(blk in blocks) {
val instructionsToReplace = mutableMapOf<Int, Instruction>()
blk.instructions.asSequence().withIndex().filter {it.value.opcode!=Opcode.LINE}.windowed(2).toList().forEach {
if(it[0].value.opcode==Opcode.CALL && it[1].value.opcode==Opcode.RETURN) {
blk.instructions.asSequence().withIndex().filter {it.value.opcode!= Opcode.LINE }.windowed(2).toList().forEach {
if(it[0].value.opcode== Opcode.CALL && it[1].value.opcode== Opcode.RETURN) {
instructionsToReplace[it[1].index] = Instruction(Opcode.JUMP, callLabel = it[0].value.callLabel)
instructionsToReplace[it[0].index] = Instruction(Opcode.NOP)
}
@ -315,12 +315,12 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
instructionsToReplace[index0] = ins
instructionsToReplace[index1] = Instruction(Opcode.NOP)
}
Opcode.CAST_B_TO_F, Opcode.CAST_UB_TO_F-> {
Opcode.CAST_B_TO_F, Opcode.CAST_UB_TO_F -> {
val ins = Instruction(Opcode.PUSH_FLOAT, RuntimeValue(DataType.FLOAT, ins0.arg!!.integerValue().toDouble()))
instructionsToReplace[index0] = ins
instructionsToReplace[index1] = Instruction(Opcode.NOP)
}
Opcode.CAST_W_TO_F, Opcode.CAST_UW_TO_F-> throw CompilerException("invalid conversion following a byte")
Opcode.CAST_W_TO_F, Opcode.CAST_UW_TO_F -> throw CompilerException("invalid conversion following a byte")
Opcode.DISCARD_BYTE -> {
instructionsToReplace[index0] = Instruction(Opcode.NOP)
instructionsToReplace[index1] = Instruction(Opcode.NOP)
@ -462,7 +462,7 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
}
fun newBlock(name: String, address: Int?, options: Set<String>) {
currentBlock = ProgramBlock(name, address, force_output="force_output" in options)
currentBlock = ProgramBlock(name, address, force_output = "force_output" in options)
blocks.add(currentBlock)
}

View File

@ -1,4 +1,4 @@
package prog8.compiler.intermediate
package compiler.intermediate
enum class Opcode {

View File

@ -1,4 +1,4 @@
package prog8.compiler.target.c64.codegen
package compiler.target.c64.codegen
// note: to put stuff on the stack, we use Absolute,X addressing mode which is 3 bytes / 4 cycles
// possible space optimization is to use zeropage (indirect),Y which is 2 bytes, but 5 cycles

View File

@ -1,4 +1,4 @@
package prog8.compiler.target.c64.codegen
package compiler.target.c64.codegen
import prog8.compiler.CompilerException
import prog8.compiler.intermediate.Instruction

View File

@ -2,20 +2,12 @@ package prog8
import prog8.compiler.compileProgram
import prog8.vm.astvm.AstVm
import prog8.vm.stackvm.stackVmMain
import java.nio.file.Paths
import kotlin.system.exitProcess
fun main(args: Array<String>) {
// check if the user wants to launch the VM instead
if("-vm" in args) {
val newArgs = args.toMutableList()
newArgs.remove("-vm")
return stackVmMain(newArgs.toTypedArray())
}
printSoftwareHeader("compiler")
if (args.isEmpty())
@ -33,19 +25,15 @@ internal fun printSoftwareHeader(what: String) {
private fun compileMain(args: Array<String>) {
var emulatorToStart = ""
var moduleFile = ""
var writeVmCode = false
var writeAssembly = true
var optimize = true
var optimizeInlining = true
var launchAstVm = false
var asm2 = false
for (arg in args) {
if(arg=="-emu")
emulatorToStart = "x64"
else if(arg=="-emu2")
emulatorToStart = "x64sc"
else if(arg=="-writevm")
writeVmCode = true
else if(arg=="-noasm")
writeAssembly = false
else if(arg=="-noopt")
@ -54,10 +42,6 @@ private fun compileMain(args: Array<String>) {
optimizeInlining = false
else if(arg=="-avm")
launchAstVm = true
else if(arg=="-asm2") {
writeVmCode = false
asm2 = true
}
else if(!arg.startsWith("-"))
moduleFile = arg
else
@ -68,8 +52,7 @@ private fun compileMain(args: Array<String>) {
val filepath = Paths.get(moduleFile).normalize()
val (programAst, programName) = compileProgram(filepath, optimize, optimizeInlining,
!launchAstVm && !asm2, writeVmCode, writeAssembly, asm2)
val (programAst, programName) = compileProgram(filepath, optimize, optimizeInlining, writeAssembly)
if(launchAstVm) {
println("\nLaunching AST-based vm...")
@ -95,10 +78,7 @@ private fun usage() {
System.err.println("Missing argument(s):")
System.err.println(" [-emu] auto-start the 'x64' C-64 emulator after successful compilation")
System.err.println(" [-emu2] auto-start the 'x64sc' C-64 emulator after successful compilation")
System.err.println(" [-writevm] write intermediate vm code to a file as well")
System.err.println(" [-noasm] don't create assembly code")
System.err.println(" [-asm2] use new Ast-Asmgen2 (WIP)")
System.err.println(" [-vm] launch the prog8 virtual machine instead of the compiler")
System.err.println(" [-avm] launch the prog8 ast-based virtual machine after compilation")
System.err.println(" [-noopt] don't perform any optimizations")
System.err.println(" [-nooptinline] don't perform subroutine inlining optimizations")

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,6 @@ import prog8.ast.AstToSourceCode
import prog8.ast.Program
import prog8.ast.base.*
import prog8.ast.statements.Directive
import prog8.compiler.target.c64.codegen.AsmGen
import prog8.compiler.target.c64.MachineDefinition
import prog8.compiler.target.c64.codegen2.AsmGen2
import prog8.optimizer.constantFold
@ -14,16 +13,13 @@ import prog8.parser.ParsingFailedError
import prog8.parser.importLibraryModule
import prog8.parser.importModule
import prog8.parser.moduleName
import java.io.File
import java.io.PrintStream
import java.nio.file.Path
import kotlin.system.exitProcess
import kotlin.system.measureTimeMillis
fun compileProgram(filepath: Path,
optimize: Boolean, optimizeInlining: Boolean,
generateVmCode: Boolean, writeVmCode: Boolean,
writeAssembly: Boolean, asm2: Boolean): Pair<Program, String?> {
writeAssembly: Boolean): Pair<Program, String?> {
lateinit var programAst: Program
var programName: String? = null
@ -92,33 +88,10 @@ fun compileProgram(filepath: Path,
programAst.checkValid(compilerOptions) // check if final tree is valid
programAst.checkRecursion() // check if there are recursive subroutine calls
if(generateVmCode) {
// compile the syntax tree into stackvmProg form, and optimize that
val compiler = Compiler(programAst)
val intermediate = compiler.compile(compilerOptions)
if (optimize)
intermediate.optimize()
if (writeVmCode) {
val stackVmFilename = intermediate.name + ".vm.txt"
val stackvmFile = PrintStream(File(stackVmFilename), "utf-8")
intermediate.writeCode(stackvmFile)
stackvmFile.close()
println("StackVM program code written to '$stackVmFilename'")
}
if (writeAssembly && !asm2) {
val zeropage = MachineDefinition.C64Zeropage(compilerOptions)
intermediate.allocateZeropage(zeropage)
val assembly = AsmGen(compilerOptions, intermediate, programAst.heap, zeropage).compileToAssembly(optimize)
assembly.assemble(compilerOptions)
programName = assembly.name
}
}
if(asm2 && writeAssembly) {
if(writeAssembly) {
// asm generation directly from the Ast, no need for intermediate code
val assembly = AsmGen2(programAst, compilerOptions, MachineDefinition.C64Zeropage(compilerOptions)).compileToAssembly(optimize)
val zeropage = MachineDefinition.C64Zeropage(compilerOptions)
val assembly = AsmGen2(programAst, compilerOptions, zeropage).compileToAssembly(optimize)
assembly.assemble(compilerOptions)
programName = assembly.name
}

View File

@ -5,18 +5,15 @@ import prog8.ast.Node
import prog8.ast.Program
import prog8.ast.antlr.escape
import prog8.ast.base.*
import prog8.ast.base.initvarsSubName
import prog8.ast.expressions.*
import prog8.ast.statements.*
import prog8.compiler.*
import prog8.compiler.target.c64.AssemblyProgram
import prog8.compiler.target.c64.MachineDefinition
import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_HEX
import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_PLUS1_HEX
import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_HEX
import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_PLUS1_HEX
import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_HEX
import prog8.compiler.target.c64.Petscii
import prog8.compiler.target.c64.codegen.optimizeAssembly
import prog8.functions.BuiltinFunctions
import java.io.File
import java.util.*
@ -198,7 +195,7 @@ internal class AsmGen2(val program: Program,
val bytes = Petscii.encodeScreencode(str, true)
bytes.plus(0)
}
else -> throw prog8.compiler.target.c64.codegen.AssemblyError("invalid str type")
else -> throw AssemblyError("invalid str type")
}
}
@ -533,7 +530,7 @@ internal class AsmGen2(val program: Program,
RegisterOrPair.XY -> TODO("register X+Y param $literal")
}
} else {
TODO("register param")
TODO("register param non-const")
}
}
}
@ -544,7 +541,7 @@ internal class AsmGen2(val program: Program,
}
private fun translate(stmt: Label) {
out("${stmt.name}")
out(stmt.name)
}
private fun translate(stmt: BranchStatement) {
@ -779,7 +776,7 @@ internal class AsmGen2(val program: Program,
}
private fun translateExpression(expr: ArrayIndexedExpression) {
out("; TODO evaluate arrayindexed ${expr}") // TODO
out("; TODO evaluate arrayindexed $expr") // TODO
}
private fun translateExpression(expr: TypecastExpression) {
@ -864,11 +861,11 @@ internal class AsmGen2(val program: Program,
}
private fun translateExpression(expr: AddressOf) {
out("; TODO take address of ${expr}") // TODO
out("; TODO take address of $expr") // TODO
}
private fun translateExpression(expr: DirectMemoryRead) {
out("; TODO memread ${expr}") // TODO
out("; TODO memread $expr") // TODO
}
private fun translateExpression(expr: NumericLiteralValue) {

View File

@ -1,4 +1,4 @@
package prog8.compiler.target.c64.codegen
package prog8.compiler.target.c64.codegen2
import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_HEX
import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_PLUS1_HEX

View File

@ -7,15 +7,11 @@ import prog8.ast.expressions.FunctionCall
import prog8.ast.expressions.IdentifierReference
import prog8.ast.expressions.NumericLiteralValue
import prog8.ast.statements.FunctionCallStatement
import prog8.ast.statements.Subroutine
import prog8.compiler.target.c64.MachineDefinition
import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_HEX
import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_PLUS1_HEX
import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_HEX
import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_PLUS1_HEX
import prog8.compiler.CompilationOptions
import prog8.compiler.Zeropage
import prog8.functions.BuiltinFunctions
import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_PLUS1_HEX
import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_HEX
import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_PLUS1_HEX
import prog8.functions.FunctionSignature
internal class BuiltinFunctionsAsmGen(private val program: Program,