From c0920a43a3ddf980ebd519c718e976735853d839 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Fri, 11 Jan 2019 20:24:36 +0100 Subject: [PATCH] optimize % and logical operations on words --- .../src/prog8/compiler/target/c64/AsmGen.kt | 76 ++++++++ .../prog8/optimizing/SimplifyExpressions.kt | 33 +++- .../prog8/optimizing/StatementOptimizer.kt | 169 ++++++++-------- examples/test.p8 | 182 ++---------------- 4 files changed, 198 insertions(+), 262 deletions(-) diff --git a/compiler/src/prog8/compiler/target/c64/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/AsmGen.kt index 57d3c76a5..803613098 100644 --- a/compiler/src/prog8/compiler/target/c64/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/AsmGen.kt @@ -3052,6 +3052,82 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, " lda ${segment[0].callLabel} | eor #${hexVal(segment[1])} | sta ${ESTACK_LO.toHex()},x | dex " }, + // push memory word | wordvalue + AsmPattern(listOf(Opcode.PUSH_MEM_W, Opcode.PUSH_WORD, Opcode.BITOR_WORD), + listOf(Opcode.PUSH_MEM_UW, Opcode.PUSH_WORD, Opcode.BITOR_WORD)) { segment -> + """ + lda ${hexVal(segment[0])} + ora #<${hexVal(segment[1])} + sta ${ESTACK_LO.toHex()},x + lda ${hexValPlusOne(segment[0])} + ora #>${hexVal(segment[1])} + sta ${ESTACK_HI.toHex()},x + dex + """ + }, + // push memory word & wordvalue + AsmPattern(listOf(Opcode.PUSH_MEM_W, Opcode.PUSH_WORD, Opcode.BITAND_WORD), + listOf(Opcode.PUSH_MEM_UW, Opcode.PUSH_WORD, Opcode.BITAND_WORD)) { segment -> + """ + lda ${hexVal(segment[0])} + and #<${hexVal(segment[1])} + sta ${ESTACK_LO.toHex()},x + lda ${hexValPlusOne(segment[0])} + and #>${hexVal(segment[1])} + sta ${ESTACK_HI.toHex()},x + dex + """ + }, + // push memory word ^ wordvalue + AsmPattern(listOf(Opcode.PUSH_MEM_W, Opcode.PUSH_WORD, Opcode.BITXOR_WORD), + listOf(Opcode.PUSH_MEM_UW, Opcode.PUSH_WORD, Opcode.BITXOR_WORD)) { segment -> + """ + lda ${hexVal(segment[0])} + eor #<${hexVal(segment[1])} + sta ${ESTACK_LO.toHex()},x + lda ${hexValPlusOne(segment[0])} + eor #>${hexVal(segment[1])} + sta ${ESTACK_HI.toHex()},x + dex + """ + }, + // push var word | wordvalue + AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.PUSH_WORD, Opcode.BITOR_WORD)) { segment -> + """ + lda ${segment[0].callLabel} + ora #<${hexVal(segment[1])} + sta ${ESTACK_LO.toHex()},x + lda ${segment[0].callLabel}+1 + ora #>${hexVal(segment[1])} + sta ${ESTACK_HI.toHex()},x + dex + """ + }, + // push var word & wordvalue + AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.PUSH_WORD, Opcode.BITAND_WORD)) { segment -> + """ + lda ${segment[0].callLabel} + and #<${hexVal(segment[1])} + sta ${ESTACK_LO.toHex()},x + lda ${segment[0].callLabel}+1 + and #>${hexVal(segment[1])} + sta ${ESTACK_HI.toHex()},x + dex + """ + }, + // push var word ^ wordvalue + AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.PUSH_WORD, Opcode.BITXOR_WORD)) { segment -> + """ + lda ${segment[0].callLabel} + eor #<${hexVal(segment[1])} + sta ${ESTACK_LO.toHex()},x + lda ${segment[0].callLabel}+1 + eor #>${hexVal(segment[1])} + sta ${ESTACK_HI.toHex()},x + dex + """ + }, + AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.PUSH_VAR_BYTE, Opcode.MKWORD)) { segment -> """ lda ${segment[0].callLabel} diff --git a/compiler/src/prog8/optimizing/SimplifyExpressions.kt b/compiler/src/prog8/optimizing/SimplifyExpressions.kt index 6c7c8b005..f9a9fdba5 100644 --- a/compiler/src/prog8/optimizing/SimplifyExpressions.kt +++ b/compiler/src/prog8/optimizing/SimplifyExpressions.kt @@ -13,8 +13,6 @@ import kotlin.math.log2 -X + A -> A - X X+ (-A) -> X - A X- (-A) -> X + A - X % 1 -> constant 0 (if X is byte/word) - X % 2 -> X and 1 (if X is byte/word) todo expression optimization: common (sub) expression elimination (turn common expressions into single subroutine call + introduce variable to hold it) @@ -120,6 +118,7 @@ class SimplifyExpressions(private val namespace: INameScope, private val heap: H "+" -> return optimizeAdd(expr, leftVal, rightVal) "-" -> return optimizeSub(expr, leftVal, rightVal) "**" -> return optimizePower(expr, leftVal, rightVal) + "%" -> return optimizeRemainder(expr, leftVal, rightVal) } return expr } @@ -349,6 +348,30 @@ class SimplifyExpressions(private val namespace: INameScope, private val heap: H return expr } + private fun optimizeRemainder(expr: BinaryExpression, leftVal: LiteralValue?, rightVal: LiteralValue?): IExpression { + if(leftVal==null && rightVal==null) + return expr + + // simplify assignments A = B C + + val cv = rightVal?.asIntegerValue?.toDouble() + when(expr.operator) { + "%" -> { + if (cv == 1.0) { + optimizationsDone++ + return LiteralValue.fromNumber(0, expr.resultingDatatype(namespace, heap)!!, expr.position) + } else if (cv == 2.0) { + optimizationsDone++ + expr.operator = "&" + expr.right = LiteralValue.optimalInteger(1, expr.position) + return expr + } + } + } + return expr + + } + private fun optimizeDivision(expr: BinaryExpression, leftVal: LiteralValue?, rightVal: LiteralValue?): IExpression { if(leftVal==null && rightVal==null) return expr @@ -379,8 +402,7 @@ class SimplifyExpressions(private val namespace: INameScope, private val heap: H if(leftDt in IntegerDatatypes) { // divided by a power of two => shift right optimizationsDone++ - val numshifts = log2(cv) - println("DIV: SHIFT RIGHT $cv -> $numshifts") // TODO + val numshifts = log2(cv).toInt() return BinaryExpression(expr.left, ">>", LiteralValue.optimalInteger(numshifts, expr.position), expr.position) } } @@ -388,8 +410,7 @@ class SimplifyExpressions(private val namespace: INameScope, private val heap: H if(leftDt in IntegerDatatypes) { // divided by a negative power of two => negate, then shift right optimizationsDone++ - val numshifts = log2(-cv) - println("DIV: SHIFT RIGHT $cv -> $numshifts") // TODO + val numshifts = log2(-cv).toInt() return BinaryExpression(PrefixExpression("-", expr.left, expr.position), ">>", LiteralValue.optimalInteger(numshifts, expr.position), expr.position) } } diff --git a/compiler/src/prog8/optimizing/StatementOptimizer.kt b/compiler/src/prog8/optimizing/StatementOptimizer.kt index 7ab858e21..4a2462cfb 100644 --- a/compiler/src/prog8/optimizing/StatementOptimizer.kt +++ b/compiler/src/prog8/optimizing/StatementOptimizer.kt @@ -168,113 +168,112 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He if(assignment.aug_op!=null) throw AstException("augmented assignments should have been converted to normal assignments before this optimizer") - // remove assignments that have no effect X=X , X+=0, X-=0, X*=1, X/=1, X//=1, A |= 0, A ^= 0, A<<=0, etc etc if(assignment.targets.size==1) { val target=assignment.targets[0] if(same(target, assignment.value)) { optimizationsDone++ return NopStatement(assignment.position) } - val targetDt = target.determineDatatype(namespace, heap, assignment) + val targetDt = target.determineDatatype(namespace, heap, assignment)!! val bexpr=assignment.value as? BinaryExpression - if(bexpr!=null && same(target, bexpr.left)) { + if(bexpr!=null) { val cv = bexpr.right.constValue(namespace, heap)?.asNumericValue?.toDouble() if(cv!=null) { - when (bexpr.operator) { - "+" -> { - if (cv==0.0) { - optimizationsDone++ - return NopStatement(assignment.position) - } else if(cv in 1.0..8.0 && targetDt in IntegerDatatypes && floor(cv)==cv) { - // replace by several INCs - val decs = AnonymousScope(mutableListOf(), assignment.position) - repeat(cv.toInt()) { - decs.statements.add(PostIncrDecr(target, "++", assignment.position)) + if (same(target, bexpr.left)) { + + // remove assignments that have no effect X=X , X+=0, X-=0, X*=1, X/=1, X//=1, A |= 0, A ^= 0, A<<=0, etc etc + // A = A B + + when (bexpr.operator) { + "+" -> { + if (cv == 0.0) { + optimizationsDone++ + return NopStatement(assignment.position) + } else if (cv in 1.0..8.0 && targetDt in IntegerDatatypes && floor(cv) == cv) { + // replace by several INCs + val decs = AnonymousScope(mutableListOf(), assignment.position) + repeat(cv.toInt()) { + decs.statements.add(PostIncrDecr(target, "++", assignment.position)) + } + return decs } - return decs } - } - "-" -> { - if (cv==0.0) { - optimizationsDone++ - return NopStatement(assignment.position) - } else if(cv in 1.0..8.0 && targetDt in IntegerDatatypes && floor(cv)==cv) { - // replace by several DECs - val decs = AnonymousScope(mutableListOf(), assignment.position) - repeat(cv.toInt()) { - decs.statements.add(PostIncrDecr(target, "--", assignment.position)) + "-" -> { + if (cv == 0.0) { + optimizationsDone++ + return NopStatement(assignment.position) + } else if (cv in 1.0..8.0 && targetDt in IntegerDatatypes && floor(cv) == cv) { + // replace by several DECs + val decs = AnonymousScope(mutableListOf(), assignment.position) + repeat(cv.toInt()) { + decs.statements.add(PostIncrDecr(target, "--", assignment.position)) + } + return decs } - return decs } - } - "*" -> if (cv==1.0) { - optimizationsDone++ - return NopStatement(assignment.position) - } - "%" -> if (cv==1.0) { - optimizationsDone++ - return NopStatement(assignment.position) - } - "/" -> if (cv==1.0) { - optimizationsDone++ - return NopStatement(assignment.position) - } - "**" -> if (cv==1.0) { - optimizationsDone++ - return NopStatement(assignment.position) - } - "|" -> if (cv==0.0) { - optimizationsDone++ - return NopStatement(assignment.position) - } - "^" -> if (cv==0.0) { - optimizationsDone++ - return NopStatement(assignment.position) - } - "<<" -> { - if(cv==0.0) { + "*" -> if (cv == 1.0) { optimizationsDone++ return NopStatement(assignment.position) } - if(((targetDt==DataType.UWORD || targetDt==DataType.WORD) && cv >15.0) || - ((targetDt==DataType.UBYTE || targetDt==DataType.BYTE) && cv > 7.0)) { - assignment.value = LiteralValue.optimalInteger(0, assignment.value.position) - assignment.value.linkParents(assignment) - optimizationsDone++ - } - else { - // replace by in-place lsl(...) call - val scope = AnonymousScope(mutableListOf(), assignment.position) - var numshifts = cv.toInt() - while(numshifts>0) { - scope.statements.add(FunctionCallStatement(IdentifierReference(listOf("lsl"), assignment.position), mutableListOf(bexpr.left), assignment.position)) - numshifts-- - } - optimizationsDone++ - return scope - } - } - ">>" -> { - if(cv==0.0) { + "/" -> if (cv == 1.0) { optimizationsDone++ return NopStatement(assignment.position) } - if(((targetDt==DataType.UWORD || targetDt==DataType.WORD) && cv >15.0) || - ((targetDt==DataType.UBYTE || targetDt==DataType.BYTE) && cv > 7.0)) { - assignment.value = LiteralValue.optimalInteger(0, assignment.value.position) - assignment.value.linkParents(assignment) + "**" -> if (cv == 1.0) { optimizationsDone++ + return NopStatement(assignment.position) } - else { - // replace by in-place lsr(...) call - val scope = AnonymousScope(mutableListOf(), assignment.position) - var numshifts = cv.toInt() - while(numshifts>0) { - scope.statements.add(FunctionCallStatement(IdentifierReference(listOf("lsr"), assignment.position), mutableListOf(bexpr.left), assignment.position)) - numshifts-- - } + "|" -> if (cv == 0.0) { optimizationsDone++ - return scope + return NopStatement(assignment.position) + } + "^" -> if (cv == 0.0) { + optimizationsDone++ + return NopStatement(assignment.position) + } + "<<" -> { + if (cv == 0.0) { + optimizationsDone++ + return NopStatement(assignment.position) + } + if (((targetDt == DataType.UWORD || targetDt == DataType.WORD) && cv > 15.0) || + ((targetDt == DataType.UBYTE || targetDt == DataType.BYTE) && cv > 7.0)) { + assignment.value = LiteralValue.optimalInteger(0, assignment.value.position) + assignment.value.linkParents(assignment) + optimizationsDone++ + } else { + // replace by in-place lsl(...) call + val scope = AnonymousScope(mutableListOf(), assignment.position) + var numshifts = cv.toInt() + while (numshifts > 0) { + scope.statements.add(FunctionCallStatement(IdentifierReference(listOf("lsl"), assignment.position), mutableListOf(bexpr.left), assignment.position)) + numshifts-- + } + optimizationsDone++ + return scope + } + } + ">>" -> { + if (cv == 0.0) { + optimizationsDone++ + return NopStatement(assignment.position) + } + if (((targetDt == DataType.UWORD || targetDt == DataType.WORD) && cv > 15.0) || + ((targetDt == DataType.UBYTE || targetDt == DataType.BYTE) && cv > 7.0)) { + assignment.value = LiteralValue.optimalInteger(0, assignment.value.position) + assignment.value.linkParents(assignment) + optimizationsDone++ + } else { + // replace by in-place lsr(...) call + val scope = AnonymousScope(mutableListOf(), assignment.position) + var numshifts = cv.toInt() + while (numshifts > 0) { + scope.statements.add(FunctionCallStatement(IdentifierReference(listOf("lsr"), assignment.position), mutableListOf(bexpr.left), assignment.position)) + numshifts-- + } + optimizationsDone++ + return scope + } } } } diff --git a/examples/test.p8 b/examples/test.p8 index deb720cde..26d8cfe44 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,4 +1,5 @@ %import c64utils +%import c64flt ~ main { @@ -12,178 +13,17 @@ uword uw2 word w = 1000 word w2 + float f1 = 1.1 + float f2 = 2.2 - ub2=i*1 - c64scr.print_ub(ub2) - c64.CHROUT('\n') - ub2=i*2 - c64scr.print_ub(ub2) - c64.CHROUT('\n') - ub2=i*3 - c64scr.print_ub(ub2) - c64.CHROUT('\n') - ub2=i*4 - c64scr.print_ub(ub2) - c64.CHROUT('\n') - ub2=i*5 - c64scr.print_ub(ub2) - c64.CHROUT('\n') - ub2=i*6 - c64scr.print_ub(ub2) - c64.CHROUT('\n') - ub2=i*7 - c64scr.print_ub(ub2) - c64.CHROUT('\n') - ub2=i*8 - c64scr.print_ub(ub2) - c64.CHROUT('\n') - ub2=i*9 - c64scr.print_ub(ub2) - c64.CHROUT('\n') - ub2=i*10 - c64scr.print_ub(ub2) - c64.CHROUT('\n') - ub2=i*11 - c64scr.print_ub(ub2) - c64.CHROUT('\n') - ub2=i*12 - c64scr.print_ub(ub2) - c64.CHROUT('\n') - ub2=i*13 - c64scr.print_ub(ub2) - c64.CHROUT('\n') - ub2=i*14 - c64scr.print_ub(ub2) - c64.CHROUT('\n') - ub2=i*15 - c64scr.print_ub(ub2) - c64.CHROUT('\n') - ub2=i*16 - c64scr.print_ub(ub2) - c64.CHROUT('\n') - ub2=i*17 - c64scr.print_ub(ub2) - c64.CHROUT('\n') - ub2=i*18 - c64scr.print_ub(ub2) - c64.CHROUT('\n') - ub2=i*19 - c64scr.print_ub(ub2) - c64.CHROUT('\n') - ub2=i*20 - c64scr.print_ub(ub2) - c64.CHROUT('\n') - ub2=i*21 - c64scr.print_ub(ub2) - c64.CHROUT('\n') - ub2=i*22 - c64scr.print_ub(ub2) - c64.CHROUT('\n') - ub2=i*23 - c64scr.print_ub(ub2) - c64.CHROUT('\n') - ub2=i*24 - c64scr.print_ub(ub2) - c64.CHROUT('\n') - ub2=i*25 - c64scr.print_ub(ub2) - c64.CHROUT('\n') - - i=5 - ub2=i*40 - c64scr.print_ub(ub2) - c64.CHROUT('\n') - - c64.CHROUT('\n') - - - b2=j*1 - c64scr.print_b(b2) - c64.CHROUT('\n') - b2=j*2 - c64scr.print_b(b2) - c64.CHROUT('\n') - b2=j*3 - c64scr.print_b(b2) - c64.CHROUT('\n') - b2=j*4 - c64scr.print_b(b2) - c64.CHROUT('\n') - b2=j*5 - c64scr.print_b(b2) - c64.CHROUT('\n') - b2=j*6 - c64scr.print_b(b2) - c64.CHROUT('\n') - b2=j*7 - c64scr.print_b(b2) - c64.CHROUT('\n') - b2=j*8 - c64scr.print_b(b2) - c64.CHROUT('\n') - b2=j*9 - c64scr.print_b(b2) - c64.CHROUT('\n') - b2=j*10 - c64scr.print_b(b2) - c64.CHROUT('\n') - b2=j*11 - c64scr.print_b(b2) - c64.CHROUT('\n') - b2=j*12 - c64scr.print_b(b2) - c64.CHROUT('\n') - b2=j*13 - c64scr.print_b(b2) - c64.CHROUT('\n') - b2=j*14 - c64scr.print_b(b2) - c64.CHROUT('\n') - b2=j*15 - c64scr.print_b(b2) - c64.CHROUT('\n') - b2=j*16 - c64scr.print_b(b2) - c64.CHROUT('\n') - b2=j*17 - c64scr.print_b(b2) - c64.CHROUT('\n') - b2=j*18 - c64scr.print_b(b2) - c64.CHROUT('\n') - b2=j*19 - c64scr.print_b(b2) - c64.CHROUT('\n') - b2=j*20 - c64scr.print_b(b2) - c64.CHROUT('\n') - b2=j*21 - c64scr.print_b(b2) - c64.CHROUT('\n') - b2=j*22 - c64scr.print_b(b2) - c64.CHROUT('\n') - b2=j*23 - c64scr.print_b(b2) - c64.CHROUT('\n') - b2=j*24 - c64scr.print_b(b2) - c64.CHROUT('\n') - b2=j*25 - c64scr.print_b(b2) - c64.CHROUT('\n') - - j=3 - b2=j*40 - c64scr.print_b(b2) - c64.CHROUT('\n') - - c64.CHROUT('\n') - - - ;@todo multiplication by negative values - - ;@todo the same, for uword and word + i %= 1 + i %= 2 + ub2 = i % 1 + ub2 = i % 2 + uw %= 1 + uw %= 2 + uw2 = uw % 1 + uw2 = uw % 2 } }