PyNerva 0.0.7__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.
- nervapy/__init__.py +50 -0
- nervapy/abi.py +91 -0
- nervapy/arm/__init__.py +124 -0
- nervapy/arm/__main__.py +0 -0
- nervapy/arm/abi.py +138 -0
- nervapy/arm/formats.py +49 -0
- nervapy/arm/function.py +2465 -0
- nervapy/arm/generic.py +10796 -0
- nervapy/arm/instructions.py +519 -0
- nervapy/arm/isa.py +409 -0
- nervapy/arm/literal_pool.py +331 -0
- nervapy/arm/microarchitecture.py +211 -0
- nervapy/arm/pseudo.py +652 -0
- nervapy/arm/registers.py +1458 -0
- nervapy/arm/vfpneon.py +4092 -0
- nervapy/arm.py +13 -0
- nervapy/c/__init__.py +1 -0
- nervapy/c/types.py +436 -0
- nervapy/codegen.py +99 -0
- nervapy/common/__init__.py +4 -0
- nervapy/common/function.py +5 -0
- nervapy/common/regalloc.py +121 -0
- nervapy/constant_data.py +282 -0
- nervapy/encoder.py +246 -0
- nervapy/formats/__init__.py +2 -0
- nervapy/formats/elf/__init__.py +4 -0
- nervapy/formats/elf/file.py +178 -0
- nervapy/formats/elf/image.py +106 -0
- nervapy/formats/elf/section.py +422 -0
- nervapy/formats/elf/symbol.py +281 -0
- nervapy/formats/macho/__init__.py +2 -0
- nervapy/formats/macho/file.py +123 -0
- nervapy/formats/macho/image.py +143 -0
- nervapy/formats/macho/section.py +322 -0
- nervapy/formats/macho/symbol.py +158 -0
- nervapy/formats/mscoff/__init__.py +8 -0
- nervapy/formats/mscoff/image.py +132 -0
- nervapy/formats/mscoff/section.py +181 -0
- nervapy/formats/mscoff/symbol.py +148 -0
- nervapy/function.py +136 -0
- nervapy/literal.py +731 -0
- nervapy/loader.py +188 -0
- nervapy/name.py +159 -0
- nervapy/parse.py +52 -0
- nervapy/stream.py +58 -0
- nervapy/util.py +126 -0
- nervapy/writer.py +518 -0
- nervapy/x86_64/__init__.py +324 -0
- nervapy/x86_64/__main__.py +407 -0
- nervapy/x86_64/abi.py +517 -0
- nervapy/x86_64/amd.py +6464 -0
- nervapy/x86_64/avx.py +102029 -0
- nervapy/x86_64/crypto.py +1533 -0
- nervapy/x86_64/encoding.py +424 -0
- nervapy/x86_64/fma.py +19138 -0
- nervapy/x86_64/function.py +2707 -0
- nervapy/x86_64/generic.py +23384 -0
- nervapy/x86_64/instructions.py +500 -0
- nervapy/x86_64/isa.py +476 -0
- nervapy/x86_64/lower.py +126 -0
- nervapy/x86_64/mask.py +2593 -0
- nervapy/x86_64/meta.py +143 -0
- nervapy/x86_64/mmxsse.py +17265 -0
- nervapy/x86_64/nacl.py +327 -0
- nervapy/x86_64/operand.py +1204 -0
- nervapy/x86_64/options.py +21 -0
- nervapy/x86_64/pseudo.py +686 -0
- nervapy/x86_64/registers.py +1225 -0
- nervapy/x86_64/types.py +17 -0
- nervapy/x86_64/uarch.py +580 -0
- pynerva-0.0.7.dist-info/METADATA +310 -0
- pynerva-0.0.7.dist-info/RECORD +74 -0
- pynerva-0.0.7.dist-info/WHEEL +4 -0
- pynerva-0.0.7.dist-info/licenses/LICENSE.rst +15 -0
nervapy/x86_64/pseudo.py
ADDED
|
@@ -0,0 +1,686 @@
|
|
|
1
|
+
# This file is part of PeachPy package and is licensed under the Simplified BSD license.
|
|
2
|
+
# See license.rst for the full text of the license.
|
|
3
|
+
|
|
4
|
+
import inspect
|
|
5
|
+
|
|
6
|
+
import nervapy.stream
|
|
7
|
+
import nervapy.x86_64.isa
|
|
8
|
+
import nervapy.x86_64.options
|
|
9
|
+
from nervapy.parse import (parse_assigned_variable_name,
|
|
10
|
+
parse_with_variable_name)
|
|
11
|
+
from nervapy.x86_64.instructions import Instruction
|
|
12
|
+
from nervapy.x86_64.operand import check_operand, format_operand_type
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Label:
|
|
16
|
+
def __init__(self, name=None):
|
|
17
|
+
from nervapy.name import Name
|
|
18
|
+
|
|
19
|
+
if name is None:
|
|
20
|
+
import inspect
|
|
21
|
+
|
|
22
|
+
self.name = (
|
|
23
|
+
Name(prename=parse_assigned_variable_name(inspect.stack(), "Label")),
|
|
24
|
+
)
|
|
25
|
+
elif isinstance(name, tuple):
|
|
26
|
+
assert all(
|
|
27
|
+
isinstance(part, Name) for part in name
|
|
28
|
+
), "Name must a string or a tuple or Name objects"
|
|
29
|
+
self.name = name
|
|
30
|
+
else:
|
|
31
|
+
Name.check_name(name)
|
|
32
|
+
self.name = (Name(name=name),)
|
|
33
|
+
self.line_number = None
|
|
34
|
+
|
|
35
|
+
def __str__(self):
|
|
36
|
+
"""Returns a string representation of the name"""
|
|
37
|
+
return ".".join(map(str, self.name))
|
|
38
|
+
|
|
39
|
+
def format(self, assembly_format):
|
|
40
|
+
assert assembly_format in {
|
|
41
|
+
"peachpy",
|
|
42
|
+
"gas",
|
|
43
|
+
"nasm",
|
|
44
|
+
"go",
|
|
45
|
+
}, "Supported assembly formats are 'peachpy', 'gas', 'nasm', 'go'"
|
|
46
|
+
|
|
47
|
+
if assembly_format == "go":
|
|
48
|
+
# Go assembler rejects label names with a dot, so we replace it with underscore symbol
|
|
49
|
+
return str(self).replace(".", "_")
|
|
50
|
+
else:
|
|
51
|
+
return str(self)
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def is_named(self):
|
|
55
|
+
return not any(part.name is None for part in self.name)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class LABEL(Instruction):
|
|
59
|
+
def __init__(self, label, origin=None):
|
|
60
|
+
label = check_operand(label)
|
|
61
|
+
super(LABEL, self).__init__("LABEL", origin=origin)
|
|
62
|
+
self.operands = (label,)
|
|
63
|
+
if not isinstance(label, Label):
|
|
64
|
+
raise SyntaxError(
|
|
65
|
+
"Invalid operand for LABEL statement: Label object expected"
|
|
66
|
+
)
|
|
67
|
+
self.identifier = label.name
|
|
68
|
+
self.input_branches = set()
|
|
69
|
+
if nervapy.stream.active_stream is not None:
|
|
70
|
+
nervapy.stream.active_stream.add_instruction(self)
|
|
71
|
+
|
|
72
|
+
def __str__(self):
|
|
73
|
+
return ".".join(map(str, self.identifier)) + ":"
|
|
74
|
+
|
|
75
|
+
def format(self, assembly_format, indent=False, line_number=None):
|
|
76
|
+
assert assembly_format in {
|
|
77
|
+
"peachpy",
|
|
78
|
+
"gas",
|
|
79
|
+
"nasm",
|
|
80
|
+
"go",
|
|
81
|
+
}, "Supported assembly formats are 'peachpy', 'gas', 'nasm', 'go'"
|
|
82
|
+
|
|
83
|
+
if assembly_format == "go":
|
|
84
|
+
# Go assembler rejects label names with a dot, so we replace it with underscore symbol
|
|
85
|
+
return "_".join(map(str, self.identifier)) + ":"
|
|
86
|
+
elif assembly_format == "gas":
|
|
87
|
+
# GAS doesn't support named non-local labels
|
|
88
|
+
if self.operands[0].line_number is None:
|
|
89
|
+
return "." + str(self) + ":"
|
|
90
|
+
else:
|
|
91
|
+
return str(self.operands[0].line_number) + ": # " + str(self)
|
|
92
|
+
else:
|
|
93
|
+
return str(self)
|
|
94
|
+
|
|
95
|
+
def __enter__(self):
|
|
96
|
+
return self
|
|
97
|
+
|
|
98
|
+
def __exit__(self, exc_type, exc_value, traceback):
|
|
99
|
+
if exc_type is not None:
|
|
100
|
+
raise
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class Loop:
|
|
104
|
+
def __init__(self, name=None):
|
|
105
|
+
from nervapy.name import Name
|
|
106
|
+
|
|
107
|
+
if name is None:
|
|
108
|
+
import inspect
|
|
109
|
+
|
|
110
|
+
prename = parse_assigned_variable_name(inspect.stack(), "Loop")
|
|
111
|
+
if prename is None:
|
|
112
|
+
prename = parse_with_variable_name(inspect.stack(), "Loop")
|
|
113
|
+
self.name = (Name(prename=prename),)
|
|
114
|
+
elif isinstance(name, tuple):
|
|
115
|
+
assert all(
|
|
116
|
+
isinstance(part, Name) for part in name
|
|
117
|
+
), "Name must a string or a tuple or Name objects"
|
|
118
|
+
self.name = name
|
|
119
|
+
else:
|
|
120
|
+
Name.check_name(name)
|
|
121
|
+
self.name = (Name(name=name),)
|
|
122
|
+
self.begin = Label(self.name + (Name(name="begin"),))
|
|
123
|
+
self.end = Label(self.name + (Name(name="end"),))
|
|
124
|
+
|
|
125
|
+
def __enter__(self):
|
|
126
|
+
LABEL(self.begin)
|
|
127
|
+
|
|
128
|
+
from nervapy.common.function import active_function
|
|
129
|
+
|
|
130
|
+
if active_function is not None:
|
|
131
|
+
active_function._indent_level += 1
|
|
132
|
+
return self
|
|
133
|
+
|
|
134
|
+
def __exit__(self, exc_type, exc_value, exc_traceback):
|
|
135
|
+
from nervapy.common.function import active_function
|
|
136
|
+
|
|
137
|
+
if active_function is not None:
|
|
138
|
+
active_function._indent_level -= 1
|
|
139
|
+
|
|
140
|
+
if exc_type is None:
|
|
141
|
+
LABEL(self.end)
|
|
142
|
+
else:
|
|
143
|
+
raise
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class Block:
|
|
147
|
+
def __init__(self, name=None):
|
|
148
|
+
from nervapy.name import Name
|
|
149
|
+
|
|
150
|
+
if name is None:
|
|
151
|
+
import inspect
|
|
152
|
+
|
|
153
|
+
prename = parse_assigned_variable_name(inspect.stack(), "Block")
|
|
154
|
+
if prename is None:
|
|
155
|
+
prename = parse_with_variable_name(inspect.stack(), "Block")
|
|
156
|
+
self.name = (Name(prename=prename),)
|
|
157
|
+
elif isinstance(name, tuple):
|
|
158
|
+
assert all(
|
|
159
|
+
isinstance(part, Name) for part in name
|
|
160
|
+
), "Name must a string or a tuple or Name objects"
|
|
161
|
+
self.name = name
|
|
162
|
+
else:
|
|
163
|
+
Name.check_name(name)
|
|
164
|
+
self.name = (Name(name=name),)
|
|
165
|
+
self.begin = Label(self.name + (Name(name="begin"),))
|
|
166
|
+
self.end = Label(self.name + (Name(name="end"),))
|
|
167
|
+
|
|
168
|
+
def __enter__(self):
|
|
169
|
+
LABEL(self.begin)
|
|
170
|
+
|
|
171
|
+
from nervapy.common.function import active_function
|
|
172
|
+
|
|
173
|
+
if active_function is not None:
|
|
174
|
+
active_function._indent_level += 1
|
|
175
|
+
return self
|
|
176
|
+
|
|
177
|
+
def __exit__(self, exc_type, exc_value, exc_traceback):
|
|
178
|
+
from nervapy.common.function import active_function
|
|
179
|
+
|
|
180
|
+
if active_function is not None:
|
|
181
|
+
active_function._indent_level -= 1
|
|
182
|
+
|
|
183
|
+
if exc_type is None:
|
|
184
|
+
LABEL(self.end)
|
|
185
|
+
else:
|
|
186
|
+
raise
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
class ALIGN(Instruction):
|
|
190
|
+
supported_alignments = (2, 4, 8, 16, 32)
|
|
191
|
+
|
|
192
|
+
def __init__(self, alignment, origin=None):
|
|
193
|
+
super(ALIGN, self).__init__("ALIGN", origin=origin)
|
|
194
|
+
if not isinstance(alignment, int):
|
|
195
|
+
raise TypeError("The alignment value must be an integer")
|
|
196
|
+
if alignment not in ALIGN.supported_alignments:
|
|
197
|
+
raise ValueError(
|
|
198
|
+
"The alignment value {0} is not in the list of supported alignments ({1})".format(
|
|
199
|
+
alignment, ", ".join(ALIGN.supported_alignments)
|
|
200
|
+
)
|
|
201
|
+
)
|
|
202
|
+
self.alignment = alignment
|
|
203
|
+
if nervapy.stream.active_stream is not None:
|
|
204
|
+
nervapy.stream.active_stream.add_instruction(self)
|
|
205
|
+
|
|
206
|
+
def __str__(self):
|
|
207
|
+
return "align {0}".format(self.alignment)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
class RETURN(Instruction):
|
|
211
|
+
def __init__(self, *args, **kwargs):
|
|
212
|
+
from nervapy.common.function import active_function
|
|
213
|
+
from nervapy.x86_64.registers import (GeneralPurposeRegister,
|
|
214
|
+
MMXRegister, XMMRegister,
|
|
215
|
+
YMMRegister)
|
|
216
|
+
|
|
217
|
+
origin = kwargs.get("origin")
|
|
218
|
+
prototype = kwargs.get("prototype")
|
|
219
|
+
if (
|
|
220
|
+
origin is None
|
|
221
|
+
and prototype is None
|
|
222
|
+
and nervapy.x86_64.options.get_debug_level() > 0
|
|
223
|
+
):
|
|
224
|
+
origin = inspect.stack()
|
|
225
|
+
super(RETURN, self).__init__("RETURN", origin=origin)
|
|
226
|
+
self.operands = tuple(map(check_operand, args))
|
|
227
|
+
if len(self.operands) == 0:
|
|
228
|
+
# It is not an error to return nothing from a function with a return type
|
|
229
|
+
self.in_regs = tuple()
|
|
230
|
+
self.out_regs = tuple()
|
|
231
|
+
self.out_operands = tuple()
|
|
232
|
+
elif len(self.operands) == 1:
|
|
233
|
+
# It is an error to return something from a void function
|
|
234
|
+
from nervapy.util import int_size, is_int64
|
|
235
|
+
|
|
236
|
+
if active_function.result_type is None:
|
|
237
|
+
raise ValueError("Void function should not return a value")
|
|
238
|
+
if (
|
|
239
|
+
active_function.result_type.is_integer
|
|
240
|
+
or active_function.result_type.is_pointer
|
|
241
|
+
):
|
|
242
|
+
if is_int64(self.operands[0]):
|
|
243
|
+
if (
|
|
244
|
+
active_function.result_type.size is None
|
|
245
|
+
and int_size(self.operands[0]) > 4
|
|
246
|
+
or active_function.result_type.size is not None
|
|
247
|
+
and active_function.result_type.size
|
|
248
|
+
< int_size(self.operands[0])
|
|
249
|
+
):
|
|
250
|
+
raise ValueError(
|
|
251
|
+
"Value {0} can not be represented with return type {1}".format(
|
|
252
|
+
str(self.operands[0]), str(active_function.result_type)
|
|
253
|
+
)
|
|
254
|
+
)
|
|
255
|
+
self.in_regs = (False,)
|
|
256
|
+
self.out_regs = (False,)
|
|
257
|
+
self.out_operands = (False,)
|
|
258
|
+
elif isinstance(self.operands[0], GeneralPurposeRegister):
|
|
259
|
+
if active_function.result_type.size < self.operands[0].size:
|
|
260
|
+
raise ValueError(
|
|
261
|
+
"Register {0} can not be converted to return type {1}".format(
|
|
262
|
+
str(self.operands[0]), str(active_function.result_type)
|
|
263
|
+
)
|
|
264
|
+
)
|
|
265
|
+
self.in_regs = (True,)
|
|
266
|
+
self.out_regs = (False,)
|
|
267
|
+
self.out_operands = (False,)
|
|
268
|
+
else:
|
|
269
|
+
raise TypeError(
|
|
270
|
+
"Invalid operand type: RETURN {0} for {1} function".format(
|
|
271
|
+
str(self.operands[0]), str(active_function.result_type)
|
|
272
|
+
)
|
|
273
|
+
)
|
|
274
|
+
elif active_function.result_type.is_floating_point:
|
|
275
|
+
if isinstance(self.operands[0], XMMRegister):
|
|
276
|
+
self.in_regs = (True,)
|
|
277
|
+
self.out_regs = (False,)
|
|
278
|
+
self.out_operands = (False,)
|
|
279
|
+
else:
|
|
280
|
+
raise TypeError(
|
|
281
|
+
"Invalid operand type: RETURN {0} for {1} function".format(
|
|
282
|
+
str(self.operands[0]), str(active_function.result_type)
|
|
283
|
+
)
|
|
284
|
+
)
|
|
285
|
+
elif active_function.result_type.is_vector:
|
|
286
|
+
if (
|
|
287
|
+
isinstance(
|
|
288
|
+
self.operands[0], (MMXRegister, XMMRegister, YMMRegister)
|
|
289
|
+
)
|
|
290
|
+
and active_function.result_type.size == self.operands[0].size
|
|
291
|
+
):
|
|
292
|
+
self.in_regs = (True,)
|
|
293
|
+
self.out_regs = (False,)
|
|
294
|
+
self.out_operands = (False,)
|
|
295
|
+
else:
|
|
296
|
+
raise TypeError(
|
|
297
|
+
"Invalid operand type: RETURN {0} for {1} function".format(
|
|
298
|
+
str(self.operands[0]), str(active_function.result_type)
|
|
299
|
+
)
|
|
300
|
+
)
|
|
301
|
+
else:
|
|
302
|
+
raise SyntaxError(
|
|
303
|
+
"Invalid operand type: RETURN "
|
|
304
|
+
+ ", ".join(map(format_operand_type, self.operands))
|
|
305
|
+
)
|
|
306
|
+
else:
|
|
307
|
+
raise SyntaxError('Pseudo-instruction "RETURN" requires 0 or 1 operands')
|
|
308
|
+
if nervapy.stream.active_stream is not None:
|
|
309
|
+
nervapy.stream.active_stream.add_instruction(self)
|
|
310
|
+
|
|
311
|
+
def __str__(self):
|
|
312
|
+
if len(self.operands) == 0:
|
|
313
|
+
return "RETURN"
|
|
314
|
+
else:
|
|
315
|
+
return "RETURN " + ", ".join(map(str, self.operands))
|
|
316
|
+
|
|
317
|
+
def format(self, assembly_format, indent=False, line_number=None):
|
|
318
|
+
text = "\t" if indent else ""
|
|
319
|
+
if assembly_format == "peachpy":
|
|
320
|
+
return text + str(self)
|
|
321
|
+
else:
|
|
322
|
+
raise SyntaxError('Invalid assembly format "%s"' % assembly_format)
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
class LOAD:
|
|
326
|
+
class ARGUMENT(Instruction):
|
|
327
|
+
def __init__(self, *args, **kwargs):
|
|
328
|
+
from nervapy.common.function import active_function
|
|
329
|
+
from nervapy.x86_64 import m64
|
|
330
|
+
from nervapy.x86_64.registers import (GeneralPurposeRegister,
|
|
331
|
+
XMMRegister, YMMRegister)
|
|
332
|
+
|
|
333
|
+
origin = kwargs.get("origin")
|
|
334
|
+
prototype = kwargs.get("prototype")
|
|
335
|
+
if (
|
|
336
|
+
origin is None
|
|
337
|
+
and prototype is None
|
|
338
|
+
and nervapy.x86_64.options.get_debug_level() > 0
|
|
339
|
+
):
|
|
340
|
+
origin = inspect.stack()
|
|
341
|
+
super(LOAD.ARGUMENT, self).__init__("LOAD.ARGUMENT", origin=origin)
|
|
342
|
+
self.operands = tuple(map(check_operand, args))
|
|
343
|
+
self.out_regs = (True, False)
|
|
344
|
+
self.in_regs = (False, False)
|
|
345
|
+
if len(self.operands) != 2:
|
|
346
|
+
raise SyntaxError('Instruction "LOAD.ARGUMENT" requires 2 operands')
|
|
347
|
+
|
|
348
|
+
# Check source (second) operand
|
|
349
|
+
if not isinstance(self.operands[1], nervapy.Argument):
|
|
350
|
+
raise TypeError(
|
|
351
|
+
"The source operand to LOAD.ARGUMENT must be of Argument type"
|
|
352
|
+
)
|
|
353
|
+
argument = active_function._find_argument(self.operands[1])
|
|
354
|
+
if argument is None:
|
|
355
|
+
raise ValueError(
|
|
356
|
+
"%s is not an argument of the active function"
|
|
357
|
+
% str(self.operands[1])
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
# Check destination (first) operand
|
|
361
|
+
if isinstance(self.operands[0], GeneralPurposeRegister) and (
|
|
362
|
+
argument.is_integer or argument.is_pointer
|
|
363
|
+
):
|
|
364
|
+
if argument.size is not None and self.operands[0].size < argument.size:
|
|
365
|
+
raise ValueError(
|
|
366
|
+
"Destination register %s is too narrow for the argument %s"
|
|
367
|
+
% (self.operands[0], argument)
|
|
368
|
+
)
|
|
369
|
+
elif (
|
|
370
|
+
isinstance(self.operands[0], (XMMRegister, YMMRegister))
|
|
371
|
+
and argument.is_floating_point
|
|
372
|
+
):
|
|
373
|
+
pass
|
|
374
|
+
elif isinstance(self.operands[0], (XMMRegister, YMMRegister)) and (
|
|
375
|
+
argument.is_vector and argument.c_type != m64
|
|
376
|
+
):
|
|
377
|
+
pass
|
|
378
|
+
else:
|
|
379
|
+
raise ValueError("Unsupported combination of instruction operands")
|
|
380
|
+
|
|
381
|
+
if nervapy.stream.active_stream is not None:
|
|
382
|
+
nervapy.stream.active_stream.add_instruction(self)
|
|
383
|
+
|
|
384
|
+
def format(self, assembly_format, indent=False, line_number=None):
|
|
385
|
+
assert assembly_format in {
|
|
386
|
+
"peachpy",
|
|
387
|
+
"go",
|
|
388
|
+
}, "Supported assembly formats are 'peachpy' and 'go'"
|
|
389
|
+
|
|
390
|
+
text = "\t" if indent else ""
|
|
391
|
+
if assembly_format == "go":
|
|
392
|
+
from nervapy.x86_64.registers import (GeneralPurposeRegister,
|
|
393
|
+
GeneralPurposeRegister8,
|
|
394
|
+
GeneralPurposeRegister16,
|
|
395
|
+
GeneralPurposeRegister32,
|
|
396
|
+
GeneralPurposeRegister64,
|
|
397
|
+
MMXRegister, XMMRegister,
|
|
398
|
+
YMMRegister)
|
|
399
|
+
|
|
400
|
+
assert isinstance(
|
|
401
|
+
self.operands[0], (GeneralPurposeRegister, MMXRegister, XMMRegister)
|
|
402
|
+
), "LOAD.ARGUMENT must load into a general-purpose, mmx, or xmm register"
|
|
403
|
+
if isinstance(self.operands[0], GeneralPurposeRegister8):
|
|
404
|
+
return text + "MOVB %s+%d(FP), %s" % (
|
|
405
|
+
self.operands[1].name,
|
|
406
|
+
self.operands[1].stack_offset,
|
|
407
|
+
self.operands[0].format("go"),
|
|
408
|
+
)
|
|
409
|
+
elif isinstance(self.operands[0], GeneralPurposeRegister16):
|
|
410
|
+
mov_name = {
|
|
411
|
+
(True, 1): "MOVWLSX",
|
|
412
|
+
(True, 2): "MOVW",
|
|
413
|
+
(False, 1): "MOVWLZX",
|
|
414
|
+
(False, 2): "MOVW",
|
|
415
|
+
}[(self.operands[1].is_signed_integer, self.operands[1].size)]
|
|
416
|
+
return text + "%s %s+%d(FP), %s" % (
|
|
417
|
+
mov_name,
|
|
418
|
+
self.operands[1].name,
|
|
419
|
+
self.operands[1].stack_offset,
|
|
420
|
+
self.operands[0].format("go"),
|
|
421
|
+
)
|
|
422
|
+
elif isinstance(self.operands[0], GeneralPurposeRegister32):
|
|
423
|
+
mov_name = {
|
|
424
|
+
(True, 1): "MOVBLSX",
|
|
425
|
+
(True, 2): "MOVWLSX",
|
|
426
|
+
(True, 4): "MOVL",
|
|
427
|
+
(False, 1): "MOVBLZX",
|
|
428
|
+
(False, 2): "MOVWLZX",
|
|
429
|
+
(False, 4): "MOVL",
|
|
430
|
+
}[(self.operands[1].is_signed_integer, self.operands[1].size)]
|
|
431
|
+
return text + "%s %s+%d(FP), %s" % (
|
|
432
|
+
mov_name,
|
|
433
|
+
self.operands[1].name,
|
|
434
|
+
self.operands[1].stack_offset,
|
|
435
|
+
self.operands[0].format("go"),
|
|
436
|
+
)
|
|
437
|
+
elif isinstance(self.operands[0], GeneralPurposeRegister64):
|
|
438
|
+
mov_name = {
|
|
439
|
+
(True, 1): "MOVBQSX",
|
|
440
|
+
(True, 2): "MOVWQSX",
|
|
441
|
+
(True, 4): "MOVLQSX",
|
|
442
|
+
(True, 8): "MOVQ",
|
|
443
|
+
(False, 1): "MOVBQZX",
|
|
444
|
+
(False, 2): "MOVWQZX",
|
|
445
|
+
(False, 4): "MOVLQZX",
|
|
446
|
+
(False, 8): "MOVQ",
|
|
447
|
+
}[(self.operands[1].is_signed_integer, self.operands[1].size)]
|
|
448
|
+
return text + "%s %s+%d(FP), %s" % (
|
|
449
|
+
mov_name,
|
|
450
|
+
self.operands[1].name,
|
|
451
|
+
self.operands[1].stack_offset,
|
|
452
|
+
self.operands[0].format("go"),
|
|
453
|
+
)
|
|
454
|
+
elif isinstance(self.operands[0], MMXRegister):
|
|
455
|
+
mov_name = {4: "MOVD", 8: "MOVQ"}[self.operands[1].size]
|
|
456
|
+
return text + "%s %s+%d(FP), %s" % (
|
|
457
|
+
mov_name,
|
|
458
|
+
self.operands[1].name,
|
|
459
|
+
self.operands[1].stack_offset,
|
|
460
|
+
self.operands[0].format("go"),
|
|
461
|
+
)
|
|
462
|
+
elif isinstance(self.operands[0], XMMRegister):
|
|
463
|
+
mov_name = {4: "MOVD", 8: "MOVQ"}[self.operands[1].size]
|
|
464
|
+
return text + "%s %s+%d(FP), %s" % (
|
|
465
|
+
mov_name,
|
|
466
|
+
self.operands[1].name,
|
|
467
|
+
self.operands[1].stack_offset,
|
|
468
|
+
self.operands[0].format("go"),
|
|
469
|
+
)
|
|
470
|
+
else:
|
|
471
|
+
return text + str(self)
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
class STORE:
|
|
475
|
+
class RESULT(Instruction):
|
|
476
|
+
def __init__(self, *args, **kwargs):
|
|
477
|
+
from nervapy.common.function import active_function
|
|
478
|
+
from nervapy.util import is_int16, is_int32
|
|
479
|
+
from nervapy.x86_64.abi import goasm_amd64_abi, goasm_amd64p32_abi
|
|
480
|
+
from nervapy.x86_64.registers import (GeneralPurposeRegister,
|
|
481
|
+
MMXRegister, XMMRegister,
|
|
482
|
+
YMMRegister)
|
|
483
|
+
|
|
484
|
+
origin = kwargs.get("origin")
|
|
485
|
+
prototype = kwargs.get("prototype")
|
|
486
|
+
if (
|
|
487
|
+
origin is None
|
|
488
|
+
and prototype is None
|
|
489
|
+
and nervapy.x86_64.options.get_debug_level() > 0
|
|
490
|
+
):
|
|
491
|
+
origin = inspect.stack()
|
|
492
|
+
super(STORE.RESULT, self).__init__("STORE.RESULT", origin=origin)
|
|
493
|
+
self.operands = tuple(map(check_operand, args))
|
|
494
|
+
self.out_regs = (False,)
|
|
495
|
+
self.in_regs = (True,)
|
|
496
|
+
if len(self.operands) != 1:
|
|
497
|
+
raise SyntaxError('Instruction "STORE.RESULT" requires 1 operand')
|
|
498
|
+
|
|
499
|
+
target_function = active_function
|
|
500
|
+
destination_offset = None
|
|
501
|
+
if target_function is None:
|
|
502
|
+
target_function = kwargs.get("target_function")
|
|
503
|
+
assert target_function.abi in {goasm_amd64_abi, goasm_amd64p32_abi}
|
|
504
|
+
destination_offset = target_function.result_offset
|
|
505
|
+
if target_function.result_type is None:
|
|
506
|
+
raise ValueError("STORE.RESULT can't be used with void functions")
|
|
507
|
+
self.destination_type = target_function.result_type
|
|
508
|
+
self.destination_size = self.destination_type.size
|
|
509
|
+
# Will be updated during ABI binding (ABIFunction._lower_pseudoinstructions)
|
|
510
|
+
self.destination_offset = destination_offset
|
|
511
|
+
|
|
512
|
+
if isinstance(self.operands[0], GeneralPurposeRegister):
|
|
513
|
+
if self.operands[0].size != self.destination_size:
|
|
514
|
+
raise ValueError(
|
|
515
|
+
"Can not store result in register %s: size mismatch with return type %s"
|
|
516
|
+
% (str(self.operands[0]), str(self.destination_type))
|
|
517
|
+
)
|
|
518
|
+
elif isinstance(self.operands[0], MMXRegister):
|
|
519
|
+
if self.destination_size not in {4, 8}:
|
|
520
|
+
raise ValueError(
|
|
521
|
+
"Can not store result in register %s: size mismatch with return type %s"
|
|
522
|
+
% (str(self.operands[0]), str(self.destination_type))
|
|
523
|
+
)
|
|
524
|
+
elif isinstance(self.operands[0], XMMRegister):
|
|
525
|
+
if self.destination_size not in {4, 8}:
|
|
526
|
+
raise ValueError(
|
|
527
|
+
"Can not store result in register %s: size mismatch with return type %s"
|
|
528
|
+
% (str(self.operands[0]), str(self.destination_type))
|
|
529
|
+
)
|
|
530
|
+
elif isinstance(self.operands[0], YMMRegister):
|
|
531
|
+
raise ValueError(
|
|
532
|
+
"Can not store result in register %s: unsupported register type"
|
|
533
|
+
)
|
|
534
|
+
elif is_int32(self.operands[0]):
|
|
535
|
+
if not self.destination_type.is_integer:
|
|
536
|
+
raise ValueError(
|
|
537
|
+
"Can not store integer result %d: type mismatch with result type %s"
|
|
538
|
+
% (self.operands[0], str(self.destination_type))
|
|
539
|
+
)
|
|
540
|
+
if is_int16(self.operands[0]) and self.destination_size < 2:
|
|
541
|
+
raise ValueError(
|
|
542
|
+
"Can not store integer result %d: size mismatch with result type %s"
|
|
543
|
+
% (self.operands[0], str(self.destination_type))
|
|
544
|
+
)
|
|
545
|
+
if is_int32(self.operands[0]) and self.destination_size < 4:
|
|
546
|
+
raise ValueError(
|
|
547
|
+
"Can not store integer result %d: size mismatch with result type %s"
|
|
548
|
+
% (self.operands[0], str(self.destination_type))
|
|
549
|
+
)
|
|
550
|
+
|
|
551
|
+
if nervapy.stream.active_stream is not None:
|
|
552
|
+
nervapy.stream.active_stream.add_instruction(self)
|
|
553
|
+
|
|
554
|
+
def format(self, assembly_format, indent=False, line_number=None):
|
|
555
|
+
assert assembly_format in {
|
|
556
|
+
"peachpy",
|
|
557
|
+
"go",
|
|
558
|
+
}, "Supported assembly formats are 'peachpy' and 'go'"
|
|
559
|
+
|
|
560
|
+
text = "\t" if indent else ""
|
|
561
|
+
if assembly_format == "go":
|
|
562
|
+
from nervapy.x86_64.operand import format_operand
|
|
563
|
+
from nervapy.x86_64.registers import MMXRegister, XMMRegister
|
|
564
|
+
|
|
565
|
+
if isinstance(self.operands[0], MMXRegister):
|
|
566
|
+
mov_name = {4: "MOVD", 8: "MOVQ"}[self.destination_size]
|
|
567
|
+
elif isinstance(self.operands[0], XMMRegister):
|
|
568
|
+
if self.destination_type.is_floating_point:
|
|
569
|
+
mov_name = {4: "MOVSS", 8: "MOVSD"}[self.destination_size]
|
|
570
|
+
else:
|
|
571
|
+
mov_name = {4: "MOVD", 8: "MOVQ"}[self.destination_size]
|
|
572
|
+
else:
|
|
573
|
+
mov_name = {1: "MOVB", 2: "MOVW", 4: "MOVL", 8: "MOVQ"}[
|
|
574
|
+
self.destination_size
|
|
575
|
+
]
|
|
576
|
+
return text + "%s %s, ret+%d(FP)" % (
|
|
577
|
+
mov_name,
|
|
578
|
+
format_operand(self.operands[0], "go"),
|
|
579
|
+
self.destination_offset,
|
|
580
|
+
)
|
|
581
|
+
|
|
582
|
+
else:
|
|
583
|
+
return text + str(self)
|
|
584
|
+
|
|
585
|
+
|
|
586
|
+
class SWAP:
|
|
587
|
+
@staticmethod
|
|
588
|
+
def REGISTERS(register_x, register_y):
|
|
589
|
+
from nervapy.x86_64.registers import Register
|
|
590
|
+
|
|
591
|
+
if isinstance(register_x, Register) and isinstance(register_y, Register):
|
|
592
|
+
if (
|
|
593
|
+
register_x.kind == register_y.kind
|
|
594
|
+
and register_x.size == register_y.size
|
|
595
|
+
):
|
|
596
|
+
register_x.virtual_id, register_y.virtual_id = (
|
|
597
|
+
register_y.virtual_id,
|
|
598
|
+
register_x.virtual_id,
|
|
599
|
+
)
|
|
600
|
+
register_x.physical_id, register_y.physical_id = (
|
|
601
|
+
register_y.physical_id,
|
|
602
|
+
register_x.physical_id,
|
|
603
|
+
)
|
|
604
|
+
else:
|
|
605
|
+
raise ValueError(
|
|
606
|
+
"Registers {0} and {1} have incompatible register types".format(
|
|
607
|
+
register_x, register_y
|
|
608
|
+
)
|
|
609
|
+
)
|
|
610
|
+
else:
|
|
611
|
+
raise TypeError("Arguments must be of register regtype")
|
|
612
|
+
|
|
613
|
+
|
|
614
|
+
def REDUCE(reduction_instruction, registers):
|
|
615
|
+
if not isinstance(registers, (tuple, list)):
|
|
616
|
+
raise ValueError("List or tuple of registers expected")
|
|
617
|
+
offset = 1
|
|
618
|
+
while offset < len(registers):
|
|
619
|
+
for i in range(offset, len(registers), 2 * offset):
|
|
620
|
+
reduction_instruction(registers[i - offset], registers[i])
|
|
621
|
+
offset *= 2
|
|
622
|
+
return registers[0]
|
|
623
|
+
|
|
624
|
+
|
|
625
|
+
class IACA:
|
|
626
|
+
|
|
627
|
+
class START(Instruction):
|
|
628
|
+
def __init__(self, *args, **kwargs):
|
|
629
|
+
origin = kwargs.get("origin")
|
|
630
|
+
prototype = kwargs.get("prototype")
|
|
631
|
+
if (
|
|
632
|
+
origin is None
|
|
633
|
+
and prototype is None
|
|
634
|
+
and nervapy.x86_64.options.get_debug_level() > 0
|
|
635
|
+
):
|
|
636
|
+
origin = inspect.stack()
|
|
637
|
+
super(IACA.START, self).__init__("IACA.START", origin=origin)
|
|
638
|
+
|
|
639
|
+
self.operands = tuple(map(check_operand, args))
|
|
640
|
+
if len(self.operands) == 0:
|
|
641
|
+
# It is not an error to return nothing from a function with a return type
|
|
642
|
+
self.in_regs = tuple()
|
|
643
|
+
self.out_regs = tuple()
|
|
644
|
+
self.out_operands = tuple()
|
|
645
|
+
self.encodings.append(
|
|
646
|
+
(
|
|
647
|
+
0x0,
|
|
648
|
+
lambda op: bytearray(
|
|
649
|
+
[0x0F, 0x0B, 0xBB, 0x6F, 0x00, 0x00, 0x00, 0x64, 0x67, 0x90]
|
|
650
|
+
),
|
|
651
|
+
)
|
|
652
|
+
)
|
|
653
|
+
else:
|
|
654
|
+
raise SyntaxError('Pseudo-instruction "IACA.START" requires 0 operands')
|
|
655
|
+
if nervapy.stream.active_stream is not None:
|
|
656
|
+
nervapy.stream.active_stream.add_instruction(self)
|
|
657
|
+
|
|
658
|
+
class END(Instruction):
|
|
659
|
+
def __init__(self, *args, **kwargs):
|
|
660
|
+
origin = kwargs.get("origin")
|
|
661
|
+
prototype = kwargs.get("prototype")
|
|
662
|
+
if (
|
|
663
|
+
origin is None
|
|
664
|
+
and prototype is None
|
|
665
|
+
and nervapy.x86_64.options.get_debug_level() > 0
|
|
666
|
+
):
|
|
667
|
+
origin = inspect.stack()
|
|
668
|
+
super(IACA.END, self).__init__("IACA.END", origin=origin)
|
|
669
|
+
|
|
670
|
+
self.operands = tuple(map(check_operand, args))
|
|
671
|
+
if len(self.operands) == 0:
|
|
672
|
+
self.in_regs = tuple()
|
|
673
|
+
self.out_regs = tuple()
|
|
674
|
+
self.out_operands = tuple()
|
|
675
|
+
self.encodings.append(
|
|
676
|
+
(
|
|
677
|
+
0x0,
|
|
678
|
+
lambda op: bytearray(
|
|
679
|
+
[0xBB, 0xDE, 0x00, 0x00, 0x00, 0x64, 0x67, 0x90, 0x0F, 0x0B]
|
|
680
|
+
),
|
|
681
|
+
)
|
|
682
|
+
)
|
|
683
|
+
else:
|
|
684
|
+
raise SyntaxError('Pseudo-instruction "IACA.END" requires 0 operands')
|
|
685
|
+
if nervapy.stream.active_stream is not None:
|
|
686
|
+
nervapy.stream.active_stream.add_instruction(self)
|