carray-jit 0.1.2 → 0.1.4

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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +917 -3
  3. data/README.md +14 -12
  4. data/carray-jit.gemspec +1 -3
  5. data/docs/00_Introduction.md +5 -3
  6. data/docs/01_GettingStarted.md +1 -1
  7. data/docs/02_KernelShapes.md +94 -15
  8. data/docs/03_SupportedFeatures.md +665 -32
  9. data/docs/04_Compiling.md +34 -7
  10. data/docs/05_DesignNotes.md +3 -3
  11. data/docs/06_Cheatsheet.md +200 -7
  12. data/docs/07_StepByStep.ja.md +533 -0
  13. data/docs/07_StepByStep.md +534 -0
  14. data/docs/08_LanguageReference.md +427 -0
  15. data/examples/README.md +12 -0
  16. data/examples/applications/alarm.rb +121 -0
  17. data/examples/applications/collatz.rb +105 -0
  18. data/examples/applications/cubic_spline.rb +331 -0
  19. data/examples/applications/dithering.rb +144 -0
  20. data/examples/applications/group_stats.rb +115 -0
  21. data/examples/applications/lookup.rb +126 -0
  22. data/examples/applications/median_filter.rb +153 -0
  23. data/examples/applications/parcel_ascent.rb +220 -0
  24. data/examples/applications/point_in_polygon.rb +111 -0
  25. data/examples/applications/random_walk.rb +98 -0
  26. data/examples/applications/van_der_pol.rb +186 -0
  27. data/examples/applications/wet_bulb.rb +140 -0
  28. data/examples/features/10_complex.rb +14 -4
  29. data/examples/features/15_loops.rb +7 -1
  30. data/lib/carray/jit/access.rb +14 -0
  31. data/lib/carray/jit/analyzer.rb +2218 -140
  32. data/lib/carray/jit/block_reader.rb +37 -6
  33. data/lib/carray/jit/c_function.rb +961 -86
  34. data/lib/carray/jit/c_generator.rb +1970 -191
  35. data/lib/carray/jit/call.rb +68 -0
  36. data/lib/carray/jit/compiler.rb +102 -14
  37. data/lib/carray/jit/expression.rb +271 -33
  38. data/lib/carray/jit/kernel.rb +382 -32
  39. data/lib/carray/jit/node.rb +374 -9
  40. data/lib/carray/jit/sorting_networks.rb +182 -0
  41. data/lib/carray/jit/type_assignment.rb +424 -35
  42. data/lib/carray/jit/version.rb +1 -1
  43. data/lib/carray/jit.rb +547 -77
  44. metadata +23 -8
  45. data/ext/carray_jit_access/carray_jit_access.c +0 -460
  46. data/ext/carray_jit_access/extconf.rb +0 -8
@@ -126,6 +126,15 @@ class CArray
126
126
  # would. Only the ones a kernel actually uses are emitted, and the
127
127
  # reason each exists is at emit_complex_binary.
128
128
  COMPLEX_HELPERS = {
129
+ "complex_finite" => <<~C,
130
+ /* Complex#finite? is both parts finite, which is what Ruby asks
131
+ and is not what isfinite of a complex would mean. */
132
+ static inline int
133
+ carray_jit_complex_finite (double _Complex z)
134
+ {
135
+ return isfinite(creal(z)) && isfinite(cimag(z));
136
+ }
137
+ C
129
138
  "complex_add_real" => <<~C,
130
139
  /* Ruby leaves the imaginary part of `z + x` exactly as it was,
131
140
  rather than adding the real operand's zero to it. */
@@ -159,9 +168,61 @@ class CArray
159
168
  return CMPLX(creal(z), y + cimag(z));
160
169
  }
161
170
  C
171
+ "safe_multiply" => <<~C,
172
+ /* complex.c's safe_mul, which every part of a Ruby complex product
173
+ goes through: a zero against a number that is not a zero or a
174
+ NaN meets only that number's sign, so a zero times an infinity is
175
+ a signed zero rather than C's NaN. C's own complex `*` recovers
176
+ from infinities by Annex G's rules instead, which are not these. */
177
+ static inline double
178
+ carray_jit_safe_multiply (double a, double b)
179
+ {
180
+ if ( a != 0 && b == 0 && ! isnan(a) ) a = signbit(a) ? -1.0 : 1.0;
181
+ else if ( b != 0 && a == 0 && ! isnan(b) ) b = signbit(b) ? -1.0 : 1.0;
182
+ return a * b;
183
+ }
184
+ C
185
+ "complex_multiply" => <<~C,
186
+ /* Ruby's `a * b` for two Complex numbers, part by part in
187
+ complex.c's order: comp_mul. safe_mul differs from a plain
188
+ product only for a zero against an infinity, which a plain
189
+ product answers NaN -- so the plain parts are the answer unless
190
+ one of them is a NaN, and only then is it worked out again the
191
+ safe way. C's own `*` takes the same shape, and costs the same. */
192
+ static inline double _Complex
193
+ carray_jit_complex_multiply (double _Complex a, double _Complex b)
194
+ {
195
+ double are = creal(a), aim = cimag(a);
196
+ double bre = creal(b), bim = cimag(b);
197
+ double re = are * bre - aim * bim, im = are * bim + aim * bre;
198
+ if ( isnan(re) || isnan(im) ) {
199
+ re = carray_jit_safe_multiply(are, bre) - carray_jit_safe_multiply(aim, bim);
200
+ im = carray_jit_safe_multiply(are, bim) + carray_jit_safe_multiply(aim, bre);
201
+ }
202
+ return CMPLX(re, im);
203
+ }
204
+ C
205
+ "real_multiply_complex" => <<~C,
206
+ /* `x * z` coerces x to a Complex whose imaginary part is an exact
207
+ zero, and multiplies in full. That zero meets safe_mul as any
208
+ zero does, so it is written as 0.0 here and gives the same parts;
209
+ only an addition treats an exact zero differently, and here the
210
+ zeros are multiplied first. */
211
+ static inline double _Complex
212
+ carray_jit_real_multiply_complex (double x, double _Complex b)
213
+ {
214
+ double bre = creal(b), bim = cimag(b);
215
+ double re = x * bre - 0.0 * bim, im = x * bim + 0.0 * bre;
216
+ if ( isnan(re) || isnan(im) ) {
217
+ re = carray_jit_safe_multiply(x, bre) - carray_jit_safe_multiply(0.0, bim);
218
+ im = carray_jit_safe_multiply(x, bim) + carray_jit_safe_multiply(0.0, bre);
219
+ }
220
+ return CMPLX(re, im);
221
+ }
222
+ C
162
223
  "complex_mul_real" => <<~C,
163
- /* `z * x` scales each part. `x * z` does not -- Ruby coerces the
164
- x and multiplies in full -- so it is left to C's operator. */
224
+ /* `z * x` scales each part, with no safe_mul: Ruby's Complex#*
225
+ takes a real operand apart and multiplies each part by it. */
165
226
  static inline double _Complex
166
227
  carray_jit_complex_mul_real (double _Complex z, double x)
167
228
  {
@@ -256,8 +317,10 @@ class CArray
256
317
  BORDER_RULES = [:zero, :clamp, :wrap].freeze
257
318
 
258
319
  def initialize (analyzer, storage_types, scalar_types, c_functions: {},
320
+ randoms: {},
259
321
  masked: false, reassociate: false,
260
- steps: nil, origin: nil, block_source: nil, border: nil)
322
+ steps: nil, origin: nil, block_source: nil, border: nil,
323
+ scalar_parameters: [])
261
324
  @masked = masked
262
325
  # What a window read gets where it falls off the array. Nil for every
263
326
  # kernel but a stencil's, and for a stencil whose border is the frame
@@ -282,25 +345,51 @@ class CArray
282
345
  position += analyzer.array_ranks.fetch(array, analyzer.rank)
283
346
  end
284
347
  @array_ranks = analyzer.array_ranks
285
- @reals = analyzer.scalar_names.select { |name| scalar_types[name] == :double }.sort
286
- @integers = analyzer.scalar_names.select { |name| scalar_types[name] == :int64 }.sort
348
+ # A compiled function's scalars are the parameters of its own C
349
+ # signature: they arrive by the ABI, in whatever type the declaration
350
+ # named, so no buffer carries them and they take no bus. Set aside
351
+ # here, which leaves the check below about captures -- what it was
352
+ # always about.
353
+ carried_names = analyzer.scalar_names - scalar_parameters
354
+ @reals = carried_names.select { |name| scalar_types[name] == :double }.sort
355
+ @integers = carried_names.select { |name| scalar_types[name] == :int64 }.sort
287
356
  # A captured Complex rides in the reals buffer as its two parts, so
288
357
  # that the kernel signature stays the one shape every kernel has.
289
- @complexes = analyzer.scalar_names.select { |name| scalar_types[name] == :complex }.sort
290
- # Three buses and no fourth: a capture whose type is none of these
291
- # would be packed into nothing and read as whatever the slot held, so
292
- # it is caught here rather than at the cell it computes wrongly.
293
- carried = @reals.size + @integers.size + @complexes.size
294
- unless carried == analyzer.scalar_names.size
295
- missing = analyzer.scalar_names - @reals - @integers - @complexes
358
+ @complexes = carried_names.select { |name| scalar_types[name] == :complex }.sort
359
+ # And a captured uint64 rides in the integers buffer, which is the
360
+ # same eight bytes read the other way: the caller packs the value's
361
+ # bits and the kernel casts the slot back, so nothing is lost and the
362
+ # signature keeps its three buffers. Behind the signed ones, in the
363
+ # order the caller packs them.
364
+ @unsigned_integers =
365
+ carried_names.select { |name| scalar_types[name] == :uint64 }.sort
366
+ # A captured Integer that rides as int64 but meets a uint64, where it
367
+ # takes that width. A negative one has none to take; the caller
368
+ # refuses it, as CArray refuses the same operand (see Kernel).
369
+ @unsigned_captures = []
370
+ # Three buffers and no fourth: a capture whose type rides in none of
371
+ # them would be packed into nothing and read as whatever the slot
372
+ # held, so it is caught here rather than at the cell it computes
373
+ # wrongly.
374
+ carried = @reals.size + @integers.size + @complexes.size +
375
+ @unsigned_integers.size
376
+ unless carried == carried_names.size
377
+ missing = carried_names - @reals - @integers - @complexes -
378
+ @unsigned_integers
296
379
  raise Error,
297
380
  "captured #{missing.join(", ")} travel in none of the kernel's " \
298
- "three scalar buses; a computation type was added without a " \
381
+ "scalar buffers; a computation type was added without a " \
299
382
  "way to hand a value of it to the C"
300
383
  end
301
384
  # Only the ones the block actually called, in a fixed order, because
302
385
  # the caller packs the addresses into `functions` by this order.
303
386
  @c_functions = analyzer.c_function_names.sort.to_h { |name| [name, c_functions.fetch(name)] }
387
+ # The generators the block drew from, by the name it drew through.
388
+ # Unlike a C function, one takes no slot in any buffer: its C is
389
+ # pasted and its state is an address array, so what is kept here is
390
+ # only which generator each name is -- the kind, to paste, and the
391
+ # symbol to call.
392
+ @randoms = analyzer.random_names.to_h { |name| [name, randoms.fetch(name)] }
304
393
  # A function written here is pasted into this kernel and called by its
305
394
  # symbol; a borrowed one arrives as an address. Only the second kind
306
395
  # takes a slot in `functions`, so it is that hash the caller packs by.
@@ -330,10 +419,16 @@ class CArray
330
419
  @uses_clamp = false
331
420
  @uses_wrap = false
332
421
  @uses_real_arg = false
422
+ @uses_real_power_complex = false
423
+ @clamp_types = []
424
+ @gamma_types = []
333
425
  @complex_helpers = []
334
426
  @uses_floor_divide = false
335
427
  @uses_floor_modulo = false
428
+ @uses_shift = false
336
429
  @uses_integer_power = false
430
+ @uses_integer_abs = false
431
+ @uses_whole_number = false
337
432
  @uses_unsigned_divide = false
338
433
  @uses_unsigned_modulo = false
339
434
  @uses_unsigned_power = false
@@ -350,17 +445,29 @@ class CArray
350
445
  # this kernel is what answers for them. The codes agree because they
351
446
  # are taken from the messages, not counted off.
352
447
  @raise_messages = {}
353
- @pasted_functions.each_value do |function|
448
+ pasted_closure.each do |function|
354
449
  (function.raise_messages || {}).each do |code, message|
355
450
  register_raise(code, message)
356
451
  end
357
452
  end
453
+ # The intrinsic helpers the body asked for, as [name, storage, cells]
454
+ # -- a list used as a set, the way @clamp_types is. A pasted body's
455
+ # are merged into it by #preamble.
456
+ @intrinsic_needs = []
457
+ # Whether some body pasted into this file clears an array of its own.
458
+ @pasted_clears_a_local_array = false
358
459
  @position_temporaries = {}.compare_by_identity
460
+ # The positions a write is being guarded by, by axis, while its body
461
+ # is emitted.
462
+ @guarded_axes = {}.compare_by_identity
359
463
  @origin = origin
360
464
  @block_source = block_source
465
+ refuse_generated_indices
361
466
  end
362
467
 
363
- attr_reader :arrays, :reals, :integers, :complexes, :masked, :extent_slots,
468
+ attr_reader :arrays, :reals, :integers, :complexes, :unsigned_integers,
469
+ :unsigned_captures,
470
+ :masked, :extent_slots,
364
471
  :c_functions, :pasted_functions, :address_functions,
365
472
  :address_arrays, :address_parameters,
366
473
  # The messages `raise` in the block gave, by the code a cell
@@ -373,6 +480,14 @@ class CArray
373
480
  @uses_error_flag
374
481
  end
375
482
 
483
+ # Whether some array the body made is one of the zeroed spellings, which
484
+ # is what `<string.h>` is included for. A pasted function's body is
485
+ # emitted into this file too, and when a function body may make one of
486
+ # its own this has to ask the pasted ones as well.
487
+ def clears_a_local_array?
488
+ @analyzer.clears_a_local_array? || @pasted_clears_a_local_array
489
+ end
490
+
376
491
  def generate
377
492
  strided = build_body(false)
378
493
  contiguous = build_body(true)
@@ -409,11 +524,17 @@ class CArray
409
524
  # library handed the address calls without knowing about any of this.
410
525
  def generate_function (name, parameter_names, parameter_c_types,
411
526
  return_c_type, return_type, error_parameter: false)
412
- @own_symbol = name
527
+ # Standing alone, a body that turns out to be able to fail is lent
528
+ # under a wrapper (see #lending_wrapper), and the body itself goes
529
+ # under a name of its own. Whether it can fail is known only once it
530
+ # has been emitted, so a recursive call is written to that name from
531
+ # the start and put back to `name` below where no wrapper came.
532
+ body_symbol = "#{name}#{BODY_SUFFIX}"
533
+ @own_symbol = error_parameter ? name : body_symbol
413
534
  @in_function = true
414
535
  @error_parameter = error_parameter
536
+ @body_reports = false
415
537
  @contiguous = true
416
- @declared_locals = {}
417
538
  @temporary_count = 0
418
539
  @carried_masks = []
419
540
  statements = @analyzer.body.statements
@@ -422,7 +543,9 @@ class CArray
422
543
  @returns_nothing = return_type.nil?
423
544
  held = @returns_nothing ? statements : statements[0..-2]
424
545
  lines = held.map { |statement| emit_statement(statement, " ") }.join
546
+ lines = local_declarations(@analyzer.body, " ") + lines
425
547
  value = @returns_nothing ? nil : emit(statements.last, return_type)
548
+ parameter_names = parameter_names.map { |parameter| parameter_c_name(parameter) }
426
549
  parameters = parameter_names.zip(parameter_c_types)
427
550
  .map { |parameter, type| type.declare(parameter) }
428
551
  # Passed whether or not the body turned out to use it, so that a
@@ -430,48 +553,205 @@ class CArray
430
553
  # same argument list the definition ends up declaring.
431
554
  parameters << "int32_t *#{ERROR_FLAG}" if error_parameter
432
555
  parameters = ["void"] if parameters.empty?
433
- flag = @uses_error_flag && !error_parameter ? error_flag_declaration : ""
556
+ wrapped = @uses_error_flag && !error_parameter
557
+ unless wrapped || error_parameter
558
+ lines = lines.gsub("#{body_symbol}(", "#{name}(")
559
+ value = value&.gsub("#{body_symbol}(", "#{name}(")
560
+ end
561
+ flag = if wrapped
562
+ error_flag_declaration + error_hook_declaration +
563
+ error_standin_declaration + error_state_accessor(name)
564
+ else
565
+ ""
566
+ end
434
567
  # Kept apart from the file it is compiled in: the definition alone is
435
568
  # what a kernel pastes into its own translation unit, where the
436
569
  # includes are already written and the helpers are shared.
