ir: fix memory mapped var as for loop counter

This commit is contained in:
Irmen de Jong 2022-10-30 14:54:47 +01:00
parent 67a36d8d31
commit a5ef353484
4 changed files with 87 additions and 21 deletions

View File

@ -1,6 +1,7 @@
package prog8.codegen.intermediate package prog8.codegen.intermediate
import prog8.code.StMemVar import prog8.code.StMemVar
import prog8.code.StNode
import prog8.code.StStaticVariable import prog8.code.StStaticVariable
import prog8.code.SymbolTable import prog8.code.SymbolTable
import prog8.code.ast.* import prog8.code.ast.*
@ -411,7 +412,7 @@ class IRCodeGen(
} }
private fun translate(forLoop: PtForLoop): IRCodeChunks { private fun translate(forLoop: PtForLoop): IRCodeChunks {
val loopvar = symbolTable.lookup(forLoop.variable.targetName) as StStaticVariable val loopvar = symbolTable.lookup(forLoop.variable.targetName)!!
val iterable = forLoop.iterable val iterable = forLoop.iterable
val result = mutableListOf<IRCodeChunkBase>() val result = mutableListOf<IRCodeChunkBase>()
when(iterable) { when(iterable) {
@ -480,7 +481,7 @@ class IRCodeGen(
return result return result
} }
private fun translateForInNonConstantRange(forLoop: PtForLoop, loopvar: StStaticVariable): IRCodeChunks { private fun translateForInNonConstantRange(forLoop: PtForLoop, loopvar: StNode): IRCodeChunks {
val iterable = forLoop.iterable as PtRange val iterable = forLoop.iterable as PtRange
val step = iterable.step.number.toInt() val step = iterable.step.number.toInt()
if (step==0) if (step==0)
@ -488,26 +489,36 @@ class IRCodeGen(
val indexReg = registers.nextFree() val indexReg = registers.nextFree()
val endvalueReg = registers.nextFree() val endvalueReg = registers.nextFree()
val loopvarSymbol = loopvar.scopedName.joinToString(".") val loopvarSymbol = loopvar.scopedName.joinToString(".")
val loopvarDt = irType(loopvar.dt) val loopvarDt = when(loopvar) {
is StMemVar -> loopvar.dt
is StStaticVariable -> loopvar.dt
else -> throw AssemblyError("invalid loopvar node type")
}
val loopvarDtIr = irType(loopvarDt)
val loopLabel = createLabelName() val loopLabel = createLabelName()
val result = mutableListOf<IRCodeChunkBase>() val result = mutableListOf<IRCodeChunkBase>()
result += expressionEval.translateExpression(iterable.to, endvalueReg, -1) result += expressionEval.translateExpression(iterable.to, endvalueReg, -1)
result += expressionEval.translateExpression(iterable.from, indexReg, -1) result += expressionEval.translateExpression(iterable.from, indexReg, -1)
addInstr(result, IRInstruction(Opcode.STOREM, loopvarDt, reg1=indexReg, labelSymbol=loopvarSymbol), null, forLoop.position) addInstr(result, IRInstruction(Opcode.STOREM, loopvarDtIr, reg1=indexReg, labelSymbol=loopvarSymbol), null, forLoop.position)
result += labelFirstChunk(translateNode(forLoop.statements), loopLabel) result += labelFirstChunk(translateNode(forLoop.statements), loopLabel)
result += addConstMem(loopvarDt, null, loopvarSymbol, step, iterable.position) result += addConstMem(loopvarDtIr, null, loopvarSymbol, step, iterable.position)
addInstr(result, IRInstruction(Opcode.LOADM, loopvarDt, reg1 = indexReg, labelSymbol = loopvarSymbol), null, forLoop.position) addInstr(result, IRInstruction(Opcode.LOADM, loopvarDtIr, reg1 = indexReg, labelSymbol = loopvarSymbol), null, forLoop.position)
val branchOpcode = if(loopvar.dt in SignedDatatypes) Opcode.BLES else Opcode.BLE val branchOpcode = if(loopvarDt in SignedDatatypes) Opcode.BLES else Opcode.BLE
addInstr(result, IRInstruction(branchOpcode, loopvarDt, reg1=indexReg, reg2=endvalueReg, labelSymbol=loopLabel), null, forLoop.position) addInstr(result, IRInstruction(branchOpcode, loopvarDtIr, reg1=indexReg, reg2=endvalueReg, labelSymbol=loopLabel), null, forLoop.position)
return result return result
} }
private fun translateForInConstantRange(forLoop: PtForLoop, loopvar: StStaticVariable): IRCodeChunks { private fun translateForInConstantRange(forLoop: PtForLoop, loopvar: StNode): IRCodeChunks {
val loopLabel = createLabelName() val loopLabel = createLabelName()
val loopvarSymbol = loopvar.scopedName.joinToString(".") val loopvarSymbol = loopvar.scopedName.joinToString(".")
val indexReg = registers.nextFree() val indexReg = registers.nextFree()
val loopvarDt = irType(loopvar.dt) val loopvarDt = when(loopvar) {
is StMemVar -> loopvar.dt
is StStaticVariable -> loopvar.dt
else -> throw AssemblyError("invalid loopvar node type")
}
val loopvarDtIr = irType(loopvarDt)
val iterable = forLoop.iterable as PtRange val iterable = forLoop.iterable as PtRange
val step = iterable.step.number.toInt() val step = iterable.step.number.toInt()
val rangeStart = (iterable.from as PtNumber).number.toInt() val rangeStart = (iterable.from as PtNumber).number.toInt()
@ -516,27 +527,27 @@ class IRCodeGen(
throw AssemblyError("step 0") throw AssemblyError("step 0")
if(step>0 && rangeEndUntyped<rangeStart || step<0 && rangeEndUntyped>rangeStart) if(step>0 && rangeEndUntyped<rangeStart || step<0 && rangeEndUntyped>rangeStart)
throw AssemblyError("empty range") throw AssemblyError("empty range")
val rangeEndWrapped = if(loopvarDt==IRDataType.BYTE) rangeEndUntyped and 255 else rangeEndUntyped and 65535 val rangeEndWrapped = if(loopvarDtIr==IRDataType.BYTE) rangeEndUntyped and 255 else rangeEndUntyped and 65535
val endvalueReg: Int val endvalueReg: Int
val result = mutableListOf<IRCodeChunkBase>() val result = mutableListOf<IRCodeChunkBase>()
val chunk = IRCodeChunk(null, forLoop.position, null) val chunk = IRCodeChunk(null, forLoop.position, null)
if(rangeEndWrapped!=0) { if(rangeEndWrapped!=0) {
endvalueReg = registers.nextFree() endvalueReg = registers.nextFree()
chunk += IRInstruction(Opcode.LOAD, loopvarDt, reg1 = endvalueReg, value = rangeEndWrapped) chunk += IRInstruction(Opcode.LOAD, loopvarDtIr, reg1 = endvalueReg, value = rangeEndWrapped)
} else { } else {
endvalueReg = -1 // not used endvalueReg = -1 // not used
} }
chunk += IRInstruction(Opcode.LOAD, loopvarDt, reg1=indexReg, value=rangeStart) chunk += IRInstruction(Opcode.LOAD, loopvarDtIr, reg1=indexReg, value=rangeStart)
chunk += IRInstruction(Opcode.STOREM, loopvarDt, reg1=indexReg, labelSymbol=loopvarSymbol) chunk += IRInstruction(Opcode.STOREM, loopvarDtIr, reg1=indexReg, labelSymbol=loopvarSymbol)
result += chunk result += chunk
result += labelFirstChunk(translateNode(forLoop.statements), loopLabel) result += labelFirstChunk(translateNode(forLoop.statements), loopLabel)
result += addConstMem(loopvarDt, null, loopvarSymbol, step, iterable.position) result += addConstMem(loopvarDtIr, null, loopvarSymbol, step, iterable.position)
val chunk2 = IRCodeChunk(null, forLoop.position, null) val chunk2 = IRCodeChunk(null, forLoop.position, null)
chunk2 += IRInstruction(Opcode.LOADM, loopvarDt, reg1 = indexReg, labelSymbol = loopvarSymbol) chunk2 += IRInstruction(Opcode.LOADM, loopvarDtIr, reg1 = indexReg, labelSymbol = loopvarSymbol)
chunk2 += if(rangeEndWrapped==0) { chunk2 += if(rangeEndWrapped==0) {
IRInstruction(Opcode.BNZ, loopvarDt, reg1 = indexReg, labelSymbol = loopLabel) IRInstruction(Opcode.BNZ, loopvarDtIr, reg1 = indexReg, labelSymbol = loopLabel)
} else { } else {
IRInstruction(Opcode.BNE, loopvarDt, reg1 = indexReg, reg2 = endvalueReg, labelSymbol = loopLabel) IRInstruction(Opcode.BNE, loopvarDtIr, reg1 = indexReg, reg2 = endvalueReg, labelSymbol = loopLabel)
} }
result += chunk2 result += chunk2
return result return result

View File

@ -186,7 +186,7 @@ main {
val result = compileText(target, false, src, writeAssembly = true)!! val result = compileText(target, false, src, writeAssembly = true)!!
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8ir") val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8ir")
VmRunner().runAndTestProgram(virtfile.readText()) { vm -> VmRunner().runAndTestProgram(virtfile.readText()) { vm ->
vm.stepCount shouldBe 9999 // TODO FIX vm.stepCount shouldBe 49
} }
} }
}) })

View File

@ -393,6 +393,61 @@ val OpcodesForCpuRegisters = setOf(
Opcode.STOREZCPU Opcode.STOREZCPU
) )
val OpcodesWithMemoryAddressAsValue = setOf(
Opcode.LOADM,
Opcode.LOADX,
Opcode.LOADIX,
Opcode.STOREM,
Opcode.STOREX,
Opcode.STOREIX,
Opcode.STOREZM,
Opcode.STOREZX,
Opcode.JUMP,
Opcode.JUMPA,
Opcode.CALL,
Opcode.BSTCC,
Opcode.BSTCS,
Opcode.BSTEQ,
Opcode.BSTNE,
Opcode.BSTNEG,
Opcode.BSTPOS,
Opcode.BSTVC,
Opcode.BSTVS,
Opcode.BZ,
Opcode.BNZ,
Opcode.BEQ,
Opcode.BNE,
Opcode.BLT,
Opcode.BLTS,
Opcode.BGT,
Opcode.BGTS,
Opcode.BLE,
Opcode.BLES,
Opcode.BGE,
Opcode.BGES,
Opcode.INCM,
Opcode.DECM,
Opcode.NEGM,
Opcode.ADDM,
Opcode.SUBM,
Opcode.MULM,
Opcode.DIVM,
Opcode.DIVSM,
Opcode.INVM,
Opcode.ORM,
Opcode.XORM,
Opcode.ANDM,
Opcode.ASRM,
Opcode.LSRM,
Opcode.LSLM,
Opcode.LSLNM,
Opcode.LSRNM,
Opcode.ASRNM,
Opcode.ROLM,
Opcode.RORM,
Opcode.ROXLM,
Opcode.ROXRM
)
enum class IRDataType { enum class IRDataType {
BYTE, BYTE,
@ -635,7 +690,7 @@ data class IRInstruction(
require(reg2==null || reg2 in 0..65536) {"reg2 out of bounds"} require(reg2==null || reg2 in 0..65536) {"reg2 out of bounds"}
require(fpReg1==null || fpReg1 in 0..65536) {"fpReg1 out of bounds"} require(fpReg1==null || fpReg1 in 0..65536) {"fpReg1 out of bounds"}
require(fpReg2==null || fpReg2 in 0..65536) {"fpReg2 out of bounds"} require(fpReg2==null || fpReg2 in 0..65536) {"fpReg2 out of bounds"}
if(value!=null && labelSymbol==null) { if(value!=null && opcode !in OpcodesWithMemoryAddressAsValue) {
when (type) { when (type) {
IRDataType.BYTE -> require(value in -128..255) {"value out of range for byte: $value"} IRDataType.BYTE -> require(value in -128..255) {"value out of range for byte: $value"}
IRDataType.WORD -> require(value in -32768..65535) {"value out of range for word: $value"} IRDataType.WORD -> require(value in -32768..65535) {"value out of range for word: $value"}

View File

@ -206,7 +206,7 @@ fun parseIRCodeLine(line: String, location: Pair<IRCodeChunk, Int>?, placeholder
throw IRParseException("invalid reg1 for $line") throw IRParseException("invalid reg1 for $line")
if(format.reg2==OperandDirection.UNUSED && reg2!=null) if(format.reg2==OperandDirection.UNUSED && reg2!=null)
throw IRParseException("invalid reg2 for $line") throw IRParseException("invalid reg2 for $line")
if(value!=null) { if(value!=null && opcode !in OpcodesWithMemoryAddressAsValue) {
when (type) { when (type) {
IRDataType.BYTE -> { IRDataType.BYTE -> {
if (value < -128 || value > 255) if (value < -128 || value > 255)