From 4b747859b3cd8b17f3eff7b087cbc75d07a6d0c0 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sun, 20 Sep 2020 01:14:53 +0200 Subject: [PATCH] types of constant values now actually follow their declared const var type --- compiler/res/prog8lib/cx16lib.p8 | 104 +++++----- .../optimizer/ConstantFoldingOptimizer.kt | 172 ---------------- .../optimizer/ConstantIdentifierReplacer.kt | 192 ++++++++++++++++++ compiler/src/prog8/optimizer/Extensions.kt | 33 ++- examples/cx16/numbergame.p8 | 2 + examples/cx16/swirl.p8 | 10 +- examples/numbergame.p8 | 3 + examples/swirl.p8 | 10 +- examples/test.p8 | 41 ++-- 9 files changed, 293 insertions(+), 274 deletions(-) create mode 100644 compiler/src/prog8/optimizer/ConstantIdentifierReplacer.kt diff --git a/compiler/res/prog8lib/cx16lib.p8 b/compiler/res/prog8lib/cx16lib.p8 index 2e742ec00..057c82aff 100644 --- a/compiler/res/prog8lib/cx16lib.p8 +++ b/compiler/res/prog8lib/cx16lib.p8 @@ -67,62 +67,62 @@ cx16 { ; the sixteen virtual 16-bit registers - &uword r0 = $02 - &uword r1 = $04 - &uword r2 = $06 - &uword r3 = $08 - &uword r4 = $0a - &uword r5 = $0c - &uword r6 = $0e - &uword r7 = $10 - &uword r8 = $12 - &uword r9 = $14 - &uword r10 = $16 - &uword r11 = $18 - &uword r12 = $1a - &uword r13 = $1c - &uword r14 = $1e - &uword r15 = $20 + &uword r0 = $0002 + &uword r1 = $0004 + &uword r2 = $0006 + &uword r3 = $0008 + &uword r4 = $000a + &uword r5 = $000c + &uword r6 = $000e + &uword r7 = $0010 + &uword r8 = $0012 + &uword r9 = $0014 + &uword r10 = $0016 + &uword r11 = $0018 + &uword r12 = $001a + &uword r13 = $001c + &uword r14 = $001e + &uword r15 = $0020 ; VERA registers const uword VERA_BASE = $9F20 - &ubyte VERA_ADDR_L = VERA_BASE + $00 - &ubyte VERA_ADDR_M = VERA_BASE + $01 - &ubyte VERA_ADDR_H = VERA_BASE + $02 - &ubyte VERA_DATA0 = VERA_BASE + $03 - &ubyte VERA_DATA1 = VERA_BASE + $04 - &ubyte VERA_CTRL = VERA_BASE + $05 - &ubyte VERA_IEN = VERA_BASE + $06 - &ubyte VERA_ISR = VERA_BASE + $07 - &ubyte VERA_IRQ_LINE_L = VERA_BASE + $08 - &ubyte VERA_DC_VIDEO = VERA_BASE + $09 - &ubyte VERA_DC_HSCALE = VERA_BASE + $0A - &ubyte VERA_DC_VSCALE = VERA_BASE + $0B - &ubyte VERA_DC_BORDER = VERA_BASE + $0C - &ubyte VERA_DC_HSTART = VERA_BASE + $09 - &ubyte VERA_DC_HSTOP = VERA_BASE + $0A - &ubyte VERA_DC_VSTART = VERA_BASE + $0B - &ubyte VERA_DC_VSTOP = VERA_BASE + $0C - &ubyte VERA_L0_CONFIG = VERA_BASE + $0D - &ubyte VERA_L0_MAPBASE = VERA_BASE + $0E - &ubyte VERA_L0_TILEBASE = VERA_BASE + $0F - &ubyte VERA_L0_HSCROLL_L = VERA_BASE + $10 - &ubyte VERA_L0_HSCROLL_H = VERA_BASE + $11 - &ubyte VERA_L0_VSCROLL_L = VERA_BASE + $12 - &ubyte VERA_L0_VSCROLL_H = VERA_BASE + $13 - &ubyte VERA_L1_CONFIG = VERA_BASE + $14 - &ubyte VERA_L1_MAPBASE = VERA_BASE + $15 - &ubyte VERA_L1_TILEBASE = VERA_BASE + $16 - &ubyte VERA_L1_HSCROLL_L = VERA_BASE + $17 - &ubyte VERA_L1_HSCROLL_H = VERA_BASE + $18 - &ubyte VERA_L1_VSCROLL_L = VERA_BASE + $19 - &ubyte VERA_L1_VSCROLL_H = VERA_BASE + $1A - &ubyte VERA_AUDIO_CTRL = VERA_BASE + $1B - &ubyte VERA_AUDIO_RATE = VERA_BASE + $1C - &ubyte VERA_AUDIO_DATA = VERA_BASE + $1D - &ubyte VERA_SPI_DATA = VERA_BASE + $1E - &ubyte VERA_SPI_CTRL = VERA_BASE + $1F + &ubyte VERA_ADDR_L = VERA_BASE + $0000 + &ubyte VERA_ADDR_M = VERA_BASE + $0001 + &ubyte VERA_ADDR_H = VERA_BASE + $0002 + &ubyte VERA_DATA0 = VERA_BASE + $0003 + &ubyte VERA_DATA1 = VERA_BASE + $0004 + &ubyte VERA_CTRL = VERA_BASE + $0005 + &ubyte VERA_IEN = VERA_BASE + $0006 + &ubyte VERA_ISR = VERA_BASE + $0007 + &ubyte VERA_IRQ_LINE_L = VERA_BASE + $0008 + &ubyte VERA_DC_VIDEO = VERA_BASE + $0009 + &ubyte VERA_DC_HSCALE = VERA_BASE + $000A + &ubyte VERA_DC_VSCALE = VERA_BASE + $000B + &ubyte VERA_DC_BORDER = VERA_BASE + $000C + &ubyte VERA_DC_HSTART = VERA_BASE + $0009 + &ubyte VERA_DC_HSTOP = VERA_BASE + $000A + &ubyte VERA_DC_VSTART = VERA_BASE + $000B + &ubyte VERA_DC_VSTOP = VERA_BASE + $000C + &ubyte VERA_L0_CONFIG = VERA_BASE + $000D + &ubyte VERA_L0_MAPBASE = VERA_BASE + $000E + &ubyte VERA_L0_TILEBASE = VERA_BASE + $000F + &ubyte VERA_L0_HSCROLL_L = VERA_BASE + $0010 + &ubyte VERA_L0_HSCROLL_H = VERA_BASE + $0011 + &ubyte VERA_L0_VSCROLL_L = VERA_BASE + $0012 + &ubyte VERA_L0_VSCROLL_H = VERA_BASE + $0013 + &ubyte VERA_L1_CONFIG = VERA_BASE + $0014 + &ubyte VERA_L1_MAPBASE = VERA_BASE + $0015 + &ubyte VERA_L1_TILEBASE = VERA_BASE + $0016 + &ubyte VERA_L1_HSCROLL_L = VERA_BASE + $0017 + &ubyte VERA_L1_HSCROLL_H = VERA_BASE + $0018 + &ubyte VERA_L1_VSCROLL_L = VERA_BASE + $0019 + &ubyte VERA_L1_VSCROLL_H = VERA_BASE + $001A + &ubyte VERA_AUDIO_CTRL = VERA_BASE + $001B + &ubyte VERA_AUDIO_RATE = VERA_BASE + $001C + &ubyte VERA_AUDIO_DATA = VERA_BASE + $001D + &ubyte VERA_SPI_DATA = VERA_BASE + $001E + &ubyte VERA_SPI_CTRL = VERA_BASE + $001F ; VERA_PSG_BASE = $1F9C0 ; VERA_PALETTE_BASE = $1FA00 ; VERA_SPRITES_BASE = $1FC00 diff --git a/compiler/src/prog8/optimizer/ConstantFoldingOptimizer.kt b/compiler/src/prog8/optimizer/ConstantFoldingOptimizer.kt index b8668421e..4f7d4c79f 100644 --- a/compiler/src/prog8/optimizer/ConstantFoldingOptimizer.kt +++ b/compiler/src/prog8/optimizer/ConstantFoldingOptimizer.kt @@ -7,178 +7,6 @@ import prog8.ast.expressions.* import prog8.ast.processing.AstWalker import prog8.ast.processing.IAstModification import prog8.ast.statements.* -import prog8.compiler.target.CompilationTarget - - -// First thing to do is replace all constant identifiers with their actual value, -// and the array var initializer values and sizes. -// This is needed because further constant optimizations depend on those. -internal class ConstantIdentifierReplacer(private val program: Program, private val errors: ErrorReporter) : AstWalker() { - private val noModifications = emptyList() - - override fun after(identifier: IdentifierReference, parent: Node): Iterable { - // replace identifiers that refer to const value, with the value itself - // if it's a simple type and if it's not a left hand side variable - if(identifier.parent is AssignTarget) - return noModifications - var forloop = identifier.parent as? ForLoop - if(forloop==null) - forloop = identifier.parent.parent as? ForLoop - if(forloop!=null && identifier===forloop.loopVar) - return noModifications - - val cval = identifier.constValue(program) ?: return noModifications - return when (cval.type) { - in NumericDatatypes -> listOf(IAstModification.ReplaceNode(identifier, NumericLiteralValue(cval.type, cval.number, identifier.position), identifier.parent)) - in PassByReferenceDatatypes -> throw FatalAstException("pass-by-reference type should not be considered a constant") - else -> noModifications - } - } - - override fun before(decl: VarDecl, parent: Node): Iterable { - // the initializer value can't refer to the variable itself (recursive definition) - // TODO: use call graph for this? - if(decl.value?.referencesIdentifiers(decl.name) == true || decl.arraysize?.index?.referencesIdentifiers(decl.name) == true) { - errors.err("recursive var declaration", decl.position) - return noModifications - } - - if(decl.type==VarDeclType.CONST || decl.type==VarDeclType.VAR) { - if(decl.isArray){ - if(decl.arraysize==null) { - // for arrays that have no size specifier (or a non-constant one) attempt to deduce the size - val arrayval = decl.value as? ArrayLiteralValue - if(arrayval!=null) { - return listOf(IAstModification.SetExpression( - { decl.arraysize = ArrayIndex(it, decl.position) }, - NumericLiteralValue.optimalInteger(arrayval.value.size, decl.position), - decl - )) - } - } - else if(decl.arraysize?.constIndex()==null) { - val size = decl.arraysize!!.index.constValue(program) - if(size!=null) { - return listOf(IAstModification.SetExpression( - { decl.arraysize = ArrayIndex(it, decl.position) }, - size, decl - )) - } - } - } - - when(decl.datatype) { - DataType.FLOAT -> { - // vardecl: for scalar float vars, promote constant integer initialization values to floats - val litval = decl.value as? NumericLiteralValue - if (litval!=null && litval.type in IntegerDatatypes) { - val newValue = NumericLiteralValue(DataType.FLOAT, litval.number.toDouble(), litval.position) - return listOf(IAstModification.ReplaceNode(decl.value!!, newValue, decl)) - } - } - DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W -> { - val numericLv = decl.value as? NumericLiteralValue - val rangeExpr = decl.value as? RangeExpr - if(rangeExpr!=null) { - // convert the initializer range expression to an actual array - val declArraySize = decl.arraysize?.constIndex() - if(declArraySize!=null && declArraySize!=rangeExpr.size()) - errors.err("range expression size doesn't match declared array size", decl.value?.position!!) - val constRange = rangeExpr.toConstantIntegerRange() - if(constRange!=null) { - val eltType = rangeExpr.inferType(program).typeOrElse(DataType.UBYTE) - val newValue = if(eltType in ByteDatatypes) { - ArrayLiteralValue(InferredTypes.InferredType.known(decl.datatype), - constRange.map { NumericLiteralValue(eltType, it.toShort(), decl.value!!.position) }.toTypedArray(), - position = decl.value!!.position) - } else { - ArrayLiteralValue(InferredTypes.InferredType.known(decl.datatype), - constRange.map { NumericLiteralValue(eltType, it, decl.value!!.position) }.toTypedArray(), - position = decl.value!!.position) - } - return listOf(IAstModification.ReplaceNode(decl.value!!, newValue, decl)) - } - } - if(numericLv!=null && numericLv.type==DataType.FLOAT) - errors.err("arraysize requires only integers here", numericLv.position) - val size = decl.arraysize?.constIndex() ?: return noModifications - if (rangeExpr==null && numericLv!=null) { - // arraysize initializer is empty or a single int, and we know the size; create the arraysize. - val fillvalue = numericLv.number.toInt() - when(decl.datatype){ - DataType.ARRAY_UB -> { - if(fillvalue !in 0..255) - errors.err("ubyte value overflow", numericLv.position) - } - DataType.ARRAY_B -> { - if(fillvalue !in -128..127) - errors.err("byte value overflow", numericLv.position) - } - DataType.ARRAY_UW -> { - if(fillvalue !in 0..65535) - errors.err("uword value overflow", numericLv.position) - } - DataType.ARRAY_W -> { - if(fillvalue !in -32768..32767) - errors.err("word value overflow", numericLv.position) - } - else -> {} - } - // create the array itself, filled with the fillvalue. - val array = Array(size) {fillvalue}.map { NumericLiteralValue(ArrayElementTypes.getValue(decl.datatype), it, numericLv.position) }.toTypedArray() - val refValue = ArrayLiteralValue(InferredTypes.InferredType.known(decl.datatype), array, position = numericLv.position) - return listOf(IAstModification.ReplaceNode(decl.value!!, refValue, decl)) - } - } - DataType.ARRAY_F -> { - val size = decl.arraysize?.constIndex() ?: return noModifications - val litval = decl.value as? NumericLiteralValue - val rangeExpr = decl.value as? RangeExpr - if(rangeExpr!=null) { - // convert the initializer range expression to an actual array of floats - val declArraySize = decl.arraysize?.constIndex() - if(declArraySize!=null && declArraySize!=rangeExpr.size()) - errors.err("range expression size doesn't match declared array size", decl.value?.position!!) - val constRange = rangeExpr.toConstantIntegerRange() - if(constRange!=null) { - val newValue = ArrayLiteralValue(InferredTypes.InferredType.known(DataType.ARRAY_F), - constRange.map { NumericLiteralValue(DataType.FLOAT, it.toDouble(), decl.value!!.position) }.toTypedArray(), - position = decl.value!!.position) - return listOf(IAstModification.ReplaceNode(decl.value!!, newValue, decl)) - } - } - if(rangeExpr==null && litval!=null) { - // arraysize initializer is a single int, and we know the size. - val fillvalue = litval.number.toDouble() - if (fillvalue < CompilationTarget.instance.machine.FLOAT_MAX_NEGATIVE || fillvalue > CompilationTarget.instance.machine.FLOAT_MAX_POSITIVE) - errors.err("float value overflow", litval.position) - else { - // create the array itself, filled with the fillvalue. - val array = Array(size) {fillvalue}.map { NumericLiteralValue(DataType.FLOAT, it, litval.position) }.toTypedArray() - val refValue = ArrayLiteralValue(InferredTypes.InferredType.known(DataType.ARRAY_F), array, position = litval.position) - return listOf(IAstModification.ReplaceNode(decl.value!!, refValue, decl)) - } - } - } - else -> { - // nothing to do for this type - // this includes strings and structs - } - } - } - - val declValue = decl.value - if(declValue!=null && decl.type==VarDeclType.VAR - && declValue is NumericLiteralValue && !declValue.inferType(program).istype(decl.datatype)) { - // cast the numeric literal to the appropriate datatype of the variable - val cast = declValue.cast(decl.datatype) - if(cast.isValid) - return listOf(IAstModification.ReplaceNode(decl.value!!, cast.valueOrZero(), decl)) - } - - return noModifications - } -} internal class ConstantFoldingOptimizer(private val program: Program) : AstWalker() { diff --git a/compiler/src/prog8/optimizer/ConstantIdentifierReplacer.kt b/compiler/src/prog8/optimizer/ConstantIdentifierReplacer.kt new file mode 100644 index 000000000..d8d915fec --- /dev/null +++ b/compiler/src/prog8/optimizer/ConstantIdentifierReplacer.kt @@ -0,0 +1,192 @@ +package prog8.optimizer + +import prog8.ast.Node +import prog8.ast.Program +import prog8.ast.base.* +import prog8.ast.expressions.* +import prog8.ast.processing.AstWalker +import prog8.ast.processing.IAstModification +import prog8.ast.statements.ArrayIndex +import prog8.ast.statements.AssignTarget +import prog8.ast.statements.ForLoop +import prog8.ast.statements.VarDecl +import prog8.compiler.target.CompilationTarget + +// Fix up the literal value's type to match that of the vardecl +internal class VarConstantValueTypeAdjuster(private val program: Program, private val errors: ErrorReporter) : AstWalker() { + private val noModifications = emptyList() + + override fun after(decl: VarDecl, parent: Node): Iterable { + val declConstValue = decl.value?.constValue(program) + if(declConstValue!=null && (decl.type==VarDeclType.VAR || decl.type==VarDeclType.CONST) + && !declConstValue.inferType(program).istype(decl.datatype)) { + // cast the numeric literal to the appropriate datatype of the variable + val cast = declConstValue.cast(decl.datatype) + if(cast.isValid) + return listOf(IAstModification.ReplaceNode(decl.value!!, cast.valueOrZero(), decl)) + } + return noModifications + } +} + + +// Replace all constant identifiers with their actual value, +// and the array var initializer values and sizes. +// This is needed because further constant optimizations depend on those. +internal class ConstantIdentifierReplacer(private val program: Program, private val errors: ErrorReporter) : AstWalker() { + private val noModifications = emptyList() + + override fun after(identifier: IdentifierReference, parent: Node): Iterable { + // replace identifiers that refer to const value, with the value itself + // if it's a simple type and if it's not a left hand side variable + if(identifier.parent is AssignTarget) + return noModifications + var forloop = identifier.parent as? ForLoop + if(forloop==null) + forloop = identifier.parent.parent as? ForLoop + if(forloop!=null && identifier===forloop.loopVar) + return noModifications + + val cval = identifier.constValue(program) ?: return noModifications + return when (cval.type) { + in NumericDatatypes -> listOf(IAstModification.ReplaceNode(identifier, NumericLiteralValue(cval.type, cval.number, identifier.position), identifier.parent)) + in PassByReferenceDatatypes -> throw FatalAstException("pass-by-reference type should not be considered a constant") + else -> noModifications + } + } + + override fun before(decl: VarDecl, parent: Node): Iterable { + // the initializer value can't refer to the variable itself (recursive definition) + // TODO: use call graph for this? + if(decl.value?.referencesIdentifiers(decl.name) == true || decl.arraysize?.index?.referencesIdentifiers(decl.name) == true) { + errors.err("recursive var declaration", decl.position) + return noModifications + } + + if(decl.type== VarDeclType.CONST || decl.type== VarDeclType.VAR) { + if(decl.isArray){ + if(decl.arraysize==null) { + // for arrays that have no size specifier (or a non-constant one) attempt to deduce the size + val arrayval = decl.value as? ArrayLiteralValue + if(arrayval!=null) { + return listOf(IAstModification.SetExpression( + { decl.arraysize = ArrayIndex(it, decl.position) }, + NumericLiteralValue.optimalInteger(arrayval.value.size, decl.position), + decl + )) + } + } + else if(decl.arraysize?.constIndex()==null) { + val size = decl.arraysize!!.index.constValue(program) + if(size!=null) { + return listOf(IAstModification.SetExpression( + { decl.arraysize = ArrayIndex(it, decl.position) }, + size, decl + )) + } + } + } + + when(decl.datatype) { + DataType.FLOAT -> { + // vardecl: for scalar float vars, promote constant integer initialization values to floats + val litval = decl.value as? NumericLiteralValue + if (litval!=null && litval.type in IntegerDatatypes) { + val newValue = NumericLiteralValue(DataType.FLOAT, litval.number.toDouble(), litval.position) + return listOf(IAstModification.ReplaceNode(decl.value!!, newValue, decl)) + } + } + DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W -> { + val numericLv = decl.value as? NumericLiteralValue + val rangeExpr = decl.value as? RangeExpr + if(rangeExpr!=null) { + // convert the initializer range expression to an actual array + val declArraySize = decl.arraysize?.constIndex() + if(declArraySize!=null && declArraySize!=rangeExpr.size()) + errors.err("range expression size doesn't match declared array size", decl.value?.position!!) + val constRange = rangeExpr.toConstantIntegerRange() + if(constRange!=null) { + val eltType = rangeExpr.inferType(program).typeOrElse(DataType.UBYTE) + val newValue = if(eltType in ByteDatatypes) { + ArrayLiteralValue(InferredTypes.InferredType.known(decl.datatype), + constRange.map { NumericLiteralValue(eltType, it.toShort(), decl.value!!.position) }.toTypedArray(), + position = decl.value!!.position) + } else { + ArrayLiteralValue(InferredTypes.InferredType.known(decl.datatype), + constRange.map { NumericLiteralValue(eltType, it, decl.value!!.position) }.toTypedArray(), + position = decl.value!!.position) + } + return listOf(IAstModification.ReplaceNode(decl.value!!, newValue, decl)) + } + } + if(numericLv!=null && numericLv.type== DataType.FLOAT) + errors.err("arraysize requires only integers here", numericLv.position) + val size = decl.arraysize?.constIndex() ?: return noModifications + if (rangeExpr==null && numericLv!=null) { + // arraysize initializer is empty or a single int, and we know the size; create the arraysize. + val fillvalue = numericLv.number.toInt() + when(decl.datatype){ + DataType.ARRAY_UB -> { + if(fillvalue !in 0..255) + errors.err("ubyte value overflow", numericLv.position) + } + DataType.ARRAY_B -> { + if(fillvalue !in -128..127) + errors.err("byte value overflow", numericLv.position) + } + DataType.ARRAY_UW -> { + if(fillvalue !in 0..65535) + errors.err("uword value overflow", numericLv.position) + } + DataType.ARRAY_W -> { + if(fillvalue !in -32768..32767) + errors.err("word value overflow", numericLv.position) + } + else -> {} + } + // create the array itself, filled with the fillvalue. + val array = Array(size) {fillvalue}.map { NumericLiteralValue(ArrayElementTypes.getValue(decl.datatype), it, numericLv.position) }.toTypedArray() + val refValue = ArrayLiteralValue(InferredTypes.InferredType.known(decl.datatype), array, position = numericLv.position) + return listOf(IAstModification.ReplaceNode(decl.value!!, refValue, decl)) + } + } + DataType.ARRAY_F -> { + val size = decl.arraysize?.constIndex() ?: return noModifications + val litval = decl.value as? NumericLiteralValue + val rangeExpr = decl.value as? RangeExpr + if(rangeExpr!=null) { + // convert the initializer range expression to an actual array of floats + val declArraySize = decl.arraysize?.constIndex() + if(declArraySize!=null && declArraySize!=rangeExpr.size()) + errors.err("range expression size doesn't match declared array size", decl.value?.position!!) + val constRange = rangeExpr.toConstantIntegerRange() + if(constRange!=null) { + val newValue = ArrayLiteralValue(InferredTypes.InferredType.known(DataType.ARRAY_F), + constRange.map { NumericLiteralValue(DataType.FLOAT, it.toDouble(), decl.value!!.position) }.toTypedArray(), + position = decl.value!!.position) + return listOf(IAstModification.ReplaceNode(decl.value!!, newValue, decl)) + } + } + if(rangeExpr==null && litval!=null) { + // arraysize initializer is a single int, and we know the size. + val fillvalue = litval.number.toDouble() + if (fillvalue < CompilationTarget.instance.machine.FLOAT_MAX_NEGATIVE || fillvalue > CompilationTarget.instance.machine.FLOAT_MAX_POSITIVE) + errors.err("float value overflow", litval.position) + else { + // create the array itself, filled with the fillvalue. + val array = Array(size) {fillvalue}.map { NumericLiteralValue(DataType.FLOAT, it, litval.position) }.toTypedArray() + val refValue = ArrayLiteralValue(InferredTypes.InferredType.known(DataType.ARRAY_F), array, position = litval.position) + return listOf(IAstModification.ReplaceNode(decl.value!!, refValue, decl)) + } + } + } + else -> { + // nothing to do for this type + // this includes strings and structs + } + } + } + + return noModifications + } +} diff --git a/compiler/src/prog8/optimizer/Extensions.kt b/compiler/src/prog8/optimizer/Extensions.kt index 72f44e4cb..87800312e 100644 --- a/compiler/src/prog8/optimizer/Extensions.kt +++ b/compiler/src/prog8/optimizer/Extensions.kt @@ -5,20 +5,31 @@ import prog8.ast.base.ErrorReporter internal fun Program.constantFold(errors: ErrorReporter) { - val replacer = ConstantIdentifierReplacer(this, errors) - replacer.visit(this) + val valuetypefixer = VarConstantValueTypeAdjuster(this, errors) + valuetypefixer.visit(this) if(errors.isEmpty()) { - replacer.applyModifications() + valuetypefixer.applyModifications() - val optimizer = ConstantFoldingOptimizer(this) - optimizer.visit(this) - while (errors.isEmpty() && optimizer.applyModifications() > 0) { - optimizer.visit(this) - } - - if(errors.isEmpty()) { - replacer.visit(this) + val replacer = ConstantIdentifierReplacer(this, errors) + replacer.visit(this) + if (errors.isEmpty()) { replacer.applyModifications() + + valuetypefixer.visit(this) + if(errors.isEmpty()) { + valuetypefixer.applyModifications() + + val optimizer = ConstantFoldingOptimizer(this) + optimizer.visit(this) + while (errors.isEmpty() && optimizer.applyModifications() > 0) { + optimizer.visit(this) + } + + if (errors.isEmpty()) { + replacer.visit(this) + replacer.applyModifications() + } + } } } diff --git a/examples/cx16/numbergame.p8 b/examples/cx16/numbergame.p8 index d4903c03e..a99d0f1d6 100644 --- a/examples/cx16/numbergame.p8 +++ b/examples/cx16/numbergame.p8 @@ -5,6 +5,8 @@ ; The classic number guessing game. +; TODO this code is identical to the C64 one except the imports + main { sub start() { diff --git a/examples/cx16/swirl.p8 b/examples/cx16/swirl.p8 index 467db8fb2..ced6ca80e 100644 --- a/examples/cx16/swirl.p8 +++ b/examples/cx16/swirl.p8 @@ -5,7 +5,8 @@ ; TODO this code is identical to the c64 one except the import main { - + const uword screenwidth = txt.DEFAULT_WIDTH + const uword screenheight = txt.DEFAULT_HEIGHT struct Ball { uword anglex uword angley @@ -13,14 +14,11 @@ main { } sub start() { - Ball ball - repeat { - ubyte x = msb(sin8u(msb(ball.anglex)) as uword * txt.DEFAULT_WIDTH) - ubyte y = msb(cos8u(msb(ball.angley)) as uword * txt.DEFAULT_HEIGHT) + ubyte x = msb(sin8u(msb(ball.anglex)) * screenwidth) + ubyte y = msb(cos8u(msb(ball.angley)) * screenheight) txt.setcc(x, y, 81, ball.color) - ball.anglex+=366 ball.angley+=291 ball.color++ diff --git a/examples/numbergame.p8 b/examples/numbergame.p8 index 99132fbfb..8214b7ee8 100644 --- a/examples/numbergame.p8 +++ b/examples/numbergame.p8 @@ -4,6 +4,9 @@ ; The classic number guessing game. +; TODO this code is identical to the commanderx16 one except the imports + + main { sub start() { diff --git a/examples/swirl.p8 b/examples/swirl.p8 index 050f1dee0..8654c2028 100644 --- a/examples/swirl.p8 +++ b/examples/swirl.p8 @@ -4,7 +4,8 @@ ; TODO this code is identical to the commanderx16 one except the import main { - + const uword screenwidth = txt.DEFAULT_WIDTH + const uword screenheight = txt.DEFAULT_HEIGHT struct Ball { uword anglex uword angley @@ -12,14 +13,11 @@ main { } sub start() { - Ball ball - repeat { - ubyte x = msb(sin8u(msb(ball.anglex)) as uword * txt.DEFAULT_WIDTH) - ubyte y = msb(cos8u(msb(ball.angley)) as uword * txt.DEFAULT_HEIGHT) + ubyte x = msb(sin8u(msb(ball.anglex)) * screenwidth) + ubyte y = msb(cos8u(msb(ball.angley)) * screenheight) txt.setcc(x, y, 81, ball.color) - ball.anglex+=366 ball.angley+=291 ball.color++ diff --git a/examples/test.p8 b/examples/test.p8 index 07088e22d..1f1848508 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,7 +1,7 @@ ;%import c64lib ;%import c64graphics ;%import c64textio -;%import c64flt +%import c64flt ;%option enable_floats %target cx16 %import cx16textio @@ -12,38 +12,25 @@ main { sub start() { - const uword cvalue = 155 - const uword cvalue2 = 5555 - uword wvalue = 155 - uword wvalue2 = 5555 + const ubyte cbvalue = 40 + const uword cwvalue = cbvalue + uword wvalue = 40 - ; TODO ALL multiplications below should yield a word result - uword x - ubyte bb = 9 - x = bb * cvalue ; TODO wrong result, must be word - txt.print_uw(x) + ubyte x + ubyte bb = 99 + x = msb(sin8u(bb) * cwvalue) + txt.print_ub(x) txt.chrout('\n') - x = bb * cvalue2 - txt.print_uw(x) + x = msb(sin8u(bb) * wvalue) + txt.print_ub(x) txt.chrout('\n') - x = bb * wvalue - txt.print_uw(x) - txt.chrout('\n') - x = bb * wvalue2 - txt.print_uw(x) txt.chrout('\n') - x = cvalue * bb ; TODO wrong result, must be word - txt.print_uw(x) + x = msb(cwvalue*sin8u(bb)) + txt.print_ub(x) txt.chrout('\n') - x = cvalue2 * bb - txt.print_uw(x) - txt.chrout('\n') - x = wvalue * bb - txt.print_uw(x) - txt.chrout('\n') - x = wvalue2 * bb - txt.print_uw(x) + x = msb(wvalue*sin8u(bb)) + txt.print_ub(x) txt.chrout('\n') } }