Skip to content

Commit a40b013

Browse files
authored
Merge pull request #565 from boriel/feature/optimize_mul8_and_mul16_for_zxnext
Feature/optimize mul8 and mul16 for zxnext
2 parents 9f2ac65 + a2fa632 commit a40b013

15 files changed

Lines changed: 349 additions & 14 deletions

File tree

src/arch/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
import importlib
66

77

8-
__all__ = ["zx48k", "zxnext"]
8+
__all__ = [
9+
"zx48k",
10+
"zxnext",
11+
]
912

1013
AVAILABLE_ARCHITECTURES = __all__
1114
target = None

src/arch/z80/backend/__init__.py

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -128,18 +128,25 @@
128128
__all__ = [
129129
"tmp_label",
130130
"_fpop",
131+
"HI16",
132+
"INITS",
133+
"LO16",
131134
"LABEL_COUNTER",
132135
"MEMORY",
136+
"MEMINITS",
137+
"QUADS",
138+
"REQUIRES",
133139
"TMP_COUNTER",
134140
"TMP_STORAGES",
135-
"HI16",
136-
"LO16",
141+
"emit",
142+
"emit_end",
143+
"emit_start",
137144
]
138145

139146
# Default code ORG
140-
OPTIONS(Action.ADD, name="org", type=int, default=32768)
147+
OPTIONS(Action.ADD_IF_NOT_DEFINED, name="org", type=int, default=32768)
141148
# Default HEAP SIZE (Dynamic memory) in bytes
142-
OPTIONS(Action.ADD, name="heap_size", type=int, default=4768, ignore_none=True) # A bit more than 4K
149+
OPTIONS(Action.ADD_IF_NOT_DEFINED, name="heap_size", type=int, default=4768, ignore_none=True) # A bit more than 4K
143150

144151

145152
def init():
@@ -148,15 +155,15 @@ def init():
148155
common.init()
149156

150157
# Default code ORG
151-
OPTIONS(Action.ADD, name="org", type=int, default=32768)
158+
OPTIONS(Action.ADD_IF_NOT_DEFINED, name="org", type=int, default=32768)
152159
# Default HEAP SIZE (Dynamic memory) in bytes
153-
OPTIONS(Action.ADD, name="heap_size", type=int, default=4768, ignore_none=True) # A bit more than 4K
160+
OPTIONS(Action.ADD_IF_NOT_DEFINED, name="heap_size", type=int, default=4768, ignore_none=True) # A bit more than 4K
154161
# Labels for HEAP START (might not be used if not needed)
155-
OPTIONS(Action.ADD, name="heap_start_label", type=str, default=f"{NAMESPACE}.ZXBASIC_MEM_HEAP")
162+
OPTIONS(Action.ADD_IF_NOT_DEFINED, name="heap_start_label", type=str, default=f"{NAMESPACE}.ZXBASIC_MEM_HEAP")
156163
# Labels for HEAP SIZE (might not be used if not needed)
157-
OPTIONS(Action.ADD, name="heap_size_label", type=str, default=f"{NAMESPACE}.ZXBASIC_HEAP_SIZE")
164+
OPTIONS(Action.ADD_IF_NOT_DEFINED, name="heap_size_label", type=str, default=f"{NAMESPACE}.ZXBASIC_HEAP_SIZE")
158165
# Flag for headerless mode (No prologue / epilogue)
159-
OPTIONS(Action.ADD, name="headerless", type=bool, default=False, ignore_none=True)
166+
OPTIONS(Action.ADD_IF_NOT_DEFINED, name="headerless", type=bool, default=False, ignore_none=True)
160167

161168
engine.main() # inits the optimizer
162169

src/arch/zx48k/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from src.arch.z80 import beep
66
from src.arch.z80.translator import * # noqa
7-
from src.arch.z80 import backend # noqa
7+
from src.arch.zx48k import backend # noqa
88
from src.arch.z80 import optimizer # noqa
99

1010

