jukefa-asmgen 0.6.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (197) hide show
  1. asmgen/__init__.py +5 -0
  2. asmgen/asmblocks/__init__.py +8 -0
  3. asmgen/asmblocks/aarch64/__init__.py +9 -0
  4. asmgen/asmblocks/aarch64/gen.py +259 -0
  5. asmgen/asmblocks/aarch64/opmem/__init__.py +11 -0
  6. asmgen/asmblocks/aarch64/opmem/base.py +182 -0
  7. asmgen/asmblocks/aarch64/opmem/load.py +21 -0
  8. asmgen/asmblocks/aarch64/opmem/prefetch.py +40 -0
  9. asmgen/asmblocks/aarch64/opmem/signatures.py +134 -0
  10. asmgen/asmblocks/aarch64/opmem/store.py +21 -0
  11. asmgen/asmblocks/aarch64/opmove/__init__.py +22 -0
  12. asmgen/asmblocks/aarch64/opset/__init__.py +4 -0
  13. asmgen/asmblocks/aarch64/opset/base.py +66 -0
  14. asmgen/asmblocks/aarch64/opset/signatures.py +11 -0
  15. asmgen/asmblocks/aarch64/optransform/__init__.py +9 -0
  16. asmgen/asmblocks/aarch64/optransform/base.py +218 -0
  17. asmgen/asmblocks/aarch64/optransform/scalar.py +81 -0
  18. asmgen/asmblocks/aarch64/types.py +78 -0
  19. asmgen/asmblocks/avx/__init__.py +9 -0
  20. asmgen/asmblocks/avx/avx2.py +146 -0
  21. asmgen/asmblocks/avx/avx512.py +149 -0
  22. asmgen/asmblocks/avx/base.py +456 -0
  23. asmgen/asmblocks/avx/gen.py +12 -0
  24. asmgen/asmblocks/avx/opmem/__init__.py +10 -0
  25. asmgen/asmblocks/avx/opmem/base.py +482 -0
  26. asmgen/asmblocks/avx/opmem/load.py +43 -0
  27. asmgen/asmblocks/avx/opmem/signatures.py +190 -0
  28. asmgen/asmblocks/avx/opmem/store.py +75 -0
  29. asmgen/asmblocks/avx/opmove/__init__.py +4 -0
  30. asmgen/asmblocks/avx/opmove/base.py +114 -0
  31. asmgen/asmblocks/avx/opmove/signatures.py +94 -0
  32. asmgen/asmblocks/avx/opset/__init__.py +4 -0
  33. asmgen/asmblocks/avx/opset/base.py +93 -0
  34. asmgen/asmblocks/avx/opset/signatures.py +31 -0
  35. asmgen/asmblocks/avx/optransform/__init__.py +11 -0
  36. asmgen/asmblocks/avx/optransform/add.py +36 -0
  37. asmgen/asmblocks/avx/optransform/base.py +140 -0
  38. asmgen/asmblocks/avx/optransform/fma.py +20 -0
  39. asmgen/asmblocks/avx/optransform/mul.py +36 -0
  40. asmgen/asmblocks/avx/optransform/signatures.py +54 -0
  41. asmgen/asmblocks/avx/setup.py +21 -0
  42. asmgen/asmblocks/avx/types.py +115 -0
  43. asmgen/asmblocks/neon/__init__.py +9 -0
  44. asmgen/asmblocks/neon/gen.py +168 -0
  45. asmgen/asmblocks/neon/opmem/__init__.py +10 -0
  46. asmgen/asmblocks/neon/opmem/base.py +318 -0
  47. asmgen/asmblocks/neon/opmem/load.py +21 -0
  48. asmgen/asmblocks/neon/opmem/signatures.py +178 -0
  49. asmgen/asmblocks/neon/opmem/store.py +20 -0
  50. asmgen/asmblocks/neon/opmove/__init__.py +4 -0
  51. asmgen/asmblocks/neon/opmove/base.py +80 -0
  52. asmgen/asmblocks/neon/opmove/signatures.py +78 -0
  53. asmgen/asmblocks/neon/opset/__init__.py +4 -0
  54. asmgen/asmblocks/neon/opset/base.py +33 -0
  55. asmgen/asmblocks/neon/opset/signatures.py +18 -0
  56. asmgen/asmblocks/neon/optransform/__init__.py +11 -0
  57. asmgen/asmblocks/neon/optransform/add.py +39 -0
  58. asmgen/asmblocks/neon/optransform/base.py +67 -0
  59. asmgen/asmblocks/neon/optransform/fma.py +37 -0
  60. asmgen/asmblocks/neon/optransform/mul.py +46 -0
  61. asmgen/asmblocks/neon/optransform/signatures.py +185 -0
  62. asmgen/asmblocks/neon/types.py +23 -0
  63. asmgen/asmblocks/noarch.py +811 -0
  64. asmgen/asmblocks/op/__init__.py +44 -0
  65. asmgen/asmblocks/op/constraint.py +441 -0
  66. asmgen/asmblocks/op/domain.py +275 -0
  67. asmgen/asmblocks/op/misc.py +17 -0
  68. asmgen/asmblocks/op/modifier.py +15 -0
  69. asmgen/asmblocks/op/operand.py +129 -0
  70. asmgen/asmblocks/op/operation.py +296 -0
  71. asmgen/asmblocks/op/opmem.py +163 -0
  72. asmgen/asmblocks/op/opmove.py +151 -0
  73. asmgen/asmblocks/op/opset.py +370 -0
  74. asmgen/asmblocks/op/optransform.py +154 -0
  75. asmgen/asmblocks/op/scalar.py +223 -0
  76. asmgen/asmblocks/op/shift.py +90 -0
  77. asmgen/asmblocks/op/signature.py +211 -0
  78. asmgen/asmblocks/riscv64/__init__.py +9 -0
  79. asmgen/asmblocks/riscv64/gen.py +222 -0
  80. asmgen/asmblocks/riscv64/opmem/__init__.py +11 -0
  81. asmgen/asmblocks/riscv64/opmem/base.py +150 -0
  82. asmgen/asmblocks/riscv64/opmem/load.py +20 -0
  83. asmgen/asmblocks/riscv64/opmem/prefetch.py +40 -0
  84. asmgen/asmblocks/riscv64/opmem/signatures.py +99 -0
  85. asmgen/asmblocks/riscv64/opmem/store.py +20 -0
  86. asmgen/asmblocks/riscv64/opmove/__init__.py +20 -0
  87. asmgen/asmblocks/riscv64/opset/__init__.py +4 -0
  88. asmgen/asmblocks/riscv64/opset/base.py +24 -0
  89. asmgen/asmblocks/riscv64/opset/signatures.py +11 -0
  90. asmgen/asmblocks/riscv64/optransform/__init__.py +67 -0
  91. asmgen/asmblocks/riscv64/types.py +68 -0
  92. asmgen/asmblocks/rvv/__init__.py +9 -0
  93. asmgen/asmblocks/rvv/gen.py +191 -0
  94. asmgen/asmblocks/rvv/opmem/__init__.py +10 -0
  95. asmgen/asmblocks/rvv/opmem/base.py +301 -0
  96. asmgen/asmblocks/rvv/opmem/load.py +27 -0
  97. asmgen/asmblocks/rvv/opmem/signatures.py +214 -0
  98. asmgen/asmblocks/rvv/opmem/store.py +24 -0
  99. asmgen/asmblocks/rvv/opmove/__init__.py +4 -0
  100. asmgen/asmblocks/rvv/opmove/base.py +79 -0
  101. asmgen/asmblocks/rvv/opmove/signatures.py +77 -0
  102. asmgen/asmblocks/rvv/opset/__init__.py +4 -0
  103. asmgen/asmblocks/rvv/opset/base.py +54 -0
  104. asmgen/asmblocks/rvv/opset/signatures.py +18 -0
  105. asmgen/asmblocks/rvv/optransform/__init__.py +11 -0
  106. asmgen/asmblocks/rvv/optransform/add.py +22 -0
  107. asmgen/asmblocks/rvv/optransform/base.py +198 -0
  108. asmgen/asmblocks/rvv/optransform/fma.py +30 -0
  109. asmgen/asmblocks/rvv/optransform/mul.py +22 -0
  110. asmgen/asmblocks/rvv/optransform/signatures.py +116 -0
  111. asmgen/asmblocks/rvv/setup.py +82 -0
  112. asmgen/asmblocks/rvv/types.py +24 -0
  113. asmgen/asmblocks/rvv071/__init__.py +9 -0
  114. asmgen/asmblocks/rvv071/gen.py +90 -0
  115. asmgen/asmblocks/rvv071/opmem.py +61 -0
  116. asmgen/asmblocks/rvv071/opmove.py +33 -0
  117. asmgen/asmblocks/rvv071/setup.py +18 -0
  118. asmgen/asmblocks/setup.py +168 -0
  119. asmgen/asmblocks/sme/__init__.py +9 -0
  120. asmgen/asmblocks/sme/gen.py +115 -0
  121. asmgen/asmblocks/sme/opmem/__init__.py +10 -0
  122. asmgen/asmblocks/sme/opmem/base.py +247 -0
  123. asmgen/asmblocks/sme/opmem/load.py +21 -0
  124. asmgen/asmblocks/sme/opmem/signatures.py +199 -0
  125. asmgen/asmblocks/sme/opmem/store.py +21 -0
  126. asmgen/asmblocks/sme/opmove/__init__.py +10 -0
  127. asmgen/asmblocks/sme/opmove/base.py +188 -0
  128. asmgen/asmblocks/sme/opmove/signatures.py +248 -0
  129. asmgen/asmblocks/sme/opset/__init__.py +4 -0
  130. asmgen/asmblocks/sme/opset/base.py +31 -0
  131. asmgen/asmblocks/sme/opset/signatures.py +16 -0
  132. asmgen/asmblocks/sme/optransform/__init__.py +10 -0
  133. asmgen/asmblocks/sme/optransform/fopa.py +108 -0
  134. asmgen/asmblocks/sme/optransform/signatures.py +118 -0
  135. asmgen/asmblocks/sme/setup.py +68 -0
  136. asmgen/asmblocks/sme/types.py +35 -0
  137. asmgen/asmblocks/sve/__init__.py +9 -0
  138. asmgen/asmblocks/sve/gen.py +161 -0
  139. asmgen/asmblocks/sve/opmem/__init__.py +10 -0
  140. asmgen/asmblocks/sve/opmem/base.py +249 -0
  141. asmgen/asmblocks/sve/opmem/load.py +23 -0
  142. asmgen/asmblocks/sve/opmem/signatures.py +192 -0
  143. asmgen/asmblocks/sve/opmem/store.py +21 -0
  144. asmgen/asmblocks/sve/opmove/__init__.py +11 -0
  145. asmgen/asmblocks/sve/opmove/base.py +120 -0
  146. asmgen/asmblocks/sve/opmove/signatures.py +130 -0
  147. asmgen/asmblocks/sve/opset/__init__.py +4 -0
  148. asmgen/asmblocks/sve/opset/base.py +52 -0
  149. asmgen/asmblocks/sve/opset/signatures.py +31 -0
  150. asmgen/asmblocks/sve/optransform/__init__.py +11 -0
  151. asmgen/asmblocks/sve/optransform/add.py +39 -0
  152. asmgen/asmblocks/sve/optransform/base.py +44 -0
  153. asmgen/asmblocks/sve/optransform/fma.py +19 -0
  154. asmgen/asmblocks/sve/optransform/mul.py +40 -0
  155. asmgen/asmblocks/sve/optransform/scalar.py +20 -0
  156. asmgen/asmblocks/sve/optransform/signatures.py +189 -0
  157. asmgen/asmblocks/sve/setup.py +48 -0
  158. asmgen/asmblocks/sve/types.py +39 -0
  159. asmgen/asmblocks/x86/__init__.py +8 -0
  160. asmgen/asmblocks/x86/opmem/__init__.py +11 -0
  161. asmgen/asmblocks/x86/opmem/base.py +162 -0
  162. asmgen/asmblocks/x86/opmem/displacement.py +57 -0
  163. asmgen/asmblocks/x86/opmem/load.py +23 -0
  164. asmgen/asmblocks/x86/opmem/prefetch.py +41 -0
  165. asmgen/asmblocks/x86/opmem/signatures.py +129 -0
  166. asmgen/asmblocks/x86/opmem/store.py +23 -0
  167. asmgen/asmblocks/x86/opmove/__init__.py +28 -0
  168. asmgen/asmblocks/x86/opset/__init__.py +4 -0
  169. asmgen/asmblocks/x86/opset/base.py +51 -0
  170. asmgen/asmblocks/x86/opset/signatures.py +11 -0
  171. asmgen/asmblocks/x86/optransform/__init__.py +109 -0
  172. asmgen/asmblocks/x86/types.py +95 -0
  173. asmgen/asmdata.py +141 -0
  174. asmgen/benchmark/__init__.py +5 -0
  175. asmgen/benchmark/extra_sources.py +11 -0
  176. asmgen/callconv/__init__.py +0 -0
  177. asmgen/callconv/callconv.py +353 -0
  178. asmgen/callconv/fngen.py +164 -0
  179. asmgen/compilation/__init__.py +5 -0
  180. asmgen/compilation/compiler_presets.py +127 -0
  181. asmgen/compilation/tools.py +164 -0
  182. asmgen/cppgen/__init__.py +5 -0
  183. asmgen/cppgen/analyzers.py +29 -0
  184. asmgen/cppgen/checkers.py +162 -0
  185. asmgen/cppgen/declarations.py +209 -0
  186. asmgen/cppgen/expressions.py +62 -0
  187. asmgen/cppgen/templates.py +163 -0
  188. asmgen/cppgen/types.py +25 -0
  189. asmgen/cppgen/writers.py +84 -0
  190. asmgen/emulation.py +186 -0
  191. asmgen/registers.py +605 -0
  192. asmgen/util.py +10 -0
  193. jukefa_asmgen-0.6.0.dist-info/METADATA +50 -0
  194. jukefa_asmgen-0.6.0.dist-info/RECORD +197 -0
  195. jukefa_asmgen-0.6.0.dist-info/WHEEL +4 -0
  196. jukefa_asmgen-0.6.0.dist-info/licenses/LICENSE-GPL-3.0 +674 -0
  197. jukefa_asmgen-0.6.0.dist-info/licenses/LICENSE-MIT +21 -0
