mirror of
https://github.com/irmen/prog8.git
synced 2025-11-05 17:21:42 +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 ->
|
initializers.forEach { assign ->
|
||||||
if((assign.value as? PtNumber)?.number != 0.0 || allocator.isZpVar(assign.target.identifier!!.name))
|
if((assign.value as? PtNumber)?.number != 0.0 || allocator.isZpVar(assign.target.identifier!!.name))
|
||||||
asmgen.translate(assign)
|
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")
|
asmgen.out(" rts\n .bend")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,15 +64,17 @@ class IRCodeGen(
|
|||||||
if(variable.uninitialized && variable.parent.type==StNodeType.BLOCK) {
|
if(variable.uninitialized && variable.parent.type==StNodeType.BLOCK) {
|
||||||
val block = variable.parent.astNode as PtBlock
|
val block = variable.parent.astNode as PtBlock
|
||||||
val initialization = (block.children.firstOrNull {
|
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?)
|
} as PtAssignment?)
|
||||||
val initValue = initialization?.value
|
val initValue = initialization?.value
|
||||||
when(initValue){
|
when(initValue){
|
||||||
is PtBool -> {
|
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())
|
variable.setOnetimeInitNumeric(initValue.asInt().toDouble())
|
||||||
initsToRemove += block to initialization
|
initsToRemove += block to initialization
|
||||||
}
|
}
|
||||||
is PtNumber -> {
|
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)
|
variable.setOnetimeInitNumeric(initValue.number)
|
||||||
initsToRemove += block to initialization
|
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 assign = PtAssignment(srcAssign.position, srcAssign.origin==AssignmentOrigin.VARINIT)
|
||||||
val multi = srcAssign.target.multi
|
val multi = srcAssign.target.multi
|
||||||
if(multi==null) {
|
if(multi==null) {
|
||||||
|
|||||||
@@ -52,7 +52,8 @@ internal class StatementReorderer(
|
|||||||
if (decl.datatype.isNumericOrBool) {
|
if (decl.datatype.isNumericOrBool) {
|
||||||
if(decl !in declsProcessedWithInitAssignment) {
|
if(decl !in declsProcessedWithInitAssignment) {
|
||||||
declsProcessedWithInitAssignment.add(decl)
|
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.origin==VarDeclOrigin.USERCODE && decl.allowInitializeWithZero) {
|
||||||
if(decl.dirty) {
|
if(decl.dirty) {
|
||||||
// no initialization at all!
|
// 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).
|
// 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
|
// 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'
|
// So basically consider 'ubyte xx' as a short form for 'ubyte xx; xx=0'
|
||||||
decl.value = null
|
// (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)
|
||||||
val canskip = canSkipInitializationWith0(decl)
|
if (!canSkipInitializationWith0(decl)) {
|
||||||
if (!canskip) {
|
|
||||||
// Add assignment to initialize with zero
|
// 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 identifier = IdentifierReference(listOf(decl.name), decl.position)
|
||||||
val assignzero = Assignment(AssignTarget(identifier, null, null, null, false, decl.position),
|
val assignzero = Assignment(AssignTarget(identifier, null, null, null, false, decl.position),
|
||||||
decl.zeroElementValue(), AssignmentOrigin.VARINIT, decl.position)
|
decl.zeroElementValue(), AssignmentOrigin.VARINIT, decl.position)
|
||||||
@@ -115,6 +114,11 @@ internal class StatementReorderer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun canSkipInitializationWith0(decl: VarDecl): Boolean {
|
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),
|
// 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.
|
// and there is nothing important in between, we can skip the initialization.
|
||||||
val statements = (decl.parent as? IStatementContainer)?.statements ?: return false
|
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 result = compileText(C64Target(), true, src, outputDir, writeAssembly = true)!!.compilerAst
|
||||||
val main = result.allBlocks.first { it.name=="main" }
|
val main = result.allBlocks.first { it.name=="main" }
|
||||||
main.statements.size shouldBe 17
|
main.statements.size shouldBe 15
|
||||||
val assigns = main.statements.filterIsInstance<Assignment>()
|
val assigns = main.statements.filterIsInstance<Assignment>()
|
||||||
assigns[0].target.identifier?.nameInSource shouldBe listOf("value1")
|
assigns.size shouldBe 5
|
||||||
assigns[1].target.identifier?.nameInSource shouldBe listOf("value2")
|
assigns[0].target.identifier?.nameInSource shouldBe listOf("value2")
|
||||||
assigns[2].target.identifier?.nameInSource shouldBe listOf("value3")
|
assigns[1].target.identifier?.nameInSource shouldBe listOf("value3")
|
||||||
assigns[3].target.identifier?.nameInSource shouldBe listOf("value4")
|
assigns[2].target.identifier?.nameInSource shouldBe listOf("value5")
|
||||||
assigns[4].target.identifier?.nameInSource shouldBe listOf("value5")
|
assigns[3].target.identifier?.nameInSource shouldBe listOf("value6")
|
||||||
assigns[5].target.identifier?.nameInSource shouldBe listOf("value6")
|
assigns[4].target.identifier?.nameInSource shouldBe listOf("value7")
|
||||||
assigns[6].target.identifier?.nameInSource shouldBe listOf("value7")
|
|
||||||
assigns[0].origin shouldBe AssignmentOrigin.VARINIT
|
assigns[0].origin shouldBe AssignmentOrigin.VARINIT
|
||||||
assigns[1].origin shouldBe AssignmentOrigin.VARINIT
|
assigns[1].origin shouldBe AssignmentOrigin.VARINIT
|
||||||
assigns[2].origin shouldBe AssignmentOrigin.VARINIT
|
assigns[2].origin shouldBe AssignmentOrigin.VARINIT
|
||||||
assigns[3].origin shouldBe AssignmentOrigin.VARINIT
|
assigns[3].origin shouldBe AssignmentOrigin.VARINIT
|
||||||
assigns[4].origin shouldBe AssignmentOrigin.VARINIT
|
assigns[4].origin shouldBe AssignmentOrigin.VARINIT
|
||||||
assigns[5].origin shouldBe AssignmentOrigin.VARINIT
|
assigns[0].value.constValue(result)?.asBooleanValue shouldBe true
|
||||||
assigns[6].origin shouldBe AssignmentOrigin.VARINIT
|
assigns[1].value.constValue(result)?.asBooleanValue shouldBe true
|
||||||
assigns[0].value.constValue(result)?.number shouldBe 0
|
assigns[2].value.constValue(result) shouldBe null
|
||||||
assigns[1].value.constValue(result)?.number shouldBe 1
|
assigns[3].value.constValue(result)?.number shouldBe 4242
|
||||||
assigns[2].value.constValue(result)?.number shouldBe 1
|
|
||||||
assigns[3].value.constValue(result)?.number shouldBe 0
|
|
||||||
assigns[4].value.constValue(result) shouldBe null
|
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
|
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?)
|
- 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?
|
- Kotlin: can we use inline value classes in certain spots?
|
||||||
- add float support to the configurable compiler targets
|
- add float support to the configurable compiler targets
|
||||||
|
|||||||
@@ -1,25 +1,37 @@
|
|||||||
%import textio
|
%import textio
|
||||||
%zeropage basicsafe
|
%zeropage dontuse
|
||||||
%option no_sysinit
|
%option no_sysinit
|
||||||
|
|
||||||
main {
|
main {
|
||||||
|
ubyte @shared ub_global
|
||||||
|
uword @shared uw_global = 0
|
||||||
|
bool[4] @shared bool_array_global
|
||||||
|
|
||||||
sub start() {
|
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() {
|
dump()
|
||||||
txt.print("one\n")
|
|
||||||
}
|
|
||||||
sub two() {
|
|
||||||
txt.print("two\n")
|
|
||||||
}
|
|
||||||
sub three() {
|
|
||||||
txt.print("three\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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.
|
// 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.
|
// 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.
|
// 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
|
initializationNumericValue = number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package prog8.vm
|
package prog8.vm
|
||||||
|
|
||||||
import prog8.Either
|
import prog8.Either
|
||||||
|
import prog8.code.core.DataType
|
||||||
|
import prog8.intermediate.*
|
||||||
import prog8.left
|
import prog8.left
|
||||||
import prog8.right
|
import prog8.right
|
||||||
import prog8.intermediate.*
|
|
||||||
import prog8.code.core.DataType
|
|
||||||
|
|
||||||
class VmProgramLoader {
|
class VmProgramLoader {
|
||||||
private val placeholders = mutableMapOf<Pair<IRCodeChunk, Int>, String>() // program chunk+index to symbolname
|
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 -> 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