pyopencl 2024.2.2__cp311-cp311-macosx_11_0_arm64.whl → 2024.2.5__cp311-cp311-macosx_11_0_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pyopencl might be problematic. Click here for more details.

Files changed (99) hide show
  1. pyopencl/__init__.py +16 -4
  2. pyopencl/_cl.cpython-311-darwin.so +0 -0
  3. pyopencl/algorithm.py +3 -1
  4. pyopencl/bitonic_sort.py +2 -0
  5. pyopencl/characterize/__init__.py +23 -0
  6. pyopencl/compyte/.git +1 -0
  7. pyopencl/compyte/.gitignore +21 -0
  8. pyopencl/compyte/ndarray/Makefile +31 -0
  9. pyopencl/compyte/ndarray/gpu_ndarray.h +35 -0
  10. pyopencl/compyte/ndarray/pygpu_language.h +207 -0
  11. pyopencl/compyte/ndarray/pygpu_language_cuda.cu +622 -0
  12. pyopencl/compyte/ndarray/pygpu_language_opencl.cpp +317 -0
  13. pyopencl/compyte/ndarray/pygpu_ndarray.cpp +1546 -0
  14. pyopencl/compyte/ndarray/pygpu_ndarray.h +71 -0
  15. pyopencl/compyte/ndarray/pygpu_ndarray_object.h +232 -0
  16. pyopencl/tools.py +60 -56
  17. pyopencl/version.py +9 -3
  18. {pyopencl-2024.2.2.dist-info → pyopencl-2024.2.5.dist-info}/METADATA +14 -14
  19. pyopencl-2024.2.5.dist-info/RECORD +56 -0
  20. {pyopencl-2024.2.2.dist-info → pyopencl-2024.2.5.dist-info}/WHEEL +1 -1
  21. pyopencl-2024.2.2.data/data/CITATION.cff +0 -74
  22. pyopencl-2024.2.2.data/data/CMakeLists.txt +0 -83
  23. pyopencl-2024.2.2.data/data/Makefile.in +0 -21
  24. pyopencl-2024.2.2.data/data/README.rst +0 -70
  25. pyopencl-2024.2.2.data/data/README_SETUP.txt +0 -34
  26. pyopencl-2024.2.2.data/data/aksetup_helper.py +0 -1013
  27. pyopencl-2024.2.2.data/data/configure.py +0 -6
  28. pyopencl-2024.2.2.data/data/contrib/cldis.py +0 -91
  29. pyopencl-2024.2.2.data/data/contrib/fortran-to-opencl/README +0 -29
  30. pyopencl-2024.2.2.data/data/contrib/fortran-to-opencl/translate.py +0 -1441
  31. pyopencl-2024.2.2.data/data/contrib/pyopencl.vim +0 -84
  32. pyopencl-2024.2.2.data/data/doc/Makefile +0 -23
  33. pyopencl-2024.2.2.data/data/doc/algorithm.rst +0 -214
  34. pyopencl-2024.2.2.data/data/doc/array.rst +0 -305
  35. pyopencl-2024.2.2.data/data/doc/conf.py +0 -26
  36. pyopencl-2024.2.2.data/data/doc/howto.rst +0 -105
  37. pyopencl-2024.2.2.data/data/doc/index.rst +0 -137
  38. pyopencl-2024.2.2.data/data/doc/make_constants.py +0 -561
  39. pyopencl-2024.2.2.data/data/doc/misc.rst +0 -885
  40. pyopencl-2024.2.2.data/data/doc/runtime.rst +0 -51
  41. pyopencl-2024.2.2.data/data/doc/runtime_const.rst +0 -30
  42. pyopencl-2024.2.2.data/data/doc/runtime_gl.rst +0 -78
  43. pyopencl-2024.2.2.data/data/doc/runtime_memory.rst +0 -527
  44. pyopencl-2024.2.2.data/data/doc/runtime_platform.rst +0 -184
  45. pyopencl-2024.2.2.data/data/doc/runtime_program.rst +0 -364
  46. pyopencl-2024.2.2.data/data/doc/runtime_queue.rst +0 -182
  47. pyopencl-2024.2.2.data/data/doc/subst.rst +0 -36
  48. pyopencl-2024.2.2.data/data/doc/tools.rst +0 -4
  49. pyopencl-2024.2.2.data/data/doc/types.rst +0 -42
  50. pyopencl-2024.2.2.data/data/examples/black-hole-accretion.py +0 -2227
  51. pyopencl-2024.2.2.data/data/examples/demo-struct-reduce.py +0 -75
  52. pyopencl-2024.2.2.data/data/examples/demo.py +0 -39
  53. pyopencl-2024.2.2.data/data/examples/demo_array.py +0 -32
  54. pyopencl-2024.2.2.data/data/examples/demo_array_svm.py +0 -37
  55. pyopencl-2024.2.2.data/data/examples/demo_elementwise.py +0 -34
  56. pyopencl-2024.2.2.data/data/examples/demo_elementwise_complex.py +0 -53
  57. pyopencl-2024.2.2.data/data/examples/demo_mandelbrot.py +0 -183
  58. pyopencl-2024.2.2.data/data/examples/demo_meta_codepy.py +0 -56
  59. pyopencl-2024.2.2.data/data/examples/demo_meta_template.py +0 -55
  60. pyopencl-2024.2.2.data/data/examples/dump-performance.py +0 -38
  61. pyopencl-2024.2.2.data/data/examples/dump-properties.py +0 -86
  62. pyopencl-2024.2.2.data/data/examples/gl_interop_demo.py +0 -84
  63. pyopencl-2024.2.2.data/data/examples/gl_particle_animation.py +0 -218
  64. pyopencl-2024.2.2.data/data/examples/ipython-demo.ipynb +0 -203
  65. pyopencl-2024.2.2.data/data/examples/median-filter.py +0 -99
  66. pyopencl-2024.2.2.data/data/examples/n-body.py +0 -1070
  67. pyopencl-2024.2.2.data/data/examples/narray.py +0 -37
  68. pyopencl-2024.2.2.data/data/examples/noisyImage.jpg +0 -0
  69. pyopencl-2024.2.2.data/data/examples/pi-monte-carlo.py +0 -1166
  70. pyopencl-2024.2.2.data/data/examples/svm.py +0 -82
  71. pyopencl-2024.2.2.data/data/examples/transpose.py +0 -229
  72. pyopencl-2024.2.2.data/data/pytest.ini +0 -3
  73. pyopencl-2024.2.2.data/data/src/bitlog.cpp +0 -51
  74. pyopencl-2024.2.2.data/data/src/bitlog.hpp +0 -83
  75. pyopencl-2024.2.2.data/data/src/clinfo_ext.h +0 -134
  76. pyopencl-2024.2.2.data/data/src/mempool.hpp +0 -444
  77. pyopencl-2024.2.2.data/data/src/pyopencl_ext.h +0 -77
  78. pyopencl-2024.2.2.data/data/src/tools.hpp +0 -90
  79. pyopencl-2024.2.2.data/data/src/wrap_cl.cpp +0 -61
  80. pyopencl-2024.2.2.data/data/src/wrap_cl.hpp +0 -5853
  81. pyopencl-2024.2.2.data/data/src/wrap_cl_part_1.cpp +0 -369
  82. pyopencl-2024.2.2.data/data/src/wrap_cl_part_2.cpp +0 -702
  83. pyopencl-2024.2.2.data/data/src/wrap_constants.cpp +0 -1274
  84. pyopencl-2024.2.2.data/data/src/wrap_helpers.hpp +0 -213
  85. pyopencl-2024.2.2.data/data/src/wrap_mempool.cpp +0 -738
  86. pyopencl-2024.2.2.data/data/test/add-vectors-32.spv +0 -0
  87. pyopencl-2024.2.2.data/data/test/add-vectors-64.spv +0 -0
  88. pyopencl-2024.2.2.data/data/test/empty-header.h +0 -1
  89. pyopencl-2024.2.2.data/data/test/test_algorithm.py +0 -1180
  90. pyopencl-2024.2.2.data/data/test/test_array.py +0 -2392
  91. pyopencl-2024.2.2.data/data/test/test_arrays_in_structs.py +0 -100
  92. pyopencl-2024.2.2.data/data/test/test_clmath.py +0 -529
  93. pyopencl-2024.2.2.data/data/test/test_clrandom.py +0 -75
  94. pyopencl-2024.2.2.data/data/test/test_enqueue_copy.py +0 -271
  95. pyopencl-2024.2.2.data/data/test/test_wrapper.py +0 -1565
  96. pyopencl-2024.2.2.dist-info/LICENSE +0 -282
  97. pyopencl-2024.2.2.dist-info/RECORD +0 -123
  98. pyopencl-2024.2.2.dist-info/top_level.txt +0 -1
  99. {pyopencl-2024.2.2.data/data → pyopencl-2024.2.5.dist-info/licenses}/LICENSE +0 -0
