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) {
val optimizer = IRPeepholeOptimizer(irProg)
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()
@ -249,6 +258,7 @@ class IRCodeGen(
sub.retvalRegisters,
sub.inline,
sub.position)
renamedSub.add(sub.children.single())
parent.children.remove(sub)
parent.add(renamedSub)
}
@ -1082,9 +1092,9 @@ class IRCodeGen(
irBlock += sub
}
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(
child.name, assemblyChild?.assembly ?: "", assemblyChild?.isIR==true, child.position, null
child.name, assemblyChild.assembly, assemblyChild.isIR, child.position, null
)
irBlock += IRAsmSubroutine(
child.name,

View File

@ -27,6 +27,8 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
}
removeEmptyChunks(sub)
}
irprog.linkChunks() // re-link
}
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> {
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
^^^^^^^^^^^^^^^^
- 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: 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 is IRCodeChunk && chunk.instructions.lastOrNull()?.opcode !in OpcodesThatJump)
chunk.next = next
else if(next is IRInlineAsmChunk)
chunk.next = next
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 {
val replacement = addAssemblyToProgram(it, programChunks, variableAddresses)
if(replacement!=null)
chunkReplacements += replacement
chunkReplacements += replacement
}
block.subroutines.forEach {
it.chunks.forEach { chunk ->
when (chunk) {
is IRInlineAsmChunk -> {
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 IRCodeChunk -> programChunks += chunk
@ -57,8 +55,14 @@ class VmProgramLoader {
}
}
}
if(block.asmSubroutines.any())
throw IRParseException("vm currently does not support asmsubs: ${block.asmSubroutines.first().name}")
block.asmSubroutines.forEach {
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)

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 block = IRBlock("main", null, IRBlock.BlockAlignment.NONE, Position.DUMMY)
val startSub = IRAsmSubroutine(
@ -91,16 +91,33 @@ class TestVm: FunSpec( {
emptySet(),
emptyList(),
emptyList(),
IRInlineAsmChunk("main.asmstart", "inlined asm here", true, Position.DUMMY, null),
IRInlineAsmChunk("main.asmstart", "inlined asm here", false, Position.DUMMY, null),
Position.DUMMY
)
block += startSub
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)
}
}
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") {
val runner = VmRunner()
val irSource="""<PROGRAM NAME=test>