437
- @function_definition =
438
- "#{return_c_type}\n#{name} (#{parameters.join(', ')})\n{\n" +
439
- lines + (@returns_nothing ? "}\n" : " return #{value};\n}\n")
440
- preamble + flag + @function_definition
570
+ opening = "#{return_c_type}\n#{name} (#{parameters.join(', ')})\n{\n"
571
+ body = lines + (@returns_nothing ? "}\n" : " return #{value};\n}\n")
572
+ @function_definition = opening + body
573
+ return preamble + flag + opening + body unless wrapped
574
+ preamble + flag +
575
+ "static #{return_c_type}\n#{body_symbol} (#{parameters.join(', ')})\n{\n" +
576
+ standing_gate + body + "\n" +
577
+ lending_wrapper(name, body_symbol, parameter_names, parameters,
578
+ return_c_type)
579
+ end
580
+
581
+ # What the body is defined under when a wrapper is lent in its place.
582
+ # Static, so the object still exports one function.
583
+ BODY_SUFFIX = "_body".freeze
584
+
585
+ # The hook `CFunction#on_error` sets: a C function of one `void *`,
586
+ # and the pointer it is handed. Beside the flag, and only where the
587
+ # flag is, since a body that cannot fail has nothing to call it for.
588
+ ERROR_HOOK = "carray_jit_on_error".freeze
589
+ ERROR_HOOK_DATA = "carray_jit_on_error_data".freeze
590
+
591
+ def error_hook_declaration
592
+ "/* Called once, by the call whose body put the flag up -- so a\n" \
593
+ " library that goes on calling can be told to stop (NLopt's\n" \
594
+ " nlopt_force_stop) rather than be handed stand-ins until it is\n" \
595
+ " done. Set by CFunction#on_error; null until then. Per thread,\n" \
596
+ " for the reason the flag beside it is. */\n" \
597
+ "static #{THREAD_LOCAL}void (*#{ERROR_HOOK}) (void *) = 0;\n" \
598
+ "static #{THREAD_LOCAL}void *#{ERROR_HOOK_DATA} = 0;\n\n"
599
+ end
600
+
601
+ # What a failed call answers C with. Set by the window through
602
+ # `stand_in:`, and 0 until then, which is what this always was.
603
+ ERROR_STANDIN = "carray_jit_standin".freeze
604
+
605
+ def error_standin_declaration
606
+ "/* What a call answers with once the flag stands -- cast to whatever\n" \
607
+ " this body returns. A caller that reads the flag never looks at\n" \
608
+ " it; one that reads the return value as a status does, and only\n" \
609
+ " the caller knows which it is, so the window sets it. 0 until a\n" \
610
+ " window says otherwise, which is what it always answered. */\n" \
611
+ "static #{THREAD_LOCAL}int64_t #{ERROR_STANDIN} = 0;\n\n"
612
+ end
613
+
614
+ # Where a thread's copy of the four above stands. A thread-local has
615
+ # no address the loader can hand out -- `dlsym` answers for the symbol,
616
+ # not for any one thread's copy of it -- so Ruby asks the object itself,
617
+ # from the thread whose window it is.
618
+ #
619
+ # It is the only one of the five that is exported, and it wears the
620
+ # body's own name, so that this file can be linked beside another one
621
+ # generated the same way. One object per body is what the cache makes
622
+ # and what these names once assumed; carray-jit-aot takes the C and
623
+ # links several into one library, where a fixed name is a duplicate
624
+ # symbol and the link fails. The four it answers for are `static` for
625
+ # the same reason -- nothing outside this file reaches them by name,
626
+ # Ruby included, which is what this function is for.
627
+ ERROR_STATE_SUFFIX = "_error_state".freeze
628
+
629
+ # What Ruby looks the accessor up under, for a body compiled as
630
+ # `symbol`.
631
+ def self.error_state_name (symbol)
632
+ "#{symbol}#{ERROR_STATE_SUFFIX}"
633
+ end
634
+
635
+ def error_state_accessor (name)
636
+ "/* The four above, for the calling thread, in that order. Called\n" \
637
+ " from Ruby once per thread that opens a window on this body. */\n" \
638
+ "void\n#{CGenerator.error_state_name(name)} (void **out)\n{\n" \
639
+ " out[0] = (void *) &#{ERROR_FLAG};\n" \
640
+ " out[1] = (void *) &#{ERROR_HOOK};\n" \
641
+ " out[2] = (void *) &#{ERROR_HOOK_DATA};\n" \
642
+ " out[3] = (void *) &#{ERROR_STANDIN};\n}\n\n"
643
+ end
644
+
645
+ # The entry point the address is, for a body that can fail. It turns
646
+ # a call away while the flag stands, as the body's own gate does, and
647
+ # calls the hook when this call is the one that raised it -- which is
648
+ # once, since every call after it is turned away at the top. The hook
649
+ # is outside the body so that each way the flag can go up, a `raise`
650
+ # that leaves early or a division that runs on to the end, is the same
651
+ # one test afterwards.
652
+ #
653
+ # It is also the one place that says what a failed call answers C with.
654
+ # The body has several ways of ending -- a `raise` returns early, a
655
+ # division that had no divisor runs on to the end and returns whatever
656
+ # the zero the helper handed back added up to -- and a caller reading
657
+ # the return value as a status cannot be given a different answer
658
+ # depending on which. So the gates inside the body go on returning
659
+ # zero to their own caller, which is this function or the body itself
660
+ # recursing, and what C is told is decided here, once, from the flag.
661
+ def lending_wrapper (name, body_symbol, parameter_names, parameters,
662
+ return_c_type)
663
+ arguments = parameter_names.join(", ")
664
+ if @returns_nothing
665
+ "#{return_c_type}\n#{name} (#{parameters.join(', ')})\n{\n" \
666
+ " if ( #{ERROR_FLAG} ) return;\n" \
667
+ " #{body_symbol}(#{arguments});\n" \
668
+ " if ( #{ERROR_FLAG} && #{ERROR_HOOK} ) " \
669
+ "#{ERROR_HOOK}(#{ERROR_HOOK_DATA});\n}\n"
670
+ else
671
+ standin = "(#{return_c_type}) #{ERROR_STANDIN}"
672
+ "#{return_c_type}\n#{name} (#{parameters.join(', ')})\n{\n" \
673
+ " if ( #{ERROR_FLAG} ) return #{standin};\n" \
674
+ " #{return_c_type} value = #{body_symbol}(#{arguments});\n" \
675
+ " if ( #{ERROR_FLAG} ) {\n" \
676
+ " if ( #{ERROR_HOOK} ) #{ERROR_HOOK}(#{ERROR_HOOK_DATA});\n" \
677
+ " return #{standin};\n" \
678
+ " }\n" \
679
+ " return value;\n}\n"
680
+ end
441
681
  end
442
682
 
443
683
  attr_reader :function_definition
444
684
 
685
+ # A body standing on its own does no more work once its flag stands.
686
+ #
687
+ # The `!ERROR_FLAG` at each `raise` keeps a later report from overwriting
688
+ # an earlier one, and that is enough for a caller that stops: a kernel
689
+ # ends its loop, and `CFunction#call` was one call to begin with. A
690
+ # library handed the address does not stop. It calls again, and without
691
+ # this the body skips the report it has already made and answers as
692
+ # though nothing had happened -- so an adaptive routine converges on
693
+ # values that are fiction, which is worse than a wrong answer because it
694
+ # looks like a right one.
695
+ #
696
+ # What the gate says is that the body does no more work. It does not
697
+ # say what the call is worth: the flag is the contract, and the zero
698
+ # goes to this body's own caller -- the lending wrapper, or the body
699
+ # itself recursing -- rather than to C, which is told whatever the
700
+ # window chose. A `void` body has no zero to offer and leaves its
701
+ # out-parameters alone, which is the same refusal to work.
702
+ #
703
+ # It goes in the file and not in the definition, so that the form a
704
+ # kernel pastes cannot pick it up whichever way the two forms are
705
+ # generated. A kernel reads its slot once, after a loop it stopped
706
+ # itself, and has no use for it.
707
+ def standing_gate
708
+ return "" unless @uses_error_flag && !@error_parameter
709
+ " if ( #{ERROR_FLAG} ) #{@returns_nothing ? "return;" : "return 0;"}\n\n"
710
+ end
711
+
445
712
  # What the body took from the preamble, so that a definition pasted
446
713
  # somewhere else can be given the same helpers. Only the ones a pasted
447
714
  # function can want are here: the rest -- the index check, the two
448
715
  # flooring helpers -- report through the error flag, and a function that
449
716
  # touches the flag is not pasted at all.
450
717
  def helper_needs
451
- { :integer_power => @uses_integer_power,
718
+ { :intrinsics => @intrinsic_needs.dup,
719
+ :clears_a_local_array => clears_a_local_array?,
720
+ :integer_power => @uses_integer_power,
721
+ :integer_abs => @uses_integer_abs,
722
+ :whole_number => @uses_whole_number,
452
723
  :unsigned_divide => @uses_unsigned_divide,
453
724
  :unsigned_modulo => @uses_unsigned_modulo,
454
725
  :unsigned_power => @uses_unsigned_power,
455
726
  :floor_modulo_float => @uses_floor_modulo_float,
456
727
  :real_arg => @uses_real_arg,
728
+ :real_power_complex => @uses_real_power_complex,
729
+ :clamp => @clamp_types.dup,
730
+ :gamma => @gamma_types.dup,
457
731
  :complex => @complex_helpers.dup,
458
732
  :index_check => @uses_index_check,
459
733
  :floor_divide => @uses_floor_divide,
460
- :floor_modulo => @uses_floor_modulo }
734
+ :floor_modulo => @uses_floor_modulo,
735
+ :shift => @uses_shift }
461
736
  end
462
737
 
463
- # One per compiled object, so two functions never share it, and zeroed
464
- # by whoever is about to look -- the same discipline the kernel's own
465
- # error slot keeps. It is written only where the value returned is
466
- # already a stand-in, so a caller that never looks is no worse off than
467
- # C leaves it.
738
+ # Per compiled object and per thread, and zeroed by whoever is about
739
+ # to look -- the same discipline the kernel's own error slot keeps. It
740
+ # is written only where the value returned is already a stand-in, so a
741
+ # caller that never looks is no worse off than C leaves it.
742
+ #
743
+ # `_Thread_local` because a window is one thread's: the object is shared
744
+ # whether or not anybody meant to share it -- two blocks with the same
745
+ # text compile to one body -- and a single flag between two threads is a
746
+ # window neither of them can read. It costs about half a nanosecond a
747
+ # call, measured, and only a body that can fail has one at all.
468
748
  def error_flag_declaration
469
749
  "/* Standing at 1 when a division had no divisor, and at the code of\n" \
470
750
  " a `raise` in the body where one was reached -- the numbers a\n" \
471
751
  " kernel reports through its own slot, with the same meanings. A\n" \
472
752
  " subscript on a pointer parameter is not checked here and does not\n" \
473
753
  " appear: it is the caller's business, as it is in C. */\n" \
474
- "int32_t #{ERROR_FLAG} = 0;\n\n"
754
+ "static #{THREAD_LOCAL}int32_t #{ERROR_FLAG} = 0;\n\n"
475
755
  end
476
756
 
477
757
  # The same kernel, wrapped so carray can drive it.
@@ -547,27 +827,66 @@ class CArray
547
827
  # A pasted body wants the same helpers here that it had in its own
548
828
  # file, and it is emitted below them, so this is asked before any of
549
829
  # them is written out.
550
- @pasted_functions.each_value do |function|
830
+ pasted_closure.each do |function|
551
831
  needs = function.helpers || {}
552
832
  @uses_integer_power ||= needs[:integer_power]
833
+ @uses_integer_abs ||= needs[:integer_abs]
834
+ @uses_whole_number ||= needs[:whole_number]
553
835
  @uses_unsigned_divide ||= needs[:unsigned_divide]
554
836
  @uses_unsigned_modulo ||= needs[:unsigned_modulo]
555
837
  @uses_unsigned_power ||= needs[:unsigned_power]
556
838
  @uses_floor_modulo_float ||= needs[:floor_modulo_float]
557
839
  @uses_real_arg ||= needs[:real_arg]
840
+ @uses_real_power_complex ||= needs[:real_power_complex]
841
+ @clamp_types |= needs[:clamp] || []
842
+ @gamma_types |= needs[:gamma] || []
558
843
  @complex_helpers |= needs[:complex] || []
559
844
  @uses_index_check ||= needs[:index_check]
560
845
  @uses_floor_divide ||= needs[:floor_divide]
561
846
  @uses_floor_modulo ||= needs[:floor_modulo]
847
+ @uses_shift ||= needs[:shift]
848
+ # A union rather than an or: two bodies may want a `sort` of one
849
+ # type and length and a `sum` of another, and the preamble owes one
850
+ # helper for each. The same shape `:clamp` and `:gamma` take.
851
+ @intrinsic_needs |= needs[:intrinsics] || []
852
+ # And whether anything anywhere in this file clears an array of its
853
+ # own, which is what `<string.h>` is included for. A pasted body's
854
+ # `memset` is in this translation unit, so it is this file's header.
855
+ @pasted_clears_a_local_array ||= !!needs[:clears_a_local_array]
562
856
  end
563
- text = +"#include <stdint.h>\n#include <math.h>\n#include <complex.h>\n" \
564
- "#include <stdio.h>\n\n"
857
+ # `stddef.h` is here for the signature's sake rather than the body's:
858
+ # a declaration may be written with `size_t` or `ptrdiff_t`, and that
859
+ # is the header those come from. `stdio.h` happens to declare
860
+ # `size_t` as well, which is why the omission went unnoticed until
861
+ # `ptrdiff_t` was written down.
862
+ text = +"#include <stdint.h>\n#include <stddef.h>\n" \
863
+ "#include <math.h>\n#include <complex.h>\n" \
864
+ "#include <stdio.h>\n"
865
+ # `memset`, and only where a body clears an array of its own. A
866
+ # kernel that clears nothing generates what it always did.
867
+ text << "#include <string.h>\n" if clears_a_local_array?
868
+ # malloc and free, for the arrays this kernel allocates. libc, the
869
+ # same ground `memset` above stands on: it needs no GVL and touches
870
+ # no Ruby value, which is what kept `ALLOCV` out of here.
871
+ text << "#include <stdlib.h>\n" unless heap_arrays.empty?
872
+ text << "\n"
565
873
  unless @address_functions.empty?
566
- text << "/* The C functions the block called. They arrive as\n" \
567
- " addresses rather than by linkage, so nothing here says\n" \
568
- " which library they came from. */\n"
569
- @address_functions.each_key do |name|
570
- text << @address_functions.fetch(name).c_declaration(c_function_type_name(name)) << "\n"
874
+ if @in_function
875
+ # A body standing on its own calls a borrowed function by its
876
+ # name, so what it needs is that function's own declaration --
877
+ # the one its author wrote -- and a linker.
878
+ text << "/* Declared where they are called from, and resolved " \
879
+ "by the linker\n or the loader. */\n"
880
+ @address_functions.each_value do |function|
881
+ text << "#{function.prototype};\n"
882
+ end
883
+ else
884
+ text << "/* The C functions the block called. They arrive as\n" \
885
+ " addresses rather than by linkage, so nothing here says\n" \
886
+ " which library they came from. */\n"
887
+ @address_functions.each_key do |name|
888
+ text << @address_functions.fetch(name).c_declaration(c_function_type_name(name)) << "\n"
889
+ end
571
890
  end
572
891
  text << "\n"
573
892
  end
@@ -589,14 +908,15 @@ class CArray
589
908
  computing wide and narrowing afterwards stops agreeing with
590
909
  computing narrow. */
591
910
  static inline float
592
- carray_jit_floor_modulo_float (float numerator, float denominator)
911
+ carray_jit_floor_modulo_float (float numerator, float denominator, int32_t *error)
593
912
  {
594
- float remainder = fmodf(numerator, denominator);
595
- if ( remainder != 0 ) {
596
- if ( (remainder < 0) != (denominator < 0) ) remainder += denominator;
913
+ if ( denominator == 0 ) {
914
+ if ( error ) *error = 1;
915
+ return 0;
597
916
  }
598
- else {
599
- remainder = copysignf(0.0f, denominator);
917
+ float remainder = fmodf(numerator, denominator);
918
+ if ( remainder != 0 && (remainder < 0) != (denominator < 0) ) {
919
+ remainder += denominator;
600
920
  }
601
921
  return remainder;
602
922
  }
@@ -677,6 +997,56 @@ class CArray
677
997
 
678
998
  C
679
999
  end
1000
+ if @uses_whole_number
1001
+ text << <<~C
1002
+ /* `floor`, `ceil`, `round` and `truncate` on a Float answer an
1003
+ Integer in Ruby, and a NaN or an infinity has none to answer:
1004
+ Ruby raises FloatDomainError. A number past int64 has one, but
1005
+ not in an int64_t, where the cast is undefined -- CArray raises
1006
+ RangeError storing such an Integer, and so does this. The real
1007
+ one is for a value that stays a number: 1e20.floor into a
1008
+ float64 cell is 1e20 in Ruby, and does not pass through int64.
1009
+ Adding zero clears the sign of a zero: (-0.3).ceil is the
1010
+ Integer 0, which has none, where ceil(-0.3) is -0.0. */
1011
+ static inline double
1012
+ carray_jit_whole_real (double value, int32_t *error)
1013
+ {
1014
+ if ( isnan(value) ) {
1015
+ if ( error ) *error = #{FLOAT_NAN_CODE};
1016
+ }
1017
+ else if ( isinf(value) ) {
1018
+ if ( error ) *error = value > 0 ? #{FLOAT_INFINITY_CODE} : #{FLOAT_NEGATIVE_INFINITY_CODE};
1019
+ }
1020
+ return value + 0.0;
1021
+ }
1022
+
1023
+ static inline int64_t
1024
+ carray_jit_whole_int64 (double value, int32_t *error)
1025
+ {
1026
+ if ( ! ( value >= -9223372036854775808.0 && value < 9223372036854775808.0 ) ) {
1027
+ carray_jit_whole_real(value, error);
1028
+ if ( error && ! isnan(value) && ! isinf(value) ) *error = #{INTEGER_RANGE_CODE};
1029
+ return 0;
1030
+ }
1031
+ return (int64_t) value;
1032
+ }
1033
+
1034
+ C
1035
+ end
1036
+ if @uses_integer_abs
1037
+ text << <<~C
1038
+ /* An integer's magnitude, without llabs: that is <stdlib.h>'s,
1039
+ which a kernel includes only when it allocates, and it leaves
1040
+ INT64_MIN undefined. Negated through uint64_t, INT64_MIN
1041
+ wraps to itself -- the wrap an int64 cell has everywhere else. */
1042
+ static inline int64_t
1043
+ carray_jit_integer_abs (int64_t value)
1044
+ {
1045
+ return value < 0 ? (int64_t) (0 - (uint64_t) value) : value;
1046
+ }
1047
+
1048
+ C
1049
+ end
680
1050
  COMPLEX_HELPERS.each do |name, definition|
681
1051
  [false, true].each do |narrow|
682
1052
  next unless @complex_helpers.include?([name, narrow])
@@ -684,6 +1054,76 @@ class CArray
684
1054
  : definition) << "\n"
685
1055
  end
686
1056
  end
1057
+ @gamma_types.each do |type|
1058
+ suffix, c_type, gamma, modf = GAMMA_C_TYPES.fetch(type)
1059
+ table = (1..GAMMA_TABLE_LIMIT).map { |whole|
1060
+ format_float(Math.gamma(whole.to_f), type)
1061
+ }
1062
+ text << <<~C
1063
+ /* `Math.gamma` is tgamma with Ruby's two answers around it: a
1064
+ whole number up to #{GAMMA_TABLE_LIMIT} is answered from the table Ruby
1065
+ answers it from, and a negative whole number -- where tgamma
1066
+ gives a NaN -- is the domain error Ruby raises. The values
1067
+ are the ones the Ruby that compiled this holds. */
1068
+ static const #{c_type} carray_jit_gamma_table_#{suffix}[#{GAMMA_TABLE_LIMIT}] = {
1069
+ #{table.each_slice(4).map { |row| row.join(", ") }.join(",\n ")}
1070
+ };
1071
+
1072
+ static inline #{c_type}
1073
+ carray_jit_gamma_#{suffix} (#{c_type} x, int32_t *error)
1074
+ {
1075
+ if ( isinf(x) ) {
1076
+ if ( signbit(x) ) {
1077
+ if ( error ) *error = 5;
1078
+ return 0;
1079
+ }
1080
+ return x;
1081
+ }
1082
+ #{c_type} whole;
1083
+ if ( #{modf}(x, &whole) == 0 ) {
1084
+ if ( whole < 0 ) {
1085
+ if ( error ) *error = 5;
1086
+ return 0;
1087
+ }
1088
+ if ( 0 < whole && whole <= #{GAMMA_TABLE_LIMIT} ) {
1089
+ return carray_jit_gamma_table_#{suffix}[(int)whole - 1];
1090
+ }
1091
+ }
1092
+ return #{gamma}(x);
1093
+ }
1094
+
1095
+ C
1096
+ end
1097
+ text << intrinsic_helpers
1098
+ @clamp_types.each do |type|
1099
+ suffix, c_type, has_nan = CLAMP_C_TYPES.fetch(type)
1100
+ refusal = lambda { |test, code|
1101
+ " if ( #{test} ) {\n" \
1102
+ " if ( error ) *error = #{code};\n" \
1103
+ " return value;\n" \
1104
+ " }\n"
1105
+ }
1106
+ tests = +""
1107
+ tests << refusal.call("isnan(low) || isnan(high)", 4) if has_nan
1108
+ tests << refusal.call("low > high", 3)
1109
+ tests << refusal.call("isnan(value)", 4) if has_nan
1110
+ text << <<~C
1111
+ /* `x.clamp(low, high)`, and the two things Ruby raises
1112
+ ArgumentError for: bounds the wrong way round, and a
1113
+ comparison that cannot be made because a NaN is in it. The
1114
+ order is Ruby's -- the bounds are ordered against each other
1115
+ before the value is looked at. */
1116
+ static inline #{c_type}
1117
+ carray_jit_clamp_#{suffix} (#{c_type} value, #{c_type} low, #{c_type} high, int32_t *error)
1118
+ {
1119
+ #{tests.chomp}
1120
+ if ( value < low ) return low;
1121
+ if ( value > high ) return high;
1122
+ return value;
1123
+ }
1124
+
1125
+ C
1126
+ end
687
1127
  if @uses_real_arg
