Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/ext/gen_interpreters.py
8817 views
1
r"""
2
Generate interpreters for fast_callable
3
4
AUTHORS:
5
6
- Carl Witty
7
8
This file is part of the Sage support for "planned" computations;
9
that is, computations that are separated into a planning stage and
10
a plan-execution stage. Here, we generate fast interpreters for plan
11
executions.
12
13
There are at least two kinds of computations that are often planned in
14
this fashion. First is arithmetic expression evaluation, where we
15
take an arbitrary user-specified arithmetic expression and compile it
16
into a bytecode form for fast interpretation. Second is things like
17
FFTs and large multiplications, where large problems are split into
18
multiple smaller problems... we can do the logical "splitting" for a
19
given size only once, producing a plan which can be reused as often as
20
we want for different problems of the same size. Currently only
21
arithmetic expression evaluation is implemented, but other kinds of
22
planned computations should be easy to add.
23
24
Typically, for arithmetic expressions, we want the storage of
25
intermediate results to be handled automatically (on a stack); for
26
FFTs/multiplications/etc., the planner will keep track of intermediate
27
results itself.
28
29
For arithmetic expression evaluation, we want to have lots of
30
interpreters (at least one, and possibly several, per
31
specially-handled type). Also, for any given type, we have many
32
possible variants of instruction encoding, etc.; some of these could
33
be handled with conditional compilation, but some are more
34
complicated. So we end up writing an interpreter generator.
35
36
We want to share as much code as possible across all of these
37
interpreters, while still maintaining the freedom to make drastic
38
changes in the interpretation strategy (which may change the
39
generated code, the calling convention for the interpreter, etc.)
40
41
To make this work, the interpreter back-end is divided into three
42
parts:
43
44
1. The interpreter itself, in C or C++.
45
46
2. The wrapper, which is a Cython object holding the
47
constants, code, etc., and which actually calls the interpreter.
48
49
3. The code generator.
50
51
We generate parts 1 and 2. The code generator is table-driven,
52
and we generate the tables for the code generator.
53
54
There are a lot of techniques for fast interpreters that we do not yet
55
use; hopefully at least some of these will eventually be implemented:
56
57
- using gcc's "labels as values" extension where available
58
59
- top-of-stack caching
60
61
- superinstructions and/or superoperators
62
63
- static stack caching
64
65
- context threading/subrouting threading
66
67
- selective inlining/dynamic superinstructions
68
69
- automatic replication
70
71
Interpreters may be stack-based or register-based. Recent research
72
suggests that register-based interpreters are better, but the
73
researchers are investigating interpreters for entire programming
74
languages, rather than interpreters for expressions. I suspect
75
that stack-based expression interpreters may be better. However,
76
we'll implement both varieties and see what's best.
77
78
The relative costs of stack- and register-based interpreters will
79
depend on the costs of moving values. For complicated types (like
80
mpz_t), a register-based interpreter will quite likely be better,
81
since it will avoid moving values.
82
83
We will NOT support any sort of storage of bytecode; instead, the
84
code must be re-generated from expression trees in every Sage run.
85
This means that we can trivially experiment with different styles of
86
interpreter, or even use quite different interpreters depending on
87
the architecture, without having to worry about forward and backward
88
compatibility.
89
"""
90
#*****************************************************************************
91
# Copyright (C) 2009 Carl Witty <[email protected]>
92
#
93
# Distributed under the terms of the GNU General Public License (GPL)
94
# http://www.gnu.org/licenses/
95
#*****************************************************************************
96
97
import os
98
import re
99
from jinja2 import Environment
100
from jinja2.runtime import StrictUndefined
101
from collections import defaultdict
102
from distutils.extension import Extension
103
104
##############################
105
# This module is used during the Sage build process, so it should not
106
# use any other Sage modules. (In particular, it MUST NOT use any
107
# Cython modules -- they won't be built yet!)
108
# Also, we have some trivial dependency tracking, where we don't
109
# rebuild the interpreters if this file hasn't changed; if
110
# interpreter configuration is split out into a separate file,
111
# that will have to be changed.
112
##############################
113
114
115
# We share a single jinja2 environment among all templating in this
116
# file. We use trim_blocks=True (which means that we ignore white
117
# space after "%}" jinja2 command endings), and set undefined to
118
# complain if we use an undefined variable.
119
jinja_env = Environment(trim_blocks=True, undefined=StrictUndefined)
120
121
# Allow 'i' as a shorter alias for the built-in 'indent' filter.
122
jinja_env.filters['i'] = jinja_env.filters['indent']
123
124
def indent_lines(n, text):
125
r"""
126
INPUTS:
127
n -- indentation amount
128
text -- text to indent
129
130
Indents each line in text by n spaces.
131
132
EXAMPLES::
133
134
sage: from sage.ext.gen_interpreters import indent_lines
135
sage: indent_lines(3, "foo")
136
' foo'
137
sage: indent_lines(3, "foo\nbar")
138
' foo\n bar'
139
sage: indent_lines(3, "foo\nbar\n")
140
' foo\n bar\n'
141
"""
142
lines = text.splitlines(True)
143
spaces = ' ' * n
144
return ''.join(spaces + line for line in lines)
145
146
def je(template, **kwargs):
147
r"""
148
A convenience method for creating strings with Jinja templates.
149
The name je stands for "Jinja evaluate".
150
151
The first argument is the template string; remaining keyword
152
arguments define Jinja variables.
153
154
If the first character in the template string is a newline, it is
155
removed (this feature is useful when using multi-line templates defined
156
with triple-quoted strings -- the first line doesn't have to be on
157
the same line as the quotes, which would screw up the indentation).
158
159
(This is very inefficient, because it recompiles the Jinja
160
template on each call; don't use it in situations where
161
performance is important.)
162
163
EXAMPLES::
164
165
sage: from sage.ext.gen_interpreters import je
166
sage: je("{{ a }} > {{ b }} * {{ c }}", a='"a suffusion of yellow"', b=3, c=7)
167
u'"a suffusion of yellow" > 3 * 7'
168
"""
169
if len(template) > 0 and template[0] == '\n':
170
template = template[1:]
171
172
# It looks like Jinja2 automatically removes one trailing newline?
173
if len(template) > 0 and template[-1] == '\n':
174
template = template + '\n'
175
176
tmpl = jinja_env.from_string(template)
177
return tmpl.render(kwargs)
178
179
class StorageType(object):
180
r"""
181
A StorageType specifies the C types used to deal with values of a
182
given type.
183
184
We currently support three categories of types.
185
186
First are the "simple" types. These are types where: the
187
representation is small, functions expect arguments to be passed
188
by value, and the C/C++ assignment operator works. This would
189
include built-in C types (long, float, etc.) and small structs
190
(like gsl_complex).
191
192
Second is 'PyObject*'. This is just like a simple type, except
193
that we have to incref/decref at appropriate places.
194
195
Third is "auto-reference" types. This is how
196
GMP/MPIR/MPFR/MPFI/FLINT types work. For these types, functions
197
expect arguments to be passed by reference, and the C assignment
198
operator does not do what we want. In addition, they take
199
advantage of a quirk in C (where arrays are automatically
200
converted to pointers) to automatically pass arguments by
201
reference.
202
203
Support for further categories would not be difficult to add (such
204
as reference-counted types other than PyObject*, or
205
pass-by-reference types that don't use the GMP auto-reference
206
trick), if we ever run across a use for them.
207
"""
208
209
def __init__(self):
210
r"""
211
Initialize an instance of StorageType.
212
213
This sets several properties:
214
215
class_member_declarations:
216
A string giving variable declarations that must be members of any
217
wrapper class using this type.
218
219
class_member_initializations:
220
A string initializing the class_member_declarations; will be
221
inserted into the __init__ method of any wrapper class using this
222
type.
223
224
local_declarations:
225
A string giving variable declarations that must be local variables
226
in Cython methods using this storage type.
227
228
EXAMPLES::
229
230
sage: from sage.ext.gen_interpreters import *
231
sage: ty_double.class_member_declarations
232
''
233
sage: ty_double.class_member_initializations
234
''
235
sage: ty_double.local_declarations
236
''
237
sage: ty_mpfr.class_member_declarations
238
'cdef RealField_class domain\n'
239
sage: ty_mpfr.class_member_initializations
240
"self.domain = args['domain']\n"
241
sage: ty_mpfr.local_declarations
242
'cdef RealNumber rn\n'
243
"""
244
self.class_member_declarations = ''
245
self.class_member_initializations = ''
246
self.local_declarations = ''
247
248
def cheap_copies(self):
249
r"""
250
Returns True or False, depending on whether this StorageType
251
supports cheap copies -- whether it is cheap to copy values of
252
this type from one location to another. This is true for
253
primitive types, and for types like PyObject* (where you're only
254
copying a pointer, and possibly changing some reference counts).
255
It is false for types like mpz_t and mpfr_t, where copying values
256
can involve arbitrarily much work (including memory allocation).
257
258
The practical effect is that if cheap_copies is True,
259
instructions with outputs of this type write the results into
260
local variables, and the results are then copied to their
261
final locations. If cheap_copies is False, then the addresses
262
of output locations are passed into the instruction and the
263
instruction writes outputs directly in the final location.
264
265
EXAMPLES::
266
267
sage: from sage.ext.gen_interpreters import *
268
sage: ty_double.cheap_copies()
269
True
270
sage: ty_python.cheap_copies()
271
True
272
sage: ty_mpfr.cheap_copies()
273
False
274
"""
275
return False
276
277
def python_refcounted(self):
278
r"""
279
Says whether this storage type is a Python type, so we need to
280
use INCREF/DECREF.
281
282
(If we needed to support any non-Python refcounted types, it
283
might be better to make this object-oriented and have methods
284
like "generate an incref" and "generate a decref". But as
285
long as we only support Python, this way is probably simpler.)
286
287
EXAMPLES::
288
289
sage: from sage.ext.gen_interpreters import *
290
sage: ty_double.python_refcounted()
291
False
292
sage: ty_python.python_refcounted()
293
True
294
"""
295
return False
296
297
def cython_decl_type(self):
298
r"""
299
Gives the Cython type for a single value of this type (as a string).
300
301
EXAMPLES::
302
303
sage: from sage.ext.gen_interpreters import *
304
sage: ty_double.cython_decl_type()
305
'double'
306
sage: ty_python.cython_decl_type()
307
'object'
308
sage: ty_mpfr.cython_decl_type()
309
'mpfr_t'
310
"""
311
return self.c_decl_type()
312
313
def cython_array_type(self):
314
r"""
315
Gives the Cython type for referring to an array of values of
316
this type (as a string).
317
318
EXAMPLES::
319
320
sage: from sage.ext.gen_interpreters import *
321
sage: ty_double.cython_array_type()
322
'double*'
323
sage: ty_python.cython_array_type()
324
'PyObject**'
325
sage: ty_mpfr.cython_array_type()
326
'mpfr_t*'
327
"""
328
return self.c_ptr_type()
329
330
def needs_cython_init_clear(self):
331
r"""
332
Says whether values/arrays of this type need to be initialized
333
before use and cleared before the underlying memory is freed.
334
335
(We could remove this method, always call .cython_init() to
336
generate initialization code, and just let .cython_init()
337
generate empty code if no initialization is required; that would
338
generate empty loops, which are ugly and potentially might not
339
be optimized away.)
340
341
EXAMPLES::
342
343
sage: from sage.ext.gen_interpreters import *
344
sage: ty_double.needs_cython_init_clear()
345
False
346
sage: ty_mpfr.needs_cython_init_clear()
347
True
348
sage: ty_python.needs_cython_init_clear()
349
True
350
"""
351
return False
352
353
def c_decl_type(self):
354
r"""
355
Gives the C type for a single value of this type (as a string).
356
357
EXAMPLES::
358
359
sage: from sage.ext.gen_interpreters import *
360
sage: ty_double.c_decl_type()
361
'double'
362
sage: ty_python.c_decl_type()
363
'PyObject*'
364
sage: ty_mpfr.c_decl_type()
365
'mpfr_t'
366
"""
367
raise NotImplementedError
368
369
def c_ptr_type(self):
370
r"""
371
Gives the C type for a pointer to this type (as a reference to
372
either a single value or an array) (as a string).
373
374
EXAMPLES::
375
376
sage: from sage.ext.gen_interpreters import *
377
sage: ty_double.c_ptr_type()
378
'double*'
379
sage: ty_python.c_ptr_type()
380
'PyObject**'
381
sage: ty_mpfr.c_ptr_type()
382
'mpfr_t*'
383
"""
384
return self.c_decl_type() + '*'
385
386
def c_local_type(self):
387
r"""
388
Gives the C type used for a value of this type inside an
389
instruction. For assignable/cheap_copy types, this is the
390
same as c_decl_type; for auto-reference types, this is the
391
pointer type.
392
393
EXAMPLES::
394
395
sage: from sage.ext.gen_interpreters import *
396
sage: ty_double.c_local_type()
397
'double'
398
sage: ty_python.c_local_type()
399
'PyObject*'
400
sage: ty_mpfr.c_local_type()
401
'mpfr_ptr'
402
"""
403
raise NotImplementedError
404
405
def assign_c_from_py(self, c, py):
406
r"""
407
Given a Cython variable/array reference/etc. of this storage type,
408
and a Python expression, generate code to assign to the Cython
409
variable from the Python expression.
410
411
EXAMPLES::
412
413
sage: from sage.ext.gen_interpreters import *
414
sage: ty_double.assign_c_from_py('foo', 'bar')
415
u'foo = bar'
416
sage: ty_python.assign_c_from_py('foo[i]', 'bar[j]')
417
u'foo[i] = <PyObject *>bar[j]; Py_INCREF(foo[i])'
418
sage: ty_mpfr.assign_c_from_py('foo', 'bar')
419
u'rn = self.domain(bar)\nmpfr_set(foo, rn.value, GMP_RNDN)'
420
"""
421
return je("{{ c }} = {{ py }}", c=c, py=py)
422
423
def declare_chunk_class_members(self, name):
424
r"""
425
Returns a string giving the declarations of the class members
426
in a wrapper class for a memory chunk with this storage type
427
and the given name.
428
429
EXAMPLES::
430
431
sage: from sage.ext.gen_interpreters import *
432
sage: ty_mpfr.declare_chunk_class_members('args')
433
u' cdef int _n_args\n cdef mpfr_t* _args\n'
434
"""
435
return je("""
436
{# XXX Variables here (and everywhere, really) should actually be Py_ssize_t #}
437
cdef int _n_{{ name }}
438
cdef {{ myself.cython_array_type() }} _{{ name }}
439
""", myself=self, name=name)
440
441
def alloc_chunk_data(self, name, len):
442
r"""
443
Returns a string allocating the memory for the class members for
444
a memory chunk with this storage type and the given name.
445
446
EXAMPLES::
447
448
sage: from sage.ext.gen_interpreters import *
449
sage: print ty_mpfr.alloc_chunk_data('args', 'MY_LENGTH')
450
self._n_args = MY_LENGTH
451
self._args = <mpfr_t*>sage_malloc(sizeof(mpfr_t) * MY_LENGTH)
452
if self._args == NULL: raise MemoryError
453
for i in range(MY_LENGTH):
454
mpfr_init2(self._args[i], self.domain.prec())
455
<BLANKLINE>
456
"""
457
return je("""
458
self._n_{{ name }} = {{ len }}
459
self._{{ name }} = <{{ myself.c_ptr_type() }}>sage_malloc(sizeof({{ myself.c_decl_type() }}) * {{ len }})
460
if self._{{ name }} == NULL: raise MemoryError
461
{% if myself.needs_cython_init_clear() %}
462
for i in range({{ len }}):
463
{{ myself.cython_init('self._%s[i]' % name) }}
464
{% endif %}
465
""", myself=self, name=name, len=len)
466
467
def dealloc_chunk_data(self, name):
468
r"""
469
Returns a string to be put in the __dealloc__ method of a
470
wrapper class using a memory chunk with this storage type, to
471
deallocate the corresponding class members.
472
473
EXAMPLES::
474
475
sage: from sage.ext.gen_interpreters import *
476
sage: print ty_double.dealloc_chunk_data('args')
477
if self._args:
478
sage_free(self._args)
479
<BLANKLINE>
480
sage: print ty_mpfr.dealloc_chunk_data('constants')
481
if self._constants:
482
for i in range(self._n_constants):
483
mpfr_clear(self._constants[i])
484
sage_free(self._constants)
485
<BLANKLINE>
486
"""
487
return je("""
488
if self._{{ name }}:
489
{% if myself.needs_cython_init_clear() %}
490
for i in range(self._n_{{ name }}):
491
{{ myself.cython_clear('self._%s[i]' % name) }}
492
{% endif %}
493
sage_free(self._{{ name }})
494
""", myself=self, name=name)
495
496
class StorageTypeAssignable(StorageType):
497
r"""
498
StorageTypeAssignable is a subtype of StorageType that deals with
499
types with cheap copies, like primitive types and PyObject*.
500
"""
501
502
def __init__(self, ty):
503
r"""
504
Initializes the property type (the C/Cython name for this type),
505
as well as the properties described in the documentation for
506
StorageType.__init__.
507
508
EXAMPLES::
509
510
sage: from sage.ext.gen_interpreters import *
511
sage: ty_double.class_member_declarations
512
''
513
sage: ty_double.class_member_initializations
514
''
515
sage: ty_double.local_declarations
516
''
517
sage: ty_double.type
518
'double'
519
sage: ty_python.type
520
'PyObject*'
521
"""
522
StorageType.__init__(self)
523
self.type = ty
524
525
def cheap_copies(self):
526
r"""
527
Returns True or False, depending on whether this StorageType
528
supports cheap copies -- whether it is cheap to copy values of
529
this type from one location to another. (See StorageType.cheap_copies
530
for more on this property.)
531
532
Since having cheap copies is essentially the definition of
533
StorageTypeAssignable, this always returns True.
534
535
EXAMPLES::
536
537
sage: from sage.ext.gen_interpreters import *
538
sage: ty_double.cheap_copies()
539
True
540
sage: ty_python.cheap_copies()
541
True
542
"""
543
return True
544
545
def c_decl_type(self):
546
r"""
547
Gives the C type for a single value of this type (as a string).
548
549
EXAMPLES::
550
551
sage: from sage.ext.gen_interpreters import *
552
sage: ty_double.c_decl_type()
553
'double'
554
sage: ty_python.c_decl_type()
555
'PyObject*'
556
"""
557
return self.type
558
559
def c_local_type(self):
560
r"""
561
Gives the C type used for a value of this type inside an
562
instruction. For assignable/cheap_copy types, this is the
563
same as c_decl_type; for auto-reference types, this is the
564
pointer type.
565
566
EXAMPLES::
567
568
sage: from sage.ext.gen_interpreters import *
569
sage: ty_double.c_local_type()
570
'double'
571
sage: ty_python.c_local_type()
572
'PyObject*'
573
"""
574
return self.type
575
576
class StorageTypeSimple(StorageTypeAssignable):
577
r"""
578
StorageTypeSimple is a subtype of StorageTypeAssignable that deals
579
with non-reference-counted types with cheap copies, like primitive
580
types. As of yet, it has no functionality differences from
581
StorageTypeAssignable.
582
"""
583
pass
584
585
ty_int = StorageTypeSimple('int')
586
ty_double = StorageTypeSimple('double')
587
588
class StorageTypeDoubleComplex(StorageTypeSimple):
589
r"""
590
This is specific to the complex double type. It behaves exactly
591
like a StorageTypeSimple in C, but needs a little help to do
592
conversions in Cython.
593
594
This uses functions defined in CDFInterpreter, and is for use in
595
that context.
596
"""
597
def assign_c_from_py(self, c, py):
598
"""
599
sage: from sage.ext.gen_interpreters import ty_double_complex
600
sage: ty_double_complex.assign_c_from_py('z_c', 'z_py')
601
u'z_c = CDE_to_dz(z_py)'
602
"""
603
return je("{{ c }} = CDE_to_dz({{ py }})", c=c, py=py)
604
605
ty_double_complex = StorageTypeDoubleComplex('double_complex')
606
607
class StorageTypePython(StorageTypeAssignable):
608
r"""
609
StorageTypePython is a subtype of StorageTypeAssignable that deals
610
with Python objects.
611
612
Just allocating an array full of PyObject* leads to problems,
613
because the Python garbage collector must be able to get to every
614
Python object, and it wouldn't know how to get to these arrays.
615
So we allocate the array as a Python list, but then we immediately
616
pull the ob_item out of it and deal only with that from then on.
617
618
We often leave these lists with NULL entries. This is safe for
619
the garbage collector and the deallocator, which is all we care
620
about; but it would be unsafe to provide Python-level access to
621
these lists.
622
623
There is one special thing about StorageTypePython: memory that is
624
used by the interpreter as scratch space (for example, the stack)
625
must be cleared after each call (so we don't hold on to
626
potentially-large objects and waste memory). Since we have to do
627
this anyway, the interpreter gains a tiny bit of speed by assuming
628
that the scratch space is cleared on entry; for example, when
629
pushing a value onto the stack, it doesn't bother to XDECREF the
630
previous value because it's always NULL.
631
"""
632
633
def __init__(self):
634
r"""
635
Initializes the properties described in the documentation
636
for StorageTypeAssignable.__init__. The type is always
637
'PyObject*'.
638
639
EXAMPLES::
640
641
sage: from sage.ext.gen_interpreters import *
642
sage: ty_python.class_member_declarations
643
''
644
sage: ty_python.class_member_initializations
645
''
646
sage: ty_python.local_declarations
647
''
648
sage: ty_python.type
649
'PyObject*'
650
"""
651
StorageTypeAssignable.__init__(self, 'PyObject*')
652
653
def python_refcounted(self):
654
r"""
655
Says whether this storage type is a Python type, so we need to
656
use INCREF/DECREF.
657
658
Returns True.
659
660
EXAMPLES::
661
662
sage: from sage.ext.gen_interpreters import *
663
sage: ty_python.python_refcounted()
664
True
665
"""
666
return True
667
668
def cython_decl_type(self):
669
r"""
670
Gives the Cython type for a single value of this type (as a string).
671
672
EXAMPLES::
673
674
sage: from sage.ext.gen_interpreters import *
675
sage: ty_python.cython_decl_type()
676
'object'
677
"""
678
return 'object'
679
680
def declare_chunk_class_members(self, name):
681
r"""
682
Returns a string giving the declarations of the class members
683
in a wrapper class for a memory chunk with this storage type
684
and the given name.
685
686
EXAMPLES::
687
688
sage: from sage.ext.gen_interpreters import *
689
sage: ty_python.declare_chunk_class_members('args')
690
u' cdef object _list_args\n cdef int _n_args\n cdef PyObject** _args\n'
691
"""
692
return je("""
693
cdef object _list_{{ name }}
694
cdef int _n_{{ name }}
695
cdef {{ myself.cython_array_type() }} _{{ name }}
696
""", myself=self, name=name)
697
698
def alloc_chunk_data(self, name, len):
699
r"""
700
Returns a string allocating the memory for the class members for
701
a memory chunk with this storage type and the given name.
702
703
EXAMPLES::
704
705
sage: from sage.ext.gen_interpreters import *
706
sage: print ty_python.alloc_chunk_data('args', 'MY_LENGTH')
707
self._n_args = MY_LENGTH
708
self._list_args = PyList_New(self._n_args)
709
self._args = (<PyListObject *>self._list_args).ob_item
710
<BLANKLINE>
711
"""
712
return je("""
713
self._n_{{ name }} = {{ len }}
714
self._list_{{ name }} = PyList_New(self._n_{{ name }})
715
self._{{ name }} = (<PyListObject *>self._list_{{ name }}).ob_item
716
""", myself=self, name=name, len=len)
717
718
def dealloc_chunk_data(self, name):
719
r"""
720
Returns a string to be put in the __dealloc__ method of a
721
wrapper class using a memory chunk with this storage type, to
722
deallocate the corresponding class members.
723
724
Our array was allocated as a Python list; this means we actually
725
don't need to do anything to deallocate it.
726
727
EXAMPLES::
728
729
sage: from sage.ext.gen_interpreters import *
730
sage: ty_python.dealloc_chunk_data('args')
731
''
732
"""
733
return ''
734
735
def needs_cython_init_clear(self):
736
r"""
737
Says whether values/arrays of this type need to be initialized
738
before use and cleared before the underlying memory is freed.
739
740
Returns True.
741
742
EXAMPLES::
743
744
sage: from sage.ext.gen_interpreters import *
745
sage: ty_python.needs_cython_init_clear()
746
True
747
"""
748
return True
749
750
def assign_c_from_py(self, c, py):
751
r"""
752
Given a Cython variable/array reference/etc. of this storage type,
753
and a Python expression, generate code to assign to the Cython
754
variable from the Python expression.
755
756
EXAMPLES::
757
758
sage: from sage.ext.gen_interpreters import *
759
sage: ty_python.assign_c_from_py('foo[i]', 'bar[j]')
760
u'foo[i] = <PyObject *>bar[j]; Py_INCREF(foo[i])'
761
"""
762
return je("""{{ c }} = <PyObject *>{{ py }}; Py_INCREF({{ c }})""",
763
c=c, py=py)
764
765
def cython_init(self, loc):
766
r"""
767
Generates code to initialize a variable (or array reference)
768
holding a PyObject*. Sets it to NULL.
769
770
EXAMPLES::
771
772
sage: from sage.ext.gen_interpreters import *
773
sage: ty_python.cython_init('foo[i]')
774
u'foo[i] = NULL'
775
"""
776
return je("{{ loc }} = NULL", loc=loc)
777
778
def cython_clear(self, loc):
779
r"""
780
Generates code to clear a variable (or array reference) holding
781
a PyObject*.
782
783
EXAMPLES::
784
785
sage: from sage.ext.gen_interpreters import *
786
sage: ty_python.cython_clear('foo[i]')
787
u'Py_CLEAR(foo[i])'
788
"""
789
return je("Py_CLEAR({{ loc }})", loc=loc)
790
791
ty_python = StorageTypePython()
792
793
class StorageTypeAutoReference(StorageType):
794
r"""
795
StorageTypeAutoReference is a subtype of StorageType that deals with
796
types in the style of GMP/MPIR/MPFR/MPFI/FLINT, where copies are
797
not cheap, functions expect arguments to be passed by reference,
798
and the API takes advantage of the C quirk where arrays are
799
automatically converted to pointers to automatically pass
800
arguments by reference.
801
"""
802
803
def __init__(self, decl_ty, ref_ty):
804
r"""
805
Initializes the properties decl_type and ref_type (the C type
806
names used when declaring variables and function parameters,
807
respectively), as well as the properties described in
808
the documentation for StorageType.__init__.
809
810
EXAMPLES::
811
812
sage: from sage.ext.gen_interpreters import *
813
sage: ty_mpfr.class_member_declarations
814
'cdef RealField_class domain\n'
815
sage: ty_mpfr.class_member_initializations
816
"self.domain = args['domain']\n"
817
sage: ty_mpfr.local_declarations
818
'cdef RealNumber rn\n'
819
sage: ty_mpfr.decl_type
820
'mpfr_t'
821
sage: ty_mpfr.ref_type
822
'mpfr_ptr'
823
"""
824
StorageType.__init__(self)
825
self.decl_type = decl_ty
826
self.ref_type = ref_ty
827
828
def c_decl_type(self):
829
r"""
830
Gives the C type for a single value of this type (as a string).
831
832
EXAMPLES::
833
834
sage: from sage.ext.gen_interpreters import *
835
sage: ty_mpfr.c_decl_type()
836
'mpfr_t'
837
"""
838
return self.decl_type
839
840
def c_local_type(self):
841
r"""
842
Gives the C type used for a value of this type inside an
843
instruction. For assignable/cheap_copy types, this is the
844
same as c_decl_type; for auto-reference types, this is the
845
pointer type.
846
847
EXAMPLES::
848
849
sage: from sage.ext.gen_interpreters import *
850
sage: ty_mpfr.c_local_type()
851
'mpfr_ptr'
852
"""
853
return self.ref_type
854
855
def needs_cython_init_clear(self):
856
r"""
857
Says whether values/arrays of this type need to be initialized
858
before use and cleared before the underlying memory is freed.
859
860
All known examples of auto-reference types do need a special
861
initialization call, so this always returns True.
862
863
EXAMPLES::
864
865
sage: from sage.ext.gen_interpreters import *
866
sage: ty_mpfr.needs_cython_init_clear()
867
True
868
"""
869
return True
870
871
class StorageTypeMPFR(StorageTypeAutoReference):
872
r"""
873
StorageTypeMPFR is a subtype of StorageTypeAutoReference that deals
874
the MPFR's mpfr_t type.
875
876
For any given program that we're interpreting, ty_mpfr can only
877
refer to a single precision. An interpreter that needs to use
878
two precisions of mpfr_t in the same program should instantiate two
879
separate instances of StorageTypeMPFR. (Interpreters that need
880
to handle arbitrarily many precisions in the same program are not
881
handled at all.)
882
"""
883
884
def __init__(self, id=''):
885
r"""
886
Initializes the id property, as well as the properties described
887
in the documentation for StorageTypeAutoReference.__init__.
888
889
The id property is used if you want to have an interpreter
890
that handles two instances of StorageTypeMPFR (that is,
891
handles mpfr_t variables at two different precisions
892
simultaneously). It's a string that's used to generate
893
variable names that don't conflict. (The id system has
894
never actually been used, so bugs probably remain.)
895
896
EXAMPLES::
897
898
sage: from sage.ext.gen_interpreters import *
899
sage: ty_mpfr.class_member_declarations
900
'cdef RealField_class domain\n'
901
sage: ty_mpfr.class_member_initializations
902
"self.domain = args['domain']\n"
903
sage: ty_mpfr.local_declarations
904
'cdef RealNumber rn\n'
905
sage: ty_mpfr.decl_type
906
'mpfr_t'
907
sage: ty_mpfr.ref_type
908
'mpfr_ptr'
909
910
TESTS::
911
912
sage: ty_mpfr2 = StorageTypeMPFR(id='_the_second')
913
sage: ty_mpfr2.class_member_declarations
914
'cdef RealField_class domain_the_second\n'
915
sage: ty_mpfr2.class_member_initializations
916
"self.domain_the_second = args['domain_the_second']\n"
917
sage: ty_mpfr2.local_declarations
918
'cdef RealNumber rn_the_second\n'
919
"""
920
StorageTypeAutoReference.__init__(self, 'mpfr_t', 'mpfr_ptr')
921
self.id = id
922
self.class_member_declarations = "cdef RealField_class domain%s\n" % self.id
923
self.class_member_initializations = \
924
"self.domain%s = args['domain%s']\n" % (self.id, self.id)
925
self.local_declarations = "cdef RealNumber rn%s\n" % self.id
926
927
def cython_init(self, loc):
928
r"""
929
Generates code to initialize an mpfr_t reference (a variable, an
930
array reference, etc.)
931
932
EXAMPLES::
933
934
sage: from sage.ext.gen_interpreters import *
935
sage: ty_mpfr.cython_init('foo[i]')
936
u'mpfr_init2(foo[i], self.domain.prec())'
937
"""
938
return je("mpfr_init2({{ loc }}, self.domain{{ myself.id }}.prec())",
939
myself=self, loc=loc)
940
941
def cython_clear(self, loc):
942
r"""
943
Generates code to clear an mpfr_t reference (a variable, an
944
array reference, etc.)
945
946
EXAMPLES::
947
948
sage: from sage.ext.gen_interpreters import *
949
sage: ty_mpfr.cython_clear('foo[i]')
950
'mpfr_clear(foo[i])'
951
"""
952
return 'mpfr_clear(%s)' % loc
953
954
def assign_c_from_py(self, c, py):
955
r"""
956
Given a Cython variable/array reference/etc. of this storage type,
957
and a Python expression, generate code to assign to the Cython
958
variable from the Python expression.
959
960
EXAMPLES::
961
962
sage: from sage.ext.gen_interpreters import *
963
sage: ty_mpfr.assign_c_from_py('foo[i]', 'bar[j]')
964
u'rn = self.domain(bar[j])\nmpfr_set(foo[i], rn.value, GMP_RNDN)'
965
"""
966
return je("""
967
rn{{ myself.id }} = self.domain({{ py }})
968
mpfr_set({{ c }}, rn.value, GMP_RNDN)""", myself=self, c=c, py=py)
969
970
ty_mpfr = StorageTypeMPFR()
971
972
class MemoryChunk(object):
973
r"""
974
Memory chunks control allocation, deallocation, initialization,
975
etc. of the vectors and objects in the interpreter. Basically,
976
there is one memory chunk per argument to the C interpreter.
977
978
There are three "generic" varieties of memory chunk: "constants",
979
"arguments", and "scratch". These are named after their most
980
common use, but they could be used for other things in some
981
interpreters.
982
983
All three kinds of chunks are allocated in the wrapper class.
984
Constants are initialized when the wrapper is constructed;
985
arguments are initialized in the __call__ method, from the
986
caller's arguments. "scratch" chunks are not initialized at all;
987
they are used for scratch storage (often, but not necessarily, for
988
a stack) in the interpreter.
989
990
Interpreters which need memory chunks that don't fit into these
991
categories can create new subclasses of MemoryChunk.
992
"""
993
994
def __init__(self, name, storage_type):
995
r"""
996
Initialize an instance of MemoryChunk.
997
998
This sets the properties "name" (the name of this memory chunk;
999
used in generated variable names, etc.) and "storage_type",
1000
which is a StorageType object.
1001
1002
EXAMPLES::
1003
1004
sage: from sage.ext.gen_interpreters import *
1005
sage: mc = MemoryChunkArguments('args', ty_mpfr)
1006
sage: mc.name
1007
'args'
1008
sage: mc.storage_type is ty_mpfr
1009
True
1010
"""
1011
self.name = name
1012
self.storage_type = storage_type
1013
1014
def __repr__(self):
1015
r"""
1016
Give a string representation of this memory chunk.
1017
1018
EXAMPLES::
1019
1020
sage: from sage.ext.gen_interpreters import *
1021
sage: mc = MemoryChunkArguments('args', ty_mpfr)
1022
sage: mc
1023
{MC:args}
1024
sage: mc.__repr__()
1025
'{MC:args}'
1026
"""
1027
return '{MC:%s}' % self.name
1028
1029
def declare_class_members(self):
1030
r"""
1031
Returns a string giving the declarations of the class members
1032
in a wrapper class for this memory chunk.
1033
1034
EXAMPLES::
1035
1036
sage: from sage.ext.gen_interpreters import *
1037
sage: mc = MemoryChunkArguments('args', ty_mpfr)
1038
sage: mc.declare_class_members()
1039
u' cdef int _n_args\n cdef mpfr_t* _args\n'
1040
"""
1041
return self.storage_type.declare_chunk_class_members(self.name)
1042
1043
def init_class_members(self):
1044
r"""
1045
Returns a string to be put in the __init__ method of a wrapper
1046
class using this memory chunk, to initialize the corresponding
1047
class members.
1048
1049
EXAMPLES::
1050
1051
sage: from sage.ext.gen_interpreters import *
1052
sage: mc = MemoryChunkArguments('args', ty_mpfr)
1053
sage: print mc.init_class_members()
1054
count = args['args']
1055
self._n_args = count
1056
self._args = <mpfr_t*>sage_malloc(sizeof(mpfr_t) * count)
1057
if self._args == NULL: raise MemoryError
1058
for i in range(count):
1059
mpfr_init2(self._args[i], self.domain.prec())
1060
<BLANKLINE>
1061
"""
1062
return ""
1063
1064
def dealloc_class_members(self):
1065
r"""
1066
Returns a string to be put in the __dealloc__ method of a wrapper
1067
class using this memory chunk, to deallocate the corresponding
1068
class members.
1069
1070
EXAMPLES::
1071
1072
sage: from sage.ext.gen_interpreters import *
1073
sage: mc = MemoryChunkArguments('args', ty_mpfr)
1074
sage: print mc.dealloc_class_members()
1075
if self._args:
1076
for i in range(self._n_args):
1077
mpfr_clear(self._args[i])
1078
sage_free(self._args)
1079
<BLANKLINE>
1080
"""
1081
return ""
1082
1083
def declare_parameter(self):
1084
r"""
1085
Returns the string to use to declare the interpreter parameter
1086
corresponding to this memory chunk.
1087
1088
EXAMPLES::
1089
1090
sage: from sage.ext.gen_interpreters import *
1091
sage: mc = MemoryChunkArguments('args', ty_mpfr)
1092
sage: mc.declare_parameter()
1093
'mpfr_t* args'
1094
"""
1095
return '%s %s' % (self.storage_type.c_ptr_type(), self.name)
1096
1097
def declare_call_locals(self):
1098
r"""
1099
Returns a string to put in the __call__ method of a wrapper
1100
class using this memory chunk, to allocate local variables.
1101
1102
EXAMPLES::
1103
1104
sage: from sage.ext.gen_interpreters import *
1105
sage: mc = MemoryChunkRRRetval('retval', ty_mpfr)
1106
sage: mc.declare_call_locals()
1107
u' cdef RealNumber retval = (self.domain)()\n'
1108
"""
1109
return ""
1110
1111
def pass_argument(self):
1112
r"""
1113
Returns the string to pass the argument corresponding to this
1114
memory chunk to the interpreter.
1115
1116
EXAMPLES::
1117
1118
sage: from sage.ext.gen_interpreters import *
1119
sage: mc = MemoryChunkConstants('constants', ty_mpfr)
1120
sage: mc.pass_argument()
1121
'self._constants'
1122
"""
1123
raise NotImplementedError
1124
1125
def pass_call_c_argument(self):
1126
r"""
1127
Returns the string to pass the argument corresponding to this
1128
memory chunk to the interpreter, for use in the call_c method.
1129
Almost always the same as pass_argument.
1130
1131
EXAMPLES::
1132
1133
sage: from sage.ext.gen_interpreters import *
1134
sage: mc = MemoryChunkConstants('constants', ty_mpfr)
1135
sage: mc.pass_call_c_argument()
1136
'self._constants'
1137
"""
1138
return self.pass_argument()
1139
1140
def needs_cleanup_on_error(self):
1141
r"""
1142
In an interpreter that can terminate prematurely (due to an
1143
exception from calling Python code, or divide by zero, or
1144
whatever) it will just return at the end of the current instruction,
1145
skipping the rest of the program. Thus, it may still have
1146
values pushed on the stack, etc.
1147
1148
This method returns True if this memory chunk is modified by the
1149
interpreter and needs some sort of cleanup when an error happens.
1150
1151
EXAMPLES::
1152
1153
sage: from sage.ext.gen_interpreters import *
1154
sage: mc = MemoryChunkConstants('constants', ty_mpfr)
1155
sage: mc.needs_cleanup_on_error()
1156
False
1157
"""
1158
return False
1159
1160
def is_stack(self):
1161
r"""
1162
Says whether this memory chunk is a stack. This affects code
1163
generation for instructions using this memory chunk.
1164
1165
It would be nicer to make this object-oriented somehow, so
1166
that the code generator called MemoryChunk methods instead of
1167
using
1168
if ch.is_stack():
1169
... hardcoded stack code
1170
else:
1171
... hardcoded non-stack code
1172
but that hasn't been done yet.
1173
1174
EXAMPLES::
1175
1176
sage: from sage.ext.gen_interpreters import *
1177
sage: mc = MemoryChunkScratch('scratch', ty_mpfr)
1178
sage: mc.is_stack()
1179
False
1180
sage: mc = MemoryChunkScratch('stack', ty_mpfr, is_stack=True)
1181
sage: mc.is_stack()
1182
True
1183
"""
1184
return False
1185
1186
def is_python_refcounted_stack(self):
1187
r"""
1188
Says whether this memory chunk refers to a stack where the entries
1189
need to be INCREF/DECREF'ed.
1190
1191
It would be nice to make this object-oriented, so that the
1192
code generator called MemoryChunk methods to do the potential
1193
INCREF/DECREF and didn't have to explicitly test
1194
is_python_refcounted_stack.
1195
1196
EXAMPLES::
1197
1198
sage: from sage.ext.gen_interpreters import *
1199
sage: mc = MemoryChunkScratch('args', ty_python)
1200
sage: mc.is_python_refcounted_stack()
1201
False
1202
sage: mc = MemoryChunkScratch('args', ty_python, is_stack=True)
1203
sage: mc.is_python_refcounted_stack()
1204
True
1205
sage: mc = MemoryChunkScratch('args', ty_mpfr, is_stack=True)
1206
sage: mc.is_python_refcounted_stack()
1207
False
1208
"""
1209
return self.is_stack() and self.storage_type.python_refcounted()
1210
1211
class MemoryChunkLonglivedArray(MemoryChunk):
1212
r"""
1213
MemoryChunkLonglivedArray is a subtype of MemoryChunk that deals
1214
with memory chunks that are both 1) allocated as class members (rather
1215
than being allocated in __call__) and 2) are arrays.
1216
"""
1217
1218
def init_class_members(self):
1219
r"""
1220
Returns a string to be put in the __init__ method of a wrapper
1221
class using this memory chunk, to initialize the corresponding
1222
class members.
1223
1224
EXAMPLES::
1225
1226
sage: from sage.ext.gen_interpreters import *
1227
sage: mc = MemoryChunkArguments('args', ty_double)
1228
sage: print mc.init_class_members()
1229
count = args['args']
1230
self._n_args = count
1231
self._args = <double*>sage_malloc(sizeof(double) * count)
1232
if self._args == NULL: raise MemoryError
1233
<BLANKLINE>
1234
"""
1235
return je("""
1236
count = args['{{ myself.name }}']
1237
{% print myself.storage_type.alloc_chunk_data(myself.name, 'count') %}
1238
""", myself=self)
1239
1240
def dealloc_class_members(self):
1241
r"""
1242
Returns a string to be put in the __dealloc__ method of a wrapper
1243
class using this memory chunk, to deallocate the corresponding
1244
class members.
1245
1246
EXAMPLES::
1247
1248
sage: from sage.ext.gen_interpreters import *
1249
sage: mc = MemoryChunkArguments('args', ty_mpfr)
1250
sage: print mc.dealloc_class_members()
1251
if self._args:
1252
for i in range(self._n_args):
1253
mpfr_clear(self._args[i])
1254
sage_free(self._args)
1255
<BLANKLINE>
1256
"""
1257
return self.storage_type.dealloc_chunk_data(self.name)
1258
1259
def pass_argument(self):
1260
r"""
1261
Returns the string to pass the argument corresponding to this
1262
memory chunk to the interpreter.
1263
1264
EXAMPLES::
1265
1266
sage: from sage.ext.gen_interpreters import *
1267
sage: mc = MemoryChunkConstants('constants', ty_mpfr)
1268
sage: mc.pass_argument()
1269
'self._constants'
1270
"""
1271
return 'self._%s' % self.name
1272
1273
class MemoryChunkConstants(MemoryChunkLonglivedArray):
1274
r"""
1275
MemoryChunkConstants is a subtype of MemoryChunkLonglivedArray.
1276
1277
MemoryChunkConstants chunks have their contents set in the
1278
wrapper's __init__ method (and not changed afterward).
1279
"""
1280
1281
def init_class_members(self):
1282
r"""
1283
Returns a string to be put in the __init__ method of a wrapper
1284
class using this memory chunk, to initialize the corresponding
1285
class members.
1286
1287
EXAMPLES::
1288
1289
sage: from sage.ext.gen_interpreters import *
1290
sage: mc = MemoryChunkConstants('constants', ty_mpfr)
1291
sage: print mc.init_class_members()
1292
val = args['constants']
1293
self._n_constants = len(val)
1294
self._constants = <mpfr_t*>sage_malloc(sizeof(mpfr_t) * len(val))
1295
if self._constants == NULL: raise MemoryError
1296
for i in range(len(val)):
1297
mpfr_init2(self._constants[i], self.domain.prec())
1298
for i in range(len(val)):
1299
rn = self.domain(val[i])
1300
mpfr_set(self._constants[i], rn.value, GMP_RNDN)
1301
<BLANKLINE>
1302
"""
1303
return je("""
1304
val = args['{{ myself.name }}']
1305
{% print myself.storage_type.alloc_chunk_data(myself.name, 'len(val)') %}
1306
for i in range(len(val)):
1307
{{ myself.storage_type.assign_c_from_py('self._%s[i]' % myself.name, 'val[i]') | i(12) }}
1308
""", myself=self)
1309
1310
class MemoryChunkArguments(MemoryChunkLonglivedArray):
1311
r"""
1312
MemoryChunkArguments is a subtype of MemoryChunkLonglivedArray,
1313
for dealing with arguments to the wrapper's __call__ method.
1314
1315
Currently the __call__ method is declared to take a varargs
1316
*args argument tuple. We assume that the MemoryChunk named 'args'
1317
will deal with that tuple.
1318
"""
1319
1320
def setup_args(self):
1321
r"""
1322
Handle the arguments of __call__ -- copy them into a pre-allocated
1323
array, ready to pass to the interpreter.
1324
1325
EXAMPLES::
1326
1327
sage: from sage.ext.gen_interpreters import *
1328
sage: mc = MemoryChunkArguments('args', ty_mpfr)
1329
sage: print mc.setup_args()
1330
cdef mpfr_t* c_args = self._args
1331
cdef int i
1332
for i from 0 <= i < len(args):
1333
rn = self.domain(args[i])
1334
mpfr_set(self._args[i], rn.value, GMP_RNDN)
1335
<BLANKLINE>
1336
"""
1337
return je("""
1338
cdef {{ myself.storage_type.c_ptr_type() }} c_args = self._args
1339
cdef int i
1340
for i from 0 <= i < len(args):
1341
{{ myself.storage_type.assign_c_from_py('self._args[i]', 'args[i]') | i(4) }}
1342
""", myself=self)
1343
1344
def pass_argument(self):
1345
r"""
1346
Returns the string to pass the argument corresponding to this
1347
memory chunk to the interpreter.
1348
1349
EXAMPLES::
1350
1351
sage: from sage.ext.gen_interpreters import *
1352
sage: mc = MemoryChunkArguments('args', ty_mpfr)
1353
sage: mc.pass_argument()
1354
'c_args'
1355
"""
1356
return 'c_args'
1357
1358
class MemoryChunkScratch(MemoryChunkLonglivedArray):
1359
r"""
1360
MemoryChunkScratch is a subtype of MemoryChunkLonglivedArray
1361
for dealing with memory chunks that are allocated in the wrapper,
1362
but only used in the interpreter -- stacks, scratch registers, etc.
1363
1364
(Currently these are only used as stacks.)
1365
"""
1366
1367
def __init__(self, name, storage_type, is_stack=False):
1368
r"""
1369
Initialize an instance of MemoryChunkScratch.
1370
1371
Initializes the _is_stack property, as well as
1372
the properties described in the documentation for
1373
MemoryChunk.__init__.
1374
1375
EXAMPLES::
1376
1377
sage: from sage.ext.gen_interpreters import *
1378
sage: mc = MemoryChunkScratch('stack', ty_double, is_stack=True)
1379
sage: mc.name
1380
'stack'
1381
sage: mc.storage_type is ty_double
1382
True
1383
sage: mc._is_stack
1384
True
1385
"""
1386
MemoryChunkLonglivedArray.__init__(self, name, storage_type)
1387
self._is_stack = is_stack
1388
1389
def is_stack(self):
1390
r"""
1391
Says whether this memory chunk is a stack. This affects code
1392
generation for instructions using this memory chunk.
1393
1394
EXAMPLES::
1395
1396
sage: from sage.ext.gen_interpreters import *
1397
sage: mc = MemoryChunkScratch('stack', ty_mpfr, is_stack=True)
1398
sage: mc.is_stack()
1399
True
1400
"""
1401
return self._is_stack
1402
1403
def needs_cleanup_on_error(self):
1404
r"""
1405
In an interpreter that can terminate prematurely (due to an
1406
exception from calling Python code, or divide by zero, or
1407
whatever) it will just return at the end of the current instruction,
1408
skipping the rest of the program. Thus, it may still have
1409
values pushed on the stack, etc.
1410
1411
This method returns True if this memory chunk is modified by the
1412
interpreter and needs some sort of cleanup when an error happens.
1413
1414
EXAMPLES::
1415
1416
sage: from sage.ext.gen_interpreters import *
1417
sage: mc = MemoryChunkScratch('registers', ty_python)
1418
sage: mc.needs_cleanup_on_error()
1419
True
1420
"""
1421
return self.storage_type.python_refcounted()
1422
1423
def handle_cleanup(self):
1424
r"""
1425
Handle the cleanup if the interpreter exits with an error.
1426
1427
For scratch/stack chunks that hold Python-refcounted values,
1428
we assume that they are filled with NULL on every entry to the
1429
interpreter. If the interpreter exited with an error, it may
1430
have left values in the chunk, so we need to go through
1431
the chunk and Py_CLEAR it.
1432
1433
EXAMPLES::
1434
1435
sage: from sage.ext.gen_interpreters import *
1436
sage: mc = MemoryChunkScratch('registers', ty_python)
1437
sage: print mc.handle_cleanup()
1438
for i in range(self._n_registers):
1439
Py_CLEAR(self._registers[i])
1440
<BLANKLINE>
1441
"""
1442
# XXX This is a lot slower than it needs to be, because
1443
# we don't have a "cdef int i" in scope here.
1444
return je("""
1445
for i in range(self._n_{{ myself.name }}):
1446
Py_CLEAR(self._{{ myself.name }}[i])
1447
""", myself=self)
1448
1449
class MemoryChunkRRRetval(MemoryChunk):
1450
r"""
1451
A special-purpose memory chunk, for dealing with the return value
1452
of the RR-based interpreter.
1453
"""
1454
1455
def declare_class_members(self):
1456
r"""
1457
Returns a string giving the declarations of the class members
1458
in a wrapper class for this memory chunk.
1459
1460
EXAMPLES::
1461
1462
sage: from sage.ext.gen_interpreters import *
1463
sage: mc = MemoryChunkRRRetval('retval', ty_mpfr)
1464
sage: mc.declare_class_members()
1465
''
1466
"""
1467
return ""
1468
1469
def declare_call_locals(self):
1470
r"""
1471
Returns a string to put in the __call__ method of a wrapper
1472
class using this memory chunk, to allocate local variables.
1473
1474
EXAMPLES::
1475
1476
sage: from sage.ext.gen_interpreters import *
1477
sage: mc = MemoryChunkRRRetval('retval', ty_mpfr)
1478
sage: mc.declare_call_locals()
1479
u' cdef RealNumber retval = (self.domain)()\n'
1480
"""
1481
return je("""
1482
cdef RealNumber {{ myself.name }} = (self.domain)()
1483
""", myself=self)
1484
1485
def pass_argument(self):
1486
r"""
1487
Returns the string to pass the argument corresponding to this
1488
memory chunk to the interpreter.
1489
1490
EXAMPLES::
1491
1492
sage: from sage.ext.gen_interpreters import *
1493
sage: mc = MemoryChunkRRRetval('retval', ty_mpfr)
1494
sage: mc.pass_argument()
1495
u'&retval.value'
1496
"""
1497
return je("""&{{ myself.name }}.value""", myself=self)
1498
1499
def pass_call_c_argument(self):
1500
r"""
1501
Returns the string to pass the argument corresponding to this
1502
memory chunk to the interpreter, for use in the call_c method.
1503
1504
EXAMPLES::
1505
1506
sage: from sage.ext.gen_interpreters import *
1507
sage: mc = MemoryChunkRRRetval('retval', ty_mpfr)
1508
sage: mc.pass_call_c_argument()
1509
'result'
1510
"""
1511
return "result"
1512
1513
class MemoryChunkPythonArguments(MemoryChunk):
1514
r"""
1515
A special-purpose memory chunk, for the generic Python-object based
1516
interpreter. Rather than copy the arguments into an array allocated
1517
in the wrapper, we use the PyTupleObject internals and pass the array
1518
that's inside the argument tuple.
1519
"""
1520
1521
def declare_class_members(self):
1522
r"""
1523
Returns a string giving the declarations of the class members
1524
in a wrapper class for this memory chunk.
1525
1526
EXAMPLES::
1527
1528
sage: from sage.ext.gen_interpreters import *
1529
sage: mc = MemoryChunkPythonArguments('args', ty_python)
1530
"""
1531
return " cdef int _n_%s\n" % self.name
1532
1533
def init_class_members(self):
1534
r"""
1535
Returns a string to be put in the __init__ method of a wrapper
1536
class using this memory chunk, to initialize the corresponding
1537
class members.
1538
1539
EXAMPLES::
1540
1541
sage: from sage.ext.gen_interpreters import *
1542
sage: mc = MemoryChunkPythonArguments('args', ty_python)
1543
sage: mc.init_class_members()
1544
u" count = args['args']\n self._n_args = count\n"
1545
"""
1546
return je("""
1547
count = args['{{ myself.name }}']
1548
self._n_args = count
1549
""", myself=self)
1550
1551
def setup_args(self):
1552
r"""
1553
Handle the arguments of __call__. Nothing to do.
1554
1555
EXAMPLES::
1556
1557
sage: from sage.ext.gen_interpreters import *
1558
sage: mc = MemoryChunkPythonArguments('args', ty_python)
1559
sage: mc.setup_args()
1560
''
1561
"""
1562
return ''
1563
1564
def pass_argument(self):
1565
r"""
1566
Pass the innards of the argument tuple to the interpreter.
1567
1568
EXAMPLES::
1569
1570
sage: from sage.ext.gen_interpreters import *
1571
sage: mc = MemoryChunkPythonArguments('args', ty_python)
1572
sage: mc.pass_argument()
1573
'(<PyTupleObject*>args).ob_item'
1574
"""
1575
return "(<PyTupleObject*>args).ob_item"
1576
1577
class MemoryChunkElementArguments(MemoryChunkPythonArguments):
1578
r"""
1579
A special-purpose memory chunk, for the Python-object based
1580
interpreters that want to process (and perhaps modify) the data.
1581
1582
We allocate a new list (via the map function) on every call to
1583
hold the modified arguments. That's not strictly necessary --
1584
we could pre-allocate a list and map into it -- but this lets us
1585
use simpler code for a very-likely-negligible efficiency cost.
1586
(The Element interpreter is going to allocate lots of objects
1587
as it runs, anyway.)
1588
"""
1589
1590
def setup_args(self):
1591
r"""
1592
Handle the arguments of __call__. Note: This hardcodes
1593
"self._domain".
1594
1595
EXAMPLES::
1596
1597
sage: from sage.ext.gen_interpreters import *
1598
sage: mc = MemoryChunkElementArguments('args', ty_python)
1599
sage: mc.setup_args()
1600
'mapped_args = map(self._domain, args)\n'
1601
"""
1602
return "mapped_args = map(self._domain, args)\n"
1603
1604
def pass_argument(self):
1605
r"""
1606
Pass the innards of the argument tuple to the interpreter.
1607
1608
EXAMPLES::
1609
1610
sage: from sage.ext.gen_interpreters import *
1611
sage: mc = MemoryChunkElementArguments('args', ty_python)
1612
sage: mc.pass_argument()
1613
'(<PyListObject*>mapped_args).ob_item'
1614
"""
1615
return "(<PyListObject*>mapped_args).ob_item"
1616
1617
class MemoryChunkPyConstant(MemoryChunk):
1618
r"""
1619
A special-purpose memory chunk, for holding a single Python constant
1620
and passing it to the interpreter as a PyObject*.
1621
"""
1622
1623
def __init__(self, name):
1624
r"""
1625
Initialize an instance of MemoryChunkPyConstant.
1626
1627
Always uses the type ty_python.
1628
1629
EXAMPLES::
1630
1631
sage: from sage.ext.gen_interpreters import *
1632
sage: mc = MemoryChunkPyConstant('domain')
1633
sage: mc.name
1634
'domain'
1635
sage: mc.storage_type is ty_python
1636
True
1637
"""
1638
MemoryChunk.__init__(self, name, ty_python)
1639
1640
def declare_class_members(self):
1641
r"""
1642
Returns a string giving the declarations of the class members
1643
in a wrapper class for this memory chunk.
1644
1645
EXAMPLES::
1646
1647
sage: from sage.ext.gen_interpreters import *
1648
sage: mc = MemoryChunkPyConstant('domain')
1649
sage: mc.declare_class_members()
1650
u' cdef object _domain\n'
1651
"""
1652
return je("""
1653
cdef object _{{ myself.name }}
1654
""", myself=self)
1655
1656
def init_class_members(self):
1657
r"""
1658
Returns a string to be put in the __init__ method of a wrapper
1659
class using this memory chunk, to initialize the corresponding
1660
class members.
1661
1662
EXAMPLES::
1663
1664
sage: from sage.ext.gen_interpreters import *
1665
sage: mc = MemoryChunkPyConstant('domain')
1666
sage: mc.init_class_members()
1667
u" self._domain = args['domain']\n"
1668
"""
1669
return je("""
1670
self._{{ myself.name }} = args['{{ myself.name }}']
1671
""", myself=self)
1672
1673
def declare_parameter(self):
1674
r"""
1675
Returns the string to use to declare the interpreter parameter
1676
corresponding to this memory chunk.
1677
1678
EXAMPLES::
1679
1680
sage: from sage.ext.gen_interpreters import *
1681
sage: mc = MemoryChunkPyConstant('domain')
1682
sage: mc.declare_parameter()
1683
'PyObject* domain'
1684
"""
1685
return 'PyObject* %s' % self.name
1686
1687
def pass_argument(self):
1688
r"""
1689
Returns the string to pass the argument corresponding to this
1690
memory chunk to the interpreter.
1691
1692
EXAMPLES::
1693
1694
sage: from sage.ext.gen_interpreters import *
1695
sage: mc = MemoryChunkPyConstant('domain')
1696
sage: mc.pass_argument()
1697
'<PyObject*>self._domain'
1698
"""
1699
return '<PyObject*>self._%s' % self.name
1700
1701
def params_gen(**chunks):
1702
r"""
1703
Instructions have a parameter specification that says where they get
1704
their inputs and where their outputs go. Each parameter has
1705
the same form: it is a triple (chunk, addr, len). The chunk says
1706
where the parameter is read from/written to. The addr says which
1707
value in the chunk is used. If the chunk is a stack chunk, then
1708
addr must be null; the value will be read from/written to the top
1709
of the stack. Otherwise, addr must be an integer, or another chunk;
1710
if addr is another chunk, then the next value is read from that chunk
1711
to be the address.
1712
1713
The len says how many values to read/write. It can be either None
1714
(meaning to read/write only a single value), an integer, or
1715
another chunk; if it is a chunk, then the next value is read from that
1716
chunk to be the len. Note that specifying len changes the types
1717
given to the instruction, so len==None is different than len==1 even
1718
though both mean to use a single value.
1719
1720
These parameter specifications are cumbersome to write by hand, so
1721
there's also a simple string format for them. This (curried)
1722
function parses the simple string format and produces parameter
1723
specifications. The params_gen function takes keyword arguments
1724
mapping single-character names to memory chunks. The string format
1725
uses these names. The params_gen function returns another function,
1726
that takes two strings and returns a pair of lists of parameter
1727
specifications.
1728
1729
Each string is the concatenation of arbitrarily many specifications.
1730
Each specification consists of an address and a length. The
1731
address is either a single character naming a stack chunk,
1732
or a string of the form 'A[B]' where A names a non-stack chunk
1733
and B names the code chunk. The length is either empty, or '@n'
1734
for a number n (meaning to use that many arguments), or '@C', where
1735
C is the code chunk.
1736
1737
EXAMPLES::
1738
1739
sage: from sage.ext.gen_interpreters import *
1740
sage: mc_stack = MemoryChunkScratch('stack', ty_double, is_stack=True)
1741
sage: mc_args = MemoryChunkArguments('args', ty_double)
1742
sage: mc_code = MemoryChunkConstants('code', ty_int)
1743
1744
sage: pg = params_gen(D=mc_code, A=mc_args, S=mc_stack)
1745
sage: pg('S', '')
1746
([({MC:stack}, None, None)], [])
1747
sage: pg('A[D]', '')
1748
([({MC:args}, {MC:code}, None)], [])
1749
sage: pg('S@5', '')
1750
([({MC:stack}, None, 5)], [])
1751
sage: pg('S@D', '')
1752
([({MC:stack}, None, {MC:code})], [])
1753
sage: pg('A[D]@D', '')
1754
([({MC:args}, {MC:code}, {MC:code})], [])
1755
sage: pg('SSS@D', 'A[D]S@D')
1756
([({MC:stack}, None, None), ({MC:stack}, None, None), ({MC:stack}, None, {MC:code})], [({MC:args}, {MC:code}, None), ({MC:stack}, None, {MC:code})])
1757
"""
1758
1759
def make_params(s):
1760
p = []
1761
s = s.strip()
1762
while s:
1763
chunk_code = s[0]
1764
s = s[1:]
1765
chunk = chunks[chunk_code]
1766
addr = None
1767
ch_len = None
1768
# shouldn't hardcode 'code' here
1769
if chunk.is_stack() or chunk.name == 'code':
1770
pass
1771
else:
1772
m = re.match(r'\[(?:([0-9]+)|([a-zA-Z]))\]', s)
1773
if m.group(1):
1774
addr = int(m.group(1))
1775
else:
1776
ch = chunks[m.group(2)]
1777
assert ch.storage_type is ty_int
1778
addr = ch
1779
s = s[m.end():].strip()
1780
if len(s) and s[0] == '@':
1781
m = re.match(r'@(?:([0-9]+)|([a-zA-Z]))', s)
1782
if m.group(1):
1783
ch_len = int(m.group(1))
1784
else:
1785
ch = chunks[m.group(2)]
1786
assert ch.storage_type is ty_int
1787
ch_len = ch
1788
s = s[m.end():].strip()
1789
p.append((chunk, addr, ch_len))
1790
return p
1791
1792
def params(s_ins, s_outs):
1793
ins = make_params(s_ins)
1794
outs = make_params(s_outs)
1795
return (ins, outs)
1796
1797
return params
1798
1799
def string_of_addr(a):
1800
r"""
1801
An address or a length from a parameter specification may be
1802
either None, an integer, or a MemoryChunk. If the address or
1803
length is an integer or a MemoryChunk, this function will convert
1804
it to a string giving an expression that will evaluate to the correct
1805
address or length. (See the docstring for params_gen for more
1806
information on parameter specifications.)
1807
1808
EXAMPLES::
1809
1810
sage: from sage.ext.gen_interpreters import *
1811
sage: mc_code = MemoryChunkConstants('code', ty_int)
1812
sage: string_of_addr(mc_code)
1813
'*code++'
1814
sage: string_of_addr(42r)
1815
'42'
1816
"""
1817
if isinstance(a, (int, long)):
1818
return str(a)
1819
assert(isinstance(a, MemoryChunk))
1820
return '*%s++' % a.name
1821
1822
class InstrSpec(object):
1823
r"""
1824
Each instruction in an interpreter is represented as an InstrSpec.
1825
This contains all the information that we need to generate code
1826
to interpret the instruction; it also is used to build the tables
1827
that fast_callable uses, so this is the nexus point between
1828
users of the interpreter (possibly pure Python) and the
1829
generated C interpreter.
1830
1831
The underlying instructions are matched to the caller by name.
1832
For instance, fast_callable assumes that if the interpreter has an
1833
instruction named 'cos', then it will take a single argument,
1834
return a single result, and implement the cos() function.
1835
1836
The print representation of an instruction (which will probably
1837
only be used when doctesting this file) consists of the name,
1838
a simplified stack effect, and the code (truncated if it's long).
1839
The stack effect has two parts, the input and the output, separated
1840
by '->'; the input shows what will be popped from the stack,
1841
the output what will be placed on the stack. Each consists of
1842
a sequence of 'S' and '*' characters, where 'S' refers to a single
1843
argument and '*' refers to a variable number of arguments.
1844
1845
The code for an instruction is a small snippet of C code. It has
1846
available variables 'i0', 'i1', ..., 'o0', 'o1', ...; one variable
1847
for each input and output; its job is to assign values to the output
1848
variables, based on the values of the input variables.
1849
1850
Normally, in an interpreter that uses doubles, each of the input
1851
and output variables will be a double. If i0 actually represents
1852
a variable number of arguments, then it will be a pointer to
1853
double instead, and there will be another variable n_i0 giving
1854
the actual number of arguments.
1855
1856
When instructions refer to auto-reference types, they actually
1857
get a pointer to the data in its original location; it is
1858
not copied into a local variable. Mostly, this makes no difference,
1859
but there is one potential problem to be aware of. It is possible
1860
for an output variable to point to the same object as an input
1861
variable; in fact, this usually will happen when you're working
1862
with the stack. If the instruction maps to a single function call,
1863
then this is fine; the standard auto-reference implementations
1864
(GMP, MPFR, etc.) are careful to allow having the input and output
1865
be the same. But if the instruction maps to multiple function
1866
calls, you may need to use a temporary variable.
1867
1868
Here's an example of this issue. Suppose you want to make an
1869
instruction that does ``out = a+b*c``. You write code like this:
1870
out = b*c
1871
out = a+out
1872
But out will actually share the same storage as a; so the first line
1873
modifies a, and you actually end up computing 2*(b+c). The fix
1874
is to only write to the output once, at the very end of your
1875
instruction.
1876
1877
Instructions are also allowed to access memory chunks (other than
1878
the stack and code) directly. They are available as C variables
1879
with the same name as the chunk. This is useful if some type of
1880
memory chunk doesn't fit well with the params_gen interface.
1881
1882
There are additional reference-counting rules that must be
1883
followed if your interpreter operates on Python objects; these
1884
rules are described in the docstring of the PythonInterpreter
1885
class.
1886
1887
EXAMPLES::
1888
1889
sage: from sage.ext.gen_interpreters import *
1890
sage: pg = RDFInterpreter().pg
1891
sage: InstrSpec('add', pg('SS','S'), code='o0 = i0+i1;')
1892
add: SS->S = 'o0 = i0+i1;'
1893
"""
1894
1895
def __init__(self, name, io, code=None, uses_error_handler=False, handles_own_decref=False):
1896
r"""
1897
Initialize an InstrSpec.
1898
1899
INPUTS:
1900
name -- the name of the instruction
1901
io -- a pair of lists of parameter specifications for I/O of the
1902
instruction
1903
code -- a string containing a snippet of C code to read
1904
from the input variables and write to the output variables
1905
uses_error_handler -- True if the instruction calls Python
1906
and jumps to error: on a Python error
1907
handles_own_decref -- True if the instruction handles Python
1908
objects and includes its own
1909
reference-counting
1910
1911
EXAMPLES::
1912
1913
sage: from sage.ext.gen_interpreters import *
1914
1915
sage: pg = RDFInterpreter().pg
1916
sage: InstrSpec('add', pg('SS','S'), code='o0 = i0+i1;')
1917
add: SS->S = 'o0 = i0+i1;'
1918
sage: instr = InstrSpec('py_call', pg('P[D]S@D', 'S'), code=('This is very complicated. ' + 'blah ' * 30)); instr
1919
py_call: *->S = 'This is very compli... blah blah blah '
1920
sage: instr.name
1921
'py_call'
1922
sage: instr.inputs
1923
[({MC:py_constants}, {MC:code}, None), ({MC:stack}, None, {MC:code})]
1924
sage: instr.outputs
1925
[({MC:stack}, None, None)]
1926
sage: instr.code
1927
'This is very complicated. blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah '
1928
sage: instr.parameters
1929
['py_constants', 'n_inputs']
1930
sage: instr.n_inputs
1931
0
1932
sage: instr.n_outputs
1933
1
1934
"""
1935
self.name = name
1936
self.inputs = io[0]
1937
self.outputs = io[1]
1938
self.uses_error_handler = uses_error_handler
1939
self.handles_own_decref = handles_own_decref
1940
if code is not None:
1941
self.code = code
1942
# XXX We assume that there is only one stack
1943
n_inputs = 0
1944
n_outputs = 0
1945
in_effect = ''
1946
out_effect = ''
1947
p = []
1948
for (ch, addr, len) in self.inputs:
1949
if ch.is_stack():
1950
if len is None:
1951
n_inputs += 1
1952
in_effect += 'S'
1953
elif isinstance(len, (int, long)):
1954
n_inputs += len
1955
in_effect += 'S%d' % len
1956
else:
1957
p.append('n_inputs')
1958
in_effect += '*'
1959
else:
1960
p.append(ch.name)
1961
for (ch, addr, len) in self.outputs:
1962
if ch.is_stack():
1963
if len is None:
1964
n_outputs += 1
1965
out_effect += 'S'
1966
elif isinstance(len, (int, long)):
1967
n_outputs += len
1968
out_effect += 'S%d' % len
1969
else:
1970
p.append('n_outputs')
1971
out_effect += '*'
1972
else:
1973
p.append(ch.name)
1974
self.parameters = p
1975
self.n_inputs = n_inputs
1976
self.n_outputs = n_outputs
1977
self.in_effect = in_effect
1978
self.out_effect = out_effect
1979
1980
def __repr__(self):
1981
r"""
1982
Produce a string representing a given instruction, consisting
1983
of its name, a brief stack specification, and its code
1984
(possibly abbreviated).
1985
1986
EXAMPLES::
1987
1988
sage: from sage.ext.gen_interpreters import *
1989
sage: pg = RDFInterpreter().pg
1990
sage: InstrSpec('add', pg('SS','S'), code='o0 = i0+i1;')
1991
add: SS->S = 'o0 = i0+i1;'
1992
"""
1993
rcode = repr(self.code)
1994
if len(rcode) > 40:
1995
rcode = rcode[:20] + '...' + rcode[-17:]
1996
return '%s: %s->%s = %s' % \
1997
(self.name, self.in_effect, self.out_effect, rcode)
1998
1999
# Now we have a series of helper functions that make it slightly easier
2000
# to create instructions.
2001
2002
def instr_infix(name, io, op):
2003
r"""
2004
A helper function for creating instructions implemented by
2005
a single infix binary operator.
2006
2007
EXAMPLES::
2008
2009
sage: from sage.ext.gen_interpreters import *
2010
sage: pg = RDFInterpreter().pg
2011
sage: instr_infix('mul', pg('SS', 'S'), '*')
2012
mul: SS->S = 'o0 = i0 * i1;'
2013
"""
2014
return InstrSpec(name, io, code='o0 = i0 %s i1;' % op)
2015
2016
def instr_funcall_2args(name, io, op):
2017
r"""
2018
A helper function for creating instructions implemented by
2019
a two-argument function call.
2020
2021
EXAMPLES::
2022
2023
sage: from sage.ext.gen_interpreters import *
2024
sage: pg = RDFInterpreter().pg
2025
sage: instr_funcall_2args('atan2', pg('SS', 'S'), 'atan2')
2026
atan2: SS->S = 'o0 = atan2(i0, i1);'
2027
"""
2028
return InstrSpec(name, io, code='o0 = %s(i0, i1);' % op)
2029
2030
def instr_unary(name, io, op):
2031
r"""
2032
A helper function for creating instructions with one input
2033
and one output.
2034
2035
EXAMPLES::
2036
2037
sage: from sage.ext.gen_interpreters import *
2038
sage: pg = RDFInterpreter().pg
2039
sage: instr_unary('sin', pg('S','S'), 'sin(i0)')
2040
sin: S->S = 'o0 = sin(i0);'
2041
sage: instr_unary('neg', pg('S','S'), '-i0')
2042
neg: S->S = 'o0 = -i0;'
2043
"""
2044
return InstrSpec(name, io, code='o0 = ' + op + ';')
2045
2046
def instr_funcall_2args_mpfr(name, io, op):
2047
r"""
2048
A helper function for creating MPFR instructions with two inputs
2049
and one output.
2050
2051
EXAMPLES::
2052
2053
sage: from sage.ext.gen_interpreters import *
2054
sage: pg = RRInterpreter().pg
2055
sage: instr_funcall_2args_mpfr('add', pg('SS','S'), 'mpfr_add')
2056
add: SS->S = 'mpfr_add(o0, i0, i1, GMP_RNDN);'
2057
"""
2058
return InstrSpec(name, io, code='%s(o0, i0, i1, GMP_RNDN);' % op)
2059
2060
def instr_funcall_1arg_mpfr(name, io, op):
2061
r"""
2062
A helper function for creating MPFR instructions with one input
2063
and one output.
2064
2065
EXAMPLES::
2066
2067
sage: from sage.ext.gen_interpreters import *
2068
sage: pg = RRInterpreter().pg
2069
sage: instr_funcall_1arg_mpfr('exp', pg('S','S'), 'mpfr_exp')
2070
exp: S->S = 'mpfr_exp(o0, i0, GMP_RNDN);'
2071
"""
2072
return InstrSpec(name, io, code='%s(o0, i0, GMP_RNDN);' % op)
2073
2074
class InterpreterSpec(object):
2075
r"""
2076
Each interpreter to be generated by this module is represented
2077
by an InterpreterSpec.
2078
"""
2079
2080
def __init__(self):
2081
r"""
2082
Initialize an InterpreterSpec.
2083
2084
Initializes the following fields:
2085
2086
h_header -- a code snippet to go at the top of the C interpreter
2087
header file
2088
2089
c_header -- a code snippet to go at the top of the C interpreter
2090
source file
2091
pxd_header -- a code snippet to go at the top of the wrapper
2092
class .pxd file
2093
pyx_header -- a code snippet to go at the top of the wrapper
2094
class source file
2095
err_return -- a string indicating the value to be returned
2096
in case of a Python exception
2097
mc_code -- a memory chunk to use for the interpreted code
2098
extra_class_members -- Class members for the wrapper that
2099
don't correspond to memory chunks
2100
extra_members_initialize -- Code to initialize extra_class_members
2101
2102
EXAMPLES::
2103
2104
sage: from sage.ext.gen_interpreters import *
2105
sage: interp = RDFInterpreter()
2106
sage: interp.h_header
2107
'\n#include <gsl/gsl_math.h>\n'
2108
sage: interp.c_header
2109
''
2110
sage: interp.pxd_header
2111
''
2112
sage: interp.pyx_header
2113
''
2114
sage: interp.err_return
2115
'-1094648009105371'
2116
sage: interp.mc_code
2117
{MC:code}
2118
sage: interp = RRInterpreter()
2119
sage: interp.extra_class_members
2120
''
2121
sage: interp.extra_members_initialize
2122
''
2123
"""
2124
self.h_header = ''
2125
self.c_header = ''
2126
self.pxd_header = ''
2127
self.pyx_header = ''
2128
self.err_return = 'NULL'
2129
self.mc_code = MemoryChunkConstants('code', ty_int)
2130
self.extra_class_members = ''
2131
self.extra_members_initialize = ''
2132
2133
def _set_opcodes(self):
2134
r"""
2135
Assign opcodes to the instructions in this interpreter.
2136
2137
Must be called at the end of __init__ by any subclass of
2138
InterpreterSpec.
2139
2140
EXAMPLES::
2141
2142
sage: from sage.ext.gen_interpreters import *
2143
sage: interp = RDFInterpreter()
2144
sage: interp.instr_descs[5].opcode
2145
5
2146
"""
2147
for i in range(len(self.instr_descs)):
2148
self.instr_descs[i].opcode = i
2149
2150
2151
class StackInterpreter(InterpreterSpec):
2152
r"""
2153
A subclass of InterpreterSpec, specialized for stack-based
2154
interpreters. (Currently all interpreters are stack-based.)
2155
"""
2156
2157
def __init__(self, type, mc_retval=None):
2158
r"""
2159
Initialize a StackInterpreter.
2160
2161
INPUTS:
2162
type -- A StorageType; the basic type that this interpreter
2163
operates on
2164
mc_retval -- default None; if not None, a special-purpose
2165
MemoryChunk to use as a return value
2166
2167
Initializes the fields described in the documentation for
2168
InterpreterSpec.__init__, as well as the following:
2169
2170
mc_args, mc_constants, mc_stack -- MemoryChunk values
2171
return_type -- the type returned by the C interpreter (None for int,
2172
where 1 means success and 0 means error)
2173
mc_retval -- None, or the MemoryChunk to use as a return value
2174
ipow_range -- the range of exponents supported by the ipow
2175
instruction (default is False, meaning never use ipow)
2176
adjust_retval -- None, or a string naming a function to call
2177
in the wrapper's __call__ to modify the return
2178
value of the interpreter
2179
implement_call_c -- True if the wrapper should have a fast cdef call_c
2180
method (that bypasses the Python call overhead)
2181
(default True)
2182
2183
EXAMPLES::
2184
2185
sage: from sage.ext.gen_interpreters import *
2186
sage: rdf = RDFInterpreter()
2187
sage: rr = RRInterpreter()
2188
sage: el = ElementInterpreter()
2189
sage: rdf.mc_args
2190
{MC:args}
2191
sage: rdf.mc_constants
2192
{MC:constants}
2193
sage: rdf.mc_stack
2194
{MC:stack}
2195
sage: rr.mc_retval
2196
{MC:retval}
2197
sage: rr.return_type is None
2198
True
2199
sage: rdf.return_type.type
2200
'double'
2201
sage: rdf.implement_call_c
2202
True
2203
sage: el.implement_call_c
2204
False
2205
"""
2206
InterpreterSpec.__init__(self)
2207
self.mc_args = MemoryChunkArguments('args', type)
2208
self.mc_constants = MemoryChunkConstants('constants', type)
2209
self.mc_stack = MemoryChunkScratch('stack', type, is_stack=True)
2210
if isinstance(type, StorageTypeAssignable):
2211
self.return_type = type
2212
else:
2213
self.return_type = None
2214
self.mc_retval = mc_retval
2215
self.ipow_range = False
2216
self.adjust_retval = None
2217
self.implement_call_c = True
2218
2219
class RDFInterpreter(StackInterpreter):
2220
r"""
2221
A subclass of StackInterpreter, specifying an interpreter over
2222
machine-floating-point values (C doubles). This is used for
2223
both domain=RDF and domain=float; currently the only difference
2224
between the two is the type of the value returned from the
2225
wrapper (they use the same wrapper and interpreter).
2226
"""
2227
2228
def __init__(self):
2229
r"""
2230
Initialize an RDFInterpreter.
2231
2232
EXAMPLES::
2233
2234
sage: from sage.ext.gen_interpreters import *
2235
sage: interp = RDFInterpreter()
2236
sage: interp.name
2237
'rdf'
2238
sage: interp.extra_class_members
2239
'cdef object _domain\n'
2240
sage: interp.extra_members_initialize
2241
"self._domain = args['domain']\n"
2242
sage: interp.adjust_retval
2243
'self._domain'
2244
sage: interp.mc_py_constants
2245
{MC:py_constants}
2246
sage: interp.chunks
2247
[{MC:args}, {MC:constants}, {MC:py_constants}, {MC:stack}, {MC:code}]
2248
sage: interp.pg('A[D]', 'S')
2249
([({MC:args}, {MC:code}, None)], [({MC:stack}, None, None)])
2250
sage: instrs = dict([(ins.name, ins) for ins in interp.instr_descs])
2251
sage: instrs['add']
2252
add: SS->S = 'o0 = i0 + i1;'
2253
sage: instrs['py_call']
2254
py_call: *->S = '\nPyObject *py_arg...goto error;\n}\n'
2255
2256
Make sure that pow behaves reasonably::
2257
2258
sage: var('x,y')
2259
(x, y)
2260
sage: ff = fast_callable(x^y, vars=[x,y], domain=RDF)
2261
sage: ff(1.5, 3)
2262
3.375
2263
sage: ff(-2, 3)
2264
-8.0
2265
sage: ff(-2, 1/3)
2266
Traceback (most recent call last):
2267
...
2268
ValueError: negative number to a fractional power not real
2269
"""
2270
2271
StackInterpreter.__init__(self, ty_double)
2272
self.name = 'rdf'
2273
self.mc_py_constants = MemoryChunkConstants('py_constants', ty_python)
2274
# This is a randomly chosen number. Whenever this number is
2275
# returned, the wrapper has to check whether an exception actually
2276
# happened, so if an expression evaluates to this number execution
2277
# is slightly slower. Hopefully that won't happen too often :)
2278
self.err_return = '-1094648009105371'
2279
self.chunks = [self.mc_args, self.mc_constants, self.mc_py_constants,
2280
self.mc_stack,
2281
self.mc_code]
2282
pg = params_gen(A=self.mc_args, C=self.mc_constants, D=self.mc_code,
2283
S=self.mc_stack, P=self.mc_py_constants)
2284
self.pg = pg
2285
self.h_header = """
2286
#include <gsl/gsl_math.h>
2287
"""
2288
instrs = [
2289
InstrSpec('load_arg', pg('A[D]', 'S'),
2290
code='o0 = i0;'),
2291
InstrSpec('load_const', pg('C[D]', 'S'),
2292
code='o0 = i0;'),
2293
InstrSpec('return', pg('S', ''),
2294
code='return i0;'),
2295
InstrSpec('py_call', pg('P[D]S@D', 'S'),
2296
uses_error_handler=True,
2297
code="""
2298
PyObject *py_args = PyTuple_New(n_i1);
2299
if (py_args == NULL) goto error;
2300
int i;
2301
for (i = 0; i < n_i1; i++) {
2302
PyObject *arg = PyFloat_FromDouble(i1[i]);
2303
if (arg == NULL) {
2304
Py_DECREF(py_args);
2305
goto error;
2306
}
2307
PyTuple_SET_ITEM(py_args, i, arg);
2308
}
2309
PyObject *result = PyObject_CallObject(i0, py_args);
2310
Py_DECREF(py_args);
2311
if (result == NULL) goto error;
2312
/* If result is not a float, then this will turn it into a float first. */
2313
o0 = PyFloat_AsDouble(result);
2314
Py_DECREF(result);
2315
if (o0 == -1 && PyErr_Occurred()) {
2316
goto error;
2317
}
2318
"""),
2319
InstrSpec('pow', pg('SS', 'S'),
2320
uses_error_handler=True,
2321
code="""
2322
/* See python's pow in floatobject.c */
2323
if (i0 == 0) o0 = 1.0;
2324
else {
2325
if (i0 < 0 && i1 != floor(i1)) {
2326
PyErr_SetString(PyExc_ValueError, "negative number to a fractional power not real");
2327
goto error;
2328
}
2329
o0 = pow(i0, i1);
2330
}
2331
""")
2332
]
2333
for (name, op) in [('add', '+'), ('sub', '-'),
2334
('mul', '*'), ('div', '/')]:
2335
instrs.append(instr_infix(name, pg('SS', 'S'), op))
2336
instrs.append(instr_funcall_2args('ipow', pg('SD', 'S'), 'gsl_pow_int'))
2337
for (name, op) in [('neg', '-i0'), ('invert', '1/i0'),
2338
('abs', 'fabs(i0)')]:
2339
instrs.append(instr_unary(name, pg('S', 'S'), op))
2340
for name in ['sqrt', 'ceil', 'floor', 'sin', 'cos', 'tan',
2341
'asin', 'acos', 'atan', 'sinh', 'cosh', 'tanh',
2342
'asinh', 'acosh', 'atanh', 'exp', 'log']:
2343
instrs.append(instr_unary(name, pg('S', 'S'), "%s(i0)" % name))
2344
self.instr_descs = instrs
2345
self._set_opcodes()
2346
# supported for exponents that fit in an int
2347
self.ipow_range = (int(-2**31), int(2**31-1))
2348
self.extra_class_members = "cdef object _domain\n"
2349
self.extra_members_initialize = "self._domain = args['domain']\n"
2350
self.adjust_retval = 'self._domain'
2351
2352
2353
class CDFInterpreter(StackInterpreter):
2354
r"""
2355
A subclass of StackInterpreter, specifying an interpreter over
2356
complex machine-floating-point values (C doubles).
2357
"""
2358
2359
def __init__(self):
2360
r"""
2361
Initialize a CDFInterpreter.
2362
2363
EXAMPLES::
2364
2365
sage: from sage.ext.gen_interpreters import *
2366
sage: interp = CDFInterpreter()
2367
sage: interp.name
2368
'cdf'
2369
sage: interp.mc_py_constants
2370
{MC:py_constants}
2371
sage: interp.chunks
2372
[{MC:args}, {MC:constants}, {MC:py_constants}, {MC:stack}, {MC:code}]
2373
sage: interp.pg('A[D]', 'S')
2374
([({MC:args}, {MC:code}, None)], [({MC:stack}, None, None)])
2375
sage: instrs = dict([(ins.name, ins) for ins in interp.instr_descs])
2376
sage: instrs['add']
2377
add: SS->S = 'o0 = i0 + i1;'
2378
sage: instrs['sin']
2379
sin: S->S = 'o0 = csin(i0);'
2380
sage: instrs['py_call']
2381
py_call: *->S = '\nif (!cdf_py_call_...goto error;\n}\n'
2382
2383
A test of integer powers::
2384
2385
sage: f(x) = sum(x^k for k in [-20..20])
2386
sage: f(CDF(1+2j))
2387
-10391779.0 + 3349659.5*I
2388
sage: ff = fast_callable(f, CDF)
2389
sage: ff(1 + 2j)
2390
-10391779.0 + 3349659.5*I
2391
sage: ff.python_calls()
2392
[]
2393
2394
sage: f(x) = sum(x^k for k in [0..5])
2395
sage: ff = fast_callable(f, CDF)
2396
sage: ff(2)
2397
63.0
2398
sage: ff(2j)
2399
13.0 + 26.0*I
2400
"""
2401
2402
StackInterpreter.__init__(self, ty_double_complex)
2403
self.name = 'cdf'
2404
self.mc_py_constants = MemoryChunkConstants('py_constants', ty_python)
2405
# See comment for RDFInterpreter
2406
self.err_return = '-1094648119105371'
2407
self.adjust_retval = "dz_to_CDE"
2408
self.chunks = [self.mc_args, self.mc_constants, self.mc_py_constants,
2409
self.mc_stack,
2410
self.mc_code]
2411
pg = params_gen(A=self.mc_args, C=self.mc_constants, D=self.mc_code,
2412
S=self.mc_stack, P=self.mc_py_constants)
2413
self.pg = pg
2414
self.h_header = """
2415
#include <stdlib.h>
2416
#include <complex.h>
2417
2418
/* On Solaris, we need to define _Imaginary_I when compiling with GCC,
2419
* otherwise the constant I doesn't work. The definition below is based
2420
* on glibc. */
2421
#ifdef __GNUC__
2422
#undef _Imaginary_I
2423
#define _Imaginary_I (__extension__ 1.0iF)
2424
#endif
2425
2426
typedef double complex double_complex;
2427
2428
extern int cdf_py_call_helper(PyObject*, int, double complex*, double complex*);
2429
2430
static inline double complex csquareX(double complex z) {
2431
double complex res;
2432
__real__(res) = __real__(z) * __real__(z) - __imag__(z) * __imag__(z);
2433
__imag__(res) = 2 * __real__(z) * __imag__(z);
2434
return res;
2435
}
2436
2437
static inline double complex cpow_int(double complex z, int exp) {
2438
if (exp < 0) return 1/cpow_int(z, -exp);
2439
switch (exp) {
2440
case 0: return 1;
2441
case 1: return z;
2442
case 2: return csquareX(z);
2443
case 3: return csquareX(z) * z;
2444
case 4:
2445
case 5:
2446
case 6:
2447
case 7:
2448
case 8:
2449
{
2450
double complex z2 = csquareX(z);
2451
double complex z4 = csquareX(z2);
2452
if (exp == 4) return z4;
2453
if (exp == 5) return z4 * z;
2454
if (exp == 6) return z4 * z2;
2455
if (exp == 7) return z4 * z2 * z;
2456
if (exp == 8) return z4 * z4;
2457
}
2458
}
2459
if (cimag(z) == 0) return pow(creal(z), exp);
2460
if (creal(z) == 0) {
2461
double r = pow(cimag(z), exp);
2462
switch (exp % 4) {
2463
case 0:
2464
return r;
2465
case 1:
2466
return r * I;
2467
case 2:
2468
return -r;
2469
default /* case 3 */:
2470
return -r * I;
2471
}
2472
}
2473
return cpow(z, exp);
2474
}
2475
"""
2476
self.pxd_header = """
2477
# This is to work around a header incompatibility with PARI using
2478
# "I" as variable conflicting with the complex "I".
2479
cdef extern from "pari/paricfg.h":
2480
pass
2481
cdef extern from "pari/pari.h":
2482
pass
2483
cdef extern from "pari/paripriv.h":
2484
pass
2485
2486
# Cython does not (yet) support complex numbers natively, so this is a bit hackish.
2487
cdef extern from "complex.h":
2488
ctypedef double double_complex "double complex"
2489
"""
2490
self.pyx_header = """
2491
from sage.rings.complex_double cimport ComplexDoubleElement
2492
import sage.rings.complex_double
2493
cdef object CDF = sage.rings.complex_double.CDF
2494
2495
cdef extern from "solaris_fixes.h": pass
2496
2497
# Cython does not (yet) support complex numbers natively, so this is a bit hackish.
2498
cdef extern from "complex.h":
2499
ctypedef double double_complex "double complex"
2500
cdef double creal(double_complex)
2501
cdef double cimag(double_complex)
2502
cdef double_complex _Complex_I
2503
2504
cdef inline double_complex CDE_to_dz(zz):
2505
cdef ComplexDoubleElement z = <ComplexDoubleElement>(zz if isinstance(zz, ComplexDoubleElement) else CDF(zz))
2506
return z._complex.dat[0] + _Complex_I * z._complex.dat[1]
2507
2508
cdef inline ComplexDoubleElement dz_to_CDE(double_complex dz):
2509
cdef ComplexDoubleElement z = <ComplexDoubleElement>PY_NEW(ComplexDoubleElement)
2510
z._complex.dat[0] = creal(dz)
2511
z._complex.dat[1] = cimag(dz)
2512
return z
2513
2514
cdef public bint cdf_py_call_helper(object fn,
2515
int n_args,
2516
double_complex* args, double_complex* retval) except 0:
2517
py_args = []
2518
cdef int i
2519
for i from 0 <= i < n_args:
2520
py_args.append(dz_to_CDE(args[i]))
2521
py_result = fn(*py_args)
2522
cdef ComplexDoubleElement result
2523
if isinstance(py_result, ComplexDoubleElement):
2524
result = <ComplexDoubleElement>py_result
2525
else:
2526
result = CDF(py_result)
2527
retval[0] = CDE_to_dz(result)
2528
return 1
2529
2530
"""[1:]
2531
2532
instrs = [
2533
InstrSpec('load_arg', pg('A[D]', 'S'),
2534
code='o0 = i0;'),
2535
InstrSpec('load_const', pg('C[D]', 'S'),
2536
code='o0 = i0;'),
2537
InstrSpec('return', pg('S', ''),
2538
code='return i0;'),
2539
InstrSpec('py_call', pg('P[D]S@D', 'S'),
2540
uses_error_handler=True,
2541
code="""
2542
if (!cdf_py_call_helper(i0, n_i1, i1, &o0)) {
2543
goto error;
2544
}
2545
""")
2546
]
2547
for (name, op) in [('add', '+'), ('sub', '-'),
2548
('mul', '*'), ('div', '/')]:
2549
instrs.append(instr_infix(name, pg('SS', 'S'), op))
2550
instrs.append(instr_funcall_2args('pow', pg('SS', 'S'), 'cpow'))
2551
instrs.append(instr_funcall_2args('ipow', pg('SD', 'S'), 'cpow_int'))
2552
for (name, op) in [('neg', '-i0'), ('invert', '1/i0'),
2553
('abs', 'cabs(i0)')]:
2554
instrs.append(instr_unary(name, pg('S', 'S'), op))
2555
for name in ['sqrt', 'sin', 'cos', 'tan',
2556
'asin', 'acos', 'atan', 'sinh', 'cosh', 'tanh',
2557
'asinh', 'acosh', 'atanh', 'exp', 'log']:
2558
instrs.append(instr_unary(name, pg('S', 'S'), "c%s(i0)" % name))
2559
self.instr_descs = instrs
2560
self._set_opcodes()
2561
# supported for exponents that fit in an int
2562
self.ipow_range = (int(-2**31), int(2**31-1))
2563
2564
2565
class RRInterpreter(StackInterpreter):
2566
r"""
2567
A subclass of StackInterpreter, specifying an interpreter over
2568
MPFR arbitrary-precision floating-point numbers.
2569
"""
2570
2571
def __init__(self):
2572
r"""
2573
Initialize an RDFInterpreter.
2574
2575
EXAMPLES::
2576
2577
sage: from sage.ext.gen_interpreters import *
2578
sage: interp = RRInterpreter()
2579
sage: interp.name
2580
'rr'
2581
sage: interp.mc_py_constants
2582
{MC:py_constants}
2583
sage: interp.chunks
2584
[{MC:args}, {MC:retval}, {MC:constants}, {MC:py_constants}, {MC:stack}, {MC:code}, {MC:domain}]
2585
sage: interp.pg('A[D]', 'S')
2586
([({MC:args}, {MC:code}, None)], [({MC:stack}, None, None)])
2587
sage: instrs = dict([(ins.name, ins) for ins in interp.instr_descs])
2588
sage: instrs['add']
2589
add: SS->S = 'mpfr_add(o0, i0, i1, GMP_RNDN);'
2590
sage: instrs['py_call']
2591
py_call: *->S = '\nif (!rr_py_call_h...goto error;\n}\n'
2592
2593
That py_call instruction is particularly interesting, and
2594
demonstrates a useful technique to let you use Cython code
2595
in an interpreter. Let's look more closely::
2596
2597
sage: print instrs['py_call'].code
2598
if (!rr_py_call_helper(domain, i0, n_i1, i1, o0)) {
2599
goto error;
2600
}
2601
2602
This instruction makes use of the function rr_py_call_helper,
2603
which is declared::
2604
2605
sage: print interp.h_header
2606
<BLANKLINE>
2607
#include <mpfr.h>
2608
<BLANKLINE>
2609
extern int rr_py_call_helper(PyObject*, PyObject*, int, mpfr_t*, mpfr_t*);
2610
2611
In particular, rr_py_call_helper comes from::
2612
2613
sage: print interp.pyx_header
2614
cdef public bint rr_py_call_helper(object domain, object fn,
2615
int n_args,
2616
mpfr_t* args, mpfr_t* retval) except 0:
2617
py_args = []
2618
cdef int i
2619
cdef RealNumber rn
2620
for i from 0 <= i < n_args:
2621
rn = domain()
2622
mpfr_set(rn.value, args[i], GMP_RNDN)
2623
py_args.append(rn)
2624
cdef RealNumber result = domain(fn(*py_args))
2625
mpfr_set(retval[0], result.value, GMP_RNDN)
2626
return 1
2627
2628
2629
So instructions where you need to interact with Python can
2630
call back into Cython code fairly easily.
2631
"""
2632
2633
StackInterpreter.__init__(self, ty_mpfr, mc_retval= MemoryChunkRRRetval('retval', ty_mpfr))
2634
self.name = 'rr'
2635
self.err_return = '0'
2636
self.mc_py_constants = MemoryChunkConstants('py_constants', ty_python)
2637
self.mc_domain = MemoryChunkPyConstant('domain')
2638
self.chunks = [self.mc_args, self.mc_retval, self.mc_constants,
2639
self.mc_py_constants,
2640
self.mc_stack, self.mc_code, self.mc_domain]
2641
pg = params_gen(A=self.mc_args, C=self.mc_constants, D=self.mc_code,
2642
S=self.mc_stack,
2643
P=self.mc_py_constants)
2644
self.pg = pg
2645
self.h_header = """
2646
#include <mpfr.h>
2647
2648
extern int rr_py_call_helper(PyObject*, PyObject*, int, mpfr_t*, mpfr_t*);
2649
"""
2650
self.pxd_header = """
2651
from sage.rings.real_mpfr cimport RealField_class, RealNumber
2652
from sage.libs.mpfr cimport *
2653
"""
2654
self.pyx_header = """
2655
cdef public bint rr_py_call_helper(object domain, object fn,
2656
int n_args,
2657
mpfr_t* args, mpfr_t* retval) except 0:
2658
py_args = []
2659
cdef int i
2660
cdef RealNumber rn
2661
for i from 0 <= i < n_args:
2662
rn = domain()
2663
mpfr_set(rn.value, args[i], GMP_RNDN)
2664
py_args.append(rn)
2665
cdef RealNumber result = domain(fn(*py_args))
2666
mpfr_set(retval[0], result.value, GMP_RNDN)
2667
return 1
2668
2669
"""[1:]
2670
instrs = [
2671
InstrSpec('load_arg', pg('A[D]', 'S'),
2672
code='mpfr_set(o0, i0, GMP_RNDN);'),
2673
InstrSpec('load_const', pg('C[D]', 'S'),
2674
code='mpfr_set(o0, i0, GMP_RNDN);'),
2675
InstrSpec('return', pg('S', ''),
2676
code='mpfr_set(retval[0], i0, GMP_RNDN);\nreturn 1;\n'),
2677
InstrSpec('py_call', pg('P[D]S@D', 'S'),
2678
uses_error_handler=True,
2679
code="""
2680
if (!rr_py_call_helper(domain, i0, n_i1, i1, o0)) {
2681
goto error;
2682
}
2683
""")
2684
]
2685
for (name, op) in [('add', 'mpfr_add'), ('sub', 'mpfr_sub'),
2686
('mul', 'mpfr_mul'), ('div', 'mpfr_div'),
2687
('pow', 'mpfr_pow')]:
2688
instrs.append(instr_funcall_2args_mpfr(name, pg('SS', 'S'), op))
2689
instrs.append(instr_funcall_2args_mpfr('ipow', pg('SD', 'S'), 'mpfr_pow_si'))
2690
for name in ['neg', 'abs',
2691
'log', 'log2', 'log10',
2692
'exp', 'exp2', 'exp10',
2693
'cos', 'sin', 'tan',
2694
'sec', 'csc', 'cot',
2695
'acos', 'asin', 'atan',
2696
'cosh', 'sinh', 'tanh',
2697
'sech', 'csch', 'coth',
2698
'acosh', 'asinh', 'atanh',
2699
'log1p', 'expm1', 'eint',
2700
'gamma', 'lngamma',
2701
'zeta', 'erf', 'erfc',
2702
'j0', 'j1', 'y0', 'y1']:
2703
instrs.append(instr_funcall_1arg_mpfr(name, pg('S', 'S'), 'mpfr_' + name))
2704
# mpfr_ui_div constructs a temporary mpfr_t and then calls mpfr_div;
2705
# it would probably be (slightly) faster to use a permanent copy
2706
# of "one" (on the other hand, the constructed temporary copy is
2707
# on the stack, so it's very likely to be in the cache).
2708
instrs.append(InstrSpec('invert', pg('S', 'S'),
2709
code='mpfr_ui_div(o0, 1, i0, GMP_RNDN);'))
2710
self.instr_descs = instrs
2711
self._set_opcodes()
2712
# Supported for exponents that fit in a long, so we could use
2713
# a much wider range on a 64-bit machine. On the other hand,
2714
# it's easier to write the code this way, and constant integer
2715
# exponents outside this range probably aren't very common anyway.
2716
self.ipow_range = (int(-2**31), int(2**31-1))
2717
2718
class PythonInterpreter(StackInterpreter):
2719
r"""
2720
A subclass of StackInterpreter, specifying an interpreter over
2721
Python objects.
2722
2723
Let's discuss how the reference-counting works in Python-object
2724
based interpreters.
2725
2726
There is a simple rule to remember: when executing the code
2727
snippets, the input variables contain borrowed references;
2728
you must fill in the output variables with references you own.
2729
2730
As an optimization, an instruction may set .handles_own_decref; in
2731
that case, it must decref any input variables that came from the
2732
stack. (Input variables that came from arguments/constants chunks
2733
must NOT be decref'ed!) In addition, with .handles_own_decref, if
2734
any of your input variables are arbitrary-count, then you must
2735
NULL out these variables as you decref them. (Use Py_CLEAR to do
2736
this, unless you understand the documentation of Py_CLEAR and why
2737
it's different than Py_XDECREF followed by assigning NULL.)
2738
2739
Note that as a tiny optimization, the interpreter always assumes
2740
(and ensures) that empty parts of the stack contain NULL, so
2741
it doesn't bother to Py_XDECREF before it pushes onto the stack.
2742
"""
2743
2744
def __init__(self):
2745
r"""
2746
Initialize a PythonInterpreter.
2747
2748
EXAMPLES::
2749
2750
sage: from sage.ext.gen_interpreters import *
2751
sage: interp = PythonInterpreter()
2752
sage: interp.name
2753
'py'
2754
sage: interp.mc_args
2755
{MC:args}
2756
sage: interp.chunks
2757
[{MC:args}, {MC:constants}, {MC:stack}, {MC:code}]
2758
sage: instrs = dict([(ins.name, ins) for ins in interp.instr_descs])
2759
sage: instrs['add']
2760
add: SS->S = 'o0 = PyNumber_Add(i0, i1);'
2761
sage: instrs['py_call']
2762
py_call: *->S = '\nPyObject *py_args...CREF(py_args);\n'
2763
"""
2764
2765
StackInterpreter.__init__(self, ty_python)
2766
self.name = 'py'
2767
# StackInterpreter.__init__ gave us a MemoryChunkArguments.
2768
# Override with MemoryChunkPythonArguments.
2769
self.mc_args = MemoryChunkPythonArguments('args', ty_python)
2770
self.chunks = [self.mc_args, self.mc_constants, self.mc_stack,
2771
self.mc_code]
2772
pg = params_gen(A=self.mc_args, C=self.mc_constants, D=self.mc_code,
2773
S=self.mc_stack)
2774
self.pg = pg
2775
self.h_header = """
2776
#define CHECK(x) (x != NULL)
2777
"""
2778
instrs = [
2779
InstrSpec('load_arg', pg('A[D]', 'S'),
2780
code='o0 = i0; Py_INCREF(o0);'),
2781
InstrSpec('load_const', pg('C[D]', 'S'),
2782
code='o0 = i0; Py_INCREF(o0);'),
2783
InstrSpec('return', pg('S', ''),
2784
code='return i0;',
2785
handles_own_decref=True),
2786
InstrSpec('py_call', pg('C[D]S@D', 'S'),
2787
handles_own_decref=True,
2788
code="""
2789
PyObject *py_args = PyTuple_New(n_i1);
2790
if (py_args == NULL) goto error;
2791
int i;
2792
for (i = 0; i < n_i1; i++) {
2793
PyObject *arg = i1[i];
2794
PyTuple_SET_ITEM(py_args, i, arg);
2795
i1[i] = NULL;
2796
}
2797
o0 = PyObject_CallObject(i0, py_args);
2798
Py_DECREF(py_args);
2799
""")
2800
]
2801
for (name, op) in [('add', 'PyNumber_Add'),
2802
('sub', 'PyNumber_Subtract'),
2803
('mul', 'PyNumber_Multiply'),
2804
('div', 'PyNumber_Divide')]:
2805
instrs.append(instr_funcall_2args(name, pg('SS', 'S'), op))
2806
instrs.append(InstrSpec('pow', pg('SS', 'S'),
2807
code='o0 = PyNumber_Power(i0, i1, Py_None);'))
2808
instrs.append(InstrSpec('ipow', pg('SC[D]', 'S'),
2809
code='o0 = PyNumber_Power(i0, i1, Py_None);'))
2810
for (name, op) in [('neg', 'PyNumber_Negative'),
2811
('invert', 'PyNumber_Invert'),
2812
('abs', 'PyNumber_Absolute')]:
2813
instrs.append(instr_unary(name, pg('S', 'S'), '%s(i0)'%op))
2814
self.instr_descs = instrs
2815
self._set_opcodes()
2816
# Always use ipow
2817
self.ipow_range = True
2818
# We don't yet support call_c for Python-object interpreters
2819
# (the default implementation doesn't work, because of
2820
# object vs. PyObject* confusion)
2821
self.implement_call_c = False
2822
2823
class ElementInterpreter(PythonInterpreter):
2824
r"""
2825
A subclass of PythonInterpreter, specifying an interpreter over
2826
Sage elements with a particular parent.
2827
2828
This is very similar to the PythonInterpreter, but after every
2829
instruction, the result is checked to make sure it actually an
2830
element with the correct parent; if not, we attempt to convert it.
2831
2832
Uses the same instructions (with the same implementation) as
2833
PythonInterpreter.
2834
"""
2835
2836
def __init__(self):
2837
r"""
2838
Initialize an ElementInterpreter.
2839
2840
EXAMPLES::
2841
2842
sage: from sage.ext.gen_interpreters import *
2843
sage: interp = ElementInterpreter()
2844
sage: interp.name
2845
'el'
2846
sage: interp.mc_args
2847
{MC:args}
2848
sage: interp.chunks
2849
[{MC:args}, {MC:constants}, {MC:stack}, {MC:domain}, {MC:code}]
2850
sage: instrs = dict([(ins.name, ins) for ins in interp.instr_descs])
2851
sage: instrs['add']
2852
add: SS->S = 'o0 = PyNumber_Add(i0, i1);'
2853
sage: instrs['py_call']
2854
py_call: *->S = '\nPyObject *py_args...CREF(py_args);\n'
2855
"""
2856
2857
PythonInterpreter.__init__(self)
2858
self.name = 'el'
2859
# PythonInterpreter.__init__ gave us a MemoryChunkPythonArguments.
2860
# Override with MemoryChunkElementArguments.
2861
self.mc_args = MemoryChunkElementArguments('args', ty_python)
2862
self.mc_domain_info = MemoryChunkPyConstant('domain')
2863
self.chunks = [self.mc_args, self.mc_constants, self.mc_stack,
2864
self.mc_domain_info, self.mc_code]
2865
self.h_header = """
2866
extern PyObject* el_check_element(PyObject*, PyObject*);
2867
2868
#define CHECK(x) do_check(&(x), domain)
2869
2870
static inline int do_check(PyObject **x, PyObject *domain) {
2871
if (*x == NULL) return 0;
2872
PyObject *new_x = el_check_element(*x, domain);
2873
Py_DECREF(*x);
2874
*x = new_x;
2875
if (*x == NULL) return 0;
2876
return 1;
2877
}
2878
"""
2879
self.pyx_header = """
2880
from sage.structure.element cimport Element
2881
2882
cdef public object el_check_element(object v, parent):
2883
cdef Element v_el
2884
2885
if PY_TYPE_CHECK(v, Element):
2886
v_el = <Element>v
2887
if v_el._parent is parent:
2888
return v_el
2889
2890
return parent(v)
2891
2892
"""[1:]
2893
2894
class InterpreterGenerator(object):
2895
r"""
2896
This class takes an InterpreterSpec and generates the corresponding
2897
C interpreter and Cython wrapper.
2898
2899
See the documentation for methods get_wrapper and get_interpreter
2900
for more information.
2901
"""
2902
2903
def __init__(self, spec):
2904
r"""
2905
Initialize an InterpreterGenerator.
2906
2907
INPUTS:
2908
spec -- an InterpreterSpec
2909
2910
EXAMPLES::
2911
2912
sage: from sage.ext.gen_interpreters import *
2913
sage: interp = RDFInterpreter()
2914
sage: gen = InterpreterGenerator(interp)
2915
sage: gen._spec is interp
2916
True
2917
sage: gen.uses_error_handler
2918
False
2919
"""
2920
2921
self._spec = spec
2922
self.uses_error_handler = False
2923
2924
def gen_code(self, instr_desc, write):
2925
r"""
2926
Generates code for a single instruction.
2927
2928
INPUTS:
2929
instr_desc -- an InstrSpec
2930
write -- a Python callable
2931
2932
This function calls its write parameter successively with
2933
strings; when these strings are concatenated, the result is
2934
the code for the given instruction.
2935
2936
See the documentation for the get_interpreter method for more
2937
information.
2938
2939
EXAMPLES::
2940
2941
sage: from sage.ext.gen_interpreters import *
2942
sage: interp = RDFInterpreter()
2943
sage: gen = InterpreterGenerator(interp)
2944
sage: import cStringIO
2945
sage: buff = cStringIO.StringIO()
2946
sage: instrs = dict([(ins.name, ins) for ins in interp.instr_descs])
2947
sage: gen.gen_code(instrs['div'], buff.write)
2948
sage: print buff.getvalue()
2949
case 8: /* div */
2950
{
2951
double i1 = *--stack;
2952
double i0 = *--stack;
2953
double o0;
2954
o0 = i0 / i1;
2955
*stack++ = o0;
2956
}
2957
break;
2958
<BLANKLINE>
2959
"""
2960
2961
d = instr_desc
2962
w = write
2963
s = self._spec
2964
2965
if d.uses_error_handler:
2966
self.uses_error_handler = True
2967
2968
w(je("""
2969
case {{ d.opcode }}: /* {{ d.name }} */
2970
{
2971
""", d=d))
2972
2973
# If the inputs to an instruction come from the stack,
2974
# then we want to generate code for the inputs in reverse order:
2975
# for instance, the divide instruction, which takes inputs A and B
2976
# and generates A/B, needs to pop B off the stack first.
2977
# On the other hand, if the inputs come from the constant pool,
2978
# then we want to generate code for the inputs in normal order,
2979
# because the addresses in the code stream will be in that order.
2980
# We handle this by running through the inputs in two passes:
2981
# first a forward pass, where we handle non-stack inputs
2982
# (and lengths for stack inputs), and then a reverse pass,
2983
# where we handle stack inputs.
2984
for i in range(len(d.inputs)):
2985
(ch, addr, input_len) = d.inputs[i]
2986
chst = ch.storage_type
2987
if addr is not None:
2988
w(" int ai%d = %s;\n" % (i, string_of_addr(addr)))
2989
if input_len is not None:
2990
w(" int n_i%d = %s;\n" % (i, string_of_addr(input_len)))
2991
if not ch.is_stack():
2992
# Shouldn't hardcode 'code' here
2993
if ch.name == 'code':
2994
w(" %s i%d = %s;\n" % (chst.c_local_type(), i, string_of_addr(ch)))
2995
elif input_len is not None:
2996
w(" %s i%d = %s + ai%d;\n" %
2997
(chst.c_ptr_type(), i, ch.name, i))
2998
else:
2999
w(" %s i%d = %s[ai%d];\n" %
3000
(chst.c_local_type(), i, ch.name, i))
3001
3002
for i in reversed(range(len(d.inputs))):
3003
(ch, addr, input_len) = d.inputs[i]
3004
chst = ch.storage_type
3005
if ch.is_stack():
3006
if input_len is not None:
3007
w(" %s -= n_i%d;\n" % (ch.name, i))
3008
w(" %s i%d = %s;\n" % (chst.c_ptr_type(), i, ch.name))
3009
else:
3010
w(" %s i%d = *--%s;\n" % (chst.c_local_type(), i, ch.name))
3011
if ch.is_python_refcounted_stack():
3012
w(" *%s = NULL;\n" % ch.name)
3013
3014
for i in range(len(d.outputs)):
3015
(ch, addr, output_len) = d.outputs[i]
3016
chst = ch.storage_type
3017
if addr is not None:
3018
w(" int ao%d = %s;\n" % (i, string_of_addr(addr)))
3019
if output_len is not None:
3020
w(" int n_o%d = %s;\n" % (i, string_of_addr(output_len)))
3021
if ch.is_stack():
3022
w(" %s o%d = %s;\n" %
3023
(chst.c_ptr_type(), i, ch.name))
3024
w(" %s += n_o%d;\n" % (ch.name, i))
3025
else:
3026
w(" %s o%d = %s + ao%d;\n" %
3027
(chst.c_ptr_type(), i, ch.name, i))
3028
else:
3029
if not chst.cheap_copies():
3030
if ch.is_stack():
3031
w(" %s o%d = *%s++;\n" %
3032
(chst.c_local_type(), i, ch.name))
3033
else:
3034
w(" %s o%d = %s[ao%d];\n" %
3035
(chst.c_local_type(), i, ch.name, i))
3036
else:
3037
w(" %s o%d;\n" % (chst.c_local_type(), i))
3038
w(indent_lines(8, d.code.rstrip('\n') + '\n'))
3039
3040
stack_offsets = defaultdict(int)
3041
for i in range(len(d.inputs)):
3042
(ch, addr, input_len) = d.inputs[i]
3043
chst = ch.storage_type
3044
if ch.is_python_refcounted_stack() and not d.handles_own_decref:
3045
if input_len is None:
3046
w(" Py_DECREF(i%d);\n" % i)
3047
stack_offsets[ch] += 1
3048
else:
3049
w(je("""
3050
int {{ iter }};
3051
for ({{ iter }} = 0; {{ iter }} < n_i{{ i }}; {{ iter }}++) {
3052
Py_CLEAR(i{{ i }}[{{ iter }}]);
3053
}
3054
""", iter='_interp_iter_%d' % i, i=i))
3055
3056
for i in range(len(d.outputs)):
3057
ch = d.outputs[i][0]
3058
chst = ch.storage_type
3059
if chst.python_refcounted():
3060
# We don't yet support code chunks
3061
# that produce multiple Python values, because of
3062
# the way it complicates error handling.
3063
assert i == 0
3064
w(" if (!CHECK(o%d)) {\n" % i)
3065
w(" Py_XDECREF(o%d);\n" % i)
3066
w(" goto error;\n")
3067
w(" }\n")
3068
self.uses_error_handler = True
3069
if chst.cheap_copies():
3070
if ch.is_stack():
3071
w(" *%s++ = o%d;\n" % (ch.name, i))
3072
else:
3073
w(" %s[ao%d] = o%d;\n" % (ch.name, i, i))
3074
3075
w(je("""
3076
}
3077
break;
3078
"""))
3079
3080
def func_header(self, cython=False):
3081
r"""
3082
Generates the function header for the declaration (in the Cython
3083
wrapper) or the definition (in the C interpreter) of the interpreter
3084
function.
3085
3086
EXAMPLES::
3087
3088
sage: from sage.ext.gen_interpreters import *
3089
sage: interp = ElementInterpreter()
3090
sage: gen = InterpreterGenerator(interp)
3091
sage: print gen.func_header()
3092
PyObject* interp_el(PyObject** args,
3093
PyObject** constants,
3094
PyObject** stack,
3095
PyObject* domain,
3096
int* code)
3097
sage: print gen.func_header(cython=True)
3098
object interp_el(PyObject** args,
3099
PyObject** constants,
3100
PyObject** stack,
3101
PyObject* domain,
3102
int* code)
3103
"""
3104
s = self._spec
3105
ret_ty = 'bint' if cython else 'int'
3106
if s.return_type:
3107
ret_ty = s.return_type.c_decl_type()
3108
if cython:
3109
ret_ty = s.return_type.cython_decl_type()
3110
return je("""{{ ret_ty }} interp_{{ s.name }}(
3111
{%- for ch in s.chunks %}
3112
{% if not loop.first %},
3113
{% endif %}{{ ch.declare_parameter() }}
3114
{%- endfor %})""", ret_ty=ret_ty, s=s)
3115
3116
def write_interpreter_header(self, write):
3117
r"""
3118
Generate the header code for the C interpreter.
3119
3120
EXAMPLES::
3121
3122
sage: from sage.ext.gen_interpreters import *
3123
sage: interp = RDFInterpreter()
3124
sage: gen = InterpreterGenerator(interp)
3125
sage: import cStringIO
3126
sage: buff = cStringIO.StringIO()
3127
sage: gen.write_interpreter_header(buff.write)
3128
sage: print buff.getvalue()
3129
/* Automatically generated by ext/gen_interpreters.py. Do not edit! */ ...
3130
"""
3131
s = self._spec
3132
w = write
3133
w(je("""
3134
/* Automatically generated by ext/gen_interpreters.py. Do not edit! */
3135
#include <Python.h>
3136
{% print s.h_header %}
3137
3138
{{ myself.func_header() }};
3139
""", s=s, i=indent_lines, myself=self))
3140
3141
def write_interpreter(self, write):
3142
r"""
3143
Generate the code for the C interpreter.
3144
3145
This function calls its write parameter successively with
3146
strings; when these strings are concatenated, the result is
3147
the code for the interpreter.
3148
3149
See the documentation for the get_interpreter method for more
3150
information.
3151
3152
EXAMPLES::
3153
3154
sage: from sage.ext.gen_interpreters import *
3155
sage: interp = RDFInterpreter()
3156
sage: gen = InterpreterGenerator(interp)
3157
sage: import cStringIO
3158
sage: buff = cStringIO.StringIO()
3159
sage: gen.write_interpreter(buff.write)
3160
sage: print buff.getvalue()
3161
/* Automatically generated by ext/gen_interpreters.py. Do not edit! */ ...
3162
"""
3163
s = self._spec
3164
w = write
3165
w(je("""
3166
/* Automatically generated by ext/gen_interpreters.py. Do not edit! */
3167
#include "interp_{{ s.name }}.h"
3168
{% print s.c_header %}
3169
3170
{{ myself.func_header() }} {
3171
while (1) {
3172
switch (*code++) {
3173
""", s=s, myself=self, i=indent_lines))
3174
for instr_desc in s.instr_descs:
3175
self.gen_code(instr_desc, w)
3176
w(je("""
3177
}
3178
}
3179
{% if myself.uses_error_handler %}
3180
error:
3181
return {{ s.err_return }};
3182
{% endif %}
3183
}
3184
3185
""", s=s, i=indent_lines, myself=self))
3186
3187
def write_wrapper(self, write):
3188
r"""
3189
Generate the code for the Cython wrapper.
3190
This function calls its write parameter successively with
3191
strings; when these strings are concatenated, the result is
3192
the code for the wrapper.
3193
3194
See the documentation for the get_wrapper method for more
3195
information.
3196
3197
EXAMPLES::
3198
3199
sage: from sage.ext.gen_interpreters import *
3200
sage: interp = RDFInterpreter()
3201
sage: gen = InterpreterGenerator(interp)
3202
sage: import cStringIO
3203
sage: buff = cStringIO.StringIO()
3204
sage: gen.write_wrapper(buff.write)
3205
sage: print buff.getvalue()
3206
# Automatically generated by ext/gen_interpreters.py. Do not edit! ...
3207
"""
3208
s = self._spec
3209
w = write
3210
types = set()
3211
do_cleanup = False
3212
for ch in s.chunks:
3213
if ch.storage_type is not None:
3214
types.add(ch.storage_type)
3215
do_cleanup = do_cleanup or ch.needs_cleanup_on_error()
3216
for ch in s.chunks:
3217
if ch.name == 'args':
3218
arg_ch = ch
3219
3220
the_call = je("""
3221
{% if s.return_type %}return {% endif -%}
3222
{% if s.adjust_retval %}{{ s.adjust_retval }}({% endif %}
3223
interp_{{ s.name }}({{ arg_ch.pass_argument() }}
3224
{% for ch in s.chunks[1:] %}
3225
, {{ ch.pass_argument() }}
3226
{% endfor %}
3227
){% if s.adjust_retval %}){% endif %}
3228
3229
""", s=s, arg_ch=arg_ch)
3230
3231
the_call_c = je("""
3232
{% if s.return_type %}result[0] = {% endif %}
3233
interp_{{ s.name }}(args
3234
{% for ch in s.chunks[1:] %}
3235
, {{ ch.pass_call_c_argument() }}
3236
{% endfor %}
3237
)
3238
3239
""", s=s, arg_ch=arg_ch)
3240
3241
w(je("""
3242
# Automatically generated by ext/gen_interpreters.py. Do not edit!
3243
3244
include "sage/ext/stdsage.pxi"
3245
from cpython cimport PyObject
3246
cdef extern from "Python.h":
3247
void Py_DECREF(PyObject *o)
3248
void Py_INCREF(PyObject *o)
3249
void Py_CLEAR(PyObject *o)
3250
3251
cdef extern from "listobject.h":
3252
object PyList_New(Py_ssize_t len)
3253
ctypedef struct PyListObject:
3254
PyObject **ob_item
3255
3256
cdef extern from "tupleobject.h":
3257
ctypedef struct PyTupleObject:
3258
PyObject **ob_item
3259
3260
from sage.ext.fast_callable cimport Wrapper
3261
{% print s.pyx_header %}
3262
3263
cdef extern from "interp_{{ s.name }}.h":
3264
{{ myself.func_header(cython=true) -}}
3265
{% if s.err_return != 'NULL' %}
3266
except? {{ s.err_return }}
3267
{% endif %}
3268
3269
cdef class Wrapper_{{ s.name }}(Wrapper):
3270
# attributes are declared in corresponding .pxd file
3271
3272
def __init__(self, args):
3273
Wrapper.__init__(self, args, metadata)
3274
cdef int i
3275
cdef int count
3276
{% for ty in types %}
3277
{% print indent_lines(8, ty.local_declarations) %}
3278
{% print indent_lines(8, ty.class_member_initializations) %}
3279
{% endfor %}
3280
{% for ch in s.chunks %}
3281
{% print ch.init_class_members() %}
3282
{% endfor %}
3283
{% print indent_lines(8, s.extra_members_initialize) %}
3284
3285
def __dealloc__(self):
3286
cdef int i
3287
{% for ch in s.chunks %}
3288
{% print ch.dealloc_class_members() %}
3289
{% endfor %}
3290
3291
def __call__(self, *args):
3292
if self._n_args != len(args): raise ValueError
3293
{% for ty in types %}
3294
{% print indent_lines(8, ty.local_declarations) %}
3295
{% endfor %}
3296
{% print indent_lines(8, arg_ch.setup_args()) %}
3297
{% for ch in s.chunks %}
3298
{% print ch.declare_call_locals() %}
3299
{% endfor %}
3300
{% if do_cleanup %}
3301
try:
3302
{% print indent_lines(4, the_call) %}
3303
except BaseException:
3304
{% for ch in s.chunks %}
3305
{% if ch.needs_cleanup_on_error() %}
3306
{% print indent_lines(12, ch.handle_cleanup()) %}
3307
{% endif %}
3308
{% endfor %}
3309
raise
3310
{% else %}
3311
{% print the_call %}
3312
{% endif %}
3313
{% if not s.return_type %}
3314
return retval
3315
{% endif %}
3316
3317
{% if s.implement_call_c %}
3318
cdef bint call_c(self,
3319
{{ arg_ch.storage_type.c_ptr_type() }} args,
3320
{{ arg_ch.storage_type.c_ptr_type() }} result) except 0:
3321
{% if do_cleanup %}
3322
try:
3323
{% print indent_lines(4, the_call_c) %}
3324
except BaseException:
3325
{% for ch in s.chunks %}
3326
{% if ch.needs_cleanup_on_error() %}
3327
{% print indent_lines(12, ch.handle_cleanup()) %}
3328
{% endif %}
3329
{% endfor %}
3330
raise
3331
{% else %}
3332
{% print the_call_c %}
3333
{% endif %}
3334
return 1
3335
{% endif %}
3336
3337
from sage.ext.fast_callable import CompilerInstrSpec, InterpreterMetadata
3338
metadata = InterpreterMetadata(by_opname={
3339
{% for instr in s.instr_descs %}
3340
'{{ instr.name }}':
3341
(CompilerInstrSpec({{ instr.n_inputs }}, {{ instr.n_outputs }}, {{ instr.parameters }}), {{ instr.opcode }}),
3342
{% endfor %}
3343
},
3344
by_opcode=[
3345
{% for instr in s.instr_descs %}
3346
('{{ instr.name }}',
3347
CompilerInstrSpec({{ instr.n_inputs }}, {{ instr.n_outputs }}, {{ instr.parameters }})),
3348
{% endfor %}
3349
],
3350
ipow_range={{ s.ipow_range }})
3351
""", s=s, myself=self, types=types, arg_ch=arg_ch, indent_lines=indent_lines, the_call=the_call, the_call_c=the_call_c, do_cleanup=do_cleanup))
3352
3353
def write_pxd(self, write):
3354
r"""
3355
Generate the pxd file for the Cython wrapper.
3356
This function calls its write parameter successively with
3357
strings; when these strings are concatenated, the result is
3358
the code for the pxd file.
3359
3360
See the documentation for the get_pxd method for more
3361
information.
3362
3363
EXAMPLES::
3364
3365
sage: from sage.ext.gen_interpreters import *
3366
sage: interp = RDFInterpreter()
3367
sage: gen = InterpreterGenerator(interp)
3368
sage: import cStringIO
3369
sage: buff = cStringIO.StringIO()
3370
sage: gen.write_pxd(buff.write)
3371
sage: print buff.getvalue()
3372
# Automatically generated by ext/gen_interpreters.py. Do not edit! ...
3373
"""
3374
s = self._spec
3375
w = write
3376
types = set()
3377
for ch in s.chunks:
3378
if ch.storage_type is not None:
3379
types.add(ch.storage_type)
3380
for ch in s.chunks:
3381
if ch.name == 'args':
3382
arg_ch = ch
3383
3384
w(je("""
3385
# Automatically generated by ext/gen_interpreters.py. Do not edit!
3386
3387
from cpython cimport PyObject
3388
3389
from sage.ext.fast_callable cimport Wrapper
3390
{% print s.pxd_header %}
3391
3392
cdef class Wrapper_{{ s.name }}(Wrapper):
3393
{% for ty in types %}
3394
{% print indent_lines(4, ty.class_member_declarations) %}
3395
{% endfor %}
3396
{% for ch in s.chunks %}
3397
{% print ch.declare_class_members() %}
3398
{% endfor %}
3399
{% print indent_lines(4, s.extra_class_members) %}
3400
{% if s.implement_call_c %}
3401
cdef bint call_c(self,
3402
{{ arg_ch.storage_type.c_ptr_type() }} args,
3403
{{ arg_ch.storage_type.c_ptr_type() }} result) except 0
3404
{% endif %}
3405
""", s=s, myself=self, types=types, indent_lines=indent_lines, arg_ch=arg_ch))
3406
3407
def get_interpreter_header(self):
3408
r"""
3409
Returns the header code for the C interpreter.
3410
3411
EXAMPLES:
3412
3413
First we get the InterpreterSpec for several interpreters::
3414
3415
sage: from sage.ext.gen_interpreters import *
3416
sage: rdf_spec = RDFInterpreter()
3417
sage: rr_spec = RRInterpreter()
3418
sage: cdf_spec = CDFInterpreter()
3419
sage: el_spec = ElementInterpreter()
3420
3421
Then we get the actual interpreter code::
3422
3423
sage: rdf_interp_h = InterpreterGenerator(rdf_spec).get_interpreter_header()
3424
sage: rr_interp_h = InterpreterGenerator(rr_spec).get_interpreter_header()
3425
sage: cdf_interp_h = InterpreterGenerator(cdf_spec).get_interpreter_header()
3426
sage: el_interp_h = InterpreterGenerator(el_spec).get_interpreter_header()
3427
3428
Each interpreter starts with a file header; this can be
3429
customized on a per-interpreter basis::
3430
3431
sage: print rdf_interp_h
3432
/* Automatically generated by ext/gen_interpreters.py. Do not edit! */
3433
#include <Python.h>
3434
<BLANKLINE>
3435
#include <gsl/gsl_math.h>
3436
...
3437
sage: print rr_interp_h
3438
/* Automatically generated by ext/gen_interpreters.py. Do not edit! */
3439
#include <Python.h>
3440
<BLANKLINE>
3441
#include <mpfr.h>
3442
...
3443
sage: print cdf_interp_h
3444
/* Automatically generated by ext/gen_interpreters.py. Do not edit! */
3445
#include <Python.h>
3446
<BLANKLINE>
3447
#include <stdlib.h>
3448
#include <complex.h>
3449
...
3450
sage: print el_interp_h
3451
/* Automatically generated by ext/gen_interpreters.py. Do not edit! */
3452
#include <Python.h>
3453
<BLANKLINE>
3454
extern PyObject* el_check_element(PyObject*, PyObject*);
3455
<BLANKLINE>
3456
#define CHECK(x) do_check(&(x), domain)
3457
...
3458
"""
3459
import cStringIO
3460
buff = cStringIO.StringIO()
3461
self.write_interpreter_header(buff.write)
3462
return buff.getvalue()
3463
3464
def get_interpreter(self):
3465
r"""
3466
Returns the code for the C interpreter.
3467
3468
EXAMPLES:
3469
3470
First we get the InterpreterSpec for several interpreters::
3471
3472
sage: from sage.ext.gen_interpreters import *
3473
sage: rdf_spec = RDFInterpreter()
3474
sage: rr_spec = RRInterpreter()
3475
sage: el_spec = ElementInterpreter()
3476
3477
Then we get the actual interpreter code::
3478
3479
sage: rdf_interp = InterpreterGenerator(rdf_spec).get_interpreter()
3480
sage: rr_interp = InterpreterGenerator(rr_spec).get_interpreter()
3481
sage: el_interp = InterpreterGenerator(el_spec).get_interpreter()
3482
3483
Now we can look through these interpreters.
3484
3485
Each interpreter starts with a file header; this can be
3486
customized on a per-interpreter basis::
3487
3488
sage: print rr_interp
3489
/* Automatically generated by ext/gen_interpreters.py. Do not edit! */
3490
#include "interp_rr.h"
3491
...
3492
3493
Next is the function header, with one argument per memory chunk
3494
in the interpreter spec::
3495
3496
sage: print el_interp
3497
/* ... */ ...
3498
PyObject* interp_el(PyObject** args,
3499
PyObject** constants,
3500
PyObject** stack,
3501
PyObject* domain,
3502
int* code) {
3503
...
3504
3505
Currently, the interpreters have a very simple structure; just
3506
grab the next instruction and execute it, in a switch
3507
statement::
3508
3509
sage: print rdf_interp
3510
/* ... */ ...
3511
while (1) {
3512
switch (*code++) {
3513
...
3514
3515
Then comes the code for each instruction. Here is one of the
3516
simplest instructions::
3517
3518
sage: print rdf_interp
3519
/* ... */ ...
3520
case 10: /* neg */
3521
{
3522
double i0 = *--stack;
3523
double o0;
3524
o0 = -i0;
3525
*stack++ = o0;
3526
}
3527
break;
3528
...
3529
3530
We simply pull the top of the stack into a variable, negate it,
3531
and write the result back onto the stack.
3532
3533
Let's look at the MPFR-based version of this instruction.
3534
This is an example of an interpreter with an auto-reference
3535
type::
3536
3537
sage: print rr_interp
3538
/* ... */ ...
3539
case 10: /* neg */
3540
{
3541
mpfr_ptr i0 = *--stack;
3542
mpfr_ptr o0 = *stack++;
3543
mpfr_neg(o0, i0, GMP_RNDN);
3544
}
3545
break;
3546
...
3547
3548
Here we see that the input and output variables are actually
3549
just pointers into the stack. But due to the auto-reference
3550
trick, the actual code snippet, ``mpfr_net(o0, i0, GMP_RNDN);``,
3551
is exactly the same as if i0 and o0 were declared as local
3552
mpfr_t variables.
3553
3554
For completeness, let's look at this instruction in the
3555
Python-object element interpreter::
3556
3557
sage: print el_interp
3558
/* ... */ ...
3559
case 10: /* neg */
3560
{
3561
PyObject* i0 = *--stack;
3562
*stack = NULL;
3563
PyObject* o0;
3564
o0 = PyNumber_Negative(i0);
3565
Py_DECREF(i0);
3566
if (!CHECK(o0)) {
3567
Py_XDECREF(o0);
3568
goto error;
3569
}
3570
*stack++ = o0;
3571
}
3572
break;
3573
...
3574
3575
The original code snippet was only ``o0 = PyNumber_Negative(i0);``;
3576
all the rest is automatically generated. For ElementInterpreter,
3577
the CHECK macro actually checks for an exception (makes sure that
3578
o0 is not NULL), tests if the o0 is an element with the correct
3579
parent, and if not converts it into the correct parent. (That is,
3580
it can potentially modify the variable o0.)
3581
"""
3582
import cStringIO
3583
buff = cStringIO.StringIO()
3584
self.write_interpreter(buff.write)
3585
return buff.getvalue()
3586
3587
def get_wrapper(self):
3588
r"""
3589
Returns the code for the Cython wrapper.
3590
3591
EXAMPLES:
3592
3593
First we get the InterpreterSpec for several interpreters::
3594
3595
sage: from sage.ext.gen_interpreters import *
3596
sage: rdf_spec = RDFInterpreter()
3597
sage: rr_spec = RRInterpreter()
3598
sage: el_spec = ElementInterpreter()
3599
3600
Then we get the actual wrapper code::
3601
3602
sage: rdf_wrapper = InterpreterGenerator(rdf_spec).get_wrapper()
3603
sage: rr_wrapper = InterpreterGenerator(rr_spec).get_wrapper()
3604
sage: el_wrapper = InterpreterGenerator(el_spec).get_wrapper()
3605
3606
Now we can look through these wrappers.
3607
3608
Each wrapper starts with a file header; this can be
3609
customized on a per-interpreter basis (some blank lines have been
3610
elided below)::
3611
3612
sage: print rdf_wrapper
3613
# Automatically generated by ext/gen_interpreters.py. Do not edit!
3614
include "sage/ext/stdsage.pxi"
3615
from cpython cimport PyObject
3616
cdef extern from "Python.h":
3617
void Py_DECREF(PyObject *o)
3618
void Py_INCREF(PyObject *o)
3619
void Py_CLEAR(PyObject *o)
3620
cdef extern from "listobject.h":
3621
object PyList_New(Py_ssize_t len)
3622
ctypedef struct PyListObject:
3623
PyObject **ob_item
3624
cdef extern from "tupleobject.h":
3625
ctypedef struct PyTupleObject:
3626
PyObject **ob_item
3627
from sage.ext.fast_callable cimport Wrapper
3628
...
3629
3630
Next is the declaration of the C interpreter function::
3631
3632
sage: print rdf_wrapper
3633
# ...
3634
cdef extern from "interp_rdf.h":
3635
double interp_rdf(double* args,
3636
double* constants,
3637
PyObject** py_constants,
3638
double* stack,
3639
int* code) except? -1094648009105371
3640
...
3641
3642
We need a way to propagate exceptions back to the wrapper,
3643
even though we only return a double from interp_rdf. The
3644
``except? -1094648009105371`` (that's a randomly chosen
3645
number) means that we will return that number if there's an
3646
exception, but the wrapper still has to check whether that's a
3647
legitimate return or an exception. (Cython does this
3648
automatically.)
3649
3650
Next comes the actual wrapper class. The member declarations
3651
are in the corresponding pxd file; see the documentation for
3652
get_pxd to see them::
3653
3654
sage: print rdf_wrapper
3655
# ...
3656
cdef class Wrapper_rdf(Wrapper):
3657
# attributes are declared in corresponding .pxd file
3658
...
3659
3660
Next is the __init__ method, which starts like this::
3661
3662
sage: print rdf_wrapper
3663
# ...
3664
def __init__(self, args):
3665
Wrapper.__init__(self, args, metadata)
3666
cdef int i
3667
cdef int count
3668
...
3669
3670
To make it possible to generate code for all expression
3671
interpreters with a single code generator, all wrappers
3672
have the same API. The __init__ method takes a single
3673
argument (here called *args*), which is a dictionary holding
3674
all the information needed to initialize this wrapper.
3675
3676
We call Wrapper.__init__, which saves a copy of this arguments
3677
object and of the interpreter metadata in the wrapper. (This is
3678
only used for debugging.)
3679
3680
Now we allocate memory for each memory chunk. (We allocate
3681
the memory here, and reuse it on each call of the
3682
wrapper/interpreter. This is for speed reasons; in a fast
3683
interpreter like RDFInterpreter, there are no memory allocations
3684
involved in a call of the wrapper, except for the ones that
3685
are required by the Python calling convention. Eventually
3686
we will support alternate Cython-only entry points that do
3687
absolutely no memory allocation.)
3688
3689
Basically the same code is repeated, with minor variations, for
3690
each memory chunk; for brevity, we'll only show the code
3691
for 'constants'::
3692
3693
sage: print rdf_wrapper
3694
# ...
3695
val = args['constants']
3696
self._n_constants = len(val)
3697
self._constants = <double*>sage_malloc(sizeof(double) * len(val))
3698
if self._constants == NULL: raise MemoryError
3699
for i in range(len(val)):
3700
self._constants[i] = val[i]
3701
...
3702
3703
Recall that _n_constants is an int, and _constants is a
3704
double*.
3705
3706
The RRInterpreter version is more complicated, because it has to
3707
call mpfr_init::
3708
3709
sage: print rr_wrapper
3710
# ...
3711
cdef RealNumber rn
3712
...
3713
val = args['constants']
3714
self._n_constants = len(val)
3715
self._constants = <mpfr_t*>sage_malloc(sizeof(mpfr_t) * len(val))
3716
if self._constants == NULL: raise MemoryError
3717
for i in range(len(val)):
3718
mpfr_init2(self._constants[i], self.domain.prec())
3719
for i in range(len(val)):
3720
rn = self.domain(val[i])
3721
mpfr_set(self._constants[i], rn.value, GMP_RNDN)
3722
...
3723
3724
And as described in the documentation for get_pxd, in
3725
Python-object based interpreters we actually allocate the
3726
memory as a Python list::
3727
3728
sage: print el_wrapper
3729
# ...
3730
val = args['constants']
3731
self._n_constants = len(val)
3732
self._list_constants = PyList_New(self._n_constants)
3733
self._constants = (<PyListObject *>self._list_constants).ob_item
3734
for i in range(len(val)):
3735
self._constants[i] = <PyObject *>val[i]; Py_INCREF(self._constants[i])
3736
...
3737
3738
Of course, once we've allocated the memory, we eventually have
3739
to free it. (Again, we'll only look at 'constants'.)::
3740
3741
sage: print rdf_wrapper
3742
# ...
3743
def __dealloc__(self):
3744
...
3745
if self._constants:
3746
sage_free(self._constants)
3747
...
3748
3749
The RRInterpreter code is more complicated again because it has
3750
to call mpfr_clear::
3751
3752
sage: print rr_wrapper
3753
# ...
3754
def __dealloc__(self):
3755
cdef int i
3756
...
3757
if self._constants:
3758
for i in range(self._n_constants):
3759
mpfr_clear(self._constants[i])
3760
sage_free(self._constants)
3761
...
3762
3763
But the ElementInterpreter code is extremely simple --
3764
it doesn't have to do anything to deallocate constants!
3765
(Since the memory for constants is actually allocated as a
3766
Python list, and Cython knows how to deallocate Python lists.)
3767
3768
Finally we get to the __call__ method. We grab the arguments
3769
passed by the caller, stuff them in our pre-allocated
3770
argument array, and then call the C interpreter.
3771
3772
We optionally adjust the return value of the interpreter
3773
(currently only the RDF/float interpreter performs this step;
3774
this is the only place where domain=RDF differs than
3775
domain=float)::
3776
3777
sage: print rdf_wrapper
3778
# ...
3779
def __call__(self, *args):
3780
if self._n_args != len(args): raise ValueError
3781
cdef double* c_args = self._args
3782
cdef int i
3783
for i from 0 <= i < len(args):
3784
self._args[i] = args[i]
3785
return self._domain(interp_rdf(c_args
3786
, self._constants
3787
, self._py_constants
3788
, self._stack
3789
, self._code
3790
))
3791
...
3792
3793
In Python-object based interpreters, the call to the C
3794
interpreter has to be a little more complicated. We don't
3795
want to hold on to Python objects from an old computation by
3796
leaving them referenced from the stack. In normal operation,
3797
the C interpreter clears out the stack as it runs, leaving the
3798
stack totally clear when the interpreter finishes. However,
3799
this doesn't happen if the C interpreter raises an exception.
3800
In that case, we have to clear out any remnants from the stack
3801
in the wrapper::
3802
3803
sage: print el_wrapper
3804
# ...
3805
try:
3806
return interp_el((<PyListObject*>mapped_args).ob_item
3807
, self._constants
3808
, self._stack
3809
, <PyObject*>self._domain
3810
, self._code
3811
)
3812
except BaseException:
3813
for i in range(self._n_stack):
3814
Py_CLEAR(self._stack[i])
3815
raise
3816
...
3817
3818
Finally, we define a cdef call_c method, for quickly calling
3819
this object from Cython. (The method is omitted from
3820
Python-object based interpreters.)::
3821
sage: print rdf_wrapper
3822
# ...
3823
cdef bint call_c(self,
3824
double* args,
3825
double* result) except 0:
3826
result[0] = interp_rdf(args
3827
, self._constants
3828
, self._py_constants
3829
, self._stack
3830
, self._code
3831
)
3832
return 1
3833
...
3834
3835
The method for the RR interpreter is slightly different, because
3836
the interpreter takes a pointer to a result location instead of
3837
returning the value::
3838
3839
sage: print rr_wrapper
3840
# ...
3841
cdef bint call_c(self,
3842
mpfr_t* args,
3843
mpfr_t* result) except 0:
3844
interp_rr(args
3845
, result
3846
, self._constants
3847
, self._py_constants
3848
, self._stack
3849
, self._code
3850
, <PyObject*>self._domain
3851
)
3852
return 1
3853
...
3854
3855
That's it for the wrapper class. The only thing remaining is
3856
the interpreter metadata. This is the information necessary
3857
for the code generator to map instruction names to opcodes; it
3858
also gives information about stack usage, etc. This is fully
3859
documented at InterpreterMetadata; for now, we'll just show
3860
what it looks like.
3861
3862
Currently, there are three parts to the metadata; the first maps
3863
instruction names to instruction descriptions. The second one
3864
maps opcodes to instruction descriptions. Note that we don't
3865
use InstrSpec objects here; instead, we use CompilerInstrSpec
3866
objects, which are much simpler and contain only the information
3867
we'll need at runtime. The third part says what range the
3868
ipow instruction is defined over.
3869
3870
First the part that maps instruction names to
3871
(CompilerInstrSpec, opcode) pairs::
3872
3873
sage: print rdf_wrapper
3874
# ...
3875
from sage.ext.fast_callable import CompilerInstrSpec, InterpreterMetadata
3876
metadata = InterpreterMetadata(by_opname={
3877
...
3878
'return':
3879
(CompilerInstrSpec(1, 0, []), 2),
3880
'py_call':
3881
(CompilerInstrSpec(0, 1, ['py_constants', 'n_inputs']), 3),
3882
'pow':
3883
(CompilerInstrSpec(2, 1, []), 4),
3884
'add':
3885
(CompilerInstrSpec(2, 1, []), 5),
3886
...
3887
}, ...)
3888
3889
There's also a table that maps opcodes to (instruction name,
3890
CompilerInstrSpec) pairs::
3891
3892
sage: print rdf_wrapper
3893
# ...
3894
metadata = InterpreterMetadata(..., by_opcode=[
3895
...
3896
('return',
3897
CompilerInstrSpec(1, 0, [])),
3898
('py_call',
3899
CompilerInstrSpec(0, 1, ['py_constants', 'n_inputs'])),
3900
('pow',
3901
CompilerInstrSpec(2, 1, [])),
3902
('add',
3903
CompilerInstrSpec(2, 1, [])),
3904
...
3905
], ...)
3906
3907
And then the ipow range::
3908
3909
sage: print rdf_wrapper
3910
# ...
3911
metadata = InterpreterMetadata(...,
3912
ipow_range=(-2147483648, 2147483647))
3913
3914
And that's it for the wrapper.
3915
"""
3916
import cStringIO
3917
buff = cStringIO.StringIO()
3918
self.write_wrapper(buff.write)
3919
return buff.getvalue()
3920
3921
def get_pxd(self):
3922
r"""
3923
Returns the code for the Cython .pxd file.
3924
3925
EXAMPLES:
3926
3927
First we get the InterpreterSpec for several interpreters:
3928
3929
sage: from sage.ext.gen_interpreters import *
3930
sage: rdf_spec = RDFInterpreter()
3931
sage: rr_spec = RRInterpreter()
3932
sage: el_spec = ElementInterpreter()
3933
3934
Then we get the corresponding .pxd::
3935
3936
sage: rdf_pxd = InterpreterGenerator(rdf_spec).get_pxd()
3937
sage: rr_pxd = InterpreterGenerator(rr_spec).get_pxd()
3938
sage: el_pxd = InterpreterGenerator(el_spec).get_pxd()
3939
3940
Now we can look through these pxd files.
3941
3942
Each .pxd starts with a file header; this can be
3943
customized on a per-interpreter basis (some blank lines have been
3944
elided below)::
3945
3946
sage: print rdf_pxd
3947
# Automatically generated by ext/gen_interpreters.py. Do not edit!
3948
from cpython cimport PyObject
3949
from sage.ext.fast_callable cimport Wrapper
3950
...
3951
sage: print rr_pxd
3952
# ...
3953
from sage.rings.real_mpfr cimport RealField_class, RealNumber
3954
from sage.libs.mpfr cimport *
3955
...
3956
3957
Next and last is the declaration of the wrapper class, which
3958
starts off with a list of member declarations::
3959
3960
sage: print rdf_pxd
3961
# ...
3962
cdef class Wrapper_rdf(Wrapper):
3963
cdef int _n_args
3964
cdef double* _args
3965
cdef int _n_constants
3966
cdef double* _constants
3967
cdef object _list_py_constants
3968
cdef int _n_py_constants
3969
cdef PyObject** _py_constants
3970
cdef int _n_stack
3971
cdef double* _stack
3972
cdef int _n_code
3973
cdef int* _code
3974
...
3975
3976
Contrast the declaration of ``_stack`` here with the
3977
ElementInterpreter version. To simplify our handling of
3978
reference counting and garbage collection, in a Python-object
3979
based interpreter, we allocate arrays as Python lists,
3980
and then pull the array out of the innards of the list::
3981
3982
sage: print el_pxd
3983
# ...
3984
cdef object _list_stack
3985
cdef int _n_stack
3986
cdef PyObject** _stack
3987
...
3988
3989
Then, at the end of the wrapper class, we declare a cdef method
3990
for quickly calling the wrapper object from Cython. (This method
3991
is omitted from Python-object based interpreters.)::
3992
3993
sage: print rdf_pxd
3994
# ...
3995
cdef bint call_c(self,
3996
double* args,
3997
double* result) except 0
3998
sage: print rr_pxd
3999
# ...
4000
cdef bint call_c(self,
4001
mpfr_t* args,
4002
mpfr_t* result) except 0
4003
4004
"""
4005
import cStringIO
4006
buff = cStringIO.StringIO()
4007
self.write_pxd(buff.write)
4008
return buff.getvalue()
4009
4010
def write_if_changed(fn, value):
4011
r"""
4012
Writes value to the file named fn, if value is different than
4013
the current contents.
4014
4015
EXAMPLES::
4016
4017
sage: from sage.ext.gen_interpreters import *
4018
sage: def last_modification(fn): return os.stat(fn).st_mtime
4019
sage: fn = tmp_filename('gen_interp')
4020
sage: write_if_changed(fn, 'Hello, world')
4021
sage: t1 = last_modification(fn)
4022
sage: open(fn).read()
4023
'Hello, world'
4024
sage: sleep(2) # long time
4025
sage: write_if_changed(fn, 'Goodbye, world')
4026
sage: t2 = last_modification(fn)
4027
sage: open(fn).read()
4028
'Goodbye, world'
4029
sage: sleep(2) # long time
4030
sage: write_if_changed(fn, 'Goodbye, world')
4031
sage: t3 = last_modification(fn)
4032
sage: open(fn).read()
4033
'Goodbye, world'
4034
sage: t1 == t2 # long time
4035
False
4036
sage: t2 == t3
4037
True
4038
"""
4039
old_value = None
4040
try:
4041
with open(fn) as file:
4042
old_value = file.read()
4043
except IOError:
4044
pass
4045
4046
if value != old_value:
4047
# We try to remove the file, in case it exists. This is to
4048
# automatically break hardlinks... see #5350 for motivation.
4049
try:
4050
os.remove(fn)
4051
except OSError:
4052
pass
4053
4054
with open(fn, 'w') as file:
4055
file.write(value)
4056
4057
def build_interp(interp_spec, dir):
4058
r"""
4059
Given an InterpreterSpec, writes the C interpreter and the Cython
4060
wrapper (generates a pyx and a pxd file).
4061
4062
EXAMPLES::
4063
4064
sage: from sage.ext.gen_interpreters import *
4065
sage: testdir = tmp_dir()
4066
sage: rdf_interp = RDFInterpreter()
4067
sage: build_interp(rdf_interp, testdir)
4068
sage: open(testdir + '/interp_rdf.c').readline()
4069
'/* Automatically generated by ext/gen_interpreters.py. Do not edit! */\n'
4070
"""
4071
ig = InterpreterGenerator(interp_spec)
4072
interp_fn = '%s/interp_%s.c' % (dir, interp_spec.name)
4073
header_fn = '%s/interp_%s.h' % (dir, interp_spec.name)
4074
wrapper_fn = '%s/wrapper_%s.pyx' % (dir, interp_spec.name)
4075
pxd_fn = '%s/wrapper_%s.pxd' % (dir, interp_spec.name)
4076
interp = ig.get_interpreter()
4077
header = ig.get_interpreter_header()
4078
wrapper = ig.get_wrapper()
4079
pxd = ig.get_pxd()
4080
write_if_changed(interp_fn, interp)
4081
write_if_changed(header_fn, header)
4082
write_if_changed(wrapper_fn, wrapper)
4083
write_if_changed(pxd_fn, pxd)
4084
4085
def rebuild(dir):
4086
r"""
4087
Check whether the interpreter and wrapper sources have been written
4088
since the last time this module was changed. If not, write them.
4089
4090
EXAMPLES::
4091
4092
sage: from sage.ext.gen_interpreters import *
4093
sage: testdir = tmp_dir()
4094
sage: rebuild(testdir)
4095
Building interpreters for fast_callable
4096
sage: rebuild(testdir)
4097
sage: open(testdir + '/wrapper_el.pyx').readline()
4098
'# Automatically generated by ext/gen_interpreters.py. Do not edit!\n'
4099
"""
4100
module_mtime = os.stat(__file__).st_mtime
4101
try:
4102
if os.stat(os.path.join(dir, 'timestamp')).st_mtime >= module_mtime:
4103
# No need to rebuild.
4104
return
4105
except OSError:
4106
pass
4107
4108
# This line will show up in "sage -b" (once per upgrade, not every time
4109
# you run it).
4110
print "Building interpreters for fast_callable"
4111
4112
interp = RDFInterpreter()
4113
build_interp(interp, dir)
4114
4115
interp = CDFInterpreter()
4116
build_interp(interp, dir)
4117
4118
interp = RRInterpreter()
4119
build_interp(interp, dir)
4120
4121
interp = PythonInterpreter()
4122
build_interp(interp, dir)
4123
4124
interp = ElementInterpreter()
4125
build_interp(interp, dir)
4126
4127
# Do this last, so we don't do it if there's an error above.
4128
with open(os.path.join(dir, 'timestamp'), 'w'):
4129
pass
4130
4131
# This list of modules gets added to the list in module_list.py.
4132
# For now, that's not important -- we could have just put this
4133
# list in module_list.py directly. But eventually, we'll have
4134
# interpreters that are conditionally built (for example,
4135
# interpreters that rely on SSE so they only work on x86), so
4136
# it makes sense to keep the decisions about which interpreters
4137
# to write and which interpreters to build in the same place.
4138
modules = [
4139
Extension('sage.ext.interpreters.wrapper_rdf',
4140
sources = ['sage/ext/interpreters/wrapper_rdf.pyx',
4141
'sage/ext/interpreters/interp_rdf.c'],
4142
libraries = ['gsl']),
4143
4144
Extension('sage.ext.interpreters.wrapper_cdf',
4145
sources = ['sage/ext/interpreters/wrapper_cdf.pyx',
4146
'sage/ext/interpreters/interp_cdf.c'],),
4147
4148
Extension('sage.ext.interpreters.wrapper_rr',
4149
sources = ['sage/ext/interpreters/wrapper_rr.pyx',
4150
'sage/ext/interpreters/interp_rr.c'],
4151
libraries=['mpfr']),
4152
4153
Extension('sage.ext.interpreters.wrapper_py',
4154
sources = ['sage/ext/interpreters/wrapper_py.pyx',
4155
'sage/ext/interpreters/interp_py.c']),
4156
4157
Extension('sage.ext.interpreters.wrapper_el',
4158
sources = ['sage/ext/interpreters/wrapper_el.pyx',
4159
'sage/ext/interpreters/interp_el.c']),
4160
4161
]
4162
4163