@@ -1,1441 +0,0 @@
1
- __copyright__ = "Copyright (C) 2009 Andreas Kloeckner"
2
-
3
- __license__ = """
4
- Permission is hereby granted, free of charge, to any person obtaining a copy
5
- of this software and associated documentation files (the "Software"), to deal
6
- in the Software without restriction, including without limitation the rights
7
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
- copies of the Software, and to permit persons to whom the Software is
9
- furnished to do so, subject to the following conditions:
10
-
11
- The above copyright notice and this permission notice shall be included in
12
- all copies or substantial portions of the Software.
13
-
14
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
- THE SOFTWARE.
21
- """
22
-
23
- import re
24
- from sys import intern
25
- from warnings import warn
26
-
27
- import cgen
28
- import numpy as np
29
- import pymbolic.primitives as p
30
- import pytools.lex
31
- from pymbolic.mapper import CombineMapper
32
- from pymbolic.mapper.c_code import CCodeMapper as CCodeMapperBase
33
- from pymbolic.parser import Parser as ExpressionParserBase
34
-
35
-
36
- class TranslatorWarning(UserWarning):
37
- pass
38
-
39
-
40
- class TranslationError(RuntimeError):
41
- pass
42
-
43
-
44
- def complex_type_name(dtype):
45
- if dtype == np.complex64:
46
- return "cfloat"
47
- if dtype == np.complex128:
48
- return "cdouble"
49
- else:
50
- raise RuntimeError
51
-
52
-
53
- # {{{ AST components
54
-
55
- def dtype_to_ctype(dtype):
56
- if dtype is None:
57
- raise ValueError("dtype may not be None")
58
-
59
- dtype = np.dtype(dtype)
60
- if dtype == np.int64:
61
- return "long"
62
- elif dtype == np.uint64:
63
- return "unsigned long"
64
- elif dtype == np.int32:
65
- return "int"
66
- elif dtype == np.uint32:
67
- return "unsigned int"
68
- elif dtype == np.int16:
69
- return "short int"
70
- elif dtype == np.uint16:
71
- return "short unsigned int"
72
- elif dtype == np.int8:
73
- return "signed char"
74
- elif dtype == np.uint8:
75
- return "unsigned char"
76
- elif dtype == np.float32:
77
- return "float"
78
- elif dtype == np.float64:
79
- return "double"
80
- elif dtype == np.complex64:
81
- return "cfloat_t"
82
- elif dtype == np.complex128:
83
- return "cdouble_t"
84
- else:
85
- raise ValueError("unable to map dtype '%s'" % dtype)
86
-
87
-
88
- class POD(cgen.POD):
89
- def get_decl_pair(self):
90
- return [dtype_to_ctype(self.dtype)], self.name
91
-
92
- # }}}
93
-
94
-
95
- # {{{ expression parser
96
-
97
- _less_than = intern("less_than")
98
- _greater_than = intern("greater_than")
99
- _less_equal = intern("less_equal")
100
- _greater_equal = intern("greater_equal")
101
- _equal = intern("equal")
102
- _not_equal = intern("not_equal")
103
-
104
- _not = intern("not")
105
- _and = intern("and")
106
- _or = intern("or")
107
-
108
-
109
- class TypedLiteral(p.Leaf):
110
- def __init__(self, value, dtype):
111
- self.value = value
112
- self.dtype = np.dtype(dtype)
113
-
114
- def __getinitargs__(self):
115
- return self.value, self.dtype
116
-
117
- mapper_method = intern("map_literal")
118
-
119
-
120
- def simplify_typed_literal(expr):
121
- if (isinstance(expr, p.Product)
122
- and len(expr.children) == 2
123
- and isinstance(expr.children[1], TypedLiteral)
124
- and p.is_constant(expr.children[0])
125
- and expr.children[0] == -1):
126
- tl = expr.children[1]
127
- return TypedLiteral("-"+tl.value, tl.dtype)
128
- else:
129
- return expr
130
-
131
-
132
- class FortranExpressionParser(ExpressionParserBase):
133
- # FIXME double/single prec literals
134
-
135
- lex_table = [
136
- (_less_than, pytools.lex.RE(r"\.lt\.", re.I)),
137
- (_greater_than, pytools.lex.RE(r"\.gt\.", re.I)),
138
- (_less_equal, pytools.lex.RE(r"\.le\.", re.I)),
139
- (_greater_equal, pytools.lex.RE(r"\.ge\.", re.I)),
140
- (_equal, pytools.lex.RE(r"\.eq\.", re.I)),
141
- (_not_equal, pytools.lex.RE(r"\.ne\.", re.I)),
142
-
143
- (_not, pytools.lex.RE(r"\.not\.", re.I)),
144
- (_and, pytools.lex.RE(r"\.and\.", re.I)),
145
- (_or, pytools.lex.RE(r"\.or\.", re.I)),
146
- ] + ExpressionParserBase.lex_table
147
-
148
- def __init__(self, tree_walker):
149
- self.tree_walker = tree_walker
150
-
151
- _PREC_FUNC_ARGS = 1
152
-
153
- def parse_terminal(self, pstate):
154
- scope = self.tree_walker.scope_stack[-1]
155
-
156
- from pymbolic.parser import _closepar, _float, _identifier, _openpar
157
-
158
- next_tag = pstate.next_tag()
159
- if next_tag is _float:
160
- value = pstate.next_str_and_advance().lower()
161
- if "d" in value:
162
- dtype = np.float64
163
- else:
164
- dtype = np.float32
165
-
166
- value = value.replace("d", "e")
167
- if value.startswith("."):
168
- prev_value = value
169
- value = "0"+value
170
- print(value, prev_value)
171
- elif value.startswith("-."):
172
- prev_value = value
173
- value = "-0"+value[1:]
174
- print(value, prev_value)
175
- return TypedLiteral(value, dtype)
176
-
177
- elif next_tag is _identifier:
178
- name = pstate.next_str_and_advance()
179
-
180
- if pstate.is_at_end() or pstate.next_tag() is not _openpar:
181
- # not a subscript
182
- scope.use_name(name)
183
-
184
- return p.Variable(name)
185
-
186
- left_exp = p.Variable(name)
187
-
188
- pstate.advance()
189
- pstate.expect_not_end()
190
-
191
- if scope.is_known(name):
192
- cls = p.Subscript
193
- else:
194
- cls = p.Call
195
-
196
- if pstate.next_tag is _closepar:
197
- pstate.advance()
198
- left_exp = cls(left_exp, ())
199
- else:
200
- args = self.parse_expression(pstate, self._PREC_FUNC_ARGS)
201
- if not isinstance(args, tuple):
202
- args = (args,)
203
- left_exp = cls(left_exp, args)
204
- pstate.expect(_closepar)
205
- pstate.advance()
206
-
207
- return left_exp
208
- else:
209
- return ExpressionParserBase.parse_terminal(
210
- self, pstate)
211
-
212
- COMP_MAP = {
213
- _less_than: "<",
214
- _less_equal: "<=",
215
- _greater_than: ">",
216
- _greater_equal: ">=",
217
- _equal: "==",
218
- _not_equal: "!=",
219
- }
220
-
221
- def parse_prefix(self, pstate, min_precedence=0):
222
- import pymbolic.primitives as primitives
223
- from pymbolic.parser import _PREC_UNARY
224
-
225
- pstate.expect_not_end()
226
-
227
- if pstate.is_next(_not):
228
- pstate.advance()
229
- return primitives.LogicalNot(
230
- self.parse_expression(pstate, _PREC_UNARY))
231
- else:
232
- return ExpressionParserBase.parse_prefix(self, pstate)
233
-
234
- def parse_postfix(self, pstate, min_precedence, left_exp):
235
- from pymbolic.parser import (
236
- _PREC_CALL, _PREC_COMPARISON, _PREC_LOGICAL_AND, _PREC_LOGICAL_OR,
237
- _openpar)
238
- from pymbolic.primitives import Comparison, LogicalAnd, LogicalOr
239
-
240
- next_tag = pstate.next_tag()
241
- if next_tag is _openpar and _PREC_CALL > min_precedence:
242
- raise TranslationError("parenthesis operator only works on names")
243
- elif next_tag in self.COMP_MAP and _PREC_COMPARISON > min_precedence:
244
- pstate.advance()
245
- left_exp = Comparison(
246
- left_exp,
247
- self.COMP_MAP[next_tag],
248
- self.parse_expression(pstate, _PREC_COMPARISON))
249
- did_something = True
250
- elif next_tag is _and and _PREC_LOGICAL_AND > min_precedence:
251
- pstate.advance()
252
- left_exp = LogicalAnd((left_exp,
253
- self.parse_expression(pstate, _PREC_LOGICAL_AND)))
254
- did_something = True
255
- elif next_tag is _or and _PREC_LOGICAL_OR > min_precedence:
256
- pstate.advance()
257
- left_exp = LogicalOr((left_exp,
258
- self.parse_expression(pstate, _PREC_LOGICAL_OR)))
259
- did_something = True
260
- else:
261
- left_exp, did_something = ExpressionParserBase.parse_postfix(
262
- self, pstate, min_precedence, left_exp)
263
-
264
- if isinstance(left_exp, tuple) and min_precedence < self._PREC_FUNC_ARGS:
265
- # this must be a complex literal
266
- assert len(left_exp) == 2
267
- r, i = left_exp
268
-
269
- r = simplify_typed_literal(r)
270
- i = simplify_typed_literal(i)
271
-
272
- dtype = (r.dtype.type(0) + i.dtype.type(0)).dtype
273
- if dtype == np.float32:
274
- dtype = np.complex64
275
- else:
276
- dtype = np.complex128
277
-
278
- left_exp = TypedLiteral(left_exp, dtype)
279
-
280
- return left_exp, did_something
281
-
282
- # }}}
283
-
284
-
285
- # {{{ expression generator
286
-
287
- class TypeInferenceMapper(CombineMapper):
288
- def __init__(self, scope):
289
- self.scope = scope
290
-
291
- def combine(self, dtypes):
292
- return sum(dtype.type(1) for dtype in dtypes).dtype
293
-
294
- def map_literal(self, expr):
295
- return expr.dtype
296
-
297
- def map_constant(self, expr):
298
- return np.asarray(expr).dtype
299
-
300
- def map_variable(self, expr):
301
- return self.scope.get_type(expr.name)
302
-
303
- def map_call(self, expr):
304
- name = expr.function.name
305
- if name == "fromreal":
306
- arg, = expr.parameters
307
- base_dtype = self.rec(arg)
308
- tgt_real_dtype = (np.float32(0)+base_dtype.type(0)).dtype
309
- assert tgt_real_dtype.kind == "f"
310
- if tgt_real_dtype == np.float32:
311
- return np.dtype(np.complex64)
312
- elif tgt_real_dtype == np.float64:
313
- return np.dtype(np.complex128)
314
- else:
315
- raise RuntimeError("unexpected complex type")
316
-
317
- elif name in ["imag", "real", "abs", "dble"]:
318
- arg, = expr.parameters
319
- base_dtype = self.rec(arg)
320
-
321
- if base_dtype == np.complex128:
322
- return np.dtype(np.float64)
323
- elif base_dtype == np.complex64:
324
- return np.dtype(np.float32)
325
- else:
326
- return base_dtype
327
-
328
- else:
329
- return CombineMapper.map_call(self, expr)
330
-
331
-
332
- class ComplexCCodeMapper(CCodeMapperBase):
333
- def __init__(self, infer_type):
334
- CCodeMapperBase.__init__(self)
335
- self.infer_type = infer_type
336
-
337
- def map_sum(self, expr, enclosing_prec):
338
- tgt_dtype = self.infer_type(expr)
339
- is_complex = tgt_dtype.kind == "c"
340
-
341
- if not is_complex:
342
- return CCodeMapperBase.map_sum(self, expr, enclosing_prec)
343
- else:
344
- tgt_name = complex_type_name(tgt_dtype)
345
-
346
- reals = [child for child in expr.children
347
- if "c" != self.infer_type(child).kind]
348
- complexes = [child for child in expr.children
349
- if "c" == self.infer_type(child).kind]
350
-
351
- from pymbolic.mapper.stringifier import PREC_NONE, PREC_SUM
352
- real_sum = self.join_rec(" + ", reals, PREC_SUM)
353
-
354
- if len(complexes) == 1:
355
- myprec = PREC_SUM
356
- else:
357
- myprec = PREC_NONE
358
-
359
- complex_sum = self.rec(complexes[0], myprec)
360
- for child in complexes[1:]:
361
- complex_sum = "{}_add({}, {})".format(
362
- tgt_name, complex_sum,
363
- self.rec(child, PREC_NONE))
364
-
365
- if real_sum:
366
- result = "{}_add({}_fromreal({}), {})".format(
367
- tgt_name, tgt_name, real_sum, complex_sum)
368
- else:
369
- result = complex_sum
370
-
371
- return self.parenthesize_if_needed(result, enclosing_prec, PREC_SUM)
372
-
373
- def map_product(self, expr, enclosing_prec):
374
- tgt_dtype = self.infer_type(expr)
375
- is_complex = "c" == tgt_dtype.kind
376
-
377
- if not is_complex:
378
- return CCodeMapperBase.map_product(self, expr, enclosing_prec)
379
- else:
380
- tgt_name = complex_type_name(tgt_dtype)
381
-
382
- reals = [child for child in expr.children
383
- if "c" != self.infer_type(child).kind]
384
- complexes = [child for child in expr.children
385
- if "c" == self.infer_type(child).kind]
386
-
387
- from pymbolic.mapper.stringifier import PREC_NONE, PREC_PRODUCT
388
- real_prd = self.join_rec("*", reals, PREC_PRODUCT)
389
-
390
- if len(complexes) == 1:
391
- myprec = PREC_PRODUCT
392
- else:
393
- myprec = PREC_NONE
394
-
395
- complex_prd = self.rec(complexes[0], myprec)
396
- for child in complexes[1:]:
397
- complex_prd = "{}_mul({}, {})".format(
398
- tgt_name, complex_prd,
399
- self.rec(child, PREC_NONE))
400
-
401
- if real_prd:
402
- result = f"{tgt_name}_rmul({real_prd}, {complex_prd})"
403
- else:
404
- result = complex_prd
405
-
406
- return self.parenthesize_if_needed(result, enclosing_prec, PREC_PRODUCT)
407
-
408
- def map_quotient(self, expr, enclosing_prec):
409
- from pymbolic.mapper.stringifier import PREC_NONE
410
- n_complex = "c" == self.infer_type(expr.numerator).kind
411
- d_complex = "c" == self.infer_type(expr.denominator).kind
412
-
413
- tgt_dtype = self.infer_type(expr)
414
-
415
- if not (n_complex or d_complex):
416
- return CCodeMapperBase.map_quotient(self, expr, enclosing_prec)
417
- elif n_complex and not d_complex:
418
- return "{}_divider({}, {})".format(
419
- complex_type_name(tgt_dtype),
420
- self.rec(expr.numerator, PREC_NONE),
421
- self.rec(expr.denominator, PREC_NONE))
422
- elif not n_complex and d_complex:
423
- return "{}_rdivide({}, {})".format(
424
- complex_type_name(tgt_dtype),
425
- self.rec(expr.numerator, PREC_NONE),
426
- self.rec(expr.denominator, PREC_NONE))
427
- else:
428
- return "{}_divide({}, {})".format(
429
- complex_type_name(tgt_dtype),
430
- self.rec(expr.numerator, PREC_NONE),
431
- self.rec(expr.denominator, PREC_NONE))
432
-
433
- def map_remainder(self, expr, enclosing_prec):
434
- tgt_dtype = self.infer_type(expr)
435
- if "c" == tgt_dtype.kind:
436
- raise RuntimeError("complex remainder not defined")
437
-
438
- return CCodeMapperBase.map_remainder(self, expr, enclosing_prec)
439
-
440
- def map_power(self, expr, enclosing_prec):
441
- from pymbolic.mapper.stringifier import PREC_NONE
442
-
443
- tgt_dtype = self.infer_type(expr)
444
- if "c" == tgt_dtype.kind:
445
- if expr.exponent in [2, 3, 4]:
446
- value = expr.base
447
- for i in range(expr.exponent-1):
448
- value = value * expr.base
449
- return self.rec(value, enclosing_prec)
450
- else:
451
- b_complex = "c" == self.infer_type(expr.base).kind
452
- e_complex = "c" == self.infer_type(expr.exponent).kind
453
-
454
- if b_complex and not e_complex:
455
- return "{}_powr({}, {})".format(
456
- complex_type_name(tgt_dtype),
457
- self.rec(expr.base, PREC_NONE),
458
- self.rec(expr.exponent, PREC_NONE))
459
- else:
460
- return "{}_pow({}, {})".format(
461
- complex_type_name(tgt_dtype),
462
- self.rec(expr.base, PREC_NONE),
463
- self.rec(expr.exponent, PREC_NONE))
464
-
465
- return CCodeMapperBase.map_power(self, expr, enclosing_prec)
466
-
467
-
468
- class CCodeMapper(ComplexCCodeMapper):
469
- # Whatever is needed to mop up after Fortran goes here.
470
- # Stuff that deals with generating real-valued code
471
- # from complex code goes above.
472
-
473
- def __init__(self, translator, scope):
474
- ComplexCCodeMapper.__init__(self, scope.get_type_inference_mapper())
475
- self.translator = translator
476
- self.scope = scope
477
-
478
- def map_subscript(self, expr, enclosing_prec):
479
- idx_dtype = self.infer_type(expr.index)
480
- if not "i" == idx_dtype.kind or "u" == idx_dtype.kind:
481
- ind_prefix = "(int) "
482
- else:
483
- ind_prefix = ""
484
-
485
- idx = expr.index
486
- if isinstance(idx, tuple) and len(idx) == 1:
487
- idx, = idx
488
-
489
- from pymbolic.mapper.stringifier import PREC_CALL, PREC_NONE
490
- return self.parenthesize_if_needed(
491
- self.format("%s[%s%s]",
492
- self.scope.translate_var_name(expr.aggregate.name),
493
- ind_prefix,
494
- self.rec(idx, PREC_NONE)),
495
- enclosing_prec, PREC_CALL)
496
-
497
- def map_call(self, expr, enclosing_prec):
498
- from pymbolic.mapper.stringifier import PREC_NONE
499
-
500
- tgt_dtype = self.infer_type(expr)
501
- arg_dtypes = [self.infer_type(par) for par in expr.parameters]
502
-
503
- name = expr.function.name
504
- if "f" == tgt_dtype.kind and name == "abs":
505
- name = "fabs"
506
-
507
- elif "c" == tgt_dtype.kind:
508
- if name in ["conjg", "dconjg"]:
509
- name = "conj"
510
-
511
- if name[:2] == "cd" and name[2:] in ["log", "exp", "sqrt"]:
512
- name = name[2:]
513
-
514
- if name == "dble":
515
- name = "real"
516
-
517
- name = "{}_{}".format(
518
- complex_type_name(tgt_dtype),
519
- name)
520
-
521
- elif name in ["aimag", "real", "imag"] and tgt_dtype.kind == "f":
522
- arg_dtype, = arg_dtypes
523
-
524
- if name == "aimag":
525
- name = "imag"
526
-
527
- name = "{}_{}".format(
528
- complex_type_name(arg_dtype),
529
- name)
530
-
531
- elif "c" == tgt_dtype.kind and name == "abs":
532
- arg_dtype, = arg_dtypes
533
-
534
- name = "%s_abs" % (
535
- complex_type_name(arg_dtype))
536
-
537
- return self.format("%s(%s)",
538
- name,
539
- self.join_rec(", ", expr.parameters, PREC_NONE))
540
-
541
- def map_variable(self, expr, enclosing_prec):
542
- # guaranteed to not be a subscript or a call
543
-
544
- name = expr.name
545
- shape = self.scope.get_shape(name)
546
- name = self.scope.translate_var_name(name)
547
- if expr.name in self.scope.arg_names:
548
- arg_idx = self.scope.arg_names.index(name)
549
- if self.translator.arg_needs_pointer(
550
- self.scope.subprogram_name, arg_idx):
551
- return "*"+name
552
- else:
553
- return name
554
- elif shape not in [(), None]:
555
- return "*"+name
556
- else:
557
- return name
558
-
559
- def map_literal(self, expr, enclosing_prec):
560
- from pymbolic.mapper.stringifier import PREC_NONE
561
- if expr.dtype.kind == "c":
562
- r, i = expr.value
563
- return "{}_new({}, {})".format(
564
- complex_type_name(expr.dtype),
565
- self.rec(r, PREC_NONE),
566
- self.rec(i, PREC_NONE))
567
- else:
568
- return expr.value
569
-
570
- def map_wildcard(self, expr, enclosing_prec):
571
- return ":"
572
-
573
-
574
- # }}}
575
-
576
- class Scope:
577
- def __init__(self, subprogram_name, arg_names=set()):
578
- self.subprogram_name = subprogram_name
579
-
580
- # map name to data
581
- self.data_statements = {}
582
-
583
- # map first letter to type
584
- self.implicit_types = {}
585
-
586
- # map name to dim tuple
587
- self.dim_map = {}
588
-
589
- # map name to dim tuple
590
- self.type_map = {}
591
-
592
- # map name to data
593
- self.data = {}
594
-
595
- self.arg_names = arg_names
596
-
597
- self.used_names = set()
598
-
599
- self.type_inf_mapper = None
600
-
601
- def known_names(self):
602
- return (self.used_names
603
- | set(self.dim_map.keys())
604
- | set(self.type_map.keys()))
605
-
606
- def is_known(self, name):
607
- return (name in self.used_names
608
- or name in self.dim_map
609
- or name in self.type_map)
610
-
611
- def use_name(self, name):
612
- self.used_names.add(name)
613
-
614
- def get_type(self, name):
615
- try:
616
- return self.type_map[name]
617
- except KeyError:
618
-
619
- if self.implicit_types is None:
620
- raise TranslationError(
621
- "no type for '%s' found in implict none routine"
622
- % name)
623
-
624
- return self.implicit_types.get(name[0], np.dtype(np.int32))
625
-
626
- def get_shape(self, name):
627
- return self.dim_map.get(name, ())
628
-
629
- def get_type_inference_mapper(self):
630
- if self.type_inf_mapper is None:
631
- self.type_inf_mapper = TypeInferenceMapper(self)
632
-
633
- return self.type_inf_mapper
634
-
635
- def translate_var_name(self, name):
636
- shape = self.dim_map.get(name)
637
- if name in self.data and shape is not None:
638
- return f"{self.subprogram_name}_{name}"
639
- else:
640
- return name
641
-
642
-
643
- class FTreeWalkerBase:
644
- def __init__(self):
645
- self.scope_stack = []
646
-
647
- self.expr_parser = FortranExpressionParser(self)
648
-
649
- def rec(self, expr, *args, **kwargs):
650
- mro = list(type(expr).__mro__)
651
- dispatch_class = kwargs.pop("dispatch_class", type(self))
652
-
653
- while mro:
654
- method_name = "map_"+mro.pop(0).__name__
655
-
656
- try:
657
- method = getattr(dispatch_class, method_name)
658
- except AttributeError:
659
- pass
660
- else:
661
- return method(self, expr, *args, **kwargs)
662
-
663
- raise NotImplementedError(
664
- "%s does not know how to map type '%s'"
665
- % (type(self).__name__,
666
- type(expr)))
667
-
668
- ENTITY_RE = re.compile(
669
- r"^(?P<name>[_0-9a-zA-Z]+)"
670
- r"(\((?P<shape>[-+*0-9:a-zA-Z,]+)\))?$")
671
-
672
- def parse_dimension_specs(self, dim_decls):
673
- def parse_bounds(bounds_str):
674
- start_end = bounds_str.split(":")
675
-
676
- assert 1 <= len(start_end) <= 2
677
-
678
- return tuple(self.parse_expr(s) for s in start_end)
679
-
680
- for decl in dim_decls:
681
- entity_match = self.ENTITY_RE.match(decl)
682
- assert entity_match
683
-
684
- groups = entity_match.groupdict()
685
- name = groups["name"]
686
- assert name
687
-
688
- if groups["shape"]:
689
- shape = [parse_bounds(s) for s in groups["shape"].split(",")]
690
- else:
691
- shape = None
692
-
693
- yield name, shape
694
-
695
- def __call__(self, expr, *args, **kwargs):
696
- return self.rec(expr, *args, **kwargs)
697
-
698
- # {{{ expressions
699
-
700
- def parse_expr(self, expr_str):
701
- return self.expr_parser(expr_str)
702
-
703
- # }}}
704
-
705
-
706
- class ArgumentAnalayzer(FTreeWalkerBase):
707
- def __init__(self):
708
- FTreeWalkerBase.__init__(self)
709
-
710
- # map (func, arg_nr) to
711
- # "w" for "needs pointer"
712
- # [] for no obstacle to de-pointerification known
713
- # [(func_name, arg_nr), ...] # depends on how this arg is used
714
-
715
- self.arg_usage_info = {}
716
-
717
- def arg_needs_pointer(self, func, arg_nr):
718
- data = self.arg_usage_info.get((func, arg_nr), [])
719
-
720
- if isinstance(data, list):
721
- return any(
722
- self.arg_needs_pointer(sub_func, sub_arg_nr)
723
- for sub_func, sub_arg_nr in data)
724
-
725
- return True
726
-
727
- # {{{ map_XXX functions
728
-
729
- def map_BeginSource(self, node):
730
- scope = Scope(None)
731
- self.scope_stack.append(scope)
732
-
733
- for c in node.content:
734
- self.rec(c)
735
-
736
- def map_Subroutine(self, node):
737
- scope = Scope(node.name, list(node.args))
738
- self.scope_stack.append(scope)
739
-
740
- for c in node.content:
741
- self.rec(c)
742
-
743
- self.scope_stack.pop()
744
-
745
- def map_EndSubroutine(self, node):
746
- pass
747
-
748
- def map_Implicit(self, node):
749
- pass
750
-
751
- # {{{ types, declarations
752
-
753
- def map_Equivalence(self, node):
754
- raise NotImplementedError("equivalence")
755
-
756
- def map_Dimension(self, node):
757
- scope = self.scope_stack[-1]
758
-
759
- for name, shape in self.parse_dimension_specs(node.items):
760
- if name in scope.arg_names:
761
- arg_idx = scope.arg_names.index(name)
762
- self.arg_usage_info[scope.subprogram_name, arg_idx] = "w"
763
-
764
- def map_External(self, node):
765
- pass
766
-
767
- def map_type_decl(self, node):
768
- scope = self.scope_stack[-1]
769
-
770
- for name, shape in self.parse_dimension_specs(node.entity_decls):
771
- if shape is not None and name in scope.arg_names:
772
- arg_idx = scope.arg_names.index(name)
773
- self.arg_usage_info[scope.subprogram_name, arg_idx] = "w"
774
-
775
- map_Logical = map_type_decl
776
- map_Integer = map_type_decl
777
- map_Real = map_type_decl
778
- map_Complex = map_type_decl
779
-
780
- # }}}
781
-
782
- def map_Data(self, node):
783
- pass
784
-
785
- def map_Parameter(self, node):
786
- raise NotImplementedError("parameter")
787
-
788
- # {{{ I/O
789
-
790
- def map_Open(self, node):
791
- pass
792
-
793
- def map_Format(self, node):
794
- pass
795
-
796
- def map_Write(self, node):
797
- pass
798
-
799
- def map_Print(self, node):
800
- pass
801
-
802
- def map_Read1(self, node):
803
- pass
804
-
805
- # }}}
806
-
807
- def map_Assignment(self, node):
808
- scope = self.scope_stack[-1]
809
-
810
- lhs = self.parse_expr(node.variable)
811
-
812
- if isinstance(lhs, p.Subscript):
813
- lhs_name = lhs.aggregate.name
814
- elif isinstance(lhs, p.Call):
815
- # in absence of dim info, subscripts get parsed as calls
816
- lhs_name = lhs.function.name
817
- else:
818
- lhs_name = lhs.name
819
-
820
- if lhs_name in scope.arg_names:
821
- arg_idx = scope.arg_names.index(lhs_name)
822
- self.arg_usage_info[scope.subprogram_name, arg_idx] = "w"
823
-
824
- def map_Allocate(self, node):
825
- raise NotImplementedError("allocate")
826
-
827
- def map_Deallocate(self, node):
828
- raise NotImplementedError("deallocate")
829
-
830
- def map_Save(self, node):
831
- raise NotImplementedError("save")
832
-
833
- def map_Line(self, node):
834
- raise NotImplementedError
835
-
836
- def map_Program(self, node):
837
- raise NotImplementedError
838
-
839
- def map_Entry(self, node):
840
- raise NotImplementedError
841
-
842
- # {{{ control flow
843
-
844
- def map_Goto(self, node):
845
- pass
846
-
847
- def map_Call(self, node):
848
- scope = self.scope_stack[-1]
849
-
850
- for i, arg_str in enumerate(node.items):
851
- arg = self.parse_expr(arg_str)
852
- if isinstance(arg, (p.Variable, p.Subscript)):
853
- if isinstance(arg, p.Subscript):
854
- arg_name = arg.aggregate.name
855
- else:
856
- arg_name = arg.name
857
-
858
- if arg_name in scope.arg_names:
859
- arg_idx = scope.arg_names.index(arg_name)
860
- arg_usage = self.arg_usage_info.setdefault(
861
- (scope.subprogram_name, arg_idx),
862
- [])
863
- if isinstance(arg_usage, list):
864
- arg_usage.append((node.designator, i))
865
-
866
- def map_Return(self, node):
867
- pass
868
-
869
- def map_ArithmeticIf(self, node):
870
- pass
871
-
872
- def map_If(self, node):
873
- for c in node.content:
874
- self.rec(c)
875
-
876
- def map_IfThen(self, node):
877
- for c in node.content:
878
- self.rec(c)
879
-
880
- def map_ElseIf(self, node):
881
- pass
882
-
883
- def map_Else(self, node):
884
- pass
885
-
886
- def map_EndIfThen(self, node):
887
- pass
888
-
889
- def map_Do(self, node):
890
- for c in node.content:
891
- self.rec(c)
892
-
893
- def map_EndDo(self, node):
894
- pass
895
-
896
- def map_Continue(self, node):
897
- pass
898
-
899
- def map_Stop(self, node):
900
- pass
901
-
902
- def map_Comment(self, node):
903
- pass
904
-
905
- # }}}
906
-
907
- # }}}
908
-
909
-
910
- # {{{ translator
911
-
912
- class F2CLTranslator(FTreeWalkerBase):
913
- def __init__(self, addr_space_hints, force_casts, arg_info,
914
- use_restrict_pointers):
915
- FTreeWalkerBase.__init__(self)
916
- self.addr_space_hints = addr_space_hints
917
- self.force_casts = force_casts
918
- self.arg_info = arg_info
919
- self.use_restrict_pointers = use_restrict_pointers
920
-
921
- def arg_needs_pointer(self, subprogram_name, arg_index):
922
- return self.arg_info.arg_needs_pointer(subprogram_name, arg_index)
923
-
924
- # {{{ declaration helpers
925
-
926
- def get_declarator(self, name):
927
- scope = self.scope_stack[-1]
928
- return POD(scope.get_type(name), name)
929
-
930
- def get_declarations(self):
931
- scope = self.scope_stack[-1]
932
-
933
- result = []
934
- pre_func_decl = []
935
-
936
- def gen_shape(start_end):
937
- return ":".join(self.gen_expr(s) for s in start_end)
938
-
939
- for name in sorted(scope.known_names()):
940
- shape = scope.dim_map.get(name)
941
-
942
- if shape is not None:
943
- dim_stmt = cgen.Statement(
944
- 'dimension \"fortran\" {}[{}]'.format(
945
- scope.translate_var_name(name),
946
- ", ".join(gen_shape(s) for s in shape)
947
- ))
948
-
949
- # cannot omit "dimension" decl even for rank-1 args:
950
- result.append(dim_stmt)
951
-
952
- if name in scope.data:
953
- assert name not in scope.arg_names
954
-
955
- data = scope.data[name]
956
-
957
- if shape is None:
958
- assert len(data) == 1
959
- result.append(
960
- cgen.Initializer(
961
- self.get_declarator(name),
962
- self.gen_expr(data[0])
963
- ))
964
- else:
965
- from cgen.opencl import CLConstant
966
- pre_func_decl.append(
967
- cgen.Initializer(
968
- CLConstant(
969
- cgen.ArrayOf(self.get_declarator(
970
- f"{scope.subprogram_name}_{name}"))),
971
- "{ %s }" % ",\n".join(self.gen_expr(x) for x in data)
972
- ))
973
- else:
974
- if name not in scope.arg_names:
975
- if shape is not None:
976
- result.append(cgen.Statement(
977
- "%s %s[nitemsof(%s)]"
978
- % (
979
- dtype_to_ctype(scope.get_type(name)),
980
- name, name)))
981
- else:
982
- result.append(self.get_declarator(name))
983
-
984
- return pre_func_decl, result
985
-
986
- def map_statement_list(self, content):
987
- body = []
988
-
989
- for c in content:
990
- mapped = self.rec(c)
991
- if mapped is None:
992
- warn("mapping '%s' returned None" % type(c))
993
- elif isinstance(mapped, list):
994
- body.extend(mapped)
995
- else:
996
- body.append(mapped)
997
-
998
- return body
999
-
1000
- # }}}
1001
-
1002
- # {{{ map_XXX functions
1003
-
1004
- def map_BeginSource(self, node):
1005
- scope = Scope(None)
1006
- self.scope_stack.append(scope)
1007
-
1008
- return self.map_statement_list(node.content)
1009
-
1010
- def map_Subroutine(self, node):
1011
- assert not node.prefix
1012
- assert not hasattr(node, "suffix")
1013
-
1014
- scope = Scope(node.name, list(node.args))
1015
- self.scope_stack.append(scope)
1016
-
1017
- body = self.map_statement_list(node.content)
1018
-
1019
- pre_func_decl, in_func_decl = self.get_declarations()
1020
- body = in_func_decl + [cgen.Line()] + body
1021
-
1022
- if isinstance(body[-1], cgen.Statement) and body[-1].text == "return":
1023
- body.pop()
1024
-
1025
- def get_arg_decl(arg_idx, arg_name):
1026
- decl = self.get_declarator(arg_name)
1027
-
1028
- if self.arg_needs_pointer(node.name, arg_idx):
1029
- hint = self.addr_space_hints.get((node.name, arg_name))
1030
- if hint:
1031
- decl = hint(cgen.Pointer(decl))
1032
- else:
1033
- if self.use_restrict_pointers:
1034
- decl = cgen.RestrictPointer(decl)
1035
- else:
1036
- decl = cgen.Pointer(decl)
1037
-
1038
- return decl
1039
-
1040
- result = cgen.FunctionBody(
1041
- cgen.FunctionDeclaration(
1042
- cgen.Value("void", node.name),
1043
- [get_arg_decl(i, arg) for i, arg in enumerate(node.args)]
1044
- ),
1045
- cgen.Block(body))
1046
-
1047
- self.scope_stack.pop()
1048
- if pre_func_decl:
1049
- return pre_func_decl + [cgen.Line(), result]
1050
- else:
1051
- return result
1052
-
1053
- def map_EndSubroutine(self, node):
1054
- return []
1055
-
1056
- def map_Implicit(self, node):
1057
- scope = self.scope_stack[-1]
1058
-
1059
- if not node.items:
1060
- assert not scope.implicit_types
1061
- scope.implicit_types = None
1062
-
1063
- for stmt, specs in node.items:
1064
- tp = self.dtype_from_stmt(stmt)
1065
- for start, end in specs:
1066
- for char_code in range(ord(start), ord(end)+1):
1067
- scope.implicit_types[chr(char_code)] = tp
1068
-
1069
- return []
1070
-
1071
- # {{{ types, declarations
1072
-
1073
- def map_Equivalence(self, node):
1074
- raise NotImplementedError("equivalence")
1075
-
1076
- TYPE_MAP = {
1077
- ("real", "4"): np.float32,
1078
- ("real", "8"): np.float64,
1079
- ("real", "16"): np.float128,
1080
-
1081
- ("complex", "8"): np.complex64,
1082
- ("complex", "16"): np.complex128,
1083
- ("complex", "32"): np.complex256,
1084
-
1085
- ("integer", ""): np.int32,
1086
- ("integer", "4"): np.int32,
1087
- ("integer", "8"): np.int64,
1088
- }
1089
-
1090
- def dtype_from_stmt(self, stmt):
1091
- length, kind = stmt.selector
1092
- assert not kind
1093
- return np.dtype(self.TYPE_MAP[(type(stmt).__name__.lower(), length)])
1094
-
1095
- def map_type_decl(self, node):
1096
- scope = self.scope_stack[-1]
1097
-
1098
- tp = self.dtype_from_stmt(node)
1099
-
1100
- for name, shape in self.parse_dimension_specs(node.entity_decls):
1101
- if shape is not None:
1102
- assert name not in scope.dim_map
1103
- scope.dim_map[name] = shape
1104
- scope.use_name(name)
1105
-
1106
- assert name not in scope.type_map
1107
- scope.type_map[name] = tp
1108
-
1109
- return []
1110
-
1111
- map_Logical = map_type_decl
1112
- map_Integer = map_type_decl
1113
- map_Real = map_type_decl
1114
- map_Complex = map_type_decl
1115
-
1116
- def map_Dimension(self, node):
1117
- scope = self.scope_stack[-1]
1118
-
1119
- for name, shape in self.parse_dimension_specs(node.items):
1120
- if shape is not None:
1121
- assert name not in scope.dim_map
1122
- scope.dim_map[name] = shape
1123
- scope.use_name(name)
1124
-
1125
- return []
1126
-
1127
- def map_External(self, node):
1128
- raise NotImplementedError("external")
1129
-
1130
- # }}}
1131
-
1132
- def map_Data(self, node):
1133
- scope = self.scope_stack[-1]
1134
-
1135
- for name, data in node.stmts:
1136
- name, = name
1137
- assert name not in scope.data
1138
- scope.data[name] = [self.parse_expr(i) for i in data]
1139
-
1140
- return []
1141
-
1142
- def map_Parameter(self, node):
1143
- raise NotImplementedError("parameter")
1144
-
1145
- # {{{ I/O
1146
-
1147
- def map_Open(self, node):
1148
- raise NotImplementedError
1149
-
1150
- def map_Format(self, node):
1151
- warn("'format' unsupported", TranslatorWarning)
1152
-
1153
- def map_Write(self, node):
1154
- warn("'write' unsupported", TranslatorWarning)
1155
-
1156
- def map_Print(self, node):
1157
- warn("'print' unsupported", TranslatorWarning)
1158
-
1159
- def map_Read1(self, node):
1160
- warn("'read' unsupported", TranslatorWarning)
1161
-
1162
- # }}}
1163
-
1164
- def map_Assignment(self, node):
1165
- lhs = self.parse_expr(node.variable)
1166
- from pymbolic.primitives import Subscript
1167
- if isinstance(lhs, Subscript):
1168
- lhs_name = lhs.aggregate.name
1169
- else:
1170
- lhs_name = lhs.name
1171
-
1172
- scope = self.scope_stack[-1]
1173
- scope.use_name(lhs_name)
1174
- infer_type = scope.get_type_inference_mapper()
1175
-
1176
- rhs = self.parse_expr(node.expr)
1177
- lhs_dtype = infer_type(lhs)
1178
- rhs_dtype = infer_type(rhs)
1179
-
1180
- # check for silent truncation of complex
1181
- if lhs_dtype.kind != "c" and rhs_dtype.kind == "c":
1182
- from pymbolic import var
1183
- rhs = var("real")(rhs)
1184
- # check for silent widening of real
1185
- if lhs_dtype.kind == "c" and rhs_dtype.kind != "c":
1186
- from pymbolic import var
1187
- rhs = var("fromreal")(rhs)
1188
-
1189
- return cgen.Assign(self.gen_expr(lhs), self.gen_expr(rhs))
1190
-
1191
- def map_Allocate(self, node):
1192
- raise NotImplementedError("allocate")
1193
-
1194
- def map_Deallocate(self, node):
1195
- raise NotImplementedError("deallocate")
1196
-
1197
- def map_Save(self, node):
1198
- raise NotImplementedError("save")
1199
-
1200
- def map_Line(self, node):
1201
- #from warnings import warn
1202
- #warn("Encountered a 'line': %s" % node)
1203
- raise NotImplementedError
1204
-
1205
- def map_Program(self, node):
1206
- raise NotImplementedError
1207
-
1208
- def map_Entry(self, node):
1209
- raise NotImplementedError
1210
-
1211
- # {{{ control flow
1212
-
1213
- def map_Goto(self, node):
1214
- return cgen.Statement("goto label_%s" % node.label)
1215
-
1216
- def map_Call(self, node):
1217
- def transform_arg(i, arg_str):
1218
- expr = self.parse_expr(arg_str)
1219
- result = self.gen_expr(expr)
1220
- if self.arg_needs_pointer(node.designator, i):
1221
- result = "&"+result
1222
-
1223
- cast = self.force_casts.get(
1224
- (node.designator, i))
1225
- if cast is not None:
1226
- result = f"({cast}) ({result})"
1227
-
1228
- return result
1229
-
1230
- return cgen.Statement("{}({})".format(
1231
- node.designator,
1232
- ", ".join(transform_arg(i, arg_str)
1233
- for i, arg_str in enumerate(node.items))))
1234
-
1235
- def map_Return(self, node):
1236
- return cgen.Statement("return")
1237
-
1238
- def map_ArithmeticIf(self, node):
1239
- raise NotImplementedError
1240
-
1241
- def map_If(self, node):
1242
- return cgen.If(self.transform_expr(node.expr),
1243
- self.rec(node.content[0]))
1244
-
1245
- def map_IfThen(self, node):
1246
- current_cond = self.transform_expr(node.expr)
1247
-
1248
- blocks_and_conds = []
1249
- else_block = []
1250
-
1251
- def end_block():
1252
- if current_body:
1253
- if current_cond is None:
1254
- else_block[:] = self.map_statement_list(current_body)
1255
- else:
1256
- blocks_and_conds.append(
1257
- (current_cond, cgen.block_if_necessary(
1258
- self.map_statement_list(current_body))))
1259
-
1260
- del current_body[:]
1261
-
1262
- from fparser.statements import Else, ElseIf
1263
- i = 0
1264
- current_body = []
1265
- while i < len(node.content):
1266
- c = node.content[i]
1267
- if isinstance(c, ElseIf):
1268
- end_block()
1269
- current_cond = self.transform_expr(c.expr)
1270
- elif isinstance(c, Else):
1271
- end_block()
1272
- current_cond = None
1273
- else:
1274
- current_body.append(c)
1275
-
1276
- i += 1
1277
- end_block()
1278
-
1279
- def block_or_none(body):
1280
- if not body:
1281
- return None
1282
- else:
1283
- return cgen.block_if_necessary(body)
1284
-
1285
- return cgen.make_multiple_ifs(
1286
- blocks_and_conds,
1287
- block_or_none(else_block))
1288
-
1289
- def map_EndIfThen(self, node):
1290
- return []
1291
-
1292
- def map_Do(self, node):
1293
- scope = self.scope_stack[-1]
1294
-
1295
- body = self.map_statement_list(node.content)
1296
-
1297
- if node.loopcontrol:
1298
- loop_var, loop_bounds = node.loopcontrol.split("=")
1299
- loop_var = loop_var.strip()
1300
- scope.use_name(loop_var)
1301
- loop_bounds = [self.parse_expr(s) for s in loop_bounds.split(",")]
1302
-
1303
- if len(loop_bounds) == 2:
1304
- start, stop = loop_bounds
1305
- step = 1
1306
- elif len(loop_bounds) == 3:
1307
- start, stop, step = loop_bounds
1308
- else:
1309
- raise RuntimeError("loop bounds not understood: %s"
1310
- % node.loopcontrol)
1311
-
1312
- if not isinstance(step, int):
1313
- print(type(step))
1314
- raise TranslationError(
1315
- "non-constant steps not yet supported: %s" % step)
1316
-
1317
- if step < 0:
1318
- comp_op = ">="
1319
- else:
1320
- comp_op = "<="
1321
-
1322
- return cgen.For(
1323
- "{} = {}".format(loop_var, self.gen_expr(start)),
1324
- "{} {} {}".format(loop_var, comp_op, self.gen_expr(stop)),
1325
- "{} += {}".format(loop_var, self.gen_expr(step)),
1326
- cgen.block_if_necessary(body))
1327
-
1328
- else:
1329
- raise NotImplementedError("unbounded do loop")
1330
-
1331
- def map_EndDo(self, node):
1332
- return []
1333
-
1334
- def map_Continue(self, node):
1335
- return cgen.Statement("label_%s:" % node.label)
1336
-
1337
- def map_Stop(self, node):
1338
- raise NotImplementedError("stop")
1339
-
1340
- def map_Comment(self, node):
1341
- if node.content:
1342
- return cgen.LineComment(node.content.strip())
1343
- else:
1344
- return []
1345
-
1346
- # }}}
1347
-
1348
- # }}}
1349
-
1350
- # {{{ expressions
1351
-
1352
- def gen_expr(self, expr):
1353
- scope = self.scope_stack[-1]
1354
- return CCodeMapper(self, scope)(expr)
1355
-
1356
- def transform_expr(self, expr_str):
1357
- return self.gen_expr(self.expr_parser(expr_str))
1358
-
1359
- # }}}
1360
-
1361
- # }}}
1362
-
1363
-
1364
- def f2cl(source, free_form=False, strict=True,
1365
- addr_space_hints={}, force_casts={},
1366
- do_arg_analysis=True,
1367
- use_restrict_pointers=False,
1368
- try_compile=False):
1369
- from fparser import api
1370
- tree = api.parse(source, isfree=free_form, isstrict=strict,
1371
- analyze=False, ignore_comments=False)
1372
-
1373
- arg_info = ArgumentAnalayzer()
1374
- if do_arg_analysis:
1375
- arg_info(tree)
1376
-
1377
- source = F2CLTranslator(addr_space_hints, force_casts,
1378
- arg_info, use_restrict_pointers=use_restrict_pointers)(tree)
1379
-
1380
- func_decls = []
1381
- for entry in source:
1382
- if isinstance(entry, cgen.FunctionBody):
1383
- func_decls.append(entry.fdecl)
1384
-
1385
- mod = cgen.Module(func_decls + [cgen.Line()] + source)
1386
-
1387
- #open("pre-cnd.cl", "w").write(str(mod))
1388
-
1389
- from cnd import transform_cl
1390
- str_mod = transform_cl(str(mod))
1391
-
1392
- if try_compile:
1393
- import pyopencl as cl
1394
- ctx = cl.create_some_context()
1395
- cl.Program(ctx, """
1396
- #if __OPENCL_VERSION__ <= CL_VERSION_1_1
1397
- #pragma OPENCL EXTENSION cl_khr_fp64: enable
1398
- #endif
1399
- #include <pyopencl-complex.h>
1400
- """).build()
1401
- return str_mod
1402
-
1403
-
1404
- def f2cl_files(source_file, target_file, **kwargs):
1405
- mod = f2cl(open(source_file).read(), **kwargs)
1406
- open(target_file, "w").write(mod)
1407
-
1408
-
1409
- if __name__ == "__main__":
1410
- import logging
1411
- console = logging.StreamHandler()
1412
- console.setLevel(logging.DEBUG)
1413
- formatter = logging.Formatter("%(name)-12s: %(levelname)-8s %(message)s")
1414
- console.setFormatter(formatter)
1415
- logging.getLogger("fparser").addHandler(console)
1416
-
1417
- from cgen.opencl import CLConstant
1418
-
1419
- if 0:
1420
- f2cl_files("hank107.f", "hank107.cl",
1421
- addr_space_hints={
1422
- ("hank107p", "p"): CLConstant,
1423
- ("hank107pc", "p"): CLConstant,
1424
- },
1425
- force_casts={
1426
- ("hank107p", 0): "__constant cdouble_t *",
1427
- })
1428
-
1429
- f2cl_files("cdjseval2d.f", "cdjseval2d.cl")
1430
-
1431
- f2cl_files("hank103.f", "hank103.cl",
1432
- addr_space_hints={
1433
- ("hank103p", "p"): CLConstant,
1434
- ("hank103pc", "p"): CLConstant,
1435
- },
1436
- force_casts={
1437
- ("hank103p", 0): "__constant cdouble_t *",
1438
- },
1439
- try_compile=True)
1440
-
1441
- # vim: foldmethod=marker