vm: fix symbols to be case sensitive properly in p8virt assembler

This commit is contained in:
Irmen de Jong 2022-09-25 11:00:04 +02:00
parent ca41669f4f
commit dda19c29fe
7 changed files with 97 additions and 48 deletions

View File

@ -3,18 +3,16 @@ package prog8tests
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldNotBe
import prog8.code.core.ICompilationTarget
import prog8.code.target.C64Target
import prog8.code.target.Cx16Target
import prog8.code.target.*
import prog8.compiler.CompilationResult
import prog8.compiler.CompilerArguments
import prog8.compiler.compileProgram
import prog8tests.helpers.assumeDirectory
import prog8tests.helpers.cartesianProduct
import prog8tests.helpers.outputDir
import prog8tests.helpers.workingDir
import prog8tests.helpers.*
import prog8tests.helpers.compileText
import java.nio.file.Path
import kotlin.io.path.absolute
import kotlin.io.path.exists
import kotlin.io.path.readText
/**
@ -47,8 +45,11 @@ private fun compileTheThing(filepath: Path, optimize: Boolean, target: ICompilat
private fun prepareTestFiles(source: String, optimize: Boolean, target: ICompilationTarget): Pair<String, Path> {
val searchIn = mutableListOf(examplesDir)
if (target is Cx16Target) {
searchIn.add(0, assumeDirectory(examplesDir, "cx16"))
when (target) {
is Cx16Target -> searchIn.add(0, assumeDirectory(examplesDir, "cx16"))
is VMTarget -> searchIn.add(0, assumeDirectory(examplesDir, "vm"))
is C128Target -> searchIn.add(0, assumeDirectory(examplesDir, "c128"))
is AtariTarget -> searchIn.add(0, assumeDirectory(examplesDir, "atari"))
}
val filepath = searchIn.asSequence()
.map { it.resolve("$source.p8") }
@ -168,3 +169,24 @@ class TestCompilerOnExamplesBothC64andCx16: FunSpec({
}
}
})
class TestCompilerOnExamplesVirtual: FunSpec({
val onlyVirtual = listOf(
"bouncegfx",
"bsieve",
"pixelshader",
"sincos",
"textelite"
)
onlyVirtual.forEach {
val target = VMTarget()
val (displayName, filepath) = prepareTestFiles(it, false, target)
test(displayName) {
val src = filepath.readText()
compileText(target, false, src, writeAssembly = true, keepIR=false) shouldNotBe null
compileText(target, false, src, writeAssembly = true, keepIR=true) shouldNotBe null
}
}
})

View File

@ -28,6 +28,9 @@ main {
val result = compileText(target, true, src, writeAssembly = true, keepIR=true)!!
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8virt")
VmRunner().runProgram(virtfile.readText())
val result2 = compileText(target, true, src, writeAssembly = true, keepIR=false)!!
val virtfile2 = result2.compilationOptions.outputDir.resolve(result2.program.name + ".p8virt")
VmRunner().runProgram(virtfile2.readText())
}
test("compile virtual: array with pointers") {
@ -50,6 +53,9 @@ main {
val result = compileText(target, true, src, writeAssembly = true, keepIR=true)!!
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8virt")
VmRunner().runProgram(virtfile.readText())
val result2 = compileText(target, true, src, writeAssembly = true, keepIR=false)!!
val virtfile2 = result2.compilationOptions.outputDir.resolve(result2.program.name + ".p8virt")
VmRunner().runProgram(virtfile2.readText())
}
test("compile virtual: str args and return type") {
@ -68,6 +74,9 @@ main {
val result = compileText(target, true, src, writeAssembly = true, keepIR=true)!!
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8virt")
VmRunner().runProgram(virtfile.readText())
val result2 = compileText(target, true, src, writeAssembly = true, keepIR=false)!!
val virtfile2 = result2.compilationOptions.outputDir.resolve(result2.program.name + ".p8virt")
VmRunner().runProgram(virtfile2.readText())
}
test("compile virtual: nested labels") {
@ -108,6 +117,9 @@ mylabel_inside:
val result = compileText(target, true, src, writeAssembly = true, keepIR=true)!!
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8virt")
VmRunner().runProgram(virtfile.readText())
val result2 = compileText(target, true, src, writeAssembly = true, keepIR=false)!!
val virtfile2 = result2.compilationOptions.outputDir.resolve(result2.program.name + ".p8virt")
VmRunner().runProgram(virtfile2.readText())
}
test("case sensitive symbols") {
@ -136,5 +148,12 @@ skipLABEL:
vm.memory.getUB(0) shouldBe 42u
vm.memory.getUB(3) shouldBe 66u
}
val result2 = compileText(target, true, src, writeAssembly = true, keepIR=false)!!
val virtfile2 = result2.compilationOptions.outputDir.resolve(result2.program.name + ".p8virt")
VmRunner().runAndTestProgram(virtfile2.readText()) { vm ->
vm.memory.getUB(0) shouldBe 42u
vm.memory.getUB(3) shouldBe 66u
}
}
})

View File

@ -3,9 +3,8 @@ TODO
For next release
^^^^^^^^^^^^^^^^
- fix vm symbol case insensitivity (TestCompilerVirtual)
- fix vm crash in TestCompilerVirtual: array with pointers
- fix vm crash (parseValue error) in examples/vm/textelite.p8 (Assembler, caused by above?)
- fix vm assembler bug in TestCompilerVirtual when no IR code is written (IRWriter.writeVariableAllocations TODO)
- fix examples/vm/textelite.p8 having wrong randomization? (starts with wrong planet)
...
@ -21,6 +20,7 @@ Future Things and Ideas
^^^^^^^^^^^^^^^^^^^^^^^
Compiler:
- vm: get rid of p8virt format and Assembler, run p8ir directly
- vm/ir: put variables and arrays in BSS section (unless -noreinit is specified)
- vm: Jumps go to a code block rather than a specific address(label) -> also helps future dead code elimination?
- vm: the above means that every label introduces a new code block. This eliminates the use of actual labels altogether.

View File

@ -14,7 +14,7 @@ main {
sub start() {
txt.lowercase()
txt.print("\u000c\n --- TextElite v1.2 ---\n")
txt.print("--- TextElite v1.2 ---\n")
txt.print("VirtualMachine edition: no disk saving, bad text layout!\n")
galaxy.travel_to(1, numforLave)

View File

@ -122,6 +122,7 @@ class IRFileWriter(private val irProgram: IRProgram) {
if(it.number!=null)
it.number!!.toInt().toString()
else {
// TODO : don't do a lookup; addressOf should be scoped properly already!
val target = variable.lookup(it.addressOf!!)
?: throw InternalCompilerException("symbol not found: ${it.addressOf} in ${variable.scopedName}")
"&${target.scopedName.joinToString(".")}"

View File

@ -180,6 +180,18 @@ class Assembler {
var fpReg3: Int? = null
var value: Float? = null
var operand: String?
fun parseValueOrPlaceholder(operand: String, pc: Int, rest: String, restIndex: Int, opcode: Opcode): Float {
return if(operand.startsWith('_')) {
placeholders[pc] = rest.split(",")[restIndex].trim().drop(1)
0f
} else if(operand[0].isLetter()) {
placeholders[pc] = rest.split(",")[restIndex].trim()
0f
} else
parseValue(opcode, operand, pc)
}
if(operands.isNotEmpty() && operands[0].isNotEmpty()) {
operand = operands.removeFirst().trim()
if(operand[0]=='r')
@ -187,13 +199,7 @@ class Assembler {
else if(operand[0]=='f' && operand[1]=='r')
fpReg1 = operand.substring(2).toInt()
else {
value = if(operand.startsWith('_')) {
// it's a label, keep the original case!
val labelname = rest.split(",").first().trim()
parseValue(opcode, labelname, program.size)
} else {
parseValue(opcode, operand, program.size)
}
value = parseValueOrPlaceholder(operand, program.size, rest, 0, opcode)
operands.clear()
}
if(operands.isNotEmpty()) {
@ -203,7 +209,7 @@ class Assembler {
else if(operand[0]=='f' && operand[1]=='r')
fpReg2 = operand.substring(2).toInt()
else {
value = parseValue(opcode, operand, program.size)
value = parseValueOrPlaceholder(operand, program.size, rest, 1, opcode)
operands.clear()
}
if(operands.isNotEmpty()) {
@ -213,13 +219,11 @@ class Assembler {
else if(operand[0]=='f' && operand[1]=='r')
fpReg3 = operand.substring(2).toInt()
else {
val symbol=rest.split(',').last()
value = parseValue(opcode, symbol, program.size)
value = parseValueOrPlaceholder(operand, program.size, rest, 2, opcode)
operands.clear()
}
if(operands.isNotEmpty()) {
val symbol=rest.split(',').last()
value = parseValue(opcode, symbol, program.size)
TODO("placeholder symbol? $operands rest=$rest'")
operands.clear()
}
}
@ -319,26 +323,18 @@ class Assembler {
}
private fun parseValue(opcode: Opcode, value: String, pc: Int): Float {
if(value.startsWith("-")) {
return -parseValue(opcode, value.substring(1), pc)
}
if(value.startsWith('$'))
return value.substring(1).toInt(16).toFloat()
if(value.startsWith('%'))
return value.substring(1).toInt(2).toFloat()
if(value.startsWith("0x"))
return value.substring(2).toInt(16).toFloat()
if(value.startsWith('_')) {
if(opcode !in OpcodesForCpuRegisters)
placeholders[pc] = value.substring(1)
return 0f
}
if(value[0].isLetter()) {
if(opcode !in OpcodesForCpuRegisters)
placeholders[pc] = value
return 0f
}
return value.toFloat()
return if(value.startsWith("-"))
-parseValue(opcode, value.substring(1), pc)
else if(value.startsWith('$'))
value.substring(1).toInt(16).toFloat()
else if(value.startsWith('%'))
value.substring(1).toInt(2).toFloat()
else if(value.startsWith("0x"))
value.substring(2).toInt(16).toFloat()
else if(value.startsWith('_') || value[0].isLetter())
throw IllegalArgumentException("attempt to parse non-numeric value $value")
else
value.toFloat()
}
private fun convertType(typestr: String): VmDataType? {

View File

@ -1,6 +1,7 @@
package prog8.vm
import prog8.code.core.AssemblyError
import java.lang.NumberFormatException
import kotlin.math.min
/*
@ -253,13 +254,23 @@ object SysCalls {
}
Syscall.STR_TO_UWORD -> {
val stringAddr = vm.registers.getUW(0)
val string = vm.memory.getString(stringAddr.toInt())
vm.registers.setUW(0, string.toUShort())
val string = vm.memory.getString(stringAddr.toInt()).takeWhile { it.isDigit() }
val value = try {
string.toUShort()
} catch(_: NumberFormatException) {
0u
}
vm.registers.setUW(0, value)
}
Syscall.STR_TO_WORD -> {
val stringAddr = vm.registers.getUW(0)
val string = vm.memory.getString(stringAddr.toInt())
vm.registers.setSW(0, string.toShort())
val string = vm.memory.getString(stringAddr.toInt()).takeWhile { it.isDigit() }
val value = try {
string.toShort()
} catch(_: NumberFormatException) {
0
}
vm.registers.setSW(0, value)
}
Syscall.COMPARE_STRINGS -> {
val firstAddr = vm.registers.getUW(0)