avoid generating superfluous '0' variable initializations, and fix erroneous vardecl order shifting

This commit is contained in:
Irmen de Jong 2020-09-16 21:19:57 +02:00
parent 2a6d9d7e31
commit 6395e39d63
8 changed files with 45 additions and 29 deletions

View File

@ -559,9 +559,11 @@ internal class AstChecker(private val program: Program,
checkValueTypeAndRange(decl.datatype, decl.value as NumericLiteralValue)
}
else -> {
err("var/const declaration needs a compile-time constant initializer value, or range, instead found: ${decl.value!!.javaClass.simpleName}")
super.visit(decl)
return
if(decl.type==VarDeclType.CONST) {
err("const declaration needs a compile-time constant initializer value, or range")
super.visit(decl)
return
}
}
}
}

View File

@ -12,6 +12,7 @@ internal class AstVariousTransforms(private val program: Program) : AstWalker()
override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> {
if(functionCallStatement.target.nameInSource == listOf("swap")) {
// TODO don't replace swap(), let the code generator figure this all out
// if x and y are both just identifiers, do not rewrite (there should be asm generation for that)
// otherwise:
// rewrite swap(x,y) as follows:

View File

@ -71,23 +71,6 @@ internal class StatementReorderer(val program: Program) : AstWalker() {
return noModifications
}
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
val declValue = decl.value
if(declValue!=null && decl.type== VarDeclType.VAR && decl.datatype in NumericDatatypes) {
val declConstValue = declValue.constValue(program)
if(declConstValue==null) {
// move the vardecl (without value) to the scope and replace this with a regular assignment
decl.value = null
val target = AssignTarget(IdentifierReference(listOf(decl.name), decl.position), null, null, decl.position)
val assign = Assignment(target, declValue, decl.position)
return listOf(
IAstModification.ReplaceNode(decl, assign, parent),
IAstModification.InsertFirst(decl, decl.definingScope() as Node)
)
}
}
return noModifications
}
override fun after(whenStatement: WhenStatement, parent: Node): Iterable<IAstModification> {
val choices = whenStatement.choiceValues(program).sortedBy {

View File

@ -18,6 +18,21 @@ class TypecastsAdder(val program: Program, val errors: ErrorReporter) : AstWalke
private val noModifications = emptyList<IAstModification>()
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
val declValue = decl.value
if(decl.type==VarDeclType.VAR && declValue!=null && decl.struct==null) {
val valueDt = declValue.inferType(program)
if(!valueDt.istype(decl.datatype)) {
return listOf(IAstModification.ReplaceNode(
declValue,
TypecastExpression(declValue, decl.datatype, true, declValue.position),
decl
))
}
}
return noModifications
}
override fun after(expr: BinaryExpression, parent: Node): Iterable<IAstModification> {
val leftDt = expr.left.inferType(program)
val rightDt = expr.right.inferType(program)

View File

@ -15,7 +15,7 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: E
private val noModifications = emptyList<IAstModification>()
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
if (decl.value == null && decl.type == VarDeclType.VAR && decl.datatype in NumericDatatypes) {
if (decl.value == null && !decl.autogeneratedDontRemove && decl.type == VarDeclType.VAR && decl.datatype in NumericDatatypes) {
// a numeric vardecl without an initial value is initialized with zero.
decl.value = decl.zeroElementValue()
}
@ -55,7 +55,8 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: E
}
}
if (!conflicts) {
val numericVarsWithValue = decls.filter { it.value != null && it.datatype in NumericDatatypes }
// move vardecls of the scope into the upper scope. Make sure the order remains the same!
val numericVarsWithValue = decls.filter { it.value != null && it.datatype in NumericDatatypes }.reversed()
return numericVarsWithValue.map {
val initValue = it.value!! // assume here that value has always been set by now
it.value = null // make sure no value init assignment for this vardecl will be created later (would be superfluous)

View File

@ -160,6 +160,6 @@ internal class AsmAssignment(val source: AsmAssignSource,
init {
if(target.register !in setOf(RegisterOrPair.XY, RegisterOrPair.AX, RegisterOrPair.AY))
require(source.datatype==target.datatype) {"source and target datatype must be identical"}
require(source.datatype.memorySize() == target.datatype.memorySize()) { "source and target datatype must be same storage class" }
}
}

View File

@ -1,7 +1,6 @@
%import c64lib
%import c64graphics
main {
; vertices
@ -78,11 +77,12 @@ main {
const uword screen_width = 320
const ubyte screen_height = 200
sub draw_lines() {
ubyte @zp i
for i in len(edgesFrom) -1 downto 0 {
ubyte @zp vFrom = edgesFrom[i]
ubyte @zp vTo = edgesTo[i]
ubyte @zp vTo = edgesTo[i] ; TODO need compiler error for double declaration if also declared outside the for loop!
word @zp persp1 = 256 + rotatedz[vFrom]/256
word @zp persp2 = 256 + rotatedz[vTo]/256
graphics.line(rotatedx[vFrom] / persp1 + screen_width/2 as uword,

View File

@ -6,16 +6,30 @@
main {
struct Color {
ubyte red
ubyte green
ubyte blue
}
sub start() {
ubyte ub =9
ubyte ub = 9
uword yy = 9999 ; this is okay (no 0-initialization generated) but... the next:
uword xx = ub ; TODO don't generate xx = 0 assignment if it's initialized with something else...
uword zz
ub++
xx++
yy++
Color purple = [1,2,3]
uword x1
uword x2
word dx = x2 - x1 as word
;ub++
;xx++
;yy++
;zz++
;asmsub clear_screen (ubyte char @ A, ubyte color @ Y) clobbers(A) { ...}
; TODO dont cause name conflict if we define sub or sub with param 'color' or even a var 'color' later.