ir: fix asmsub contents not appearing in IR file

This commit is contained in:
Irmen de Jong 2022-11-01 00:15:39 +01:00
parent b22804efaf
commit e67c05c274
8 changed files with 89 additions and 15 deletions

View File

@ -56,7 +56,16 @@ class IRCodeGen(
if(options.optimize) { if(options.optimize) {
val optimizer = IRPeepholeOptimizer(irProg) val optimizer = IRPeepholeOptimizer(irProg)
optimizer.optimize() optimizer.optimize()
irProg.linkChunks() // re-link
// TODO FIX & REENABLE:
// val remover = IRUnusedCodeRemover(irProg, errors)
// do {
// val numRemoved = remover.optimize()
// } while(numRemoved>0 && errors.noErrors())
//
// errors.report()
irProg.linkChunks() // re-link
} }
irProg.validate() irProg.validate()
@ -249,6 +258,7 @@ class IRCodeGen(
sub.retvalRegisters, sub.retvalRegisters,
sub.inline, sub.inline,
sub.position) sub.position)
renamedSub.add(sub.children.single())
parent.children.remove(sub) parent.children.remove(sub)
parent.add(renamedSub) parent.add(renamedSub)
} }
@ -1082,9 +1092,9 @@ class IRCodeGen(
irBlock += sub irBlock += sub
} }
is PtAsmSub -> { is PtAsmSub -> {
val assemblyChild = if(child.children.isEmpty()) null else (child.children.single() as PtInlineAssembly) val assemblyChild = child.children.single() as PtInlineAssembly
val asmChunk = IRInlineAsmChunk( val asmChunk = IRInlineAsmChunk(
child.name, assemblyChild?.assembly ?: "", assemblyChild?.isIR==true, child.position, null child.name, assemblyChild.assembly, assemblyChild.isIR, child.position, null
) )
irBlock += IRAsmSubroutine( irBlock += IRAsmSubroutine(
child.name, child.name,

View File

@ -27,6 +27,8 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
} }
removeEmptyChunks(sub) removeEmptyChunks(sub)
} }
irprog.linkChunks() // re-link
} }
private fun removeEmptyChunks(sub: IRSubroutine) { private fun removeEmptyChunks(sub: IRSubroutine) {

View File

@ -0,0 +1,38 @@
package prog8.codegen.intermediate
import prog8.code.core.IErrorReporter
import prog8.code.core.SourceCode.Companion.libraryFilePrefix
import prog8.intermediate.*
internal class IRUnusedCodeRemover(private val irprog: IRProgram, private val errors: IErrorReporter) {
fun optimize(): Int {
val linkedChunks = mutableSetOf<IRCodeChunkBase>()
var numRemoved = 0
irprog.blocks.asSequence().flatMap { it.subroutines }.forEach { sub ->
sub.chunks.forEach { chunk ->
if(chunk.next!=null)
linkedChunks += chunk.next!!
chunk.instructions.forEach {
if(it.branchTarget!=null)
linkedChunks += it.branchTarget!!
}
if(chunk.label=="main.start")
linkedChunks += chunk
}
}
irprog.blocks.asSequence().flatMap { it.subroutines }.forEach { sub ->
sub.chunks.reversed().forEach { chunk ->
if(chunk !in linkedChunks) {
if(!chunk.position.file.startsWith(libraryFilePrefix))
errors.warn("unreachable code", chunk.position)
sub.chunks.remove(chunk)
numRemoved++
}
}
}
return numRemoved
}
}

View File

@ -240,6 +240,6 @@ main {
val exc = shouldThrow<Exception> { val exc = shouldThrow<Exception> {
VmRunner().runProgram(virtfile.readText()) VmRunner().runProgram(virtfile.readText())
} }
exc.message shouldContain("does not support asmsubs") exc.message shouldContain("does not support non-IR asmsubs")
} }
}) })

View File

@ -3,7 +3,8 @@ TODO
For next release For next release
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^
- ir: asmsub contents remains blank in IR file ? - ir: position of chunk of text.print("abc") seems to point to the string arg instead of the call
- fix unused chunk remover that now causes code execution error (IRCodeGen should enable it)
- ir: improve dead code elimination by checking chunk linkage. Does this solve the next issue?: - ir: improve dead code elimination by checking chunk linkage. Does this solve the next issue?:
- ir: how to remove all unused subroutines? (the 6502 assembly codegen relies on 64tass solve this for us) - ir: how to remove all unused subroutines? (the 6502 assembly codegen relies on 64tass solve this for us)

View File