asmgen/__init__.py ADDED
@@ -0,0 +1,5 @@
1
+ # ------------------------------------------------------------------------------
2
+ # SPDX-License-Identifier: MIT OR GPL-3.0-or-later
3
+ # Copyright (C) 2021 Stepan Nassyr <s.nassyr@fz-juelich.de>
4
+ # Copyright (C) 2021 Stepan Nassyr <s.nassyr@xcpp.org>
5
+ # ------------------------------------------------------------------------------
@@ -0,0 +1,8 @@
1
+ # ------------------------------------------------------------------------------
2
+ # SPDX-License-Identifier: MIT OR GPL-3.0-or-later
3
+ # Copyright (C) 2021 Stepan Nassyr <s.nassyr@fz-juelich.de>
4
+ # Copyright (C) 2021 Stepan Nassyr <s.nassyr@xcpp.org>
5
+ # ------------------------------------------------------------------------------
6
+ """
7
+ Module containing ASM generator abstract class and implementations for different ISAs
8
+ """
@@ -0,0 +1,9 @@
1
+ # ------------------------------------------------------------------------------
2
+ # SPDX-License-Identifier: MIT OR GPL-3.0-or-later
3
+ # Copyright (C) 2021 Stepan Nassyr <s.nassyr@fz-juelich.de>
4
+ # Copyright (C) 2021 Stepan Nassyr <s.nassyr@xcpp.org>
5
+ # ------------------------------------------------------------------------------
6
+ """
7
+ AArch64 asm generator, register types and scalar memory ops
8
+ """
9
+ from .gen import aarch64
@@ -0,0 +1,259 @@
1
+ # ------------------------------------------------------------------------------
2
+ # SPDX-License-Identifier: MIT OR GPL-3.0-or-later
3
+ # Copyright (C) 2021 Stepan Nassyr <s.nassyr@fz-juelich.de>
4
+ # Copyright (C) 2021 Stepan Nassyr <s.nassyr@xcpp.org>
5
+ # ------------------------------------------------------------------------------
6
+ """
7
+ ARM64/AArch64 asm generator and related types
8
+ """
9
+
10
+ from copy import deepcopy
11
+ from typing import Union
12
+
13
+ from ..noarch import compiler_family
14
+ from ..noarch import asmgen,comparison
15
+ from ...registers import (
16
+ adt_size,
17
+
18
+ asm_data_type as adt,
19
+ greg_base, freg_base
20
+ )
21
+
22
+ from .types import aarch64_greg,aarch64_freg
23
+ from ...callconv.callconv import callconv
24
+
25
+ from .opmem import aarch64_load, aarch64_store
26
+ from .opmem import aarch64_prefetch
27
+ from ...registers import asm_data_type as _ADT
28
+ from ..op.operand import operand_modifier as _opd_mod
29
+ from ..op.opmove import opmove_modifier as _move_mod
30
+ from ..op.scalar import BITS_GP as _BITS_GP
31
+ from ..op.opset import opset_modifier as _opset_mod
32
+ from ..op.optransform import optransform_modifier as _opd3_mod
33
+
34
+ _GP = _ADT.UINT64 # general registers' arithmetic: 64-bit
35
+
36
+ class aarch64(asmgen):
37
+ """
38
+ ARM64/AArch64 asmgen implementation
39
+ """
40
+
41
+ #: -march's base, and the features as its extensions (per backend)
42
+ MARCH_BASE = "armv8-a"
43
+ MARCH_EXTENSIONS : dict[str, str] = {}
44
+
45
+ def compiler_flags(self, compiler : str = "gcc") -> list[str]:
46
+ compiler_family(compiler)
47
+ enabled = self.enabled_features()
48
+ extensions = [self.MARCH_EXTENSIONS[f] for f in self.FEATURES
49
+ if f in enabled and f in self.MARCH_EXTENSIONS]
50
+ return ["-march=" + "+".join([self.MARCH_BASE] + extensions)]
51
+
52
+ #: the nop: nop
53
+ NOP_BYTES = 4
54
+ NOP_ENCODING = 0xd503201f
55
+
56
+ dt_greg_pfx = {
57
+ adt.DOUBLE : "x",
58
+ adt.SINGLE : "w",
59
+ }
60
+
61
+ cb_insts = {
62
+ 'NZ' : 'cbnz',
63
+ 'EZ' : 'cbz',
64
+ 'NE' : 'b.ne',
65
+ 'EQ' : 'b.eq',
66
+ 'LE' : 'b.le',
67
+ 'GE' : 'b.ge',
68
+ 'LT' : 'b.lt',
69
+ 'GT' : 'b.gt',
70
+ }
71
+
72
+ def __init__(self):
73
+ super().__init__()
74
+ self.callconvs = {
75
+ "aapcs64" : callconv(
76
+ param_regs={ 'greg' : list(range(0, 8)),
77
+ 'freg' : list(range(0, 8))},
78
+ caller_save_lists={ 'greg' : list(range(0, 8)) + # func args/return vals
79
+ [8] + # XR, indirect result reg
80
+ list(range(9,16)) + # locals
81
+ [18] # platform reg
82
+ ,
83
+ 'freg' : list(range(0, 8)) +
84
+ list(range(16,32))
85
+ },
86
+ callee_save_lists={ 'greg' : list(range(19,29)) + # Callee-saved
87
+ [29, # Frame Pointer
88
+ 30 # Link Register
89
+ ] +
90
+ [31], # SP
91
+ 'freg' : list(range(8,16))},
92
+ spreg=31)
93
+ }
94
+ self.load = aarch64_load(asmwrap=self.asmwrap)
95
+ self.store = aarch64_store(asmwrap=self.asmwrap)
96
+ self.prefetch = aarch64_prefetch(asmwrap=self.asmwrap)
97
+ self.default_callconv = "aapcs64"
98
+
99
+ def create_callconv(self, name : str = "default"):
100
+
101
+ if "default" == name:
102
+ name = self.default_callconv
103
+
104
+ return deepcopy(self.callconvs[name])
105
+
106
+ def label(self, *, label : str) -> str:
107
+ return self.asmwrap(f"{self.labelstr(label)}:")
108
+
109
+ def jump(self, *, label : str) -> str:
110
+ return self.asmwrap(f"b {self.labelstr(label)}")
111
+
112
+ def loopbegin(self, *, reg : greg_base,
113
+ label : str) -> str:
114
+ asmblock = self.asmwrap(f"{self.labelstr(label)}:")
115
+ asmblock += self.asmwrap(f"sub {reg},{reg},1")
116
+ return asmblock
117
+
118
+ def loopbegin_nz(self, *, reg : greg_base,
119
+ label : str,
120
+ labelskip : str) -> str:
121
+ asmblock = self.asmwrap(f"cmp {reg},0")
122
+ asmblock += self.asmwrap(f"b.eq {self.labelstr(labelskip)}")
123
+ asmblock += self.asmwrap(f"{self.labelstr(label)}:")
124
+ asmblock += self.asmwrap(f"sub {reg},{reg},1")
125
+ return asmblock
126
+
127
+ def loopend(self, *, reg : greg_base,
128
+ label : str) -> str:
129
+ asmblock = self.asmwrap(f"cmp {reg},0")
130
+ asmblock += self.asmwrap(f"b.ne {self.labelstr(label)}")
131
+ return asmblock
132
+
133
+ def fcb(self, *, reg1, reg2, cmp: comparison, label: str, dt: adt, greg=None) -> str:
134
+ """
135
+ cb on FP registers: equality as floating point, so -0.0 equals 0.0
136
+ and NaN equals nothing
137
+ """
138
+ insts = {'EQ': 'b.eq', 'EZ': 'b.eq', 'NE': 'b.ne', 'NZ': 'b.ne',
139
+ 'LT': 'b.mi', 'LE': 'b.ls', 'GT': 'b.gt', 'GE': 'b.ge'}
140
+ other = reg2 if reg2 is not None else "#0.0"
141
+ return self.asmwrap(f"fcmp {reg1},{other}") + \
142
+ self.asmwrap(f"{insts[cmp.name]} {self.labelstr(label)}")
143
+
144
+ def cb(self, *, reg1, reg2, cmp: comparison, label: str,
145
+ dt: adt | None = None, greg: greg_base | None = None) -> str:
146
+ if isinstance(reg1, freg_base):
147
+ return self.fcb(reg1=reg1, reg2=reg2, cmp=cmp, label=label, dt=dt, greg=greg)
148
+ inst = self.cb_insts[cmp.name]
149
+ if reg2 is None:
150
+ return self.asmwrap(f"{inst} {reg1},{self.labelstr(label)}")
151
+
152
+ return self.asmwrap(f"cmp {reg1},{reg2}")+\
153
+ self.asmwrap(f"{inst} {self.labelstr(label)}")
154
+
155
+ def jzero(self, *, reg : greg_base,
156
+ label : str) -> str:
157
+ asmblock = self.asmwrap(f"cmp {reg},0")
158
+ asmblock += self.asmwrap(f"b.eq {self.labelstr(label)}")
159
+ return asmblock
160
+
161
+ def jfzero(self, *, freg1 : freg_base, freg2 : freg_base,
162
+ greg : greg_base, label : str,
163
+ dt : adt):
164
+ asmblock = self.asmwrap(f"fcmp {freg1},#0.0")
165
+ asmblock += self.asmwrap(f"b.eq {self.labelstr(label)}")
166
+ return asmblock
167
+
168
+ def shared_registers(self) -> list[tuple[str, str, dict[int, int] | None]]:
169
+ # a scalar FP register is the low part of the vector register
170
+ return [("freg", "vreg", None)]
171
+
172
+ def reserved_registers(self) -> dict[str, dict[str, int]]:
173
+ # x18 is the platform register on Apple and Windows
174
+ return {"greg": {"sp": 31, "lr": 30, "fp": 29, "platform": 18}}
175
+ def max_gregs(self):
176
+ return 32
177
+ def max_mregs(self):
178
+ return 0
179
+ def max_fregs(self):
180
+ return 32
181
+
182
+ def kiterkleft_pow2(self, *, kreg : greg_base,
183
+ kleftreg : greg_base,
184
+ unroll : int) -> str:
185
+ """
186
+ kiterkleft variant for unroll values that are powers of 2
187
+
188
+ Can be simplified down to a "right shift" and "and"
189
+ """
190
+
191
+ asmblock = ""
192
+
193
+ unrollpower = unroll.bit_length()-1
194
+
195
+ # Example unroll=4: kleft = k & 0b0111
196
+ asmblock += self.asmwrap(f"and {kleftreg},{kreg},#{unroll-1}")
197
+ # Example unroll=4: k = k >> 2
198
+ asmblock += self.shift(adreg=kreg, bimm=unrollpower, cdreg=kreg, a_dt=_GP, c_dt=_GP, modifiers={_opd3_mod.SHR})
199
+
200
+ return asmblock
201
+
202
+ def kiterkleft(self, *, kreg : greg_base,
203
+ kleftreg : greg_base,
204
+ tmpreg : greg_base,
205
+ unroll : int) -> str:
206
+
207
+ if unroll.bit_count() == 1:
208
+ return self.kiterkleft_pow2(kreg=kreg,kleftreg=kleftreg,unroll=unroll)
209
+
210
+ # TODO: Division by invariant multiplication (the naive attempt below fails,
211
+ # need to read up on it)
212
+
213
+ # runroll = (1<<64) // unroll
214
+ # shift = 64 - unroll.bit_length()
215
+ # asmblock = ""
216
+
217
+ # # Move reciprocal into tmpreg
218
+ # asmblock += self.asmwrap(f"mov {tmpreg}, #{(runroll >> 0) & 0xFFFF}")
219
+ # asmblock += self.asmwrap(f"movk {tmpreg}, #{(runroll >> 16) & 0xFFFF}, lsl 16")
220
+ # asmblock += self.asmwrap(f"movk {tmpreg}, #{(runroll >> 32) & 0xFFFF}, lsl 32")
221
+ # asmblock += self.asmwrap(f"movk {tmpreg}, #{(runroll >> 48) & 0xFFFF}, lsl 48")
222
+
223
+
224
+ # # tmp = k // unroll
225
+ # asmblock += self.mul_greg_greg(dst=tmpreg, reg1=kreg, reg2=tmpreg)
226
+ # asmblock += self.shift_greg_right(reg=tmpreg,bit_count=shift)
227
+ #
228
+ # # kleft = k - (tmp * unroll)
229
+ # asmblock += self.mov_greg_imm(reg=kleftreg, imm=unroll)
230
+ # asmblock += self.asmwrap(f"msub {kleftreg},{tmpreg},{kleftreg},{kreg}")
231
+
232
+ # # k = tmp
233
+ # asmblock += self.mov_greg(src=tmpreg,dst=kreg)
234
+
235
+ # return asmblock
236
+
237
+
238
+ # DIV version
239
+
240
+ asmblock = ""
241
+
242
+ asmblock += self.set(dreg=kleftreg, dt=_GP, modifiers={_opset_mod.CONST}, value=unroll)
243
+ # tmp = k // unroll
244
+ asmblock += self.asmwrap(f"udiv {tmpreg},{kreg},{kleftreg}")
245
+ # kleft = k - (tmp * unroll)
246
+ asmblock += self.asmwrap(f"msub {kleftreg},{tmpreg},{kleftreg},{kreg}")
247
+ # k = tmp
248
+ asmblock += self.move(dregs=[tmpreg, kreg], dts=[_GP, _GP])
249
+
250
+
251
+ return asmblock
252
+
253
+
254
+
255
+ def greg(self, reg_idx : int) -> greg_base:
256
+ return aarch64_greg(reg_idx)
257
+
258
+ def freg(self, reg_idx : int, dt : adt) -> freg_base:
259
+ return aarch64_freg(reg_idx=reg_idx, dt=dt)
@@ -0,0 +1,11 @@
1
+ # ------------------------------------------------------------------------------
2
+ # SPDX-License-Identifier: MIT OR GPL-3.0-or-later
3
+ # Copyright (C) 2021 Stepan Nassyr <s.nassyr@fz-juelich.de>
4
+ # Copyright (C) 2021 Stepan Nassyr <s.nassyr@xcpp.org>
5
+ # ------------------------------------------------------------------------------
6
+ """
7
+ Meta-module for Base AArch64 opmem operations
8
+ """
9
+ from .load import *
10
+ from .store import *
11
+ from .prefetch import *
@@ -0,0 +1,182 @@
1
+ # ------------------------------------------------------------------------------
2
+ # SPDX-License-Identifier: MIT OR GPL-3.0-or-later
3
+ # Copyright (C) 2021 Stepan Nassyr <s.nassyr@fz-juelich.de>
4
+ # Copyright (C) 2021 Stepan Nassyr <s.nassyr@xcpp.org>
5
+ # ------------------------------------------------------------------------------
6
+ """
7
+ Aarch64 opmem operations
8
+ """
9
+
10
+ from typing import Callable
11
+
12
+ from ...op import (
13
+ opmem,
14
+ opmem_modifier as mod,
15
+ opmem_action,
16
+ operation_signature,
17
+ operand_modifier as opd_mod,
18
+ )
19
+ from ...op.constraint import ValueType
20
+ from ....registers import asm_data_type as adt, adt_size
21
+
22
+ from ..types import aarch64_greg, aarch64_freg
23
+
24
+ from .signatures import make_aarch64_opmem_signatures
25
+ from ...op.opmem import param_signatures
26
+
27
+ class aarch64_opmem(opmem):
28
+ """
29
+ AArch64 scalar instruction with 1 data operand and 1 address operand.
30
+ Handles standard scalar loads/stores (ldr, str, ldrb, strh, etc.)
31
+ """
32
+
33
+ def __init__(self, action: opmem_action,
34
+ asmwrap : Callable[[str],str]):
35
+ self.action = action
36
+ self.asmwrap=asmwrap
37
+
38
+ sigs = make_aarch64_opmem_signatures()
39
+ self.signatures = sigs + param_signatures(sigs)
40
+
41
+ def all_signatures(self) -> list[operation_signature]:
42
+ return self.signatures
43
+
44
+ @property
45
+ def inst_base(self):
46
+ """
47
+ Base root for the instruction
48
+ """
49
+ if self.action == opmem_action.LOAD:
50
+ return "ldr"
51
+ if self.action == opmem_action.STORE:
52
+ return "str"
53
+ raise ValueError(f"Invalid action: {self.action}")
54
+
55
+ # I explicitly want it this way
56
+ # pylint: disable-next=too-many-branches
57
+ def diagnose_failure(self,
58
+ modifiers: set[mod],
59
+ operand_modifiers : dict[str,set[opd_mod]],
60
+ kwargs : dict[str,ValueType],
61
+ dts : dict[str,adt]):
62
+
63
+ if mod.TINDEX in modifiers:
64
+ raise ValueError(
65
+ "Base AArch64 has no ld/st with 2D tile offset indices")
66
+ if mod.VINDEX in modifiers:
67
+ raise ValueError(
68
+ "Base AArch64 has no ld/st with 1D vector offset indices")
69
+ #if mod.GLANE in modifiers:
70
+ # raise ValueError("Base AArch64 has no GP-reg lane ld/st")
71
+ #if mod.ILANE in modifiers:
72
+ # raise ValueError("Base AArch64 has no immediate lane ld/st")
73
+ if mod.TOFFSET in modifiers:
74
+ raise ValueError("Base AArch64 has no ld/st with 2D tile offsets")
75
+ if mod.VOFFSET in modifiers:
76
+ raise ValueError("Base AArch64 has no ld/st with vector offsets")
77
+ if mod.ISTRIDE in modifiers:
78
+ raise ValueError(
79
+ "Base AArch64 has no ld/st with immediate strides")
80
+ if mod.GSTRIDE in modifiers:
81
+ raise ValueError("Base AArch64 has no ld/st with GP-reg strides")
82
+ if mod.STRUCT in modifiers:
83
+ raise ValueError("Base AArch64 has no structured ld/st")
84
+ #if mod.BCAST in modifiers:
85
+ # raise ValueError("Base AArch64 has no broadcasting ld/st")
86
+ if mod.MASK in modifiers:
87
+ raise ValueError("Base AArch64 has no masked ld/st")
88
+ #if mod.ROW in modifiers:
89
+ # raise ValueError("Base AArch64 has no row selection ld/st")
90
+ #if mod.COL in modifiers:
91
+ # raise ValueError("Base AArch64 has no column selection ld/st")
92
+ if mod.NT in modifiers:
93
+ raise NotImplementedError("Non-temporals for Base AArch64 not yet implemented")
94
+
95
+ # `dts` has one entry per passed `dreg`; ld/st always use exactly one
96
+ # register, data-less ops (prefetches) use none
97
+ if self.action in (opmem_action.LOAD, opmem_action.STORE) \
98
+ and len(dts) != 1:
99
+ raise ValueError("AArch64 scalar load/store uses exactly one register.")
100
+
101
+ if mod.POSTINC in modifiers:
102
+ if "iinc" in kwargs and "increg" in kwargs:
103
+ raise ValueError("iinc, increg are mutually exclusive")
104
+ if "iinc" not in kwargs and "increg" not in kwargs:
105
+ raise ValueError("Missing one of these parameters: iinc, increg")
106
+
107
+ if mod.IOFFSET in modifiers and "ioffset" not in kwargs:
108
+ raise ValueError("Missing operand: ioffset")
109
+
110
+ if mod.GOFFSET in modifiers and "offreg" not in kwargs:
111
+ raise ValueError("Missing operand: offreg")
112
+
113
+ def get_addressing(self,
114
+ areg: aarch64_greg,
115
+ modifiers: set[mod], **kwargs) -> str:
116
+ """
117
+ Constructs the addressing string
118
+
119
+ :param areg: address register
120
+ :param modifiers: operation modifiers
121
+
122
+ :return: string containing the addressing
123
+ """
124
+ if mod.PARAM in modifiers:
125
+ return f"%[{kwargs['param']}]"
126
+ if not isinstance(areg, aarch64_greg):
127
+ raise ValueError(f"{areg} is not an aarch64_greg")
128
+
129
+ base_addr = f"[{areg}]"
130
+
131
+ if mod.POSTINC in modifiers:
132
+ increg = kwargs.get("increg", None)
133
+ if increg is not None:
134
+ return f"{base_addr}, {increg}"
135
+
136
+ iinc = kwargs["iinc"]
137
+ return f"{base_addr}, #{iinc}"
138
+
139
+ if mod.IOFFSET in modifiers:
140
+ ioffset = kwargs["ioffset"]
141
+ if ioffset == 0:
142
+ return base_addr
143
+ return f"[{areg}, #{ioffset}]"
144
+
145
+ if mod.GOFFSET in modifiers:
146
+ offreg = kwargs["offreg"]
147
+ return f"[{areg}, {offreg}]"
148
+
149
+ return base_addr
150
+
151
+ def get_inst_mnemonic(self, dt: adt, is_freg: bool) -> str:
152
+ """
153
+ Construct instruction mnemonic
154
+ """
155
+ base = self.inst_base
156
+
157
+ if is_freg:
158
+ return base
159
+
160
+ size = adt_size(dt)
161
+ if size == 1:
162
+ return base + "b"
163
+ if size == 2:
164
+ return base + "h"
165
+
166
+ return base
167
+
168
+ def implementation(self, *, dregs: list, agreg : aarch64_greg|None = None,
169
+ modifiers: set[mod], **kwargs) -> str:
170
+
171
+ if len(dregs) != 1:
172
+ raise ValueError(
173
+ "AArch64 scalar load/store uses exactly one register.")
174
+
175
+ a_dt = kwargs['a_dt']
176
+ dreg = dregs[0].retype(dt=a_dt)
177
+ is_freg = isinstance(dreg, aarch64_freg)
178
+
179
+ inst = self.get_inst_mnemonic(a_dt, is_freg)
180
+ addressing = self.get_addressing(agreg, modifiers, **kwargs)
181
+
182
+ return self.asmwrap(f"{inst} {dreg}, {addressing}")
@@ -0,0 +1,21 @@
1
+ # ------------------------------------------------------------------------------
2
+ # SPDX-License-Identifier: MIT OR GPL-3.0-or-later
3
+ # Copyright (C) 2021 Stepan Nassyr <s.nassyr@fz-juelich.de>
4
+ # Copyright (C) 2021 Stepan Nassyr <s.nassyr@xcpp.org>
5
+ # ------------------------------------------------------------------------------
6
+ """
7
+ Base AArch64 load instructions
8
+ """
9
+
10
+ from typing import Callable
11
+
12
+ from ...op import opmem_action as action
13
+ from .base import aarch64_opmem
14
+
15
+ class aarch64_load(aarch64_opmem):
16
+ """
17
+ RISC-V freg and greg loads
18
+ """
19
+
20
+ def __init__(self, asmwrap : Callable[[str],str]):
21
+ super().__init__(action=action.LOAD, asmwrap=asmwrap)
@@ -0,0 +1,40 @@
1
+ # ------------------------------------------------------------------------------
2
+ # SPDX-License-Identifier: MIT OR GPL-3.0-or-later
3
+ # Copyright (C) 2021 Stepan Nassyr <s.nassyr@fz-juelich.de>
4
+ # Copyright (C) 2021 Stepan Nassyr <s.nassyr@xcpp.org>
5
+ # ------------------------------------------------------------------------------
6
+ """
7
+ Base AArch64 prefetch instructions
8
+ """
9
+
10
+ from typing import Callable
11
+
12
+ from ...op import opmem_action as action
13
+ from ...op import opmem_modifier as mod
14
+ from ...op import operand_modifier as opd_mod
15
+ from ..types import aarch64_greg
16
+ from .base import aarch64_opmem
17
+ from .signatures import make_aarch64_prefetch_signatures
18
+
19
+ class aarch64_prefetch(aarch64_opmem):
20
+ """
21
+ Base AArch64 prefetch (prfm PLDL1KEEP).
22
+
23
+ Data-less opmem (no dregs/dt). Cache level/locality/target selection
24
+ is not exposed yet.
25
+ """
26
+
27
+ def __init__(self,
28
+ asmwrap : Callable[[str],str]):
29
+ super().__init__(action=action.PREFETCH, asmwrap=asmwrap)
30
+ self.signatures = make_aarch64_prefetch_signatures()
31
+
32
+ # pylint: disable-next=arguments-differ
33
+ def implementation(self, *, agreg: aarch64_greg,
34
+ modifiers: set[mod],
35
+ operand_modifiers : dict[str,set[opd_mod]],
36
+ **kwargs) -> str:
37
+ del operand_modifiers
38
+
39
+ addressing = self.get_addressing(agreg, modifiers, **kwargs)
40
+ return self.asmwrap(f"prfm PLDL1KEEP, {addressing}")
@@ -0,0 +1,134 @@
1
+ # ------------------------------------------------------------------------------
2
+ # SPDX-License-Identifier: MIT OR GPL-3.0-or-later
3
+ # Copyright (C) 2021 Stepan Nassyr <s.nassyr@fz-juelich.de>
4
+ # Copyright (C) 2021 Stepan Nassyr <s.nassyr@xcpp.org>
5
+ # ------------------------------------------------------------------------------
6
+ """
7
+ Valid signatures for AArch64 opmem operations
8
+ """
9
+
10
+ from ....registers import adt_size
11
+ from ...op.constraint import either_constraint, minmax_constraint, multiple_constraint
12
+ from ...op import (
13
+ operation_signature as sig,
14
+ operand_shape as osh,
15
+ operand_type as ot,
16
+ operand_role as orl,
17
+ register_type as rt,
18
+ opmem_modifier as mod
19
+ )
20
+
21
+ from ....registers import asm_data_type as adt, adt_is_float
22
+
23
+ _FLOATS = [adt.FP64, adt.FP32, adt.FP16, adt.FP8E4M3, adt.FP8E5M2]
24
+ _INTS = [adt.SINT64, adt.SINT32, adt.SINT16, adt.SINT8,
25
+ adt.UINT64, adt.UINT32, adt.UINT16, adt.UINT8]
26
+
27
+
28
+ def _scale(dt) -> int:
29
+ """
30
+ What an unsigned immediate offset is scaled by: the access's size - a
31
+ prefetch's (no data) 8, as prfm's
32
+ """
33
+ return 8 if dt is None else adt_size(dt)
34
+
35
+ def make_aarch64_opmem_signatures():
36
+ """
37
+ Generate signatures for AArch64 opmem operations
38
+ """
39
+ sigs = []
40
+
41
+
42
+ for dt in _FLOATS+_INTS:
43
+
44
+ a_rt = rt.FP if adt_is_float(dt) else rt.GP
45
+
46
+ # (f)ld without offset
47
+ sigs.append(sig(
48
+ modifiers=set(),
49
+ structural_params={},
50
+ operands={
51
+ 'adreg': osh(ot.REGISTER, orl.DATA, a_rt, dt),
52
+ 'agreg': osh(ot.REGISTER, orl.ADDRESS, rt.GP, adt.UINT64)
53
+ }
54
+ ))
55
+ # (f)ld with immediate offset
56
+ sigs.append(sig(
57
+ modifiers={mod.IOFFSET},
58
+ structural_params={},
59
+ operands={
60
+ 'adreg': osh(ot.REGISTER, orl.DATA, a_rt, dt),
61
+ 'agreg': osh(ot.REGISTER, orl.ADDRESS, rt.GP, adt.UINT64),
62
+ 'ioffset': osh(ot.IMMEDIATE, orl.PARAM, None, adt.SINT64, value_constraints=[either_constraint(options=[
63
+ [minmax_constraint(minval=0, maxval=4095*_scale(dt)), multiple_constraint(multiple=_scale(dt))],
64
+ [minmax_constraint(minval=-256, maxval=255)]])])
65
+ }
66
+ ))
67
+ # (f)ld with gp-reg offset
68
+ sigs.append(sig(
69
+ modifiers={mod.GOFFSET},
70
+ structural_params={},
71
+ operands={
72
+ 'adreg': osh(ot.REGISTER, orl.DATA, a_rt, dt),
73
+ 'agreg': osh(ot.REGISTER, orl.ADDRESS, rt.GP, adt.UINT64),
74
+ 'offreg': osh(ot.REGISTER, orl.ADDRESS, rt.GP, adt.UINT64)
75
+ }
76
+ ))
77
+ # (f)ld with postinc immediate offset
78
+ sigs.append(sig(
79
+ modifiers={mod.POSTINC},
80
+ structural_params={},
81
+ operands={
82
+ 'adreg': osh(ot.REGISTER, orl.DATA, a_rt, dt),
83
+ 'agreg': osh(ot.REGISTER, orl.ADDRESS, rt.GP, adt.UINT64),
84
+ 'iinc': osh(ot.IMMEDIATE, orl.PARAM, None, adt.SINT64, value_constraints=[minmax_constraint(minval=-256, maxval=255)])
85
+ }
86
+ ))
87
+ # (f)ld with postinc gp-reg offset
88
+ sigs.append(sig(
89
+ modifiers={mod.POSTINC},
90
+ structural_params={},
91
+ operands={
92
+ 'adreg': osh(ot.REGISTER, orl.DATA, a_rt, dt),
93
+ 'agreg': osh(ot.REGISTER, orl.ADDRESS, rt.GP, adt.UINT64),
94
+ 'increg': osh(ot.REGISTER, orl.ADDRESS, rt.GP, adt.UINT64)
95
+ }
96
+ ))
97
+
98
+ return sigs
99
+
100
+
101
+ def make_aarch64_prefetch_signatures():
102
+ """
103
+ Generate signatures for AArch64 prefetch operations
104
+ """
105
+ return [
106
+ # prefetch without offset
107
+ sig(
108
+ modifiers=set(),
109
+ structural_params={},
110
+ operands={
111
+ 'agreg': osh(ot.REGISTER, orl.ADDRESS, rt.GP, adt.UINT64)
112
+ }
113
+ ),
114
+ # prefetch with immediate offset
115
+ sig(
116
+ modifiers={mod.IOFFSET},
117
+ structural_params={},
118
+ operands={
119
+ 'agreg': osh(ot.REGISTER, orl.ADDRESS, rt.GP, adt.UINT64),
120
+ 'ioffset': osh(ot.IMMEDIATE, orl.PARAM, None, adt.SINT64, value_constraints=[either_constraint(options=[
121
+ [minmax_constraint(minval=0, maxval=4095*_scale(None)), multiple_constraint(multiple=_scale(None))],
122
+ [minmax_constraint(minval=-256, maxval=255)]])])
123
+ }
124
+ ),
125
+ # prefetch with gp-reg offset
126
+ sig(
127
+ modifiers={mod.GOFFSET},
128
+ structural_params={},
129
+ operands={
130
+ 'agreg': osh(ot.REGISTER, orl.ADDRESS, rt.GP, adt.UINT64),
131
+ 'offreg': osh(ot.REGISTER, orl.ADDRESS, rt.GP, adt.UINT64)
132
+ }
133
+ ),
134
+ ]