688
1128
  text << <<~C
689
1129
  /* The argument of a real number, which Ruby reads off the sign
@@ -698,6 +1138,33 @@ class CArray
698
1138
 
699
1139
  C
700
1140
  end
1141
+ if @uses_real_power_complex
1142
+ text << <<~C
1143
+ /* A real power read as complex. Ruby answers a negative base
1144
+ raised to a power that is not an integer with a Complex, in
1145
+ polar form: (-x)**y at the angle y*pi, exact on the axes.
1146
+ Anything else is the real power. */
1147
+ static double _Complex
1148
+ carray_jit_real_power_complex (double x, double y)
1149
+ {
1150
+ double fi, fr, a;
1151
+ if ( ! ( x < 0.0 ) || y == round(y) ) return CMPLX(pow(x, y), 0.0);
1152
+ a = pow(-x, y);
1153
+ fr = modf(y, &fi);
1154
+ if ( fr == 0.5 || fr == -0.5 ) {
1155
+ int up = ( fr == 0.5 );
1156
+ if ( ( modf(fi / 2.0, &fi) != fr ) ^ up ) a = -a;
1157
+ return CMPLX(0.0, a);
1158
+ }
1159
+ #if defined(__APPLE__)
1160
+ return CMPLX(a * __cospi(y), a * __sinpi(y));
1161
+ #else
1162
+ return CMPLX(a * cos(y * M_PI), a * sin(y * M_PI));
1163
+ #endif
1164
+ }
1165
+
1166
+ C
1167
+ end
701
1168
  if @uses_clamp
702
1169
  text << <<~C
703
1170
  /* A window that falls off the array reads the nearest cell it
@@ -754,10 +1221,15 @@ class CArray
754
1221
  /* Ruby's `%` floors with its division: the remainder carries the
755
1222
  sign of the divisor, where C's `%` and fmod carry the sign of
756
1223
  the dividend. So add the divisor back when the remainder is
757
- non-zero and disagrees with it in sign -- and, for floats,
758
- give a zero remainder the divisor's sign, so the rule holds
759
- without exception. This mirrors CArray's own `:mod` kernel in
760
- `ext/mkkernel.rb`. */
1224
+ non-zero and disagrees with it in sign. A zero remainder keeps
1225
+ fmod's sign, the dividend's, as Ruby's Float#% does: -4.0 % 2.0
1226
+ is -0.0. (CArray's own `%` gives it the divisor's sign instead;
1227
+ a block means what it means in Ruby.)
1228
+
1229
+ A zero divisor is Ruby's rather than CArray's: `3.0 % 0.0` raises
1230
+ ZeroDivisionError in Ruby, a float divisor as much as an integer
1231
+ one, where fmod and CArray answer NaN. `3.0 / 0.0` is not that
1232
+ case -- an infinity in Ruby as in C -- and is left alone. */
761
1233
  static inline int64_t
762
1234
  carray_jit_floor_modulo (int64_t numerator, int64_t denominator, int32_t *error)
763
1235
  {
@@ -765,6 +1237,7 @@ class CArray
765
1237
  if ( error ) *error = 1;
766
1238
  return 0;
767
1239
  }
1240
+ if ( denominator == -1 ) return 0;
768
1241
  int64_t remainder = numerator % denominator;
769
1242
  if ( remainder != 0 && ((remainder < 0) != (denominator < 0)) ) {
770
1243
  remainder += denominator;
@@ -773,20 +1246,69 @@ class CArray
773
1246
  }
774
1247
 
775
1248
  static inline double
