added some more division by zero checks

bitwise operator optimizations
This commit is contained in:
Irmen de Jong 2018-09-25 22:16:32 +02:00
parent a2c165839d
commit f85d8edeba
4 changed files with 113 additions and 39 deletions

View File

@ -4,26 +4,15 @@
sub start() -> () {
byte i
float yy
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
yy = flt(height+1.1)
pixely = height / 100
;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
pixely |= 1 ; pixely = pixely | 1
pixely &= 1 ; pixely = pixely & 1
pixely ^= 1 ; pixely = pixely ^ 1
}
}

View File

@ -421,6 +421,17 @@ class AstChecker(private val namespace: INameScope, private val compilerOptions:
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 {
fun err(msg: String) {
checkResult.add(SyntaxError(msg, range.position))

View File

@ -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 {
val error = "cannot divide $left by $right"
return when {
left.asIntegerValue!=null -> when {
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)
}
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)
}
else -> throw ExpressionError(error, left.position)
}
left.floatvalue!=null -> when {
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)
}
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)
}
else -> throw ExpressionError(error, left.position)
@ -241,22 +245,22 @@ class ConstExprEvaluator {
return when {
left.asIntegerValue!=null -> when {
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)
}
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)
}
else -> throw ExpressionError(error, left.position)
}
left.floatvalue!=null -> when {
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)
}
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)
}
else -> throw ExpressionError(error, left.position)
@ -270,22 +274,22 @@ class ConstExprEvaluator {
return when {
left.asIntegerValue!=null -> when {
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)
}
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)
}
else -> throw ExpressionError(error, left.position)
}
left.floatvalue!=null -> when {
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)
}
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)
}
else -> throw ExpressionError(error, left.position)

View File

@ -1,7 +1,6 @@
package prog8.optimizing
import prog8.ast.IAstProcessor
import prog8.ast.INameScope
import prog8.ast.*
/*
todo simplify expression terms:
@ -43,27 +42,98 @@ import prog8.ast.INameScope
X**-2 -> 1.0/X/X
X**-3 -> 1.0/X/X/X
X << 0 -> X
X | 0 -> X
x & 0 -> 0
X ^ 0 -> X
X*Y - X -> X*(Y-1)
-X + A -> A - X
-X - A -> -(X+A)
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: 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 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 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
// @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
}
}