src/arch/zx48k/backend/__init__.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# -*- coding: utf-8 -*-
2+
3+
from src.api.config import OPTIONS
4+
from src.arch.z80 import backend
5+
6+
from src.arch.z80.backend import tmp_label, _fpop, HI16, INITS, LO16, LABEL_COUNTER, MEMORY, MEMINITS
7+
from src.arch.z80.backend import QUADS, REQUIRES, TMP_COUNTER, TMP_STORAGES
8+
from src.arch.z80.backend import emit, emit_end, emit_start
9+
10+
11+
__all__ = [
12+
"tmp_label",
13+
"_fpop",
14+
"HI16",
15+
"INITS",
16+
"LO16",
17+
"LABEL_COUNTER",
18+
"MEMORY",
19+
"MEMINITS",
20+
"QUADS",
21+
"REQUIRES",
22+
"TMP_COUNTER",
23+
"TMP_STORAGES",
24+
"emit",
25+
"emit_end",
26+
"emit_start",
27+
]
28+
29+
30+
# ZXNext asm enabled by default for this arch
31+
OPTIONS.zxnext = False
32+
33+
34+
def init():
35+
# ZXNext asm enabled by default for this arch
36+
OPTIONS.zxnext = False
37+
38+
backend.init()

src/arch/zxnext/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from src.arch.z80 import beep
66
from src.arch.z80.translator import * # noqa
7-
from src.arch.z80 import backend # noqa
7+
from src.arch.zxnext import backend # noqa
88
from src.arch.z80 import optimizer # noqa
99

1010

src/arch/zxnext/backend/_8bit.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# -*- coding: utf-8 -*-
2+
3+
4+
from typing import List
5+
6+
from src.arch.z80.backend import Quad
7+
from src.arch.z80.backend._8bit import _8bit_oper, int8
8+
from src.arch.z80.backend.common import _int_ops
9+
10+
11+
def _mul8(ins: Quad) -> List[str]:
12+
"""Multiplies 2 las values from the stack.
13+
14+
Optimizations:
15+
* If any of the ops is ZERO,
16+
then do A = 0 ==> XOR A, cause A * 0 = 0 * A = 0
17+
18+
* If any ot the ops is ONE, do NOTHING
19+
A * 1 = 1 * A = A
20+
"""
21+
22+
op1, op2 = tuple(ins.quad[2:])
23+
if _int_ops(op1, op2) is not None:
24+
op1, op2 = _int_ops(op1, op2)
25+
26+
output = _8bit_oper(op1)
27+
28+
if op2 == 0:
29+
output.append("xor a")
30+
output.append("push af")
31+
return output
32+
33+
if op2 == 1: # A * 1 = 1 * A = A
34+
output.append("push af")
35+
return output
36+
37+
if op2 == 2: # A * 2 == A SLA 1
38+
output.append("add a, a")
39+
output.append("push af")
40+
return output
41+
42+
if op2 == 4: # A * 4 == A SLA 2
43+
output.append("add a, a")
44+
output.append("add a, a")
45+
output.append("push af")
46+
return output
47+
48+
output.append("ld h, %i" % int8(op2))
49+
else:
50+
if op2[0] == "_": # stack optimization
51+
op1, op2 = op2, op1
52+
53+
output = _8bit_oper(op1, op2)
54+
55+
output.append("ld d, h") # Immediate
56+
output.append("ld e, a")
57+
output.append("mul d, e")
58+
output.append("ld a, e")
59+
output.append("push af")
60+
return output
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# -*- coding: utf-8 -*-
2+
3+
from src.api.config import OPTIONS
4+
from src.arch.z80 import backend
5+
from src.arch.z80.backend import ICInfo
6+
7+
from src.arch.zxnext.backend._8bit import _mul8
8+
9+
from src.arch.z80.backend import tmp_label, _fpop, HI16, INITS, LO16, LABEL_COUNTER, MEMORY, MEMINITS
10+
from src.arch.z80.backend import QUADS, REQUIRES, TMP_COUNTER, TMP_STORAGES
11+
from src.arch.z80.backend import emit, emit_end, emit_start
12+
13+
14+
__all__ = [
15+
"tmp_label",
16+
"_fpop",
17+
"HI16",
18+
"INITS",
19+
"LO16",
20+
"LABEL_COUNTER",
21+
"MEMORY",
22+
"MEMINITS",
23+
"QUADS",
24+
"REQUIRES",
25+
"TMP_COUNTER",
26+
"TMP_STORAGES",
27+
"emit",
28+
"emit_end",
29+
"emit_start",
30+
]
31+
32+
33+
# ZXNext asm enabled by default for this arch
34+
OPTIONS.zxnext = True
35+
36+
37+
# Override z80 generic implementation with ZX Next ones
38+
QUADS.update({"muli8": ICInfo(3, _mul8), "mulu8": ICInfo(3, _mul8)})
39+
40+
41+
def init():
42+
# ZXNext asm enabled by default for this arch
43+
OPTIONS.zxnext = True
44+
45+
backend.init()

