IR: fix some things related to asmsubs

This commit is contained in:
Irmen de Jong 2024-03-21 23:40:36 +01:00
parent 60244aaf16
commit 66e7c51064
14 changed files with 90 additions and 36 deletions

View File

@ -44,7 +44,7 @@ sealed class PtExpression(val type: DataType, position: Position) : PtNode(posit
}
is PtContainmentCheck -> other is PtContainmentCheck && other.type==type && other.element isSameAs element && other.iterable isSameAs iterable
is PtIdentifier -> other is PtIdentifier && other.type==type && other.name==name
is PtMachineRegister -> other is PtMachineRegister && other.type==type && other.register==register
is PtIrRegister -> other is PtIrRegister && other.type==type && other.register==register
is PtMemoryByte -> other is PtMemoryByte && other.address isSameAs address
is PtNumber -> other is PtNumber && other.type==type && other.number==number
is PtBool -> other is PtBool && other.value==value
@ -87,7 +87,7 @@ sealed class PtExpression(val type: DataType, position: Position) : PtNode(posit
is PtContainmentCheck -> false
is PtFunctionCall -> false
is PtIdentifier -> true
is PtMachineRegister -> true
is PtIrRegister -> true
is PtMemoryByte -> address is PtNumber || address is PtIdentifier
is PtBool -> true
is PtNumber -> true
@ -354,7 +354,7 @@ class PtTypeCast(type: DataType, position: Position) : PtExpression(type, positi
// special node that isn't created from compiling user code, but used internally in the Intermediate Code
class PtMachineRegister(val register: Int, type: DataType, position: Position) : PtExpression(type, position)
class PtIrRegister(val register: Int, type: DataType, position: Position) : PtExpression(type, position)
fun constValue(expr: PtExpression): Double? = if(expr is PtNumber) expr.number else if(expr is PtBool) expr.asInt().toDouble() else null

View File

@ -34,7 +34,7 @@ fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Uni
str + node.name + "()"
}
is PtIdentifier -> "${node.name} ${type(node.type)}"
is PtMachineRegister -> "VMREG#${node.register} ${type(node.type)}"
is PtIrRegister -> "VMREG#${node.register} ${type(node.type)}"
is PtMemoryByte -> "@()"
is PtNumber -> {
val numstr = if(node.type == DataType.FLOAT) node.number.toString() else node.number.toHex()

View File

@ -81,7 +81,7 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as
}
is PtAddressOf -> false
is PtIdentifier -> false
is PtMachineRegister -> false
is PtIrRegister -> false
is PtMemoryByte -> return usesOtherRegistersWhileEvaluating(arg.address)
is PtNumber -> false
is PtBool -> false

View File

@ -70,7 +70,7 @@ internal class IfElseAsmGen(private val program: PtProgram,
is PtNumber,
is PtBool,
is PtIdentifier,
is PtMachineRegister,
is PtIrRegister,
is PtArrayIndexer,
is PtPrefix,
is PtBinaryExpression -> { /* no cmp necessary the lda has been done just prior */ }

View File

@ -667,7 +667,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
internal fun directIntoY(expr: PtExpression): Boolean {
return when(expr) {
is PtIdentifier -> true
is PtMachineRegister -> true
is PtIrRegister -> true
is PtNumber -> true
is PtBuiltinFunctionCall -> expr.name in arrayOf("lsb", "msb")
else -> false

View File

@ -8,7 +8,7 @@ import prog8.intermediate.*
internal class AssignmentGen(private val codeGen: IRCodeGen, private val expressionEval: ExpressionGen) {
internal fun translate(assignment: PtAssignment): IRCodeChunks {
if(assignment.target.children.single() is PtMachineRegister)
if(assignment.target.children.single() is PtIrRegister)
throw AssemblyError("assigning to a register should be done by just evaluating the expression into resultregister")
val chunks = translateRegularAssign(assignment)
@ -17,7 +17,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
}
internal fun translate(augAssign: PtAugmentedAssign): IRCodeChunks {
if(augAssign.target.children.single() is PtMachineRegister)
if(augAssign.target.children.single() is PtIrRegister)
throw AssemblyError("assigning to a register should be done by just evaluating the expression into resultregister")
val target = augAssign.target
@ -270,11 +270,11 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
else
throw AssemblyError("assignment value and target dt mismatch")
} else false
if (assignment.value is PtMachineRegister) {
valueRegister = (assignment.value as PtMachineRegister).register
if (assignment.value is PtIrRegister) {
valueRegister = (assignment.value as PtIrRegister).register
if(extendByteToWord) {
valueRegister = codeGen.registers.nextFree()
addInstr(result, IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1=valueRegister, reg2=(assignment.value as PtMachineRegister).register), null)
addInstr(result, IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1=valueRegister, reg2=(assignment.value as PtIrRegister).register), null)
}
} else {
val tr = expressionEval.translateExpression(assignment.value)

View File

@ -857,7 +857,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
val assignTarget = PtAssignTarget(target.position)
assignTarget.children.add(target)
assignment.children.add(assignTarget)
assignment.children.add(PtMachineRegister(register, target.type, target.position))
assignment.children.add(PtIrRegister(register, target.type, target.position))
val result = mutableListOf<IRCodeChunkBase>()
result += codeGen.translateNode(assignment)
return result

View File

@ -24,7 +24,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
fun translateExpression(expr: PtExpression): ExpressionCodeResult {
return when (expr) {
is PtMachineRegister -> {
is PtIrRegister -> {
ExpressionCodeResult(emptyList(), irType(expr.type), expr.register, -1)
}
is PtBool -> {
@ -505,8 +505,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
if(returnIrType==IRDataType.FLOAT)
FunctionCallArgs.RegSpec(returnIrType, codeGen.registers.nextFreeFloat(), returns.register)
else {
statusFlagResult = returns.register.statusflag
val returnRegister = if(statusFlagResult==null) codeGen.registers.nextFree() else -1
val returnRegister = codeGen.registers.nextFree()
FunctionCallArgs.RegSpec(returnIrType, returnRegister, returns.register)
}
} else {

View File

@ -3,16 +3,17 @@
%option no_sysinit
main {
str scanline_buf = "?"* 20
sub start() {
if diskio.f_open("test.prg") and diskio.f_read(scanline_buf, 2)==2
cx16.r0++
bool @shared flag
if diskio.f_open("test.prg") or diskio.f_read(scanline_buf, 2)==2
cx16.r0++
cx16.r0L = test(12345, flag, -42)
if diskio.f_open("test.prg") xor diskio.f_read(scanline_buf, 2)==2
cx16.r0++
}
asmsub test(uword arg @AY, bool flag @Pc, byte value @X) -> ubyte @A, bool @Pc {
%asm {{
txa
rts
}}
}
}

View File

@ -497,7 +497,7 @@ class IRFileReader {
private fun parseDatatype(type: String, isArray: Boolean): DataType {
if(isArray) {
return when(type) {
// note: there are no BOOLEANS anymore in the IR. Only UBYTE.
// note: there are no BOOLEANS arrays anymore in the IR. Only UBYTE.
"byte" -> DataType.ARRAY_B
"ubyte", "str" -> DataType.ARRAY_UB
"word" -> DataType.ARRAY_W
@ -509,7 +509,7 @@ class IRFileReader {
}
} else {
return when(type) {
// note: there are no BOOLEANS anymore in the IR. Only UBYTE.
"bool" -> DataType.BOOL
"byte" -> DataType.BYTE
"ubyte" -> DataType.UBYTE
"word" -> DataType.WORD

View File

@ -41,6 +41,12 @@ loadi reg1, reg2 - load reg1 with value at memory indirect,
loadx reg1, reg2, address - load reg1 with value at memory address indexed by value in reg2 (only the lsb part used for indexing)
loadix reg1, reg2, pointeraddr - load reg1 with value at memory indirect, pointed to by pointeraddr indexed by value in reg2 (only the lsb part used for indexing)
loadr reg1, reg2 - load reg1 with value in register reg2
loadha reg1 - load cpu hardware register A into reg1.b
loadhx reg1 - load cpu hardware register X into reg1.b
loadhy reg1 - load cpu hardware register Y into reg1.b
loadhax reg1 - load cpu hardware register pair AX into reg1.w
loadhay reg1 - load cpu hardware register pair AY into reg1.w
loadhxy reg1 - load cpu hardware register pair XY into reg1.w
storem reg1, address - store reg1 at memory address
storei reg1, reg2 - store reg1 at memory indirect, memory pointed to by reg2
storex reg1, reg2, address - store reg1 at memory address, indexed by value in reg2 (only the lsb part used for indexing)
@ -48,6 +54,12 @@ storeix reg1, reg2, pointeraddr - store reg1 at memory indirect, pointed t
storezm address - store zero at memory address
storezi reg1 - store zero at memory pointed to by reg1
storezx reg1, address - store zero at memory address, indexed by value in reg1 (only the lsb part used for indexing)
storeha reg1 - store reg1.b into cpu hardware register A
storehx reg1 - store reg1.b into cpu hardware register X
storehy reg1 - store reg1.b into cpu hardware register Y
storehax reg1 - store reg1.w into cpu hardware register pair AX
storehay reg1 - store reg1.w into cpu hardware register pair AY
storehxy reg1 - store reg1.w into cpu hardware register pair XY
CONTROL FLOW
@ -247,6 +259,12 @@ enum class Opcode {
LOADX,
LOADIX,
LOADR,
LOADHA,
LOADHX,
LOADHY,
LOADHAX,
LOADHAY,
LOADHXY,
STOREM,
STOREI,
STOREX,
@ -254,6 +272,12 @@ enum class Opcode {
STOREZM,
STOREZI,
STOREZX,
STOREHA,
STOREHX,
STOREHY,
STOREHAX,
STOREHAY,
STOREHXY,
JUMP,
JUMPI,
@ -444,6 +468,12 @@ val OpcodesThatSetStatusbitsButNotCarry = arrayOf(
Opcode.LOADX,
Opcode.LOADIX,
Opcode.LOADR,
Opcode.LOADHA,
Opcode.LOADHX,
Opcode.LOADHY,
Opcode.LOADHAX,
Opcode.LOADHAY,
Opcode.LOADHXY,
Opcode.NEG,
Opcode.NEGM,
Opcode.INC,
@ -585,6 +615,13 @@ val instructionFormats = mutableMapOf(
Opcode.LOADX to InstructionFormat.from("BW,>r1,<r2,<a | F,>fr1,<r1,<a"),
Opcode.LOADIX to InstructionFormat.from("BW,>r1,<r2,<a | F,>fr1,<r1,<a"),
Opcode.LOADR to InstructionFormat.from("BW,>r1,<r2 | F,>fr1,<fr2"),
Opcode.LOADHA to InstructionFormat.from("B,>r1"),
Opcode.LOADHA to InstructionFormat.from("B,>r1"),
Opcode.LOADHX to InstructionFormat.from("B,>r1"),
Opcode.LOADHY to InstructionFormat.from("B,>r1"),
Opcode.LOADHAX to InstructionFormat.from("W,>r1"),
Opcode.LOADHAY to InstructionFormat.from("W,>r1"),
Opcode.LOADHXY to InstructionFormat.from("W,>r1"),
Opcode.STOREM to InstructionFormat.from("BW,<r1,>a | F,<fr1,>a"),
Opcode.STOREI to InstructionFormat.from("BW,<r1,<r2 | F,<fr1,<r1"),
Opcode.STOREX to InstructionFormat.from("BW,<r1,<r2,>a | F,<fr1,<r1,>a"),
@ -592,6 +629,13 @@ val instructionFormats = mutableMapOf(
Opcode.STOREZM to InstructionFormat.from("BW,>a | F,>a"),
Opcode.STOREZI to InstructionFormat.from("BW,<r1 | F,<r1"),
Opcode.STOREZX to InstructionFormat.from("BW,<r1,>a | F,<r1,>a"),
Opcode.STOREHA to InstructionFormat.from("B,<r1"),
Opcode.STOREHA to InstructionFormat.from("B,<r1"),
Opcode.STOREHX to InstructionFormat.from("B,<r1"),
Opcode.STOREHY to InstructionFormat.from("B,<r1"),
Opcode.STOREHAX to InstructionFormat.from("W,<r1"),
Opcode.STOREHAY to InstructionFormat.from("W,<r1"),
Opcode.STOREHXY to InstructionFormat.from("W,<r1"),
Opcode.JUMP to InstructionFormat.from("N,<a"),
Opcode.JUMPI to InstructionFormat.from("N,<a"),
Opcode.PREPARECALL to InstructionFormat.from("N,<i"),
@ -1020,13 +1064,10 @@ data class IRInstruction(
IRDataType.FLOAT -> result.add("fr${returns.registerNum}.f")
}
} else {
result.add("@" + cpuReg)
if(returns.cpuRegister?.statusflag==null) {
when (returns.dt) {
IRDataType.BYTE -> result.add(".b")
IRDataType.WORD -> result.add(".w")
IRDataType.FLOAT -> result.add(".f")
}
when(returns.dt) {
IRDataType.BYTE -> result.add("r${returns.registerNum}.b@" + cpuReg)
IRDataType.WORD -> result.add("r${returns.registerNum}.w@" + cpuReg)
IRDataType.FLOAT -> result.add("r${returns.registerNum}.f@" + cpuReg)
}
}
}

View File

@ -178,6 +178,12 @@ class VirtualMachine(irProgram: IRProgram) {
Opcode.LOADI -> InsLOADI(ins)
Opcode.LOADIX -> InsLOADIX(ins)
Opcode.LOADR -> InsLOADR(ins)
Opcode.LOADHA,
Opcode.LOADHX,
Opcode.LOADHY,
Opcode.LOADHAX,
Opcode.LOADHAY,
Opcode.LOADHXY -> throw IllegalArgumentException("VM cannot access actual CPU hardware register")
Opcode.STOREM -> InsSTOREM(ins)
Opcode.STOREX -> InsSTOREX(ins)
Opcode.STOREIX -> InsSTOREIX(ins)
@ -185,10 +191,16 @@ class VirtualMachine(irProgram: IRProgram) {
Opcode.STOREZM -> InsSTOREZM(ins)
Opcode.STOREZX -> InsSTOREZX(ins)
Opcode.STOREZI -> InsSTOREZI(ins)
Opcode.STOREHA,
Opcode.STOREHX,
Opcode.STOREHY,
Opcode.STOREHAX,
Opcode.STOREHAY,
Opcode.STOREHXY -> throw IllegalArgumentException("VM cannot access actual CPU hardware register")
Opcode.JUMP -> InsJUMP(ins)
Opcode.JUMPI -> InsJUMPI(ins)
Opcode.PREPARECALL -> nextPc()
Opcode.CALLI -> throw IllegalArgumentException("VM cannot run code from memory")
Opcode.CALLI -> throw IllegalArgumentException("VM cannot run code from memory bytes")
Opcode.CALL -> InsCALL(ins)
Opcode.SYSCALL -> InsSYSCALL(ins)
Opcode.RETURN -> InsRETURN()
@ -319,6 +331,7 @@ class VirtualMachine(irProgram: IRProgram) {
Opcode.FFLOOR -> InsFFLOOR(ins)
Opcode.FCEIL -> InsFCEIL(ins)
Opcode.FCOMP -> InsFCOMP(ins)
else -> throw IllegalArgumentException("invalid opcode ${ins.opcode}")
}
}

View File

@ -44,7 +44,7 @@ class VmProgramLoader {
block.children.forEach { child ->
when(child) {
is IRAsmSubroutine -> throw IRParseException("vm does not support non-inlined asmsubs (use normal sub): ${child.label}")
is IRAsmSubroutine -> throw IRParseException("vm does not support asmsubs (use normal sub): ${child.label}")
is IRCodeChunk -> programChunks += child
is IRInlineAsmChunk -> throw IRParseException("encountered unconverted inline assembly chunk")
is IRInlineBinaryChunk -> throw IRParseException("inline binary data not yet supported in the VM")

View File

@ -85,7 +85,7 @@ class TestVm: FunSpec( {
)
block += startSub
program.addBlock(block)
shouldThrowWithMessage<IRParseException>("vm does not support non-inlined asmsubs (use normal sub): main.asmstart") {
shouldThrowWithMessage<IRParseException>("vm does not support asmsubs (use normal sub): main.asmstart") {
VirtualMachine(program)
}
}