776
- carray_jit_floor_modulo_real (double numerator, double denominator)
1249
+ carray_jit_floor_modulo_real (double numerator, double denominator, int32_t *error)
777
1250
  {
778
- double remainder = fmod(numerator, denominator);
779
- if ( remainder != 0 ) {
780
- if ( (remainder < 0) != (denominator < 0) ) remainder += denominator;
1251
+ if ( denominator == 0 ) {
1252
+ if ( error ) *error = 1;
1253
+ return 0;
781
1254
  }
782
- else {
783
- remainder = copysign(0.0, denominator);
1255
+ double remainder = fmod(numerator, denominator);
1256
+ if ( remainder != 0 && (remainder < 0) != (denominator < 0) ) {
1257
+ remainder += denominator;
784
1258
  }
785
1259
  return remainder;
786
1260
  }
787
1261
 
788
1262
  C
789
1263
  end
1264
+ if @uses_shift
1265
+ text << <<~C
1266
+ /* Integer#<< and #>>: a negative count shifts the other way, and a
1267
+ count of 64 or more shifts every bit out -- to 0, or to -1 for a
1268
+ negative value shifted right. C leaves both undefined, and a
1269
+ left shift of a negative value too, so the left shift is made in
1270
+ uint64_t. A count held unsigned is brought into int64_t range
1271
+ first; past 64 they all mean the same. */
1272
+ static inline int64_t
1273
+ carray_jit_shift_count (uint64_t count)
1274
+ {
1275
+ return count > 64 ? 64 : (int64_t) count;
1276
+ }
1277
+
1278
+ static inline int64_t
1279
+ carray_jit_shift_left (int64_t value, int64_t count)
1280
+ {
1281
+ if ( count >= 64 ) return 0;
1282
+ if ( count <= -64 ) return value < 0 ? -1 : 0;
1283
+ if ( count < 0 ) return value >> -count;
1284
+ return (int64_t) ((uint64_t) value << count);
1285
+ }
1286
+
1287
+ static inline int64_t
1288
+ carray_jit_shift_right (int64_t value, int64_t count)
1289
+ {
1290
+ if ( count >= 64 ) return value < 0 ? -1 : 0;
1291
+ if ( count <= -64 ) return 0;
1292
+ if ( count < 0 ) return (int64_t) ((uint64_t) value << -count);
1293
+ return value >> count;
1294
+ }
1295
+
1296
+ static inline uint64_t
1297
+ carray_jit_unsigned_shift_left (uint64_t value, int64_t count)
1298
+ {
1299
+ if ( count >= 64 || count <= -64 ) return 0;
1300
+ return count < 0 ? value >> -count : value << count;
1301
+ }
1302
+
1303
+ static inline uint64_t
1304
+ carray_jit_unsigned_shift_right (uint64_t value, int64_t count)
1305
+ {
1306
+ if ( count >= 64 || count <= -64 ) return 0;
1307
+ return count < 0 ? value << -count : value >> count;
1308
+ }
1309
+
1310
+ C
1311
+ end
790
1312
  if @uses_floor_divide
791
1313
  text << <<~C
792
1314
  /* Ruby and CArray floor integer division and give the remainder the
@@ -805,6 +1327,9 @@ class CArray
805
1327
  if ( error ) *error = 1;
806
1328
  return 0;
807
1329
  }
1330
+ /* INT64_MIN / -1 does not fit, and x86 traps on it: the
1331
+ quotient is the negation wrapped, as CArray answers it. */
1332
+ if ( denominator == -1 ) return (int64_t) (0 - (uint64_t) numerator);
808
1333
  int64_t quotient = numerator / denominator;
809
1334
  if ( numerator % denominator != 0 && ((numerator < 0) != (denominator < 0)) ) {
810
1335
  quotient -= 1;
@@ -814,9 +1339,40 @@ class CArray
814
1339
 
815
1340
  C
816
1341
  end
1342
+ text << random_source
817
1343
  text << pasted_definitions
818
1344
  end
819
1345
 
1346
+ # The generators the block drew from, as CArray wrote them.
1347
+ #
1348
+ # This is the COMPLEX_HELPERS path and not the pasted-body one: what
1349
+ # CArray hands over is a run of `static inline` functions, not one
1350
+ # definition to be given a `static` and a name. It goes in verbatim --
1351
+ # reading it here to check it would be this gem deciding what CArray's
1352
+ # generator is, which is the drift the shared text exists to prevent.
1353
+ #
1354
+ # Only when a draw was written, and once however many generators drew:
1355
+ # two CArray::Rng of the same kind are the same C over different
1356
+ # state.
1357
+ def random_source
1358
+ kinds = @analyzer.random_names.map { |name|
1359
+ @randoms.fetch(name).generator
1360
+ }.uniq.sort
1361
+ return "" if kinds.empty?
1362
+ # What every generator's text wants beside it and none of them owns.
1363
+ # Once, ahead of them: two generators in this file would otherwise
1364
+ # define it twice.
1365
+ text = +"/* What a draw needs beside a generator, from\n" \
1366
+ " CArray::Rng::COMMON_SOURCE. */\n" +
1367
+ CArray::Rng::COMMON_SOURCE + "\n"
1368
+ text + kinds.map { |kind|
1369
+ "/* #{kind}, from CArray::Rng::SOURCE -- the same text CArray\n" \
1370
+ " compiled, so a kernel continues the sequence `random!` left\n" \
1371
+ " off at rather than agreeing with it by construction. */\n" +
1372
+ CArray::Rng::SOURCE.fetch(kind) + "\n"
1373
+ }.join
1374
+ end
1375
+
820
1376
  # The bodies of the functions written with `jit_function`, put in this
821
1377
  # translation unit as statics and called by name. An address the
822
1378
  # compiler cannot see through is a call it cannot inline, and the loop
@@ -829,18 +1385,49 @@ class CArray
829
1385
  # one. The name carries the digest of the body, so two of them are the
830
1386
  # same function, and one is pasted once however many names the block
831
1387
  # reached it by.
1388
+ # Every function whose definition ends up in this file: the ones the
1389
+ # block named, and the ones those call. Helpers and raise messages
1390
+ # are asked of all of them, since a body pasted three deep reports
1391
+ # through the same slot and wants the same preamble.
1392
+ def pasted_closure
1393
+ found = {}
1394
+ walk = lambda do |function|
1395
+ # A borrowed function has no definition to paste; it is declared.
1396
+ next unless function.pasted?
1397
+ next if found[function.symbol]
1398
+ found[function.symbol] = function
1399
+ (function.dependencies || []).each { |called| walk.call(called) }
1400
+ end
1401
+ @pasted_functions.each_value { |function| walk.call(function) }
1402
+ found.values
1403
+ end
1404
+
1405
+ # A pasted body may itself call a function compiled here, which it
1406
+ # reaches by symbol -- so that one is pasted too, and ahead of it, or
1407
+ # the call would be to a name this file has not defined yet. The same
1408
+ # `seen` covers both: one definition per symbol however many ways it
1409
+ # was reached.
832
1410
  def pasted_definitions
833
1411
  seen = {}
834
1412
  text = +""
835
1413
  @pasted_functions.each_value do |function|
836
- next if seen[function.name]
837
- seen[function.name] = true
838
- text << "/* #{function} */\n" \
839
- "static #{function.definition}\n"
1414
+ text << paste_definition(function, seen)
840
1415
  end
841
1416
  text
842
1417
  end
843
1418
 
1419
+ def paste_definition (function, seen)
1420
+ return "" unless function.pasted?
1421
+ return "" if seen[function.symbol]
1422
+ seen[function.symbol] = true
1423
+ text = +""
1424
+ (function.dependencies || []).each do |called|
1425
+ text << paste_definition(called, seen)
1426
+ end
1427
+ text << "/* #{function} */\n" \
1428
+ "static #{function.definition}\n"
1429
+ end
1430
+
844
1431
  # One compiled object holds both loops and picks between them once,
845
1432
  # outside the loop. The contiguous form indexes a typed pointer along
846
1433
  # the innermost axis, which the compiler can vectorise; the strided form
@@ -848,7 +1435,7 @@ class CArray
848
1435
  def dispatcher
849
1436
  tests = @arrays.map { |array|
850
1437
  "strides[#{@stride_offsets.fetch(array) + array_rank(array) - 1}] == " \
851
- "(int64_t) sizeof(#{storage_c_type(array)})"
1438
+ "(int64_t) sizeof(#{storage_c_type(array_storage(array))})"
852
1439
  }
853
1440
  # A kernel reaching no array cell has nothing to be contiguous about
854
1441
  # -- it can only be one whose work is a call, the arrays it touches
@@ -878,7 +1465,6 @@ class CArray
878
1465
 
879
1466
  def build_body (contiguous)
880
1467
  @contiguous = contiguous
881
- @declared_locals = {}
882
1468
  @temporary_count = 0
883
1469
  @carried_masks = []
884
1470
  # Whether this body has a way to report -- asked of the statements
@@ -886,10 +1472,202 @@ class CArray
886
1472
  # kernel carries every extent of its arrays so the border rule has
887
1473
  # them, which says nothing about whether a cell can fail.
888
1474
  @body_reports = false
1475
+ indent = " " + " " * @rank
889
1476
  statements = @analyzer.body.statements.map { |statement|
890
- emit_statement(statement, " " + " " * @rank)
1477
+ emit_statement(statement, indent)
1478
+ }.join
1479
+ "{\n" + declarations + heap_prologue + loop_open +
1480
+ local_declarations(@analyzer.body, indent) + statements +
1481
+ loop_close + heap_epilogue + "}\n"
1482
+ end
1483
+
1484
+ # The arrays this kernel allocates, in the order the block declared
1485
+ # them, as [C name, storage, shape].
1486
+ #
1487
+ # Gathered from every scope rather than from the one being emitted: the
1488
+ # allocation is at the function's entry, outside the cell loop, so a
1489
+ # pointer declared for an array the block made inside an inner loop
1490
+ # still stands at the top of the function. Two sibling loops that each
1491
+ # write `w` are two bindings and so two pointers, which is what keeps
1492
+ # them the two arrays Ruby says they are.
1493
+ def heap_arrays
1494
+ @heap_arrays ||= begin
1495
+ found = []
1496
+ walk = lambda do |node|
1497
+ if node.respond_to?(:array_declarations) && node.array_declarations
1498
+ node.array_declarations.each do |name, binding, storage, shape, heap|
1499
+ next unless heap
1500
+ entry = [local_c_name(name, binding), storage, shape]
1501
+ found << entry unless found.include?(entry)
1502
+ end
1503
+ end
1504
+ node.children.each { |child| walk.call(child) if child.is_a?(Node) }
1505
+ end
1506
+ walk.call(@analyzer.body)
1507
+ found
1508
+ end
1509
+ end
1510
+
1511
+ # One allocation per array at the entry, before the loop: the cells,
1512
+ # and the shadow beside them where the kernel carries masks.
1513
+ #
1514
+ # The lengths come first and stand in `const int64_t` of their own,
1515
+ # because each is read three times over -- to check it, to size the
1516
+ # allocation, and at every subscript on that axis -- and the expression
1517
+ # behind it may be anything the block wrote. A length that is not a
1518
+ # whole number of cells above zero is reported rather than allocated,
1519
+ # which is what the same shape written as a number is refused for as
1520
+ # the block is read. So is a length whose cells would not fit in a
1521
+ # `size_t`: the multiplication into `malloc` would wrap, and a small
1522
+ # allocation answered for a huge one is the worst of the outcomes.
1523
+ #
1524
+ # That is asked of the lengths before they are multiplied, one axis at
1525
+ # a time against what the axes before it leave of the limit. Asked of
1526
+ # the product, it came too late: two lengths of 2**32 multiply to a
1527
+ # number that has already wrapped to zero, which fits, and every
1528
+ # subscript was then checked against its own axis and let through
1529
+ # into an allocation of nothing. The limit is `int64_t` as well as
1530
+ # `size_t`, since that is what the cells are counted in.
1531
+ def heap_prologue
1532
+ return "" if heap_arrays.empty?
1533
+ lines = +""
1534
+ heap_arrays.each do |variable, storage, shape|
1535
+ shape.each_with_index do |extent, axis|
1536
+ next if extent.is_a?(Integer)
1537
+ lines << " const int64_t #{heap_extent_name(variable, axis)} = " \
1538
+ "#{emit(extent.node, :int64)};\n"
1539
+ end
1540
+ room = "(uint64_t) (SIZE_MAX / sizeof(#{storage_c_type(storage)}))"
1541
+ lines << " const uint64_t #{heap_limit_name(variable)} =\n" \
1542
+ " #{room} < (uint64_t) INT64_MAX ? #{room} : (uint64_t) INT64_MAX;\n"
1543
+ lengths = heap_extent_texts(variable, shape)
1544
+ tests = shape.each_with_index.filter_map { |extent, axis|
1545
+ next if extent.is_a?(Integer)
1546
+ "#{heap_extent_name(variable, axis)} >= 1"
1547
+ } + lengths.each_index.map { |axis|
1548
+ left = [heap_limit_name(variable)] +
1549
+ lengths.first(axis).map { |length| "(uint64_t) #{length}" }
1550
+ "(uint64_t) #{lengths[axis]} <= #{left.join(' / ')}"
1551
+ }
1552
+ lines << " const int #{heap_fits_name(variable)} =\n" \
1553
+ " #{tests.join("\n && ")};\n"
1554
+ next if literal_shape?(shape)
1555
+ lines << " const int64_t #{heap_cells_name(variable)} = " \
1556
+ "#{heap_fits_name(variable)} ? #{lengths.join(' * ')} : 0;\n"
1557
+ end
1558
+ heap_arrays.each do |variable, storage, _shape|
1559
+ lines << " #{storage_c_type(storage)} *#{variable} = NULL;\n"
1560
+ lines << " uint8_t *#{local_mask_name(variable)} = NULL;\n" if @masked
1561
+ end
1562
+ unfit = heap_arrays.map { |variable, _storage, _shape|
1563
+ "!#{heap_fits_name(variable)}"
1564
+ }
1565
+ lines << " if ( #{unfit.join(' || ')} ) {\n" \
1566
+ " if ( error ) *error = #{SHAPE_CODE};\n" \
1567
+ " return;\n" \
1568
+ " }\n"
1569
+ heap_arrays.each do |variable, storage, shape|
1570
+ cells = local_array_cells_text(variable, shape)
1571
+ lines << " #{variable} = malloc(sizeof(#{storage_c_type(storage)}) " \
1572
+ "* (size_t) #{cells});\n"
1573
+ next unless @masked
1574
+ lines << " #{local_mask_name(variable)} = malloc((size_t) #{cells});\n"
1575
+ end
1576
+ held = heap_arrays.flat_map { |variable, _storage, _shape|
1577
+ [variable] + (@masked ? [local_mask_name(variable)] : [])
1578
+ }
1579
+ lines << " if ( #{held.map { |name| "!#{name}" }.join(' || ')} ) {\n"
1580
+ held.each { |name| lines << " free(#{name});\n" }
1581
+ lines << " if ( error ) *error = #{MEMORY_CODE};\n" \
1582
+ " return;\n" \
1583
+ " }\n\n"
1584
+ lines
1585
+ end
1586
+
1587
+ # Every way out of a kernel that allocated: the fall-through at the end
1588
+ # of the loop, and the one `return` a `raise` emits, which stands
1589
+ # inside it. Counted rather than assumed -- a leak here is a leak per
1590
+ # call, and the sweep calls once per chunk.
1591
+ def heap_epilogue
1592
+ heap_release(" ")
1593
+ end
1594
+
1595
+ def heap_release (indent)
1596
+ return "" if heap_arrays.empty?
1597
+ heap_arrays.map { |variable, _storage, _shape|
1598
+ "#{indent}free(#{variable});\n" +
1599
+ (@masked ? "#{indent}free(#{local_mask_name(variable)});\n" : "")
1600
+ }.join
1601
+ end
1602
+
1603
+ def heap_extent_name (variable, axis)
1604
+ "#{variable}__extent#{axis}"
1605
+ end
1606
+
1607
+ def heap_cells_name (variable)
1608
+ "#{variable}__cells"
1609
+ end
1610
+
1611
+ def heap_limit_name (variable)
1612
+ "#{variable}__limit"
1613
+ end
1614
+
1615
+ def heap_fits_name (variable)
1616
+ "#{variable}__fits"
1617
+ end
1618
+
1619
+ def heap_extent_texts (variable, shape)
1620
+ shape.each_with_index.map { |extent, axis|
1621
+ extent.is_a?(Integer) ? extent.to_s : heap_extent_name(variable, axis)
1622
+ }
1623
+ end
1624
+
1625
+ def literal_shape? (shape)
1626
+ shape.all? { |extent| extent.is_a?(Integer) }
1627
+ end
1628
+
1629
+ # The locals a scope holds, declared at the head of its block with no
1630
+ # value: every assignment below is a plain one, wherever it stands --
1631
+ # inside a `while` or an arm of an `if` included -- and nothing is read
1632
+ # before it is written, which the typing has already made sure of.
1633
+ def local_declarations (scope, indent)
1634
+ scope.declarations.map { |name, binding, type|
1635
+ variable = local_c_name(name, binding)
1636
+ "#{indent}#{COMPUTATION_C_TYPES.fetch(type)} #{variable};\n" +
1637
+ (@masked ? "#{indent}uint8_t #{local_mask_name(variable)};\n" : "")
1638
+ }.join + local_array_declarations(scope, indent)
1639
+ end
1640
+
1641
+ # The arrays a scope holds, declared at the head of its block beside the
1642
+ # locals. The length is the one the block wrote, so the C array is a
1643
+ # real one -- a fixed-size automatic object, not a pointer into
1644
+ # anything -- and its cells are addressed by constants.
1645
+ #
1646
+ # What clears the zeroed ones is emitted where the statement stands
1647
+ # rather than here: in Ruby a fresh array is made at that line each time
1648
+ # it runs, so a loop's body starts from cleared cells on every pass.
1649
+ def local_array_declarations (scope, indent)
1650
+ scope.array_declarations.map { |name, binding, storage, shape, heap|
1651
+ # One the kernel allocates is a pointer standing at the top of the
1652
+ # function, declared and freed with the allocation (see
1653
+ # #heap_prologue), so the scope it belongs to declares nothing.
1654
+ next "" if heap
1655
+ # One flat run of cells, whatever the rank: the subscripts are
1656
+ # folded to a row-major offset with the strides baked in (see
1657
+ # #local_array_reference), and a flat array is also what a C
1658
+ # function's pointer parameter is handed. `double m[3][4]` would
1659
+ # be the same bytes and a second spelling to keep in step.
1660
+ variable = local_c_name(name, binding)
1661
+ cells = shape.inject(1, :*)
1662
+ # Where the kernel carries masks, a shadow of one byte a cell
1663
+ # beside the cells -- the same arrangement a scalar local has, one
1664
+ # byte beside its value, spread over the cells. A cell of a local
1665
+ # array then reads like a cell of a captured one: the value, and
1666
+ # whether it is there.
1667
+ "#{indent}#{storage_c_type(storage)} #{variable}[#{cells}];\n" +
1668
+ (@masked ?
1669
+ "#{indent}uint8_t #{local_mask_name(variable)}[#{cells}];\n" : "")
891
1670
  }.join
892
- "{\n" + declarations + loop_open + statements + loop_close + "}\n"
893
1671
  end
894
1672
 
895
1673
  def array_rank (array)
@@ -930,38 +1708,44 @@ class CArray
930
1708
  end
931
1709
  end
932
1710
  @reals.each_with_index do |name, index|
933
- lines << " const double #{c_name(name)} = reals[#{index}];\n"
1711
+ lines << " const double #{bare_name(name)} = reals[#{index}];\n"
934
1712
  end
935
1713
  @complexes.each_with_index do |name, index|
936
1714
  slot = @reals.size + 2 * index
937
- lines << " const double _Complex #{c_name(name)} = " \
1715
+ lines << " const double _Complex #{bare_name(name)} = " \
938
1716
  "CMPLX(reals[#{slot}], reals[#{slot + 1}]);\n"
939
1717
  end
940
1718
  @integers.each_with_index do |name, index|
941
- lines << " const int64_t #{c_name(name)} = integers[#{index}];\n"
1719
+ lines << " const int64_t #{bare_name(name)} = integers[#{index}];\n"
1720
+ end
1721
+ # The cast is the whole of how a uint64 capture travels: the caller
1722
+ # packed the value's bits into the slot, and reading them as what they
1723
+ # are is what puts the value back.
1724
+ @unsigned_integers.each_with_index do |name, index|
1725
+ lines << " const uint64_t #{bare_name(name)} = " \
1726
+ "(uint64_t) integers[#{@integers.size + index}];\n"
942
1727
  end
943
1728
  @extent_slots.each_with_index do |(array, axis), slot|
944
1729
  lines << " const int64_t #{extent_name(array, axis)} = " \
945
- "integers[#{@integers.size + slot}];\n"
1730
+ "integers[#{@integers.size + @unsigned_integers.size + slot}];\n"
946
1731
  end
947
1732
  @address_functions.each_key.with_index do |name, index|
948
- lines << " const #{c_function_type_name(name)} #{c_name(name)} = " \
1733
+ lines << " const #{c_function_type_name(name)} #{bare_name(name)} = " \
949
1734
  "(#{c_function_type_name(name)}) functions[#{index}];\n"
950
1735
  end
951
1736
  @address_arrays.each_with_index do |array, index|
952
1737
  # Typed by the array rather than by the parameter it will be passed
953
1738
  # to: the caller has already checked that the two agree, and the
954
1739
  # array is the one that owns the memory.
955
- lines << " #{storage_c_type(array)} *const #{c_name(array)} = " \
956
- "(#{storage_c_type(array)} *) data[#{index}];\n"
1740
+ storage = storage_c_type(array_storage(array))
1741
+ lines << " #{storage} *const #{bare_name(array)} = " \
1742
+ "(#{storage} *) data[#{index}];\n"
957
1743
  end
958
1744
  lines.empty? ? "" : lines.join + "\n"
959
1745
  end
960
1746
 
961
- # Which way each axis runs is derived, not chosen: reading a cell the
962
- # kernel will later write means that cell has to be reached in one
963
- # particular order, and any other order would read what was never
964
- # written.
1747
+ # Which way each axis runs is the extent's step, and the loop runs that
1748
+ # order; nothing here checks it against the cells the body reads.
965
1749
  # Each axis carries a start, a limit and a step. The step is a compiled
966
1750
  # constant when it is one, because `i++` is what lets the loop vectorise
967
1751
  # and that is the case nearly every kernel is in.
@@ -997,6 +1781,20 @@ class CArray
997
1781
  def emit_statement (statement, indent)
998
1782
  case statement
999
1783
  when Assignment then emit_assignment(statement, indent)
1784
+ when ParallelAssignment then
1785
+ # The values, and then the writes. They are ordinary statements by
1786
+ # the time they reach here -- the analyzer made them so -- and the
1787
+ # order they are in is the whole of what a parallel assignment
1788
+ # means.
1789
+ statement.statements.map { |inner|
1790
+ emit_statement(inner, indent)
1791
+ }.join
1792
+ when IntrinsicStatement then emit_intrinsic_statement(statement, indent)
1793
+ when LocalArrayDeclaration then emit_local_array_clearing(statement, indent)
1794
+ when LocalArrayWrite then guarded(statement, indent) { |inner|
1795
+ emit_local_array_write(statement, inner) }
1796
+ when LocalArrayMaskWrite then guarded(statement, indent) { |inner|
1797
+ emit_local_array_mask_write(statement, inner) }
1000
1798
  when ElementWrite then guarded(statement, indent) { |inner|
1001
1799
  emit_element_write(statement, inner) }
1002
1800
  when MaskWrite then guarded(statement, indent) { |inner|
@@ -1019,6 +1817,33 @@ class CArray
1019
1817
 
1020
1818
  # 1 and 2 are the divisor that was not there and the subscript that ran
1021
1819
  # off its array. A `raise` in the block takes a code from here up.
1820
+ # What a kernel says when it could not start: a shape it worked out
1821
+ # that is no shape, and an allocation that failed. Negative, because
1822
+ # the positive codes from RAISE_CODE_FLOOR up are a digest of a
1823
+ # `raise` message and a fixed one among them could collide; nothing
1824
+ # reaches for a negative code, so the fixed ones are kept down here,
1825
+ # the kernel's own.
1826
+ SHAPE_CODE = -1
1827
+ MEMORY_CODE = -2
1828
+
1829
+ # And what a rounding reports where Ruby has no Integer to answer, or
1830
+ # has one an int64 cannot hold. Negative for the same reason: fixed
1831
+ # codes, which a `raise` digest must not land on.
1832
+ FLOAT_NAN_CODE = -3
1833
+ FLOAT_INFINITY_CODE = -4
1834
+ FLOAT_NEGATIVE_INFINITY_CODE = -5
1835
+ INTEGER_RANGE_CODE = -6
1836
+
1837
+ # The fixed failures a body reports, as the exception each one raises.
1838
+ # A kernel and a compiled function both look here, so the two say the
1839
+ # same thing for the same cell.
1840
+ FIXED_FAILURES = {
1841
+ FLOAT_NAN_CODE => [FloatDomainError, "NaN"],
1842
+ FLOAT_INFINITY_CODE => [FloatDomainError, "Infinity"],
1843
+ FLOAT_NEGATIVE_INFINITY_CODE => [FloatDomainError, "-Infinity"],
1844
+ INTEGER_RANGE_CODE => [RangeError, "a rounded Float is past the range of int64"],
1845
+ }.freeze
1846
+
1022
1847
  RAISE_CODE_FLOOR = 3
1023
1848
 
1024
1849
  # The code is taken from the message rather than counted off as messages
@@ -1067,10 +1892,13 @@ class CArray
1067
1892
  # A function returns whatever it returns, whatever happened -- the
1068
1893
  # arrangement its C caller is left with, and the one the division
1069
1894
  # helper already keeps by returning zero from a divide it refused.
1070
- # The value is not the answer; the flag says so.
1895
+ # The value is not the answer; the flag says so. For a body lent
1896
+ # out, this zero reaches the wrapper rather than C, and the wrapper
1897
+ # answers C with what the window chose.
1071
1898
  leaving = @in_function && !@returns_nothing ? "return 0;" : "return;"
1072
1899
  "#{indent}if ( #{tests.join(' && ')} ) {\n" \
1073
- "#{indent} #{report}\n" \
1900
+ "#{indent} #{report}\n" +
1901
+ heap_release("#{indent} ") +
1074
1902
  "#{indent} #{leaving}\n" \
1075
1903
  "#{indent}}\n"
1076
1904
  end
@@ -1229,17 +2057,28 @@ class CArray
1229
2057
  # report -- but writing outside it cannot: the report would arrive after
1230
2058
  # the damage. So a scatter works its positions out first, and writes
1231
2059
  # only if every one of them is inside.
2060
+ #
2061
+ # Each position carries the text of the extent it is tested against
2062
+ # rather than an array and an axis to look one up from. An operand's
2063
+ # extent is a variable the kernel was handed, and there are extents that
2064
+ # are not one of those; what the test needs is the text either way.
1232
2065
  def guarded (write, indent)
1233
2066
  positions = scattered_positions(write)
1234
2067
  return yield(indent) if positions.empty?
1235
2068
 
1236
2069
  lines = "#{indent}{\n"
1237
- positions.each do |temporary, node, array, axis|
2070
+ # Held by axis as well as by node: an axis whose length the kernel
2071
+ # works out is tested here even where the position is an index, and
2072
+ # an index is not a node the reference can look itself up by.
2073
+ held = {}
2074
+ positions.each_with_index do |(temporary, node, _extent), axis|
1238
2075
  lines << "#{indent} const int64_t #{temporary} = #{emit(node, :int64)};\n"
1239
2076
  @position_temporaries[node] = temporary
2077
+ held[positions_axis(write, axis)] = temporary
1240
2078
  end
1241
- test = positions.map { |temporary, _, array, axis|
1242
- "#{temporary} >= 0 && #{temporary} < #{extent_name(array, axis)}"
2079
+ @guarded_axes[write] = held
2080
+ test = positions.map { |temporary, _node, extent|
2081
+ "#{temporary} >= 0 && #{temporary} < #{extent}"
1243
2082
  }.join(" && ")
1244
2083
  lines << "#{indent} if ( #{test} ) {\n"
1245
2084
  lines << yield("#{indent} ")
@@ -1247,19 +2086,74 @@ class CArray
1247
2086
  lines << "#{indent} if ( #{error_argument} ) *#{error_argument} = 2;\n"
1248
2087
  lines << "#{indent} }\n"
1249
2088
  lines << "#{indent}}\n"
1250
- positions.each { |_, node, _, _| @position_temporaries.delete(node) }
2089
+ positions.each { |_, node, _| @position_temporaries.delete(node) }
2090
+ @guarded_axes.delete(write)
1251
2091
  lines
1252
2092
  end
1253
2093
 
2094
+ # Which axis the nth guarded position belongs to.
2095
+ def positions_axis (write, nth)
2096
+ guarded_axes_of(write).fetch(nth)
2097
+ end
2098
+
2099
+ def guarded_axes_of (write)
2100
+ write_subscripts(write).each_with_index.filter_map { |(index, offset), axis|
2101
+ axis if guarded_axis?(write, index, offset, axis)
2102
+ }
2103
+ end
2104
+
2105
+ # [temporary, position, extent text] for each axis of a write that is
2106
+ # addressed at a position only the running kernel knows.
1254
2107
  def scattered_positions (write)
1255
2108
  subscripts = write_subscripts(write)
1256
2109
  subscripts.each_with_index.filter_map { |(index, offset), axis|
1257
- next unless index.nil? && offset.is_a?(Node) &&
1258
- !Analyzer.fixed_subscript?(offset)
1259
- [next_temporary("position"), offset, write.array, axis]
2110
+ # An axis whose length the kernel works out has nothing that was
2111
+ # settled as the block was read -- a number, an index, an index
2112
+ # with an offset, all of them -- so every write onto one works its
2113
+ # position out here and is tested before it lands.
2114
+ next unless guarded_axis?(write, index, offset, axis)
2115
+ position = if index.nil? && offset.is_a?(Node) then offset
2116
+ elsif index.nil? then IntegerLiteral.new(offset)
2117
+ elsif offset.is_a?(Node) then offset
2118
+ else index_position_node(index, offset)
2119
+ end
2120
+ [next_temporary("position"), position, write_extent(write, axis)]
1260
2121
  }
1261
2122
  end
1262
2123
 
2124
+ # `k`, `k + 1`: the position an index and its offset stand for, as a
2125
+ # node, so that a write onto an axis the kernel sized can work it out
2126
+ # into a temporary and test it the way a scatter does.
2127
+ def index_position_node (index, offset)
2128
+ read = IndexVariable.new(index, 0)
2129
+ read.type = :int64
2130
+ return read if offset.zero?
2131
+ built = BinaryOperation.new(offset.negative? ? :- : :+, read,
2132
+ IntegerLiteral.new(offset.abs))
2133
+ built.type = :int64
2134
+ built
2135
+ end
2136
+
2137
+ def sized_at_runtime? (write, axis)
2138
+ write.respond_to?(:shape) && !write.shape.fetch(axis).is_a?(Integer)
2139
+ end
2140
+
2141
+ def guarded_axis? (write, index, offset, axis)
2142
+ return true if sized_at_runtime?(write, axis)
2143
+ index.nil? && offset.is_a?(Node) && !Analyzer.fixed_subscript?(offset)
2144
+ end
2145
+
2146
+ # The extent an axis of a write is tested against. An operand's is a
2147
+ # variable the kernel was handed; an array the body made carries the
2148
+ # length the block wrote, and there is no variable to name.
2149
+ def write_extent (write, axis)
2150
+ case write
2151
+ when LocalArrayWrite, LocalArrayMaskWrite
2152
+ local_array_extent_text(write, axis)
2153
+ else extent_name(write.array, axis)
2154
+ end
2155
+ end
2156
+
1263
2157
  # `out[i] = UNDEF` marks the cell missing. The bytes underneath are out
1264
2158
  # of contract, so there is nothing to store into them.
1265
2159
  def emit_mask_only_write (write, indent)
@@ -1267,8 +2161,23 @@ class CArray
1267
2161
  end
1268
2162
 
1269
2163
  # The loop a reduction runs in, inside one cell of the outer loops.
2164
+ #
2165
+ # A failure that reports and carries on -- a division handed back a
2166
+ # zero, a computed index handed back cell 0 -- is stopped here, at the
2167
+ # head of the next pass, in a function as in a kernel. The flag is
2168
+ # spelled three ways: a kernel's slot, the flag standing in a function's
2169
+ # own object, and the pointer a pasted body is handed, which a kernel
2170
+ # passes as null under a masked cell and so is asked about first.
2171
+ #
2172
+ # Called once the loop's body is emitted, since the body is what says
2173
+ # whether there is anything to report.
1270
2174
  def inner_loop_guard (indent)
1271
- @body_reports ? "#{indent} if ( *error ) break;\n" : ""
2175
+ return "" unless @body_reports
2176
+ flag = if !@in_function then "*error"
2177
+ elsif @error_parameter then "#{ERROR_FLAG} && *#{ERROR_FLAG}"
2178
+ else ERROR_FLAG
2179
+ end
2180
+ "#{indent} if ( #{flag} ) break;\n"
1272
2181
  end
1273
2182
 
1274
2183
  # The same shape the bounded loop gets, minus the counter -- including
@@ -1294,13 +2203,13 @@ class CArray
1294
2203
  @carried_masks =
1295
2204
  @masked ? (outer + [emit_mask(loop_node.condition)]).uniq : outer
1296
2205
 
1297
- text = "#{indent}while (#{emit(loop_node.condition, :boolean)}) {\n" +
1298
- inner_loop_guard(indent)
1299
- text += loop_node.statements.map { |statement|
2206
+ condition = emit(loop_node.condition, :boolean)
2207
+ body = loop_node.statements.map { |statement|
1300
2208
  emit_statement(statement, indent + " ")
1301
2209
  }.join
1302
2210
  @carried_masks = outer
1303
- text + "#{indent}}\n"
2211
+ "#{indent}while (#{condition}) {\n" + inner_loop_guard(indent) +
2212
+ body + "#{indent}}\n"
1304
2213
  end
1305
2214
 
1306
2215
  def emit_inner_loop (loop_node, indent)
@@ -1308,13 +2217,54 @@ class CArray
1308
2217
  return emit_split_reduction(loop_node, accumulation, indent) if accumulation
1309
2218
 
1310
2219
  index = loop_node.index
1311
- text = "#{indent}for (int64_t #{index} = #{emit(loop_node.from, :int64)}; " \
1312
- "#{index} < #{emit(loop_node.to, :int64)}; #{index}++) {\n" +
1313
- inner_loop_guard(indent)
1314
- text += loop_node.statements.map { |statement|
1315
- emit_statement(statement, indent + " ")
1316
- }.join
1317
- text + "#{indent}}\n"
2220
+ step = loop_node.step
2221
+ inner = indent + " "
2222
+ prelude, from, trips = loop_trips(loop_node, inner)
2223
+ count = "#{index}__t"
2224
+ body = local_declarations(loop_node, inner + " ") +
2225
+ loop_node.statements.map { |statement|
2226
+ emit_statement(statement, inner + " ")
2227
+ }.join
2228
+ "#{indent}{\n" + prelude +
2229
+ "#{inner}for (uint64_t #{count} = 0; #{count} < #{trips}; #{count}++) {\n" \
2230
+ "#{inner} int64_t #{index} = (int64_t) ((uint64_t) #{from} + " \
2231
+ "#{count} * (uint64_t) INT64_C(#{step}));\n" +
2232
+ inner_loop_guard(inner) + body + "#{inner}}\n" + "#{indent}}\n"
2233
+ end
2234
+
2235
+ # How many passes a loop makes, counted before it starts and in uint64.
2236
+ # Counting by comparing the index with the end overflows at the ends of
2237
+ # int64: an inclusive range ends at its last index plus one, and
2238
+ # `(MAX-2..MAX).each` ended at MAX + 1, which is no int64 at all. The
2239
+ # analyzer writes an inclusive end, and a `step` loop's end, as that
2240
+ # plus or minus one; read back here, the last index is used as it is.
2241
+ #
2242
+ # Returns [the C declaring the first index, the end and the count,
2243
+ # the first index's C name, the count's C name].
2244
+ def loop_trips (loop_node, inner)
2245
+ index = loop_node.index
2246
+ step = loop_node.step
2247
+ stride = step.abs
2248
+ to = loop_node.to
2249
+ last = to.is_a?(BinaryOperation) &&
2250
+ to.operator == (step.positive? ? :+ : :-) &&
2251
+ to.right.is_a?(IntegerLiteral) && to.right.value == 1 ? to.left : nil
2252
+ from_name, end_name, trips_name = "#{index}__from", "#{index}__end", "#{index}__trips"
2253
+ ahead = step.positive? ? "(uint64_t) #{end_name} - (uint64_t) #{from_name}" :
2254
+ "(uint64_t) #{from_name} - (uint64_t) #{end_name}"
2255
+ trips =
2256
+ if last
2257
+ reached = step.positive? ? "#{from_name} <= #{end_name}" : "#{from_name} >= #{end_name}"
2258
+ "(#{reached}) ? (#{ahead}) / #{stride}u + 1 : 0"
2259
+ else
2260
+ reached = step.positive? ? "#{from_name} < #{end_name}" : "#{from_name} > #{end_name}"
2261
+ "(#{reached}) ? (#{ahead} - 1) / #{stride}u + 1 : 0"
2262
+ end
2263
+ prelude =
2264
+ "#{inner}const int64_t #{from_name} = #{emit(loop_node.from, :int64)};\n" \
2265
+ "#{inner}const int64_t #{end_name} = #{emit(last || to, :int64)};\n" \
2266
+ "#{inner}const uint64_t #{trips_name} = #{trips};\n"
2267
+ [prelude, from_name, trips_name]
1318
2268
  end
1319
2269
 
1320
2270
  # The loop is a reduction when its whole body is one local folding a
@@ -1329,14 +2279,20 @@ class CArray
1329
2279
  # A masked accumulator carries a mask beside its value, and a partial
1330
2280
  # sum would need one each. Left out rather than half-done.
1331
2281
  return nil if @masked
2282
+ # The split walks the index a round at a time from one end, so it is
2283
+ # written for a loop that counts by one. A stride or a downward
2284
+ # sweep keeps the serial loop -- which costs nothing that was there
2285
+ # before, those loops having been unwritable until now.
2286
+ return nil unless loop_node.step == 1
1332
2287
  return nil unless loop_node.statements.size == 1
1333
2288
 
1334
2289
  assignment = loop_node.statements.first
1335
2290
  return nil unless assignment.is_a?(Assignment)
1336
- name = assignment.binding_name
1337
- # Declared before this loop, at this type, so the fold continues a
1338
- # value rather than starting one.
1339
- return nil unless @declared_locals[name] == assignment.type
2291
+ local = assignment.local
2292
+ # Live when this loop was entered, at this type and binding, so the
2293
+ # fold continues a value rather than starting one.
2294
+ return nil unless loop_node.entering&.[](assignment.name) ==
2295
+ [assignment.type, assignment.binding]
1340
2296
 
1341
2297
  expression = assignment.expression
1342
2298
  return nil unless expression.is_a?(BinaryOperation)
@@ -1351,9 +2307,9 @@ class CArray
1351
2307
  return nil if literal_extent(loop_node)&.<(PARTIAL_ACCUMULATORS)
1352
2308
 
1353
2309
  left, right = expression.left, expression.right
1354
- if accumulator?(left, name) && !mentions_local?(right, name)
2310
+ if accumulator?(left, local) && !mentions_local?(right, local)
1355
2311
  [assignment, operator]
1356
- elsif accumulator?(right, name) && !mentions_local?(left, name)
2312
+ elsif accumulator?(right, local) && !mentions_local?(left, local)
1357
2313
  [assignment, operator]
1358
2314
  end
1359
2315
  end
@@ -1376,13 +2332,14 @@ class CArray
1376
2332
  end
1377
2333
  end
1378
2334
 
1379
- def accumulator? (node, name)
1380
- node.is_a?(LocalRead) && node.binding_name == name
2335
+ # `local` is [name, binding]: the variable, not how it is spelled.
2336
+ def accumulator? (node, local)
2337
+ node.is_a?(LocalRead) && node.local == local
1381
2338
  end
1382
2339
 
1383
- def mentions_local? (node, name)
1384
- return true if accumulator?(node, name)
1385
- node.children.any? { |child| mentions_local?(child, name) }
2340
+ def mentions_local? (node, local)
2341
+ return true if accumulator?(node, local)
2342
+ node.children.any? { |child| mentions_local?(child, local) }
1386
2343
  end
1387
2344
 
1388
2345
  # The fold, run as PARTIAL_ACCUMULATORS chains instead of one, with the
@@ -1392,38 +2349,50 @@ class CArray
1392
2349
  # the operator's identity, so it is folded in exactly once. Each chain
1393
2350
  # keeps the term's own operand order -- what is licensed here is the
1394
2351
  # order the *iterations* are grouped in, not the order within one.
2352
+ # `k++`, `k--`, or the stride written out.
2353
+ def stride_step (index, step)
2354
+ case step
2355
+ when 1 then "#{index}++"
2356
+ when -1 then "#{index}--"
2357
+ else step.positive? ? "#{index} += #{step}" : "#{index} -= #{-step}"
2358
+ end
2359
+ end
2360
+
1395
2361
  def emit_split_reduction (loop_node, accumulation, indent)
1396
2362
  assignment, operator = accumulation
1397
- name = assignment.binding_name
2363
+ name = local_c_name(assignment.name, assignment.binding)
1398
2364
  type = assignment.type
1399
2365
  index = loop_node.index
1400
2366
  base = "#{index}__base"
1401
- limit = "#{index}__end"
1402
- lanes = (0...PARTIAL_ACCUMULATORS).map { |lane| "#{name}__p#{lane}" }
2367
+ # A lane belongs to the accumulator, so its C name comes the way every
2368
+ # local's does.
2369
+ lanes = (0...PARTIAL_ACCUMULATORS).map { |lane|
2370
+ local_c_name(assignment.name, assignment.binding, lane)
2371
+ }
1403
2372
  identity = (operator == :* ? ONES : ZEROES).fetch(type)
1404
2373
 
1405
2374
  inner = indent + " "
1406
- text = "#{indent}{\n"
1407
- text += "#{inner}int64_t #{base} = #{emit(loop_node.from, :int64)};\n"
1408
- text += "#{inner}const int64_t #{limit} = #{emit(loop_node.to, :int64)};\n"
2375
+ prelude, from, trips = loop_trips(loop_node, inner)
2376
+ text = "#{indent}{\n" + prelude
2377
+ text += "#{inner}uint64_t #{base} = 0;\n"
1409
2378
  text += "#{inner}#{COMPUTATION_C_TYPES.fetch(type)} #{lanes.first} = #{name}" +
1410
2379
  lanes.drop(1).map { |lane| ", #{lane} = #{identity}" }.join + ";\n"
1411
- text += "#{inner}for (; #{base} + #{PARTIAL_ACCUMULATORS} <= #{limit}; " \
2380
+ rounds = lanes.each_with_index.map { |lane, offset|
2381
+ term = lane_expression(assignment.expression, assignment.local, offset)
2382
+ "#{inner} {\n" \
2383
+ "#{inner} const int64_t #{index} = (int64_t) ((uint64_t) #{from} + #{base} + #{offset});\n" \
2384
+ "#{inner} #{lane} = #{emit(term, type)};\n" \
2385
+ "#{inner} }\n"
2386
+ }.join
2387
+ text += "#{inner}for (; #{trips} - #{base} >= #{PARTIAL_ACCUMULATORS}; " \
1412
2388
  "#{base} += #{PARTIAL_ACCUMULATORS}) {\n"
1413
- text += inner_loop_guard(inner)
1414
- lanes.each_with_index do |lane, offset|
1415
- term = lane_expression(assignment.expression, name, lane)
1416
- text += "#{inner} {\n"
1417
- text += "#{inner} const int64_t #{index} = #{base} + #{offset};\n"
1418
- text += "#{inner} #{lane} = #{emit(term, type)};\n"
1419
- text += "#{inner} }\n"
1420
- end
2389
+ text += inner_loop_guard(inner) + rounds
1421
2390
  text += "#{inner}}\n"
1422
2391
  text += "#{inner}#{name} = #{combine_partials(lanes, operator)};\n"
1423
- text += "#{inner}for (int64_t #{index} = #{base}; #{index} < #{limit}; " \
1424
- "#{index}++) {\n"
1425
- text += inner_loop_guard(inner)
1426
- text += emit_statement(assignment, inner + " ")
2392
+ tail = emit_statement(assignment, inner + " ")
2393
+ text += "#{inner}for (; #{base} < #{trips}; #{base}++) {\n"
2394
+ text += "#{inner} const int64_t #{index} = (int64_t) ((uint64_t) #{from} + #{base});\n"
2395
+ text += inner_loop_guard(inner) + tail
1427
2396
  text += "#{inner}}\n"
1428
2397
  text + "#{indent}}\n"
1429
2398
  end
@@ -1431,11 +2400,12 @@ class CArray
1431
2400
  # The same term, folding into one chain instead of into the
1432
2401
  # accumulator. The accumulator appears once and at the top, which is
1433
2402
  # what reduction_accumulation checked, so only that operand moves.
1434
- def lane_expression (expression, name, lane)
2403
+ def lane_expression (expression, local, lane)
1435
2404
  operands = [expression.left, expression.right].map { |operand|
1436
- next operand unless accumulator?(operand, name)
2405
+ next operand unless accumulator?(operand, local)
1437
2406
  read = LocalRead.new(operand.name, operand.location)
1438
- read.binding_name = lane
2407
+ read.binding = operand.binding
2408
+ read.lane = lane
1439
2409
  read.type = operand.type
1440
2410
  read
1441
2411
  }
@@ -1481,26 +2451,28 @@ class CArray
1481
2451
  end
1482
2452
 
1483
2453
  def emit_assignment (assignment, indent)
1484
- name = assignment.binding_name
2454
+ name = local_c_name(assignment.name, assignment.binding)
1485
2455
  type = assignment.type
1486
- declared = @declared_locals.key?(name)
1487
- @declared_locals[name] = type
1488
2456
 
1489
2457
  # A local carries a mask alongside its value, so that reading it later
1490
- # is the same as reading what it was computed from.
2458
+ # is the same as reading what it was computed from -- and, as a cell
2459
+ # written here would, the masks of the branches this assignment stands
2460
+ # in. An `if` or a `while` taken on a missing cell was decided by
2461
+ # bytes that mean nothing, so what it writes means nothing either,
2462
+ # wherever it writes it. Without this the rule held for
2463
+ # `out[i] = 1.0` and not for `v = 1.0; out[i] = v`, which is the
2464
+ # spelling a search over a row takes.
1491
2465
  mask = if @masked
1492
- "#{indent}#{declared ? '' : 'uint8_t '}" \
1493
- "#{local_mask_name(name)} = #{emit_mask(assignment.expression)};\n"
2466
+ "#{indent}#{local_mask_name(name)} = " \
2467
+ "#{combine_masks(@carried_masks + [emit_mask(assignment.expression)])};\n"
1494
2468
  else
1495
2469
  ""
1496
2470
  end
1497
2471
 
1498
2472
  if assignment.expression.is_a?(Conditional)
1499
- lines = declared ? "" : "#{indent}#{COMPUTATION_C_TYPES.fetch(type)} #{name};\n"
1500
- lines + emit_conditional_statement(assignment.expression, name, type, indent) + mask
2473
+ emit_conditional_statement(assignment.expression, name, type, indent) + mask
1501
2474
  else
1502
- prefix = declared ? "" : "#{COMPUTATION_C_TYPES.fetch(type)} "
1503
- "#{indent}#{prefix}#{name} = #{emit(assignment.expression, type)};\n" + mask
2475
+ "#{indent}#{name} = #{emit(assignment.expression, type)};\n" + mask
1504
2476
  end
1505
2477
  end
1506
2478
 
@@ -1519,6 +2491,213 @@ class CArray
1519
2491
  subscripts || @analyzer.index_names.map { |name| [name, 0] }
1520
2492
  end
1521
2493
 
2494
+ # `sum(w)` / `min(w)` / `max(w)`: a call to a helper in the preamble.
2495
+ #
2496
+ # A call rather than a loop unrolled at the statement, because these
2497
+ # stand in expressions -- `max(w) - min(w)` is one line with two of them
2498
+ # -- and an expression has nowhere to put a loop. What it costs is
2499
+ # nothing: the helper is `static inline` and the length is a literal, so
2500
+ # the compiler has the same code in front of it either way.
2501
+ def intrinsic_reference (node)
2502
+ need(node.intrinsic, node.storage, nil)
2503
+ "#{intrinsic_helper_name(node.intrinsic, node.storage)}" \
2504
+ "(#{local_c_name(node.name, node.binding)}, " \
2505
+ "#{local_array_extent_text(node, 0)})"
2506
+ end
2507
+
2508
+ # A length the kernel works out cannot choose a network -- the choice
2509
+ # is made as the C is written and a network is a fixed run of
2510
+ # comparators -- so it sorts by the helper that takes its length as an
2511
+ # argument, which is the insertion sort.
2512
+ def emit_intrinsic_statement (statement, indent)
2513
+ cells = statement.shape.first
2514
+ name = local_c_name(statement.name, statement.binding)
2515
+ # One cell is in order already, and a network of no comparators is
2516
+ # nothing to call.
2517
+ return "" if cells == 1
2518
+ unless cells.is_a?(Integer)
2519
+ need(:sort, statement.storage, nil)
2520
+ return "#{indent}#{intrinsic_helper_name(:sort, statement.storage)}" \
2521
+ "(#{name}, #{local_array_extent_text(statement, 0)});\n"
2522
+ end
2523
+ if SortingNetworks.covers?(cells)
2524
+ need(:sort, statement.storage, cells)
2525
+ "#{indent}#{intrinsic_helper_name(:sort, statement.storage)}" \
2526
+ "_#{cells}(#{name});\n"
2527
+ else
2528
+ need(:sort, statement.storage, nil)
2529
+ "#{indent}#{intrinsic_helper_name(:sort, statement.storage)}" \
2530
+ "(#{name}, #{cells});\n"
2531
+ end
2532
+ end
2533
+
2534
+ def intrinsic_helper_name (intrinsic, storage)
2535
+ "carray_jit_#{intrinsic}_#{storage}"
2536
+ end
2537
+
2538
+ # What the preamble has to write out. A list used as a set, the way
2539
+ # `@clamp_types` and `@gamma_types` are, so that two sorts of one type
2540
+ # and length are one helper.
2541
+ def need (intrinsic, storage, cells)
2542
+ entry = [intrinsic, storage, cells]
2543
+ @intrinsic_needs << entry unless @intrinsic_needs.include?(entry)
2544
+ end
2545
+
2546
+ # `w = CArray.double(9)` where the statement stands. The declaration is
2547
+ # at the head of the block; what is left here is what Ruby does at this
2548
+ # line, which for the zeroed spellings is a fresh array of zeros.
2549
+ #
2550
+ # `sizeof` rather than a byte count written out: the length is already
2551
+ # in the declaration, and one place for it is one place to be wrong.
2552
+ # The shadow is cleared with the cells, and a cleared shadow byte is
2553
+ # "not missing": a fresh array in Ruby holds zeros, which are values
2554
+ # that are there. The `empty` spelling says nothing about either, so
2555
+ # its shadow is whatever the stack held -- the same bargain its cells
2556
+ # are under, and the same promise the block made by writing `empty`.
2557
+ def emit_local_array_clearing (declaration, indent)
2558
+ return "" unless declaration.zeroed
2559
+ name = local_c_name(declaration.name, declaration.binding)
2560
+ # `sizeof` answers for an array and not for a pointer, so one the
2561
+ # kernel allocated is cleared by the count it was allocated with.
2562
+ if declaration.heap
2563
+ cells = local_array_cells_text(name, declaration.shape)
2564
+ bytes = "sizeof(#{storage_c_type(declaration.storage)}) * " \
2565
+ "(size_t) #{cells}"
2566
+ return "#{indent}memset(#{name}, 0, #{bytes});\n" +
2567
+ (@masked ?
2568
+ "#{indent}memset(#{local_mask_name(name)}, 0, " \
2569
+ "(size_t) #{cells});\n" : "")
2570
+ end
2571
+ "#{indent}memset(#{name}, 0, sizeof #{name});\n" +
2572
+ (@masked ?
2573
+ "#{indent}memset(#{local_mask_name(name)}, 0, " \
2574
+ "sizeof #{local_mask_name(name)});\n" : "")
2575
+ end
2576
+
2577
+ # `w[k] = UNDEF`: the shadow byte alone. The cell's bytes are out of
2578
+ # contract once it is marked, so there is nothing to store into them.
2579
+ def emit_local_array_mask_write (write, indent)
2580
+ "#{indent}#{local_array_reference(write, :mask)} = 1;\n"
2581
+ end
2582
+
2583
+ def emit_local_array_write (write, indent)
2584
+ target = local_array_reference(write)
2585
+ expression = write.expression
2586
+ # A cell of a local array carries a mask beside it the way a scalar
2587
+ # local carries one beside its value, and by the same rule: what the
2588
+ # expression written into it carried, and the branches the write
2589
+ # stands in. A write reached because a missing cell said so was
2590
+ # reached for no reason, whichever of the three it writes.
2591
+ mask = if @masked
2592
+ "#{indent}#{local_array_reference(write, :mask)} = " \
2593
+ "#{combine_masks(@carried_masks + [emit_mask(write.expression)])};\n"
2594
+ else
2595
+ ""
2596
+ end
2597
+ if expression.is_a?(Conditional)
2598
+ temporary = next_temporary
2599
+ type = expression.type
2600
+ "#{indent}#{COMPUTATION_C_TYPES.fetch(type)} #{temporary};\n" +
2601
+ emit_conditional_statement(expression, temporary, type, indent) +
2602
+ "#{indent}#{target} = " \
2603
+ "#{cast_to_storage(temporary, type, write.storage)};\n" + mask
2604
+ else
2605
+ type = complex_storage_of_power(expression, write.storage) || expression.type
2606
+ value = cast_to_storage(emit(expression, type), type, write.storage)
2607
+ "#{indent}#{target} = #{value};\n" + mask
2608
+ end
2609
+ end
2610
+
2611
+ # `w[(k) + 1]`, and for a rank above one the row-major offset with the
2612
+ # strides folded in -- the shape is written in the block, so they are
2613
+ # constants rather than numbers the kernel is handed.
2614
+ # `:mask` asks for the shadow byte beside the cell rather than the
2615
+ # cell: the same position, in the array beside it. It reports no index
2616
+ # of its own, for the reason a captured array's mask read does not --
2617
+ # the value's read asks the same question a moment later, and one
2618
+ # report is the one the cell deserves.
2619
+ def local_array_reference (node, kind = :data)
2620
+ name = local_c_name(node.name, node.binding)
2621
+ name = local_mask_name(name) if kind == :mask
2622
+ terms = node.subscripts.each_with_index.map { |(index, offset), axis|
2623
+ position = local_array_position(node, index, offset, axis,
2624
+ reporting: kind != :mask)
2625
+ stride = local_array_stride_text(node, axis)
2626
+ stride == "1" ? position : "(#{position}) * #{stride}"
2627
+ }
2628
+ "#{name}[#{terms.join(' + ')}]"
2629
+ end
2630
+
2631
+ # How long an axis of a local array is, as the C says it: the number
2632
+ # the block wrote, or the name the kernel worked the length out into.
2633
+ def local_array_extent_text (node, axis)
2634
+ extent = node.shape.fetch(axis)
2635
+ return extent.to_s if extent.is_a?(Integer)
2636
+ heap_extent_name(local_c_name(node.name, node.binding), axis)
2637
+ end
2638
+
2639
+ # And how many cells it has altogether, for the allocation and the
2640
+ # clearing.
2641
+ def local_array_cells_text (variable, shape)
2642
+ return shape.inject(1, :*).to_s if literal_shape?(shape)
2643
+ heap_cells_name(variable)
2644
+ end
2645
+
2646
+ # How far one step along an axis moves: the cells of every axis inside
2647
+ # it, which are numbers where the block wrote numbers and the lengths
2648
+ # the kernel worked out where it did not.
2649
+ def local_array_stride_text (node, axis)
2650
+ inner = node.shape[(axis + 1)..]
2651
+ return inner.inject(1, :*).to_s if literal_shape?(inner)
2652
+ inner.each_with_index.map { |extent, offset|
2653
+ extent.is_a?(Integer) ? extent.to_s :
2654
+ heap_extent_name(local_c_name(node.name, node.binding),
2655
+ axis + 1 + offset)
2656
+ }.join(" * ")
2657
+ end
2658
+
2659
+ # An axis the analyzer settled carries an index and a literal offset,
2660
+ # and the C says so with nothing around it. One it could not settle
2661
+ # carries the expression, and the check is here.
2662
+ def local_array_position (node, index, offset, axis, reporting: true)
2663
+ settled = node.shape.fetch(axis).is_a?(Integer)
2664
+ # The write around this has already worked the position out and
2665
+ # tested it.
2666
+ guarded = @guarded_axes[node]
2667
+ return guarded.fetch(axis) if guarded&.key?(axis)
2668
+ if index.nil?
2669
+ return offset.to_s unless offset.is_a?(Node)
2670
+ # A position that is a number is settled against a length that is
2671
+ # one. Against a length the kernel works out it is not: 3 is
2672
+ # inside an array of 4 cells and outside one of 2, so it is checked
2673
+ # where the cell is reached like any other.
2674
+ return emit(offset, :int64) if settled &&
2675
+ Analyzer.fixed_subscript?(offset)
2676
+ # A write has already worked this position out and tested it.
2677
+ held = @position_temporaries[offset]
2678
+ return held if held
2679
+ @uses_index_check = true
2680
+ return "carray_jit_index(#{emit(offset, :int64)}, " \
2681
+ "#{local_array_extent_text(node, axis)}, " \
2682
+ "#{reporting ? error_argument : '(int32_t *) 0'})"
2683
+ end
2684
+ # An index on an axis whose length the kernel works out was not
2685
+ # settled either: (a) had no number to compare the loop's reach
2686
+ # against, so the reach is tested here.
2687
+ unless settled
2688
+ @uses_index_check = true
2689
+ position = if offset.zero? then index.to_s
2690
+ elsif offset.negative? then "#{index} - #{-offset}"
2691
+ else "#{index} + #{offset}"
2692
+ end
2693
+ return "carray_jit_index(#{position}, " \
2694
+ "#{local_array_extent_text(node, axis)}, " \
2695
+ "#{reporting ? error_argument : '(int32_t *) 0'})"
2696
+ end
2697
+ return index.to_s if offset.zero?
2698
+ offset.negative? ? "#{index} - #{-offset}" : "#{index} + #{offset}"
2699
+ end
2700
+
1522
2701
  def emit_element_write (write, indent)
1523
2702
  unless @masked
1524
2703
  @masked_flag = nil
@@ -1547,13 +2726,15 @@ class CArray
1547
2726
  when ElementRead
1548
2727
  cell_reference(node.array, node.subscripts, :mask)
1549
2728
  when LocalRead
1550
- local_mask_name(node.binding_name)
2729
+ local_mask_name(local_c_name(node.name, node.binding, node.lane))
2730
+ when LocalArrayRead
2731
+ local_array_reference(node, :mask)
1551
2732
  when Conditional
1552
2733
  branches = "#{emit(node.condition, :boolean)} ? " \
1553
2734
  "#{emit_mask(node.consequent)} : #{emit_mask(node.alternative)}"
1554
2735
  combine_masks([emit_mask(node.condition), "(#{branches})"])
1555
2736
  when IntegerLiteral, FloatLiteral, IndexVariable, CaptureRead, MaskTest,
1556
- BoundsValue, ZeroLike
2737
+ LocalArrayMaskTest, PointerTest, BoundsValue, ZeroLike
1557
2738
  "0"
1558
2739
  else
1559
2740
  combine_masks(node.children.map { |child| emit_mask(child) })
@@ -1578,14 +2759,33 @@ class CArray
1578
2759
  type = expression.type
1579
2760
  "#{indent}#{COMPUTATION_C_TYPES.fetch(type)} #{temporary};\n" +
1580
2761
  emit_conditional_statement(expression, temporary, type, indent) +
1581
- "#{indent}#{target} = #{cast_to_storage(temporary, type, write.array)};\n"
2762
+ "#{indent}#{target} = " \
2763
+ "#{cast_to_storage(temporary, type, array_storage(write.array))};\n"
1582
2764
  else
1583
- value = cast_to_storage(emit(expression, expression.type),
1584
- expression.type, write.array)
2765
+ storage = array_storage(write.array)
2766
+ real = REAL_STORAGE_TYPES[storage]
2767
+ if real && rounded_real?(expression, real)
2768
+ return "#{indent}#{target} = #{emit(expression, real)};\n"
2769
+ end
2770
+ type = complex_storage_of_power(expression, storage) || expression.type
2771
+ value = cast_to_storage(emit(expression, type), type, storage)
1585
2772
  "#{indent}#{target} = #{value};\n"
1586
2773
  end
1587
2774
  end
1588
2775
 
2776
+ # A real power stored in a complex cell is read as complex; see
2777
+ # complex_read_power?.
2778
+ COMPLEX_STORAGE_TYPES = { "cmplx128" => :complex, "cmplx64" => :float_complex }.freeze
2779
+
2780
+ def complex_storage_of_power (expression, storage)
2781
+ type = COMPLEX_STORAGE_TYPES[storage]
2782
+ type if type && complex_read_power?(expression, type)
2783
+ end
2784
+
2785
+ # A float cell, by what it computes in: the storage a rounding written
2786
+ # straight into keeps as a real number (see #rounded_real?).
2787
+ REAL_STORAGE_TYPES = { "float64" => :double, "float32" => :float }.freeze
2788
+
1589
2789
  # A conditional in statement position becomes if/else rather than a
1590
2790
  # ternary; it reads far better when the branches are long.
1591
2791
  def emit_conditional_statement (node, target, type, indent)
@@ -1596,31 +2796,230 @@ class CArray
1596
2796
  "#{indent}}\n"
1597
2797
  end
1598
2798
 
1599
- def storage_c_type (array)
1600
- STORAGE_C_TYPES.fetch(@storage_types.fetch(array))
2799
+ # What a cell is held in, and the casts between that and the type the
2800
+ # kernel computes in.
2801
+ #
2802
+ # Each is asked about a storage type rather than about an array's name.
2803
+ # An operand's storage type is looked up under its name, but not every
2804
+ # array a body reaches is an operand -- so a helper that did the lookup
2805
+ # itself could only answer for the ones that are, and the answer for
2806
+ # anything else would be a KeyError out of the middle of code
2807
+ # generation. The name that has one is looked up by #array_storage at
2808
+ # the call site.
2809
+ def storage_c_type (storage)
2810
+ STORAGE_C_TYPES.fetch(storage)
2811
+ end
2812
+
2813
+ # ---- the intrinsics, written into the preamble ----
2814
+
2815
+ # The accumulator `min` and `max` start from over an integer array,
2816
+ # where starting at the limit of the type rather than at the first cell
2817
+ # saves asking whether a cell has been seen yet. A floating array
2818
+ # starts at NaN instead, which any number displaces -- see
2819
+ # #intrinsic_fold_helper.
2820
+ INTRINSIC_LIMITS = {
2821
+ :int64 => ["INT64_MAX", "INT64_MIN"],
2822
+ :uint64 => ["UINT64_MAX", "0"],
2823
+ }.freeze
2824
+
2825
+ def computation_c_type_of (storage)
2826
+ COMPUTATION_C_TYPES.fetch(TypeAssignment.storage_type(storage))
2827
+ end
2828
+
2829
+ def floating_storage? (storage)
2830
+ type = TypeAssignment.storage_type(storage)
2831
+ [:float, :double].include?(type)
2832
+ end
2833
+
2834
+ def intrinsic_helpers
2835
+ return "" if @intrinsic_needs.empty?
2836
+ text = +""
2837
+ %i[sum min max].each do |intrinsic|
2838
+ @intrinsic_needs.select { |kind, _, _| kind == intrinsic }
2839
+ .map { |_, storage, _| storage }.uniq.each do |storage|
2840
+ text << intrinsic_fold_helper(intrinsic, storage)
2841
+ end
2842
+ end
2843
+ sorted = @intrinsic_needs.select { |kind, _, _| kind == :sort }
2844
+ sorted.map { |_, storage, _| storage }.uniq.each do |storage|
2845
+ text << intrinsic_order_helper(storage)
2846
+ end
2847
+ sorted.each do |_, storage, cells|
2848
+ text << (cells ? intrinsic_network_helper(storage, cells)
2849
+ : intrinsic_insertion_helper(storage))
2850
+ end
2851
+ text
2852
+ end
2853
+
2854
+ def intrinsic_fold_helper (intrinsic, storage)
2855
+ cell = storage_c_type(storage)
2856
+ result = computation_c_type_of(storage)
2857
+ type = TypeAssignment.storage_type(storage)
2858
+ if intrinsic == :sum
2859
+ return <<~C
2860
+ /* `sum(w)`, added in index order from the first cell: what the
2861
+ same loop written out in Ruby adds, in the same order, so the
2862
+ last bit is the same one. No partial sums -- a local array is
2863
+ small enough that splitting buys nothing and would change the
2864
+ answer. */
2865
+ static inline #{result}
2866
+ carray_jit_sum_#{storage} (const #{cell} *w, int64_t n)
2867
+ {
2868
+ #{result} total = 0;
2869
+ for ( int64_t k = 0; k < n; k++ ) total += w[k];
2870
+ return total;
2871
+ }
2872
+
2873
+ C
2874
+ end
2875
+ if floating_storage?(storage)
2876
+ comparison = intrinsic == :min ? "<" : ">"
2877
+ return <<~C
2878
+ /* `#{intrinsic}(w)`, which is what CArray's own #{intrinsic} answers.
2879
+ A cell takes the accumulator only by beating it outright, or by
2880
+ being a number where the accumulator is still NaN: so a NaN is
2881
+ skipped wherever it stands, an array of nothing but NaN comes
2882
+ back NaN, and of two cells that compare equal the first is kept
2883
+ -- which is how CArray keeps 0.0 or -0.0, whichever came first.
2884
+ fmin and fmax answer the same but for that: C leaves which zero
2885
+ they give up to the library. Starting at NaN is what lets the
2886
+ first cell in take the accumulator without a seen-yet test. */
2887
+ static inline #{result}
2888
+ carray_jit_#{intrinsic}_#{storage} (const #{cell} *w, int64_t n)
2889
+ {
2890
+ #{result} best = NAN;
2891
+ for ( int64_t k = 0; k < n; k++ ) {
2892
+ if ( w[k] #{comparison} best || best != best ) best = w[k];
2893
+ }
2894
+ return best;
2895
+ }
2896
+
2897
+ C
2898
+ end
2899
+ limit = INTRINSIC_LIMITS.fetch(type)[intrinsic == :min ? 0 : 1]
2900
+ comparison = intrinsic == :min ? "<" : ">"
2901
+ <<~C
2902
+ /* `#{intrinsic}(w)`, which is what CArray's own #{intrinsic} answers.
2903
+ An integer type has no NaN, so the limit this starts from is only
2904
+ ever an answer for an array with no cells. */
2905
+ static inline #{result}
2906
+ carray_jit_#{intrinsic}_#{storage} (const #{cell} *w, int64_t n)
2907
+ {
2908
+ #{result} best = #{limit};
2909
+ for ( int64_t k = 0; k < n; k++ ) best = (w[k] #{comparison} best) ? w[k] : best;
2910
+ return best;
2911
+ }
2912
+
2913
+ C
2914
+ end
2915
+
2916
+ # The order the two sorts put the cells in, in one place so that the
2917
+ # network and the loop cannot disagree about it.
2918
+ #
2919
+ # A NaN comes after every number and ties with another NaN, which makes
2920
+ # this a total preorder -- and a comparator network sorts under any of
2921
+ # those, so the finite cells come out ascending with the NaNs behind
2922
+ # them. That is where CArray's own sort puts them.
2923
+ #
2924
+ # The min / max folds above skip a NaN, which drops a cell rather than
2925
+ # moving it. A fold wants that; a sort has to put every cell somewhere.
2926
+ def intrinsic_order_helper (storage)
2927
+ cell = storage_c_type(storage)
2928
+ nan_term = floating_storage?(storage) ? " || (a != a && b == b)" : ""
2929
+ <<~C
2930
+ /* Whether `a` belongs after `b` once the cells are in order.#{
2931
+ floating_storage?(storage) ?
2932
+ "\n A NaN belongs after every number, and two NaNs tie." : ""} */
2933
+ static inline int
2934
+ carray_jit_after_#{storage} (#{cell} a, #{cell} b)
2935
+ {
2936
+ return (b < a)#{nan_term};
2937
+ }
2938
+
2939
+ /* One compare-exchange: the smaller of the two ends up in `low`.
2940
+ Written as two selects rather than a branch, so the sequence a
2941
+ network lays out has nothing in it to predict. */
2942
+ static inline void
2943
+ carray_jit_cx_#{storage} (#{cell} *low, #{cell} *high)
2944
+ {
2945
+ #{cell} a = *low, b = *high;
2946
+ int swap = carray_jit_after_#{storage}(a, b);
2947
+ *low = swap ? b : a;
2948
+ *high = swap ? a : b;
2949
+ }
2950
+
2951
+ C
2952
+ end
2953
+
2954
+ def intrinsic_network_helper (storage, cells)
2955
+ network = SortingNetworks.for(cells)
2956
+ pairs = network.map { |low, high|
2957
+ " carray_jit_cx_#{storage}(&w[#{low}], &w[#{high}]);"
2958
+ }.join("\n")
2959
+ <<~C
2960
+ /* `sort(w)` for #{cells} cells: a comparator network, which is the
2961
+ same #{network.size} compare-exchanges every time in the same
2962
+ order -- no branch, nothing to predict, and the smallest number
2963
+ of comparisons known for this length. */
2964
+ static inline void
2965
+ carray_jit_sort_#{storage}_#{cells} (#{storage_c_type(storage)} *w)
2966
+ {
2967
+ #{pairs}
2968
+ }
2969
+
2970
+ C
2971
+ end
2972
+
2973
+ def intrinsic_insertion_helper (storage)
2974
+ cell = storage_c_type(storage)
2975
+ <<~C
2976
+ /* `sort(w)` past the length the networks cover: an insertion sort,
2977
+ which is a loop. The tables would keep growing and what a
2978
+ network buys shrinks -- long before this there are more
2979
+ comparators than the machine has registers. */
2980
+ static inline void
2981
+ carray_jit_sort_#{storage} (#{cell} *w, int64_t n)
2982
+ {
2983
+ for ( int64_t k = 1; k < n; k++ ) {
2984
+ #{cell} value = w[k];
2985
+ int64_t j = k - 1;
2986
+ while ( j >= 0 && carray_jit_after_#{storage}(w[j], value) ) {
2987
+ w[j + 1] = w[j];
2988
+ j--;
2989
+ }
2990
+ w[j + 1] = value;
2991
+ }
2992
+ }
2993
+
2994
+ C
2995
+ end
2996
+
2997
+ # The storage type of an operand, by the name the block reached it by.
2998
+ def array_storage (array)
2999
+ @storage_types.fetch(array)
1601
3000
  end
1602
3001
 
1603
- def cast_to_storage (text, type, array)
3002
+ def cast_to_storage (text, type, storage)
1604
3003
  # Storing into a boolean array normalises: CArray's boolean is a byte
1605
3004
  # holding 0 or 1, and a kernel is not the place that invariant stops
1606
3005
  # being true.
1607
- return "(uint8_t)((#{text}) ? 1 : 0)" if boolean_storage?(array)
1608
- target = storage_c_type(array)
3006
+ return "(uint8_t)((#{text}) ? 1 : 0)" if boolean_storage?(storage)
3007
+ target = storage_c_type(storage)
1609
3008
  return text if COMPUTATION_C_TYPES.fetch(type) == target
1610
3009
  "(#{target})(#{text})"
1611
3010
  end
1612
3011
 
1613
3012
  # The cast that takes a stored cell to the type the kernel computes in,
1614
3013
  # or nil where the two already agree.
1615
- def widening_cast (array, type)
3014
+ def widening_cast (storage, type)
1616
3015
  return nil if type == :boolean
1617
3016
  wanted = COMPUTATION_C_TYPES.fetch(type)
1618
- return nil if storage_c_type(array) == wanted
3017
+ return nil if storage_c_type(storage) == wanted
1619
3018
  "(#{wanted})"
1620
3019
  end
1621
3020
 
1622
- def boolean_storage? (array)
1623
- @storage_types.fetch(array, nil) == "boolean"
3021
+ def boolean_storage? (storage)
3022
+ storage == "boolean"
1624
3023
  end
1625
3024
 
1626
3025
  # A Ruby name is not always a C one: `Foo::TABLE` names one thing in
@@ -1630,6 +3029,152 @@ class CArray
1630
3029
  name.to_s.gsub("::", "__")
1631
3030
  end
1632
3031
 
3032
+ # The identifier each name is written as where it is written on its own,
3033
+ # as a variable of the kernel's body.
3034
+ #
3035
+ # `c_name` is not enough there. The kernel's own parameters are `data`,
3036
+ # `error`, `strides`, `bounds` -- ordinary words a block may perfectly
3037
+ # well have used for a capture -- and C keeps a list of its own;
3038
+ # `RESERVED_NAMES` is already both, and was already consulted for an
3039
+ # index. A capture was not consulted about, and a block closing over
3040
+ # something called `data` compiled to C that redeclared the kernel's own
3041
+ # parameter. A leading underscore is C's to reserve as well, which is
3042
+ # what the made-up names here start with. And a C name that starts
3043
+ # `carray_jit_` is the generator's, whoever wrote it in Ruby.
3044
+ #
3045
+ # An index is refused for this rather than moved, because its name is
3046
+ # written in the block and read back in messages. A capture's is not:
3047
+ # what it is called in the C is nobody's business, so it is moved out of
3048
+ # the way instead of the caller being asked to rename a variable in code
3049
+ # that has nothing to do with the kernel.
3050
+ #
3051
+ # Worked out for the whole kernel at once, because where a moved name
3052
+ # lands is not a question about that name alone: a block closing over
3053
+ # both `data` and `carray_jit_name_data` would otherwise have the first
3054
+ # move onto the second. So every name that stays is claimed first, and
3055
+ # a move that would collide keeps going.
3056
+ #
3057
+ # Only a name that had to move moves, so the C a reader sees is what it
3058
+ # was. A decorated name (`p_a`, `a_s0`, `m_a`) could not collide with a
3059
+ # parameter or a keyword and is left alone.
3060
+ def bare_names
3061
+ @bare_names ||= begin
3062
+ names = (@reals + @integers + @complexes + @unsigned_integers +
3063
+ @address_arrays + @address_functions.keys).uniq
3064
+ taken = names.map { |name| c_name(name) }
3065
+ names.each_with_object({}) do |name, found|
3066
+ text = c_name(name)
3067
+ if RESERVED_NAMES.include?(name.to_sym) || text.start_with?("_") ||
3068
+ text.start_with?("carray_jit_")
3069
+ # Not the bare `carray_jit_` prefix: `carray_jit_error` is the
3070
+ # error flag, and a capture called `error` would land on it.
3071
+ text = "carray_jit_name_#{text}"
3072
+ text = "#{text}_" while taken.include?(text)
3073
+ taken << text
3074
+ end
3075
+ found[name] = text
3076
+ end
3077
+ end
3078
+ end
3079
+
3080
+ def bare_name (name)
3081
+ bare_names.fetch(name) { c_name(name) }
3082
+ end
3083
+
3084
+ # A parameter the body assigns is a local of the same name from the
3085
+ # top of the body on, so the C parameter it starts from goes under a
3086
+ # name of its own -- one only this generator writes. Every other
3087
+ # name is what it always was.
3088
+ def parameter_c_name (name)
3089
+ return bare_name(name) unless @analyzer.assigned_parameters.include?(name.to_sym)
3090
+ "carray_jit_parameter_#{c_name(name)}"
3091
+ end
3092
+
3093
+ # The names this generator writes of its own, beside the kernel's
3094
+ # parameters and C's keywords: every decoration of every array the
3095
+ # kernel reaches, at every axis it has, and a borrowed function's type.
3096
+ # All of them, whether or not this kernel ends up writing each one, so
3097
+ # that the set is settled before anything is emitted.
3098
+ def decorated_names
3099
+ @decorated_names ||=
3100
+ @arrays.flat_map { |array|
3101
+ [pointer_name(array), mask_pointer_name(array)] +
3102
+ (0...array_rank(array)).flat_map { |axis|
3103
+ [stride_name(array, axis), mask_stride_name(array, axis),
3104
+ extent_name(array, axis)]
3105
+ }
3106
+ } + @address_functions.keys.map { |name| c_function_type_name(name) }
3107
+ end
3108
+
3109
+ # Whether a name is one the generator writes, or could. Everything it
3110
+ # makes up that is not a parameter, a keyword or a decoration has `__`
3111
+ # in it or starts `carray_jit_` -- the suffixes a local's bindings take,
3112
+ # an inner index's second name, the temporaries -- so those two are
3113
+ # taken whole.
3114
+ def generated_name? (text)
3115
+ RESERVED_NAMES.include?(text.to_sym) || text.include?("__") ||
3116
+ text.start_with?("carray_jit_") || decorated_names.include?(text)
3117
+ end
3118
+
3119
+ # The C name of each local the block assigns, by its Ruby name. A local
3120
+ # is ordinary Ruby and may be called anything, including a name the
3121
+ # generator writes -- `a_n0`, `error`, `int`, `x__2` -- and a local of
3122
+ # that name declared in the kernel's body hid what it named. So it is
3123
+ # moved, to `carray_jit_name<K>_<name>`, K counting the moved locals from
3124
+ # 1 in the order the body first assigns them, so the C -- and the cache
3125
+ # key it is part of -- is the same every time. One that does not
3126
+ # collide keeps the name the block gave it, which is what a reader of
3127
+ # the C looks for.
3128
+ #
3129
+ # The number is what keeps two moved locals apart once a suffix is on
3130
+ # them. A Ruby identifier cannot start with a digit, so the digits after
3131
+ # `carray_jit_name` run to the next `_`, and a different K is a different
3132
+ # C name whatever `__2`, `__p0` or `__mask` follows. A C name starting
3133
+ # `carray_jit_` is the generator's, so no capture is spelled like one.
3134
+ def local_c_names
3135
+ @local_c_names ||= begin
3136
+ moved = 0
3137
+ assigned_locals(@analyzer.body).uniq.to_h { |name|
3138
+ text = name.to_s
3139
+ text = "carray_jit_name#{moved += 1}_#{text}" if generated_name?(text)
3140
+ [name, text]
3141
+ }
3142
+ end
3143
+ end
3144
+
3145
+ # Every name the body binds, in the order it first binds them. An array
3146
+ # the body made is one of these: it is a local that happens to have
3147
+ # cells, and it is moved off the generator's own names for the same
3148
+ # reason and by the same numbering.
3149
+ def assigned_locals (node)
3150
+ own = case node
3151
+ when Assignment, LocalArrayDeclaration then [node.name]
3152
+ else []
3153
+ end
3154
+ own + node.children.compact.flat_map { |child| assigned_locals(child) }
3155
+ end
3156
+
3157
+ # A local's C variable is its name, moved or not, and then what says
3158
+ # which of its variables: `__2` for its second binding, `__p0` for a
3159
+ # partial accumulator of a split fold -- `carray_jit_name_error__2`.
3160
+ def local_c_name (name, binding, lane = nil)
3161
+ local_c_names.fetch(name) + (binding == 1 ? "" : "__#{binding}") +
3162
+ (lane ? "__p#{lane}" : "")
3163
+ end
3164
+
3165
+ # An index is refused where a local is moved: its name is the block's
3166
+ # text, and the messages speak of it. The parameters and C's keywords
3167
+ # were refused as the block was read; what is refused here needed the
3168
+ # arrays first.
3169
+ def refuse_generated_indices
3170
+ taken = @analyzer.index_names.select { |name| generated_name?(c_name(name)) }
3171
+ return if taken.empty?
3172
+ raise Unsupported.new(
3173
+ "#{taken.map { |name| "`#{name}`" }.join(', ')} " \
3174
+ "#{taken.size == 1 ? 'is a name' : 'are names'} the kernel's own C " \
3175
+ "uses, so #{taken.size == 1 ? 'it cannot be an index' : 'they cannot be indices'}")
3176
+ end
3177
+
1633
3178
  def pointer_name (array)
1634
3179
  "p_#{c_name(array)}"
1635
3180
  end
@@ -1652,8 +3197,37 @@ class CArray
1652
3197
  # what the kernel raises. Nothing in the C reaches Ruby to do it: the
1653
3198
  # function still returns a number and touches no Ruby value, which is
1654
3199
  # what lets its address be handed to a library, or called off the GVL.
3200
+ # The widths `clamp` is emitted for: the suffix its helper takes, the C
3201
+ # type, and whether that type has a NaN to refuse.
3202
+ CLAMP_C_TYPES = {
3203
+ :double => ["double", "double", true],
3204
+ :float => ["float", "float", true],
3205
+ :int64 => ["int64", "int64_t", false],
3206
+ :uint64 => ["uint64", "uint64_t", false],
3207
+ }.freeze
3208
+
3209
+ # The widths `Math.gamma` is emitted for: the helper's suffix, the C
3210
+ # type, and the C function it falls through to.
3211
+ GAMMA_C_TYPES = {
3212
+ :double => ["double", "double", "tgamma", "modf"],
3213
+ :float => ["float", "float", "tgammaf", "modff"],
3214
+ }.freeze
3215
+
3216
+ # Ruby answers `Math.gamma` for a small whole number from a table of
3217
+ # exact values rather than from tgamma, so the table is written into
3218
+ # the C -- filled from the Ruby that is compiling, the way `Math::PI`
3219
+ # is emitted as the double Ruby would have used. Its length is Ruby's
3220
+ # own: the table covers 1 through 23, and tgamma has the rest.
3221
+ GAMMA_TABLE_LIMIT = 23
3222
+
1655
3223
  ERROR_FLAG = "carray_jit_error"
1656
3224
 
3225
+ # The storage class the flag and the hook beside it are declared with.
3226
+ # C11's, which is what every compiler this gem drives is given; MSVC's
3227
+ # `__declspec(thread)` is not written here because the build flags are
3228
+ # already gcc's and cl has never been one of them.
3229
+ THREAD_LOCAL = "_Thread_local ".freeze
3230
+
1657
3231
  # A computation type this generator has no C for. Nothing reaches here
1658
3232
  # today -- every type TypeAssignment can assign is named at each of the
1659
3233
  # sites that calls this -- and that is the point: a type added later
@@ -1666,18 +3240,19 @@ class CArray
1666
3240
  end
1667
3241
 
1668
3242
  def error_argument
3243
+ # Asking for the slot is what says this body can report, and every
3244
+ # place that can -- a checked subscript, the division helpers, a
3245
+ # `raise`, a pasted function that takes the flag -- asks here. So the
3246
+ # loops around it learn it from the statements they hold, which are
3247
+ # emitted before the loop's guard is written. A function's loops ask
3248
+ # too: they stop on its flag the way a kernel's stop on the slot.
3249
+ @body_reports = true
1669
3250
  if @in_function
1670
3251
  @uses_error_flag = true
1671
3252
  # A pasted body reports into the kernel's slot, which reaches it as
1672
3253
  # a parameter; a standalone one into the flag in its own object.
1673
3254
  return @error_parameter ? ERROR_FLAG : "&#{ERROR_FLAG}"
1674
3255
  end
1675
- # Asking for the slot is what says this body can report, and every
1676
- # place that can -- a checked subscript, the division helpers, a
1677
- # `raise`, a pasted function that takes the flag -- asks here. So the
1678
- # loops above learn it from the statements they will hold, which are
1679
- # emitted before the loop is opened.
1680
- @body_reports = true
1681
3256
  @masked_flag ? "(#{@masked_flag} ? (int32_t *) 0 : error)" : "error"
1682
3257
  end
1683
3258
 
@@ -1787,7 +3362,7 @@ class CArray
1787
3362
  return "#{mask_pointer_name(array)}[#{terms.join(' + ')}]"
1788
3363
  end
1789
3364
 
1790
- type = storage_c_type(array)
3365
+ type = storage_c_type(array_storage(array))
1791
3366
  outer = (0...(count - 1)).map { |axis|
1792
3367
  index, offset = subscripts[axis]
1793
3368
  "(#{index_expression(array, axis, index, offset)}) * " \
@@ -1810,11 +3385,30 @@ class CArray
1810
3385
  # Emits `node` so that its value has type `target`, inserting a cast
1811
3386
  # only where the type actually changes.
1812
3387
  def emit (node, target)
3388
+ note_unsigned_capture(node, target)
3389
+ return emit_complex_read_power(node, target).first if complex_read_power?(node, target)
3390
+ return emit_rounded_real(node, target).first if rounded_real?(node, target)
1813
3391
  widen(*emit_raw(node), node.type, target).first
1814
3392
  end
1815
3393
 
3394
+ # A signed capture read where a uint64 is computed -- absorbed into one,
3395
+ # or compared with one. Kernel refuses a negative value for it.
3396
+ def note_unsigned_capture (node, target)
3397
+ return unless node.is_a?(CaptureRead) && target == :uint64 &&
3398
+ @integers.include?(node.name)
3399
+ @unsigned_captures |= [node.name]
3400
+ end
3401
+
1816
3402
  def emit_operand (node, target, parent_precedence, right_side = false)
1817
- text, precedence = widen(*emit_raw(node), node.type, target)
3403
+ note_unsigned_capture(node, target)
3404
+ text, precedence =
3405
+ if complex_read_power?(node, target)
3406
+ emit_complex_read_power(node, target)
3407
+ elsif rounded_real?(node, target)
3408
+ emit_rounded_real(node, target)
3409
+ else
3410
+ widen(*emit_raw(node), node.type, target)
3411
+ end
1818
3412
  parenthesize(text, precedence, right_side ? parent_precedence + 1 : parent_precedence)
1819
3413
  end
1820
3414
 
@@ -1822,13 +3416,32 @@ class CArray
1822
3416
  # most of these on its own, but writing them down is what makes the
1823
3417
  # dumped source say where the type changed -- and `int64_t` to
1824
3418
  # `double _Complex` is a conversion worth seeing.
3419
+ #
3420
+ # `int64` and `uint64` are the exception the rank cannot express.
3421
+ # They are the same width and differ only in sign, so the rank puts
3422
+ # one above the other and a `uint64` reaching an `int64` context is a
3423
+ # step *down* it -- left uncast, on the reasoning that C would do it
3424
+ # anyway. C does not: in `i < n` with `i` an `int64_t` and `n` a
3425
+ # `size_t`, the conversion C performs is on the other operand, and a
3426
+ # loop counting down from -1 then runs against a bound of 2**64 - 1.
3427
+ # The compiler says so as `-Wsign-compare`, which is the warning every
3428
+ # generated loop over a `size_t` extent carried.
1825
3429
  def widen (text, precedence, from, to)
1826
3430
  here, there = NUMERIC_RANK[from], NUMERIC_RANK[to]
1827
- return [text, precedence] if here.nil? || there.nil? || there <= here
3431
+ return [text, precedence] if here.nil? || there.nil?
3432
+ unless there > here || crosses_sign?(from, to)
3433
+ return [text, precedence]
3434
+ end
1828
3435
  ["(#{COMPUTATION_C_TYPES.fetch(to)})" \
1829
3436
  "#{parenthesize(text, precedence, LEAF_PRECEDENCE)}", UNARY_PRECEDENCE]
1830
3437
  end
1831
3438
 
3439
+ def crosses_sign? (from, to)
3440
+ from != to &&
3441
+ TypeAssignment::INTEGER_TYPES.include?(from) &&
3442
+ TypeAssignment::INTEGER_TYPES.include?(to)
3443
+ end
3444
+
1832
3445
  def parenthesize (text, precedence, needed)
1833
3446
  precedence < needed ? "(#{text})" : text
1834
3447
  end
@@ -1849,8 +3462,11 @@ class CArray
1849
3462
  when BoundsValue then ["bounds[#{node.slot}]", LEAF_PRECEDENCE]
1850
3463
  when ZeroLike
1851
3464
  [ZEROES.fetch(node.type), LEAF_PRECEDENCE]
1852
- when LocalRead then [node.binding_name.to_s, LEAF_PRECEDENCE]
1853
- when CaptureRead then [c_name(node.name), LEAF_PRECEDENCE]
3465
+ when LocalRead then [local_c_name(node.name, node.binding, node.lane),
3466
+ LEAF_PRECEDENCE]
3467
+ when CaptureRead
3468
+ note_unsigned_capture(node, node.type)
3469
+ [parameter_c_name(node.name), LEAF_PRECEDENCE]
1854
3470
  # A read is widened to the type the kernel computes in, because that
1855
3471
  # is the type the Ruby loop computes in: reading a float32 cell in
1856
3472
  # Ruby gives a Float, and reading an int32 cell gives an Integer that
@@ -1861,9 +3477,20 @@ class CArray
1861
3477
  # A boolean cell is a byte holding 0 or 1, so it is already the value
1862
3478
  # it stands for. Keeping it that way on the way out is this kernel's
1863
3479
  # business, and cast_to_storage does it.
3480
+ when IntrinsicCall
3481
+ [intrinsic_reference(node), LEAF_PRECEDENCE]
3482
+ when LocalArrayRead
3483
+ cell = local_array_reference(node)
3484
+ widening = widening_cast(node.storage, node.type)
3485
+ if widening
3486
+ ["#{widening}#{parenthesize(cell, LEAF_PRECEDENCE, UNARY_PRECEDENCE)}",
3487
+ UNARY_PRECEDENCE]
3488
+ else
3489
+ [cell, LEAF_PRECEDENCE]
3490
+ end
1864
3491
  when ElementRead
1865
3492
  cell = cell_reference(node.array, node.subscripts)
1866
- widening = widening_cast(node.array, node.type)
3493
+ widening = widening_cast(array_storage(node.array), node.type)
1867
3494
  if widening
1868
3495
  ["#{widening}#{parenthesize(cell, LEAF_PRECEDENCE, UNARY_PRECEDENCE)}",
1869
3496
  UNARY_PRECEDENCE]
@@ -1871,6 +3498,11 @@ class CArray
1871
3498
  [cell, LEAF_PRECEDENCE]
1872
3499
  end
1873
3500
  when MaskTest then emit_mask_test(node)
3501
+ when LocalArrayMaskTest then emit_local_array_mask_test(node)
3502
+ when NumericPredicate then emit_numeric_predicate(node)
3503
+ when PointerTest
3504
+ ["#{node.name} #{node.null ? '==' : '!='} NULL", PRECEDENCE.fetch(:==)]
3505
+ when Clamp then emit_clamp(node)
1874
3506
  when UnaryMinus
1875
3507
  operand, precedence = emit_raw(node.operand)
1876
3508
  ["-#{parenthesize(operand, precedence, UNARY_PRECEDENCE)}", UNARY_PRECEDENCE]
@@ -1891,7 +3523,11 @@ class CArray
1891
3523
  when Power then emit_power(node)
1892
3524
  when MathCall then emit_math_call(node)
1893
3525
  when ArrayAddress
1894
- [c_name(node.array), LEAF_PRECEDENCE]
3526
+ [bare_name(node.array), LEAF_PRECEDENCE]
3527
+ when LocalArrayAddress
3528
+ # The array's own name, which is the address: C decays it at the
3529
+ # call, and there is no buffer for the caller to have packed.
3530
+ [local_c_name(node.name, node.binding), LEAF_PRECEDENCE]
1895
3531
  when PointerRead
1896
3532
  # A pointer parameter is reached the way C reaches it: contiguous,
1897
3533
  # from the address it was handed. No base, no stride, no bounds --
@@ -1905,7 +3541,8 @@ class CArray
1905
3541
  # scalars; this one is right here, so the call is direct.
1906
3542
  arguments = node.arguments.zip(node.parameters)
1907
3543
  .map { |argument, parameter|
1908
- if argument.is_a?(ArrayAddress)
3544
+ if argument.is_a?(ArrayAddress) ||
3545
+ argument.is_a?(LocalArrayAddress)
1909
3546
  emit(argument, :address)
1910
3547
  else
1911
3548
  emit(argument, parameter.computation)
@@ -1913,11 +3550,21 @@ class CArray
1913
3550
  }
1914
3551
  arguments << ERROR_FLAG if @error_parameter
1915
3552
  ["#{@own_symbol}(#{arguments.join(', ')})", LEAF_PRECEDENCE]
3553
+ when RandomDraw
3554
+ # The state is the address of the captured array, which the
3555
+ # declarations above bound to a name; the draw advances it in
3556
+ # place, which is what leaves the generator where the kernel left
3557
+ # it.
3558
+ symbol = CArray::Rng::DRAW_FUNCTIONS
3559
+ .fetch(@randoms.fetch(node.generator).generator)
3560
+ .fetch(node.kind)
3561
+ ["#{symbol}(#{bare_name(node.state)})", LEAF_PRECEDENCE]
1916
3562
  when CFunctionCall
1917
3563
  c_function = @c_functions.fetch(node.name)
1918
3564
  arguments = node.arguments.zip(c_function.parameters)
1919
3565
  .map { |argument, parameter|
1920
- if argument.is_a?(ArrayAddress)
3566
+ if argument.is_a?(ArrayAddress) ||
3567
+ argument.is_a?(LocalArrayAddress)
1921
3568
  emit(argument, :address)
1922
3569
  else
1923
3570
  emit(argument, parameter.computation)
@@ -1925,7 +3572,18 @@ class CArray
1925
3572
  }
1926
3573
  # A pasted body is reached by its symbol; an address by the local
1927
3574
  # the declarations bound it to.
1928
- called = c_function.pasted? ? c_function.name : c_name(node.name)
3575
+ called = if c_function.pasted?
3576
+ c_function.symbol
3577
+ elsif @in_function
3578
+ # Borrowed, inside a body that has no `functions` buffer
3579
+ # to take an address in -- so it is called by the name it
3580
+ # has, declared in the preamble, and the linker or the
3581
+ # loader resolves it. `jit_extern` opened the library to
3582
+ # find it, so by here the symbol is in the process.
3583
+ c_function.symbol
3584
+ else
3585
+ bare_name(node.name)
3586
+ end
1929
3587
  # And one that can report a failure is handed the slot this kernel
1930
3588
  # is watching -- null under a masked cell, where the value written
1931
3589
  # is out of contract and a division by zero there was not asked
@@ -1941,11 +3599,56 @@ class CArray
1941
3599
  end
1942
3600
 
1943
3601
  # `a[i] == UNDEF` reads the mask byte, never the value.
3602
+ # `Math.gamma` is Ruby's, which is tgamma with two things around it: a
3603
+ # table of exact values for a small integer argument, and the domain
3604
+ # error Ruby raises where tgamma answers with a NaN.
3605
+ def emit_gamma (node)
3606
+ type = node.type
3607
+ unhandled_type(node, "Math.gamma") unless GAMMA_C_TYPES.key?(type)
3608
+ @gamma_types |= [type]
3609
+ suffix, = GAMMA_C_TYPES.fetch(type)
3610
+ ["carray_jit_gamma_#{suffix}(#{emit(node.arguments.first, type)}, " \
3611
+ "#{error_argument})", LEAF_PRECEDENCE]
3612
+ end
3613
+
3614
+ # `x.clamp(low, high)` through a helper of its own width, so that each
3615
+ # of the three is computed once and the two failures Ruby raises for
3616
+ # are reported where they happen.
3617
+ def emit_clamp (node)
3618
+ type = node.type
3619
+ unhandled_type(node, "clamp") unless CLAMP_C_TYPES.key?(type)
3620
+ @clamp_types |= [type]
3621
+ ["carray_jit_clamp_#{CLAMP_C_TYPES.fetch(type).first}(" \
3622
+ "#{emit(node.value, type)}, #{emit(node.low, type)}, " \
3623
+ "#{emit(node.high, type)}, #{error_argument})", LEAF_PRECEDENCE]
3624
+ end
3625
+
3626
+ # `isnan` and `isfinite` are C's own, and take a number of any width.
3627
+ # A Complex answers `finite?` the way Ruby answers it -- both parts
3628
+ # finite -- through a helper, so that the number is computed once.
3629
+ # An Integer is finite whatever it holds, and goes through `isfinite`
3630
+ # all the same rather than being answered here: the read it stands for
3631
+ # is a read, and dropping it would drop what the read reports.
3632
+ def emit_numeric_predicate (node)
3633
+ type = node.operand.type
3634
+ function = node.name == :nan? ? "isnan" : "isfinite"
3635
+ if complex_type?(type)
3636
+ return emit_helper_call("complex_finite", [emit(node.operand, type)],
3637
+ type == :float_complex)
3638
+ end
3639
+ ["#{function}(#{emit(node.operand, type)})", LEAF_PRECEDENCE]
3640
+ end
3641
+
1944
3642
  def emit_mask_test (node)
1945
3643
  cell = cell_reference(node.array, node.subscripts, :mask)
1946
3644
  node.negated ? ["! #{cell}", UNARY_PRECEDENCE] : [cell, LEAF_PRECEDENCE]
1947
3645
  end
1948
3646
 
3647
+ def emit_local_array_mask_test (node)
3648
+ cell = local_array_reference(node, :mask)
3649
+ node.negated ? ["! #{cell}", UNARY_PRECEDENCE] : [cell, LEAF_PRECEDENCE]
3650
+ end
3651
+
1949
3652
  # Float#floor and friends hand back an Integer in Ruby, so the C rounds
1950
3653
  # and then narrows. An Integer receiver is already there.
1951
3654
  def emit_conversion (node)
@@ -1957,7 +3660,28 @@ class CArray
1957
3660
  UNARY_PRECEDENCE]
1958
3661
  end
1959
3662
  return [emit(node.operand, :double), LEAF_PRECEDENCE] if node.result_type == :double
1960
- ["(int64_t)#{node.name}(#{emit(node.operand, :double)})", UNARY_PRECEDENCE]
3663
+ @uses_whole_number = true
3664
+ ["carray_jit_whole_int64(#{node.name}(#{emit(node.operand, :double)}), " \
3665
+ "#{error_argument})", LEAF_PRECEDENCE]
3666
+ end
3667
+
3668
+ # The same rounding where the answer is wanted as a real number: the
3669
+ # Integer Ruby answers is exact however large, and a float cell holds
3670
+ # it as the rounded double already is, so it does not go through int64
3671
+ # and is not held to its range.
3672
+ def rounded_real? (node, target)
3673
+ node.is_a?(Conversion) && node.result_type == :int64 &&
3674
+ node.type == :int64 &&
3675
+ !TypeAssignment::INTEGER_TYPES.include?(node.operand.type) &&
3676
+ [:double, :float].include?(target)
3677
+ end
3678
+
3679
+ def emit_rounded_real (node, target)
3680
+ @uses_whole_number = true
3681
+ text = "carray_jit_whole_real(#{node.name}(#{emit(node.operand, :double)}), " \
3682
+ "#{error_argument})"
3683
+ return [text, LEAF_PRECEDENCE] if target == :double
3684
+ ["(float)#{text}", UNARY_PRECEDENCE]
1961
3685
  end
1962
3686
 
1963
3687
  # creal and cimag are the way out of the complex type; conj stays in it.
@@ -1982,6 +3706,24 @@ class CArray
1982
3706
  end
1983
3707
  end
1984
3708
 
3709
+ # A real power read where a complex is wanted -- stored in a complex
3710
+ # cell or joined with a complex. pow answers a negative base raised to
3711
+ # a power that is not an integer with NaN; Ruby answers with a Complex,
3712
+ # and as the value is going to be complex anyway, so does the kernel.
3713
+ # Read as a real, the power stays pow's.
3714
+ def complex_read_power? (node, target)
3715
+ node.is_a?(Power) && [:double, :float].include?(node.type) &&
3716
+ complex_type?(target)
3717
+ end
3718
+
3719
+ def emit_complex_read_power (node, target)
3720
+ @uses_real_power_complex = true
3721
+ text = "carray_jit_real_power_complex(#{emit(node.base, :double)}, " \
3722
+ "#{emit(node.exponent, :double)})"
3723
+ return [text, LEAF_PRECEDENCE] if target == :complex
3724
+ ["(float _Complex)#{text}", UNARY_PRECEDENCE]
3725
+ end
3726
+
1985
3727
  # An integer power is squared out rather than sent through pow, whose
1986
3728
  # double result would not be the exact integer Ruby gives.
1987
3729
  #
@@ -2018,7 +3760,7 @@ class CArray
2018
3760
  LEAF_PRECEDENCE]
2019
3761
  end
2020
3762
 
2021
- # cabs, fabs and llabs are three functions rather than one because C has
3763
+ # cabs, fabs and an integer helper are three rather than one because C has
2022
3764
  # no generic for them, so this names each type instead of letting one of
2023
3765
  # them be what a type it has not heard of falls into.
2024
3766
  def emit_absolute_value (node)
@@ -2033,8 +3775,10 @@ class CArray
2033
3775
  case node.type
2034
3776
  when :double then ["fabs(#{emit(node.operand, :double)})", LEAF_PRECEDENCE]
2035
3777
  when :float then ["fabsf(#{emit(node.operand, :float)})", LEAF_PRECEDENCE]
2036
- when :int64 then ["llabs(#{emit(node.operand, :int64)})", LEAF_PRECEDENCE]
2037
- # An unsigned number is its own magnitude, and llabs would take it
3778
+ when :int64
3779
+ @uses_integer_abs = true
3780
+ ["carray_jit_integer_abs(#{emit(node.operand, :int64)})", LEAF_PRECEDENCE]
3781
+ # An unsigned number is its own magnitude, and a signed helper would take it
2038
3782
  # through a signed type on the way.
2039
3783
  when :uint64 then [emit(node.operand, :uint64), LEAF_PRECEDENCE]
2040
3784
  else unhandled_type(node, "abs")
@@ -2051,6 +3795,8 @@ class CArray
2051
3795
  return emit_integer_division(node) if node.operator == :/ &&
2052
3796
  TypeAssignment::INTEGER_TYPES.include?(node.type)
2053
3797
  return emit_modulo(node) if node.operator == :%
3798
+ return emit_shift(node) if [:<<, :>>].include?(node.operator) &&
3799
+ TypeAssignment::INTEGER_TYPES.include?(node.type)
2054
3800
  return emit_complex_binary(node) if complex_type?(node.type)
2055
3801
 
2056
3802
  operand_type =
@@ -2090,10 +3836,13 @@ class CArray
2090
3836
  # and dividing by one divides each part.
2091
3837
  #
2092
3838
  # Subtraction is the exception: there the zero really is subtracted, in
2093
- # Ruby as in C, so `z - x` and `x - z` are C's own operator. So is
2094
- # `x * z`, which Ruby coerces and multiplies out in full -- which is
2095
- # why `2.0 * Complex(1.0, -0.0)` and `Complex(1.0, -0.0) * 2.0` do not
2096
- # agree with each other, and each is reproduced its own way.
3839
+ # Ruby as in C, so `z - x` and `x - z` are C's own operator. `x * z`
3840
+ # is not the exception it looks like: Ruby coerces the x and multiplies
3841
+ # out in full, as it does two Complex numbers, and a full product in
3842
+ # Ruby is safe_mul's part by part -- a zero times an infinity a zero --
3843
+ # where C's `*` recovers from infinities by Annex G's rules. So both
3844
+ # go through complex.c's comp_mul, and `2.0 * Complex(1.0, -0.0)` and
3845
+ # `Complex(1.0, -0.0) * 2.0` still differ, each reproduced its own way.
2097
3846
  #
2098
3847
  # And a complex division is Smith's method as complex.c writes it,
2099
3848
  # which is not what the C library's __divdc3 computes.
@@ -2114,18 +3863,7 @@ class CArray
2114
3863
  if complex_type == :float_complex &&
2115
3864
  [:*, :/].include?(node.operator) &&
2116
3865
  complex_type?(node.left.type) && complex_type?(node.right.type)
2117
- helper = mixed_helper(node, :complex)
2118
- if helper
2119
- text, = emit_helper_call(*helper, false)
2120
- else
2121
- precedence = PRECEDENCE.fetch(node.operator)
2122
- # Parenthesised, because the cast binds tighter than the operator:
2123
- # without them it would narrow the left operand and leave the
2124
- # multiplication to be worked out around it.
2125
- text = "(#{emit_operand(node.left, :complex, precedence)} " \
2126
- "#{node.operator} " \
2127
- "#{emit_operand(node.right, :complex, precedence)})"
2128
- end
3866
+ text, = emit_helper_call(*mixed_helper(node, :complex), false)
2129
3867
  return ["(float _Complex)#{text}", UNARY_PRECEDENCE]
2130
3868
  end
2131
3869
  narrow = complex_type == :float_complex
@@ -2138,6 +3876,9 @@ class CArray
2138
3876
  end
2139
3877
 
2140
3878
  def emit_helper_call (name, arguments, narrow)
3879
+ COMPLEX_HELPER_NEEDS.fetch(name, []).each do |needed|
3880
+ @complex_helpers |= [[needed, narrow]]
3881
+ end
2141
3882
  @complex_helpers |= [[name, narrow]]
2142
3883
  prefix = narrow ? "carray_jit_f_" : "carray_jit_"
2143
3884
  ["#{prefix}#{name}(#{arguments.join(', ')})", LEAF_PRECEDENCE]
@@ -2168,10 +3909,20 @@ class CArray
2168
3909
  when :*
2169
3910
  if real_type?(right)
2170
3911
  ["complex_mul_real", [emit(left, ctype), emit(right, rtype)]]
3912
+ elsif real_type?(left)
3913
+ ["real_multiply_complex", [emit(left, rtype), emit(right, ctype)]]
3914
+ else
3915
+ ["complex_multiply", [emit(left, ctype), emit(right, ctype)]]
2171
3916
  end
2172
3917
  end
2173
3918
  end
2174
3919
 
3920
+ # The helpers that call another, which has to be emitted above them.
3921
+ COMPLEX_HELPER_NEEDS = {
3922
+ "complex_multiply" => ["safe_multiply"],
3923
+ "real_multiply_complex" => ["safe_multiply"],
3924
+ }.freeze
3925
+
2175
3926
  def complex_type? (type)
2176
3927
  TypeAssignment.complex?(type)
2177
3928
  end
@@ -2220,6 +3971,7 @@ class CArray
2220
3971
  return ["(float _Complex)#{text}", UNARY_PRECEDENCE]
2221
3972
  end
2222
3973
  function = node.name.to_s
3974
+ return emit_gamma(node) if function == "gamma"
2223
3975
  function += "f" if node.type == :float
2224
3976
  arguments = node.arguments.map { |argument| emit(argument, node.type) }
2225
3977
  ["#{function}(#{arguments.join(', ')})", LEAF_PRECEDENCE]
@@ -2256,6 +4008,19 @@ class CArray
2256
4008
  "#{emit(node.right, :int64)}, #{error_argument})", LEAF_PRECEDENCE]
2257
4009
  end
2258
4010
 
4011
+ # A shift is Integer's -- see carray_jit_shift_left.
4012
+ def emit_shift (node)
4013
+ @uses_shift = true
4014
+ direction = node.operator == :<< ? "left" : "right"
4015
+ prefix = node.type == :uint64 ? "carray_jit_unsigned_shift_" : "carray_jit_shift_"
4016
+ count = if node.right.type == :uint64
4017
+ "carray_jit_shift_count(#{emit(node.right, :uint64)})"
4018
+ else
4019
+ emit(node.right, :int64)
4020
+ end
4021
+ ["#{prefix}#{direction}(#{emit(node.left, node.type)}, #{count})", LEAF_PRECEDENCE]
4022
+ end
4023
+
2259
4024
  # `%` floors, so it is not C's `%` -- see the helper above.
2260
4025
  def emit_modulo (node)
2261
4026
  if node.type == :uint64
@@ -2272,11 +4037,11 @@ class CArray
2272
4037
  if node.type == :float
2273
4038
  @uses_floor_modulo_float = true
2274
4039
  return ["carray_jit_floor_modulo_float(#{emit(node.left, :float)}, " \
2275
- "#{emit(node.right, :float)})", LEAF_PRECEDENCE]
4040
+ "#{emit(node.right, :float)}, #{error_argument})", LEAF_PRECEDENCE]
2276
4041
  end
2277
4042
  unhandled_type(node, "%") unless node.type == :double
2278
4043
  ["carray_jit_floor_modulo_real(#{emit(node.left, :double)}, " \
2279
- "#{emit(node.right, :double)})", LEAF_PRECEDENCE]
4044
+ "#{emit(node.right, :double)}, #{error_argument})", LEAF_PRECEDENCE]
2280
4045
  end
2281
4046
 
2282
4047
  def power_of_two_shift (node)
@@ -2286,11 +4051,23 @@ class CArray
2286
4051
  Math.log2(value).to_i
2287
4052
  end
2288
4053
 
4054
+ # A literal past int64 is a uint64 if it fits one, and refused with the
4055
+ # message a capture of the same value gets if it does not -- written
4056
+ # out, it was a compiler error about a constant too large for its type.
2289
4057
  def format_integer (value)
2290
- "INT64_C(#{value})"
4058
+ case TypeAssignment.integer_type(value)
4059
+ when :uint64 then "UINT64_C(#{value})"
4060
+ else "INT64_C(#{value})"
4061
+ end
2291
4062
  end
2292
4063
 
2293
4064
  def format_float (value, type = :double)
4065
+ # 1e400 is an infinity in Ruby; written out with %g it is the word
4066
+ # `inf`, which C does not know.
4067
+ if value.infinite?
4068
+ text = value.positive? ? "INFINITY" : "(-INFINITY)"
4069
+ return type == :float ? "((float)#{text})" : text
4070
+ end
2294
4071
  # A float literal without the suffix is a double, and one double in an
2295
4072
  # expression takes the whole expression with it -- so the suffix is
2296
4073
  # what keeps a float32 kernel computing in float.
@@ -2306,9 +4083,11 @@ class CArray
2306
4083
  text
2307
4084
  end
2308
4085
 
4086
+ # Spelled with `__`, which is what keeps it out of a block's way: a
4087
+ # local with `__` in its name is moved (see `local_c_names`).
2309
4088
  def next_temporary (prefix = "result")
2310
4089
  @temporary_count += 1
2311
- "#{prefix}#{@temporary_count}"
4090
+ "#{prefix}__#{@temporary_count}"
2312
4091
  end
2313
4092
 
2314
4093
  end