mirror of
https://github.com/irmen/prog8.git
synced 2024-09-07 03:54:27 +00:00
ir: fix handling of labeled chunks
This commit is contained in:
parent
6fc89607d3
commit
a9f9c40d8a
@ -407,13 +407,12 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
}
|
||||
|
||||
private fun assignRegisterTo(target: PtExpression, register: Int): IRCodeChunks {
|
||||
val code = IRCodeChunk(null, target.position)
|
||||
val assignment = PtAssignment(target.position)
|
||||
val assignTarget = PtAssignTarget(target.position)
|
||||
assignTarget.children.add(target)
|
||||
assignment.children.add(assignTarget)
|
||||
assignment.children.add(PtMachineRegister(register, target.type, target.position))
|
||||
val result = mutableListOf<IRCodeChunkBase>(code)
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
result += codeGen.translateNode(assignment)
|
||||
return result
|
||||
}
|
||||
|
@ -56,8 +56,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
listOf(code)
|
||||
}
|
||||
is PtMemoryByte -> {
|
||||
val code = IRCodeChunk(null, expr.position)
|
||||
val result = mutableListOf<IRCodeChunkBase>(code)
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
if(expr.address is PtNumber) {
|
||||
val address = (expr.address as PtNumber).number.toInt()
|
||||
addInstr(result, IRInstruction(Opcode.LOADM, IRDataType.BYTE, reg1=resultRegister, value = address), null, expr.position)
|
||||
|
@ -213,7 +213,7 @@ class IRCodeGen(
|
||||
}
|
||||
|
||||
internal fun translateNode(node: PtNode): IRCodeChunks {
|
||||
return when(node) {
|
||||
val chunks = when(node) {
|
||||
is PtScopeVarsDecls -> emptyList() // vars should be looked up via symbol table
|
||||
is PtVariable -> emptyList() // var should be looked up via symbol table
|
||||
is PtMemMapped -> emptyList() // memmapped var should be looked up via symbol table
|
||||
@ -264,6 +264,14 @@ class IRCodeGen(
|
||||
is PtSub -> throw AssemblyError("nested subroutines should have been flattened ${node.position}")
|
||||
else -> TODO("missing codegen for $node")
|
||||
}
|
||||
|
||||
chunks.forEach { chunk ->
|
||||
require(chunk.isNotEmpty() || chunk.label != null) {
|
||||
"chunk should have instructions and/or a label"
|
||||
}
|
||||
}
|
||||
|
||||
return chunks
|
||||
}
|
||||
|
||||
private fun translate(branch: PtConditionalBranch): IRCodeChunks {
|
||||
|
@ -5,6 +5,7 @@ import prog8.intermediate.*
|
||||
internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
||||
fun optimize() {
|
||||
irprog.blocks.asSequence().flatMap { it.subroutines }.forEach { sub ->
|
||||
removeEmptyChunks(sub)
|
||||
joinChunks(sub)
|
||||
sub.chunks.forEach { chunk ->
|
||||
// we don't optimize Inline Asm chunks here.
|
||||
@ -27,6 +28,51 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeEmptyChunks(sub: IRSubroutine) {
|
||||
if(sub.chunks.isEmpty())
|
||||
return
|
||||
|
||||
/*
|
||||
Empty Code chunk with label ->
|
||||
If next chunk has no label -> move label to next chunk, remove original
|
||||
If next chunk has label -> label name should be the same, remove original. Otherwise FOR NOW leave it in place. (TODO: consolidate labels into 1)
|
||||
Empty Code chunk without label ->
|
||||
should not have been generated! ERROR.
|
||||
*/
|
||||
|
||||
|
||||
val relabelChunks = mutableListOf<Pair<Int, String>>()
|
||||
val removeChunks = mutableListOf<Int>()
|
||||
|
||||
sub.chunks.withIndex().forEach { (index, chunk) ->
|
||||
require(chunk.isNotEmpty() || chunk.label!=null) {
|
||||
"chunk should have instructions and/or a label"
|
||||
}
|
||||
|
||||
if(chunk is IRCodeChunk && chunk.label!=null && chunk.instructions.isEmpty()) {
|
||||
val nextchunk = sub.chunks[index+1]
|
||||
if(nextchunk.label==null) {
|
||||
// can transplant label to next chunk and remove this empty one.
|
||||
relabelChunks += Pair(index+1, chunk.label!!)
|
||||
removeChunks += index
|
||||
} else {
|
||||
if(chunk.label==nextchunk.label)
|
||||
removeChunks += index
|
||||
else {
|
||||
// TODO: consolidate labels on same chunk
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
relabelChunks.forEach { (index, label) ->
|
||||
val chunk = IRCodeChunk(label, sub.chunks[index].position)
|
||||
chunk.instructions += sub.chunks[index].instructions
|
||||
sub.chunks[index] = chunk
|
||||
}
|
||||
removeChunks.reversed().forEach { index -> sub.chunks.removeAt(index) }
|
||||
}
|
||||
|
||||
private fun joinChunks(sub: IRSubroutine) {
|
||||
/*
|
||||
Subroutine contains a list of chunks.
|
||||
@ -34,9 +80,10 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
||||
TODO: this has to be changed later...
|
||||
*/
|
||||
|
||||
/* if(sub.chunks.isEmpty())
|
||||
if(sub.chunks.isEmpty())
|
||||
return
|
||||
|
||||
/*
|
||||
fun mayJoin(previous: IRCodeChunkBase, chunk: IRCodeChunkBase): Boolean {
|
||||
if(previous is IRCodeChunk && chunk is IRCodeChunk) {
|
||||
return true
|
||||
|
@ -3,8 +3,9 @@ TODO
|
||||
|
||||
For next release
|
||||
^^^^^^^^^^^^^^^^
|
||||
- ir: get rid of IRCodeLabel, make every label start a new code chunk, give those a 'label' property.
|
||||
- ir: fix program to be list of chunks
|
||||
- ir: fix unit tests
|
||||
- ir: link all sequential chunks to another (exiting one chunk 'calls' the next chunk)
|
||||
- ir: jump/branch instructions don't link to a PC index anymore, but to the actual chunk with that label
|
||||
- ir: fix joinChunks() in the IR optimizer ? Fix TestIRPeepholeOptimizer and TestVm
|
||||
- vm: program is list of chunks, fix dispatcher
|
||||
|
@ -263,7 +263,7 @@ class IRFileReader {
|
||||
line = lines.next()
|
||||
var chunk = IRCodeChunk(null, Position.DUMMY)
|
||||
if(line=="<C>") {
|
||||
chunk = parseCodeChunk(line, lines, null)!!
|
||||
chunk = parseCodeChunk(line, lines)!!
|
||||
line = lines.next()
|
||||
}
|
||||
if(line!="</INITGLOBALS>")
|
||||
@ -285,8 +285,8 @@ class IRFileReader {
|
||||
}
|
||||
|
||||
private val blockPattern = Regex("<BLOCK NAME=(.+) ADDRESS=(.+) ALIGN=(.+) POS=(.+)>")
|
||||
private val inlineAsmPattern = Regex("<INLINEASM IR=(.+) POS=(.+)>")
|
||||
private val bytesPattern = Regex("<BYTES POS=(.+)>")
|
||||
private val inlineAsmPattern = Regex("<INLINEASM LABEL=(.*) IR=(.+) POS=(.+)>")
|
||||
private val bytesPattern = Regex("<BYTES LABEL=(.*) POS=(.+)>")
|
||||
private val asmsubPattern = Regex("<ASMSUB NAME=(.+) ADDRESS=(.+) CLOBBERS=(.*) RETURNS=(.*) POS=(.+)>")
|
||||
private val subPattern = Regex("<SUB NAME=(.+) RETURNTYPE=(.+) POS=(.+)>")
|
||||
private val posPattern = Regex("\\[(.+): line (.+) col (.+)-(.+)\\]")
|
||||
@ -312,18 +312,19 @@ class IRFileReader {
|
||||
val sub = parseAsmSubroutine(line, lines)
|
||||
block += sub
|
||||
} else if(line.startsWith("<INLINEASM ")) {
|
||||
val asm = parseInlineAssembly(line, lines, null)
|
||||
val asm = parseInlineAssembly(line, lines)
|
||||
block += asm
|
||||
} else
|
||||
throw IRParseException("invalid line in BLOCK")
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseInlineAssembly(startline: String, lines: Iterator<String>, label: String?): IRInlineAsmChunk {
|
||||
// <INLINEASM IR=true POS=[examples/test.p8: line 8 col 6-9]>
|
||||
private fun parseInlineAssembly(startline: String, lines: Iterator<String>): IRInlineAsmChunk {
|
||||
// <INLINEASM LABEL=optional-label IR=true POS=[examples/test.p8: line 8 col 6-9]>
|
||||
val match = inlineAsmPattern.matchEntire(startline) ?: throw IRParseException("invalid INLINEASM")
|
||||
val isIr = match.groupValues[1].toBoolean()
|
||||
val pos = parsePosition(match.groupValues[2])
|
||||
val label = match.groupValues[1]
|
||||
val isIr = match.groupValues[2].toBoolean()
|
||||
val pos = parsePosition(match.groupValues[3])
|
||||
val asmlines = mutableListOf<String>()
|
||||
var line = lines.next()
|
||||
while(line!="</INLINEASM>") {
|
||||
@ -352,7 +353,7 @@ class IRFileReader {
|
||||
params += Pair(dt, regsf)
|
||||
}
|
||||
line = lines.next()
|
||||
val asm = parseInlineAssembly(line, lines, null)
|
||||
val asm = parseInlineAssembly(line, lines)
|
||||
while(line!="</ASMSUB>")
|
||||
line = lines.next()
|
||||
val clobberRegs = if(clobbers.isBlank()) emptyList() else clobbers.split(',').map { CpuRegister.valueOf(it) }
|
||||
@ -386,12 +387,12 @@ class IRFileReader {
|
||||
val line = lines.next()
|
||||
if(line=="</SUB>")
|
||||
return sub
|
||||
val chunk = if(line=="<C>")
|
||||
parseCodeChunk(line, lines, null)
|
||||
val chunk = if(line.startsWith("<C"))
|
||||
parseCodeChunk(line, lines)
|
||||
else if(line.startsWith("<BYTES "))
|
||||
parseBinaryBytes(line, lines, null)
|
||||
parseBinaryBytes(line, lines)
|
||||
else if(line.startsWith("<INLINEASM "))
|
||||
parseInlineAssembly(line, lines, null)
|
||||
parseInlineAssembly(line, lines)
|
||||
else
|
||||
throw IRParseException("invalid sub child node")
|
||||
|
||||
@ -406,9 +407,10 @@ class IRFileReader {
|
||||
return sub
|
||||
}
|
||||
|
||||
private fun parseBinaryBytes(startline: String, lines: Iterator<String>, label: String?): IRInlineBinaryChunk {
|
||||
private fun parseBinaryBytes(startline: String, lines: Iterator<String>): IRInlineBinaryChunk {
|
||||
val match = bytesPattern.matchEntire(startline) ?: throw IRParseException("invalid BYTES")
|
||||
val pos = parsePosition(match.groupValues[1])
|
||||
val label = match.groupValues[1]
|
||||
val pos = parsePosition(match.groupValues[2])
|
||||
val bytes = mutableListOf<UByte>()
|
||||
var line = lines.next()
|
||||
while(line!="</BYTES>") {
|
||||
@ -436,13 +438,17 @@ class IRFileReader {
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseCodeChunk(firstline: String, lines: Iterator<String>, label: String?): IRCodeChunk? {
|
||||
if(firstline!="<C>") {
|
||||
private fun parseCodeChunk(firstline: String, lines: Iterator<String>): IRCodeChunk? {
|
||||
if(!firstline.startsWith("<C")) {
|
||||
if(firstline=="</SUB>")
|
||||
return null
|
||||
else
|
||||
throw IRParseException("invalid or empty <C>ODE chunk")
|
||||
}
|
||||
val label = if(firstline.startsWith("<C LABEL="))
|
||||
firstline.split('=', limit = 2)[1].dropLast(1)
|
||||
else
|
||||
null
|
||||
val chunk = IRCodeChunk(label, Position.DUMMY)
|
||||
while(true) {
|
||||
val line = lines.next()
|
||||
|
@ -64,12 +64,14 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
||||
is IRInlineAsmChunk -> writeInlineAsm(chunk)
|
||||
is IRInlineBinaryChunk -> writeInlineBytes(chunk)
|
||||
else -> {
|
||||
out.write("<C>\n")
|
||||
if (chunk.instructions.isEmpty())
|
||||
throw InternalCompilerException("empty code chunk in ${it.name} ${it.position}")
|
||||
if(chunk.label!=null)
|
||||
out.write("<C LABEL=${chunk.label}>\n")
|
||||
else
|
||||
out.write("<C>\n")
|
||||
chunk.instructions.forEach { instr ->
|
||||
numInstr++
|
||||
out.write(instr.toString())
|
||||
out.write("\n")
|
||||
}
|
||||
out.write("</C>\n")
|
||||
}
|
||||
@ -100,7 +102,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
||||
}
|
||||
|
||||
private fun writeInlineBytes(chunk: IRInlineBinaryChunk) {
|
||||
out.write("<BYTES POS=${chunk.position}>\n")
|
||||
out.write("<BYTES LABEL=${chunk.label ?: ""} POS=${chunk.position}>\n")
|
||||
chunk.data.withIndex().forEach {(index, byte) ->
|
||||
out.write(byte.toString(16).padStart(2,'0'))
|
||||
if(index and 63 == 63 && index < chunk.data.size-1)
|
||||
@ -110,7 +112,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
||||
}
|
||||
|
||||
private fun writeInlineAsm(chunk: IRInlineAsmChunk) {
|
||||
out.write("<INLINEASM IR=${chunk.isIR} POS=${chunk.position}>\n")
|
||||
out.write("<INLINEASM LABEL=${chunk.label ?: ""} IR=${chunk.isIR} POS=${chunk.position}>\n")
|
||||
out.write(chunk.assembly)
|
||||
out.write("\n</INLINEASM>\n")
|
||||
}
|
||||
|
@ -72,7 +72,8 @@ class IRProgram(val name: String,
|
||||
}
|
||||
it.subroutines.forEach { sub ->
|
||||
sub.chunks.forEach { chunk ->
|
||||
if (chunk is IRInlineAsmChunk) { require(chunk.instructions.isEmpty()) }
|
||||
if (chunk is IRCodeChunk) require(chunk.instructions.isNotEmpty() || chunk.label!=null)
|
||||
else require(chunk.instructions.isEmpty())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -143,7 +144,12 @@ class IRSubroutine(val name: String,
|
||||
require(returnType==null || returnType in NumericDatatypes) {"non-numeric returntype $returnType"}
|
||||
}
|
||||
|
||||
operator fun plusAssign(chunk: IRCodeChunkBase) { chunks+= chunk }
|
||||
operator fun plusAssign(chunk: IRCodeChunkBase) {
|
||||
require(chunk.isNotEmpty() || chunk.label!=null) {
|
||||
"chunk should have instructions and/or a label"
|
||||
}
|
||||
chunks+= chunk
|
||||
}
|
||||
}
|
||||
|
||||
class IRAsmSubroutine(
|
||||
|
Loading…
Reference in New Issue
Block a user