@ -107,8 +107,10 @@ class IRProgram(val name: String,
if(next!=null) { if(next!=null) {
if (next is IRCodeChunk && chunk.instructions.lastOrNull()?.opcode !in OpcodesThatJump) if (next is IRCodeChunk && chunk.instructions.lastOrNull()?.opcode !in OpcodesThatJump)
chunk.next = next chunk.next = next
else if(next is IRInlineAsmChunk)
chunk.next = next
else else
throw AssemblyError("code chunk flows into following non-code chunk") throw AssemblyError("code chunk flows into following non-executable chunk")
} }
} }

View File

@ -40,16 +40,14 @@ class VmProgramLoader {
block.inlineAssembly.forEach { block.inlineAssembly.forEach {
val replacement = addAssemblyToProgram(it, programChunks, variableAddresses) val replacement = addAssemblyToProgram(it, programChunks, variableAddresses)
if(replacement!=null) chunkReplacements += replacement
chunkReplacements += replacement
} }
block.subroutines.forEach { block.subroutines.forEach {
it.chunks.forEach { chunk -> it.chunks.forEach { chunk ->
when (chunk) { when (chunk) {
is IRInlineAsmChunk -> { is IRInlineAsmChunk -> {
val replacement = addAssemblyToProgram(chunk, programChunks, variableAddresses) val replacement = addAssemblyToProgram(chunk, programChunks, variableAddresses)
if(replacement!=null) chunkReplacements += replacement
chunkReplacements += replacement
} }
is IRInlineBinaryChunk -> TODO("inline binary data not yet supported in the VM") is IRInlineBinaryChunk -> TODO("inline binary data not yet supported in the VM")
is IRCodeChunk -> programChunks += chunk is IRCodeChunk -> programChunks += chunk
@ -57,8 +55,14 @@ class VmProgramLoader {
} }
} }
} }
if(block.asmSubroutines.any()) block.asmSubroutines.forEach {
throw IRParseException("vm currently does not support asmsubs: ${block.asmSubroutines.first().name}") if(!it.asmChunk.isIR)
throw IRParseException("vm currently does not support non-IR asmsubs: ${block.asmSubroutines.first().name}")
else {
val replacement = addAssemblyToProgram(it.asmChunk, programChunks, variableAddresses)
chunkReplacements += replacement
}
}
} }
pass2translateSyscalls(programChunks) pass2translateSyscalls(programChunks)

View File

@ -82,7 +82,7 @@ class TestVm: FunSpec( {
} }
} }
test("vm asmsub not supported") { test("non-IR asmsub not supported in vm") {
val program = IRProgram("test", IRSymbolTable(null), getTestOptions(), VMTarget()) val program = IRProgram("test", IRSymbolTable(null), getTestOptions(), VMTarget())
val block = IRBlock("main", null, IRBlock.BlockAlignment.NONE, Position.DUMMY) val block = IRBlock("main", null, IRBlock.BlockAlignment.NONE, Position.DUMMY)
val startSub = IRAsmSubroutine( val startSub = IRAsmSubroutine(
@ -91,16 +91,33 @@ class TestVm: FunSpec( {
emptySet(), emptySet(),
emptyList(), emptyList(),
emptyList(), emptyList(),
IRInlineAsmChunk("main.asmstart", "inlined asm here", true, Position.DUMMY, null), IRInlineAsmChunk("main.asmstart", "inlined asm here", false, Position.DUMMY, null),
Position.DUMMY Position.DUMMY
) )
block += startSub block += startSub
program.addBlock(block) program.addBlock(block)
shouldThrowWithMessage<IRParseException>("vm currently does not support asmsubs: main.asmstart") { shouldThrowWithMessage<IRParseException>("vm currently does not support non-IR asmsubs: main.asmstart") {
VirtualMachine(program) VirtualMachine(program)
} }
} }
test("IR asmsub ok in vm") {
val program = IRProgram("test", IRSymbolTable(null), getTestOptions(), VMTarget())
val block = IRBlock("main", null, IRBlock.BlockAlignment.NONE, Position.DUMMY)
val startSub = IRAsmSubroutine(
"main.start",
0x2000u,
emptySet(),
emptyList(),
emptyList(),
IRInlineAsmChunk("main.start", "return", true, Position.DUMMY, null),
Position.DUMMY
)
block += startSub
program.addBlock(block)
VirtualMachine(program).run()
}
test("vmrunner") { test("vmrunner") {
val runner = VmRunner() val runner = VmRunner()
val irSource="""<PROGRAM NAME=test> val irSource="""<PROGRAM NAME=test>