From 905d8a0c0613ca825de4a36a8ca967752b3cfeff Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sun, 31 Mar 2019 18:04:19 +0200 Subject: [PATCH] actually, get rid of integer pow() because a naive multiplication loop approach is way too slow --- compiler/res/prog8lib/math.asm | 20 ++++----- compiler/res/prog8lib/prog8lib.asm | 38 ++++++++-------- compiler/src/prog8/ast/AstChecker.kt | 11 +---- compiler/src/prog8/compiler/Compiler.kt | 6 +-- .../src/prog8/compiler/intermediate/Opcode.kt | 2 - .../src/prog8/compiler/target/c64/AsmGen.kt | 4 +- compiler/src/prog8/stackvm/StackVm.kt | 16 ------- docs/source/syntaxreference.rst | 3 +- docs/source/todo.rst | 1 - examples/test.p8 | 45 +++---------------- 10 files changed, 41 insertions(+), 105 deletions(-) diff --git a/compiler/res/prog8lib/math.asm b/compiler/res/prog8lib/math.asm index 52d433028..cec232150 100644 --- a/compiler/res/prog8lib/math.asm +++ b/compiler/res/prog8lib/math.asm @@ -58,29 +58,29 @@ multiply_words .proc stx c64.SCRATCH_ZPREGX mult16 lda #$00 - sta multiply_words_result+2 ; clear upper bits of product - sta multiply_words_result+3 + sta result+2 ; clear upper bits of product + sta result+3 ldx #16 ; for all 16 bits... - lsr c64.SCRATCH_ZPWORD1+1 ; divide multiplier by 2 ror c64.SCRATCH_ZPWORD1 bcc + - lda multiply_words_result+2 ; get upper half of product and add multiplicand + lda result+2 ; get upper half of product and add multiplicand clc adc c64.SCRATCH_ZPWORD2 - sta multiply_words_result+2 - lda multiply_words_result+3 + sta result+2 + lda result+3 adc c64.SCRATCH_ZPWORD2+1 + ror a ; rotate partial product - sta multiply_words_result+3 - ror multiply_words_result+2 - ror multiply_words_result+1 - ror multiply_words_result + sta result+3 + ror result+2 + ror result+1 + ror result dex bne - ldx c64.SCRATCH_ZPREGX rts -multiply_words_result .byte 0,0,0,0 +result .byte 0,0,0,0 .pend diff --git a/compiler/res/prog8lib/prog8lib.asm b/compiler/res/prog8lib/prog8lib.asm index 28495f685..9276d695e 100644 --- a/compiler/res/prog8lib/prog8lib.asm +++ b/compiler/res/prog8lib/prog8lib.asm @@ -105,7 +105,7 @@ not_word .proc sta c64.ESTACK_HI + 1,x rts .pend - + bitand_b .proc ; -- bitwise and (of 2 bytes) lda c64.ESTACK_LO+2,x @@ -114,7 +114,7 @@ bitand_b .proc sta c64.ESTACK_LO+1,x rts .pend - + bitor_b .proc ; -- bitwise or (of 2 bytes) lda c64.ESTACK_LO+2,x @@ -123,7 +123,7 @@ bitor_b .proc sta c64.ESTACK_LO+1,x rts .pend - + bitxor_b .proc ; -- bitwise xor (of 2 bytes) lda c64.ESTACK_LO+2,x @@ -144,7 +144,7 @@ bitand_w .proc inx rts .pend - + bitor_w .proc ; -- bitwise or (of 2 words) lda c64.ESTACK_LO+2,x @@ -156,7 +156,7 @@ bitor_w .proc inx rts .pend - + bitxor_w .proc ; -- bitwise xor (of 2 bytes) lda c64.ESTACK_LO+2,x @@ -168,7 +168,7 @@ bitxor_w .proc inx rts .pend - + and_b .proc ; -- logical and (of 2 bytes) lda c64.ESTACK_LO+2,x @@ -183,7 +183,7 @@ and_b .proc sta c64.ESTACK_LO+1,x rts .pend - + or_b .proc ; -- logical or (of 2 bytes) lda c64.ESTACK_LO+2,x @@ -194,7 +194,7 @@ or_b .proc sta c64.ESTACK_LO+1,x rts .pend - + xor_b .proc ; -- logical xor (of 2 bytes) lda c64.ESTACK_LO+2,x @@ -227,7 +227,7 @@ and_w .proc sta c64.ESTACK_HI+1,x rts .pend - + or_w .proc ; -- logical or (word or word -> byte) lda c64.ESTACK_LO+2,x @@ -241,7 +241,7 @@ or_w .proc sta c64.ESTACK_HI+1,x rts .pend - + xor_w .proc ; -- logical xor (word xor word -> byte) lda c64.ESTACK_LO+2,x @@ -322,9 +322,9 @@ mul_word .proc stx c64.SCRATCH_ZPREGX jsr math.multiply_words ldx c64.SCRATCH_ZPREGX - lda math.multiply_words.multiply_words_result + lda math.multiply_words.result sta c64.ESTACK_LO+1,x - lda math.multiply_words.multiply_words_result+1 + lda math.multiply_words.result+1 sta c64.ESTACK_HI+1,x rts .pend @@ -648,8 +648,8 @@ func_read_flags .proc dex rts .pend - - + + func_sqrt16 .proc lda c64.ESTACK_LO+1,x sta c64.SCRATCH_ZPWORD2 @@ -698,8 +698,8 @@ _skip3 rts _stab .byte $01,$02,$04,$08,$10,$20,$40,$80 .pend - - + + func_sin8 .proc ldy c64.ESTACK_LO+1,x lda _sinecos8,y @@ -1194,7 +1194,7 @@ func_rndw .proc .pend -func_memcopy .proc +func_memcopy .proc ; note: clobbers A,Y inx stx c64.SCRATCH_ZPREGX @@ -1220,7 +1220,7 @@ func_memcopy .proc rts .pend -func_memset .proc +func_memset .proc ; note: clobbers A,Y inx stx c64.SCRATCH_ZPREGX @@ -1240,7 +1240,7 @@ func_memset .proc rts .pend -func_memsetw .proc +func_memsetw .proc ; note: clobbers A,Y ; -- fill memory from (SCRATCH_ZPWORD1) number of words in SCRATCH_ZPWORD2, with word value in AY. diff --git a/compiler/src/prog8/ast/AstChecker.kt b/compiler/src/prog8/ast/AstChecker.kt index ee238c83a..115179175 100644 --- a/compiler/src/prog8/ast/AstChecker.kt +++ b/compiler/src/prog8/ast/AstChecker.kt @@ -688,15 +688,8 @@ private class AstChecker(private val namespace: INameScope, } } "**" -> { - if(leftDt in IntegerDatatypes) { - val constvalRight = expr.right.constValue(namespace, heap)?.asNumericValue?.toDouble() - if(constvalRight==null) { - if(rightDt==DataType.FLOAT || rightDt==DataType.BYTE || rightDt==DataType.WORD) - checkResult.add(ExpressionError("raising to a signed value requires floating point", expr.position)) - } else if(constvalRight<0.0) { - checkResult.add(ExpressionError("raising to negative power requires floating point", expr.position)) - } - } + if(leftDt in IntegerDatatypes) + checkResult.add(ExpressionError("power operator requires floating point", expr.position)) } "and", "or", "xor" -> { // only integer numeric operands accepted, and if literal constants, only boolean values accepted (0 or 1) diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 8565b6d50..2b1367ee2 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -1238,11 +1238,9 @@ internal class Compiler(private val rootModule: Module, } "**" -> { when(dt) { - DataType.UBYTE -> Opcode.POW_UB - DataType.BYTE, DataType.WORD -> throw CompilerException("power operator only available for unsigned integer types and floats") - DataType.UWORD -> Opcode.POW_UW + in IntegerDatatypes -> throw CompilerException("power operator requires floating points") DataType.FLOAT -> Opcode.POW_F - else -> throw CompilerException("only byte/word/float possible") + else -> throw CompilerException("only numeric datatype possible") } } "&" -> { diff --git a/compiler/src/prog8/compiler/intermediate/Opcode.kt b/compiler/src/prog8/compiler/intermediate/Opcode.kt index f2dadcf95..43b9ba8d9 100644 --- a/compiler/src/prog8/compiler/intermediate/Opcode.kt +++ b/compiler/src/prog8/compiler/intermediate/Opcode.kt @@ -58,8 +58,6 @@ enum class Opcode { DIV_F, REMAINDER_UB, // signed remainder is undefined/unimplemented REMAINDER_UW, // signed remainder is undefined/unimplemented - POW_UB, - POW_UW, POW_F, NEG_B, NEG_W, diff --git a/compiler/src/prog8/compiler/target/c64/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/AsmGen.kt index 35dd03709..0352010a9 100644 --- a/compiler/src/prog8/compiler/target/c64/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/AsmGen.kt @@ -729,9 +729,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, Opcode.ABS_B -> " jsr prog8_lib.abs_b" Opcode.ABS_W -> " jsr prog8_lib.abs_w" Opcode.ABS_F -> " jsr c64flt.abs_f" - Opcode.POW_UB -> " jsr prog8_lib.pow_ub" // @todo implement - Opcode.POW_UW -> " jsr prog8_lib.pow_uw" // @todo implement - Opcode.POW_F -> " jsr c64flt.pow_f" // @todo implement + Opcode.POW_F -> " jsr c64flt.pow_f" Opcode.INV_BYTE -> { """ lda ${(ESTACK_LO + 1).toHex()},x diff --git a/compiler/src/prog8/stackvm/StackVm.kt b/compiler/src/prog8/stackvm/StackVm.kt index 710059b8b..225eee64f 100644 --- a/compiler/src/prog8/stackvm/StackVm.kt +++ b/compiler/src/prog8/stackvm/StackVm.kt @@ -615,22 +615,6 @@ class StackVm(private var traceOutputFile: String?) { evalstack.push(value) setFlags(value) } - Opcode.POW_UB -> { - val (top, second) = evalstack.pop2() - checkDt(top, DataType.UBYTE) - checkDt(second, DataType.UBYTE) - val value=second.pow(top) - evalstack.push(value) - setFlags(value) - } - Opcode.POW_UW -> { - val (top, second) = evalstack.pop2() - checkDt(top, DataType.UWORD) - checkDt(second, DataType.UWORD) - val value=second.pow(top) - evalstack.push(value) - setFlags(value) - } Opcode.POW_F -> { val (top, second) = evalstack.pop2() checkDt(top, DataType.FLOAT) diff --git a/docs/source/syntaxreference.rst b/docs/source/syntaxreference.rst index 60bea7f77..eed976921 100644 --- a/docs/source/syntaxreference.rst +++ b/docs/source/syntaxreference.rst @@ -372,8 +372,7 @@ Operators arithmetic: ``+`` ``-`` ``*`` ``/`` ``**`` ``%`` ``+``, ``-``, ``*``, ``/`` are the familiar arithmetic operations. ``/`` is division (will result in integer division when using on integer operands, and a floating point division when at least one of the operands is a float) - ``**`` is the power operator: ``3 ** 5`` is equal to 3*3*3*3*3 and is 243. (certain restrictions - apply when dealing with signed or negative numbers) + ``**`` is the power operator: ``3 ** 5`` is equal to 3*3*3*3*3 and is 243. (it only works on floating point variables) ``%`` is the remainder operator: ``25 % 7`` is 4. Be careful: without a space, %10 will be parsed as the binary number 2 Remainder is only supported on integer operands (not floats). diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 667796489..72b81ba55 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -86,6 +86,5 @@ of values together (and use it multiple times). Something like:: Misc ^^^^ -- code generation for POW instruction - are there any other missing instructions in the code generator? - implement %asmbinary diff --git a/examples/test.p8 b/examples/test.p8 index 91422a88c..346befdbf 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -13,53 +13,20 @@ float fl=2.3 float fl2=20 -; ub = ub ** 7 -; c64scr.print_ub(ub) -; c64.CHROUT('\n') -; uw = uw ** 5 -; c64scr.print_uw(uw) -; c64.CHROUT('\n') + + fl = (ub as float) ** 4 + fl = 2.3 fl = fl ** 20.0 c64flt.print_f(fl) c64.CHROUT('\n') -; ub=3 ; @todo no instruction? -; ub **=7 ; @todo no instruction? -; c64scr.print_ub(ub) -; c64.CHROUT('\n') -; uw = 9 ; @todo no instruction? -; uw **=5 ; @todo no instruction? -; c64scr.print_uw(uw) -; c64.CHROUT('\n') - fl = 2.3 ; @todo no instruction? - fl **=20.0 ; @todo no instruction? + fl = 2.3 + fl = fl ** fl2 c64flt.print_f(fl) c64.CHROUT('\n') - -; ub=3 -; ub **= 7 -; c64scr.print_ub(ub) -; c64.CHROUT('\n') -; uw = 9 -; uw **= 5 -; c64scr.print_uw(uw) -; c64.CHROUT('\n') fl = 2.3 - fl **= 20.0 - c64flt.print_f(fl) - c64.CHROUT('\n') - -; ub=3 -; ub **= ub2 -; c64scr.print_ub(ub) -; c64.CHROUT('\n') -; uw = 9 -; uw **= uw2 -; c64scr.print_uw(uw) -; c64.CHROUT('\n') - fl = 2.3 - fl **= fl2 + fl **=20.0 c64flt.print_f(fl) c64.CHROUT('\n')