Skip to content

Commit 46a9b3f

Browse files
committed
Optimize jumps on jumps
This optimization is done at the basic block levels, not using opt templates. When a call/jr/jp jumps to another jr/jp with no condition or with the same condition as its original caller, the labels is updated. So: jp X ... X: jp Y is converted to jp Y Also clean up some iteration over dictionaries.
1 parent d6b9d57 commit 46a9b3f

6 files changed

Lines changed: 140 additions & 3 deletions

File tree

arch/zx48k/optimizer/__init__.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,6 @@ def optimize(initial_memory):
185185
if OPTIONS.optimization.value <= 2: # if -O2 or lower, do nothing and return
186186
return '\n'.join(x for x in initial_memory if not RE_PRAGMA.match(x))
187187

188-
init()
189188
bb = basicblock.BasicBlock(initial_memory)
190189
cleanup_local_labels(bb)
191190
initialize_memory(bb)
@@ -210,6 +209,26 @@ def optimize(initial_memory):
210209
basic_blocks[0].prev = LABELS['*START*'].basic_block
211210
LABELS[END_PROGRAM_LABEL].basic_block.add_goes_to(LABELS['*__END_PROGRAM*'].basic_block)
212211

212+
# In O3 we simplify the graph by reducing jumps over jumps
213+
for label in JUMP_LABELS:
214+
block = LABELS[label].basic_block
215+
if isinstance(block, DummyBasicBlock):
216+
continue
217+
218+
# The instruction that starts this block must be one of jr / jp
219+
first = block.get_first_non_label_instruction()
220+
if first is None or first.inst not in ('jp', 'jr'):
221+
continue
222+
223+
for blk in list(LABELS[label].used_by):
224+
if not first.condition_flag or blk[-1].condition_flag == first.condition_flag:
225+
new_label = first.opers[0]
226+
blk[-1].asm = blk[-1].code.replace(label, new_label)
227+
block.delete_comes_from(blk)
228+
LABELS[label].used_by.remove(blk)
229+
LABELS[new_label].used_by.add(blk)
230+
blk.add_goes_to(LABELS[new_label].basic_block)
231+
213232
for x in basic_blocks:
214233
x.compute_cpu_state()
215234

arch/zx48k/optimizer/basicblock.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -302,10 +302,11 @@ def update_goes_and_comes(self):
302302
return # subroutine returns are updated from CALLer blocks
303303

304304
if oper and oper[0]:
305-
if oper[0] not in LABELS.keys():
305+
if oper[0] not in LABELS:
306306
__DEBUG__("INFO: %s is not defined. No optimization is done." % oper[0], 1)
307307
LABELS[oper[0]] = LabelInfo(oper[0], 0, DummyBasicBlock(ALL_REGS, ALL_REGS))
308308

309+
LABELS[oper[0]].used_by.add(self)
309310
self.add_goes_to(LABELS[oper[0]].basic_block)
310311

311312
if inst in {'djnz', 'jp', 'jr'}:
@@ -651,7 +652,7 @@ def get_basic_blocks(block):
651652
block.delete_goes_to(new_block)
652653

653654
for l in mem.opers:
654-
if l in LABELS.keys():
655+
if l in LABELS:
655656
JUMP_LABELS.add(l)
656657
block.label_goes.append(l)
657658
break
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
org 32768
2+
__START_PROGRAM:
3+
di
4+
push ix
5+
push iy
6+
exx
7+
push hl
8+
exx
9+
ld hl, 0
10+
add hl, sp
11+
ld (__CALL_BACK__), hl
12+
ei
13+
__LABEL__10:
14+
call __LABEL__50
15+
__LABEL__20:
16+
ld a, 1
17+
ld (_a), a
18+
__LABEL__25:
19+
ld bc, 0
20+
__END_PROGRAM:
21+
di
22+
ld hl, (__CALL_BACK__)
23+
ld sp, hl
24+
exx
25+
pop hl
26+
pop iy
27+
pop ix
28+
exx
29+
ei
30+
ret
31+
__CALL_BACK__:
32+
DEFW 0
33+
__LABEL__30:
34+
jp __LABEL__50
35+
__LABEL__40:
36+
ld a, 2
37+
ld (_a), a
38+
__LABEL__50:
39+
ld hl, _a
40+
inc (hl)
41+
__LABEL__60:
42+
ret
43+
ld bc, 0
44+
jp __END_PROGRAM
45+
46+
ZXBASIC_USER_DATA:
47+
_a:
48+
DEFB 00
49+
; Defines DATA END --> HEAP size is 0
50+
ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP
51+
; Defines USER DATA Length in bytes
52+
ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA
53+
END
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
10 GOSUB 30
3+
20 LET a = 1
4+
25 END
5+
30 GOTO 50
6+
40 LET a = 2
7+
50 LET a = a + 1
8+
60 RETURN
9+

tests/functional/opt3_gotogoto.asm

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
org 32768
2+
__START_PROGRAM:
3+
di
4+
push ix
5+
push iy
6+
exx
7+
push hl
8+
exx
9+
ld hl, 0
10+
add hl, sp
11+
ld (__CALL_BACK__), hl
12+
ei
13+
__LABEL__10:
14+
jp __LABEL__50
15+
__LABEL__20:
16+
ld a, 1
17+
ld (_a), a
18+
__LABEL__30:
19+
jp __LABEL__50
20+
__LABEL__40:
21+
ld a, 2
22+
ld (_a), a
23+
__LABEL__50:
24+
ld hl, _a
25+
inc (hl)
26+
ld bc, 0
27+
__END_PROGRAM:
28+
di
29+
ld hl, (__CALL_BACK__)
30+
ld sp, hl
31+
exx
32+
pop hl
33+
pop iy
34+
pop ix
35+
exx
36+
ei
37+
ret
38+
__CALL_BACK__:
39+
DEFW 0
40+
41+
ZXBASIC_USER_DATA:
42+
_a:
43+
DEFB 00
44+
; Defines DATA END --> HEAP size is 0
45+
ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP
46+
; Defines USER DATA Length in bytes
47+
ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA
48+
END

tests/functional/opt3_gotogoto.bas

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
10 GOTO 30
3+
20 LET a = 1
4+
30 GOTO 50
5+
40 LET a = 2
6+
50 LET a = a + 1
7+

0 commit comments

Comments
 (0)