Skip to content

Commit 231b50d

Browse files
committed
optimize certain word multiplication with bit shifting if it's a power of 2
1 parent a71895c commit 231b50d

File tree

3 files changed

+61
-65
lines changed

3 files changed

+61
-65
lines changed

codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import prog8.code.ast.*
55
import prog8.code.core.*
66
import prog8.codegen.cpu6502.AsmGen6502Internal
77
import prog8.codegen.cpu6502.VariableAllocator
8+
import kotlin.math.log2
89

910

1011
internal class AssignmentAsmGen(
@@ -1145,6 +1146,14 @@ internal class AssignmentAsmGen(
11451146
assignExpressionToRegister(expr.left, RegisterOrPair.A, expr.type.isSigned)
11461147
if (value in asmgen.optimizedByteMultiplications)
11471148
asmgen.out(" jsr prog8_math.mul_byte_${value}")
1149+
else if(value in powersOfTwoInt) {
1150+
val shifts = log2(value.toDouble()).toInt()
1151+
if(shifts>=8) {
1152+
asmgen.out(" lda #0")
1153+
} else {
1154+
repeat(shifts) { asmgen.out(" asl a") }
1155+
}
1156+
}
11481157
else
11491158
asmgen.out(" ldy #$value | jsr prog8_math.multiply_bytes")
11501159
assignRegisterByte(target, CpuRegister.A, false, true)
@@ -1155,7 +1164,26 @@ internal class AssignmentAsmGen(
11551164
assignExpressionToRegister(expr.left, RegisterOrPair.AY, expr.type.isSigned)
11561165
asmgen.out(" jsr prog8_math.mul_word_${value}")
11571166
}
1167+
else if(value in powersOfTwoInt) {
1168+
val shifts = log2(value.toDouble()).toInt()
1169+
if(shifts>=16) {
1170+
assignExpressionToRegister(expr.left, RegisterOrPair.AY, expr.type.isSigned)
1171+
asmgen.out(" lda #0 | ldy #0")
1172+
} else {
1173+
if(target.kind==TargetStorageKind.VARIABLE && target.datatype.isWord) {
1174+
assignExpressionToVariable(expr.left, target.asmVarname, target.datatype)
1175+
repeat(shifts) { asmgen.out(" asl ${target.asmVarname} | rol ${target.asmVarname}+1") }
1176+
return true
1177+
} else {
1178+
assignExpressionToRegister(expr.left, RegisterOrPair.AY, expr.type.isSigned)
1179+
asmgen.out(" sty P8ZP_SCRATCH_REG")
1180+
repeat(shifts) { asmgen.out(" asl a | rol P8ZP_SCRATCH_REG") }
1181+
asmgen.out(" ldy P8ZP_SCRATCH_REG")
1182+
}
1183+
}
1184+
}
11581185
else {
1186+
assignExpressionToRegister(expr.left, RegisterOrPair.AY, expr.type.isSigned)
11591187
if(expr.definingBlock()!!.options.veraFxMuls){
11601188
// cx16 verafx hardware mul
11611189
asmgen.assignWordOperandsToAYAndVar(expr.right, expr.left, "cx16.r1")

docs/source/todo.rst

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,18 +58,15 @@ and for example the below code omits line 5::
5858
STRUCTS and TYPED POINTERS
5959
--------------------------
6060

61+
- the type of struct initializer arrays should not be uword[] but ^^struct[] ?
6162
- implement the remaining TODO's in PointerAssignmentsGen.
6263
- optimize deref in PointerAssignmentsGen: optimize 'forceTemporary' to only use a temporary when the offset is >0
64+
- optimize addUnsignedByteOrWordToAY in PointerAssignmentsGen a bit more
6365
- optimize the float copying in assignIndexedPointer() (also word?)
6466
- implement even more struct instance assignments (via memcopy) in CodeDesugarer (see the TODO) (add to documentation as well, paragraph 'Structs')
65-
- try to optimize pointer arithmetic used in peek/poke a bit more so the routines in sorting module can use typed pointers without increasing code size, see test.p8 in commit d394dc1e
66-
- should @(wordpointer) be equivalent to wordpointer^^ (that would require a LOT of code rewrite that now knows that @() is strictly byte based) ?
67-
or do an implicit cast @(wpointer as ubyte^^) ? And/or add a warning about that?
68-
- optimize addUnsignedByteOrWordToAY in PointerAssignmentsGen a bit more
69-
- support for typed function pointers? (&routine could be typed by default as well then)
7067
- support @nosplit pointer arrays?
7168
- support pointer to pointer?
72-
- the type of struct initializer arrays should not be uword[] but ^^struct[]
69+
- support for typed function pointers? (&routine could be typed by default as well then)
7370
- really fixing the pointer dereferencing issues (cursed hybrid beween IdentifierReference, PtrDereferece and PtrIndexedDereference) may require getting rid of scoped identifiers altogether and treat '.' as a "scope or pointer following operator"
7471
- (later, nasty parser problem:) support chaining pointer dereference on function calls that return a pointer. (type checking now fails on stuff like func().field and func().next.field)
7572

examples/test.p8

Lines changed: 30 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,34 @@
1-
%import textio
2-
%zeropage basicsafe
3-
41
main {
5-
word bignum
6-
7-
struct Node {
8-
ubyte id
9-
str name
10-
bool flag
11-
word counter
12-
}
13-
142
sub start() {
15-
^^Node test = []
16-
bignum = 11111
17-
test.counter = 22222
18-
19-
txt.print_w(bignum)
20-
txt.spc()
21-
bignum++
22-
23-
txt.print_w(bignum)
24-
txt.spc()
25-
bignum--
26-
27-
txt.print_w(bignum)
28-
txt.nl()
29-
30-
txt.print_w(test.counter)
31-
txt.spc()
32-
test.counter ++
33-
34-
txt.print_w(test.counter)
35-
txt.spc()
36-
test.counter --
37-
38-
txt.print_w(test.counter)
39-
txt.nl()
40-
41-
txt.print_w(bignum)
42-
txt.spc()
43-
bignum+=5555
44-
45-
txt.print_w(bignum)
46-
txt.spc()
47-
bignum-=5555
48-
49-
txt.print_w(bignum)
50-
txt.nl()
51-
52-
txt.print_w(test.counter)
53-
txt.spc()
54-
test.counter += 5555
55-
56-
txt.print_w(test.counter)
57-
txt.spc()
58-
test.counter -= 5555
59-
60-
txt.print_w(test.counter)
61-
txt.nl()
3+
^^uword @shared ptr
4+
5+
add1()
6+
add2()
7+
sub1()
8+
sub2()
9+
10+
sub add1() {
11+
ptr += 5
12+
cx16.r0 = ptr + 5
13+
cx16.r0 = peekw(ptr + 5)
14+
}
15+
16+
sub add2() {
17+
ptr += cx16.r0L
18+
cx16.r0 = ptr + cx16.r0L
19+
cx16.r0 = peekw(ptr + cx16.r0L)
20+
}
21+
22+
sub sub1() {
23+
ptr -= 5
24+
cx16.r0 = ptr - 5
25+
cx16.r0 = peekw(ptr - 5)
26+
}
27+
28+
sub sub2() {
29+
ptr -= cx16.r0L
30+
cx16.r0 = ptr - cx16.r0L
31+
cx16.r0 = peekw(ptr - cx16.r0L)
32+
}
6233
}
6334
}

0 commit comments

Comments
 (0)