mirror of
https://github.com/irmen/prog8.git
synced 2025-11-03 19:16:13 +00:00
remove redundant variable=0 initializations (BSS clear takes care of them)
This commit is contained in:
@@ -353,7 +353,9 @@ internal class ProgramAndVarsGen(
|
||||
initializers.forEach { assign ->
|
||||
if((assign.value as? PtNumber)?.number != 0.0 || allocator.isZpVar(assign.target.identifier!!.name))
|
||||
asmgen.translate(assign)
|
||||
// the other variables that should be set to zero are done so as part of the BSS section.
|
||||
else
|
||||
throw AssemblyError("non-zp variable should not be initialized to zero; it will be zeroed as part of BSS clear")
|
||||
// the other variables that should be set to zero are done so as part of the BSS section clear.
|
||||
}
|
||||
asmgen.out(" rts\n .bend")
|
||||
}
|
||||
|
||||
@@ -64,15 +64,17 @@ class IRCodeGen(
|
||||
if(variable.uninitialized && variable.parent.type==StNodeType.BLOCK) {
|
||||
val block = variable.parent.astNode as PtBlock
|
||||
val initialization = (block.children.firstOrNull {
|
||||
it is PtAssignment && it.target.identifier?.name==variable.scopedName
|
||||
it is PtAssignment && it.isVarInitializer && it.target.identifier?.name==variable.scopedName
|
||||
} as PtAssignment?)
|
||||
val initValue = initialization?.value
|
||||
when(initValue){
|
||||
is PtBool -> {
|
||||
require(initValue.asInt()!=0) { "boolean var should not be initialized with false, it wil be set to false as part of BSS clear, initializer=$initialization" }
|
||||
variable.setOnetimeInitNumeric(initValue.asInt().toDouble())
|
||||
initsToRemove += block to initialization
|
||||
}
|
||||
is PtNumber -> {
|
||||
require(initValue.number!=0.0) { "variable should not be initialized with 0, it will already be zeroed as part of BSS clear, initializer=$initialization" }
|
||||
variable.setOnetimeInitNumeric(initValue.number)
|
||||
initsToRemove += block to initialization
|
||||
}
|
||||
|
||||
@@ -164,6 +164,9 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro
|
||||
}
|
||||
}
|
||||
|
||||
if(srcAssign.origin == AssignmentOrigin.VARINIT && srcAssign.parent is Block && srcAssign.value.constValue(program)?.number==0.0)
|
||||
throw FatalAstException("should not have a redundant block-level variable=0 assignment; it will be zeroed as part of BSS clear")
|
||||
|
||||
val assign = PtAssignment(srcAssign.position, srcAssign.origin==AssignmentOrigin.VARINIT)
|
||||
val multi = srcAssign.target.multi
|
||||
if(multi==null) {
|
||||
|
||||
@@ -52,7 +52,8 @@ internal class StatementReorderer(
|
||||
if (decl.datatype.isNumericOrBool) {
|
||||
if(decl !in declsProcessedWithInitAssignment) {
|
||||
declsProcessedWithInitAssignment.add(decl)
|
||||
if (decl.value == null) {
|
||||
if (decl.value == null || decl.value?.constValue(program)?.number==0.0) {
|
||||
decl.value = null
|
||||
if (decl.origin==VarDeclOrigin.USERCODE && decl.allowInitializeWithZero) {
|
||||
if(decl.dirty) {
|
||||
// no initialization at all!
|
||||
@@ -62,11 +63,9 @@ internal class StatementReorderer(
|
||||
// unless there's already an assignment below it, that initializes the value (or a for loop that uses it as loopvar).
|
||||
// This allows you to restart the program and have the same starting values of the variables
|
||||
// So basically consider 'ubyte xx' as a short form for 'ubyte xx; xx=0'
|
||||
decl.value = null
|
||||
val canskip = canSkipInitializationWith0(decl)
|
||||
if (!canskip) {
|
||||
// (this explicit initialization assignment to 0 is not required for global variables in the block scope, these are zeroed as part of the BSS section clear)
|
||||
if (!canSkipInitializationWith0(decl)) {
|
||||
// Add assignment to initialize with zero
|
||||
// Note: for block-level vars, this will introduce assignments in the block scope. These have to be dealt with correctly later.
|
||||
val identifier = IdentifierReference(listOf(decl.name), decl.position)
|
||||
val assignzero = Assignment(AssignTarget(identifier, null, null, null, false, decl.position),
|
||||
decl.zeroElementValue(), AssignmentOrigin.VARINIT, decl.position)
|
||||
@@ -115,6 +114,11 @@ internal class StatementReorderer(
|
||||
}
|
||||
|
||||
private fun canSkipInitializationWith0(decl: VarDecl): Boolean {
|
||||
// if the variable is declared in a block, we can omit the init with 0 because
|
||||
// the variable will be initialized to zero when the BSS section is cleared as a whole.
|
||||
if(decl.parent is Block)
|
||||
return true
|
||||
|
||||
// if there is an assignment to the variable below it (regular assign, or For loop),
|
||||
// and there is nothing important in between, we can skip the initialization.
|
||||
val statements = (decl.parent as? IStatementContainer)?.statements ?: return false
|
||||
|
||||
@@ -125,29 +125,24 @@ main {
|
||||
|
||||
val result = compileText(C64Target(), true, src, outputDir, writeAssembly = true)!!.compilerAst
|
||||
val main = result.allBlocks.first { it.name=="main" }
|
||||
main.statements.size shouldBe 17
|
||||
main.statements.size shouldBe 15
|
||||
val assigns = main.statements.filterIsInstance<Assignment>()
|
||||
assigns[0].target.identifier?.nameInSource shouldBe listOf("value1")
|
||||
assigns[1].target.identifier?.nameInSource shouldBe listOf("value2")
|
||||
assigns[2].target.identifier?.nameInSource shouldBe listOf("value3")
|
||||
assigns[3].target.identifier?.nameInSource shouldBe listOf("value4")
|
||||
assigns[4].target.identifier?.nameInSource shouldBe listOf("value5")
|
||||
assigns[5].target.identifier?.nameInSource shouldBe listOf("value6")
|
||||
assigns[6].target.identifier?.nameInSource shouldBe listOf("value7")
|
||||
assigns.size shouldBe 5
|
||||
assigns[0].target.identifier?.nameInSource shouldBe listOf("value2")
|
||||
assigns[1].target.identifier?.nameInSource shouldBe listOf("value3")
|
||||
assigns[2].target.identifier?.nameInSource shouldBe listOf("value5")
|
||||
assigns[3].target.identifier?.nameInSource shouldBe listOf("value6")
|
||||
assigns[4].target.identifier?.nameInSource shouldBe listOf("value7")
|
||||
assigns[0].origin shouldBe AssignmentOrigin.VARINIT
|
||||
assigns[1].origin shouldBe AssignmentOrigin.VARINIT
|
||||
assigns[2].origin shouldBe AssignmentOrigin.VARINIT
|
||||
assigns[3].origin shouldBe AssignmentOrigin.VARINIT
|
||||
assigns[4].origin shouldBe AssignmentOrigin.VARINIT
|
||||
assigns[5].origin shouldBe AssignmentOrigin.VARINIT
|
||||
assigns[6].origin shouldBe AssignmentOrigin.VARINIT
|
||||
assigns[0].value.constValue(result)?.number shouldBe 0
|
||||
assigns[1].value.constValue(result)?.number shouldBe 1
|
||||
assigns[2].value.constValue(result)?.number shouldBe 1
|
||||
assigns[3].value.constValue(result)?.number shouldBe 0
|
||||
assigns[0].value.constValue(result)?.asBooleanValue shouldBe true
|
||||
assigns[1].value.constValue(result)?.asBooleanValue shouldBe true
|
||||
assigns[2].value.constValue(result) shouldBe null
|
||||
assigns[3].value.constValue(result)?.number shouldBe 4242
|
||||
assigns[4].value.constValue(result) shouldBe null
|
||||
assigns[5].value.constValue(result)?.number shouldBe 4242
|
||||
assigns[6].value.constValue(result) shouldBe null
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ TODO
|
||||
Future Things and Ideas
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- randrange() function can be optimized by just multiplying by the range and bit shifting down?
|
||||
- romable: should we have a way to explicitly set the memory address for the BSS area (instead of only the highram bank number on X16, allow a memory address too for the -varshigh option?)
|
||||
- Kotlin: can we use inline value classes in certain spots?
|
||||
- add float support to the configurable compiler targets
|
||||
|
||||
@@ -1,25 +1,37 @@
|
||||
%import textio
|
||||
%zeropage basicsafe
|
||||
%zeropage dontuse
|
||||
%option no_sysinit
|
||||
|
||||
main {
|
||||
ubyte @shared ub_global
|
||||
uword @shared uw_global = 0
|
||||
bool[4] @shared bool_array_global
|
||||
|
||||
sub start() {
|
||||
uword[] @nosplit ptrs = [one, two, three]
|
||||
ubyte @shared ub_scoped
|
||||
uword @shared uw_scoped = 0
|
||||
bool[4] @shared bool_array_scoped
|
||||
|
||||
ubyte @shared x =1
|
||||
dump()
|
||||
|
||||
goto ptrs[x]
|
||||
}
|
||||
ub_scoped++
|
||||
uw_scoped++
|
||||
bool_array_scoped[2]=true
|
||||
ub_global++
|
||||
uw_global++
|
||||
bool_array_global[2]=true
|
||||
|
||||
sub one() {
|
||||
txt.print("one\n")
|
||||
}
|
||||
sub two() {
|
||||
txt.print("two\n")
|
||||
}
|
||||
sub three() {
|
||||
txt.print("three\n")
|
||||
}
|
||||
dump()
|
||||
|
||||
sub dump() {
|
||||
txt.print_ub(ub_global)
|
||||
txt.print_uw(uw_global)
|
||||
txt.print_bool(bool_array_global[2])
|
||||
txt.nl()
|
||||
txt.print_ub(ub_scoped)
|
||||
txt.print_uw(uw_scoped)
|
||||
txt.print_bool(bool_array_scoped[2])
|
||||
txt.nl()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,6 +198,8 @@ class StStaticVariable(name: String,
|
||||
// This has to do with the way Prog8 does the (re)initialization of such variables: via code assignment statements.
|
||||
// Certain codegens might want to put them back into the variable directly.
|
||||
// For strings and arrays this doesn't occur - these are always already specced at creation time.
|
||||
|
||||
require(number!=0.0) { "variable should not be initialized with 0, it will already be zeroed as part of BSS clear" }
|
||||
initializationNumericValue = number
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package prog8.vm
|
||||
|
||||
import prog8.Either
|
||||
import prog8.code.core.DataType
|
||||
import prog8.intermediate.*
|
||||
import prog8.left
|
||||
import prog8.right
|
||||
import prog8.intermediate.*
|
||||
import prog8.code.core.DataType
|
||||
|
||||
class VmProgramLoader {
|
||||
private val placeholders = mutableMapOf<Pair<IRCodeChunk, Int>, String>() // program chunk+index to symbolname
|
||||
@@ -223,6 +223,15 @@ class VmProgramLoader {
|
||||
else -> throw IRParseException("invalid dt")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
when {
|
||||
variable.dt.isUnsignedByte || variable.dt.isBool -> memory.setUB(addr, 0u)
|
||||
variable.dt.isSignedByte -> memory.setSB(addr, 0)
|
||||
variable.dt.isUnsignedWord -> memory.setUW(addr, 0u)
|
||||
variable.dt.isSignedWord -> memory.setSW(addr, 0)
|
||||
variable.dt.isFloat -> memory.setFloat(addr, 0.0)
|
||||
else -> throw IRParseException("invalid dt")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user