mirror of
https://github.com/irmen/prog8.git
synced 2026-10-22 05:02:58 +00:00
keep routines referenced from struct instance initializers, so that unusedcoderemover doesn't strip them
This commit is contained in:
1 parent
6c107379df
commit
e38f71fd2d
2 files changed
+48
No files matched your search
@@ -8,6 +8,18 @@ class IRUnusedCodeRemover(
|
||||
private val irprog: IRProgram,
|
||||
private val errors: IErrorReporter
|
||||
) {
|
||||
/**
|
||||
* The symbols that struct instance initializers take the address of. These are plain data
|
||||
* references: nothing ever calls them, so without this the code they point at is considered
|
||||
* unused and removed, leaving a dangling reference in the instance initializer.
|
||||
* The same reasoning applies to the array initializers of variables, which are handled
|
||||
* separately at each of the use sites below.
|
||||
*/
|
||||
private fun structInstanceInitRefs(): Sequence<IRStSymbolicReference.Symbol> =
|
||||
irprog.st.allStructInstances()
|
||||
.flatMap { instance -> instance.values.asSequence().map { it.value } }
|
||||
.filterIsInstance<IRStSymbolicReference.Symbol>()
|
||||
|
||||
fun optimize(): Int {
|
||||
var numRemoved = removeUnusedSubroutines() + removeUnusedAsmSubroutines()
|
||||
|
||||
@@ -52,6 +64,14 @@ class IRUnusedCodeRemover(
|
||||
return // symbol occurs in an initializer value (address-of this symbol)_
|
||||
}
|
||||
}
|
||||
|
||||
irprog.st.allStructInstances().forEach { instance ->
|
||||
if(instance.values.any { fieldValue ->
|
||||
val ref = fieldValue.value
|
||||
ref is IRStSymbolicReference.Symbol && ref.name.startsWith(blockLabel)
|
||||
})
|
||||
return // symbol occurs in a struct instance initializer value
|
||||
}
|
||||
}
|
||||
|
||||
val blockStructs = irprog.st.allStructDefs().filter { it.name.startsWith(prefix) }
|
||||
@@ -221,6 +241,11 @@ class IRUnusedCodeRemover(
|
||||
}
|
||||
}
|
||||
|
||||
// ... and likewise the ones referenced in struct instance initializers:
|
||||
structInstanceInitRefs()
|
||||
.filter { irprog.st.lookup(it.name) == null }
|
||||
.forEach { ref -> irprog.getChunkWithLabel(ref.name).let { reachable += it } }
|
||||
|
||||
fun grow() {
|
||||
val new = mutableSetOf<IRCodeChunkBase>()
|
||||
reachable.forEach {
|
||||
@@ -277,6 +302,11 @@ class IRUnusedCodeRemover(
|
||||
}
|
||||
}
|
||||
|
||||
// ... and likewise the chunks referenced in struct instance initializers:
|
||||
structInstanceInitRefs()
|
||||
.filter { irprog.st.lookup(it.name) == null }
|
||||
.forEach { ref -> allLabeledChunks[ref.name]?.let { linkedChunks += it } }
|
||||
|
||||
irprog.foreachCodeChunk { chunk ->
|
||||
chunk.next?.let { next -> linkedChunks += next }
|
||||
chunk.instructions.forEach {
|
||||
|
||||
@@ -362,4 +362,22 @@ class TestArraysOfStructs: FunSpec({
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test("routine referenced only from a struct instance initializer is not removed as unused") {
|
||||
val src = """
|
||||
main {
|
||||
sub handler() -> ubyte { return 42 }
|
||||
struct Function { pointer addr }
|
||||
^^Function[] a = [ ^^Function:[&handler] ]
|
||||
sub start() {
|
||||
pointer p = a[0].addr
|
||||
call(p)
|
||||
}
|
||||
}"""
|
||||
val out = tempdir().toPath()
|
||||
compileText(C64Target(), true, src, out, writeAssembly = true, assemble = false, newCodegen = true)!!
|
||||
val asmFile = out.toFile().listFiles()!!.single { it.name.endsWith(".asm") }
|
||||
val lines = asmFile.readText().lines().map { it.trim().replace(Regex("\\s+"), " ") }
|
||||
lines.any { it == "p8b_main.p8s_handler .proc" } shouldBe true
|
||||
}
|
||||
})
|
||||
Reference in new issue
Block a user