mirror of
https://github.com/irmen/prog8.git
synced 2024-09-07 03:54:27 +00:00
ir: fix asmsub contents not appearing in IR file
This commit is contained in:
parent
b22804efaf
commit
e67c05c274
@ -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,
|
||||||
|
@ -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) {
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
@ -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")
|
||||||
}
|
}
|
||||||
})
|
})
|
@ -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)
|
||||||
|
|
||||||
|
@ -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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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>
|
||||||
|
Loading…
Reference in New Issue
Block a user