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.
Files changed (74) hide show
  1. nervapy/__init__.py +50 -0
  2. nervapy/abi.py +91 -0
  3. nervapy/arm/__init__.py +124 -0
  4. nervapy/arm/__main__.py +0 -0
  5. nervapy/arm/abi.py +138 -0
  6. nervapy/arm/formats.py +49 -0
  7. nervapy/arm/function.py +2465 -0
  8. nervapy/arm/generic.py +10796 -0
  9. nervapy/arm/instructions.py +519 -0
  10. nervapy/arm/isa.py +409 -0
  11. nervapy/arm/literal_pool.py +331 -0
  12. nervapy/arm/microarchitecture.py +211 -0
  13. nervapy/arm/pseudo.py +652 -0
  14. nervapy/arm/registers.py +1458 -0
  15. nervapy/arm/vfpneon.py +4092 -0
  16. nervapy/arm.py +13 -0
  17. nervapy/c/__init__.py +1 -0
  18. nervapy/c/types.py +436 -0
  19. nervapy/codegen.py +99 -0
  20. nervapy/common/__init__.py +4 -0
  21. nervapy/common/function.py +5 -0
  22. nervapy/common/regalloc.py +121 -0
  23. nervapy/constant_data.py +282 -0
  24. nervapy/encoder.py +246 -0
  25. nervapy/formats/__init__.py +2 -0
  26. nervapy/formats/elf/__init__.py +4 -0
  27. nervapy/formats/elf/file.py +178 -0
  28. nervapy/formats/elf/image.py +106 -0
  29. nervapy/formats/elf/section.py +422 -0
  30. nervapy/formats/elf/symbol.py +281 -0
  31. nervapy/formats/macho/__init__.py +2 -0
  32. nervapy/formats/macho/file.py +123 -0
  33. nervapy/formats/macho/image.py +143 -0
  34. nervapy/formats/macho/section.py +322 -0
  35. nervapy/formats/macho/symbol.py +158 -0
  36. nervapy/formats/mscoff/__init__.py +8 -0
  37. nervapy/formats/mscoff/image.py +132 -0
  38. nervapy/formats/mscoff/section.py +181 -0
  39. nervapy/formats/mscoff/symbol.py +148 -0
  40. nervapy/function.py +136 -0
  41. nervapy/literal.py +731 -0
  42. nervapy/loader.py +188 -0
  43. nervapy/name.py +159 -0
  44. nervapy/parse.py +52 -0
  45. nervapy/stream.py +58 -0
  46. nervapy/util.py +126 -0
  47. nervapy/writer.py +518 -0
  48. nervapy/x86_64/__init__.py +324 -0
  49. nervapy/x86_64/__main__.py +407 -0
  50. nervapy/x86_64/abi.py +517 -0
  51. nervapy/x86_64/amd.py +6464 -0
  52. nervapy/x86_64/avx.py +102029 -0
  53. nervapy/x86_64/crypto.py +1533 -0
  54. nervapy/x86_64/encoding.py +424 -0
  55. nervapy/x86_64/fma.py +19138 -0
  56. nervapy/x86_64/function.py +2707 -0
  57. nervapy/x86_64/generic.py +23384 -0
  58. nervapy/x86_64/instructions.py +500 -0
  59. nervapy/x86_64/isa.py +476 -0
  60. nervapy/x86_64/lower.py +126 -0
  61. nervapy/x86_64/mask.py +2593 -0
  62. nervapy/x86_64/meta.py +143 -0
  63. nervapy/x86_64/mmxsse.py +17265 -0
  64. nervapy/x86_64/nacl.py +327 -0
  65. nervapy/x86_64/operand.py +1204 -0
  66. nervapy/x86_64/options.py +21 -0
  67. nervapy/x86_64/pseudo.py +686 -0
  68. nervapy/x86_64/registers.py +1225 -0
  69. nervapy/x86_64/types.py +17 -0
  70. nervapy/x86_64/uarch.py +580 -0
  71. pynerva-0.0.7.dist-info/METADATA +310 -0
  72. pynerva-0.0.7.dist-info/RECORD +74 -0
  73. pynerva-0.0.7.dist-info/WHEEL +4 -0
  74. pynerva-0.0.7.dist-info/licenses/LICENSE.rst +15 -0
