diff --git a/src/main/scala/millfork/compiler/AbstractStatementPreprocessor.scala b/src/main/scala/millfork/compiler/AbstractStatementPreprocessor.scala index 002d6d2f..4f24ff4d 100644 --- a/src/main/scala/millfork/compiler/AbstractStatementPreprocessor.scala +++ b/src/main/scala/millfork/compiler/AbstractStatementPreprocessor.scala @@ -231,8 +231,8 @@ abstract class AbstractStatementPreprocessor(protected val ctx: CompilationConte !env.overlapsVariable(f.variable, source) && !env.overlapsVariable(f.variable, f.start) && !env.overlapsVariable(f.variable, f.end) && - source.isPure && - sourceType.size == 1 && + ctx.isConstant(source) && + sourceType.size <= 1 && targetType.size == 1 && sourceType.isAssignableTo(targetType) ) { @@ -738,9 +738,9 @@ object AbstractStatementPreprocessor { val sourceType = AbstractExpressionCompiler.getExpressionType(ctx, source) val targetType = AbstractExpressionCompiler.getExpressionType(ctx, target) if ( - source.isPure && - index.isPure && - sourceType.size == 1 && + ctx.isConstant(source) && + ctx.isConstant(index) && + sourceType.size <= 1 && targetType.size == 1 && sourceType.isAssignableTo(targetType)&& !env.isVolatile(VariableExpression(pointy)) && diff --git a/src/main/scala/millfork/compiler/CompilationContext.scala b/src/main/scala/millfork/compiler/CompilationContext.scala index 53907630..244d71dc 100644 --- a/src/main/scala/millfork/compiler/CompilationContext.scala +++ b/src/main/scala/millfork/compiler/CompilationContext.scala @@ -2,7 +2,7 @@ package millfork.compiler import millfork.env.{Environment, Label, NormalFunction, NormalParamSignature} import millfork.error.Logger -import millfork.node.NiceFunctionProperty +import millfork.node.{Expression, NiceFunctionProperty} import millfork.{CompilationFlag, CompilationOptions, JobContext} /** @@ -15,6 +15,9 @@ case class CompilationContext(env: Environment, niceFunctionProperties: Set[(NiceFunctionProperty, String)], breakLabels: Map[String, Label] = Map(), continueLabels: Map[String, Label] = Map()){ + + def isConstant(v: Expression): Boolean = v.isPure || env.eval(v).isDefined + def withInlinedEnv(environment: Environment, newLabel: String): CompilationContext = { val newEnv = new Environment(Some(env), newLabel, environment.cpuFamily, options) newEnv.things ++= environment.things diff --git a/src/main/scala/millfork/compiler/mos/BuiltIns.scala b/src/main/scala/millfork/compiler/mos/BuiltIns.scala index de396887..d5384072 100644 --- a/src/main/scala/millfork/compiler/mos/BuiltIns.scala +++ b/src/main/scala/millfork/compiler/mos/BuiltIns.scala @@ -1292,7 +1292,7 @@ object BuiltIns { def compileByteMultiplication(ctx: CompilationContext, v: Expression, c: Int): List[AssemblyLine] = { c match { case 0 => - if (v.isPure) return List(AssemblyLine.immediate(LDA, 0)) + if (ctx.isConstant(v)) return List(AssemblyLine.immediate(LDA, 0)) else return MosExpressionCompiler.compileToA(ctx, v) ++ List(AssemblyLine.immediate(LDA, 0)) case 1 => return MosExpressionCompiler.compileToA(ctx, v) case 2 | 4 | 8 | 16 | 32 => diff --git a/src/main/scala/millfork/compiler/z80/Z80BulkMemoryOperations.scala b/src/main/scala/millfork/compiler/z80/Z80BulkMemoryOperations.scala index 4457be62..9bb641af 100644 --- a/src/main/scala/millfork/compiler/z80/Z80BulkMemoryOperations.scala +++ b/src/main/scala/millfork/compiler/z80/Z80BulkMemoryOperations.scala @@ -21,7 +21,7 @@ object Z80BulkMemoryOperations { */ def compileMemcpy(ctx: CompilationContext, target: IndexedExpression, source: IndexedExpression, f: ForStatement): List[ZLine] = { val sourceOffset = removeVariableOnce(ctx, f.variable, source.index).getOrElse(return compileForStatement(ctx, f)._1) - if (!sourceOffset.isPure) return compileForStatement(ctx, f)._1 + if (!ctx.isConstant(sourceOffset)) return compileForStatement(ctx, f)._1 val sourceIndexExpression = sourceOffset #+# f.start val calculateSource = Z80ExpressionCompiler.calculateAddressToHL(ctx, IndexedExpression(source.name, sourceIndexExpression).pos(source.position), forWriting = false) compileMemoryBulk(ctx, target, f, @@ -85,11 +85,11 @@ object Z80BulkMemoryOperations { if (ctx.options.flag(CompilationFlag.EmitZ80Opcodes)) { removeVariableOnce(ctx, f.variable, target.index) match { - case Some(targetOffset) if targetOffset.isPure => + case Some(targetOffset) if ctx.isConstant(targetOffset) => return compileForZ80(targetOffset) case _ => } - if (target.isPure && target.name == f.variable && !ctx.env.overlapsVariable(f.variable, target.index)) { + if (ctx.isConstant(target) && target.name == f.variable && !ctx.env.overlapsVariable(f.variable, target.index)) { return compileForZ80(target.index) } } @@ -437,7 +437,7 @@ object Z80BulkMemoryOperations { val pointy = ctx.env.getPointy(target.name) if (pointy.elementType.alignedSize > 1) return Z80StatementCompiler.compileForStatement(ctx, f)._1 val targetOffset = removeVariableOnce(ctx, f.variable, target.index).getOrElse(return compileForStatement(ctx, f)._1) - if (!targetOffset.isPure) return compileForStatement(ctx, f)._1 + if (!ctx.isConstant(targetOffset)) return compileForStatement(ctx, f)._1 val indexVariableSize = ctx.env.get[Variable](f.variable).typ.size val wrapper = createForLoopPreconditioningIfStatement(ctx, f) val decreasingDespiteSyntax = preferDecreasing && (f.direction == ForDirection.ParallelTo || f.direction == ForDirection.ParallelUntil)