mirror of
https://github.com/irmen/prog8.git
synced 2025-02-16 22:30:46 +00:00
added some more division by zero checks
bitwise operator optimizations
This commit is contained in:
parent
a2c165839d
commit
f85d8edeba
@ -4,26 +4,15 @@
|
|||||||
|
|
||||||
sub start() -> () {
|
sub start() -> () {
|
||||||
|
|
||||||
byte i
|
|
||||||
|
|
||||||
float yy
|
|
||||||
word pixely
|
word pixely
|
||||||
word yoffset
|
|
||||||
word height
|
|
||||||
|
|
||||||
|
pixely = A % 0 ; @todo divide 0
|
||||||
|
pixely = A / 0 ; @todo divide 0
|
||||||
|
pixely = A // 0 ; @todo divide 0
|
||||||
|
|
||||||
; @todo expression must not result in float but in word
|
pixely |= 1 ; pixely = pixely | 1
|
||||||
yy = flt(height+1.1)
|
pixely &= 1 ; pixely = pixely & 1
|
||||||
pixely = height / 100
|
pixely ^= 1 ; pixely = pixely ^ 1
|
||||||
;yy = height- 1.1
|
|
||||||
;yy = height*1.1
|
|
||||||
;yy = height/3.6
|
|
||||||
;yy = height//3.6
|
|
||||||
;yy = height**3.6
|
|
||||||
;yy = height%3.6
|
|
||||||
;yy = height/3.6+0.4
|
|
||||||
;yy = 2/height/3.6+0.4
|
|
||||||
;yy = (pixely-yoffset)/height/3.6+0.4
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -421,6 +421,17 @@ class AstChecker(private val namespace: INameScope, private val compilerOptions:
|
|||||||
return super.process(literalValue)
|
return super.process(literalValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun process(expr: BinaryExpression): IExpression {
|
||||||
|
when(expr.operator){
|
||||||
|
"/", "//", "%" -> {
|
||||||
|
val numeric = expr.right.constValue(namespace)?.asNumericValue?.toDouble()
|
||||||
|
if(numeric==0.0)
|
||||||
|
checkResult.add(ExpressionError("division by zero", expr.right.position))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.process(expr)
|
||||||
|
}
|
||||||
|
|
||||||
override fun process(range: RangeExpr): IExpression {
|
override fun process(range: RangeExpr): IExpression {
|
||||||
fun err(msg: String) {
|
fun err(msg: String) {
|
||||||
checkResult.add(SyntaxError(msg, range.position))
|
checkResult.add(SyntaxError(msg, range.position))
|
||||||
|
@ -207,27 +207,31 @@ class ConstExprEvaluator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun divideByZeroError(pos: Position): Unit = throw ExpressionError("division by zero", pos)
|
||||||
|
|
||||||
|
|
||||||
private fun divide(left: LiteralValue, right: LiteralValue): LiteralValue {
|
private fun divide(left: LiteralValue, right: LiteralValue): LiteralValue {
|
||||||
val error = "cannot divide $left by $right"
|
val error = "cannot divide $left by $right"
|
||||||
return when {
|
return when {
|
||||||
left.asIntegerValue!=null -> when {
|
left.asIntegerValue!=null -> when {
|
||||||
right.asIntegerValue!=null -> {
|
right.asIntegerValue!=null -> {
|
||||||
if(right.asIntegerValue==0) throw ExpressionError("attempt to divide by zero", left.position)
|
if(right.asIntegerValue==0) divideByZeroError(right.position)
|
||||||
LiteralValue.optimalNumeric(left.asIntegerValue / right.asIntegerValue, left.position)
|
LiteralValue.optimalNumeric(left.asIntegerValue / right.asIntegerValue, left.position)
|
||||||
}
|
}
|
||||||
right.floatvalue!=null -> {
|
right.floatvalue!=null -> {
|
||||||
if(right.floatvalue==0.0) throw ExpressionError("attempt to divide by zero", left.position)
|
if(right.floatvalue==0.0) divideByZeroError(right.position)
|
||||||
LiteralValue(DataType.FLOAT, floatvalue = left.asIntegerValue / right.floatvalue, position = left.position)
|
LiteralValue(DataType.FLOAT, floatvalue = left.asIntegerValue / right.floatvalue, position = left.position)
|
||||||
}
|
}
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
left.floatvalue!=null -> when {
|
left.floatvalue!=null -> when {
|
||||||
right.asIntegerValue!=null -> {
|
right.asIntegerValue!=null -> {
|
||||||
if(right.asIntegerValue==0) throw ExpressionError("attempt to divide by zero", left.position)
|
if(right.asIntegerValue==0) divideByZeroError(right.position)
|
||||||
LiteralValue(DataType.FLOAT, floatvalue = left.floatvalue / right.asIntegerValue, position = left.position)
|
LiteralValue(DataType.FLOAT, floatvalue = left.floatvalue / right.asIntegerValue, position = left.position)
|
||||||
}
|
}
|
||||||
right.floatvalue!=null -> {
|
right.floatvalue!=null -> {
|
||||||
if(right.floatvalue==0.0) throw ExpressionError("attempt to divide by zero", left.position)
|
if(right.floatvalue==0.0) divideByZeroError(right.position)
|
||||||
LiteralValue(DataType.FLOAT, floatvalue = left.floatvalue / right.floatvalue, position = left.position)
|
LiteralValue(DataType.FLOAT, floatvalue = left.floatvalue / right.floatvalue, position = left.position)
|
||||||
}
|
}
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
@ -241,22 +245,22 @@ class ConstExprEvaluator {
|
|||||||
return when {
|
return when {
|
||||||
left.asIntegerValue!=null -> when {
|
left.asIntegerValue!=null -> when {
|
||||||
right.asIntegerValue!=null -> {
|
right.asIntegerValue!=null -> {
|
||||||
if(right.asIntegerValue==0) throw ExpressionError("attempt to divide by zero", left.position)
|
if(right.asIntegerValue==0) divideByZeroError(right.position)
|
||||||
LiteralValue.optimalInteger(left.asIntegerValue / right.asIntegerValue, left.position)
|
LiteralValue.optimalInteger(left.asIntegerValue / right.asIntegerValue, left.position)
|
||||||
}
|
}
|
||||||
right.floatvalue!=null -> {
|
right.floatvalue!=null -> {
|
||||||
if(right.floatvalue==0.0) throw ExpressionError("attempt to divide by zero", left.position)
|
if(right.floatvalue==0.0) divideByZeroError(right.position)
|
||||||
LiteralValue.optimalInteger(left.asIntegerValue / right.floatvalue, left.position)
|
LiteralValue.optimalInteger(left.asIntegerValue / right.floatvalue, left.position)
|
||||||
}
|
}
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
left.floatvalue!=null -> when {
|
left.floatvalue!=null -> when {
|
||||||
right.asIntegerValue!=null -> {
|
right.asIntegerValue!=null -> {
|
||||||
if(right.asIntegerValue==0) throw ExpressionError("attempt to divide by zero", left.position)
|
if(right.asIntegerValue==0) divideByZeroError(right.position)
|
||||||
LiteralValue.optimalInteger(left.floatvalue / right.asIntegerValue, left.position)
|
LiteralValue.optimalInteger(left.floatvalue / right.asIntegerValue, left.position)
|
||||||
}
|
}
|
||||||
right.floatvalue!=null -> {
|
right.floatvalue!=null -> {
|
||||||
if(right.floatvalue==0.0) throw ExpressionError("attempt to divide by zero", left.position)
|
if(right.floatvalue==0.0) divideByZeroError(right.position)
|
||||||
LiteralValue.optimalInteger(left.floatvalue / right.floatvalue, left.position)
|
LiteralValue.optimalInteger(left.floatvalue / right.floatvalue, left.position)
|
||||||
}
|
}
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
@ -270,22 +274,22 @@ class ConstExprEvaluator {
|
|||||||
return when {
|
return when {
|
||||||
left.asIntegerValue!=null -> when {
|
left.asIntegerValue!=null -> when {
|
||||||
right.asIntegerValue!=null -> {
|
right.asIntegerValue!=null -> {
|
||||||
if(right.asIntegerValue==0) throw ExpressionError("attempt to divide by zero", left.position)
|
if(right.asIntegerValue==0) divideByZeroError(right.position)
|
||||||
LiteralValue.optimalNumeric(left.asIntegerValue % right.asIntegerValue, left.position)
|
LiteralValue.optimalNumeric(left.asIntegerValue % right.asIntegerValue, left.position)
|
||||||
}
|
}
|
||||||
right.floatvalue!=null -> {
|
right.floatvalue!=null -> {
|
||||||
if(right.floatvalue==0.0) throw ExpressionError("attempt to divide by zero", left.position)
|
if(right.floatvalue==0.0) divideByZeroError(right.position)
|
||||||
LiteralValue(DataType.FLOAT, floatvalue = left.asIntegerValue % right.floatvalue, position = left.position)
|
LiteralValue(DataType.FLOAT, floatvalue = left.asIntegerValue % right.floatvalue, position = left.position)
|
||||||
}
|
}
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
left.floatvalue!=null -> when {
|
left.floatvalue!=null -> when {
|
||||||
right.asIntegerValue!=null -> {
|
right.asIntegerValue!=null -> {
|
||||||
if(right.asIntegerValue==0) throw ExpressionError("attempt to divide by zero", left.position)
|
if(right.asIntegerValue==0) divideByZeroError(right.position)
|
||||||
LiteralValue(DataType.FLOAT, floatvalue = left.floatvalue % right.asIntegerValue, position = left.position)
|
LiteralValue(DataType.FLOAT, floatvalue = left.floatvalue % right.asIntegerValue, position = left.position)
|
||||||
}
|
}
|
||||||
right.floatvalue!=null -> {
|
right.floatvalue!=null -> {
|
||||||
if(right.floatvalue==0.0) throw ExpressionError("attempt to divide by zero", left.position)
|
if(right.floatvalue==0.0) divideByZeroError(right.position)
|
||||||
LiteralValue(DataType.FLOAT, floatvalue = left.floatvalue % right.floatvalue, position = left.position)
|
LiteralValue(DataType.FLOAT, floatvalue = left.floatvalue % right.floatvalue, position = left.position)
|
||||||
}
|
}
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package prog8.optimizing
|
package prog8.optimizing
|
||||||
|
|
||||||
import prog8.ast.IAstProcessor
|
import prog8.ast.*
|
||||||
import prog8.ast.INameScope
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
todo simplify expression terms:
|
todo simplify expression terms:
|
||||||
@ -43,27 +42,98 @@ import prog8.ast.INameScope
|
|||||||
X**-2 -> 1.0/X/X
|
X**-2 -> 1.0/X/X
|
||||||
X**-3 -> 1.0/X/X/X
|
X**-3 -> 1.0/X/X/X
|
||||||
X << 0 -> X
|
X << 0 -> X
|
||||||
X | 0 -> X
|
|
||||||
x & 0 -> 0
|
|
||||||
X ^ 0 -> X
|
|
||||||
X*Y - X -> X*(Y-1)
|
X*Y - X -> X*(Y-1)
|
||||||
-X + A -> A - X
|
-X + A -> A - X
|
||||||
-X - A -> -(X+A)
|
-X - A -> -(X+A)
|
||||||
X % 1 -> constant 0 (if X is byte/word)
|
X % 1 -> constant 0 (if X is byte/word)
|
||||||
X % 2 -> X and 255 (byte) X and 65535 (word)
|
X % 2 -> X and 1 (if X is byte/word)
|
||||||
|
|
||||||
|
|
||||||
todo expression optimization: remove redundant builtin function calls
|
todo expression optimization: remove redundant builtin function calls
|
||||||
todo expression optimization: simplify logical expression when a term makes it always true or false (1 or 0)
|
|
||||||
todo expression optimization: optimize some simple multiplications into shifts (A*8 -> A<<3, A/4 -> A>>2)
|
todo expression optimization: optimize some simple multiplications into shifts (A*8 -> A<<3, A/4 -> A>>2)
|
||||||
todo optimize addition with self into shift 1 (A+=A -> A<<=1)
|
todo optimize addition with self into shift 1 (A+=A -> A<<=1)
|
||||||
todo expression optimization: common (sub) expression elimination (turn common expressions into single subroutine call)
|
todo expression optimization: common (sub) expression elimination (turn common expressions into single subroutine call)
|
||||||
todo remove or simplify logical aug assigns like A |= 0, A |= true, A |= false (or perhaps turn them into byte values first?)
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class SimplifyExpressions(namespace: INameScope) : IAstProcessor {
|
class SimplifyExpressions(private val namespace: INameScope) : IAstProcessor {
|
||||||
var optimizationsDone: Int = 0
|
var optimizationsDone: Int = 0
|
||||||
|
|
||||||
// @todo build this optimizer
|
override fun process(assignment: Assignment): IStatement {
|
||||||
|
if(assignment.aug_op!=null) {
|
||||||
|
throw AstException("augmented assignments should have been converted to normal assignments before this optimizer")
|
||||||
|
}
|
||||||
|
return super.process(assignment)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun process(expr: BinaryExpression): IExpression {
|
||||||
|
super.process(expr)
|
||||||
|
val leftVal = expr.left.constValue(namespace)
|
||||||
|
val rightVal = expr.right.constValue(namespace)
|
||||||
|
val constTrue = LiteralValue.fromBoolean(true, expr.position)
|
||||||
|
val constFalse = LiteralValue.fromBoolean(false, expr.position)
|
||||||
|
|
||||||
|
// simplify logical expressions when a term is constant and determines the outcome
|
||||||
|
when(expr.operator) {
|
||||||
|
"or" -> {
|
||||||
|
if((leftVal!=null && leftVal.asBooleanValue) || (rightVal!=null && rightVal.asBooleanValue)) {
|
||||||
|
optimizationsDone++
|
||||||
|
return constTrue
|
||||||
|
}
|
||||||
|
if(leftVal!=null && !leftVal.asBooleanValue) {
|
||||||
|
optimizationsDone++
|
||||||
|
return expr.right
|
||||||
|
}
|
||||||
|
if(rightVal!=null && !rightVal.asBooleanValue) {
|
||||||
|
optimizationsDone++
|
||||||
|
return expr.left
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"and" -> {
|
||||||
|
if((leftVal!=null && !leftVal.asBooleanValue) || (rightVal!=null && !rightVal.asBooleanValue)) {
|
||||||
|
optimizationsDone++
|
||||||
|
return constFalse
|
||||||
|
}
|
||||||
|
if(leftVal!=null && leftVal.asBooleanValue) {
|
||||||
|
optimizationsDone++
|
||||||
|
return expr.right
|
||||||
|
}
|
||||||
|
if(rightVal!=null && rightVal.asBooleanValue) {
|
||||||
|
optimizationsDone++
|
||||||
|
return expr.left
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"xor" -> {
|
||||||
|
if(leftVal!=null && !leftVal.asBooleanValue) {
|
||||||
|
optimizationsDone++
|
||||||
|
return expr.right
|
||||||
|
}
|
||||||
|
if(rightVal!=null && !rightVal.asBooleanValue) {
|
||||||
|
optimizationsDone++
|
||||||
|
return expr.left
|
||||||
|
}
|
||||||
|
if(leftVal!=null && leftVal.asBooleanValue) {
|
||||||
|
optimizationsDone++
|
||||||
|
return PrefixExpression("not", expr.right, expr.right.position)
|
||||||
|
}
|
||||||
|
if(rightVal!=null && rightVal.asBooleanValue) {
|
||||||
|
optimizationsDone++
|
||||||
|
return PrefixExpression("not", expr.left, expr.left.position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"|", "^" -> {
|
||||||
|
if(leftVal!=null && !leftVal.asBooleanValue)
|
||||||
|
return expr.right
|
||||||
|
if(rightVal!=null && !rightVal.asBooleanValue)
|
||||||
|
return expr.left
|
||||||
|
}
|
||||||
|
"&" -> {
|
||||||
|
if(leftVal!=null && !leftVal.asBooleanValue)
|
||||||
|
return constFalse
|
||||||
|
if(rightVal!=null && !rightVal.asBooleanValue)
|
||||||
|
return constFalse
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return expr
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user