nervapy/arm/pseudo.py ADDED
@@ -0,0 +1,652 @@
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
+ from nervapy.arm.instructions import Instruction, Operand, QuasiInstruction
8
+
9
+
10
+ class Label(object):
11
+ def __init__(self, name, is_external=False):
12
+ super(Label, self).__init__()
13
+ self.name = name
14
+ self.is_external = is_external
15
+
16
+ def __str__(self):
17
+ return "<LABEL:" + self.name + ">"
18
+
19
+
20
+ class ExternalFunction(object):
21
+ """Represents an external function that needs to be imported."""
22
+
23
+ def __init__(self, name):
24
+ super(ExternalFunction, self).__init__()
25
+ self.name = name
26
+
27
+ def __str__(self):
28
+ return self.name
29
+
30
+
31
+ class LabelQuasiInstruction(QuasiInstruction):
32
+ def __init__(self, name, origin=None):
33
+ super(LabelQuasiInstruction, self).__init__("<LABEL>", origin=origin)
34
+ if name.is_label():
35
+ self.name = name.label
36
+ else:
37
+ raise TypeError("Name must be an Label or string")
38
+ self.input_branches = set()
39
+
40
+ def __str__(self):
41
+ return "L" + self.name + ":"
42
+
43
+
44
+ class AlignQuasiInstruction(QuasiInstruction):
45
+ supported_alignments = [2, 4, 8, 16, 32]
46
+
47
+ def __init__(self, alignment, origin=None):
48
+ super(AlignQuasiInstruction, self).__init__("<ALIGN>", origin=origin)
49
+ if isinstance(alignment, int):
50
+ if alignment in AlignQuasiInstruction.supported_alignments:
51
+ self.alignment = alignment
52
+ else:
53
+ raise ValueError(
54
+ "The alignment value {0} is not in the list of supported alignments ({1})".format(
55
+ alignment, ", ".join(AlignQuasiInstruction.supported_alignments)
56
+ )
57
+ )
58
+ else:
59
+ raise TypeError("The alignment value must be an integer")
60
+
61
+ def __str__(self):
62
+ return "align {0}".format(self.alignment)
63
+
64
+
65
+ class LoadConstantPseudoInstruction(Instruction):
66
+ def __init__(self, destination, source, origin=None):
67
+ super(LoadConstantPseudoInstruction, self).__init__(
68
+ "<LOAD-CONSTANT>", origin=origin
69
+ )
70
+ if destination.is_register():
71
+ self.destination = destination
72
+ else:
73
+ raise ValueError(
74
+ "Load constant pseudo-instruction expects a register as a destination"
75
+ )
76
+ if source.is_constant():
77
+ if (
78
+ destination.register.size * 8
79
+ == source.constant.size * source.constant.repeats
80
+ ):
81
+ self.source = source
82
+ elif (
83
+ destination.register.size == 16
84
+ and source.constant.size == 64
85
+ and source.constant.repeats == 1
86
+ and source.constant.basic_type == "float64"
87
+ ):
88
+ self.source = source
89
+ elif (
90
+ destination.register.size == 16
91
+ and source.constant.size == 32
92
+ and source.constant.repeats == 1
93
+ and source.constant.basic_type == "float32"
94
+ ):
95
+ self.source = source
96
+ else:
97
+ raise ValueError(
98
+ "The size of constant should be the same as the size of register"
99
+ )
100
+ else:
101
+ raise ValueError(
102
+ "Load constant pseudo-instruction expects a Constant instance as a source"
103
+ )
104
+ self.size = 4 + 4
105
+
106
+ def __str__(self):
107
+ return "LOAD.CONSTANT {0} = {1}".format(self.destination, self.source)
108
+
109
+ def get_input_registers_list(self):
110
+ return list()
111
+
112
+ def get_output_registers_list(self):
113
+ return [self.destination.register]
114
+
115
+ def get_constant(self):
116
+ return self.source.constant
117
+
118
+ def get_local_variable(self):
119
+ return None
120
+
121
+
122
+ class LoadArgumentPseudoInstruction(Instruction):
123
+ def __init__(self, destination, source, origin=None):
124
+ from nervapy import Argument, Yep32f, Yep64f
125
+ from nervapy.arm.function import active_function
126
+
127
+ super(LoadArgumentPseudoInstruction, self).__init__(
128
+ "<LOAD-PARAMETER>", [destination, source], origin=origin
129
+ )
130
+ if isinstance(source, Argument):
131
+ argument = active_function.find_argument(source)
132
+ if argument is not None:
133
+ self.argument = argument
134
+ else:
135
+ raise ValueError(
136
+ "{0} is not an argument of the active function".format(source)
137
+ )
138
+ else:
139
+ raise TypeError("LOAD.ARGUMENT expects an Argument object as a source")
140
+ if destination.is_general_purpose_register() and (
141
+ argument.is_integer or argument.is_pointer or argument.is_codeunit
142
+ ):
143
+ if destination.register.size >= argument.size:
144
+ self.destination = destination
145
+ else:
146
+ raise ValueError(
147
+ "Destination register %s is too narrow for the argument %s"
148
+ % (destination, argument)
149
+ )
150
+ elif destination.is_s_register() and source.c_type == Yep32f:
151
+ self.destination = destination
152
+ elif destination.is_d_register() and source.c_type == Yep64f:
153
+ self.destination = destination
154
+ else:
155
+ raise ValueError("Unsupported combination of instruction operands")
156
+
157
+ def __str__(self):
158
+ return "LOAD.ARGUMENT {0} = {1}".format(self.destination, self.argument)
159
+
160
+ def get_input_registers_list(self):
161
+ from nervapy.arm.registers import sp
162
+
163
+ if self.argument.register:
164
+ return [self.argument.register]
165
+ else:
166
+ return [sp]
167
+
168
+ def get_output_registers_list(self):
169
+ return [self.destination.register]
170
+
171
+
172
+ class ReturnInstruction(QuasiInstruction):
173
+ def __init__(self, return_value=None, origin=None):
174
+ super(ReturnInstruction, self).__init__("RETURN", origin=origin)
175
+ if return_value.is_none():
176
+ self.return_value = None
177
+ elif return_value.is_modified_immediate12():
178
+ self.return_value = return_value.immediate
179
+ else:
180
+ raise ValueError(
181
+ "Return value is not representable as a 12-bit modified immediate integer"
182
+ )
183
+
184
+ def to_instruction_list(self):
185
+ from nervapy.arm.generic import BX, MOV
186
+ from nervapy.arm.registers import lr, r0
187
+ from nervapy.stream import InstructionStream
188
+
189
+ return_instructions = InstructionStream()
190
+ with return_instructions:
191
+ if self.return_value is None:
192
+ pass
193
+ else:
194
+ MOV(r0, self.return_value)
195
+ BX(lr)
196
+ return list(iter(return_instructions))
197
+
198
+ def __str__(self):
199
+ return "RETURN {0}".format(self.return_value)
200
+
201
+ def get_input_registers_list(self):
202
+ from nervapy.arm.registers import sp
203
+
204
+ return [sp]
205
+
206
+ def get_output_registers_list(self):
207
+ from nervapy.arm.registers import sp
208
+
209
+ return [sp]
210
+
211
+ def get_constant(self):
212
+ return None
213
+
214
+ def get_local_variable(self):
215
+ return None
216
+
217
+
218
+ class AssumeInitializedPseudoInstruction(Instruction):
219
+ def __init__(self, destination, origin=None):
220
+ super(AssumeInitializedPseudoInstruction, self).__init__(
221
+ "<ASSUME-INITIALIZED>", origin=origin
222
+ )
223
+ if destination.is_register():
224
+ self.destination = destination
225
+ else:
226
+ raise ValueError(
227
+ "Assume initialized pseudo-instruction expects a register as a destination"
228
+ )
229
+ self.size = 0
230
+
231
+ def __str__(self):
232
+ return "ASSUME.INITIALIZED {0}".format(self.destination)
233
+
234
+ def get_input_registers_list(self):
235
+ return list()
236
+
237
+ def get_output_registers_list(self):
238
+ return [self.destination.register]
239
+
240
+ def get_constant(self):
241
+ return None
242
+
243
+ def get_local_variable(self):
244
+ return None
245
+
246
+
247
+ def LABEL(name):
248
+ instruction = LabelQuasiInstruction(Operand(name))
249
+ if nervapy.stream.active_stream is not None:
250
+ nervapy.stream.active_stream.add_instruction(instruction)
251
+ return instruction
252
+
253
+
254
+ class Loop:
255
+ def __init__(self, name=None):
256
+ if name is None:
257
+ import inspect
258
+ import re
259
+
260
+ source_line = inspect.stack()[1][4][0].strip()
261
+ match = re.match(
262
+ "(?:\\w+\\.)*(\\w+)\\s*=\\s*(?:\\w+\\.)*Loop\\(.*\\)", source_line
263
+ )
264
+ if match:
265
+ name = match.group(1)
266
+ else:
267
+ match = re.match(
268
+ "\\s*with\\s+(?:\\w+\\.)*Loop\\(.*\\)\\s+as\\s+(\\w+)\\s*:\\s*",
269
+ source_line,
270
+ )
271
+ if match:
272
+ name = match.group(1)
273
+ else:
274
+ raise ValueError("Loop name is unspecified")
275
+ self.name = name
276
+ self.begin = Label(self.name + "_begin")
277
+ self.end = Label(self.name + "_end")
278
+
279
+ def __enter__(self):
280
+ LABEL(self.begin)
281
+ return self
282
+
283
+ def __exit__(self, type, value, traceback):
284
+ if type is None:
285
+ LABEL(self.end)
286
+
287
+
288
+ def ALIGN(alignment):
289
+ instruction = AlignQuasiInstruction(alignment)
290
+ if nervapy.stream.active_stream is not None:
291
+ nervapy.stream.active_stream.add_instruction(instruction)
292
+ return instruction
293
+
294
+
295
+ def RETURN(return_value=None):
296
+ instruction = ReturnInstruction(Operand(return_value))
297
+ if nervapy.stream.active_stream is not None:
298
+ nervapy.stream.active_stream.add_instruction(instruction)
299
+ return instruction
300
+
301
+
302
+ class LOAD:
303
+ @staticmethod
304
+ def CONSTANT(destination, source):
305
+ from nervapy.arm.function import active_function
306
+
307
+ origin = inspect.stack() if active_function.collect_origin else None
308
+ instruction = LoadConstantPseudoInstruction(
309
+ Operand(destination), Operand(source), origin=origin
310
+ )
311
+ if nervapy.stream.active_stream is not None:
312
+ nervapy.stream.active_stream.add_instruction(instruction)
313
+ return instruction
314
+
315
+ @staticmethod
316
+ def ARGUMENT(destination, source):
317
+ from nervapy.arm.function import active_function
318
+
319
+ origin = inspect.stack() if active_function.collect_origin else None
320
+ instruction = LoadArgumentPseudoInstruction(
321
+ Operand(destination), source, origin=origin
322
+ )
323
+ if nervapy.stream.active_stream is not None:
324
+ nervapy.stream.active_stream.add_instruction(instruction)
325
+ return instruction
326
+
327
+ @staticmethod
328
+ def ARGUMENTS():
329
+ from nervapy import Yep32f, Yep64f
330
+ from nervapy.arm.function import active_function
331
+ from nervapy.arm.registers import (DRegister, GeneralPurposeRegister,
332
+ SRegister)
333
+
334
+ registers = list()
335
+ for argument in active_function.arguments:
336
+ if argument.is_pointer or argument.is_integer or argument.is_codeunit:
337
+ if argument.size <= 4:
338
+ register = GeneralPurposeRegister()
339
+ LOAD.ARGUMENT(register, argument)
340
+ else:
341
+ raise NotImplementedError("TODO: Handle 8-byte integers")
342
+ elif argument.is_floating_point:
343
+ if argument.c_type == Yep32f:
344
+ register = SRegister()
345
+ LOAD.ARGUMENT(register, argument)
346
+ elif argument.c_type == Yep64f:
347
+ register = DRegister()
348
+ LOAD.ARGUMENT(register, argument)
349
+ else:
350
+ raise TypeError("Unknown floating-point type %s" % argument.c_type)
351
+ else:
352
+ raise TypeError("Unknown argument type %s" % argument.c_type)
353
+ registers.append(register)
354
+ return tuple(registers)
355
+
356
+ @staticmethod
357
+ def ZERO(destination, ctype):
358
+ if isinstance(ctype, nervapy.c.Type):
359
+ # if isinstance(destination, SRegister):
360
+ # PXOR( destination, destination )
361
+ # elif isinstance(destination, DRegister):
362
+ # if ctype.is_floating_point():
363
+ # if Target.has_avx():
364
+ # SIMD_XOR = {4: VXORPS, 8: VXORPD }[ctype.get_size()]
365
+ # else:
366
+ # SIMD_XOR = {4: XORPS, 8: XORPD}[ctype.get_size()]
367
+ # else:
368
+ # SIMD_XOR = VPXOR if Target.has_avx() else PXOR
369
+ # SIMD_XOR( destination, destination )
370
+ # elif isinstance(destination, QRegister):
371
+ # LOAD.ZERO( destination.get_oword(), ctype )
372
+ # else:
373
+ raise TypeError("Unsupported type of destination register")
374
+ else:
375
+ raise TypeError("Type must be a C type")
376
+
377
+ @staticmethod
378
+ def ELEMENT(destination, source, ctype, increment_pointer=False):
379
+ from nervapy import Type
380
+ from nervapy.arm.function import active_function
381
+ from nervapy.arm.generic import ADD, LDR, LDRB, LDRH, LDRSB, LDRSH
382
+ from nervapy.arm.instructions import Operand
383
+ from nervapy.arm.registers import (DRegister, GeneralPurposeRegister,
384
+ Register, SRegister)
385
+ from nervapy.arm.vfpneon import VLDR
386
+
387
+ if not isinstance(ctype, Type):
388
+ raise TypeError("Type must be a C type")
389
+ if isinstance(destination, Register):
390
+ raise TypeError("Destination must be a register")
391
+ if not Operand(source).is_memory_address():
392
+ raise TypeError("Source must be a memory operand")
393
+ memory_size = ctype.get_size(active_function.abi)
394
+ if isinstance(destination, GeneralPurposeRegister):
395
+ if ctype.is_unsigned_integer:
396
+ if memory_size == 4:
397
+ if increment_pointer:
398
+ LDR(destination, source, memory_size)
399
+ else:
400
+ LDR(destination, source)
401
+ elif memory_size == 2:
402
+ if increment_pointer:
403
+ LDRH(destination, source, memory_size)
404
+ else:
405
+ LDRH(destination, source)
406
+ elif memory_size == 1:
407
+ if increment_pointer:
408
+ LDRB(destination, source, memory_size)
409
+ else:
410
+ LDRB(destination, source)
411
+ else:
412
+ raise ValueError(
413
+ "Invalid memory operand size {0}".format(memory_size)
414
+ )
415
+ elif ctype.is_signed_integer:
416
+ if memory_size == 4:
417
+ if increment_pointer:
418
+ LDR(destination, source, memory_size)
419
+ else:
420
+ LDR(destination, source)
421
+ elif memory_size == 2:
422
+ if increment_pointer:
423
+ LDRSH(destination, source, memory_size)
424
+ else:
425
+ LDRSH(destination, source)
426
+ elif memory_size == 1:
427
+ if increment_pointer:
428
+ LDRSB(destination, source, memory_size)
429
+ else:
430
+ LDRSB(destination, source)
431
+ else:
432
+ raise ValueError(
433
+ "Invalid memory operand size {0}".format(memory_size)
434
+ )
435
+ else:
436
+ raise TypeError("Invalid memory operand type")
437
+ elif isinstance(destination, SRegister):
438
+ if ctype.is_floating_point:
439
+ if memory_size == 4:
440
+ VLDR(destination, source)
441
+ if increment_pointer:
442
+ address_register = Operand(source).get_registers_list()[0]
443
+ ADD(address_register, memory_size)
444
+ else:
445
+ raise ValueError(
446
+ "Invalid memory operand size {0}".format(memory_size)
447
+ )
448
+ else:
449
+ raise TypeError("Invalid memory operand type")
450
+ elif isinstance(destination, DRegister):
451
+ if ctype.is_floating_point:
452
+ if memory_size == 8:
453
+ VLDR(destination, source)
454
+ if increment_pointer:
455
+ address_register = Operand(source).get_registers_list()[0]
456
+ ADD(address_register, memory_size)
457
+ else:
458
+ raise ValueError(
459
+ "Invalid memory operand size {0}".format(memory_size)
460
+ )
461
+ else:
462
+ raise TypeError("Invalid memory operand type")
463
+ else:
464
+ raise TypeError("Unsupported destination type")
465
+
466
+
467
+ class STORE:
468
+ @staticmethod
469
+ def ELEMENT(destination, source, ctype, increment_pointer=False):
470
+ from nervapy.arm.function import active_function
471
+ from nervapy.arm.generic import ADD, STR, STRB, STRH
472
+ from nervapy.arm.instructions import Operand
473
+ from nervapy.arm.registers import (DRegister, GeneralPurposeRegister,
474
+ SRegister)
475
+ from nervapy.arm.vfpneon import VSTR
476
+
477
+ if isinstance(ctype, nervapy.c.Type):
478
+ if Operand(destination).is_memory_address():
479
+ if Operand(source).is_register():
480
+ memory_size = ctype.get_size(active_function.abi)
481
+ if isinstance(source, GeneralPurposeRegister):
482
+ if ctype.is_integer():
483
+ if memory_size == 4:
484
+ if increment_pointer:
485
+ STR(source, destination, memory_size)
486
+ else:
487
+ STR(source, destination)
488
+ elif memory_size == 2:
489
+ if increment_pointer:
490
+ STRH(source, destination, memory_size)
491
+ else:
492
+ STRH(source, destination)
493
+ elif memory_size == 1:
494
+ if increment_pointer:
495
+ STRB(source, destination, memory_size)
496
+ else:
497
+ STRB(source, destination)
498
+ else:
499
+ raise ValueError(
500
+ "Invalid memory operand size {0}".format(
501
+ memory_size
502
+ )
503
+ )
504
+ else:
505
+ raise TypeError("Invalid memory operand type")
506
+ elif isinstance(source, SRegister):
507
+ if ctype.is_floating_point():
508
+ if memory_size == 4:
509
+ VSTR(source, destination)
510
+ if increment_pointer:
511
+ address_register = Operand(
512
+ destination
513
+ ).get_registers_list()[0]
514
+ ADD(address_register, memory_size)
515
+ else:
516
+ raise ValueError(
517
+ "Invalid memory operand size {0}".format(
518
+ memory_size
519
+ )
520
+ )
521
+ else:
522
+ raise TypeError("Invalid memory operand type")
523
+ elif isinstance(source, DRegister):
524
+ if ctype.is_floating_point():
525
+ if memory_size == 8:
526
+ VSTR(source, destination)
527
+ if increment_pointer:
528
+ address_register = Operand(
529
+ destination
530
+ ).get_registers_list()[0]
531
+ ADD(address_register, memory_size)
532
+ else:
533
+ raise ValueError(
534
+ "Invalid memory operand size {0}".format(
535
+ memory_size
536
+ )
537
+ )
538
+ else:
539
+ raise TypeError("Invalid memory operand type")
540
+ else:
541
+ raise TypeError("Source must be a general-purpose register")
542
+ else:
543
+ raise TypeError("Source must be a register")
544
+ else:
545
+ raise TypeError("Destination must be a memory operand")
546
+ else:
547
+ raise TypeError("Type must be a C type")
548
+
549
+
550
+ class ASSUME:
551
+ @staticmethod
552
+ def INITIALIZED(destination):
553
+ from nervapy.arm.function import active_function
554
+
555
+ origin = inspect.stack() if active_function.collect_origin else None
556
+ instruction = AssumeInitializedPseudoInstruction(
557
+ Operand(destination), origin=origin
558
+ )
559
+ if nervapy.stream.active_stream is not None:
560
+ nervapy.stream.active_stream.add_instruction(instruction)
561
+ return instruction
562
+
563
+
564
+ class IMPORT:
565
+ """Declare external functions for ARMCC assembly."""
566
+
567
+ @staticmethod
568
+ def FUNCTION(name):
569
+ """
570
+ Declare an external function that will be called.
571
+ For ARMCC, this generates an IMPORT directive.
572
+
573
+ Args:
574
+ name: Name of the external function (string or ExternalFunction)
575
+
576
+ Returns:
577
+ ExternalFunction object that can be used with BL
578
+ """
579
+ from nervapy.arm.function import active_function
580
+
581
+ if isinstance(name, str):
582
+ external_func = ExternalFunction(name)
583
+ elif isinstance(name, ExternalFunction):
584
+ external_func = name
585
+ else:
586
+ raise TypeError("Function name must be a string or ExternalFunction")
587
+
588
+ # Register the external function with the active function
589
+ if active_function is not None:
590
+ if not hasattr(active_function, "external_functions"):
591
+ active_function.external_functions = set()
592
+ active_function.external_functions.add(external_func.name)
593
+
594
+ return external_func
595
+
596
+
597
+ class INIT:
598
+ @staticmethod
599
+ def ONCE(register_class, constant, register=None):
600
+ if register is None:
601
+ origin = (
602
+ inspect.stack()
603
+ if nervapy.arm.function.active_function.collect_origin
604
+ else None
605
+ )
606
+ register = register_class()
607
+ instruction = LoadConstantPseudoInstruction(
608
+ Operand(register), Operand(constant), origin=origin
609
+ )
610
+ if nervapy.stream.active_stream is not None:
611
+ nervapy.stream.active_stream.add_instruction(instruction)
612
+ return register
613
+ else:
614
+ return register
615
+
616
+
617
+ class REDUCE:
618
+ @staticmethod
619
+ def SUM(acc, input_type, output_type):
620
+ raise NotImplementedError("Needs ARM implementation")
621
+
622
+ @staticmethod
623
+ def MAX(acc, input_type, output_type):
624
+ raise NotImplementedError("Needs ARM implementation")
625
+
626
+ @staticmethod
627
+ def MIN(acc, input_type, output_type):
628
+ raise NotImplementedError("Needs ARM implementation")
629
+
630
+
631
+ class SWAP:
632
+ @staticmethod
633
+ def REGISTERS(register_x, register_y):
634
+ from nervapy.arm.registers import Register
635
+
636
+ if isinstance(register_x, Register) and isinstance(register_y, Register):
637
+ if (
638
+ register_x.type == register_y.type
639
+ and register_x.size == register_y.size
640
+ ):
641
+ register_x.number, register_y.number = (
642
+ register_y.number,
643
+ register_x.number,
644
+ )
645
+ else:
646
+ raise ValueError(
647
+ "Registers {0} and {1} have incompatible register types".format(
648
+ register_x, register_y
649
+ )
650
+ )
651
+ else:
652
+ raise TypeError("Arguments must be of register type")