carray-jit 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +10 -0
  3. data/CHANGELOG.md +84 -0
  4. data/LICENSE +21 -0
  5. data/README.md +88 -0
  6. data/bin/carray-jit +194 -0
  7. data/carray-jit.gemspec +41 -0
  8. data/docs/00_Introduction.md +40 -0
  9. data/docs/01_GettingStarted.md +80 -0
  10. data/docs/02_KernelShapes.md +397 -0
  11. data/docs/03_SupportedFeatures.md +595 -0
  12. data/docs/04_Compiling.md +234 -0
  13. data/docs/05_DesignNotes.md +136 -0
  14. data/docs/06_Cheatsheet.md +177 -0
  15. data/examples/README.md +56 -0
  16. data/examples/applications/game_of_life.rb +161 -0
  17. data/examples/applications/heat_equation.rb +117 -0
  18. data/examples/applications/kepler.rb +178 -0
  19. data/examples/applications/mandelbrot.rb +151 -0
  20. data/examples/applications/moving_average.rb +124 -0
  21. data/examples/applications/partial_sums.rb +141 -0
  22. data/examples/applications/point_cloud.rb +110 -0
  23. data/examples/applications/quicksort.rb +118 -0
  24. data/examples/applications/recursion.rb +121 -0
  25. data/examples/applications/relaxation.rb +115 -0
  26. data/examples/applications/sensor_gaps.rb +118 -0
  27. data/examples/applications/sieve.rb +95 -0
  28. data/examples/applications/sobel_edges.rb +80 -0
  29. data/examples/features/01_element_wise.rb +69 -0
  30. data/examples/features/02_stencil.rb +40 -0
  31. data/examples/features/03_recurrence.rb +50 -0
  32. data/examples/features/04_thomas.rb +81 -0
  33. data/examples/features/05_reduction.rb +90 -0
  34. data/examples/features/06_jit_contract.rb +58 -0
  35. data/examples/features/07_masks.rb +55 -0
  36. data/examples/features/08_views.rb +46 -0
  37. data/examples/features/09_inspecting.rb +55 -0
  38. data/examples/features/10_complex.rb +107 -0
  39. data/examples/features/11_c_functions.rb +260 -0
  40. data/examples/features/12_sweep.rb +139 -0
  41. data/examples/features/13_cscalar.rb +80 -0
  42. data/examples/features/14_stencil_window.rb +106 -0
  43. data/examples/features/15_loops.rb +148 -0
  44. data/examples/features/16_raising.rb +69 -0
  45. data/ext/carray_jit_access/carray_jit_access.c +460 -0
  46. data/ext/carray_jit_access/extconf.rb +8 -0
  47. data/lib/carray/jit/analyzer.rb +1847 -0
  48. data/lib/carray/jit/block_reader.rb +139 -0
  49. data/lib/carray/jit/c_function.rb +777 -0
  50. data/lib/carray/jit/c_generator.rb +2305 -0
  51. data/lib/carray/jit/compiler.rb +468 -0
  52. data/lib/carray/jit/errors.rb +37 -0
  53. data/lib/carray/jit/expression.rb +202 -0
  54. data/lib/carray/jit/kernel.rb +509 -0
  55. data/lib/carray/jit/node.rb +573 -0
  56. data/lib/carray/jit/sweep.rb +97 -0
  57. data/lib/carray/jit/type_assignment.rb +811 -0
  58. data/lib/carray/jit/version.rb +5 -0
  59. data/lib/carray/jit.rb +1210 -0
  60. metadata +139 -0
