mirror of
https://github.com/irmen/prog8.git
synced 2024-12-25 23:29:55 +00:00
retain type of consts better to avoid precision loss
this also fixed a difference in const calculation where the result could differ if you were using optimzations or not.
This commit is contained in:
parent
aba1a73e28
commit
0d3ad80659
@ -66,7 +66,7 @@ class ConstExprEvaluator {
|
||||
// DataType.WORD -> result = result.toShort().toInt()
|
||||
// else -> { /* keep as it is */ }
|
||||
// }
|
||||
return NumericLiteral.optimalNumeric(result.toDouble(), left.position)
|
||||
return NumericLiteral.optimalNumeric(left.type, null, result.toDouble(), left.position)
|
||||
}
|
||||
|
||||
private fun bitwiseXor(left: NumericLiteral, right: NumericLiteral): NumericLiteral {
|
||||
@ -133,7 +133,7 @@ class ConstExprEvaluator {
|
||||
val error = "cannot add $left and $right"
|
||||
return when (left.type) {
|
||||
in IntegerDatatypes -> when (right.type) {
|
||||
in IntegerDatatypes -> NumericLiteral.optimalInteger(left.number.toInt() + right.number.toInt(), left.position)
|
||||
in IntegerDatatypes -> NumericLiteral.optimalInteger(left.type, right.type, left.number.toInt() + right.number.toInt(), left.position)
|
||||
DataType.FLOAT -> NumericLiteral(DataType.FLOAT, left.number.toInt() + right.number, left.position)
|
||||
else -> throw ExpressionError(error, left.position)
|
||||
}
|
||||
@ -150,7 +150,7 @@ class ConstExprEvaluator {
|
||||
val error = "cannot subtract $left and $right"
|
||||
return when (left.type) {
|
||||
in IntegerDatatypes -> when (right.type) {
|
||||
in IntegerDatatypes -> NumericLiteral.optimalInteger(left.number.toInt() - right.number.toInt(), left.position)
|
||||
in IntegerDatatypes -> NumericLiteral.optimalInteger(left.type, right.type, left.number.toInt() - right.number.toInt(), left.position)
|
||||
DataType.FLOAT -> NumericLiteral(DataType.FLOAT, left.number.toInt() - right.number, left.position)
|
||||
else -> throw ExpressionError(error, left.position)
|
||||
}
|
||||
@ -167,7 +167,7 @@ class ConstExprEvaluator {
|
||||
val error = "cannot multiply ${left.type} and ${right.type}"
|
||||
return when (left.type) {
|
||||
in IntegerDatatypes -> when (right.type) {
|
||||
in IntegerDatatypes -> NumericLiteral.optimalInteger(left.number.toInt() * right.number.toInt(), left.position)
|
||||
in IntegerDatatypes -> NumericLiteral.optimalInteger(left.type, right.type, left.number.toInt() * right.number.toInt(), left.position)
|
||||
DataType.FLOAT -> NumericLiteral(DataType.FLOAT, left.number.toInt() * right.number, left.position)
|
||||
else -> throw ExpressionError(error, left.position)
|
||||
}
|
||||
@ -190,7 +190,7 @@ class ConstExprEvaluator {
|
||||
in IntegerDatatypes -> {
|
||||
if(right.number.toInt()==0) divideByZeroError(right.position)
|
||||
val result: Int = left.number.toInt() / right.number.toInt()
|
||||
NumericLiteral.optimalInteger(result, left.position)
|
||||
NumericLiteral.optimalInteger(left.type, right.type, result, left.position)
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
if(right.number==0.0) divideByZeroError(right.position)
|
||||
@ -219,7 +219,7 @@ class ConstExprEvaluator {
|
||||
in IntegerDatatypes -> when (right.type) {
|
||||
in IntegerDatatypes -> {
|
||||
if(right.number.toInt()==0) divideByZeroError(right.position)
|
||||
NumericLiteral.optimalNumeric(left.number.toInt().toDouble() % right.number.toInt().toDouble(), left.position)
|
||||
NumericLiteral.optimalNumeric(left.type, right.type, left.number.toInt().toDouble() % right.number.toInt().toDouble(), left.position)
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
if(right.number ==0.0) divideByZeroError(right.position)
|
||||
|
@ -33,6 +33,14 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors:
|
||||
}
|
||||
|
||||
override fun after(numLiteral: NumericLiteral, parent: Node): Iterable<IAstModification> {
|
||||
|
||||
if(numLiteral.type==DataType.LONG) {
|
||||
// see if LONG values may be reduced to something smaller
|
||||
val smaller = NumericLiteral.optimalInteger(numLiteral.number.toInt(), numLiteral.position)
|
||||
if(smaller.type!=DataType.LONG)
|
||||
return listOf(IAstModification.ReplaceNode(numLiteral, smaller, parent))
|
||||
}
|
||||
|
||||
if(parent is Assignment) {
|
||||
val iDt = parent.target.inferType(program)
|
||||
if(iDt.isKnown && !iDt.isBool && !iDt.istype(numLiteral.type)) {
|
||||
@ -164,13 +172,13 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors:
|
||||
if(leftconst==null && rightconst!=null && rightconst.number<0.0) {
|
||||
if (expr.operator == "-") {
|
||||
// X - -1 ---> X + 1
|
||||
val posNumber = NumericLiteral.optimalNumeric(-rightconst.number, rightconst.position)
|
||||
val posNumber = NumericLiteral.optimalNumeric(rightconst.type, null, -rightconst.number, rightconst.position)
|
||||
val plusExpr = BinaryExpression(expr.left, "+", posNumber, expr.position)
|
||||
return listOf(IAstModification.ReplaceNode(expr, plusExpr, parent))
|
||||
}
|
||||
else if (expr.operator == "+") {
|
||||
// X + -1 ---> X - 1
|
||||
val posNumber = NumericLiteral.optimalNumeric(-rightconst.number, rightconst.position)
|
||||
val posNumber = NumericLiteral.optimalNumeric(rightconst.type, null, -rightconst.number, rightconst.position)
|
||||
val plusExpr = BinaryExpression(expr.left, "-", posNumber, expr.position)
|
||||
return listOf(IAstModification.ReplaceNode(expr, plusExpr, parent))
|
||||
}
|
||||
@ -384,12 +392,13 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors:
|
||||
val numval = decl.value as? NumericLiteral
|
||||
if(decl.type== VarDeclType.CONST && numval!=null) {
|
||||
val valueDt = numval.inferType(program)
|
||||
if(valueDt istype DataType.LONG) {
|
||||
return noModifications // this is handled in the numericalvalue case
|
||||
}
|
||||
if(valueDt isnot decl.datatype) {
|
||||
if(decl.datatype!=DataType.BOOL || valueDt.isnot(DataType.UBYTE)) {
|
||||
val cast = numval.cast(decl.datatype, true)
|
||||
if (cast.isValid)
|
||||
return listOf(IAstModification.ReplaceNode(numval, cast.valueOrZero(), decl))
|
||||
}
|
||||
val cast = numval.cast(decl.datatype, true)
|
||||
if (cast.isValid)
|
||||
return listOf(IAstModification.ReplaceNode(numval, cast.valueOrZero(), decl))
|
||||
}
|
||||
}
|
||||
return noModifications
|
||||
|
@ -15,6 +15,9 @@
|
||||
;
|
||||
; NOTE: the bitmap screen data is positioned in vram at $0:0000
|
||||
;
|
||||
; NOTE: In the future, these routines might be split out to separate modules, 1 for each screen mode,
|
||||
; so they can be optimized a lot better. There's already a "gfx_lores" module with a few routines for lores 256C mode.
|
||||
;
|
||||
; SCREEN MODE LIST:
|
||||
; mode 0 = reset back to default text mode
|
||||
; mode 1 = bitmap 320 x 240 x 256c (8 bpp)
|
||||
|
@ -233,7 +233,7 @@ math {
|
||||
sub direction(ubyte x1, ubyte y1, ubyte x2, ubyte y2) -> ubyte {
|
||||
; From a pair of positive coordinates, calculate discrete direction between 0 and 23 into A.
|
||||
; This adjusts the atan() result so that the direction N is centered on the angle=N instead of having it as a boundary
|
||||
ubyte angle = atan2(x1, y1, x2, y2) - 256/48
|
||||
ubyte angle = atan2(x1, y1, x2, y2) - (256/48 as ubyte)
|
||||
return 23-lsb(mkword(angle,0) / 2730)
|
||||
}
|
||||
|
||||
|
@ -190,21 +190,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
|
||||
}
|
||||
val cvalue = assignment.value.constValue(program)
|
||||
if(cvalue!=null) {
|
||||
val number = cvalue.number
|
||||
// more complex comparisons if the type is different, but the constant value is compatible
|
||||
if (valuetype == DataType.BYTE && targettype == DataType.UBYTE) {
|
||||
if(number>0)
|
||||
return castLiteral(cvalue)
|
||||
} else if (valuetype == DataType.WORD && targettype == DataType.UWORD) {
|
||||
if(number>0)
|
||||
return castLiteral(cvalue)
|
||||
} else if (valuetype == DataType.UBYTE && targettype == DataType.BYTE) {
|
||||
if(number<0x80)
|
||||
return castLiteral(cvalue)
|
||||
} else if (valuetype == DataType.UWORD && targettype == DataType.WORD) {
|
||||
if(number<0x8000)
|
||||
return castLiteral(cvalue)
|
||||
}
|
||||
return castLiteral(cvalue)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -357,15 +343,72 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
|
||||
}
|
||||
|
||||
override fun after(range: RangeExpression, parent: Node): Iterable<IAstModification> {
|
||||
val fromConst = range.from.constValue(program)
|
||||
val toConst = range.to.constValue(program)
|
||||
|
||||
if(fromConst!=null) {
|
||||
val smaller = NumericLiteral.optimalInteger(fromConst.number.toInt(), fromConst.position)
|
||||
if(fromConst.type.largerThan(smaller.type)) {
|
||||
val toType = range.to.inferType(program)
|
||||
if(toType isnot smaller.type) {
|
||||
if(toConst!=null) {
|
||||
// can we make the to value into the same smaller type?
|
||||
val smallerTo = NumericLiteral.optimalInteger(toConst.number.toInt(), toConst.position)
|
||||
if(smaller.type==smallerTo.type) {
|
||||
val newRange = RangeExpression(smaller, smallerTo, range.step, range.position)
|
||||
return listOf(IAstModification.ReplaceNode(range, newRange, parent))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val newRange = RangeExpression(smaller, range.to, range.step, range.position)
|
||||
return listOf(IAstModification.ReplaceNode(range, newRange, parent))
|
||||
}
|
||||
}
|
||||
}
|
||||
if(toConst!=null) {
|
||||
val smaller = NumericLiteral.optimalInteger(toConst.number.toInt(), toConst.position)
|
||||
if(toConst.type.largerThan(smaller.type)) {
|
||||
val fromType = range.from.inferType(program)
|
||||
if(fromType isnot smaller.type) {
|
||||
if(fromConst!=null) {
|
||||
// can we make the from value into the same smaller type?
|
||||
val smallerFrom = NumericLiteral.optimalInteger(fromConst.number.toInt(), fromConst.position)
|
||||
if(smaller.type==smallerFrom.type) {
|
||||
val newRange = RangeExpression(smallerFrom, smaller, range.step, range.position)
|
||||
return listOf(IAstModification.ReplaceNode(range, newRange, parent))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val newRange = RangeExpression(range.from, smaller, range.step, range.position)
|
||||
return listOf(IAstModification.ReplaceNode(range, newRange, parent))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val modifications = mutableListOf<IAstModification>()
|
||||
val fromDt = range.from.inferType(program).getOr(DataType.UNDEFINED)
|
||||
val toDt = range.to.inferType(program).getOr(DataType.UNDEFINED)
|
||||
val modifications = mutableListOf<IAstModification>()
|
||||
val (commonDt, toChange) = BinaryExpression.commonDatatype(fromDt, toDt, range.from, range.to)
|
||||
if(toChange!=null)
|
||||
addTypecastOrCastedValueModification(modifications, toChange, commonDt, range)
|
||||
|
||||
return modifications
|
||||
}
|
||||
|
||||
override fun after(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable<IAstModification> {
|
||||
val constIdx = arrayIndexedExpression.indexer.constIndex()
|
||||
if(constIdx!=null) {
|
||||
val smaller = NumericLiteral.optimalInteger(constIdx, arrayIndexedExpression.indexer.position)
|
||||
val idxDt = arrayIndexedExpression.indexer.indexExpr.inferType(program).getOr(DataType.UNDEFINED)
|
||||
if(idxDt.largerThan(smaller.type)) {
|
||||
val newIdx = ArrayIndex(smaller, smaller.position)
|
||||
val newIndexer = ArrayIndexedExpression(arrayIndexedExpression.arrayvar, newIdx, arrayIndexedExpression.position)
|
||||
return listOf(IAstModification.ReplaceNode(arrayIndexedExpression, newIndexer, parent))
|
||||
}
|
||||
}
|
||||
return noModifications
|
||||
}
|
||||
|
||||
private fun addTypecastOrCastedValueModification(
|
||||
modifications: MutableList<IAstModification>,
|
||||
expressionToCast: Expression,
|
||||
|
@ -498,6 +498,24 @@ class NumericLiteral(val type: DataType, // only numerical types allowed
|
||||
fun fromBoolean(bool: Boolean, position: Position) =
|
||||
NumericLiteral(DataType.BOOL, if(bool) 1.0 else 0.0, position)
|
||||
|
||||
fun optimalNumeric(origType1: DataType, origType2: DataType?, value: Number, position: Position) : NumericLiteral {
|
||||
val optimal = optimalNumeric(value, position)
|
||||
val largestOrig = if(origType2==null) origType1 else if(origType1.largerThan(origType2)) origType1 else origType2
|
||||
if(largestOrig.largerThan(optimal.type))
|
||||
return NumericLiteral(largestOrig, optimal.number, position)
|
||||
else
|
||||
return optimal
|
||||
}
|
||||
|
||||
fun optimalInteger(origType1: DataType, origType2: DataType?, value: Int, position: Position): NumericLiteral {
|
||||
val optimal = optimalInteger(value, position)
|
||||
val largestOrig = if(origType2==null) origType1 else if(origType1.largerThan(origType2)) origType1 else origType2
|
||||
if(largestOrig.largerThan(optimal.type))
|
||||
return NumericLiteral(largestOrig, optimal.number, position)
|
||||
else
|
||||
return optimal
|
||||
}
|
||||
|
||||
fun optimalNumeric(value: Number, position: Position): NumericLiteral {
|
||||
val digits = floor(value.toDouble()) - value.toDouble()
|
||||
return if(value is Double && digits!=0.0) {
|
||||
@ -1090,7 +1108,16 @@ data class IdentifierReference(val nameInSource: List<String>, override val posi
|
||||
} else if(vardecl.type!= VarDeclType.CONST) {
|
||||
return null
|
||||
}
|
||||
return vardecl.value?.constValue(program)
|
||||
|
||||
// the value of a variable can (temporarily) be a different type as the vardecl itself.
|
||||
// don't return the value if the types don't match yet!
|
||||
val value = vardecl.value?.constValue(program)
|
||||
if(value==null || value.type==vardecl.datatype)
|
||||
return value
|
||||
val optimal = NumericLiteral.optimalNumeric(value.number, value.position)
|
||||
if(optimal.type==vardecl.datatype)
|
||||
return optimal
|
||||
return null
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
|
@ -1,8 +1,10 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
wrong answer if cast as uword is not done in:
|
||||
const uword W=320; uword x1 = ((WIDTH-256)/2 as uword) + math.sin8u(i)
|
||||
Should give type error, but seems to make num a word !?:
|
||||
const uword screenwidth = txt.DEFAULT_WIDTH
|
||||
const ubyte num = (screenwidth-1) / 2
|
||||
|
||||
|
||||
callgraph issue? : if a sub contains another sub and it calls that, the outer sub is never removed even if it doesn't get called?
|
||||
|
||||
|
@ -33,9 +33,9 @@ main {
|
||||
}
|
||||
|
||||
if fastserial
|
||||
diskio.fastmode(3)
|
||||
void diskio.fastmode(3)
|
||||
else
|
||||
diskio.fastmode(0)
|
||||
void diskio.fastmode(0)
|
||||
|
||||
test_save()
|
||||
test_save_blocks()
|
||||
|
@ -3,8 +3,8 @@
|
||||
%zeropage basicsafe
|
||||
|
||||
main {
|
||||
const uword width = 60
|
||||
const uword height = 50
|
||||
const ubyte width = 60
|
||||
const ubyte height = 50
|
||||
const ubyte max_iter = 16
|
||||
|
||||
sub start() {
|
||||
|
@ -6,8 +6,8 @@
|
||||
; Note: this program can be compiled for multiple target systems.
|
||||
|
||||
main {
|
||||
const uword width = 30
|
||||
const uword height = 20
|
||||
const ubyte width = 30
|
||||
const ubyte height = 20
|
||||
const ubyte max_iter = 16
|
||||
|
||||
sub start() {
|
||||
|
@ -1,61 +1,16 @@
|
||||
%import textio
|
||||
%import gfx_lores
|
||||
%import emudbg
|
||||
%zeropage basicsafe
|
||||
%option no_sysinit
|
||||
|
||||
main {
|
||||
const uword WIDTH = 320
|
||||
const ubyte HEIGHT = 240
|
||||
|
||||
sub start() {
|
||||
uword clo, chi
|
||||
|
||||
void cx16.set_screen_mode(128)
|
||||
|
||||
word x1, y1, x2, y2
|
||||
ubyte i
|
||||
ubyte color = 2
|
||||
|
||||
sys.set_irqd()
|
||||
emudbg.reset_cpu_cycles()
|
||||
for i in 0 to 254 step 4 {
|
||||
x1 = ((WIDTH-256)/2 as word) + math.sin8u(i) as word
|
||||
y1 = (HEIGHT-128)/2 + math.cos8u(i)/2
|
||||
x2 = ((WIDTH-64)/2 as word) + math.sin8u(i)/4 as word
|
||||
y2 = (HEIGHT-64)/2 + math.cos8u(i)/4
|
||||
cx16.GRAPH_set_colors(color, 0, 1)
|
||||
cx16.GRAPH_draw_line(x1 as uword, y1 as uword, x2 as uword, y2 as uword)
|
||||
}
|
||||
clo, chi = emudbg.cpu_cycles()
|
||||
sys.clear_irqd()
|
||||
|
||||
txt.print_uwhex(chi, true)
|
||||
txt.print_uwhex(clo, false)
|
||||
uword @shared large = (320*240/8/8)
|
||||
const uword WIDTH=320
|
||||
uword x1 = ((WIDTH-256)/2 as uword) + 200
|
||||
txt.print_uw(x1)
|
||||
txt.nl()
|
||||
|
||||
sys.wait(50)
|
||||
cx16.GRAPH_clear()
|
||||
sys.wait(50)
|
||||
|
||||
sys.set_irqd()
|
||||
emudbg.reset_cpu_cycles()
|
||||
color = 5
|
||||
for i in 0 to 254 step 4 {
|
||||
x1 = ((WIDTH-256)/2 as word) + math.sin8u(i) as word
|
||||
y1 = (HEIGHT-128)/2 + math.cos8u(i)/2
|
||||
x2 = ((WIDTH-64)/2 as word) + math.sin8u(i)/4 as word
|
||||
y2 = (HEIGHT-64)/2 + math.cos8u(i)/4
|
||||
gfx_lores.line(x1 as uword, y1 as ubyte, x2 as uword, y2 as ubyte, color)
|
||||
}
|
||||
clo, chi = emudbg.cpu_cycles()
|
||||
sys.clear_irqd()
|
||||
|
||||
txt.print_uwhex(chi, true)
|
||||
txt.print_uwhex(clo, false)
|
||||
txt.nl()
|
||||
|
||||
|
||||
x1 = ((WIDTH-256)/2) + 200
|
||||
txt.print_uw(x1)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user