mirror of
https://github.com/irmen/prog8.git
synced 2024-09-07 19:54:26 +00:00
avoid generating superfluous '0' variable initializations, and fix erroneous vardecl order shifting
This commit is contained in:
parent
2a6d9d7e31
commit
6395e39d63
@ -559,9 +559,11 @@ internal class AstChecker(private val program: Program,
|
|||||||
checkValueTypeAndRange(decl.datatype, decl.value as NumericLiteralValue)
|
checkValueTypeAndRange(decl.datatype, decl.value as NumericLiteralValue)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
err("var/const declaration needs a compile-time constant initializer value, or range, instead found: ${decl.value!!.javaClass.simpleName}")
|
if(decl.type==VarDeclType.CONST) {
|
||||||
super.visit(decl)
|
err("const declaration needs a compile-time constant initializer value, or range")
|
||||||
return
|
super.visit(decl)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ internal class AstVariousTransforms(private val program: Program) : AstWalker()
|
|||||||
|
|
||||||
override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> {
|
override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> {
|
||||||
if(functionCallStatement.target.nameInSource == listOf("swap")) {
|
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)
|
// if x and y are both just identifiers, do not rewrite (there should be asm generation for that)
|
||||||
// otherwise:
|
// otherwise:
|
||||||
// rewrite swap(x,y) as follows:
|
// rewrite swap(x,y) as follows:
|
||||||
|
@ -71,23 +71,6 @@ internal class StatementReorderer(val program: Program) : AstWalker() {
|
|||||||
return noModifications
|
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> {
|
override fun after(whenStatement: WhenStatement, parent: Node): Iterable<IAstModification> {
|
||||||
val choices = whenStatement.choiceValues(program).sortedBy {
|
val choices = whenStatement.choiceValues(program).sortedBy {
|
||||||
|
@ -18,6 +18,21 @@ class TypecastsAdder(val program: Program, val errors: ErrorReporter) : AstWalke
|
|||||||
|
|
||||||
private val noModifications = emptyList<IAstModification>()
|
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> {
|
override fun after(expr: BinaryExpression, parent: Node): Iterable<IAstModification> {
|
||||||
val leftDt = expr.left.inferType(program)
|
val leftDt = expr.left.inferType(program)
|
||||||
val rightDt = expr.right.inferType(program)
|
val rightDt = expr.right.inferType(program)
|
||||||
|
@ -15,7 +15,7 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: E
|
|||||||
private val noModifications = emptyList<IAstModification>()
|
private val noModifications = emptyList<IAstModification>()
|
||||||
|
|
||||||
override fun after(decl: VarDecl, parent: Node): Iterable<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.
|
// a numeric vardecl without an initial value is initialized with zero.
|
||||||
decl.value = decl.zeroElementValue()
|
decl.value = decl.zeroElementValue()
|
||||||
}
|
}
|
||||||
@ -55,7 +55,8 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: E
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!conflicts) {
|
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 {
|
return numericVarsWithValue.map {
|
||||||
val initValue = it.value!! // assume here that value has always been set by now
|
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)
|
it.value = null // make sure no value init assignment for this vardecl will be created later (would be superfluous)
|
||||||
|
@ -160,6 +160,6 @@ internal class AsmAssignment(val source: AsmAssignSource,
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
if(target.register !in setOf(RegisterOrPair.XY, RegisterOrPair.AX, RegisterOrPair.AY))
|
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" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
%import c64lib
|
%import c64lib
|
||||||
%import c64graphics
|
%import c64graphics
|
||||||
|
|
||||||
|
|
||||||
main {
|
main {
|
||||||
|
|
||||||
; vertices
|
; vertices
|
||||||
@ -78,11 +77,12 @@ main {
|
|||||||
const uword screen_width = 320
|
const uword screen_width = 320
|
||||||
const ubyte screen_height = 200
|
const ubyte screen_height = 200
|
||||||
|
|
||||||
|
|
||||||
sub draw_lines() {
|
sub draw_lines() {
|
||||||
ubyte @zp i
|
ubyte @zp i
|
||||||
for i in len(edgesFrom) -1 downto 0 {
|
for i in len(edgesFrom) -1 downto 0 {
|
||||||
ubyte @zp vFrom = edgesFrom[i]
|
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 persp1 = 256 + rotatedz[vFrom]/256
|
||||||
word @zp persp2 = 256 + rotatedz[vTo]/256
|
word @zp persp2 = 256 + rotatedz[vTo]/256
|
||||||
graphics.line(rotatedx[vFrom] / persp1 + screen_width/2 as uword,
|
graphics.line(rotatedx[vFrom] / persp1 + screen_width/2 as uword,
|
||||||
|
@ -6,16 +6,30 @@
|
|||||||
|
|
||||||
main {
|
main {
|
||||||
|
|
||||||
|
struct Color {
|
||||||
|
ubyte red
|
||||||
|
ubyte green
|
||||||
|
ubyte blue
|
||||||
|
}
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
|
|
||||||
ubyte ub =9
|
ubyte ub = 9
|
||||||
uword yy = 9999 ; this is okay (no 0-initialization generated) but... the next:
|
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 xx = ub ; TODO don't generate xx = 0 assignment if it's initialized with something else...
|
||||||
|
uword zz
|
||||||
|
|
||||||
ub++
|
Color purple = [1,2,3]
|
||||||
xx++
|
|
||||||
yy++
|
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) { ...}
|
;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.
|
; TODO dont cause name conflict if we define sub or sub with param 'color' or even a var 'color' later.
|
||||||
|
Loading…
Reference in New Issue
Block a user