@@ -0,0 +1,2305 @@
1
+ require "digest"
2
+
3
+ class CArray
4
+ module JIT
5
+
6
+ # Emits C for a typed kernel body.
7
+ #
8
+ # The output is meant to be read: real indentation, the same variable
9
+ # names the block used, and casts only where a type actually changes.
10
+ # `CARRAY_JIT_DUMP=1` prints it.
11
+ #
12
+ # Every kernel has the same C signature, so one Fiddle::Function shape
13
+ # serves all of them; the per-kernel detail is unpacked into named locals
14
+ # at the top of the body, where it also reads better.
15
+ class CGenerator
16
+
17
+ STORAGE_C_TYPES = {
18
+ "float64" => "double",
19
+ "float32" => "float",
20
+ "int64" => "int64_t",
21
+ "int32" => "int32_t",
22
+ "int16" => "int16_t",
23
+ "int8" => "int8_t",
24
+ "uint64" => "uint64_t",
25
+ "uint32" => "uint32_t",
26
+ "uint16" => "uint16_t",
27
+ "uint8" => "uint8_t",
28
+ "boolean" => "uint8_t",
29
+ # C99 lays a complex out as two reals in order, which is what CArray
30
+ # stores, so a cell is read in place rather than assembled.
31
+ "cmplx64" => "float _Complex",
32
+ "cmplx128" => "double _Complex",
33
+ }.freeze
34
+
35
+ COMPUTATION_C_TYPES = {
36
+ :double => "double",
37
+ :float => "float",
38
+ :int64 => "int64_t",
39
+ :uint64 => "uint64_t",
40
+ :complex => "double _Complex",
41
+ :float_complex => "float _Complex",
42
+ :boolean => "int",
43
+ }.freeze
44
+
45
+ # How far each numeric type has to be widened to reach another, taken
46
+ # from the order they widen in. Only widening is ever emitted: nothing
47
+ # narrows a complex back to a real without the block having asked for
48
+ # it by name.
49
+ NUMERIC_RANK =
50
+ TypeAssignment::NUMERIC_TYPES.each_with_index.to_h.freeze
51
+
52
+ FUNCTION_NAME = "carray_jit_kernel"
53
+
54
+ # The frame's own entry point. Same signature, same statements, and
55
+ # the reads carry the border rule; the caller walks it over the boxes
56
+ # the interior left, so nothing here has to know which cell is which.
57
+ BORDER_NAME = "carray_jit_border"
58
+
59
+ # `functions` carries the address of each C function the block called,
60
+ # beside the captured scalars: the kernel is not linked against them, so
61
+ # a compiled kernel does not depend on where they came from.
62
+ # `functions` carries the address of each C function the block called and
63
+ # `data` the address of each array it handed to one whole. Both sit
64
+ # beside the captured scalars for the same reason: they do not vary with
65
+ # the cell, and the kernel is not linked against either.
66
+ SIGNATURE =
67
+ "(char **pointers, int64_t *strides, int64_t *bounds, " \
68
+ "double *reals, int64_t *integers, void **functions, void **data, " \
69
+ "char **mask_pointers, int64_t *mask_strides, int32_t *error)".freeze
70
+
71
+ ARGUMENTS =
72
+ "pointers, strides, bounds, reals, integers, functions, data, " \
73
+ "mask_pointers, mask_strides, error".freeze
74
+
75
+ # Higher binds tighter. Used to parenthesize only where C would
76
+ # otherwise regroup the expression.
77
+ # C's precedence, not Ruby's: the tree comes from Prism, and what this
78
+ # table decides is where the parentheses go on the way out.
79
+ PRECEDENCE = {
80
+ :* => 80, :/ => 80,
81
+ :+ => 70, :- => 70,
82
+ :<< => 65, :>> => 65,
83
+ :< => 60, :<= => 60, :> => 60, :>= => 60,
84
+ :== => 55, :!= => 55,
85
+ :& => 52,
86
+ :^ => 50,
87
+ :| => 48,
88
+ :"&&" => 40,
89
+ :"||" => 35,
90
+ }.freeze
91
+
92
+ LEAF_PRECEDENCE = 100
93
+ UNARY_PRECEDENCE = 90
94
+
95
+ # cmplx64's helpers are the same helpers in the narrower width, so they
96
+ # are written once and spelled twice rather than kept in step by hand.
97
+ # The substitution is textual and the order matters -- `double _Complex`
98
+ # before `double` -- which is why it is a list and not a hash.
99
+ NARROW_COMPLEX_SPELLING = [
100
+ ["double _Complex", "float _Complex"],
101
+ ["carray_jit_", "carray_jit_f_"],
102
+ ["creal", "crealf"], ["cimag", "cimagf"],
103
+ ["CMPLX(", "CMPLXF("], ["fabs(", "fabsf("],
104
+ ["double", "float"], ["1.0", "1.0f"], ["0.0", "0.0f"],
105
+ ].freeze
106
+
107
+ def self.narrowed_complex_helper (text)
108
+ NARROW_COMPLEX_SPELLING.reduce(text) { |source, (wide, narrow)|
109
+ source.gsub(wide, narrow)
110
+ }
111
+ end
112
+
113
+ # The complex operations Ruby does not compute the way C's operators
114
+ # would. Only the ones a kernel actually uses are emitted, and the
115
+ # reason each exists is at emit_complex_binary.
116
+ COMPLEX_HELPERS = {
117
+ "complex_add_real" => <<~C,
118
+ /* Ruby leaves the imaginary part of `z + x` exactly as it was,
119
+ rather than adding the real operand's zero to it. */
120
+ static inline double _Complex
121
+ carray_jit_complex_add_real (double _Complex z, double x)
122
+ {
123
+ return CMPLX(creal(z) + x, cimag(z));
124
+ }
125
+ C
126
+ "real_add_complex" => <<~C,
127
+ /* And the same the other way round: `x + z` leaves it alone too. */
128
+ static inline double _Complex
129
+ carray_jit_real_add_complex (double x, double _Complex z)
130
+ {
131
+ return CMPLX(x + creal(z), cimag(z));
132
+ }
133
+ C
134
+ "complex_add_imaginary" => <<~C,
135
+ /* `z + 2i` adds to one part and leaves the other, for the same
136
+ reason: the literal's real part is an exact zero. */
137
+ static inline double _Complex
138
+ carray_jit_complex_add_imaginary (double _Complex z, double y)
139
+ {
140
+ return CMPLX(creal(z), cimag(z) + y);
141
+ }
142
+ C
143
+ "imaginary_add_complex" => <<~C,
144
+ static inline double _Complex
145
+ carray_jit_imaginary_add_complex (double y, double _Complex z)
146
+ {
147
+ return CMPLX(creal(z), y + cimag(z));
148
+ }
149
+ C
150
+ "complex_mul_real" => <<~C,
151
+ /* `z * x` scales each part. `x * z` does not -- Ruby coerces the
152
+ x and multiplies in full -- so it is left to C's operator. */
153
+ static inline double _Complex
154
+ carray_jit_complex_mul_real (double _Complex z, double x)
155
+ {
156
+ return CMPLX(creal(z) * x, cimag(z) * x);
157
+ }
158
+ C
159
+ "complex_div_real" => <<~C,
160
+ static inline double _Complex
161
+ carray_jit_complex_div_real (double _Complex z, double x)
162
+ {
163
+ return CMPLX(creal(z) / x, cimag(z) / x);
164
+ }
165
+ C
166
+ "complex_divide" => <<~C,
167
+ /* Ruby divides one Complex by another with Smith's method, and so
168
+ does this -- in the order complex.c writes it, because the last
169
+ bit of the answer depends on that order and the C library's own
170
+ __divdc3 arrives at a different one. */
171
+ static inline double _Complex
172
+ carray_jit_complex_divide (double _Complex a, double _Complex b)
173
+ {
174
+ double are = creal(a), aim = cimag(a);
175
+ double bre = creal(b), bim = cimag(b);
176
+ double r, n;
177
+ if ( fabs(bre) > fabs(bim) ) {
178
+ r = bim / bre;
179
+ n = bre * (1.0 + r * r);
180
+ return CMPLX((are + aim * r) / n, (aim - are * r) / n);
181
+ }
182
+ r = bre / bim;
183
+ n = bim * (1.0 + r * r);
184
+ return CMPLX((are * r + aim) / n, (aim * r - are) / n);
185
+ }
186
+ C
187
+ "real_divide_complex" => <<~C,
188
+ /* The same method for a real numerator, which Ruby coerces to a
189
+ Complex whose imaginary part is an exact Integer zero. That
190
+ zero multiplies like a float -- `0 * r` carries r's sign -- but
191
+ adds like an exact one, which f_add returns the other operand
192
+ for. So `+ 0.0 * r` appears on one branch and not on the other,
193
+ and the signs of the zeros in the answer depend on it. */
194
+ static inline double _Complex
195
+ carray_jit_real_divide_complex (double a, double _Complex b)
196
+ {
197
+ double bre = creal(b), bim = cimag(b);
198
+ double r, n;
199
+ if ( fabs(bre) > fabs(bim) ) {
200
+ r = bim / bre;
201
+ n = bre * (1.0 + r * r);
202
+ return CMPLX((a + 0.0 * r) / n, (0.0 - a * r) / n);
203
+ }
204
+ r = bre / bim;
205
+ n = bim * (1.0 + r * r);
206
+ return CMPLX(a * r / n, (0.0 * r - a) / n);
207
+ }
208
+ C
209
+ }.freeze
210
+
211
+ # What an accumulator starts from, per computation type. A complex sum
212
+ # starts from a complex zero: CMPLX carries the sign of both zeros,
213
+ # which a plain 0.0 widened to complex would not.
214
+ ZEROES = {
215
+ :int64 => "INT64_C(0)",
216
+ :float => "0.0f",
217
+ :uint64 => "UINT64_C(0)",
218
+ :double => "0.0",
219
+ :complex => "CMPLX(0.0, 0.0)",
220
+ :float_complex => "CMPLXF(0.0f, 0.0f)",
221
+ }.freeze
222
+
223
+ # What a product accumulator starts from, for the same reason.
224
+ ONES = {
225
+ :int64 => "INT64_C(1)",
226
+ :float => "1.0f",
227
+ :uint64 => "UINT64_C(1)",
228
+ :double => "1.0",
229
+ :complex => "CMPLX(1.0, 0.0)",
230
+ :float_complex => "CMPLXF(1.0f, 0.0f)",
231
+ }.freeze
232
+
233
+ # How many partial accumulators a licensed reduction runs. A serial
234
+ # accumulator is one dependent chain of additions and waits out the
235
+ # latency of each; eight of them fill it. Measured over row sums and a
236
+ # matrix multiply, eight is where the gain stops growing.
237
+ #
238
+ # The number is here, and the order it implies is written into the C,
239
+ # rather than left to the compiler's unroller: this gem compiles on the
240
+ # machine it runs on, so a schedule chosen by the compiler would vary
241
+ # with the machine and with nothing in the source saying so.
242
+ PARTIAL_ACCUMULATORS = 8
243
+
244
+ BORDER_RULES = [:zero, :clamp, :wrap].freeze
245
+
246
+ def initialize (analyzer, storage_types, scalar_types, c_functions: {},
247
+ masked: false, reassociate: false,
248
+ steps: nil, origin: nil, block_source: nil, border: nil)
249
+ @masked = masked
250
+ # What a window read gets where it falls off the array. Nil for every
251
+ # kernel but a stencil's, and for a stencil whose border is the frame
252
+ # rather than a rule -- `:mask` and `:skip` are cells the loop never
253
+ # reaches, and a cell not reached needs no C.
254
+ @border = border
255
+ # True while the border body is being emitted, which is the same
256
+ # statements as the interior with the rule woven into the reads.
257
+ @bordering = false
258
+ @reassociate = reassociate
259
+ @steps = steps || Array.new(analyzer.rank, 1)
260
+ @analyzer = analyzer
261
+ @storage_types = storage_types
262
+ @scalar_types = scalar_types
263
+ @arrays = analyzer.arrays_used.sort
264
+ # Arrays no longer share a rank, so each one's strides start where the
265
+ # previous one's left off.
266
+ @stride_offsets = {}
267
+ position = 0
268
+ @arrays.each do |array|
269
+ @stride_offsets[array] = position
270
+ position += analyzer.array_ranks.fetch(array, analyzer.rank)
271
+ end
272
+ @array_ranks = analyzer.array_ranks
273
+ @reals = analyzer.scalar_names.select { |name| scalar_types[name] == :double }.sort
274
+ @integers = analyzer.scalar_names.select { |name| scalar_types[name] == :int64 }.sort
275
+ # A captured Complex rides in the reals buffer as its two parts, so
276
+ # that the kernel signature stays the one shape every kernel has.
277
+ @complexes = analyzer.scalar_names.select { |name| scalar_types[name] == :complex }.sort
278
+ # Three buses and no fourth: a capture whose type is none of these
279
+ # would be packed into nothing and read as whatever the slot held, so
280
+ # it is caught here rather than at the cell it computes wrongly.
281
+ carried = @reals.size + @integers.size + @complexes.size
282
+ unless carried == analyzer.scalar_names.size
283
+ missing = analyzer.scalar_names - @reals - @integers - @complexes
284
+ raise Error,
285
+ "captured #{missing.join(", ")} travel in none of the kernel's " \
286
+ "three scalar buses; a computation type was added without a " \
287
+ "way to hand a value of it to the C"
288
+ end
289
+ # Only the ones the block actually called, in a fixed order, because
290
+ # the caller packs the addresses into `functions` by this order.
291
+ @c_functions = analyzer.c_function_names.sort.to_h { |name| [name, c_functions.fetch(name)] }
292
+ # A function written here is pasted into this kernel and called by its
293
+ # symbol; a borrowed one arrives as an address. Only the second kind
294
+ # takes a slot in `functions`, so it is that hash the caller packs by.
295
+ pasted, addressed = @c_functions.partition { |_, function| function.pasted? }
296
+ @pasted_functions = pasted.to_h
297
+ @address_functions = addressed.to_h
298
+ # Arrays handed to a C function whole, in a fixed order, because the
299
+ # caller packs their addresses into `data` by this order.
300
+ @address_arrays = analyzer.address_arrays.sort
301
+ @address_parameters = analyzer.address_parameters
302
+ @rank = analyzer.rank
303
+ # Every axis some array is read at a computed index. Each needs its
304
+ # extent inside the kernel, to check the index against as it is
305
+ # reached; they ride in after the captured integers.
306
+ @extent_slots = @arrays.flat_map { |array|
307
+ axes = analyzer.dynamic_axes(array)
308
+ # A border rule is applied against the extent, so a windowed array
309
+ # needs every one of its axes here -- the same slots a computed
310
+ # subscript already rides in, asked for by a different question.
311
+ if @border && analyzer.windows.include?(array)
312
+ axes |= (0...array_rank_of(analyzer, array)).to_a
313
+ end
314
+ axes.sort.map { |axis| [array, axis] }
315
+ }
316
+ @uses_index_check = false
317
+ @body_reports = false
318
+ @uses_clamp = false
319
+ @uses_wrap = false
320
+ @uses_real_arg = false
321
+ @complex_helpers = []
322
+ @uses_floor_divide = false
323
+ @uses_floor_modulo = false
324
+ @uses_integer_power = false
325
+ @uses_unsigned_divide = false
326
+ @uses_unsigned_modulo = false
327
+ @uses_unsigned_power = false
328
+ @uses_floor_modulo_float = false
329
+ @contiguous = false
330
+ @in_function = false
331
+ @uses_error_flag = false
332
+ @error_parameter = false
333
+ @masked_flag = nil
334
+ @carried_masks = []
335
+ # What `raise` in the block said, by the code a cell writes into the
336
+ # error slot to say which one it was -- and what the bodies pasted in
337
+ # here can say, since their codes come back through the same slot and
338
+ # this kernel is what answers for them. The codes agree because they
339
+ # are taken from the messages, not counted off.
340
+ @raise_messages = {}
341
+ @pasted_functions.each_value do |function|
342
+ (function.raise_messages || {}).each do |code, message|
343
+ register_raise(code, message)
344
+ end
345
+ end
346
+ @position_temporaries = {}.compare_by_identity
347
+ @origin = origin
348
+ @block_source = block_source
349
+ end
350
+
351
+ attr_reader :arrays, :reals, :integers, :complexes, :masked, :extent_slots,
352
+ :c_functions, :pasted_functions, :address_functions,
353
+ :address_arrays, :address_parameters,
354
+ # The messages `raise` in the block gave, by the code a cell
355
+ # writes into the error slot to say which one it was.
356
+ :raise_messages
357
+
358
+ # Whether the compiled function reports through the flag, so the caller
359
+ # knows whether to look the symbol up.
360
+ def uses_error_flag?
361
+ @uses_error_flag
362
+ end
363
+
364
+ def generate
365
+ strided = build_body(false)
366
+ contiguous = build_body(true)
367
+ # The frame is walked strided, whatever the operands are: it is a
368
+ # handful of boxes cut out of the array, and the innermost of them is
369
+ # not the run of cells the contiguous path is for.
370
+ border = @border ? bordered_body : nil
371
+ preamble +
372
+ "static void\ncarray_jit_strided #{SIGNATURE}\n" + strided + "\n" +
373
+ "static void\ncarray_jit_contiguous #{SIGNATURE}\n" + contiguous + "\n" +
374
+ dispatcher +
375
+ (border ? "\nvoid\n#{BORDER_NAME} #{SIGNATURE}\n" + border : "")
376
+ end
377
+
378
+ # The same tree a third time. `generate` already emits it twice, for
379
+ # the contiguous and strided ways of reaching a cell; the border is the
380
+ # third way, and differs only in what a read that falls off the array
381
+ # gives. Nothing about the loop changes -- the caller says which cells.
382
+ def bordered_body
383
+ @bordering = true
384
+ build_body(false)
385
+ ensure
386
+ @bordering = false
387
+ end
388
+
389
+ # A scalar C function: no buffers, no loop, no dispatcher. The body is
390
+ # the same statements the kernel path emits -- what differs is only what
391
+ # surrounds them, which is why the expression emitter below is shared
392
+ # rather than written twice.
393
+ # `error_parameter` generates the form a kernel pastes: the flag arrives
394
+ # as a trailing `int32_t *` rather than standing in the file, so the body
395
+ # reports into whatever the caller is watching. The standalone object
396
+ # keeps the other form -- it is what `CFunction#call` reads, and what a
397
+ # library handed the address calls without knowing about any of this.
398
+ def generate_function (name, parameter_names, parameter_c_types,
399
+ return_c_type, return_type, error_parameter: false)
400
+ @own_symbol = name
401
+ @in_function = true
402
+ @error_parameter = error_parameter
403
+ @contiguous = true
404
+ @declared_locals = {}
405
+ @temporary_count = 0
406
+ @carried_masks = []
407
+ statements = @analyzer.body.statements
408
+ # A `void` body has no last expression to return: every statement in
409
+ # it is a statement, and what it did is where its pointers pointed.
410
+ @returns_nothing = return_type.nil?
411
+ held = @returns_nothing ? statements : statements[0..-2]
412
+ lines = held.map { |statement| emit_statement(statement, " ") }.join
413
+ value = @returns_nothing ? nil : emit(statements.last, return_type)
414
+ parameters = parameter_names.zip(parameter_c_types)
415
+ .map { |parameter, type| type.declare(parameter) }
416
+ # Passed whether or not the body turned out to use it, so that a
417
+ # recursive call emitted before the first division still passes the
418
+ # same argument list the definition ends up declaring.
419
+ parameters << "int32_t *#{ERROR_FLAG}" if error_parameter
420
+ parameters = ["void"] if parameters.empty?
421
+ flag = @uses_error_flag && !error_parameter ? error_flag_declaration : ""
422
+ # Kept apart from the file it is compiled in: the definition alone is
423
+ # what a kernel pastes into its own translation unit, where the
424
+ # includes are already written and the helpers are shared.
425
+ @function_definition =
426
+ "#{return_c_type}\n#{name} (#{parameters.join(', ')})\n{\n" +
427
+ lines + (@returns_nothing ? "}\n" : " return #{value};\n}\n")
428
+ preamble + flag + @function_definition
429
+ end
430
+
431
+ attr_reader :function_definition
432
+
433
+ # What the body took from the preamble, so that a definition pasted
434
+ # somewhere else can be given the same helpers. Only the ones a pasted
435
+ # function can want are here: the rest -- the index check, the two
436
+ # flooring helpers -- report through the error flag, and a function that
437
+ # touches the flag is not pasted at all.
438
+ def helper_needs
439
+ { :integer_power => @uses_integer_power,
440
+ :unsigned_divide => @uses_unsigned_divide,
441
+ :unsigned_modulo => @uses_unsigned_modulo,
442
+ :unsigned_power => @uses_unsigned_power,
443
+ :floor_modulo_float => @uses_floor_modulo_float,
444
+ :real_arg => @uses_real_arg,
445
+ :complex => @complex_helpers.dup,
446
+ :index_check => @uses_index_check,
447
+ :floor_divide => @uses_floor_divide,
448
+ :floor_modulo => @uses_floor_modulo }
449
+ end
450
+
451
+ # One per compiled object, so two functions never share it, and zeroed
452
+ # by whoever is about to look -- the same discipline the kernel's own
453
+ # error slot keeps. It is written only where the value returned is
454
+ # already a stand-in, so a caller that never looks is no worse off than
455
+ # C leaves it.
456
+ def error_flag_declaration
457
+ "/* Standing at 1 when a division had no divisor, and at the code of\n" \
458
+ " a `raise` in the body where one was reached -- the numbers a\n" \
459
+ " kernel reports through its own slot, with the same meanings. A\n" \
460
+ " subscript on a pointer parameter is not checked here and does not\n" \
461
+ " appear: it is the caller's business, as it is in C. */\n" \
462
+ "int32_t #{ERROR_FLAG} = 0;\n\n"
463
+ end
464
+
465
+ # The same kernel, wrapped so carray can drive it.
466
+ #
467
+ # `ca_call_cslab_N` hands a callback one chunk at a time -- base and
468
+ # stride per operand and a cell count -- which is what this kernel's
469
+ # first three arguments already are, with the bounds of a flat sweep.
470
+ # So the wrapper is a call, not a second code generator: the loop, the
471
+ # arithmetic and the contiguous/strided split are the ones above.
472
+ #
473
+ # The mask is carray's here. It ORs the inputs' masks, propagates the
474
+ # result to the output, and hands the chunk's slice over -- which this
475
+ # ignores, computing every cell as the kernel does anyway, because the
476
+ # bytes under a mask are out of contract and a branchless loop is the
477
+ # point. What carray cannot express is a body that *asks* about a
478
+ # mask, so those do not come this way.
479
+ SLAB_SIGNATURE =
480
+ "(char **base, int64_t *stride, int64_t n, " \
481
+ "const uint8_t *m0, void *userdata)".freeze
482
+
483
+ def generate_slab (name)
484
+ generate + <<~C
485
+
486
+ /* What the sweep cannot carry: the captured values, the C functions
487
+ and the arrays handed to one whole. carray passes one pointer
488
+ through untouched, so they travel behind it. */
489
+ struct carray_jit_slab_context {
490
+ double *reals;
491
+ int64_t *integers;
492
+ void **functions;
493
+ void **data;
494
+ char **mask_pointers;
495
+ int64_t *mask_strides;
496
+ int32_t *error;
497
+ };
498
+
499
+ void
500
+ #{name} #{SLAB_SIGNATURE}
501
+ {
502
+ const struct carray_jit_slab_context *const context = userdata;
503
+ int64_t bounds[3];
504
+ (void) m0;
505
+ bounds[0] = 0;
506
+ bounds[1] = n;
507
+ bounds[2] = 1;
508
+ #{FUNCTION_NAME}(base, stride, bounds,
509
+ context->reals, context->integers,
510
+ context->functions, context->data,
511
+ context->mask_pointers, context->mask_strides,
512
+ context->error);
513
+ }
514
+ C
515
+ end
516
+
517
+ # Where this came from. A generated file that says only what it does is
518
+ # hard to place months later; the block it was written from is short, so
519
+ # it goes in whole, above the C it turned into.
520
+ def provenance
521
+ return "" unless @origin || @block_source
522
+ text = +"/*\n * Generated by carray-jit #{VERSION}.\n"
523
+ text << " *\n * #{@origin}\n" if @origin
524
+ if @block_source
525
+ text << " *\n"
526
+ @block_source.lines.each { |line| text << " * #{line.rstrip}\n" }
527
+ end
528
+ text << " */\n\n"
529
+ text
530
+ end
531
+
532
+ private
533
+
534
+ def preamble
535
+ # A pasted body wants the same helpers here that it had in its own
536
+ # file, and it is emitted below them, so this is asked before any of
537
+ # them is written out.
538
+ @pasted_functions.each_value do |function|
539
+ needs = function.helpers || {}
540
+ @uses_integer_power ||= needs[:integer_power]
541
+ @uses_unsigned_divide ||= needs[:unsigned_divide]
542
+ @uses_unsigned_modulo ||= needs[:unsigned_modulo]
543
+ @uses_unsigned_power ||= needs[:unsigned_power]
544
+ @uses_floor_modulo_float ||= needs[:floor_modulo_float]
545
+ @uses_real_arg ||= needs[:real_arg]
546
+ @complex_helpers |= needs[:complex] || []
547
+ @uses_index_check ||= needs[:index_check]
548
+ @uses_floor_divide ||= needs[:floor_divide]
549
+ @uses_floor_modulo ||= needs[:floor_modulo]
550
+ end
551
+ text = +"#include <stdint.h>\n#include <math.h>\n#include <complex.h>\n" \
552
+ "#include <stdio.h>\n\n"
553
+ unless @address_functions.empty?
554
+ text << "/* The C functions the block called. They arrive as\n" \
555
+ " addresses rather than by linkage, so nothing here says\n" \
556
+ " which library they came from. */\n"
557
+ @address_functions.each_key do |name|
558
+ text << @address_functions.fetch(name).c_declaration(c_function_type_name(name)) << "\n"
559
+ end
560
+ text << "\n"
561
+ end
562
+ if @masked
563
+ text << <<~C
564
+ /* A plain CArray has no mask at all -- one is created only when a
565
+ cell is actually marked -- so an unmasked operand is pointed at
566
+ this single zero byte with a stride of zero. Reading it costs
567
+ a load the compiler hoists, and saves a branch per cell. */
568
+ static const uint8_t carray_jit_present = 0;
569
+
570
+ C
571
+ end
572
+ if @uses_floor_modulo_float
573
+ text << <<~C
574
+ /* The float twin of carray_jit_floor_modulo_real. Going through
575
+ the double one and rounding back would not give the same answer:
576
+ a remainder is the tail of a subtraction, so it is exactly where
577
+ computing wide and narrowing afterwards stops agreeing with
578
+ computing narrow. */
579
+ static inline float
580
+ carray_jit_floor_modulo_float (float numerator, float denominator)
581
+ {
582
+ float remainder = fmodf(numerator, denominator);
583
+ if ( remainder != 0 ) {
584
+ if ( (remainder < 0) != (denominator < 0) ) remainder += denominator;
585
+ }
586
+ else {
587
+ remainder = copysignf(0.0f, denominator);
588
+ }
589
+ return remainder;
590
+ }
591
+
592
+ C
593
+ end
594
+ if @uses_unsigned_power
595
+ text << <<~C
596
+ /* The unsigned twin of carray_jit_integer_power. Squaring in
597
+ uint64_t keeps the wrap CArray's own uint64 operators have,
598
+ where int64_t would take the value through a signed type it
599
+ may not fit. */
600
+ static inline uint64_t
601
+ carray_jit_unsigned_power (uint64_t base, uint64_t exponent)
602
+ {
603
+ uint64_t result = 1;
604
+ while ( exponent ) {
605
+ if ( exponent & 1 ) result *= base;
606
+ base *= base;
607
+ exponent >>= 1;
608
+ }
609
+ return result;
610
+ }
611
+
612
+ C
613
+ end
614
+ if @uses_unsigned_divide
615
+ text << <<~C
616
+ /* An unsigned operand cannot be negative, so C's truncation
617
+ already floors and there is no quotient to correct -- what is
618
+ left of carray_jit_floor_divide is the zero divisor, which is
619
+ reported through *error the same way. */
620
+ static inline uint64_t
621
+ carray_jit_unsigned_divide (uint64_t numerator, uint64_t denominator, int32_t *error)
622
+ {
623
+ if ( denominator == 0 ) {
624
+ if ( error ) *error = 1;
625
+ return 0;
626
+ }
627
+ return numerator / denominator;
628
+ }
629
+
630
+ C
631
+ end
632
+ if @uses_unsigned_modulo
633
+ text << <<~C
634
+ /* Likewise the remainder: with no sign to disagree about, Ruby's
635
+ floored `%` and C's are the same operation. */
636
+ static inline uint64_t
637
+ carray_jit_unsigned_modulo (uint64_t numerator, uint64_t denominator, int32_t *error)
638
+ {
639
+ if ( denominator == 0 ) {
640
+ if ( error ) *error = 1;
641
+ return 0;
642
+ }
643
+ return numerator % denominator;
644
+ }
645
+
646
+ C
647
+ end
648
+ if @uses_integer_power
649
+ text << <<~C
650
+ /* Exponentiation by squaring, so that an integer power is the
651
+ exact integer Ruby would give rather than pow's double. The
652
+ exponent is known non-negative: a negative one gives a Rational
653
+ in Ruby, and is refused. */
654
+ static inline int64_t
655
+ carray_jit_integer_power (int64_t base, int64_t exponent)
656
+ {
657
+ int64_t result = 1;
658
+ while ( exponent > 0 ) {
659
+ if ( exponent & 1 ) result *= base;
660
+ base *= base;
661
+ exponent >>= 1;
662
+ }
663
+ return result;
664
+ }
665
+
666
+ C
667
+ end
668
+ COMPLEX_HELPERS.each do |name, definition|
669
+ [false, true].each do |narrow|
670
+ next unless @complex_helpers.include?([name, narrow])
671
+ text << (narrow ? self.class.narrowed_complex_helper(definition)
672
+ : definition) << "\n"
673
+ end
674
+ end
675
+ if @uses_real_arg
676
+ text << <<~C
677
+ /* The argument of a real number, which Ruby reads off the sign
678
+ bit rather than from a comparison: `-0.0.arg` is pi, where
679
+ `-0.0 < 0` is false. A NaN is its own argument. */
680
+ static inline double
681
+ carray_jit_real_arg (double x)
682
+ {
683
+ if ( isnan(x) ) return x;
684
+ return signbit(x) ? M_PI : 0.0;
685
+ }
686
+
687
+ C
688
+ end
689
+ if @uses_clamp
690
+ text << <<~C
691
+ /* A window that falls off the array reads the nearest cell it
692
+ has: `border: :clamp`. Written as two comparisons rather
693
+ than min/max of a difference, because the extent is what
694
+ decides and it is right there. */
695
+ static inline int64_t
696
+ carray_jit_clamp (int64_t position, int64_t extent)
697
+ {
698
+ if ( position < 0 ) return 0;
699
+ if ( position >= extent ) return extent - 1;
700
+ return position;
701
+ }
702
+
703
+ C
704
+ end
705
+ if @uses_wrap
706
+ text << <<~C
707
+ /* A window that falls off the array comes back on the other
708
+ side: `border: :wrap`. C's `%` truncates toward zero, so a
709
+ negative position needs the extent added back -- the same
710
+ correction the flooring helpers make, for the same reason. */
711
+ static inline int64_t
712
+ carray_jit_wrap (int64_t position, int64_t extent)
713
+ {
714
+ int64_t folded = position % extent;
715
+ return folded < 0 ? folded + extent : folded;
716
+ }
717
+
718
+ C
719
+ end
720
+ if @uses_index_check
721
+ text << <<~C
722
+ /* A subscript the kernel computes is checked as it is reached --
723
+ the one thing about a kernel that cannot be settled before it
724
+ runs. Out of range it reports through *error, which the Ruby
725
+ side turns into the IndexError CArray would have raised, and
726
+ reads cell 0 so that nothing is read outside the array in the
727
+ meantime. */
728
+ static inline int64_t
729
+ carray_jit_index (int64_t position, int64_t extent, int32_t *error)
730
+ {
731
+ if ( position < 0 || position >= extent ) {
732
+ if ( error ) *error = 2;
733
+ return 0;
734
+ }
735
+ return position;
736
+ }
737
+
738
+ C
739
+ end
740
+ if @uses_floor_modulo
741
+ text << <<~C
742
+ /* Ruby's `%` floors with its division: the remainder carries the
743
+ sign of the divisor, where C's `%` and fmod carry the sign of
744
+ the dividend. So add the divisor back when the remainder is
745
+ non-zero and disagrees with it in sign -- and, for floats,
746
+ give a zero remainder the divisor's sign, so the rule holds
747
+ without exception. This mirrors CArray's own `:mod` kernel in
748
+ `ext/mkkernel.rb`. */
749
+ static inline int64_t
750
+ carray_jit_floor_modulo (int64_t numerator, int64_t denominator, int32_t *error)
751
+ {
752
+ if ( denominator == 0 ) {
753
+ if ( error ) *error = 1;
754
+ return 0;
755
+ }
756
+ int64_t remainder = numerator % denominator;
757
+ if ( remainder != 0 && ((remainder < 0) != (denominator < 0)) ) {
758
+ remainder += denominator;
759
+ }
760
+ return remainder;
761
+ }
762
+
763
+ static inline double
764
+ carray_jit_floor_modulo_real (double numerator, double denominator)
765
+ {
766
+ double remainder = fmod(numerator, denominator);
767
+ if ( remainder != 0 ) {
768
+ if ( (remainder < 0) != (denominator < 0) ) remainder += denominator;
769
+ }
770
+ else {
771
+ remainder = copysign(0.0, denominator);
772
+ }
773
+ return remainder;
774
+ }
775
+
776
+ C
777
+ end
778
+ if @uses_floor_divide
779
+ text << <<~C
780
+ /* Ruby and CArray floor integer division and give the remainder the
781
+ sign of the divisor; C truncates toward zero. Correct the C
782
+ quotient by one when the division is inexact and the operands
783
+ disagree in sign. Division by zero cannot raise from here, so it
784
+ is reported through *error and checked on the Ruby side. */
785
+ static inline int64_t
786
+ carray_jit_floor_divide (int64_t numerator, int64_t denominator, int32_t *error)
787
+ {
788
+ if ( denominator == 0 ) {
789
+ /* error is null when the cell being written is masked: the
790
+ value there is out of contract, so a zero that only ever
791
+ feeds a masked cell is not a division by zero the caller
792
+ asked about. */
793
+ if ( error ) *error = 1;
794
+ return 0;
795
+ }
796
+ int64_t quotient = numerator / denominator;
797
+ if ( numerator % denominator != 0 && ((numerator < 0) != (denominator < 0)) ) {
798
+ quotient -= 1;
799
+ }
800
+ return quotient;
801
+ }
802
+
803
+ C
804
+ end
805
+ text << pasted_definitions
806
+ end
807
+
808
+ # The bodies of the functions written with `jit_function`, put in this
809
+ # translation unit as statics and called by name. An address the
810
+ # compiler cannot see through is a call it cannot inline, and the loop
811
+ # around it is one it will not vectorise -- so a function the block
812
+ # named is compiled into the kernel as if the expression had been
813
+ # written out where it is called.
814
+ #
815
+ # `static` because the symbol belongs to this kernel: the same body may
816
+ # already stand in its own object, and in another kernel beside this
817
+ # one. The name carries the digest of the body, so two of them are the
818
+ # same function, and one is pasted once however many names the block
819
+ # reached it by.
820
+ def pasted_definitions
821
+ seen = {}
822
+ text = +""
823
+ @pasted_functions.each_value do |function|
824
+ next if seen[function.name]
825
+ seen[function.name] = true
826
+ text << "/* #{function} */\n" \
827
+ "static #{function.definition}\n"
828
+ end
829
+ text
830
+ end
831
+
832
+ # One compiled object holds both loops and picks between them once,
833
+ # outside the loop. The contiguous form indexes a typed pointer along
834
+ # the innermost axis, which the compiler can vectorise; the strided form
835
+ # cannot be, and is what lets a view run without being copied first.
836
+ def dispatcher
837
+ tests = @arrays.map { |array|
838
+ "strides[#{@stride_offsets.fetch(array) + array_rank(array) - 1}] == " \
839
+ "(int64_t) sizeof(#{storage_c_type(array)})"
840
+ }
841
+ # A kernel reaching no array cell has nothing to be contiguous about
842
+ # -- it can only be one whose work is a call, the arrays it touches
843
+ # arriving whole as addresses. There is one loop then, and asking
844
+ # which to take would be an `if` with nothing in it.
845
+ if tests.empty?
846
+ return <<~C
847
+ void
848
+ #{FUNCTION_NAME} #{SIGNATURE}
849
+ {
850
+ carray_jit_contiguous(#{ARGUMENTS});
851
+ }
852
+ C
853
+ end
854
+ <<~C
855
+ void
856
+ #{FUNCTION_NAME} #{SIGNATURE}
857
+ {
858
+ if ( #{tests.join("\n && ")} ) {
859
+ carray_jit_contiguous(#{ARGUMENTS});
860
+ } else {
861
+ carray_jit_strided(#{ARGUMENTS});
862
+ }
863
+ }
864
+ C
865
+ end
866
+
867
+ def build_body (contiguous)
868
+ @contiguous = contiguous
869
+ @declared_locals = {}
870
+ @temporary_count = 0
871
+ @carried_masks = []
872
+ # Whether this body has a way to report -- asked of the statements
873
+ # themselves rather than of what rides in beside them. A windowed
874
+ # kernel carries every extent of its arrays so the border rule has
875
+ # them, which says nothing about whether a cell can fail.
876
+ @body_reports = false
877
+ statements = @analyzer.body.statements.map { |statement|
878
+ emit_statement(statement, " " + " " * @rank)
879
+ }.join
880
+ "{\n" + declarations + loop_open + statements + loop_close + "}\n"
881
+ end
882
+
883
+ def array_rank (array)
884
+ @array_ranks.fetch(array, @rank)
885
+ end
886
+
887
+ def array_rank_of (analyzer, array)
888
+ analyzer.array_ranks.fetch(array, analyzer.rank)
889
+ end
890
+
891
+ def declarations
892
+ lines = []
893
+ @arrays.each_with_index do |array, index|
894
+ base = @stride_offsets.fetch(array)
895
+ lines << " char *const #{pointer_name(array)} = pointers[#{index}];\n"
896
+ array_rank(array).times do |axis|
897
+ lines << " const int64_t #{stride_name(array, axis)} = " \
898
+ "strides[#{base + axis}];\n"
899
+ end
900
+ next unless @masked
901
+ given = "mask_pointers[#{index}]"
902
+ if @analyzer.written_arrays.include?(array)
903
+ # An array the kernel writes always has a mask by the time it gets
904
+ # here: the caller creates one when any operand carries one.
905
+ lines << " uint8_t *const #{mask_pointer_name(array)} = " \
906
+ "(uint8_t *) #{given};\n"
907
+ array_rank(array).times do |axis|
908
+ lines << " const int64_t #{mask_stride_name(array, axis)} = " \
909
+ "mask_strides[#{base + axis}];\n"
910
+ end
911
+ else
912
+ lines << " const uint8_t *const #{mask_pointer_name(array)} = " \
913
+ "#{given} ? (const uint8_t *) #{given} : &carray_jit_present;\n"
914
+ array_rank(array).times do |axis|
915
+ lines << " const int64_t #{mask_stride_name(array, axis)} = " \
916
+ "#{given} ? mask_strides[#{base + axis}] : 0;\n"
917
+ end
918
+ end
919
+ end
920
+ @reals.each_with_index do |name, index|
921
+ lines << " const double #{c_name(name)} = reals[#{index}];\n"
922
+ end
923
+ @complexes.each_with_index do |name, index|
924
+ slot = @reals.size + 2 * index
925
+ lines << " const double _Complex #{c_name(name)} = " \
926
+ "CMPLX(reals[#{slot}], reals[#{slot + 1}]);\n"
927
+ end
928
+ @integers.each_with_index do |name, index|
929
+ lines << " const int64_t #{c_name(name)} = integers[#{index}];\n"
930
+ end
931
+ @extent_slots.each_with_index do |(array, axis), slot|
932
+ lines << " const int64_t #{extent_name(array, axis)} = " \
933
+ "integers[#{@integers.size + slot}];\n"
934
+ end
935
+ @address_functions.each_key.with_index do |name, index|
936
+ lines << " const #{c_function_type_name(name)} #{c_name(name)} = " \
937
+ "(#{c_function_type_name(name)}) functions[#{index}];\n"
938
+ end
939
+ @address_arrays.each_with_index do |array, index|
940
+ # Typed by the array rather than by the parameter it will be passed
941
+ # to: the caller has already checked that the two agree, and the
942
+ # array is the one that owns the memory.
943
+ lines << " #{storage_c_type(array)} *const #{c_name(array)} = " \
944
+ "(#{storage_c_type(array)} *) data[#{index}];\n"
945
+ end
946
+ lines.empty? ? "" : lines.join + "\n"
947
+ end
948
+
949
+ # Which way each axis runs is derived, not chosen: reading a cell the
950
+ # kernel will later write means that cell has to be reached in one
951
+ # particular order, and any other order would read what was never
952
+ # written.
953
+ # Each axis carries a start, a limit and a step. The step is a compiled
954
+ # constant when it is one, because `i++` is what lets the loop vectorise
955
+ # and that is the case nearly every kernel is in.
956
+ def loop_open
957
+ @rank.times.map { |axis|
958
+ indent = " " + " " * axis
959
+ index = @analyzer.index_names[axis]
960
+ # A kernel that can fail at a cell -- a computed index off the
961
+ # end, a division with no divisor, a `raise` -- stops there, as the
962
+ # Ruby loop it stands for does. So each loop leaves as soon as one
963
+ # has: the flag is already in cache, and a kernel whose body has no
964
+ # way to report does not pay for the test at all.
965
+ guard = @body_reports ? "#{indent} if ( *error ) break;\n" : ""
966
+ start = "bounds[#{3 * axis}]"
967
+ limit = "bounds[#{3 * axis + 1}]"
968
+ step = @steps[axis]
969
+ if step && step.negative?
970
+ advance = step == -1 ? "#{index}--" : "#{index} += bounds[#{3 * axis + 2}]"
971
+ "#{indent}for (int64_t #{index} = #{start}; #{index} > #{limit}; " \
972
+ "#{advance}) {\n#{guard}"
973
+ else
974
+ advance = step == 1 ? "#{index}++" : "#{index} += bounds[#{3 * axis + 2}]"
975
+ "#{indent}for (int64_t #{index} = #{start}; #{index} < #{limit}; " \
976
+ "#{advance}) {\n#{guard}"
977
+ end
978
+ }.join
979
+ end
980
+
981
+ def loop_close
982
+ @rank.downto(1).map { |depth| " " + " " * (depth - 1) + "}\n" }.join
983
+ end
984
+
985
+ def emit_statement (statement, indent)
986
+ case statement
987
+ when Assignment then emit_assignment(statement, indent)
988
+ when ElementWrite then guarded(statement, indent) { |inner|
989
+ emit_element_write(statement, inner) }
990
+ when MaskWrite then guarded(statement, indent) { |inner|
991
+ emit_mask_only_write(statement, inner) }
992
+ when PointerWrite then
993
+ "#{indent}#{statement.name}[#{emit(statement.index, :int64)}] = " \
994
+ "#{emit(statement.expression, statement.type)};\n"
995
+ when InnerLoop then emit_inner_loop(statement, indent)
996
+ when While then emit_while(statement, indent)
997
+ when Branch then emit_branch(statement, indent)
998
+ when CallStatement then emit_call_statement(statement, indent)
999
+ when Print then emit_print(statement, indent)
1000
+ when Raise then emit_raise(statement, indent)
1001
+ when LoopSkip then "#{indent}continue;\n"
1002
+ when LoopStop then "#{indent}break;\n"
1003
+ else
1004
+ raise Error, "code generation reached #{statement.class}"
1005
+ end
1006
+ end
1007
+
1008
+ # 1 and 2 are the divisor that was not there and the subscript that ran
1009
+ # off its array. A `raise` in the block takes a code from here up.
1010
+ RAISE_CODE_FLOOR = 3
1011
+
1012
+ # The code is taken from the message rather than counted off as messages
1013
+ # are met. Counting would number the same block differently depending
1014
+ # on what else had been compiled, and a kernel is cached on disk under
1015
+ # the C it generated: a number that means one string today and another
1016
+ # tomorrow would raise the wrong message, quietly, out of a cache hit.
1017
+ # From the message, one string is one code in every process.
1018
+ def raise_code (message)
1019
+ span = 2**31 - RAISE_CODE_FLOOR
1020
+ RAISE_CODE_FLOOR +
1021
+ Digest::SHA256.hexdigest(message)[0, 16].to_i(16) % span
1022
+ end
1023
+
1024
+ # The cell reports and the loop stops; the Ruby side raises when it has
1025
+ # control back. Stopping is what `raise` means -- the cells after this
1026
+ # one are not computed, and neither is the rest of this one.
1027
+ #
1028
+ # Nothing is reported from a cell that is missing. `raise "x" if a < 0`
1029
+ # under a mask was decided by bytes that mean nothing -- the rule an
1030
+ # `if` in a masked kernel already keeps for what it writes -- so the
1031
+ # masks carried in gate the report, and a null error slot gates it
1032
+ # again where the raise stands inside a masked write.
1033
+ #
1034
+ # The first report wins. A sweep hands the kernel one chunk at a time,
1035
+ # so a later chunk still runs after a cell has raised in this one.
1036
+ def emit_raise (node, indent)
1037
+ code = raise_code(node.message)
1038
+ register_raise(code, node.message)
1039
+ slot = error_argument
1040
+ tests = []
1041
+ unless @carried_masks.empty?
1042
+ mask = combine_masks(@carried_masks)
1043
+ tests << "!#{mask}" unless mask == "0"
1044
+ end
1045
+ # A body standing on its own reports into the flag beside it, which is
1046
+ # there to be reported into: there is nothing to ask about, and asking
1047
+ # would read as though there were.
1048
+ if @in_function && !@error_parameter
1049
+ tests << "!#{ERROR_FLAG}"
1050
+ report = "#{ERROR_FLAG} = #{code};"
1051
+ else
1052
+ tests << "#{slot} && !*#{slot}"
1053
+ report = "*#{slot} = #{code};"
1054
+ end
1055
+ # A function returns whatever it returns, whatever happened -- the
1056
+ # arrangement its C caller is left with, and the one the division
1057
+ # helper already keeps by returning zero from a divide it refused.
1058
+ # The value is not the answer; the flag says so.
1059
+ leaving = @in_function && !@returns_nothing ? "return 0;" : "return;"
1060
+ "#{indent}if ( #{tests.join(' && ')} ) {\n" \
1061
+ "#{indent} #{report}\n" \
1062
+ "#{indent} #{leaving}\n" \
1063
+ "#{indent}}\n"
1064
+ end
1065
+
1066
+ # One message per code. Two that collided would be one string raised
1067
+ # where the other was written, so it is worth the check even though the
1068
+ # code is 64 bits of digest folded down and this cannot really happen.
1069
+ def register_raise (code, message)
1070
+ held = @raise_messages[code]
1071
+ if held && held != message
1072
+ raise Error, "two raise messages share a code: " \
1073
+ "#{held.inspect} and #{message.inspect}"
1074
+ end
1075
+ @raise_messages[code] = message
1076
+ end
1077
+
1078
+ # A conversion as Ruby writes it: flags, width, precision, and the
1079
+ # letter that says what is being printed.
1080
+ CONVERSION = /%([-+ 0#]*)(\d*)((?:\.\d+)?)([a-zA-Z%])/
1081
+
1082
+ INTEGER_CONVERSIONS = %w[d i u x X o].freeze
1083
+ REAL_CONVERSIONS = %w[e E f F g G a A].freeze
1084
+
1085
+ # The format is rewritten rather than passed through, because the same
1086
+ # directive does not mean the same thing in both languages: Ruby's `%d`
1087
+ # takes any Integer, and C's takes an `int`, which is not what a cell
1088
+ # holds. What each argument is, is known here, so the directive is
1089
+ # settled here too.
1090
+ # A call whose value is dropped. The cast says the dropping was meant,
1091
+ # which is what a reader of the generated C would want to know and what
1092
+ # a compiler warning would otherwise ask about.
1093
+ #
1094
+ # Under a mask the call does not happen at all. Every other statement
1095
+ # can run on bytes that mean nothing and mark what it wrote; a call
1096
+ # cannot be taken back, so this follows `raise` rather than the
1097
+ # arithmetic: a cell whose arguments are missing is a cell the function
1098
+ # is not told about.
1099
+ def emit_call_statement (statement, indent)
1100
+ text = emit_raw(statement.call).first
1101
+ return "#{indent}(void) #{text};\n" unless @masked
1102
+ mask = combine_masks(@carried_masks + [emit_mask(statement.call)])
1103
+ return "#{indent}(void) #{text};\n" if mask == "0"
1104
+ "#{indent}if ( ! #{mask} ) {\n" \
1105
+ "#{indent} (void) #{text};\n" \
1106
+ "#{indent}}\n"
1107
+ end
1108
+
1109
+ def emit_print (print, indent)
1110
+ arguments = print.arguments.dup
1111
+ text = +""
1112
+ rest = print.template
1113
+ until rest.empty?
1114
+ match = CONVERSION.match(rest)
1115
+ unless match
1116
+ text << c_string(rest)
1117
+ break
1118
+ end
1119
+ text << c_string(match.pre_match)
1120
+ rest = match.post_match
1121
+ if match[4] == "%"
1122
+ text << "%%"
1123
+ next
1124
+ end
1125
+ argument = arguments.shift
1126
+ unless argument
1127
+ raise Unsupported.new(
1128
+ "printf's format asks for more values than were given",
1129
+ print.location)
1130
+ end
1131
+ text << conversion_for(argument, match, print)
1132
+ end
1133
+ unless arguments.empty?
1134
+ raise Unsupported.new(
1135
+ "printf was given more values than its format asks for",
1136
+ print.location)
1137
+ end
1138
+ values = print.arguments.flat_map { |argument| printed_values(argument) }
1139
+ # Flushed at once: C's buffer is not Ruby's, so without this the
1140
+ # kernel's output arrives after everything the program printed
1141
+ # around it, which is no use for seeing where you are.
1142
+ "#{indent}printf(\"#{text}\"#{values.map { |v| ", #{v}" }.join});\n" \
1143
+ "#{indent}fflush(stdout);\n"
1144
+ end
1145
+
1146
+ def conversion_for (argument, match, print)
1147
+ flags, width, precision, letter = match[1], match[2], match[3], match[4]
1148
+ case argument.type
1149
+ when :int64
1150
+ unless INTEGER_CONVERSIONS.include?(letter)
1151
+ raise Unsupported.new(
1152
+ "this value is an integer, so `%#{letter}` does not print it; " \
1153
+ "write `%d`",
1154
+ argument.location || print.location)
1155
+ end
1156
+ # `l`, because a cell holds an int64_t and C's `%d` is an int.
1157
+ "%#{flags}#{width}#{precision}l#{letter}"
1158
+ when :uint64
1159
+ unless INTEGER_CONVERSIONS.include?(letter)
1160
+ raise Unsupported.new(
1161
+ "this value is an integer, so `%#{letter}` does not print it; " \
1162
+ "write `%d`",
1163
+ argument.location || print.location)
1164
+ end
1165
+ # `%d` of a uint64_t above 2**63 would print a negative number, and
1166
+ # the value Ruby prints is the one the cell holds -- so the signed
1167
+ # conversions become their unsigned twin. The rest (`%x`, `%o`) are
1168
+ # unsigned already.
1169
+ "%#{flags}#{width}#{precision}l#{letter == "i" ? "u" : letter.sub("d", "u")}"
1170
+ when :double
1171
+ unless REAL_CONVERSIONS.include?(letter)
1172
+ raise Unsupported.new(
1173
+ "this value is a real, so `%#{letter}` does not print it; " \
1174
+ "write `%g`",
1175
+ argument.location || print.location)
1176
+ end
1177
+ "%#{flags}#{width}#{precision}#{letter}"
1178
+ when :complex
1179
+ # C has no directive for a complex, so it is printed as the two
1180
+ # numbers it is, with the sign of the imaginary part always shown.
1181
+ unless REAL_CONVERSIONS.include?(letter)
1182
+ raise Unsupported.new(
1183
+ "this value is complex, so `%#{letter}` does not print it; " \
1184
+ "write `%g`",
1185
+ argument.location || print.location)
1186
+ end
1187
+ "%#{flags}#{width}#{precision}#{letter}" \
1188
+ "%+#{width}#{precision}#{letter}i"
1189
+ when :boolean
1190
+ "%#{flags}#{width}#{precision}d"
1191
+ else
1192
+ raise Unsupported.new("printf cannot print this value",
1193
+ argument.location || print.location)
1194
+ end
1195
+ end
1196
+
1197
+ def printed_values (argument)
1198
+ case argument.type
1199
+ when :complex
1200
+ ["creal(#{emit(argument, :complex)})", "cimag(#{emit(argument, :complex)})"]
1201
+ when :boolean
1202
+ ["(int) (#{emit(argument, :boolean)})"]
1203
+ else
1204
+ [emit(argument, argument.type)]
1205
+ end
1206
+ end
1207
+
1208
+ # The literal parts of the format, spelled the way C spells a string.
1209
+ def c_string (text)
1210
+ text.gsub(/[\\"\n\t\r\e\0]/,
1211
+ "\\" => "\\\\", "\"" => "\\\"", "\n" => "\\n",
1212
+ "\t" => "\\t", "\r" => "\\r", "\e" => "\\033",
1213
+ "\0" => "\\0")
1214
+ end
1215
+
1216
+ # Reading outside an array can be made harmless -- read cell zero and
1217
+ # report -- but writing outside it cannot: the report would arrive after
1218
+ # the damage. So a scatter works its positions out first, and writes
1219
+ # only if every one of them is inside.
1220
+ def guarded (write, indent)
1221
+ positions = scattered_positions(write)
1222
+ return yield(indent) if positions.empty?
1223
+
1224
+ lines = "#{indent}{\n"
1225
+ positions.each do |temporary, node, array, axis|
1226
+ lines << "#{indent} const int64_t #{temporary} = #{emit(node, :int64)};\n"
1227
+ @position_temporaries[node] = temporary
1228
+ end
1229
+ test = positions.map { |temporary, _, array, axis|
1230
+ "#{temporary} >= 0 && #{temporary} < #{extent_name(array, axis)}"
1231
+ }.join(" && ")
1232
+ lines << "#{indent} if ( #{test} ) {\n"
1233
+ lines << yield("#{indent} ")
1234
+ lines << "#{indent} } else {\n"
1235
+ lines << "#{indent} if ( #{error_argument} ) *#{error_argument} = 2;\n"
1236
+ lines << "#{indent} }\n"
1237
+ lines << "#{indent}}\n"
1238
+ positions.each { |_, node, _, _| @position_temporaries.delete(node) }
1239
+ lines
1240
+ end
1241
+
1242
+ def scattered_positions (write)
1243
+ subscripts = write_subscripts(write)
1244
+ subscripts.each_with_index.filter_map { |(index, offset), axis|
1245
+ next unless index.nil? && offset.is_a?(Node) &&
1246
+ !Analyzer.fixed_subscript?(offset)
1247
+ [next_temporary("position"), offset, write.array, axis]
1248
+ }
1249
+ end
1250
+
1251
+ # `out[i] = UNDEF` marks the cell missing. The bytes underneath are out
1252
+ # of contract, so there is nothing to store into them.
1253
+ def emit_mask_only_write (write, indent)
1254
+ "#{indent}#{cell_reference(write.array, write_subscripts(write), :mask)} = 1;\n"
1255
+ end
1256
+
1257
+ # The loop a reduction runs in, inside one cell of the outer loops.
1258
+ def inner_loop_guard (indent)
1259
+ @body_reports ? "#{indent} if ( *error ) break;\n" : ""
1260
+ end
1261
+
1262
+ # The same shape the bounded loop gets, minus the counter -- including
1263
+ # the guard, so a `raise` inside a `while` stops it at the pass that
1264
+ # raised rather than running the condition once more.
1265
+ def emit_while (loop_node, indent)
1266
+ # A loop entered on a value read from a missing cell is in the same
1267
+ # position a branch taken on one is: it was decided by bytes that mean
1268
+ # nothing, so what it writes inherits that. The carrying is the
1269
+ # branch's, spelled the same way, because it is the same rule.
1270
+ #
1271
+ # What is not the same is what running on those bytes can cost. A
1272
+ # branch on garbage takes the wrong arm and finishes; a `while` on
1273
+ # garbage can fail to finish at all, since the garbage is what decides
1274
+ # how many passes there are. Skipping the loop instead was the other
1275
+ # candidate and is worse: the locals would keep their pre-loop values
1276
+ # and a write after the loop carries no mask, so a missing cell would
1277
+ # buy a wrong answer quietly rather than a slow one loudly. A kernel
1278
+ # over masked data whose loop bound comes from a cell should say so --
1279
+ # `if a[i] == UNDEF` -- which is the same advice masked arithmetic
1280
+ # already gets.
1281
+ outer = @carried_masks
1282
+ @carried_masks =
1283
+ @masked ? (outer + [emit_mask(loop_node.condition)]).uniq : outer
1284
+
1285
+ text = "#{indent}while (#{emit(loop_node.condition, :boolean)}) {\n" +
1286
+ inner_loop_guard(indent)
1287
+ text += loop_node.statements.map { |statement|
1288
+ emit_statement(statement, indent + " ")
1289
+ }.join
1290
+ @carried_masks = outer
1291
+ text + "#{indent}}\n"
1292
+ end
1293
+
1294
+ def emit_inner_loop (loop_node, indent)
1295
+ accumulation = reduction_accumulation(loop_node)
1296
+ return emit_split_reduction(loop_node, accumulation, indent) if accumulation
1297
+
1298
+ index = loop_node.index
1299
+ text = "#{indent}for (int64_t #{index} = #{emit(loop_node.from, :int64)}; " \
1300
+ "#{index} < #{emit(loop_node.to, :int64)}; #{index}++) {\n" +
1301
+ inner_loop_guard(indent)
1302
+ text += loop_node.statements.map { |statement|
1303
+ emit_statement(statement, indent + " ")
1304
+ }.join
1305
+ text + "#{indent}}\n"
1306
+ end
1307
+
1308
+ # The loop is a reduction when its whole body is one local folding a
1309
+ # term into itself with an associative operator, and that local was
1310
+ # already live when the loop began. Anything else -- a second
1311
+ # statement, a branch, a term that reads the accumulator twice -- is not
1312
+ # a fold and keeps the serial loop.
1313
+ #
1314
+ # Returns [accumulator, operator, term], or nil.
1315
+ def reduction_accumulation (loop_node)
1316
+ return nil unless @reassociate
1317
+ # A masked accumulator carries a mask beside its value, and a partial
1318
+ # sum would need one each. Left out rather than half-done.
1319
+ return nil if @masked
1320
+ return nil unless loop_node.statements.size == 1
1321
+
1322
+ assignment = loop_node.statements.first
1323
+ return nil unless assignment.is_a?(Assignment)
1324
+ name = assignment.binding_name
1325
+ # Declared before this loop, at this type, so the fold continues a
1326
+ # value rather than starting one.
1327
+ return nil unless @declared_locals[name] == assignment.type
1328
+
1329
+ expression = assignment.expression
1330
+ return nil unless expression.is_a?(BinaryOperation)
1331
+ operator = expression.operator
1332
+ return nil unless licensed_fold?(operator, assignment.type)
1333
+
1334
+ # Short of one full round the chains never run, and their setup is
1335
+ # all the loop would pay for them. Where the extent is written out,
1336
+ # that is known here and costs nothing to act on; where it is a value
1337
+ # the kernel is handed, it is not, and a runtime test for it was
1338
+ # measured and bought less than it cost.
1339
+ return nil if literal_extent(loop_node)&.<(PARTIAL_ACCUMULATORS)
1340
+
1341
+ left, right = expression.left, expression.right
1342
+ if accumulator?(left, name) && !mentions_local?(right, name)
1343
+ [assignment, operator]
1344
+ elsif accumulator?(right, name) && !mentions_local?(left, name)
1345
+ [assignment, operator]
1346
+ end
1347
+ end
1348
+
1349
+ def literal_extent (loop_node)
1350
+ from, to = loop_node.from, loop_node.to
1351
+ return nil unless from.is_a?(IntegerLiteral) && to.is_a?(IntegerLiteral)
1352
+ to.value - from.value
1353
+ end
1354
+
1355
+ # Addition is taken in double and in complex; a complex sum is
1356
+ # componentwise in both Ruby and C, so partial sums add the same way.
1357
+ # Multiplication is taken in double only -- Ruby multiplies two
1358
+ # Complexes its own way, and combining partial products would have to
1359
+ # go through that rather than through C's operator.
1360
+ def licensed_fold? (operator, type)
1361
+ case operator
1362
+ when :+ then type == :double || type == :complex
1363
+ when :* then type == :double
1364
+ end
1365
+ end
1366
+
1367
+ def accumulator? (node, name)
1368
+ node.is_a?(LocalRead) && node.binding_name == name
1369
+ end
1370
+
1371
+ def mentions_local? (node, name)
1372
+ return true if accumulator?(node, name)
1373
+ node.children.any? { |child| mentions_local?(child, name) }
1374
+ end
1375
+
1376
+ # The fold, run as PARTIAL_ACCUMULATORS chains instead of one, with the
1377
+ # cells that do not fill a round left to a serial tail.
1378
+ #
1379
+ # The incoming value rides in the first chain and the rest start from
1380
+ # the operator's identity, so it is folded in exactly once. Each chain
1381
+ # keeps the term's own operand order -- what is licensed here is the
1382
+ # order the *iterations* are grouped in, not the order within one.
1383
+ def emit_split_reduction (loop_node, accumulation, indent)
1384
+ assignment, operator = accumulation
1385
+ name = assignment.binding_name
1386
+ type = assignment.type
1387
+ index = loop_node.index
1388
+ base = "#{index}__base"
1389
+ limit = "#{index}__end"
1390
+ lanes = (0...PARTIAL_ACCUMULATORS).map { |lane| "#{name}__p#{lane}" }
1391
+ identity = (operator == :* ? ONES : ZEROES).fetch(type)
1392
+
1393
+ inner = indent + " "
1394
+ text = "#{indent}{\n"
1395
+ text += "#{inner}int64_t #{base} = #{emit(loop_node.from, :int64)};\n"
1396
+ text += "#{inner}const int64_t #{limit} = #{emit(loop_node.to, :int64)};\n"
1397
+ text += "#{inner}#{COMPUTATION_C_TYPES.fetch(type)} #{lanes.first} = #{name}" +
1398
+ lanes.drop(1).map { |lane| ", #{lane} = #{identity}" }.join + ";\n"
1399
+ text += "#{inner}for (; #{base} + #{PARTIAL_ACCUMULATORS} <= #{limit}; " \
1400
+ "#{base} += #{PARTIAL_ACCUMULATORS}) {\n"
1401
+ text += inner_loop_guard(inner)
1402
+ lanes.each_with_index do |lane, offset|
1403
+ term = lane_expression(assignment.expression, name, lane)
1404
+ text += "#{inner} {\n"
1405
+ text += "#{inner} const int64_t #{index} = #{base} + #{offset};\n"
1406
+ text += "#{inner} #{lane} = #{emit(term, type)};\n"
1407
+ text += "#{inner} }\n"
1408
+ end
1409
+ text += "#{inner}}\n"
1410
+ text += "#{inner}#{name} = #{combine_partials(lanes, operator)};\n"
1411
+ text += "#{inner}for (int64_t #{index} = #{base}; #{index} < #{limit}; " \
1412
+ "#{index}++) {\n"
1413
+ text += inner_loop_guard(inner)
1414
+ text += emit_statement(assignment, inner + " ")
1415
+ text += "#{inner}}\n"
1416
+ text + "#{indent}}\n"
1417
+ end
1418
+
1419
+ # The same term, folding into one chain instead of into the
1420
+ # accumulator. The accumulator appears once and at the top, which is
1421
+ # what reduction_accumulation checked, so only that operand moves.
1422
+ def lane_expression (expression, name, lane)
1423
+ operands = [expression.left, expression.right].map { |operand|
1424
+ next operand unless accumulator?(operand, name)
1425
+ read = LocalRead.new(operand.name, operand.location)
1426
+ read.binding_name = lane
1427
+ read.type = operand.type
1428
+ read
1429
+ }
1430
+ term = BinaryOperation.new(expression.operator, *operands,
1431
+ expression.location)
1432
+ term.type = expression.type
1433
+ term
1434
+ end
1435
+
1436
+ # Pairwise, so that the chains meet in a tree rather than in a line.
1437
+ def combine_partials (lanes, operator)
1438
+ terms = lanes
1439
+ while terms.size > 1
1440
+ terms = terms.each_slice(2).map { |left, right|
1441
+ right ? "(#{left} #{operator} #{right})" : left
1442
+ }
1443
+ end
1444
+ terms.first
1445
+ end
1446
+
1447
+ # `if` in statement position. A branch not taken writes nothing, so the
1448
+ # cell keeps both its value and its mask -- which is what the same `if`
1449
+ # would do in Ruby.
1450
+ def emit_branch (branch, indent)
1451
+ # A branch taken on a value read from a missing cell was decided by
1452
+ # bytes that mean nothing, so what it writes inherits that. A branch
1453
+ # taken on `a[i] == UNDEF` was not.
1454
+ outer = @carried_masks
1455
+ @carried_masks = @masked ? (outer + [emit_mask(branch.condition)]).uniq : outer
1456
+
1457
+ text = "#{indent}if ( #{emit(branch.condition, :boolean)} ) {\n"
1458
+ text += branch.consequent.map { |statement|
1459
+ emit_statement(statement, indent + " ")
1460
+ }.join
1461
+ unless branch.alternative.empty?
1462
+ text += "#{indent}} else {\n"
1463
+ text += branch.alternative.map { |statement|
1464
+ emit_statement(statement, indent + " ")
1465
+ }.join
1466
+ end
1467
+ @carried_masks = outer
1468
+ text + "#{indent}}\n"
1469
+ end
1470
+
1471
+ def emit_assignment (assignment, indent)
1472
+ name = assignment.binding_name
1473
+ type = assignment.type
1474
+ declared = @declared_locals.key?(name)
1475
+ @declared_locals[name] = type
1476
+
1477
+ # A local carries a mask alongside its value, so that reading it later
1478
+ # is the same as reading what it was computed from.
1479
+ mask = if @masked
1480
+ "#{indent}#{declared ? '' : 'uint8_t '}" \
1481
+ "#{local_mask_name(name)} = #{emit_mask(assignment.expression)};\n"
1482
+ else
1483
+ ""
1484
+ end
1485
+
1486
+ if assignment.expression.is_a?(Conditional)
1487
+ lines = declared ? "" : "#{indent}#{COMPUTATION_C_TYPES.fetch(type)} #{name};\n"
1488
+ lines + emit_conditional_statement(assignment.expression, name, type, indent) + mask
1489
+ else
1490
+ prefix = declared ? "" : "#{COMPUTATION_C_TYPES.fetch(type)} "
1491
+ "#{indent}#{prefix}#{name} = #{emit(assignment.expression, type)};\n" + mask
1492
+ end
1493
+ end
1494
+
1495
+ # Masked data is out of contract -- a kernel may compute anything into a
1496
+ # masked cell -- so the value is computed for every cell and only the
1497
+ # mask is reconciled. That is what lets the loop stay branchless.
1498
+ #
1499
+ # The one thing that cannot simply be computed and discarded is an
1500
+ # integer division by zero, which would be reported even though the
1501
+ # cell it feeds is masked. So the mask is settled first and gates the
1502
+ # report.
1503
+ # Where a write lands. Normally the cell the outer indices are on; a
1504
+ # contraction into a fixed cell says so with a constant subscript.
1505
+ def write_subscripts (write)
1506
+ subscripts = write.subscripts if write.respond_to?(:subscripts)
1507
+ subscripts || @analyzer.index_names.map { |name| [name, 0] }
1508
+ end
1509
+
1510
+ def emit_element_write (write, indent)
1511
+ unless @masked
1512
+ @masked_flag = nil
1513
+ return emit_value_write(write, indent)
1514
+ end
1515
+
1516
+ flag = next_temporary("masked")
1517
+ lines = "#{indent}const uint8_t #{flag} = " \
1518
+ "#{combine_masks(@carried_masks + [emit_mask(write.expression)])};\n"
1519
+ lines += "#{indent}#{cell_reference(write.array, write_subscripts(write), :mask)} = " \
1520
+ "#{flag};\n"
1521
+ @masked_flag = flag
1522
+ lines += emit_value_write(write, indent)
1523
+ @masked_flag = nil
1524
+ lines
1525
+ end
1526
+
1527
+ # The mask of an expression, built the same shape as the expression.
1528
+ #
1529
+ # A flat union of everything the expression touches would be wrong for a
1530
+ # conditional: `cond ? 0.0 : a[i]` does not read `a[i]` when the
1531
+ # condition holds, and Ruby's answer there is not missing. So the
1532
+ # conditional's mask is conditional too.
1533
+ def emit_mask (node)
1534
+ case node
1535
+ when ElementRead
1536
+ cell_reference(node.array, node.subscripts, :mask)
1537
+ when LocalRead
1538
+ local_mask_name(node.binding_name)
1539
+ when Conditional
1540
+ branches = "#{emit(node.condition, :boolean)} ? " \
1541
+ "#{emit_mask(node.consequent)} : #{emit_mask(node.alternative)}"
1542
+ combine_masks([emit_mask(node.condition), "(#{branches})"])
1543
+ when IntegerLiteral, FloatLiteral, IndexVariable, CaptureRead, MaskTest,
1544
+ BoundsValue, ZeroLike
1545
+ "0"
1546
+ else
1547
+ combine_masks(node.children.map { |child| emit_mask(child) })
1548
+ end
1549
+ end
1550
+
1551
+ def combine_masks (parts)
1552
+ present = parts.reject { |part| part == "0" }.uniq
1553
+ return "0" if present.empty?
1554
+ present.size == 1 ? present.first : "(#{present.join(' | ')})"
1555
+ end
1556
+
1557
+ def local_mask_name (name)
1558
+ "#{name}__mask"
1559
+ end
1560
+
1561
+ def emit_value_write (write, indent)
1562
+ target = cell_reference(write.array, write_subscripts(write))
1563
+ expression = write.expression
1564
+ if expression.is_a?(Conditional)
1565
+ temporary = next_temporary
1566
+ type = expression.type
1567
+ "#{indent}#{COMPUTATION_C_TYPES.fetch(type)} #{temporary};\n" +
1568
+ emit_conditional_statement(expression, temporary, type, indent) +
1569
+ "#{indent}#{target} = #{cast_to_storage(temporary, type, write.array)};\n"
1570
+ else
1571
+ value = cast_to_storage(emit(expression, expression.type),
1572
+ expression.type, write.array)
1573
+ "#{indent}#{target} = #{value};\n"
1574
+ end
1575
+ end
1576
+
1577
+ # A conditional in statement position becomes if/else rather than a
1578
+ # ternary; it reads far better when the branches are long.
1579
+ def emit_conditional_statement (node, target, type, indent)
1580
+ "#{indent}if ( #{emit(node.condition, :boolean)} ) {\n" \
1581
+ "#{indent} #{target} = #{emit(node.consequent, type)};\n" \
1582
+ "#{indent}} else {\n" \
1583
+ "#{indent} #{target} = #{emit(node.alternative, type)};\n" \
1584
+ "#{indent}}\n"
1585
+ end
1586
+
1587
+ def storage_c_type (array)
1588
+ STORAGE_C_TYPES.fetch(@storage_types.fetch(array))
1589
+ end
1590
+
1591
+ def cast_to_storage (text, type, array)
1592
+ # Storing into a boolean array normalises: CArray's boolean is a byte
1593
+ # holding 0 or 1, and a kernel is not the place that invariant stops
1594
+ # being true.
1595
+ return "(uint8_t)((#{text}) ? 1 : 0)" if boolean_storage?(array)
1596
+ target = storage_c_type(array)
1597
+ return text if COMPUTATION_C_TYPES.fetch(type) == target
1598
+ "(#{target})(#{text})"
1599
+ end
1600
+
1601
+ # The cast that takes a stored cell to the type the kernel computes in,
1602
+ # or nil where the two already agree.
1603
+ def widening_cast (array, type)
1604
+ return nil if type == :boolean
1605
+ wanted = COMPUTATION_C_TYPES.fetch(type)
1606
+ return nil if storage_c_type(array) == wanted
1607
+ "(#{wanted})"
1608
+ end
1609
+
1610
+ def boolean_storage? (array)
1611
+ @storage_types.fetch(array, nil) == "boolean"
1612
+ end
1613
+
1614
+ # A Ruby name is not always a C one: `Foo::TABLE` names one thing in
1615
+ # Ruby and nothing at all in C, so the qualified part is spelled with
1616
+ # underscores. Every name that reaches the source goes through here.
1617
+ def c_name (name)
1618
+ name.to_s.gsub("::", "__")
1619
+ end
1620
+
1621
+ def pointer_name (array)
1622
+ "p_#{c_name(array)}"
1623
+ end
1624
+
1625
+ # The block's own name for the function, with the typedef beside it.
1626
+ def c_function_type_name (name)
1627
+ "#{c_name(name)}_fn_t"
1628
+ end
1629
+
1630
+ def extent_name (array, axis)
1631
+ "#{c_name(array)}_n#{axis}"
1632
+ end
1633
+
1634
+ # An error reported from a cell whose mask is already set is not one the
1635
+ # caller asked about: the value there is out of contract.
1636
+ # A kernel is handed a place to report through; a compiled function is
1637
+ # not, having only the signature its declaration gave it. So the
1638
+ # object carries one of its own -- a single exported int the helpers
1639
+ # write the same code into -- and `CFunction#call` reads it and raises
1640
+ # what the kernel raises. Nothing in the C reaches Ruby to do it: the
1641
+ # function still returns a number and touches no Ruby value, which is
1642
+ # what lets its address be handed to a library, or called off the GVL.
1643
+ ERROR_FLAG = "carray_jit_error"
1644
+
1645
+ # A computation type this generator has no C for. Nothing reaches here
1646
+ # today -- every type TypeAssignment can assign is named at each of the
1647
+ # sites that calls this -- and that is the point: a type added later
1648
+ # stops here rather than falling into whichever branch happened to be
1649
+ # last, which for `abs`, `%` and `**` alike was the one for doubles.
1650
+ def unhandled_type (node, what)
1651
+ raise Error, "`#{what}` has no C for a #{node.type} -- this compiler " \
1652
+ "gained a computation type without gaining the code that " \
1653
+ "emits it"
1654
+ end
1655
+
1656
+ def error_argument
1657
+ if @in_function
1658
+ @uses_error_flag = true
1659
+ # A pasted body reports into the kernel's slot, which reaches it as
1660
+ # a parameter; a standalone one into the flag in its own object.
1661
+ return @error_parameter ? ERROR_FLAG : "&#{ERROR_FLAG}"
1662
+ end
1663
+ # Asking for the slot is what says this body can report, and every
1664
+ # place that can -- a checked subscript, the division helpers, a
1665
+ # `raise`, a pasted function that takes the flag -- asks here. So the
1666
+ # loops above learn it from the statements they will hold, which are
1667
+ # emitted before the loop is opened.
1668
+ @body_reports = true
1669
+ @masked_flag ? "(#{@masked_flag} ? (int32_t *) 0 : error)" : "error"
1670
+ end
1671
+
1672
+
1673
+ def stride_name (array, axis)
1674
+ "#{c_name(array)}_s#{axis}"
1675
+ end
1676
+
1677
+ def mask_pointer_name (array)
1678
+ "m_#{c_name(array)}"
1679
+ end
1680
+
1681
+ def mask_stride_name (array, axis)
1682
+ "#{c_name(array)}_ms#{axis}"
1683
+ end
1684
+
1685
+ def index_expression (array, axis, index, offset, reporting: true)
1686
+ if index.nil?
1687
+ # A pinned axis carries either a plain position or the expression
1688
+ # that computes one -- and where that expression is one only the
1689
+ # running kernel can work out, the position is checked here.
1690
+ return offset.to_s unless offset.is_a?(Node)
1691
+ return emit(offset, :int64) if Analyzer.fixed_subscript?(offset)
1692
+ # A scatter has already worked this position out and checked it.
1693
+ held = @position_temporaries[offset]
1694
+ return held if held
1695
+ @uses_index_check = true
1696
+ return "carray_jit_index(#{emit(offset, :int64)}, " \
1697
+ "#{extent_name(array, axis)}, " \
1698
+ "#{reporting ? error_argument : '(int32_t *) 0'})"
1699
+ end
1700
+ # A walked one may carry an expression too: `a[i - window]` reads the
1701
+ # offset out of the kernel's integer arguments.
1702
+ return "#{index} + (#{emit(offset, :int64)})" if offset.is_a?(Node)
1703
+ return index.to_s if offset.zero?
1704
+ plain = offset.negative? ? "#{index} - #{-offset}" : "#{index} + #{offset}"
1705
+ return plain unless bordered_read?(array)
1706
+ case @border
1707
+ when :clamp
1708
+ @uses_clamp = true
1709
+ "carray_jit_clamp(#{plain}, #{extent_name(array, axis)})"
1710
+ when :wrap
1711
+ @uses_wrap = true
1712
+ "carray_jit_wrap(#{plain}, #{extent_name(array, axis)})"
1713
+ else
1714
+ # `:zero` leaves the position alone and answers 0 instead of
1715
+ # reading, which is the reference's business rather than the
1716
+ # index's -- see cell_reference.
1717
+ plain
1718
+ end
1719
+ end
1720
+
1721
+ # True for a read this body has to answer for: a window's, while the
1722
+ # frame is being emitted. The result array is written at the cell and
1723
+ # reaches nowhere, so it is never one of these.
1724
+ def bordered_read? (array)
1725
+ @bordering && @analyzer.windows.include?(array)
1726
+ end
1727
+
1728
+ # Where the window has to be for there to be a cell to read: one test
1729
+ # per axis it reaches away from the cell on, and none for an axis it
1730
+ # sits still on.
1731
+ def inside_tests (array, subscripts)
1732
+ subscripts.each_with_index.filter_map { |(index, offset), axis|
1733
+ next if index.nil? || !offset.is_a?(Integer) || offset.zero?
1734
+ position = index_expression(array, axis, index, offset)
1735
+ "(#{position}) >= 0 && (#{position}) < #{extent_name(array, axis)}"
1736
+ }
1737
+ end
1738
+
1739
+ # Emits with the border set aside, so that the reference inside a guard
1740
+ # is the plain one rather than a guard around a guard.
1741
+ def with_border (rule)
1742
+ held = @border
1743
+ @border = rule
1744
+ yield
1745
+ ensure
1746
+ @border = held
1747
+ end
1748
+
1749
+ # The address of one cell. On the contiguous path the innermost axis
1750
+ # becomes a typed index, which is the part that decides whether the
1751
+ # compiler can vectorise the loop.
1752
+ def cell_reference (array, subscripts, kind = :data)
1753
+ # `:zero` says a read outside the array gives zero rather than
1754
+ # somewhere else's cell, so the position is left alone and the read
1755
+ # is asked for only where there is one. Outside, a value is 0 and a
1756
+ # mask byte is 0 too: the cell is not missing, it is not there.
1757
+ if @border == :zero && bordered_read?(array)
1758
+ inside = inside_tests(array, subscripts)
1759
+ unless inside.empty?
1760
+ reference = with_border(nil) { cell_reference(array, subscripts, kind) }
1761
+ return "(#{inside.join(' && ')} ? #{reference} : 0)"
1762
+ end
1763
+ end
1764
+ count = subscripts.size
1765
+ if kind == :mask
1766
+ # The mask read does not report an index of its own: it is asked
1767
+ # first, before it is known whether the cell being written is
1768
+ # masked, and reporting there would raise for a cell whose value is
1769
+ # out of contract anyway. The read of the value asks the same
1770
+ # question a moment later, with that known.
1771
+ terms = subscripts.each_with_index.map { |(index, offset), axis|
1772
+ "(#{index_expression(array, axis, index, offset, reporting: false)}) * " \
1773
+ "#{mask_stride_name(array, axis)}"
1774
+ }
1775
+ return "#{mask_pointer_name(array)}[#{terms.join(' + ')}]"
1776
+ end
1777
+
1778
+ type = storage_c_type(array)
1779
+ outer = (0...(count - 1)).map { |axis|
1780
+ index, offset = subscripts[axis]
1781
+ "(#{index_expression(array, axis, index, offset)}) * " \
1782
+ "#{stride_name(array, axis)}"
1783
+ }
1784
+ last = count - 1
1785
+ last_index, last_offset = subscripts[last]
1786
+ if @contiguous
1787
+ base = outer.empty? ? pointer_name(array)
1788
+ : "#{pointer_name(array)} + #{outer.join(' + ')}"
1789
+ "((#{type} *)(#{base}))" \
1790
+ "[#{index_expression(array, last, last_index, last_offset)}]"
1791
+ else
1792
+ terms = outer + ["(#{index_expression(array, last, last_index, last_offset)}) * " \
1793
+ "#{stride_name(array, last)}"]
1794
+ "*(#{type} *)(#{pointer_name(array)} + #{terms.join(' + ')})"
1795
+ end
1796
+ end
1797
+
1798
+ # Emits `node` so that its value has type `target`, inserting a cast
1799
+ # only where the type actually changes.
1800
+ def emit (node, target)
1801
+ widen(*emit_raw(node), node.type, target).first
1802
+ end
1803
+
1804
+ def emit_operand (node, target, parent_precedence, right_side = false)
1805
+ text, precedence = widen(*emit_raw(node), node.type, target)
1806
+ parenthesize(text, precedence, right_side ? parent_precedence + 1 : parent_precedence)
1807
+ end
1808
+
1809
+ # The cast from one computation type to a wider one. C would perform
1810
+ # most of these on its own, but writing them down is what makes the
1811
+ # dumped source say where the type changed -- and `int64_t` to
1812
+ # `double _Complex` is a conversion worth seeing.
1813
+ def widen (text, precedence, from, to)
1814
+ here, there = NUMERIC_RANK[from], NUMERIC_RANK[to]
1815
+ return [text, precedence] if here.nil? || there.nil? || there <= here
1816
+ ["(#{COMPUTATION_C_TYPES.fetch(to)})" \
1817
+ "#{parenthesize(text, precedence, LEAF_PRECEDENCE)}", UNARY_PRECEDENCE]
1818
+ end
1819
+
1820
+ def parenthesize (text, precedence, needed)
1821
+ precedence < needed ? "(#{text})" : text
1822
+ end
1823
+
1824
+ def emit_raw (node)
1825
+ case node
1826
+ when IntegerLiteral then [format_integer(node.value), LEAF_PRECEDENCE]
1827
+ when FloatLiteral then [format_float(node.value, node.type), LEAF_PRECEDENCE]
1828
+ when ImaginaryLiteral
1829
+ real = TypeAssignment::REAL_PART_TYPES.fetch(node.type)
1830
+ ["#{complex_build(node.type)}(#{format_float(0.0, real)}, " \
1831
+ "#{format_float(node.value.to_f, real)})", LEAF_PRECEDENCE]
1832
+ when BooleanLiteral then [node.value ? "1" : "0", LEAF_PRECEDENCE]
1833
+ when BitwiseNot
1834
+ ["~#{emit_operand(node.operand, node.type, UNARY_PRECEDENCE)}",
1835
+ UNARY_PRECEDENCE]
1836
+ when IndexVariable then [node.name.to_s, LEAF_PRECEDENCE]
1837
+ when BoundsValue then ["bounds[#{node.slot}]", LEAF_PRECEDENCE]
1838
+ when ZeroLike
1839
+ [ZEROES.fetch(node.type), LEAF_PRECEDENCE]
1840
+ when LocalRead then [node.binding_name.to_s, LEAF_PRECEDENCE]
1841
+ when CaptureRead then [c_name(node.name), LEAF_PRECEDENCE]
1842
+ # A read is widened to the type the kernel computes in, because that
1843
+ # is the type the Ruby loop computes in: reading a float32 cell in
1844
+ # Ruby gives a Float, and reading an int32 cell gives an Integer that
1845
+ # does not stop at 2**31. Left as it lies, C would do the arithmetic
1846
+ # in float and in int -- narrower than Ruby on both counts, and
1847
+ # undefined rather than merely different when a narrow int overflows.
1848
+ #
1849
+ # A boolean cell is a byte holding 0 or 1, so it is already the value
1850
+ # it stands for. Keeping it that way on the way out is this kernel's
1851
+ # business, and cast_to_storage does it.
1852
+ when ElementRead
1853
+ cell = cell_reference(node.array, node.subscripts)
1854
+ widening = widening_cast(node.array, node.type)
1855
+ if widening
1856
+ ["#{widening}#{parenthesize(cell, LEAF_PRECEDENCE, UNARY_PRECEDENCE)}",
1857
+ UNARY_PRECEDENCE]
1858
+ else
1859
+ [cell, LEAF_PRECEDENCE]
1860
+ end
1861
+ when MaskTest then emit_mask_test(node)
1862
+ when UnaryMinus
1863
+ operand, precedence = emit_raw(node.operand)
1864
+ ["-#{parenthesize(operand, precedence, UNARY_PRECEDENCE)}", UNARY_PRECEDENCE]
1865
+ when LogicalNot
1866
+ operand, precedence = emit_raw(node.operand)
1867
+ ["! #{parenthesize(operand, precedence, UNARY_PRECEDENCE)}", UNARY_PRECEDENCE]
1868
+ when LogicalOperation
1869
+ precedence = PRECEDENCE.fetch(node.operator)
1870
+ ["#{emit_operand(node.left, :boolean, precedence)} #{node.operator} " \
1871
+ "#{emit_operand(node.right, :boolean, precedence)}", precedence]
1872
+ when AbsoluteValue then emit_absolute_value(node)
1873
+ when Conversion then emit_conversion(node)
1874
+ when ComplexPart then emit_complex_part(node)
1875
+ when ComplexBuild
1876
+ real = TypeAssignment::REAL_PART_TYPES.fetch(node.type)
1877
+ ["#{complex_build(node.type)}(#{emit(node.real, real)}, " \
1878
+ "#{emit(node.imaginary, real)})", LEAF_PRECEDENCE]
1879
+ when Power then emit_power(node)
1880
+ when MathCall then emit_math_call(node)
1881
+ when ArrayAddress
1882
+ [c_name(node.array), LEAF_PRECEDENCE]
1883
+ when PointerRead
1884
+ # A pointer parameter is reached the way C reaches it: contiguous,
1885
+ # from the address it was handed. No base, no stride, no bounds --
1886
+ # a subscript here is the caller's business, as it is in C.
1887
+ ["#{node.name}[#{emit(node.index, :int64)}]", LEAF_PRECEDENCE]
1888
+ when RecursiveCall
1889
+ # The function calls itself by the symbol it is being defined
1890
+ # under, not by the name the declaration spelled: that name is
1891
+ # unqualified and would reach whatever else in the process answers
1892
+ # to it. A captured function travels as a pointer beside the
1893
+ # scalars; this one is right here, so the call is direct.
1894
+ arguments = node.arguments.zip(node.parameters)
1895
+ .map { |argument, parameter|
1896
+ if argument.is_a?(ArrayAddress)
1897
+ emit(argument, :address)
1898
+ else
1899
+ emit(argument, parameter.computation)
1900
+ end
1901
+ }
1902
+ arguments << ERROR_FLAG if @error_parameter
1903
+ ["#{@own_symbol}(#{arguments.join(', ')})", LEAF_PRECEDENCE]
1904
+ when CFunctionCall
1905
+ c_function = @c_functions.fetch(node.name)
1906
+ arguments = node.arguments.zip(c_function.parameters)
1907
+ .map { |argument, parameter|
1908
+ if argument.is_a?(ArrayAddress)
1909
+ emit(argument, :address)
1910
+ else
1911
+ emit(argument, parameter.computation)
1912
+ end
1913
+ }
1914
+ # A pasted body is reached by its symbol; an address by the local
1915
+ # the declarations bound it to.
1916
+ called = c_function.pasted? ? c_function.name : c_name(node.name)
1917
+ # And one that can report a failure is handed the slot this kernel
1918
+ # is watching -- null under a masked cell, where the value written
1919
+ # is out of contract and a division by zero there was not asked
1920
+ # about. The helpers it calls check for that, as the kernel's own
1921
+ # do.
1922
+ arguments << error_argument if c_function.pasted_takes_error?
1923
+ ["#{called}(#{arguments.join(', ')})", LEAF_PRECEDENCE]
1924
+ when Conditional then emit_ternary(node)
1925
+ when BinaryOperation then emit_binary(node)
1926
+ else
1927
+ raise Error, "code generation reached #{node.class}"
1928
+ end
1929
+ end
1930
+
1931
+ # `a[i] == UNDEF` reads the mask byte, never the value.
1932
+ def emit_mask_test (node)
1933
+ cell = cell_reference(node.array, node.subscripts, :mask)
1934
+ node.negated ? ["! #{cell}", UNARY_PRECEDENCE] : [cell, LEAF_PRECEDENCE]
1935
+ end
1936
+
1937
+ # Float#floor and friends hand back an Integer in Ruby, so the C rounds
1938
+ # and then narrows. An Integer receiver is already there.
1939
+ def emit_conversion (node)
1940
+ if TypeAssignment::INTEGER_TYPES.include?(node.operand.type)
1941
+ if node.type == node.operand.type
1942
+ return [emit(node.operand, node.operand.type), LEAF_PRECEDENCE]
1943
+ end
1944
+ return ["(double)#{parenthesize(*emit_raw(node.operand), LEAF_PRECEDENCE)}",
1945
+ UNARY_PRECEDENCE]
1946
+ end
1947
+ return [emit(node.operand, :double), LEAF_PRECEDENCE] if node.result_type == :double
1948
+ ["(int64_t)#{node.name}(#{emit(node.operand, :double)})", UNARY_PRECEDENCE]
1949
+ end
1950
+
1951
+ # creal and cimag are the way out of the complex type; conj stays in it.
1952
+ #
1953
+ # A real number answers all four in Ruby, and three of them without
1954
+ # computing anything: it is its own real part and its own conjugate,
1955
+ # and its imaginary part is a zero.
1956
+ def emit_complex_part (node)
1957
+ if complex_type?(node.operand.type)
1958
+ function = { :real => "creal", :imaginary => "cimag",
1959
+ :conjugate => "conj", :arg => "carg" }.fetch(node.name)
1960
+ function += "f" if node.operand.type == :float_complex
1961
+ return ["#{function}(#{emit(node.operand, node.operand.type)})",
1962
+ LEAF_PRECEDENCE]
1963
+ end
1964
+ case node.name
1965
+ when :real, :conjugate then emit_raw(node.operand)
1966
+ when :imaginary then [ZEROES.fetch(:int64), LEAF_PRECEDENCE]
1967
+ else
1968
+ @uses_real_arg = true
1969
+ ["carray_jit_real_arg(#{emit(node.operand, :double)})", LEAF_PRECEDENCE]
1970
+ end
1971
+ end
1972
+
1973
+ # An integer power is squared out rather than sent through pow, whose
1974
+ # double result would not be the exact integer Ruby gives.
1975
+ #
1976
+ # A complex power is the one place in this compiler where the answer is
1977
+ # not the Ruby loop's to the last bit. Ruby raises a Complex to a power
1978
+ # by binary powering, with exact answers along the axes; cpow goes round
1979
+ # through exp and log. They agree to within an ulp, and that is
1980
+ # accepted here rather than reproducing complex.c's algorithm -- which
1981
+ # has changed between Ruby versions, so reproducing it would tie a
1982
+ # compiled kernel to the interpreter that compiled it.
1983
+ def emit_power (node)
1984
+ if complex_type?(node.type)
1985
+ text = "cpow(#{emit(node.base, :complex)}, " \
1986
+ "#{emit(node.exponent, :complex)})"
1987
+ return [text, LEAF_PRECEDENCE] if node.type == :complex
1988
+ return ["(float _Complex)#{text}", UNARY_PRECEDENCE]
1989
+ end
1990
+ if node.type == :uint64
1991
+ @uses_unsigned_power = true
1992
+ return ["carray_jit_unsigned_power(#{emit(node.base, :uint64)}, " \
1993
+ "#{emit(node.exponent, :uint64)})", LEAF_PRECEDENCE]
1994
+ end
1995
+ if node.type == :int64
1996
+ @uses_integer_power = true
1997
+ return ["carray_jit_integer_power(#{emit(node.base, :int64)}, " \
1998
+ "#{emit(node.exponent, :int64)})", LEAF_PRECEDENCE]
1999
+ end
2000
+ if node.type == :float
2001
+ return ["powf(#{emit(node.base, :float)}, " \
2002
+ "#{emit(node.exponent, :float)})", LEAF_PRECEDENCE]
2003
+ end
2004
+ unhandled_type(node, "**") unless node.type == :double
2005
+ ["pow(#{emit(node.base, :double)}, #{emit(node.exponent, :double)})",
2006
+ LEAF_PRECEDENCE]
2007
+ end
2008
+
2009
+ # cabs, fabs and llabs are three functions rather than one because C has
2010
+ # no generic for them, so this names each type instead of letting one of
2011
+ # them be what a type it has not heard of falls into.
2012
+ def emit_absolute_value (node)
2013
+ # The complex case is asked of the operand rather than of the result:
2014
+ # the magnitude of a complex number is a real one, so node.type is
2015
+ # already :double by the time we are here.
2016
+ if complex_type?(node.operand.type)
2017
+ function = node.operand.type == :float_complex ? "cabsf" : "cabs"
2018
+ return ["#{function}(#{emit(node.operand, node.operand.type)})",
2019
+ LEAF_PRECEDENCE]
2020
+ end
2021
+ case node.type
2022
+ when :double then ["fabs(#{emit(node.operand, :double)})", LEAF_PRECEDENCE]
2023
+ when :float then ["fabsf(#{emit(node.operand, :float)})", LEAF_PRECEDENCE]
2024
+ when :int64 then ["llabs(#{emit(node.operand, :int64)})", LEAF_PRECEDENCE]
2025
+ # An unsigned number is its own magnitude, and llabs would take it
2026
+ # through a signed type on the way.
2027
+ when :uint64 then [emit(node.operand, :uint64), LEAF_PRECEDENCE]
2028
+ else unhandled_type(node, "abs")
2029
+ end
2030
+ end
2031
+
2032
+ def emit_ternary (node)
2033
+ ["#{emit(node.condition, :boolean)} ? " \
2034
+ "#{emit(node.consequent, node.type)} : " \
2035
+ "#{emit(node.alternative, node.type)}", 10]
2036
+ end
2037
+
2038
+ def emit_binary (node)
2039
+ return emit_integer_division(node) if node.operator == :/ &&
2040
+ TypeAssignment::INTEGER_TYPES.include?(node.type)
2041
+ return emit_modulo(node) if node.operator == :%
2042
+ return emit_complex_binary(node) if complex_type?(node.type)
2043
+
2044
+ operand_type =
2045
+ if Analyzer::COMPARISON_OPERATORS.include?(node.operator)
2046
+ # Both sides are brought to the wider of the two, which is the
2047
+ # only way `z == 1` asks what Ruby asks.
2048
+ [node.left.type, node.right.type]
2049
+ .max_by { |type| NUMERIC_RANK.fetch(type, -1) }
2050
+ else
2051
+ node.type
2052
+ end
2053
+
2054
+ precedence = PRECEDENCE.fetch(node.operator)
2055
+ left = emit_operand(node.left, operand_type, precedence)
2056
+ # Every operator here groups to the left, so a right operand of the
2057
+ # same precedence needs parentheses whatever the operator is. Not
2058
+ # because C would compute a different number for integers -- it would
2059
+ # not -- but because floating-point arithmetic does not associate:
2060
+ # `a + (b + c)` regrouped as `(a + b) + c` is a different sum, and
2061
+ # this compiler's whole claim is that it computes what the same
2062
+ # expression computes in Ruby. `-` and `/` were handled and `+` and
2063
+ # `*` were not, on the reasoning that they associate. They associate
2064
+ # in arithmetic; doubles are not arithmetic.
2065
+ right = emit_operand(node.right, operand_type, precedence, true)
2066
+ ["#{left} #{node.operator} #{right}", precedence]
2067
+ end
2068
+
2069
+ # Ruby's Complex arithmetic is not C's, in three places that matter.
2070
+ #
2071
+ # A Complex added to a real number is added component by component, and
2072
+ # the imaginary part comes through untouched rather than having a zero
2073
+ # added to it: Ruby's `f_add` returns the other operand as it stands
2074
+ # when one of them is the exact Integer zero a real operand carries.
2075
+ # So `Complex(1.0, -0.0) + 2.0` is `3.0-0.0i`, where widening the 2.0
2076
+ # to a complex first would give `3.0+0.0i`, because `-0.0 + 0.0` is
2077
+ # `+0.0`. Multiplying by a real scales each part for the same reason,
2078
+ # and dividing by one divides each part.
2079
+ #
2080
+ # Subtraction is the exception: there the zero really is subtracted, in
2081
+ # Ruby as in C, so `z - x` and `x - z` are C's own operator. So is
2082
+ # `x * z`, which Ruby coerces and multiplies out in full -- which is
2083
+ # why `2.0 * Complex(1.0, -0.0)` and `Complex(1.0, -0.0) * 2.0` do not
2084
+ # agree with each other, and each is reproduced its own way.
2085
+ #
2086
+ # And a complex division is Smith's method as complex.c writes it,
2087
+ # which is not what the C library's __divdc3 computes.
2088
+ #
2089
+ # Each of these goes through a function rather than being written out,
2090
+ # so that the operand is named once: spelling `CMPLX(creal(z) + x,
2091
+ # cimag(z))` inline would emit the whole of z twice, and twice again
2092
+ # for the operation outside it.
2093
+ def emit_complex_binary (node)
2094
+ complex_type = node.type
2095
+ # Multiplying and dividing two complex numbers are the operations
2096
+ # that cancel: `(ac - bd)` and Smith's method both subtract numbers of
2097
+ # the same size, so the narrow width loses the answer rather than the
2098
+ # last bit of it. Both are reached in double and rounded once, which
2099
+ # is what Ruby does and what CArray settled on. Adding and
2100
+ # subtracting do not cancel past the one rounding a store makes
2101
+ # anyway, so they stay narrow.
2102
+ if complex_type == :float_complex &&
2103
+ [:*, :/].include?(node.operator) &&
2104
+ complex_type?(node.left.type) && complex_type?(node.right.type)
2105
+ helper = mixed_helper(node, :complex)
2106
+ if helper
2107
+ text, = emit_helper_call(*helper, false)
2108
+ else
2109
+ precedence = PRECEDENCE.fetch(node.operator)
2110
+ # Parenthesised, because the cast binds tighter than the operator:
2111
+ # without them it would narrow the left operand and leave the
2112
+ # multiplication to be worked out around it.
2113
+ text = "(#{emit_operand(node.left, :complex, precedence)} " \
2114
+ "#{node.operator} " \
2115
+ "#{emit_operand(node.right, :complex, precedence)})"
2116
+ end
2117
+ return ["(float _Complex)#{text}", UNARY_PRECEDENCE]
2118
+ end
2119
+ narrow = complex_type == :float_complex
2120
+ helper = mixed_helper(node, complex_type)
2121
+ return emit_helper_call(*helper, narrow) if helper
2122
+ precedence = PRECEDENCE.fetch(node.operator)
2123
+ ["#{emit_operand(node.left, complex_type, precedence)} #{node.operator} " \
2124
+ "#{emit_operand(node.right, complex_type, precedence, node.operator == :-)}",
2125
+ precedence]
2126
+ end
2127
+
2128
+ def emit_helper_call (name, arguments, narrow)
2129
+ @complex_helpers |= [[name, narrow]]
2130
+ prefix = narrow ? "carray_jit_f_" : "carray_jit_"
2131
+ ["#{prefix}#{name}(#{arguments.join(', ')})", LEAF_PRECEDENCE]
2132
+ end
2133
+
2134
+ # Which helper an operation carrying a complex operand needs, and what
2135
+ # to pass it -- or nil where C's own operator is what Ruby computes.
2136
+ def mixed_helper (node, ctype)
2137
+ rtype = TypeAssignment::REAL_PART_TYPES.fetch(ctype)
2138
+ left, right, operator = node.left, node.right, node.operator
2139
+ case operator
2140
+ when :/
2141
+ return ["complex_div_real", [emit(left, ctype), emit(right, rtype)]] if
2142
+ real_type?(right)
2143
+ return ["real_divide_complex", [emit(left, rtype), emit(right, ctype)]] if
2144
+ real_type?(left)
2145
+ ["complex_divide", [emit(left, ctype), emit(right, ctype)]]
2146
+ when :+
2147
+ if imaginary_literal?(right)
2148
+ ["complex_add_imaginary", [emit(left, ctype), format_float(right.value.to_f, rtype)]]
2149
+ elsif imaginary_literal?(left)
2150
+ ["imaginary_add_complex", [format_float(left.value.to_f, rtype), emit(right, ctype)]]
2151
+ elsif real_type?(right)
2152
+ ["complex_add_real", [emit(left, ctype), emit(right, rtype)]]
2153
+ elsif real_type?(left)
2154
+ ["real_add_complex", [emit(left, rtype), emit(right, ctype)]]
2155
+ end
2156
+ when :*
2157
+ if real_type?(right)
2158
+ ["complex_mul_real", [emit(left, ctype), emit(right, rtype)]]
2159
+ end
2160
+ end
2161
+ end
2162
+
2163
+ def complex_type? (type)
2164
+ TypeAssignment.complex?(type)
2165
+ end
2166
+
2167
+ # CMPLX and CMPLXF, which carry the sign of both zeros where writing
2168
+ # `re + im * I` would not.
2169
+ def complex_build (type)
2170
+ type == :float_complex ? "CMPLXF" : "CMPLX"
2171
+ end
2172
+
2173
+ # The complex functions that are safe to reach at the narrow width, and
2174
+ # they are a list rather than a rule because the reason is inside the
2175
+ # library. A libm transcendental is written to complete at its own
2176
+ # width, so `csinf` is a float32 answer to a float32 question. What is
2177
+ # not safe is a function that builds something out of the operand
2178
+ # before the transcendental starts: `clog(z)` needs `log|z|`, and on the
2179
+ # unit circle that is the difference of two numbers near one. Computed
2180
+ # in float, |z| rounds to exactly one and the real part of the answer
2181
+ # becomes zero -- measured here on four thousand points of the unit
2182
+ # circle, the error is 3.2e-08 where the answer itself is 3.7e-08.
2183
+ #
2184
+ # `**` is the same fault at one remove, `cpow` being `cexp(z * clog(a))`,
2185
+ # so it is emitted wide in emit_power and is not on this list either.
2186
+ NARROW_COMPLEX_MATH = %w[
2187
+ csqrt cexp csin ccos ctan casin catan csinh ccosh ctanh
2188
+ ].freeze
2189
+
2190
+ # A math function is reached at the width its argument claims, where
2191
+ # that is safe: `sinf` for a float32 cell, `csqrtf` for a cmplx64 one.
2192
+ # That is what CArray computes, and agreeing with it by construction is
2193
+ # worth more than agreeing because this platform happens to implement
2194
+ # `sinf` through `sin`.
2195
+ #
2196
+ # The real functions are all safe: `log(x)` reads its argument rather
2197
+ # than building one, so `logf` does not lose what `clogf` loses.
2198
+ def emit_math_call (node)
2199
+ if complex_type?(node.type)
2200
+ function = Analyzer::COMPLEX_MATH_FUNCTIONS.fetch(node.name)
2201
+ narrow = node.type == :float_complex &&
2202
+ NARROW_COMPLEX_MATH.include?(function)
2203
+ type = narrow ? :float_complex : :complex
2204
+ function += "f" if narrow
2205
+ arguments = node.arguments.map { |argument| emit(argument, type) }
2206
+ text = "#{function}(#{arguments.join(', ')})"
2207
+ return [text, LEAF_PRECEDENCE] if narrow || node.type == :complex
2208
+ return ["(float _Complex)#{text}", UNARY_PRECEDENCE]
2209
+ end
2210
+ function = node.name.to_s
2211
+ function += "f" if node.type == :float
2212
+ arguments = node.arguments.map { |argument| emit(argument, node.type) }
2213
+ ["#{function}(#{arguments.join(', ')})", LEAF_PRECEDENCE]
2214
+ end
2215
+
2216
+ def real_type? (node)
2217
+ TypeAssignment::REAL_TYPES.include?(node.type)
2218
+ end
2219
+
2220
+ def imaginary_literal? (node)
2221
+ node.is_a?(ImaginaryLiteral)
2222
+ end
2223
+
2224
+ # Integer `/` is floored to agree with Ruby and with CArray's own
2225
+ # kernels. A positive power-of-two divisor needs no correction at all:
2226
+ # an arithmetic shift already floors, and is cheaper than the truncating
2227
+ # divide the C operator would emit.
2228
+ def emit_integer_division (node)
2229
+ type = node.type
2230
+ shift = power_of_two_shift(node.right)
2231
+ if shift
2232
+ return ["#{emit_operand(node.left, type, 85)} >> #{shift}", 50]
2233
+ end
2234
+ # An unsigned operand cannot be negative, so C's truncation already
2235
+ # floors and only the zero divisor has to be caught.
2236
+ if type == :uint64
2237
+ @uses_unsigned_divide = true
2238
+ return ["carray_jit_unsigned_divide(#{emit(node.left, :uint64)}, " \
2239
+ "#{emit(node.right, :uint64)}, #{error_argument})",
2240
+ LEAF_PRECEDENCE]
2241
+ end
2242
+ @uses_floor_divide = true
2243
+ ["carray_jit_floor_divide(#{emit(node.left, :int64)}, " \
2244
+ "#{emit(node.right, :int64)}, #{error_argument})", LEAF_PRECEDENCE]
2245
+ end
2246
+
2247
+ # `%` floors, so it is not C's `%` -- see the helper above.
2248
+ def emit_modulo (node)
2249
+ if node.type == :uint64
2250
+ @uses_unsigned_modulo = true
2251
+ return ["carray_jit_unsigned_modulo(#{emit(node.left, :uint64)}, " \
2252
+ "#{emit(node.right, :uint64)}, #{error_argument})",
2253
+ LEAF_PRECEDENCE]
2254
+ end
2255
+ @uses_floor_modulo = true
2256
+ if node.type == :int64
2257
+ return ["carray_jit_floor_modulo(#{emit(node.left, :int64)}, " \
2258
+ "#{emit(node.right, :int64)}, #{error_argument})", LEAF_PRECEDENCE]
2259
+ end
2260
+ if node.type == :float
2261
+ @uses_floor_modulo_float = true
2262
+ return ["carray_jit_floor_modulo_float(#{emit(node.left, :float)}, " \
2263
+ "#{emit(node.right, :float)})", LEAF_PRECEDENCE]
2264
+ end
2265
+ unhandled_type(node, "%") unless node.type == :double
2266
+ ["carray_jit_floor_modulo_real(#{emit(node.left, :double)}, " \
2267
+ "#{emit(node.right, :double)})", LEAF_PRECEDENCE]
2268
+ end
2269
+
2270
+ def power_of_two_shift (node)
2271
+ return nil unless node.is_a?(IntegerLiteral)
2272
+ value = node.value
2273
+ return nil unless value > 0 && (value & (value - 1)).zero?
2274
+ Math.log2(value).to_i
2275
+ end
2276
+
2277
+ def format_integer (value)
2278
+ "INT64_C(#{value})"
2279
+ end
2280
+
2281
+ def format_float (value, type = :double)
2282
+ # A float literal without the suffix is a double, and one double in an
2283
+ # expression takes the whole expression with it -- so the suffix is
2284
+ # what keeps a float32 kernel computing in float.
2285
+ if type == :float
2286
+ # 9 significant digits round-trips a float exactly.
2287
+ text = format("%.9g", value)
2288
+ text << ".0" unless text.match?(/[.eEn]/)
2289
+ return text << "f"
2290
+ end
2291
+ # 17 significant digits round-trips a double exactly.
2292
+ text = format("%.17g", value)
2293
+ text << ".0" unless text.match?(/[.eEn]/)
2294
+ text
2295
+ end
2296
+
2297
+ def next_temporary (prefix = "result")
2298
+ @temporary_count += 1
2299
+ "#{prefix}#{@temporary_count}"
2300
+ end
2301
+
2302
+ end
2303
+
2304
+ end
2305
+ end