optimizers

This commit is contained in:
Irmen de Jong 2024-02-05 00:53:18 +01:00
parent 32afcbfe42
commit 6b87cbb703
10 changed files with 96 additions and 104 deletions

View File

@ -7,6 +7,7 @@ import prog8.ast.expressions.FunctionCallExpression
import prog8.ast.expressions.NumericLiteral import prog8.ast.expressions.NumericLiteral
import prog8.code.core.DataType import prog8.code.core.DataType
import prog8.code.core.IntegerDatatypes import prog8.code.core.IntegerDatatypes
import prog8.code.core.IntegerDatatypesWithBoolean
import prog8.code.core.Position import prog8.code.core.Position
import kotlin.math.* import kotlin.math.*
@ -69,15 +70,15 @@ class ConstExprEvaluator {
} }
private fun bitwiseXor(left: NumericLiteral, right: NumericLiteral): NumericLiteral { private fun bitwiseXor(left: NumericLiteral, right: NumericLiteral): NumericLiteral {
if(left.type== DataType.UBYTE) { if(left.type==DataType.UBYTE || left.type==DataType.BOOL) {
if(right.type in IntegerDatatypes) { if(right.type in IntegerDatatypesWithBoolean) {
return NumericLiteral(DataType.UBYTE, (left.number.toInt() xor (right.number.toInt() and 255)).toDouble(), left.position) return NumericLiteral(DataType.UBYTE, (left.number.toInt() xor (right.number.toInt() and 255)).toDouble(), left.position)
} }
} else if(left.type== DataType.UWORD) { } else if(left.type==DataType.UWORD) {
if(right.type in IntegerDatatypes) { if(right.type in IntegerDatatypes) {
return NumericLiteral(DataType.UWORD, (left.number.toInt() xor right.number.toInt() and 65535).toDouble(), left.position) return NumericLiteral(DataType.UWORD, (left.number.toInt() xor right.number.toInt() and 65535).toDouble(), left.position)
} }
} else if(left.type== DataType.LONG) { } else if(left.type==DataType.LONG) {
if(right.type in IntegerDatatypes) { if(right.type in IntegerDatatypes) {
return NumericLiteral.optimalNumeric((left.number.toInt() xor right.number.toInt()).toDouble(), left.position) return NumericLiteral.optimalNumeric((left.number.toInt() xor right.number.toInt()).toDouble(), left.position)
} }
@ -86,15 +87,15 @@ class ConstExprEvaluator {
} }
private fun bitwiseOr(left: NumericLiteral, right: NumericLiteral): NumericLiteral { private fun bitwiseOr(left: NumericLiteral, right: NumericLiteral): NumericLiteral {
if(left.type== DataType.UBYTE) { if(left.type==DataType.UBYTE || left.type==DataType.BOOL) {
if(right.type in IntegerDatatypes) { if(right.type in IntegerDatatypesWithBoolean) {
return NumericLiteral(DataType.UBYTE, (left.number.toInt() or (right.number.toInt() and 255)).toDouble(), left.position) return NumericLiteral(DataType.UBYTE, (left.number.toInt() or (right.number.toInt() and 255)).toDouble(), left.position)
} }
} else if(left.type== DataType.UWORD) { } else if(left.type==DataType.UWORD) {
if(right.type in IntegerDatatypes) { if(right.type in IntegerDatatypes) {
return NumericLiteral(DataType.UWORD, (left.number.toInt() or right.number.toInt() and 65535).toDouble(), left.position) return NumericLiteral(DataType.UWORD, (left.number.toInt() or right.number.toInt() and 65535).toDouble(), left.position)
} }
} else if(left.type== DataType.LONG) { } else if(left.type==DataType.LONG) {
if(right.type in IntegerDatatypes) { if(right.type in IntegerDatatypes) {
return NumericLiteral.optimalNumeric((left.number.toInt() or right.number.toInt()).toDouble(), left.position) return NumericLiteral.optimalNumeric((left.number.toInt() or right.number.toInt()).toDouble(), left.position)
} }
@ -103,11 +104,11 @@ class ConstExprEvaluator {
} }
private fun bitwiseAnd(left: NumericLiteral, right: NumericLiteral): NumericLiteral { private fun bitwiseAnd(left: NumericLiteral, right: NumericLiteral): NumericLiteral {
if(left.type== DataType.UBYTE) { if(left.type==DataType.UBYTE || left.type==DataType.BOOL) {
if(right.type in IntegerDatatypes) { if(right.type in IntegerDatatypesWithBoolean) {
return NumericLiteral(DataType.UBYTE, (left.number.toInt() and (right.number.toInt() and 255)).toDouble(), left.position) return NumericLiteral(DataType.UBYTE, (left.number.toInt() and (right.number.toInt() and 255)).toDouble(), left.position)
} }
} else if(left.type== DataType.UWORD) { } else if(left.type==DataType.UWORD) {
if(right.type in IntegerDatatypes) { if(right.type in IntegerDatatypes) {
return NumericLiteral(DataType.UWORD, (left.number.toInt() and right.number.toInt() and 65535).toDouble(), left.position) return NumericLiteral(DataType.UWORD, (left.number.toInt() and right.number.toInt() and 65535).toDouble(), left.position)
} }

View File

@ -36,9 +36,9 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors:
if(parent is Assignment) { if(parent is Assignment) {
val iDt = parent.target.inferType(program) val iDt = parent.target.inferType(program)
if(iDt.isKnown && !iDt.isBool && !iDt.istype(numLiteral.type)) { if(iDt.isKnown && !iDt.isBool && !iDt.istype(numLiteral.type)) {
val casted = numLiteral.cast(iDt.getOr(DataType.UNDEFINED)) val casted = numLiteral.cast(iDt.getOr(DataType.UNDEFINED), true)
if(casted.isValid) { if(casted.isValid) {
return listOf(IAstModification.ReplaceNode(numLiteral, casted.value!!, parent)) return listOf(IAstModification.ReplaceNode(numLiteral, casted.valueOrZero(), parent))
} }
} }
} }
@ -313,23 +313,23 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors:
override fun after(forLoop: ForLoop, parent: Node): Iterable<IAstModification> { override fun after(forLoop: ForLoop, parent: Node): Iterable<IAstModification> {
fun adjustRangeDt(rangeFrom: NumericLiteral, targetDt: DataType, rangeTo: NumericLiteral, stepLiteral: NumericLiteral?, range: RangeExpression): RangeExpression? { fun adjustRangeDt(rangeFrom: NumericLiteral, targetDt: DataType, rangeTo: NumericLiteral, stepLiteral: NumericLiteral?, range: RangeExpression): RangeExpression? {
val fromCast = rangeFrom.cast(targetDt) val fromCast = rangeFrom.cast(targetDt, true)
val toCast = rangeTo.cast(targetDt) val toCast = rangeTo.cast(targetDt, true)
if(!fromCast.isValid || !toCast.isValid) if(!fromCast.isValid || !toCast.isValid)
return null return null
val newStep = val newStep =
if(stepLiteral!=null) { if(stepLiteral!=null) {
val stepCast = stepLiteral.cast(targetDt) val stepCast = stepLiteral.cast(targetDt, true)
if(stepCast.isValid) if(stepCast.isValid)
stepCast.value!! stepCast.valueOrZero()
else else
range.step range.step
} else { } else {
range.step range.step
} }
return RangeExpression(fromCast.value!!, toCast.value!!, newStep, range.position) return RangeExpression(fromCast.valueOrZero(), toCast.valueOrZero(), newStep, range.position)
} }
// adjust the datatype of a range expression in for loops to the loop variable. // adjust the datatype of a range expression in for loops to the loop variable.
@ -386,9 +386,9 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors:
val valueDt = numval.inferType(program) val valueDt = numval.inferType(program)
if(valueDt isnot decl.datatype) { if(valueDt isnot decl.datatype) {
if(decl.datatype!=DataType.BOOL || valueDt.isnot(DataType.UBYTE)) { if(decl.datatype!=DataType.BOOL || valueDt.isnot(DataType.UBYTE)) {
val cast = numval.cast(decl.datatype) val cast = numval.cast(decl.datatype, true)
if (cast.isValid) if (cast.isValid)
return listOf(IAstModification.ReplaceNode(numval, cast.value!!, decl)) return listOf(IAstModification.ReplaceNode(numval, cast.valueOrZero(), decl))
} }
} }
} }

View File

@ -35,12 +35,12 @@ class VarConstantValueTypeAdjuster(
// avoid silent float roundings // avoid silent float roundings
if(decl.datatype in IntegerDatatypes && declConstValue.type == DataType.FLOAT) { if(decl.datatype in IntegerDatatypes && declConstValue.type == DataType.FLOAT) {
errors.err("refused truncating of float to avoid loss of precision", decl.value!!.position) errors.err("refused truncating of float to avoid loss of precision", decl.value!!.position)
} else { } else if(decl.datatype!=DataType.BOOL) {
// cast the numeric literal to the appropriate datatype of the variable // cast the numeric literal to the appropriate datatype of the variable if it's not boolean
declConstValue.linkParents(decl) declConstValue.linkParents(decl)
val cast = declConstValue.cast(decl.datatype) val cast = declConstValue.cast(decl.datatype, true)
if (cast.isValid) if (cast.isValid)
return listOf(IAstModification.ReplaceNode(decl.value!!, cast.value!!, decl)) return listOf(IAstModification.ReplaceNode(decl.value!!, cast.valueOrZero(), decl))
} }
} }
} catch (x: UndefinedSymbolError) { } catch (x: UndefinedSymbolError) {
@ -292,7 +292,7 @@ internal class ConstantIdentifierReplacer(private val program: Program, private
return noModifications return noModifications
val dt = identifier.inferType(program) val dt = identifier.inferType(program)
if(!dt.isKnown || !dt.isNumeric) if(!dt.isKnown || !dt.isNumeric && !dt.isBool)
return noModifications return noModifications
try { try {
@ -313,7 +313,7 @@ internal class ConstantIdentifierReplacer(private val program: Program, private
} }
} }
when (cval.type) { when (cval.type) {
in NumericDatatypes -> { in NumericDatatypesWithBoolean -> {
if(parent is AddressOf) if(parent is AddressOf)
return noModifications // cannot replace the identifier INSIDE the addr-of here, let's do it later. return noModifications // cannot replace the identifier INSIDE the addr-of here, let's do it later.
return listOf( return listOf(
@ -369,7 +369,7 @@ internal class ConstantIdentifierReplacer(private val program: Program, private
DataType.FLOAT -> { DataType.FLOAT -> {
// vardecl: for scalar float vars, promote constant integer initialization values to floats // vardecl: for scalar float vars, promote constant integer initialization values to floats
val litval = decl.value as? NumericLiteral val litval = decl.value as? NumericLiteral
if (litval!=null && litval.type in IntegerDatatypes) { if (litval!=null && litval.type in IntegerDatatypesWithBoolean) {
val newValue = NumericLiteral(DataType.FLOAT, litval.number, litval.position) val newValue = NumericLiteral(DataType.FLOAT, litval.number, litval.position)
return listOf(IAstModification.ReplaceNode(decl.value!!, newValue, decl)) return listOf(IAstModification.ReplaceNode(decl.value!!, newValue, decl))
} }
@ -470,12 +470,11 @@ internal class ConstantIdentifierReplacer(private val program: Program, private
val numericLv = decl.value as? NumericLiteral val numericLv = decl.value as? NumericLiteral
val size = decl.arraysize?.constIndex() ?: return null val size = decl.arraysize?.constIndex() ?: return null
if(rangeExpr==null && numericLv!=null) { if(rangeExpr==null && numericLv!=null) {
// arraysize initializer is a single int, and we know the size. // arraysize initializer is a single int, and we know the array size.
val fillvalue = numericLv.number val fillvalue = numericLv.number
if (fillvalue < compTarget.machine.FLOAT_MAX_NEGATIVE || fillvalue > compTarget.machine.FLOAT_MAX_POSITIVE) if (fillvalue < compTarget.machine.FLOAT_MAX_NEGATIVE || fillvalue > compTarget.machine.FLOAT_MAX_POSITIVE)
errors.err("float value overflow", numericLv.position) errors.err("float value overflow", numericLv.position)
else { else {
// create the array itself, filled with the fillvalue.
val array = Array(size) {fillvalue}.map { NumericLiteral(DataType.FLOAT, it, numericLv.position) }.toTypedArray<Expression>() val array = Array(size) {fillvalue}.map { NumericLiteral(DataType.FLOAT, it, numericLv.position) }.toTypedArray<Expression>()
return ArrayLiteral(InferredTypes.InferredType.known(DataType.ARRAY_F), array, position = numericLv.position) return ArrayLiteral(InferredTypes.InferredType.known(DataType.ARRAY_F), array, position = numericLv.position)
} }
@ -485,9 +484,12 @@ internal class ConstantIdentifierReplacer(private val program: Program, private
val numericLv = decl.value as? NumericLiteral val numericLv = decl.value as? NumericLiteral
val size = decl.arraysize?.constIndex() ?: return null val size = decl.arraysize?.constIndex() ?: return null
if(numericLv!=null) { if(numericLv!=null) {
// arraysize initializer is a single int, and we know the size. // arraysize initializer is a single value, and we know the array size.
val fillvalue = if(numericLv.number==0.0) 0.0 else 1.0 if(numericLv.type!=DataType.BOOL) {
val array = Array(size) {fillvalue}.map { NumericLiteral(DataType.UBYTE, fillvalue, numericLv.position) }.toTypedArray<Expression>() errors.err("initializer value is not a boolean", numericLv.position)
return null
}
val array = Array(size) {numericLv.number}.map { NumericLiteral(DataType.BOOL, it, numericLv.position) }.toTypedArray<Expression>()
return ArrayLiteral(InferredTypes.InferredType.known(DataType.ARRAY_BOOL), array, position = numericLv.position) return ArrayLiteral(InferredTypes.InferredType.known(DataType.ARRAY_BOOL), array, position = numericLv.position)
} }
} }

View File

@ -19,9 +19,7 @@ import kotlin.math.pow
// TODO add more peephole expression optimizations? Investigate what optimizations binaryen has? // TODO add more peephole expression optimizations? Investigate what optimizations binaryen has?
class ExpressionSimplifier(private val program: Program, class ExpressionSimplifier(private val program: Program, private val errors: IErrorReporter) : AstWalker() {
private val errors: IErrorReporter,
private val compTarget: ICompilationTarget) : AstWalker() {
private val powersOfTwo = (1..16).map { (2.0).pow(it) }.toSet() private val powersOfTwo = (1..16).map { (2.0).pow(it) }.toSet()
private val negativePowersOfTwo = powersOfTwo.map { -it }.toSet() private val negativePowersOfTwo = powersOfTwo.map { -it }.toSet()
@ -31,9 +29,9 @@ class ExpressionSimplifier(private val program: Program,
// try to statically convert a literal value into one of the desired type // try to statically convert a literal value into one of the desired type
val literal = typecast.expression as? NumericLiteral val literal = typecast.expression as? NumericLiteral
if (literal != null) { if (literal != null) {
val newLiteral = literal.cast(typecast.type) val newLiteral = literal.cast(typecast.type, typecast.implicit)
if (newLiteral.isValid && newLiteral.value!! !== literal) { if (newLiteral.isValid && newLiteral.valueOrZero() !== literal) {
mods += IAstModification.ReplaceNode(typecast, newLiteral.value!!, parent) mods += IAstModification.ReplaceNode(typecast, newLiteral.valueOrZero(), parent)
} }
} }
@ -255,26 +253,51 @@ class ExpressionSimplifier(private val program: Program,
} }
} }
// boolvar & 1 --> boolvar
// boolvar & 2 --> false
if(expr.operator=="&" && rightDt in IntegerDatatypes && (leftDt == DataType.BOOL || (expr.left as? TypecastExpression)?.expression?.inferType(program)?.istype(DataType.BOOL)==true)) {
if(rightVal?.number==1.0) {
return listOf(IAstModification.ReplaceNode(expr, expr.left, parent))
} else if(rightVal?.number!=null && (rightVal.number.toInt() and 1)==0) {
return listOf(IAstModification.ReplaceNode(expr, NumericLiteral.fromBoolean(false, expr.position), parent))
}
}
if(leftDt==DataType.BOOL) { if(leftDt==DataType.BOOL) {
// optimize boolean constant comparisons // optimize boolean constant comparisons
// if(expr.operator=="==" && rightVal?.number==0.0)
// return listOf(IAstModification.ReplaceNode(expr, PrefixExpression("not", expr.left, expr.position), parent))
// if(expr.operator=="!=" && rightVal?.number==1.0)
// return listOf(IAstModification.ReplaceNode(expr, PrefixExpression("not", expr.left, expr.position), parent))
if(expr.operator=="==" && rightVal?.number==1.0) if(expr.operator=="==" && rightVal?.number==1.0)
return listOf(IAstModification.ReplaceNode(expr, expr.left, parent)) return listOf(IAstModification.ReplaceNode(expr, expr.left, parent))
if(expr.operator=="!=" && rightVal?.number==0.0) if(expr.operator=="!=" && rightVal?.number==0.0)
return listOf(IAstModification.ReplaceNode(expr, expr.left, parent)) return listOf(IAstModification.ReplaceNode(expr, expr.left, parent))
if(rightDt==DataType.BOOL && expr.operator in arrayOf("and", "or", "xor")) {
if(leftVal!=null) {
val result = if(leftVal.asBooleanValue) {
when(expr.operator) {
"and" -> expr.right
"or" -> NumericLiteral.fromBoolean(true, expr.position)
"xor" -> PrefixExpression("not", expr.right, expr.position)
else -> throw FatalAstException("weird op")
}
} else {
when(expr.operator) {
"and" -> NumericLiteral.fromBoolean(false, expr.position)
"or" -> expr.right
"xor" -> expr.right
else -> throw FatalAstException("weird op")
}
}
return listOf(IAstModification.ReplaceNode(expr, result, parent))
}
else if(rightVal!=null) {
val result = if(rightVal.asBooleanValue) {
when(expr.operator) {
"and" -> expr.left
"or" -> NumericLiteral.fromBoolean(true, expr.position)
"xor" -> PrefixExpression("not", expr.left, expr.position)
else -> throw FatalAstException("weird op")
}
} else {
when(expr.operator) {
"and" -> NumericLiteral.fromBoolean(false, expr.position)
"or" -> expr.left
"xor" -> expr.left
else -> throw FatalAstException("weird op")
}
}
return listOf(IAstModification.ReplaceNode(expr, result, parent))
}
}
} }
// simplify when a term is constant and directly determines the outcome // simplify when a term is constant and directly determines the outcome
@ -387,7 +410,6 @@ class ExpressionSimplifier(private val program: Program,
return noModifications return noModifications
} }
private fun applyAbsorptionLaws(expr: BinaryExpression): Expression? { private fun applyAbsorptionLaws(expr: BinaryExpression): Expression? {
val rightB = expr.right as? BinaryExpression val rightB = expr.right as? BinaryExpression
if(rightB!=null) { if(rightB!=null) {

View File

@ -3,7 +3,6 @@ package prog8.optimizer
import prog8.ast.IBuiltinFunctions import prog8.ast.IBuiltinFunctions
import prog8.ast.Program import prog8.ast.Program
import prog8.code.core.CompilationOptions import prog8.code.core.CompilationOptions
import prog8.code.core.ICompilationTarget
import prog8.code.core.IErrorReporter import prog8.code.core.IErrorReporter
@ -60,8 +59,8 @@ fun Program.inlineSubroutines(options: CompilationOptions): Int {
return inliner.applyModifications() return inliner.applyModifications()
} }
fun Program.simplifyExpressions(errors: IErrorReporter, target: ICompilationTarget) : Int { fun Program.simplifyExpressions(errors: IErrorReporter) : Int {
val opti = ExpressionSimplifier(this, errors, target) val opti = ExpressionSimplifier(this, errors)
opti.visit(this) opti.visit(this)
return opti.applyModifications() return opti.applyModifications()
} }

View File

@ -83,7 +83,7 @@ class StatementOptimizer(private val program: Program,
// empty true part? switch with the else part // empty true part? switch with the else part
if(ifElse.truepart.isEmpty() && ifElse.elsepart.isNotEmpty()) { if(ifElse.truepart.isEmpty() && ifElse.elsepart.isNotEmpty()) {
val invertedCondition = BinaryExpression(ifElse.condition, "==", NumericLiteral(DataType.UBYTE, 0.0, ifElse.condition.position), ifElse.condition.position) val invertedCondition = invertCondition(ifElse.condition, program)
val emptyscope = AnonymousScope(mutableListOf(), ifElse.elsepart.position) val emptyscope = AnonymousScope(mutableListOf(), ifElse.elsepart.position)
val truepart = AnonymousScope(ifElse.elsepart.statements, ifElse.truepart.position) val truepart = AnonymousScope(ifElse.elsepart.statements, ifElse.truepart.position)
return listOf( return listOf(
@ -445,38 +445,6 @@ class StatementOptimizer(private val program: Program,
return listOf(IAstModification.ReplaceNode(whenStmt, ifStmt, parent)) return listOf(IAstModification.ReplaceNode(whenStmt, ifStmt, parent))
} }
if(whenStmt.condition.inferType(program).isBool) {
if(whenStmt.choices.all { it.values?.size==1 }) {
if (whenStmt.choices.all { it.values!!.single().constValue(program)!!.number in arrayOf(0.0, 1.0) }) {
// it's a when statement on booleans that can just be replaced by an if or if-else.
if (whenStmt.choices.size == 1) {
return if(whenStmt.choices[0].values!![0].constValue(program)!!.number==1.0) {
replaceWithIf(whenStmt.condition, whenStmt.choices[0].statements, null)
} else {
val notCondition = BinaryExpression(whenStmt.condition, "==", NumericLiteral(DataType.UBYTE, 0.0, whenStmt.condition.position), whenStmt.condition.position)
replaceWithIf(notCondition, whenStmt.choices[0].statements, null)
}
} else if (whenStmt.choices.size == 2) {
var trueBlock: AnonymousScope? = null
var elseBlock: AnonymousScope? = null
if(whenStmt.choices[0].values!![0].constValue(program)!!.number==1.0) {
trueBlock = whenStmt.choices[0].statements
} else {
elseBlock = whenStmt.choices[0].statements
}
if(whenStmt.choices[1].values!![0].constValue(program)!!.number==1.0) {
trueBlock = whenStmt.choices[1].statements
} else {
elseBlock = whenStmt.choices[1].statements
}
if(trueBlock!=null && elseBlock!=null) {
return replaceWithIf(whenStmt.condition, trueBlock, elseBlock)
}
}
}
}
}
val constantValue = whenStmt.condition.constValue(program)?.number val constantValue = whenStmt.condition.constValue(program)?.number
if(constantValue!=null) { if(constantValue!=null) {
// when condition is a constant // when condition is a constant

View File

@ -430,7 +430,7 @@ private fun optimizeAst(program: Program, compilerOptions: CompilationOptions, e
removeUnusedCode(program, errors,compilerOptions) removeUnusedCode(program, errors,compilerOptions)
while (true) { while (true) {
// keep optimizing expressions and statements until no more steps remain // keep optimizing expressions and statements until no more steps remain
val optsDone1 = program.simplifyExpressions(errors, compilerOptions.compTarget) val optsDone1 = program.simplifyExpressions(errors)
val optsDone2 = program.optimizeStatements(errors, functions, compilerOptions) val optsDone2 = program.optimizeStatements(errors, functions, compilerOptions)
val optsDone3 = program.inlineSubroutines(compilerOptions) val optsDone3 = program.inlineSubroutines(compilerOptions)
program.constantFold(errors, compilerOptions) // because simplified statements and expressions can result in more constants that can be folded away program.constantFold(errors, compilerOptions) // because simplified statements and expressions can result in more constants that can be folded away

View File

@ -1100,7 +1100,7 @@ internal class AstChecker(private val program: Program,
errors.err("this expression doesn't return a value", typecast.expression.position) errors.err("this expression doesn't return a value", typecast.expression.position)
if(typecast.expression is NumericLiteral) { if(typecast.expression is NumericLiteral) {
val castResult = (typecast.expression as NumericLiteral).cast(typecast.type) val castResult = (typecast.expression as NumericLiteral).cast(typecast.type, typecast.implicit)
if(castResult.isValid) if(castResult.isValid)
throw FatalAstException("cast should have been performed in const eval already") throw FatalAstException("cast should have been performed in const eval already")
errors.err(castResult.whyFailed!!, typecast.expression.position) errors.err(castResult.whyFailed!!, typecast.expression.position)
@ -1673,11 +1673,11 @@ internal class AstChecker(private val program: Program,
is IdentifierReference -> it.nameInSource.hashCode() and 0xffff is IdentifierReference -> it.nameInSource.hashCode() and 0xffff
is TypecastExpression -> { is TypecastExpression -> {
val constVal = it.expression.constValue(program) val constVal = it.expression.constValue(program)
val cast = constVal?.cast(it.type) val cast = constVal?.cast(it.type, true)
if(cast==null || !cast.isValid) if(cast==null || !cast.isValid)
-9999999 -9999999
else else
cast.value!!.number.toInt() cast.valueOrZero().number.toInt()
} }
else -> -9999999 else -> -9999999
} }

View File

@ -205,9 +205,9 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
return modifications return modifications
} else { } else {
fun castLiteral(cvalue2: NumericLiteral): List<IAstModification.ReplaceNode> { fun castLiteral(cvalue2: NumericLiteral): List<IAstModification.ReplaceNode> {
val cast = cvalue2.cast(targettype) val cast = cvalue2.cast(targettype, true)
return if(cast.isValid) return if(cast.isValid)
listOf(IAstModification.ReplaceNode(assignment.value, cast.value!!, assignment)) listOf(IAstModification.ReplaceNode(assignment.value, cast.valueOrZero(), assignment))
else else
emptyList() emptyList()
} }
@ -314,7 +314,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
val modifications = mutableListOf<IAstModification>() val modifications = mutableListOf<IAstModification>()
val dt = memread.addressExpression.inferType(program) val dt = memread.addressExpression.inferType(program)
if(dt.isKnown && dt.getOr(DataType.UWORD)!=DataType.UWORD) { if(dt.isKnown && dt.getOr(DataType.UWORD)!=DataType.UWORD) {
val castedValue = (memread.addressExpression as? NumericLiteral)?.cast(DataType.UWORD)?.value val castedValue = (memread.addressExpression as? NumericLiteral)?.cast(DataType.UWORD, true)?.valueOrZero()
if(castedValue!=null) if(castedValue!=null)
modifications += IAstModification.ReplaceNode(memread.addressExpression, castedValue, memread) modifications += IAstModification.ReplaceNode(memread.addressExpression, castedValue, memread)
else else
@ -328,7 +328,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
val modifications = mutableListOf<IAstModification>() val modifications = mutableListOf<IAstModification>()
val dt = memwrite.addressExpression.inferType(program) val dt = memwrite.addressExpression.inferType(program)
if(dt.isKnown && dt.getOr(DataType.UWORD)!=DataType.UWORD) { if(dt.isKnown && dt.getOr(DataType.UWORD)!=DataType.UWORD) {
val castedValue = (memwrite.addressExpression as? NumericLiteral)?.cast(DataType.UWORD)?.value val castedValue = (memwrite.addressExpression as? NumericLiteral)?.cast(DataType.UWORD, true)?.valueOrZero()
if(castedValue!=null) if(castedValue!=null)
modifications += IAstModification.ReplaceNode(memwrite.addressExpression, castedValue, memwrite) modifications += IAstModification.ReplaceNode(memwrite.addressExpression, castedValue, memwrite)
else else
@ -349,9 +349,9 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
if (returnDt istype subReturnType or returnDt.isNotAssignableTo(subReturnType)) if (returnDt istype subReturnType or returnDt.isNotAssignableTo(subReturnType))
return noModifications return noModifications
if (returnValue is NumericLiteral) { if (returnValue is NumericLiteral) {
val cast = returnValue.cast(subReturnType) val cast = returnValue.cast(subReturnType, true)
if(cast.isValid) if(cast.isValid)
returnStmt.value = cast.value returnStmt.value = cast.valueOrZero()
} else { } else {
val modifications = mutableListOf<IAstModification>() val modifications = mutableListOf<IAstModification>()
addTypecastOrCastedValueModification(modifications, returnValue, subReturnType, returnStmt) addTypecastOrCastedValueModification(modifications, returnValue, subReturnType, returnStmt)
@ -399,12 +399,12 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
if(sourceDt == requiredType) if(sourceDt == requiredType)
return return
if(expressionToCast is NumericLiteral && expressionToCast.type!=DataType.FLOAT) { // refuse to automatically truncate floats if(expressionToCast is NumericLiteral && expressionToCast.type!=DataType.FLOAT) { // refuse to automatically truncate floats
val castedValue = expressionToCast.cast(requiredType) val castedValue = expressionToCast.cast(requiredType, true)
if (castedValue.isValid) { if (castedValue.isValid) {
val signOriginal = sign(expressionToCast.number) val signOriginal = sign(expressionToCast.number)
val signCasted = sign(castedValue.value!!.number) val signCasted = sign(castedValue.valueOrZero().number)
if(signOriginal==signCasted) { if(signOriginal==signCasted) {
modifications += IAstModification.ReplaceNode(expressionToCast, castedValue.value!!, parent) modifications += IAstModification.ReplaceNode(expressionToCast, castedValue.valueOrZero(), parent)
} }
return return
} }

View File

@ -48,9 +48,9 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
return listOf(IAstModification.ReplaceNode(typecast, constValue, parent)) return listOf(IAstModification.ReplaceNode(typecast, constValue, parent))
if(typecast.expression is NumericLiteral) { if(typecast.expression is NumericLiteral) {
val value = (typecast.expression as NumericLiteral).cast(typecast.type) // TODO: add param typecast.implicit val value = (typecast.expression as NumericLiteral).cast(typecast.type, typecast.implicit)
if(value.isValid) if(value.isValid)
return listOf(IAstModification.ReplaceNode(typecast, value.value!!, parent)) // TODO: value.valueOrZero() return listOf(IAstModification.ReplaceNode(typecast, value.valueOrZero(), parent))
} }
val sourceDt = typecast.expression.inferType(program) val sourceDt = typecast.expression.inferType(program)