src/zxbc/zxbc.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ def main(args=None, emitter=None):
8787
options = parse_options(args)
8888
arch.set_target_arch(OPTIONS.architecture)
8989
backend = arch.target.backend
90+
backend.init() # Must reinitialize it again
91+
9092
args = [options.PROGRAM] # Strip out other options, because they're already set in the OPTIONS container
9193
input_filename = options.PROGRAM
9294

tests/functional/test.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
EXIT_CODE = 0
2323
FILTER = r"^(([ \t]*;)|(#[ \t]*line))"
24+
DEFAULT_ARCH = "zx48k" # Default testing architecture
2425

2526
# Global tests and failed counters
2627
COUNTER = 0
@@ -226,6 +227,9 @@ def _get_testbas_options(fname: str):
226227
prep = ["-e", "/dev/null"] if CLOSE_STDERR else ["-e", STDERR]
227228
options = ["-O1"]
228229

230+
arch = os.path.dirname(fname).split(os.path.sep)[-1] or DEFAULT_ARCH
231+
options.extend(["--arch", arch])
232+
229233
match = reOPT.match(getName(fname))
230234
if match:
231235
options = ["-O" + match.groups()[0]]
@@ -595,7 +599,7 @@ def main(argv=None):
595599
parser.add_argument("-e", "--stderr", type=str, default=None, help="File for stderr messages")
596600
parser.add_argument("-S", "--use-shell", action="store_true", help="Use system shell for test instead of inline")
597601
parser.add_argument(
598-
"-O", "--option", action="append", help="Option to pass to compiler in a test " "(can be used many times)"
602+
"-O", "--option", action="append", help="Option to pass to compiler in a test (can be used many times)"
599603
)
600604
parser.add_argument(
601605
"-E",
@@ -625,7 +629,7 @@ def main(argv=None):
625629
TIMEOUT = 0 # disable timeout for Vim-dif
626630

627631
temp_dir_created = set_temp_dir(args.tmp_dir)
628-
files = {fname for pattern in args.FILES for fname in glob.glob(pattern, recursive=True)}
632+
files = sorted({fname for pattern in args.FILES for fname in glob.glob(pattern, recursive=True)})
629633

630634
if args.update:
631635
upgradeTest(files, args.update)

tests/functional/zxnext/muli8.asm

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
org 32768
2+
.core.__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 (.core.__CALL_BACK__), hl
12+
ei
13+
jp .core.__MAIN_PROGRAM__
14+
.core.__CALL_BACK__:
15+
DEFW 0
16+
.core.ZXBASIC_USER_DATA:
17+
; Defines USER DATA Length in bytes
18+
.core.ZXBASIC_USER_DATA_LEN EQU .core.ZXBASIC_USER_DATA_END - .core.ZXBASIC_USER_DATA
19+
.core.__LABEL__.ZXBASIC_USER_DATA_LEN EQU .core.ZXBASIC_USER_DATA_LEN
20+
.core.__LABEL__.ZXBASIC_USER_DATA EQU .core.ZXBASIC_USER_DATA
21+
_a:
22+
DEFB 00
23+
.core.ZXBASIC_USER_DATA_END:
24+
.core.__MAIN_PROGRAM__:
25+
ld a, (_a)
26+
ld h, 3
27+
ld d, h
28+
ld e, a
29+
mul d, e
30+
ld a, e
31+
ld (_a), a
32+
ld hl, 0
33+
ld b, h
34+
ld c, l
35+
.core.__END_PROGRAM:
36+
di
37+
ld hl, (.core.__CALL_BACK__)
38+
ld sp, hl
39+
exx
40+
pop hl
41+
exx
42+
pop iy
43+
pop ix
44+
ei
45+
ret
46+
;; --- end of user code ---
47+
END

0 commit comments

Comments
 (0)