mirror of
https://github.com/irmen/prog8.git
synced 2025-02-21 10:29:03 +00:00
fix various IR file and symboltable issues
This commit is contained in:
parent
8acd94fc89
commit
fd07ae5225
@ -133,7 +133,7 @@ open class StNode(val name: String,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val scopedNameList: List<String> by lazy {
|
private val scopedNameList: List<String> by lazy {
|
||||||
if(type== StNodeType.GLOBAL)
|
if(type==StNodeType.GLOBAL)
|
||||||
emptyList()
|
emptyList()
|
||||||
else
|
else
|
||||||
parent.scopedNameList + name
|
parent.scopedNameList + name
|
||||||
@ -142,7 +142,7 @@ open class StNode(val name: String,
|
|||||||
private fun lookup(scopedName: List<String>): StNode? {
|
private fun lookup(scopedName: List<String>): StNode? {
|
||||||
// a scoped name refers to a name in another namespace, and always stars from the root.
|
// a scoped name refers to a name in another namespace, and always stars from the root.
|
||||||
var node = this
|
var node = this
|
||||||
while(node.type!= StNodeType.GLOBAL)
|
while(node.type!=StNodeType.GLOBAL)
|
||||||
node = node.parent
|
node = node.parent
|
||||||
|
|
||||||
for(name in scopedName) {
|
for(name in scopedName) {
|
||||||
@ -201,6 +201,11 @@ class StMemVar(name: String,
|
|||||||
val length: Int?, // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte
|
val length: Int?, // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte
|
||||||
astNode: PtNode) :
|
astNode: PtNode) :
|
||||||
StNode(name, StNodeType.MEMVAR, astNode) {
|
StNode(name, StNodeType.MEMVAR, astNode) {
|
||||||
|
|
||||||
|
init{
|
||||||
|
if(dt in ArrayDatatypes || dt == DataType.STR)
|
||||||
|
require(length!=null) { "memory mapped array or string must have known length" }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class StMemorySlab(
|
class StMemorySlab(
|
||||||
|
@ -26,11 +26,11 @@ class SymbolTableMaker(private val program: PtProgram, private val options: Comp
|
|||||||
PtMemMapped("P8ZP_SCRATCH_REG", DataType.UBYTE, options.compTarget.machine.zeropage.SCRATCH_REG, null, Position.DUMMY),
|
PtMemMapped("P8ZP_SCRATCH_REG", DataType.UBYTE, options.compTarget.machine.zeropage.SCRATCH_REG, null, Position.DUMMY),
|
||||||
PtMemMapped("P8ZP_SCRATCH_W1", DataType.UWORD, options.compTarget.machine.zeropage.SCRATCH_W1, null, Position.DUMMY),
|
PtMemMapped("P8ZP_SCRATCH_W1", DataType.UWORD, options.compTarget.machine.zeropage.SCRATCH_W1, null, Position.DUMMY),
|
||||||
PtMemMapped("P8ZP_SCRATCH_W2", DataType.UWORD, options.compTarget.machine.zeropage.SCRATCH_W2, null, Position.DUMMY),
|
PtMemMapped("P8ZP_SCRATCH_W2", DataType.UWORD, options.compTarget.machine.zeropage.SCRATCH_W2, null, Position.DUMMY),
|
||||||
PtMemMapped("P8ESTACK_LO", DataType.ARRAY_UB, options.compTarget.machine.ESTACK_LO, 256u, Position.DUMMY),
|
PtMemMapped("P8ESTACK_LO", DataType.ARRAY_UB, options.compTarget.machine.ESTACK_LO, 128u, Position.DUMMY),
|
||||||
PtMemMapped("P8ESTACK_HI", DataType.ARRAY_UB, options.compTarget.machine.ESTACK_HI, 256u, Position.DUMMY)
|
PtMemMapped("P8ESTACK_HI", DataType.ARRAY_UB, options.compTarget.machine.ESTACK_HI, 128u, Position.DUMMY)
|
||||||
).forEach {
|
).forEach {
|
||||||
it.parent = program
|
it.parent = program
|
||||||
st.add(StMemVar(it.name, it.type, it.address, null, it))
|
st.add(StMemVar(it.name, it.type, it.address, it.arraySize?.toInt(), it))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,7 +265,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
val addressReg = codeGen.registers.nextFree()
|
val addressReg = codeGen.registers.nextFree()
|
||||||
result += exprGen.translateExpression(call.args[0], addressReg, -1)
|
result += exprGen.translateExpression(call.args[0], addressReg, -1)
|
||||||
result += IRCodeChunk(null, null).also {
|
result += IRCodeChunk(null, null).also {
|
||||||
it += IRInstruction(Opcode.STOREZI, IRDataType.WORD, reg2 = addressReg)
|
it += IRInstruction(Opcode.STOREZI, IRDataType.WORD, reg1 = addressReg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -300,7 +300,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
val addressReg = codeGen.registers.nextFree()
|
val addressReg = codeGen.registers.nextFree()
|
||||||
result += exprGen.translateExpression(call.args[0], addressReg, -1)
|
result += exprGen.translateExpression(call.args[0], addressReg, -1)
|
||||||
result += IRCodeChunk(null, null).also {
|
result += IRCodeChunk(null, null).also {
|
||||||
it += IRInstruction(Opcode.STOREZI, IRDataType.BYTE, reg2 = addressReg)
|
it += IRInstruction(Opcode.STOREZI, IRDataType.BYTE, reg1 = addressReg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -16,6 +16,9 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
require(codeGen.registers.peekNext() > resultRegister || resultRegister >= SyscallRegisterBase) {
|
require(codeGen.registers.peekNext() > resultRegister || resultRegister >= SyscallRegisterBase) {
|
||||||
"no more registers for expression ${expr.position}"
|
"no more registers for expression ${expr.position}"
|
||||||
}
|
}
|
||||||
|
require((expr.type!=DataType.FLOAT && resultRegister>=0) || (expr.type==DataType.FLOAT && resultFpRegister>=0)) {
|
||||||
|
"mismatched result register for expression datatype ${expr.type} ${expr.position}"
|
||||||
|
}
|
||||||
|
|
||||||
return when (expr) {
|
return when (expr) {
|
||||||
is PtMachineRegister -> {
|
is PtMachineRegister -> {
|
||||||
|
@ -358,6 +358,12 @@ class IRCodeGen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun labelFirstChunk(chunks: IRCodeChunks, label: String): IRCodeChunks {
|
private fun labelFirstChunk(chunks: IRCodeChunks, label: String): IRCodeChunks {
|
||||||
|
if(chunks.isEmpty()) {
|
||||||
|
return listOf(
|
||||||
|
IRCodeChunk(label, null)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
require(chunks.isNotEmpty() && label.isNotBlank())
|
require(chunks.isNotEmpty() && label.isNotBlank())
|
||||||
val first = chunks[0]
|
val first = chunks[0]
|
||||||
if(first.label!=null) {
|
if(first.label!=null) {
|
||||||
@ -883,16 +889,25 @@ class IRCodeGen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun translate(ifElse: PtIfElse): IRCodeChunks {
|
private fun translate(ifElse: PtIfElse): IRCodeChunks {
|
||||||
if(ifElse.condition.operator !in ComparisonOperators)
|
val condition = ifElse.condition
|
||||||
|
if(condition.operator !in ComparisonOperators)
|
||||||
throw AssemblyError("if condition should only be a binary comparison expression")
|
throw AssemblyError("if condition should only be a binary comparison expression")
|
||||||
|
|
||||||
val signed = ifElse.condition.left.type in SignedDatatypes
|
val signed = condition.left.type in SignedDatatypes
|
||||||
val irDt = irType(ifElse.condition.left.type)
|
val irDtLeft = irType(condition.left.type)
|
||||||
|
|
||||||
val goto = ifElse.ifScope.children.firstOrNull() as? PtJump
|
val goto = ifElse.ifScope.children.firstOrNull() as? PtJump
|
||||||
if(goto!=null && ifElse.elseScope.children.isEmpty()) {
|
return when {
|
||||||
// special case the form: if <condition> goto <place>
|
goto!=null && ifElse.elseScope.children.isEmpty() -> translateIfFollowedByJustGoto(ifElse, goto, irDtLeft, signed)
|
||||||
|
constValue(condition.right) == 0.0 -> translateIfElseZeroComparison(ifElse, irDtLeft, signed)
|
||||||
|
else -> translateIfElseNonZeroComparison(ifElse, irDtLeft, signed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun translateIfFollowedByJustGoto(ifElse: PtIfElse, goto: PtJump, irDtLeft: IRDataType, signed: Boolean): MutableList<IRCodeChunkBase> {
|
||||||
val result = mutableListOf<IRCodeChunkBase>()
|
val result = mutableListOf<IRCodeChunkBase>()
|
||||||
|
if(irDtLeft==IRDataType.FLOAT) {
|
||||||
|
TODO("float comparison followed by goto")
|
||||||
|
} else {
|
||||||
val leftRegNum = registers.nextFree()
|
val leftRegNum = registers.nextFree()
|
||||||
val rightRegNum = registers.nextFree()
|
val rightRegNum = registers.nextFree()
|
||||||
result += expressionEval.translateExpression(ifElse.condition.left, leftRegNum, -1)
|
result += expressionEval.translateExpression(ifElse.condition.left, leftRegNum, -1)
|
||||||
@ -900,7 +915,7 @@ class IRCodeGen(
|
|||||||
val opcode: Opcode
|
val opcode: Opcode
|
||||||
val firstReg: Int
|
val firstReg: Int
|
||||||
val secondReg: Int
|
val secondReg: Int
|
||||||
when(ifElse.condition.operator) {
|
when (ifElse.condition.operator) {
|
||||||
"==" -> {
|
"==" -> {
|
||||||
opcode = Opcode.BEQ
|
opcode = Opcode.BEQ
|
||||||
firstReg = leftRegNum
|
firstReg = leftRegNum
|
||||||
@ -913,48 +928,93 @@ class IRCodeGen(
|
|||||||
}
|
}
|
||||||
"<" -> {
|
"<" -> {
|
||||||
// swapped '>'
|
// swapped '>'
|
||||||
opcode = if(signed) Opcode.BGTS else Opcode.BGT
|
opcode = if (signed) Opcode.BGTS else Opcode.BGT
|
||||||
firstReg = rightRegNum
|
firstReg = rightRegNum
|
||||||
secondReg = leftRegNum
|
secondReg = leftRegNum
|
||||||
}
|
}
|
||||||
">" -> {
|
">" -> {
|
||||||
opcode = if(signed) Opcode.BGTS else Opcode.BGT
|
opcode = if (signed) Opcode.BGTS else Opcode.BGT
|
||||||
firstReg = leftRegNum
|
firstReg = leftRegNum
|
||||||
secondReg = rightRegNum
|
secondReg = rightRegNum
|
||||||
}
|
}
|
||||||
"<=" -> {
|
"<=" -> {
|
||||||
// swapped '>='
|
// swapped '>='
|
||||||
opcode = if(signed) Opcode.BGES else Opcode.BGE
|
opcode = if (signed) Opcode.BGES else Opcode.BGE
|
||||||
firstReg = rightRegNum
|
firstReg = rightRegNum
|
||||||
secondReg = leftRegNum
|
secondReg = leftRegNum
|
||||||
}
|
}
|
||||||
">=" -> {
|
">=" -> {
|
||||||
opcode = if(signed) Opcode.BGES else Opcode.BGE
|
opcode = if (signed) Opcode.BGES else Opcode.BGE
|
||||||
firstReg = leftRegNum
|
firstReg = leftRegNum
|
||||||
secondReg = rightRegNum
|
secondReg = rightRegNum
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("invalid comparison operator")
|
else -> throw AssemblyError("invalid comparison operator")
|
||||||
}
|
}
|
||||||
if(goto.address!=null)
|
if (goto.address != null)
|
||||||
addInstr(result, IRInstruction(opcode, irDt, reg1=firstReg, reg2=secondReg, value = goto.address?.toInt()), null)
|
addInstr(result, IRInstruction(opcode, irDtLeft, reg1 = firstReg, reg2 = secondReg, value = goto.address?.toInt()), null)
|
||||||
else if(goto.generatedLabel!=null)
|
else if (goto.generatedLabel != null)
|
||||||
addInstr(result, IRInstruction(opcode, irDt, reg1=firstReg, reg2=secondReg, labelSymbol = goto.generatedLabel), null)
|
addInstr(result, IRInstruction(opcode, irDtLeft, reg1 = firstReg, reg2 = secondReg, labelSymbol = goto.generatedLabel), null)
|
||||||
else
|
else
|
||||||
addInstr(result, IRInstruction(opcode, irDt, reg1=firstReg, reg2=secondReg, labelSymbol = goto.identifier!!.name), null)
|
addInstr(result, IRInstruction(opcode, irDtLeft, reg1 = firstReg, reg2 = secondReg, labelSymbol = goto.identifier!!.name), null)
|
||||||
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
fun translateNonZeroComparison(): IRCodeChunks {
|
private fun translateIfElseZeroComparison(ifElse: PtIfElse, irDtLeft: IRDataType, signed: Boolean): IRCodeChunks {
|
||||||
|
if(irDtLeft==IRDataType.FLOAT) {
|
||||||
|
TODO("float zero compare via fcomp instruction")
|
||||||
|
} else {
|
||||||
|
// integer comparisons
|
||||||
|
fun equalOrNotEqualZero(elseBranch: Opcode): IRCodeChunks {
|
||||||
|
val result = mutableListOf<IRCodeChunkBase>()
|
||||||
|
val leftReg = registers.nextFree()
|
||||||
|
result += expressionEval.translateExpression(ifElse.condition.left, leftReg, -1)
|
||||||
|
if(ifElse.elseScope.children.isNotEmpty()) {
|
||||||
|
// if and else parts
|
||||||
|
val elseLabel = createLabelName()
|
||||||
|
val afterIfLabel = createLabelName()
|
||||||
|
addInstr(result, IRInstruction(elseBranch, irDtLeft, reg1=leftReg, labelSymbol = elseLabel), null)
|
||||||
|
result += translateNode(ifElse.ifScope)
|
||||||
|
addInstr(result, IRInstruction(Opcode.JUMP, labelSymbol = afterIfLabel), null)
|
||||||
|
result += labelFirstChunk(translateNode(ifElse.elseScope), elseLabel)
|
||||||
|
result += IRCodeChunk(afterIfLabel, null)
|
||||||
|
} else {
|
||||||
|
// only if part
|
||||||
|
val afterIfLabel = createLabelName()
|
||||||
|
addInstr(result, IRInstruction(elseBranch, irDtLeft, reg1=leftReg, labelSymbol = afterIfLabel), null)
|
||||||
|
result += translateNode(ifElse.ifScope)
|
||||||
|
result += IRCodeChunk(afterIfLabel, null)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
return when (ifElse.condition.operator) {
|
||||||
|
"==" -> equalOrNotEqualZero(Opcode.BNZ)
|
||||||
|
"!=" -> equalOrNotEqualZero(Opcode.BZ)
|
||||||
|
"<" -> if (signed) equalOrNotEqualZero(Opcode.BGEZS) else throw AssemblyError("unsigned < 0 shouldn't occur in codegen")
|
||||||
|
">" -> if (signed) equalOrNotEqualZero(Opcode.BLEZS) else throw AssemblyError("unsigned > 0 shouldn't occur in codegen")
|
||||||
|
"<=" -> if (signed) equalOrNotEqualZero(Opcode.BGZS) else throw AssemblyError("unsigned <= 0 shouldn't occur in codegen")
|
||||||
|
">=" -> if (signed) equalOrNotEqualZero(Opcode.BLZS) else throw AssemblyError("unsigned >= 0 shouldn't occur in codegen")
|
||||||
|
else -> throw AssemblyError("weird operator")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun translateIfElseNonZeroComparison(ifElse: PtIfElse, irDtLeft: IRDataType, signed: Boolean): IRCodeChunks {
|
||||||
val result = mutableListOf<IRCodeChunkBase>()
|
val result = mutableListOf<IRCodeChunkBase>()
|
||||||
val leftRegNum = registers.nextFree()
|
|
||||||
val rightRegNum = registers.nextFree()
|
|
||||||
result += expressionEval.translateExpression(ifElse.condition.left, leftRegNum, -1)
|
|
||||||
result += expressionEval.translateExpression(ifElse.condition.right, rightRegNum, -1)
|
|
||||||
|
|
||||||
val elseBranchOpcode: Opcode
|
val elseBranchOpcode: Opcode
|
||||||
val elseBranchFirstReg: Int
|
val elseBranchFirstReg: Int
|
||||||
val elseBranchSecondReg: Int
|
val elseBranchSecondReg: Int
|
||||||
when(ifElse.condition.operator) {
|
|
||||||
|
if(irDtLeft==IRDataType.FLOAT) {
|
||||||
|
TODO("float non-zero compare via fcomp instruction")
|
||||||
|
} else {
|
||||||
|
// integer comparisons
|
||||||
|
val leftRegNum = registers.nextFree()
|
||||||
|
val rightRegNum = registers.nextFree()
|
||||||
|
result += expressionEval.translateExpression(ifElse.condition.left, leftRegNum, -1)
|
||||||
|
result += expressionEval.translateExpression(ifElse.condition.right, rightRegNum, -1)
|
||||||
|
when (ifElse.condition.operator) {
|
||||||
"==" -> {
|
"==" -> {
|
||||||
elseBranchOpcode = Opcode.BNE
|
elseBranchOpcode = Opcode.BNE
|
||||||
elseBranchFirstReg = leftRegNum
|
elseBranchFirstReg = leftRegNum
|
||||||
@ -967,36 +1027,37 @@ class IRCodeGen(
|
|||||||
}
|
}
|
||||||
"<" -> {
|
"<" -> {
|
||||||
// else part when left >= right
|
// else part when left >= right
|
||||||
elseBranchOpcode = if(signed) Opcode.BGES else Opcode.BGE
|
elseBranchOpcode = if (signed) Opcode.BGES else Opcode.BGE
|
||||||
elseBranchFirstReg = leftRegNum
|
elseBranchFirstReg = leftRegNum
|
||||||
elseBranchSecondReg = rightRegNum
|
elseBranchSecondReg = rightRegNum
|
||||||
}
|
}
|
||||||
">" -> {
|
">" -> {
|
||||||
// else part when left <= right --> right >= left
|
// else part when left <= right --> right >= left
|
||||||
elseBranchOpcode = if(signed) Opcode.BGES else Opcode.BGE
|
elseBranchOpcode = if (signed) Opcode.BGES else Opcode.BGE
|
||||||
elseBranchFirstReg = rightRegNum
|
elseBranchFirstReg = rightRegNum
|
||||||
elseBranchSecondReg = leftRegNum
|
elseBranchSecondReg = leftRegNum
|
||||||
}
|
}
|
||||||
"<=" -> {
|
"<=" -> {
|
||||||
// else part when left > right
|
// else part when left > right
|
||||||
elseBranchOpcode = if(signed) Opcode.BGTS else Opcode.BGT
|
elseBranchOpcode = if (signed) Opcode.BGTS else Opcode.BGT
|
||||||
elseBranchFirstReg = leftRegNum
|
elseBranchFirstReg = leftRegNum
|
||||||
elseBranchSecondReg = rightRegNum
|
elseBranchSecondReg = rightRegNum
|
||||||
}
|
}
|
||||||
">=" -> {
|
">=" -> {
|
||||||
// else part when left < right --> right > left
|
// else part when left < right --> right > left
|
||||||
elseBranchOpcode = if(signed) Opcode.BGTS else Opcode.BGT
|
elseBranchOpcode = if (signed) Opcode.BGTS else Opcode.BGT
|
||||||
elseBranchFirstReg = rightRegNum
|
elseBranchFirstReg = rightRegNum
|
||||||
elseBranchSecondReg = leftRegNum
|
elseBranchSecondReg = leftRegNum
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("invalid comparison operator")
|
else -> throw AssemblyError("invalid comparison operator")
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ifElse.elseScope.children.isNotEmpty()) {
|
if(ifElse.elseScope.children.isNotEmpty()) {
|
||||||
// if and else parts
|
// if and else parts
|
||||||
val elseLabel = createLabelName()
|
val elseLabel = createLabelName()
|
||||||
val afterIfLabel = createLabelName()
|
val afterIfLabel = createLabelName()
|
||||||
addInstr(result, IRInstruction(elseBranchOpcode, irDt, reg1=elseBranchFirstReg, reg2=elseBranchSecondReg, labelSymbol = elseLabel), null)
|
addInstr(result, IRInstruction(elseBranchOpcode, irDtLeft,
|
||||||
|
reg1=elseBranchFirstReg, reg2=elseBranchSecondReg,
|
||||||
|
labelSymbol = elseLabel), null)
|
||||||
result += translateNode(ifElse.ifScope)
|
result += translateNode(ifElse.ifScope)
|
||||||
addInstr(result, IRInstruction(Opcode.JUMP, labelSymbol = afterIfLabel), null)
|
addInstr(result, IRInstruction(Opcode.JUMP, labelSymbol = afterIfLabel), null)
|
||||||
result += labelFirstChunk(translateNode(ifElse.elseScope), elseLabel)
|
result += labelFirstChunk(translateNode(ifElse.elseScope), elseLabel)
|
||||||
@ -1004,54 +1065,17 @@ class IRCodeGen(
|
|||||||
} else {
|
} else {
|
||||||
// only if part
|
// only if part
|
||||||
val afterIfLabel = createLabelName()
|
val afterIfLabel = createLabelName()
|
||||||
addInstr(result, IRInstruction(elseBranchOpcode, irDt, reg1=elseBranchFirstReg, reg2=elseBranchSecondReg, labelSymbol = afterIfLabel), null)
|
addInstr(result, IRInstruction(elseBranchOpcode, irDtLeft,
|
||||||
|
reg1=elseBranchFirstReg, reg2=elseBranchSecondReg,
|
||||||
|
labelSymbol = afterIfLabel), null)
|
||||||
result += translateNode(ifElse.ifScope)
|
result += translateNode(ifElse.ifScope)
|
||||||
result += IRCodeChunk(afterIfLabel, null)
|
result += IRCodeChunk(afterIfLabel, null)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
fun translateZeroComparison(): IRCodeChunks {
|
|
||||||
fun equalOrNotEqualZero(elseBranch: Opcode): IRCodeChunks {
|
|
||||||
val result = mutableListOf<IRCodeChunkBase>()
|
|
||||||
val leftReg = registers.nextFree()
|
|
||||||
result += expressionEval.translateExpression(ifElse.condition.left, leftReg, -1)
|
|
||||||
if(ifElse.elseScope.children.isNotEmpty()) {
|
|
||||||
// if and else parts
|
|
||||||
val elseLabel = createLabelName()
|
|
||||||
val afterIfLabel = createLabelName()
|
|
||||||
addInstr(result, IRInstruction(elseBranch, irDt, reg1=leftReg, labelSymbol = elseLabel), null)
|
|
||||||
result += translateNode(ifElse.ifScope)
|
|
||||||
addInstr(result, IRInstruction(Opcode.JUMP, labelSymbol = afterIfLabel), null)
|
|
||||||
result += labelFirstChunk(translateNode(ifElse.elseScope), elseLabel)
|
|
||||||
result += IRCodeChunk(afterIfLabel, null)
|
|
||||||
} else {
|
|
||||||
// only if part
|
|
||||||
val afterIfLabel = createLabelName()
|
|
||||||
addInstr(result, IRInstruction(elseBranch, irDt, reg1=leftReg, labelSymbol = afterIfLabel), null)
|
|
||||||
result += translateNode(ifElse.ifScope)
|
|
||||||
result += IRCodeChunk(afterIfLabel, null)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
return when (ifElse.condition.operator) {
|
|
||||||
"==" -> equalOrNotEqualZero(Opcode.BNZ)
|
|
||||||
"!=" -> equalOrNotEqualZero(Opcode.BZ)
|
|
||||||
"<" -> if(signed) equalOrNotEqualZero(Opcode.BGEZS) else throw AssemblyError("unsigned < 0 shouldn't occur in codegen")
|
|
||||||
">" -> if(signed) equalOrNotEqualZero(Opcode.BLEZS) else throw AssemblyError("unsigned > 0 shouldn't occur in codegen")
|
|
||||||
"<=" -> if(signed) equalOrNotEqualZero(Opcode.BGZS) else throw AssemblyError("unsigned <= 0 shouldn't occur in codegen")
|
|
||||||
">=" -> if(signed) equalOrNotEqualZero(Opcode.BLZS) else throw AssemblyError("unsigned >= 0 shouldn't occur in codegen")
|
|
||||||
else -> throw AssemblyError("weird operator")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return if(constValue(ifElse.condition.right)==0.0)
|
|
||||||
translateZeroComparison()
|
|
||||||
else
|
|
||||||
translateNonZeroComparison()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun translate(postIncrDecr: PtPostIncrDecr): IRCodeChunks {
|
private fun translate(postIncrDecr: PtPostIncrDecr): IRCodeChunks {
|
||||||
val operationMem: Opcode
|
val operationMem: Opcode
|
||||||
val operationRegister: Opcode
|
val operationRegister: Opcode
|
||||||
|
@ -100,4 +100,343 @@ class TestVmCodeGen: FunSpec({
|
|||||||
val irChunks = (result.irProgram.blocks.first().children.single() as IRSubroutine).chunks
|
val irChunks = (result.irProgram.blocks.first().children.single() as IRSubroutine).chunks
|
||||||
irChunks.size shouldBeGreaterThan 4
|
irChunks.size shouldBeGreaterThan 4
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test("float comparison expressions against zero") {
|
||||||
|
//main {
|
||||||
|
// sub start() {
|
||||||
|
// float @shared f1
|
||||||
|
//
|
||||||
|
// if f1==0
|
||||||
|
// nop
|
||||||
|
// if f1!=0
|
||||||
|
// nop
|
||||||
|
// if f1>0
|
||||||
|
// nop
|
||||||
|
// if f1<0
|
||||||
|
// nop
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
val codegen = VmCodeGen()
|
||||||
|
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
||||||
|
val block = PtBlock("main", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||||
|
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||||
|
sub.add(PtVariable("f1", DataType.FLOAT, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
|
||||||
|
val if1 = PtIfElse(Position.DUMMY)
|
||||||
|
val cmp1 = PtBinaryExpression("==", DataType.UBYTE, Position.DUMMY)
|
||||||
|
cmp1.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY))
|
||||||
|
cmp1.add(PtNumber(DataType.FLOAT, 0.0, Position.DUMMY))
|
||||||
|
if1.add(cmp1)
|
||||||
|
if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||||
|
if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||||
|
sub.add(if1)
|
||||||
|
val if2 = PtIfElse(Position.DUMMY)
|
||||||
|
val cmp2 = PtBinaryExpression("!=", DataType.UBYTE, Position.DUMMY)
|
||||||
|
cmp2.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY))
|
||||||
|
cmp2.add(PtNumber(DataType.FLOAT, 0.0, Position.DUMMY))
|
||||||
|
if2.add(cmp2)
|
||||||
|
if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||||
|
if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||||
|
sub.add(if2)
|
||||||
|
val if3 = PtIfElse(Position.DUMMY)
|
||||||
|
val cmp3 = PtBinaryExpression("<", DataType.UBYTE, Position.DUMMY)
|
||||||
|
cmp3.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY))
|
||||||
|
cmp3.add(PtNumber(DataType.FLOAT, 0.0, Position.DUMMY))
|
||||||
|
if3.add(cmp3)
|
||||||
|
if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||||
|
if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||||
|
sub.add(if3)
|
||||||
|
val if4 = PtIfElse(Position.DUMMY)
|
||||||
|
val cmp4 = PtBinaryExpression(">", DataType.UBYTE, Position.DUMMY)
|
||||||
|
cmp4.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY))
|
||||||
|
cmp4.add(PtNumber(DataType.FLOAT, 0.0, Position.DUMMY))
|
||||||
|
if4.add(cmp4)
|
||||||
|
if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||||
|
if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||||
|
sub.add(if4)
|
||||||
|
block.add(sub)
|
||||||
|
program.add(block)
|
||||||
|
|
||||||
|
val options = getTestOptions()
|
||||||
|
val st = SymbolTableMaker(program, options).make()
|
||||||
|
val errors = ErrorReporterForTests()
|
||||||
|
val result = codegen.generate(program, st, options, errors) as VmAssemblyProgram
|
||||||
|
val irChunks = (result.irProgram.blocks.first().children.single() as IRSubroutine).chunks
|
||||||
|
irChunks.size shouldBeGreaterThan 4
|
||||||
|
}
|
||||||
|
|
||||||
|
test("float comparison expressions against nonzero") {
|
||||||
|
//main {
|
||||||
|
// sub start() {
|
||||||
|
// float @shared f1
|
||||||
|
//
|
||||||
|
// if f1==42
|
||||||
|
// nop
|
||||||
|
// if f1!=42
|
||||||
|
// nop
|
||||||
|
// if f1>42
|
||||||
|
// nop
|
||||||
|
// if f1<42
|
||||||
|
// nop
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
val codegen = VmCodeGen()
|
||||||
|
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
||||||
|
val block = PtBlock("main", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||||
|
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||||
|
sub.add(PtVariable("f1", DataType.FLOAT, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
|
||||||
|
val if1 = PtIfElse(Position.DUMMY)
|
||||||
|
val cmp1 = PtBinaryExpression("==", DataType.UBYTE, Position.DUMMY)
|
||||||
|
cmp1.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY))
|
||||||
|
cmp1.add(PtNumber(DataType.FLOAT, 42.0, Position.DUMMY))
|
||||||
|
if1.add(cmp1)
|
||||||
|
if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||||
|
if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||||
|
sub.add(if1)
|
||||||
|
val if2 = PtIfElse(Position.DUMMY)
|
||||||
|
val cmp2 = PtBinaryExpression("!=", DataType.UBYTE, Position.DUMMY)
|
||||||
|
cmp2.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY))
|
||||||
|
cmp2.add(PtNumber(DataType.FLOAT, 42.0, Position.DUMMY))
|
||||||
|
if2.add(cmp2)
|
||||||
|
if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||||
|
if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||||
|
sub.add(if2)
|
||||||
|
val if3 = PtIfElse(Position.DUMMY)
|
||||||
|
val cmp3 = PtBinaryExpression("<", DataType.UBYTE, Position.DUMMY)
|
||||||
|
cmp3.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY))
|
||||||
|
cmp3.add(PtNumber(DataType.FLOAT, 42.0, Position.DUMMY))
|
||||||
|
if3.add(cmp3)
|
||||||
|
if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||||
|
if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||||
|
sub.add(if3)
|
||||||
|
val if4 = PtIfElse(Position.DUMMY)
|
||||||
|
val cmp4 = PtBinaryExpression(">", DataType.UBYTE, Position.DUMMY)
|
||||||
|
cmp4.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY))
|
||||||
|
cmp4.add(PtNumber(DataType.FLOAT, 42.0, Position.DUMMY))
|
||||||
|
if4.add(cmp4)
|
||||||
|
if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||||
|
if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||||
|
sub.add(if4)
|
||||||
|
block.add(sub)
|
||||||
|
program.add(block)
|
||||||
|
|
||||||
|
val options = getTestOptions()
|
||||||
|
val st = SymbolTableMaker(program, options).make()
|
||||||
|
val errors = ErrorReporterForTests()
|
||||||
|
val result = codegen.generate(program, st, options, errors) as VmAssemblyProgram
|
||||||
|
val irChunks = (result.irProgram.blocks.first().children.single() as IRSubroutine).chunks
|
||||||
|
irChunks.size shouldBeGreaterThan 4
|
||||||
|
}
|
||||||
|
|
||||||
|
test("float conditional jump") {
|
||||||
|
//main {
|
||||||
|
// sub start() {
|
||||||
|
// float @shared f1
|
||||||
|
//
|
||||||
|
// if f1==42
|
||||||
|
// goto $c000
|
||||||
|
// if f1>42
|
||||||
|
// goto $c000
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
val codegen = VmCodeGen()
|
||||||
|
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
||||||
|
val block = PtBlock("main", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||||
|
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||||
|
sub.add(PtVariable("f1", DataType.FLOAT, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
|
||||||
|
val if1 = PtIfElse(Position.DUMMY)
|
||||||
|
val cmp1 = PtBinaryExpression("==", DataType.UBYTE, Position.DUMMY)
|
||||||
|
cmp1.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY))
|
||||||
|
cmp1.add(PtNumber(DataType.FLOAT, 42.0, Position.DUMMY))
|
||||||
|
if1.add(cmp1)
|
||||||
|
if1.add(PtNodeGroup().also { it.add(PtJump(null, 0xc000u, null, Position.DUMMY)) })
|
||||||
|
if1.add(PtNodeGroup())
|
||||||
|
sub.add(if1)
|
||||||
|
val if2 = PtIfElse(Position.DUMMY)
|
||||||
|
val cmp2 = PtBinaryExpression(">", DataType.UBYTE, Position.DUMMY)
|
||||||
|
cmp2.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY))
|
||||||
|
cmp2.add(PtNumber(DataType.FLOAT, 42.0, Position.DUMMY))
|
||||||
|
if2.add(cmp2)
|
||||||
|
if2.add(PtNodeGroup().also { it.add(PtJump(null, 0xc000u, null, Position.DUMMY)) })
|
||||||
|
if2.add(PtNodeGroup())
|
||||||
|
sub.add(if2)
|
||||||
|
block.add(sub)
|
||||||
|
program.add(block)
|
||||||
|
|
||||||
|
val options = getTestOptions()
|
||||||
|
val st = SymbolTableMaker(program, options).make()
|
||||||
|
val errors = ErrorReporterForTests()
|
||||||
|
val result = codegen.generate(program, st, options, errors) as VmAssemblyProgram
|
||||||
|
val irChunks = (result.irProgram.blocks.first().children.single() as IRSubroutine).chunks
|
||||||
|
irChunks.size shouldBeGreaterThan 4
|
||||||
|
}
|
||||||
|
|
||||||
|
test("integer comparison expressions against zero") {
|
||||||
|
//main {
|
||||||
|
// sub start() {
|
||||||
|
// byte @shared sb1
|
||||||
|
//
|
||||||
|
// if sb1==0
|
||||||
|
// nop
|
||||||
|
// if sb1!=0
|
||||||
|
// nop
|
||||||
|
// if sb1>0
|
||||||
|
// nop
|
||||||
|
// if sb1<0
|
||||||
|
// nop
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
val codegen = VmCodeGen()
|
||||||
|
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
||||||
|
val block = PtBlock("main", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||||
|
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||||
|
sub.add(PtVariable("sb1", DataType.BYTE, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
|
||||||
|
val if1 = PtIfElse(Position.DUMMY)
|
||||||
|
val cmp1 = PtBinaryExpression("==", DataType.BYTE, Position.DUMMY)
|
||||||
|
cmp1.add(PtIdentifier("main.start.sb1", DataType.BYTE, Position.DUMMY))
|
||||||
|
cmp1.add(PtNumber(DataType.BYTE, 0.0, Position.DUMMY))
|
||||||
|
if1.add(cmp1)
|
||||||
|
if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||||
|
if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||||
|
sub.add(if1)
|
||||||
|
val if2 = PtIfElse(Position.DUMMY)
|
||||||
|
val cmp2 = PtBinaryExpression("!=", DataType.BYTE, Position.DUMMY)
|
||||||
|
cmp2.add(PtIdentifier("main.start.sb1", DataType.BYTE, Position.DUMMY))
|
||||||
|
cmp2.add(PtNumber(DataType.BYTE, 0.0, Position.DUMMY))
|
||||||
|
if2.add(cmp2)
|
||||||
|
if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||||
|
if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||||
|
sub.add(if2)
|
||||||
|
val if3 = PtIfElse(Position.DUMMY)
|
||||||
|
val cmp3 = PtBinaryExpression("<", DataType.BYTE, Position.DUMMY)
|
||||||
|
cmp3.add(PtIdentifier("main.start.sb1", DataType.BYTE, Position.DUMMY))
|
||||||
|
cmp3.add(PtNumber(DataType.BYTE, 0.0, Position.DUMMY))
|
||||||
|
if3.add(cmp3)
|
||||||
|
if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||||
|
if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||||
|
sub.add(if3)
|
||||||
|
val if4 = PtIfElse(Position.DUMMY)
|
||||||
|
val cmp4 = PtBinaryExpression(">", DataType.BYTE, Position.DUMMY)
|
||||||
|
cmp4.add(PtIdentifier("main.start.sb1", DataType.BYTE, Position.DUMMY))
|
||||||
|
cmp4.add(PtNumber(DataType.BYTE, 0.0, Position.DUMMY))
|
||||||
|
if4.add(cmp4)
|
||||||
|
if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||||
|
if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||||
|
sub.add(if4)
|
||||||
|
block.add(sub)
|
||||||
|
program.add(block)
|
||||||
|
|
||||||
|
val options = getTestOptions()
|
||||||
|
val st = SymbolTableMaker(program, options).make()
|
||||||
|
val errors = ErrorReporterForTests()
|
||||||
|
val result = codegen.generate(program, st, options, errors) as VmAssemblyProgram
|
||||||
|
val irChunks = (result.irProgram.blocks.first().children.single() as IRSubroutine).chunks
|
||||||
|
irChunks.size shouldBeGreaterThan 4
|
||||||
|
}
|
||||||
|
|
||||||
|
test("integer comparison expressions against nonzero") {
|
||||||
|
//main {
|
||||||
|
// sub start() {
|
||||||
|
// byte @shared sb1
|
||||||
|
//
|
||||||
|
// if sb1==42
|
||||||
|
// nop
|
||||||
|
// if sb1!=42
|
||||||
|
// nop
|
||||||
|
// if sb1>42
|
||||||
|
// nop
|
||||||
|
// if sb1<42
|
||||||
|
// nop
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
val codegen = VmCodeGen()
|
||||||
|
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
||||||
|
val block = PtBlock("main", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||||
|
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||||
|
sub.add(PtVariable("sb1", DataType.BYTE, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
|
||||||
|
val if1 = PtIfElse(Position.DUMMY)
|
||||||
|
val cmp1 = PtBinaryExpression("==", DataType.BYTE, Position.DUMMY)
|
||||||
|
cmp1.add(PtIdentifier("main.start.sb1", DataType.BYTE, Position.DUMMY))
|
||||||
|
cmp1.add(PtNumber(DataType.BYTE, 42.0, Position.DUMMY))
|
||||||
|
if1.add(cmp1)
|
||||||
|
if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||||
|
if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||||
|
sub.add(if1)
|
||||||
|
val if2 = PtIfElse(Position.DUMMY)
|
||||||
|
val cmp2 = PtBinaryExpression("!=", DataType.BYTE, Position.DUMMY)
|
||||||
|
cmp2.add(PtIdentifier("main.start.sb1", DataType.BYTE, Position.DUMMY))
|
||||||
|
cmp2.add(PtNumber(DataType.BYTE, 42.0, Position.DUMMY))
|
||||||
|
if2.add(cmp2)
|
||||||
|
if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||||
|
if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||||
|
sub.add(if2)
|
||||||
|
val if3 = PtIfElse(Position.DUMMY)
|
||||||
|
val cmp3 = PtBinaryExpression("<", DataType.BYTE, Position.DUMMY)
|
||||||
|
cmp3.add(PtIdentifier("main.start.sb1", DataType.BYTE, Position.DUMMY))
|
||||||
|
cmp3.add(PtNumber(DataType.BYTE, 42.0, Position.DUMMY))
|
||||||
|
if3.add(cmp3)
|
||||||
|
if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||||
|
if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||||
|
sub.add(if3)
|
||||||
|
val if4 = PtIfElse(Position.DUMMY)
|
||||||
|
val cmp4 = PtBinaryExpression(">", DataType.BYTE, Position.DUMMY)
|
||||||
|
cmp4.add(PtIdentifier("main.start.sb1", DataType.BYTE, Position.DUMMY))
|
||||||
|
cmp4.add(PtNumber(DataType.BYTE, 42.0, Position.DUMMY))
|
||||||
|
if4.add(cmp4)
|
||||||
|
if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||||
|
if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||||
|
sub.add(if4)
|
||||||
|
block.add(sub)
|
||||||
|
program.add(block)
|
||||||
|
|
||||||
|
val options = getTestOptions()
|
||||||
|
val st = SymbolTableMaker(program, options).make()
|
||||||
|
val errors = ErrorReporterForTests()
|
||||||
|
val result = codegen.generate(program, st, options, errors) as VmAssemblyProgram
|
||||||
|
val irChunks = (result.irProgram.blocks.first().children.single() as IRSubroutine).chunks
|
||||||
|
irChunks.size shouldBeGreaterThan 4
|
||||||
|
}
|
||||||
|
|
||||||
|
test("integer conditional jump") {
|
||||||
|
//main {
|
||||||
|
// sub start() {
|
||||||
|
// ubyte @shared ub1
|
||||||
|
//
|
||||||
|
// if ub1==42
|
||||||
|
// goto $c000
|
||||||
|
// if ub1>42
|
||||||
|
// goto $c000
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
val codegen = VmCodeGen()
|
||||||
|
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
||||||
|
val block = PtBlock("main", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||||
|
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||||
|
sub.add(PtVariable("ub1", DataType.UBYTE, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
|
||||||
|
val if1 = PtIfElse(Position.DUMMY)
|
||||||
|
val cmp1 = PtBinaryExpression("==", DataType.UBYTE, Position.DUMMY)
|
||||||
|
cmp1.add(PtIdentifier("main.start.ub1", DataType.UBYTE, Position.DUMMY))
|
||||||
|
cmp1.add(PtNumber(DataType.UBYTE, 42.0, Position.DUMMY))
|
||||||
|
if1.add(cmp1)
|
||||||
|
if1.add(PtNodeGroup().also { it.add(PtJump(null, 0xc000u, null, Position.DUMMY)) })
|
||||||
|
if1.add(PtNodeGroup())
|
||||||
|
sub.add(if1)
|
||||||
|
val if2 = PtIfElse(Position.DUMMY)
|
||||||
|
val cmp2 = PtBinaryExpression(">", DataType.UBYTE, Position.DUMMY)
|
||||||
|
cmp2.add(PtIdentifier("main.start.ub1", DataType.UBYTE, Position.DUMMY))
|
||||||
|
cmp2.add(PtNumber(DataType.UBYTE, 42.0, Position.DUMMY))
|
||||||
|
if2.add(cmp2)
|
||||||
|
if2.add(PtNodeGroup().also { it.add(PtJump(null, 0xc000u, null, Position.DUMMY)) })
|
||||||
|
if2.add(PtNodeGroup())
|
||||||
|
sub.add(if2)
|
||||||
|
block.add(sub)
|
||||||
|
program.add(block)
|
||||||
|
|
||||||
|
val options = getTestOptions()
|
||||||
|
val st = SymbolTableMaker(program, options).make()
|
||||||
|
val errors = ErrorReporterForTests()
|
||||||
|
val result = codegen.generate(program, st, options, errors) as VmAssemblyProgram
|
||||||
|
val irChunks = (result.irProgram.blocks.first().children.single() as IRSubroutine).chunks
|
||||||
|
irChunks.size shouldBeGreaterThan 4
|
||||||
|
}
|
||||||
|
|
||||||
})
|
})
|
@ -1 +1 @@
|
|||||||
8.10
|
8.11-dev
|
||||||
|
@ -33,7 +33,7 @@ class TestLaunchEmu: FunSpec({
|
|||||||
<INITGLOBALS>
|
<INITGLOBALS>
|
||||||
</INITGLOBALS>
|
</INITGLOBALS>
|
||||||
|
|
||||||
<BLOCK NAME="main" ADDRESS="null" ALIGN="NONE" POS="[unittest: line 42 col 1-9]">
|
<BLOCK NAME="main" ADDRESS="" ALIGN="NONE" POS="[unittest: line 42 col 1-9]">
|
||||||
</BLOCK>
|
</BLOCK>
|
||||||
</PROGRAM>
|
</PROGRAM>
|
||||||
""")
|
""")
|
||||||
|
@ -3,6 +3,14 @@ TODO
|
|||||||
|
|
||||||
For next minor release
|
For next minor release
|
||||||
^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
- fix expericodegen compiler crashes:
|
||||||
|
float comparison <= , >= , == , != all crash with mismatched result register for FLOAT (cube3d-float uses this)
|
||||||
|
maze: thinks draw is unused
|
||||||
|
tehtriz: thinks sound.init routine is unused
|
||||||
|
textelite: thinks trader.do_local routine is unused , and debug_seed
|
||||||
|
- fix IR/VM: animals.p8 example somehow doesn't print the animal name in the first question, and exits after 1 animal instead of looping
|
||||||
|
- fix Github issue with X register https://github.com/irmen/prog8/issues/94
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
@ -103,8 +103,8 @@ class IRFileReader {
|
|||||||
"output" -> outputType = OutputType.valueOf(value)
|
"output" -> outputType = OutputType.valueOf(value)
|
||||||
"launcher" -> launcher = CbmPrgLauncherType.valueOf(value)
|
"launcher" -> launcher = CbmPrgLauncherType.valueOf(value)
|
||||||
"zeropage" -> zeropage = ZeropageType.valueOf(value)
|
"zeropage" -> zeropage = ZeropageType.valueOf(value)
|
||||||
"loadAddress" -> loadAddress = value.toUInt()
|
"loadAddress" -> loadAddress = parseIRValue(value).toUInt()
|
||||||
"evalStackBaseAddress" -> evalStackBaseAddress = if(value=="null") null else parseIRValue(value).toUInt()
|
"evalStackBaseAddress" -> evalStackBaseAddress = if(value=="") null else parseIRValue(value).toUInt()
|
||||||
"zpReserved" -> {
|
"zpReserved" -> {
|
||||||
val (zpstart, zpend) = value.split(',')
|
val (zpstart, zpend) = value.split(',')
|
||||||
zpReserved.add(UIntRange(zpstart.toUInt(), zpend.toUInt()))
|
zpReserved.add(UIntRange(zpstart.toUInt(), zpend.toUInt()))
|
||||||
@ -262,10 +262,10 @@ class IRFileReader {
|
|||||||
emptyList()
|
emptyList()
|
||||||
else {
|
else {
|
||||||
val slabs = mutableListOf<StMemorySlab>()
|
val slabs = mutableListOf<StMemorySlab>()
|
||||||
val slabPattern = Regex("SLAB (.+) (.+) (.+)")
|
val slabPattern = Regex("(.+) (.+) (.+)")
|
||||||
text.lineSequence().forEach { line ->
|
text.lineSequence().forEach { line ->
|
||||||
// example: "SLAB slabname 4096 0"
|
// example: "slabname 4096 0"
|
||||||
val match = slabPattern.matchEntire(line) ?: throw IRParseException("invalid SLAB $line")
|
val match = slabPattern.matchEntire(line) ?: throw IRParseException("invalid slab $line")
|
||||||
val (name, size, align) = match.destructured
|
val (name, size, align) = match.destructured
|
||||||
val dummyNode = PtVariable(name, DataType.ARRAY_UB, ZeropageWish.NOT_IN_ZEROPAGE, null, null, Position.DUMMY)
|
val dummyNode = PtVariable(name, DataType.ARRAY_UB, ZeropageWish.NOT_IN_ZEROPAGE, null, null, Position.DUMMY)
|
||||||
slabs.add(StMemorySlab(name, size.toUInt(), align.toUInt(), dummyNode))
|
slabs.add(StMemorySlab(name, size.toUInt(), align.toUInt(), dummyNode))
|
||||||
@ -331,7 +331,7 @@ class IRFileReader {
|
|||||||
val attrs = start.attributes.asSequence().associate { it.name.localPart to it.value }
|
val attrs = start.attributes.asSequence().associate { it.name.localPart to it.value }
|
||||||
val block = IRBlock(
|
val block = IRBlock(
|
||||||
attrs.getValue("NAME"),
|
attrs.getValue("NAME"),
|
||||||
if(attrs.getValue("ADDRESS")=="null") null else parseIRValue(attrs.getValue("ADDRESS")).toUInt(),
|
if(attrs.getValue("ADDRESS")=="") null else parseIRValue(attrs.getValue("ADDRESS")).toUInt(),
|
||||||
IRBlock.BlockAlignment.valueOf(attrs.getValue("ALIGN")),
|
IRBlock.BlockAlignment.valueOf(attrs.getValue("ALIGN")),
|
||||||
parsePosition(attrs.getValue("POS")))
|
parsePosition(attrs.getValue("POS")))
|
||||||
skipText(reader)
|
skipText(reader)
|
||||||
@ -364,7 +364,7 @@ class IRFileReader {
|
|||||||
skipText(reader)
|
skipText(reader)
|
||||||
val sub = IRSubroutine(attrs.getValue("NAME"),
|
val sub = IRSubroutine(attrs.getValue("NAME"),
|
||||||
parseParameters(reader),
|
parseParameters(reader),
|
||||||
if(returntype=="null") null else parseDatatype(returntype, false),
|
if(returntype=="") null else parseDatatype(returntype, false),
|
||||||
parsePosition(attrs.getValue("POS")))
|
parsePosition(attrs.getValue("POS")))
|
||||||
|
|
||||||
skipText(reader)
|
skipText(reader)
|
||||||
@ -433,7 +433,7 @@ class IRFileReader {
|
|||||||
}
|
}
|
||||||
return IRAsmSubroutine(
|
return IRAsmSubroutine(
|
||||||
attrs.getValue("NAME"),
|
attrs.getValue("NAME"),
|
||||||
if(attrs.getValue("ADDRESS")=="null") null else parseIRValue(attrs.getValue("ADDRESS")).toUInt(),
|
if(attrs.getValue("ADDRESS")=="") null else parseIRValue(attrs.getValue("ADDRESS")).toUInt(),
|
||||||
clobberRegs.toSet(),
|
clobberRegs.toSet(),
|
||||||
params,
|
params,
|
||||||
returns,
|
returns,
|
||||||
|
@ -2,6 +2,7 @@ package prog8.intermediate
|
|||||||
|
|
||||||
import prog8.code.core.*
|
import prog8.code.core.*
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
import javax.xml.stream.XMLOutputFactory
|
||||||
import kotlin.io.path.bufferedWriter
|
import kotlin.io.path.bufferedWriter
|
||||||
import kotlin.io.path.div
|
import kotlin.io.path.div
|
||||||
|
|
||||||
@ -9,23 +10,32 @@ import kotlin.io.path.div
|
|||||||
class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
||||||
private val outfile = outfileOverride ?: (irProgram.options.outputDir / ("${irProgram.name}.p8ir"))
|
private val outfile = outfileOverride ?: (irProgram.options.outputDir / ("${irProgram.name}.p8ir"))
|
||||||
private val out = outfile.bufferedWriter(charset=Charsets.UTF_8)
|
private val out = outfile.bufferedWriter(charset=Charsets.UTF_8)
|
||||||
|
private val xml = XMLOutputFactory.newInstance().createXMLStreamWriter(out)
|
||||||
private var numChunks = 0
|
private var numChunks = 0
|
||||||
private var numInstr = 0
|
private var numInstr = 0
|
||||||
|
|
||||||
|
|
||||||
fun write(): Path {
|
fun write(): Path {
|
||||||
|
|
||||||
println("Writing intermediate representation to $outfile")
|
println("Writing intermediate representation to $outfile")
|
||||||
out.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")
|
xml.writeStartDocument("utf-8", "1.0")
|
||||||
out.write("<PROGRAM NAME=\"${irProgram.name}\">\n")
|
xml.writeEndDocument()
|
||||||
|
xml.writeCharacters("\n")
|
||||||
|
xml.writeStartElement("PROGRAM")
|
||||||
|
xml.writeAttribute("NAME", irProgram.name)
|
||||||
|
xml.writeCharacters("\n")
|
||||||
writeOptions()
|
writeOptions()
|
||||||
writeAsmSymbols()
|
writeAsmSymbols()
|
||||||
writeVariables()
|
writeVariables()
|
||||||
|
xml.writeStartElement("INITGLOBALS")
|
||||||
out.write("\n<INITGLOBALS>\n")
|
xml.writeCharacters("\n")
|
||||||
writeCodeChunk(irProgram.globalInits)
|
writeCodeChunk(irProgram.globalInits)
|
||||||
out.write("</INITGLOBALS>\n")
|
xml.writeEndElement()
|
||||||
|
xml.writeCharacters("\n\n")
|
||||||
writeBlocks()
|
writeBlocks()
|
||||||
out.write("</PROGRAM>\n")
|
xml.writeEndElement()
|
||||||
|
xml.writeCharacters("\n")
|
||||||
|
xml.close()
|
||||||
out.close()
|
out.close()
|
||||||
|
|
||||||
val used = irProgram.registersUsed()
|
val used = irProgram.registersUsed()
|
||||||
@ -35,14 +45,21 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun writeAsmSymbols() {
|
private fun writeAsmSymbols() {
|
||||||
out.write("<ASMSYMBOLS>\n")
|
xml.writeStartElement("ASMSYMBOLS")
|
||||||
irProgram.asmSymbols.forEach { (name, value) -> out.write("$name=$value\n" )}
|
xml.writeCharacters("\n")
|
||||||
out.write("</ASMSYMBOLS>\n")
|
irProgram.asmSymbols.forEach { (name, value) -> xml.writeCharacters("$name=$value\n" )}
|
||||||
|
xml.writeEndElement()
|
||||||
|
xml.writeCharacters("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun writeBlocks() {
|
private fun writeBlocks() {
|
||||||
irProgram.blocks.forEach { block ->
|
irProgram.blocks.forEach { block ->
|
||||||
out.write("\n<BLOCK NAME=\"${block.name}\" ADDRESS=\"${block.address?.toHex()}\" ALIGN=\"${block.alignment}\" POS=\"${block.position}\">\n")
|
xml.writeStartElement("BLOCK")
|
||||||
|
xml.writeAttribute("NAME", block.name)
|
||||||
|
xml.writeAttribute("ADDRESS", block.address?.toHex() ?: "")
|
||||||
|
xml.writeAttribute("ALIGN", block.alignment.toString())
|
||||||
|
xml.writeAttribute("POS", block.position.toString())
|
||||||
|
xml.writeCharacters("\n")
|
||||||
block.children.forEach { child ->
|
block.children.forEach { child ->
|
||||||
when(child) {
|
when(child) {
|
||||||
is IRAsmSubroutine -> {
|
is IRAsmSubroutine -> {
|
||||||
@ -51,25 +68,40 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
|||||||
if(ret.reg.registerOrPair!=null) "${ret.reg.registerOrPair}:${ret.dt.toString().lowercase()}"
|
if(ret.reg.registerOrPair!=null) "${ret.reg.registerOrPair}:${ret.dt.toString().lowercase()}"
|
||||||
else "${ret.reg.statusflag}:${ret.dt.toString().lowercase()}"
|
else "${ret.reg.statusflag}:${ret.dt.toString().lowercase()}"
|
||||||
}.joinToString(",")
|
}.joinToString(",")
|
||||||
out.write("<ASMSUB NAME=\"${child.label}\" ADDRESS=\"${child.address?.toHex()}\" CLOBBERS=\"$clobbers\" RETURNS=\"$returns\" POS=\"${child.position}\">\n")
|
xml.writeStartElement("ASMSUB")
|
||||||
out.write("<ASMPARAMS>\n")
|
xml.writeAttribute("NAME", child.label)
|
||||||
|
xml.writeAttribute("ADDRESS", child.address?.toHex() ?: "")
|
||||||
|
xml.writeAttribute("CLOBBERS", clobbers)
|
||||||
|
xml.writeAttribute("RETURNS", returns)
|
||||||
|
xml.writeAttribute("POS", child.position.toString())
|
||||||
|
xml.writeCharacters("\n")
|
||||||
|
xml.writeStartElement("ASMPARAMS")
|
||||||
|
xml.writeCharacters("\n")
|
||||||
child.parameters.forEach { ret ->
|
child.parameters.forEach { ret ->
|
||||||
val reg = if(ret.reg.registerOrPair!=null) ret.reg.registerOrPair.toString()
|
val reg = if(ret.reg.registerOrPair!=null) ret.reg.registerOrPair.toString()
|
||||||
else ret.reg.statusflag.toString()
|
else ret.reg.statusflag.toString()
|
||||||
out.write("${ret.dt.toString().lowercase()} $reg\n")
|
xml.writeCharacters("${ret.dt.toString().lowercase()} $reg\n")
|
||||||
}
|
}
|
||||||
out.write("</ASMPARAMS>\n")
|
xml.writeEndElement()
|
||||||
|
xml.writeCharacters("\n")
|
||||||
writeInlineAsm(child.asmChunk)
|
writeInlineAsm(child.asmChunk)
|
||||||
out.write("</ASMSUB>\n")
|
xml.writeEndElement()
|
||||||
|
xml.writeCharacters("\n\n")
|
||||||
}
|
}
|
||||||
is IRCodeChunk -> writeCodeChunk(child)
|
is IRCodeChunk -> writeCodeChunk(child)
|
||||||
is IRInlineAsmChunk -> writeInlineAsm(child)
|
is IRInlineAsmChunk -> writeInlineAsm(child)
|
||||||
is IRInlineBinaryChunk -> writeInlineBytes(child)
|
is IRInlineBinaryChunk -> writeInlineBytes(child)
|
||||||
is IRSubroutine -> {
|
is IRSubroutine -> {
|
||||||
out.write("<SUB NAME=\"${child.label}\" RETURNTYPE=\"${child.returnType.toString().lowercase()}\" POS=\"${child.position}\">\n")
|
xml.writeStartElement("SUB")
|
||||||
out.write("<PARAMS>\n")
|
xml.writeAttribute("NAME", child.label)
|
||||||
child.parameters.forEach { param -> out.write("${getTypeString(param.dt)} ${param.name}\n") }
|
xml.writeAttribute("RETURNTYPE", child.returnType?.toString()?.lowercase() ?: "")
|
||||||
out.write("</PARAMS>\n")
|
xml.writeAttribute("POS", child.position.toString())
|
||||||
|
xml.writeCharacters("\n")
|
||||||
|
xml.writeStartElement("PARAMS")
|
||||||
|
xml.writeCharacters("\n")
|
||||||
|
child.parameters.forEach { param -> xml.writeCharacters("${getTypeString(param.dt)} ${param.name}\n") }
|
||||||
|
xml.writeEndElement()
|
||||||
|
xml.writeCharacters("\n")
|
||||||
child.chunks.forEach { chunk ->
|
child.chunks.forEach { chunk ->
|
||||||
numChunks++
|
numChunks++
|
||||||
when (chunk) {
|
when (chunk) {
|
||||||
@ -79,71 +111,87 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
|||||||
else -> throw InternalCompilerException("invalid chunk")
|
else -> throw InternalCompilerException("invalid chunk")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out.write("</SUB>\n")
|
xml.writeEndElement()
|
||||||
|
xml.writeCharacters("\n\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out.write("</BLOCK>\n")
|
xml.writeEndElement()
|
||||||
|
xml.writeCharacters("\n\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun writeCodeChunk(chunk: IRCodeChunk) {
|
private fun writeCodeChunk(chunk: IRCodeChunk) {
|
||||||
if(chunk.label!=null)
|
xml.writeStartElement("CODE")
|
||||||
out.write("<CODE LABEL=\"${chunk.label}\">\n")
|
chunk.label?.let { xml.writeAttribute("LABEL", chunk.label) }
|
||||||
else
|
xml.writeCharacters("\n")
|
||||||
out.write("<CODE>\n")
|
|
||||||
chunk.instructions.forEach { instr ->
|
chunk.instructions.forEach { instr ->
|
||||||
numInstr++
|
numInstr++
|
||||||
out.write(instr.toString())
|
xml.writeCharacters(instr.toString())
|
||||||
out.write("\n")
|
xml.writeCharacters("\n")
|
||||||
}
|
}
|
||||||
out.write("</CODE>\n")
|
xml.writeEndElement()
|
||||||
|
xml.writeCharacters("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun writeInlineBytes(chunk: IRInlineBinaryChunk) {
|
private fun writeInlineBytes(chunk: IRInlineBinaryChunk) {
|
||||||
out.write("<BYTES LABEL=\"${chunk.label ?: ""}\">\n")
|
xml.writeStartElement("BYTES")
|
||||||
|
chunk.label?.let { xml.writeAttribute("LABEL", chunk.label) }
|
||||||
|
xml.writeCharacters("\n")
|
||||||
chunk.data.withIndex().forEach {(index, byte) ->
|
chunk.data.withIndex().forEach {(index, byte) ->
|
||||||
out.write(byte.toString(16).padStart(2,'0'))
|
xml.writeCharacters(byte.toString(16).padStart(2,'0'))
|
||||||
if(index and 63 == 63 && index < chunk.data.size-1)
|
if(index and 63 == 63 && index < chunk.data.size-1)
|
||||||
out.write("\n")
|
xml.writeCharacters("\n")
|
||||||
}
|
}
|
||||||
out.write("\n</BYTES>\n")
|
xml.writeEndElement()
|
||||||
|
xml.writeCharacters("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun writeInlineAsm(chunk: IRInlineAsmChunk) {
|
private fun writeInlineAsm(chunk: IRInlineAsmChunk) {
|
||||||
out.write("<INLINEASM LABEL=\"${chunk.label ?: ""}\" IR=\"${chunk.isIR}\">\n")
|
xml.writeStartElement("INLINEASM")
|
||||||
out.write(chunk.assembly)
|
xml.writeAttribute("LABEL", chunk.label ?: "")
|
||||||
out.write("\n</INLINEASM>\n")
|
xml.writeAttribute("IR", chunk.isIR.toString())
|
||||||
|
xml.writeCharacters("\n")
|
||||||
|
xml.writeCharacters(chunk.assembly)
|
||||||
|
xml.writeEndElement()
|
||||||
|
xml.writeCharacters("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun writeOptions() {
|
private fun writeOptions() {
|
||||||
out.write("<OPTIONS>\n")
|
xml.writeStartElement("OPTIONS")
|
||||||
out.write("compTarget=${irProgram.options.compTarget.name}\n")
|
xml.writeCharacters("\n")
|
||||||
out.write("output=${irProgram.options.output}\n")
|
xml.writeCharacters("compTarget=${irProgram.options.compTarget.name}\n")
|
||||||
out.write("launcher=${irProgram.options.launcher}\n")
|
xml.writeCharacters("output=${irProgram.options.output}\n")
|
||||||
out.write("zeropage=${irProgram.options.zeropage}\n")
|
xml.writeCharacters("launcher=${irProgram.options.launcher}\n")
|
||||||
|
xml.writeCharacters("zeropage=${irProgram.options.zeropage}\n")
|
||||||
for(range in irProgram.options.zpReserved) {
|
for(range in irProgram.options.zpReserved) {
|
||||||
out.write("zpReserved=${range.first},${range.last}\n")
|
xml.writeCharacters("zpReserved=${range.first},${range.last}\n")
|
||||||
}
|
}
|
||||||
out.write("loadAddress=${irProgram.options.loadAddress.toHex()}\n")
|
xml.writeCharacters("loadAddress=${irProgram.options.loadAddress.toHex()}\n")
|
||||||
out.write("optimize=${irProgram.options.optimize}\n")
|
xml.writeCharacters("optimize=${irProgram.options.optimize}\n")
|
||||||
out.write("evalStackBaseAddress=${irProgram.options.evalStackBaseAddress?.toHex()}\n")
|
xml.writeCharacters("evalStackBaseAddress=${irProgram.options.evalStackBaseAddress?.toHex() ?: ""}\n")
|
||||||
out.write("outputDir=${irProgram.options.outputDir.toAbsolutePath()}\n")
|
xml.writeCharacters("outputDir=${irProgram.options.outputDir.toAbsolutePath()}\n")
|
||||||
// other options not yet useful here?
|
// other options not yet useful here?
|
||||||
out.write("</OPTIONS>\n")
|
xml.writeEndElement()
|
||||||
|
xml.writeCharacters("\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun writeVariables() {
|
private fun writeVariables() {
|
||||||
|
|
||||||
val (variablesNoInit, variablesWithInit) = irProgram.st.allVariables().partition { it.uninitialized }
|
val (variablesNoInit, variablesWithInit) = irProgram.st.allVariables().partition { it.uninitialized }
|
||||||
|
|
||||||
out.write("\n<VARIABLESNOINIT>\n")
|
xml.writeStartElement("VARIABLESNOINIT")
|
||||||
|
xml.writeCharacters("\n")
|
||||||
for (variable in variablesNoInit) {
|
for (variable in variablesNoInit) {
|
||||||
val typeStr = getTypeString(variable)
|
val typeStr = getTypeString(variable)
|
||||||
out.write("$typeStr ${variable.name} zp=${variable.zpwish}\n")
|
xml.writeCharacters("$typeStr ${variable.name} zp=${variable.zpwish}\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
out.write("</VARIABLESNOINIT>\n<VARIABLESWITHINIT>\n")
|
xml.writeEndElement()
|
||||||
|
xml.writeCharacters("\n")
|
||||||
|
xml.writeStartElement("VARIABLESWITHINIT")
|
||||||
|
xml.writeCharacters("\n")
|
||||||
|
|
||||||
for (variable in variablesWithInit) {
|
for (variable in variablesWithInit) {
|
||||||
val typeStr = getTypeString(variable)
|
val typeStr = getTypeString(variable)
|
||||||
val value: String = when(variable.dt) {
|
val value: String = when(variable.dt) {
|
||||||
@ -174,19 +222,24 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
|||||||
}
|
}
|
||||||
else -> throw InternalCompilerException("weird dt")
|
else -> throw InternalCompilerException("weird dt")
|
||||||
}
|
}
|
||||||
out.write("$typeStr ${variable.name}=$value zp=${variable.zpwish}\n")
|
xml.writeCharacters("$typeStr ${variable.name}=$value zp=${variable.zpwish}\n")
|
||||||
}
|
}
|
||||||
out.write("</VARIABLESWITHINIT>\n")
|
xml.writeEndElement()
|
||||||
|
xml.writeCharacters("\n")
|
||||||
|
|
||||||
out.write("\n<MEMORYMAPPEDVARIABLES>\n")
|
xml.writeStartElement("MEMORYMAPPEDVARIABLES")
|
||||||
|
xml.writeCharacters("\n")
|
||||||
for (variable in irProgram.st.allMemMappedVariables()) {
|
for (variable in irProgram.st.allMemMappedVariables()) {
|
||||||
val typeStr = getTypeString(variable)
|
val typeStr = getTypeString(variable)
|
||||||
out.write("@$typeStr ${variable.name}=${variable.address.toHex()}\n")
|
xml.writeCharacters("@$typeStr ${variable.name}=${variable.address.toHex()}\n")
|
||||||
}
|
}
|
||||||
out.write("</MEMORYMAPPEDVARIABLES>\n")
|
xml.writeEndElement()
|
||||||
|
xml.writeCharacters("\n")
|
||||||
|
|
||||||
out.write("\n<MEMORYSLABS>\n")
|
xml.writeStartElement("MEMORYSLABS")
|
||||||
irProgram.st.allMemorySlabs().forEach{ slab -> out.write("SLAB ${slab.name} ${slab.size} ${slab.align}\n") }
|
xml.writeCharacters("\n")
|
||||||
out.write("</MEMORYSLABS>\n")
|
irProgram.st.allMemorySlabs().forEach{ slab -> xml.writeCharacters("${slab.name} ${slab.size} ${slab.align}\n") }
|
||||||
|
xml.writeEndElement()
|
||||||
|
xml.writeCharacters("\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -585,10 +585,10 @@ val instructionFormats = mutableMapOf(
|
|||||||
Opcode.SLES to InstructionFormat.from("BW,<>r1,<r2"),
|
Opcode.SLES to InstructionFormat.from("BW,<>r1,<r2"),
|
||||||
Opcode.SGE to InstructionFormat.from("BW,<>r1,<r2"),
|
Opcode.SGE to InstructionFormat.from("BW,<>r1,<r2"),
|
||||||
Opcode.SGES to InstructionFormat.from("BW,<>r1,<r2"),
|
Opcode.SGES to InstructionFormat.from("BW,<>r1,<r2"),
|
||||||
Opcode.INC to InstructionFormat.from("BW,<>r1"),
|
Opcode.INC to InstructionFormat.from("BW,<>r1 | F,<>fr1"),
|
||||||
Opcode.INCM to InstructionFormat.from("BW,<v"),
|
Opcode.INCM to InstructionFormat.from("BW,<v | F,<v"),
|
||||||
Opcode.DEC to InstructionFormat.from("BW,<>r1"),
|
Opcode.DEC to InstructionFormat.from("BW,<>r1 | F,<>fr1"),
|
||||||
Opcode.DECM to InstructionFormat.from("BW,<v"),
|
Opcode.DECM to InstructionFormat.from("BW,<v | F,<v"),
|
||||||
Opcode.NEG to InstructionFormat.from("BW,<>r1 | F,<>fr1"),
|
Opcode.NEG to InstructionFormat.from("BW,<>r1 | F,<>fr1"),
|
||||||
Opcode.NEGM to InstructionFormat.from("BW,<v | F,<v"),
|
Opcode.NEGM to InstructionFormat.from("BW,<v | F,<v"),
|
||||||
Opcode.ADDR to InstructionFormat.from("BW,<>r1,<r2 | F,<>fr1,<fr2"),
|
Opcode.ADDR to InstructionFormat.from("BW,<>r1,<r2 | F,<>fr1,<fr2"),
|
||||||
|
@ -95,9 +95,12 @@ class IRSymbolTable(sourceSt: SymbolTable?) {
|
|||||||
scopedName = variable.name
|
scopedName = variable.name
|
||||||
varToadd = variable
|
varToadd = variable
|
||||||
} else {
|
} else {
|
||||||
scopedName = variable.scopedName
|
scopedName = try {
|
||||||
val dummyNode = PtVariable(scopedName, variable.dt, ZeropageWish.NOT_IN_ZEROPAGE, null, null, variable.astNode.position)
|
variable.scopedName
|
||||||
varToadd = StMemVar(scopedName, variable.dt, variable.address, variable.length, dummyNode)
|
} catch (ux: UninitializedPropertyAccessException) {
|
||||||
|
variable.name
|
||||||
|
}
|
||||||
|
varToadd = StMemVar(scopedName, variable.dt, variable.address, variable.length, variable.astNode)
|
||||||
}
|
}
|
||||||
table[scopedName] = varToadd
|
table[scopedName] = varToadd
|
||||||
}
|
}
|
||||||
|
@ -47,8 +47,8 @@ compTarget=virtual
|
|||||||
output=PRG
|
output=PRG
|
||||||
launcher=BASIC
|
launcher=BASIC
|
||||||
zeropage=KERNALSAFE
|
zeropage=KERNALSAFE
|
||||||
loadAddress=0
|
loadAddress=$0000
|
||||||
evalStackBaseAddress=null
|
evalStackBaseAddress=
|
||||||
</OPTIONS>
|
</OPTIONS>
|
||||||
|
|
||||||
<ASMSYMBOLS>
|
<ASMSYMBOLS>
|
||||||
@ -75,8 +75,8 @@ load.b r1,42
|
|||||||
</CODE>
|
</CODE>
|
||||||
</INITGLOBALS>
|
</INITGLOBALS>
|
||||||
|
|
||||||
<BLOCK NAME="main" ADDRESS="null" ALIGN="NONE" POS="[examples/test.p8: line 2 col 2-5]">
|
<BLOCK NAME="main" ADDRESS="" ALIGN="NONE" POS="[examples/test.p8: line 2 col 2-5]">
|
||||||
<SUB NAME="main.start" RETURNTYPE="null" POS="[examples/test.p8: line 4 col 6-8]">
|
<SUB NAME="main.start" RETURNTYPE="" POS="[examples/test.p8: line 4 col 6-8]">
|
||||||
<PARAMS>
|
<PARAMS>
|
||||||
</PARAMS>
|
</PARAMS>
|
||||||
<CODE LABEL="main.start">
|
<CODE LABEL="main.start">
|
||||||
@ -85,8 +85,8 @@ return
|
|||||||
</SUB>
|
</SUB>
|
||||||
</BLOCK>
|
</BLOCK>
|
||||||
|
|
||||||
<BLOCK NAME="sys" ADDRESS="null" ALIGN="NONE" POS="[library:/prog8lib/virtual/syslib.p8: line 3 col 2-4]">
|
<BLOCK NAME="sys" ADDRESS="" ALIGN="NONE" POS="[library:/prog8lib/virtual/syslib.p8: line 3 col 2-4]">
|
||||||
<SUB NAME="sys.wait" RETURNTYPE="null" POS="[library:/prog8lib/virtual/syslib.p8: line 15 col 6-8]">
|
<SUB NAME="sys.wait" RETURNTYPE="" POS="[library:/prog8lib/virtual/syslib.p8: line 15 col 6-8]">
|
||||||
<PARAMS>
|
<PARAMS>
|
||||||
uword sys.wait.jiffies
|
uword sys.wait.jiffies
|
||||||
</PARAMS>
|
</PARAMS>
|
||||||
|
@ -129,7 +129,7 @@ class TestVm: FunSpec( {
|
|||||||
<INITGLOBALS>
|
<INITGLOBALS>
|
||||||
</INITGLOBALS>
|
</INITGLOBALS>
|
||||||
|
|
||||||
<BLOCK NAME="main" ADDRESS="null" ALIGN="NONE" POS="[unittest: line 42 col 1-9]">
|
<BLOCK NAME="main" ADDRESS="" ALIGN="NONE" POS="[unittest: line 42 col 1-9]">
|
||||||
</BLOCK>
|
</BLOCK>
|
||||||
</PROGRAM>
|
</PROGRAM>
|
||||||
"""
|
"""
|
||||||
|
Loading…
x
Reference in New Issue
Block a user