carray-jit 0.1.3 → 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.
@@ -363,6 +363,10 @@ class CArray
363
363
  # order the caller packs them.
364
364
  @unsigned_integers =
365
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 = []
366
370
  # Three buffers and no fourth: a capture whose type rides in none of
367
371
  # them would be packed into nothing and read as whatever the slot
368
372
  # held, so it is caught here rather than at the cell it computes
@@ -415,11 +419,13 @@ class CArray
415
419
  @uses_clamp = false
416
420
  @uses_wrap = false
417
421
  @uses_real_arg = false
422
+ @uses_real_power_complex = false
418
423
  @clamp_types = []
419
424
  @gamma_types = []
420
425
  @complex_helpers = []
421
426
  @uses_floor_divide = false
422
427
  @uses_floor_modulo = false
428
+ @uses_shift = false
423
429
  @uses_integer_power = false
424
430
  @uses_integer_abs = false
425
431
  @uses_whole_number = false
@@ -460,6 +466,7 @@ class CArray
460
466
  end
461
467
 
462
468
  attr_reader :arrays, :reals, :integers, :complexes, :unsigned_integers,
469
+ :unsigned_captures,
463
470
  :masked, :extent_slots,
464
471
  :c_functions, :pasted_functions, :address_functions,
465
472
  :address_arrays, :address_parameters,
@@ -517,7 +524,13 @@ class CArray
517
524
  # library handed the address calls without knowing about any of this.
518
525
  def generate_function (name, parameter_names, parameter_c_types,
519
526
  return_c_type, return_type, error_parameter: false)
520
- @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
521
534
  @in_function = true
522
535
  @error_parameter = error_parameter
523
536
  @body_reports = false
@@ -532,6 +545,7 @@ class CArray
532
545
  lines = held.map { |statement| emit_statement(statement, " ") }.join
533
546
  lines = local_declarations(@analyzer.body, " ") + lines
534
547
  value = @returns_nothing ? nil : emit(statements.last, return_type)
548
+ parameter_names = parameter_names.map { |parameter| parameter_c_name(parameter) }
535
549
  parameters = parameter_names.zip(parameter_c_types)
536
550
  .map { |parameter, type| type.declare(parameter) }
537
551
  # Passed whether or not the body turned out to use it, so that a
@@ -539,14 +553,131 @@ class CArray
539
553
  # same argument list the definition ends up declaring.
540
554
  parameters << "int32_t *#{ERROR_FLAG}" if error_parameter
541
555
  parameters = ["void"] if parameters.empty?
542
- 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
543
567
  # Kept apart from the file it is compiled in: the definition alone is
544
568
  # what a kernel pastes into its own translation unit, where the
545
569
  # includes are already written and the helpers are shared.
546
570
  opening = "#{return_c_type}\n#{name} (#{parameters.join(', ')})\n{\n"
547
571
  body = lines + (@returns_nothing ? "}\n" : " return #{value};\n}\n")
548
572
  @function_definition = opening + body
549
- preamble + flag + opening + standing_gate + 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
550
681
  end
551
682
 
552
683
  attr_reader :function_definition
@@ -563,10 +694,11 @@ class CArray
563
694
  # looks like a right one.
564
695
  #
565
696
  # What the gate says is that the body does no more work. It does not
566
- # say what the call is worth: the flag is the contract, and the zero is
567
- # a courtesy to a caller who never looks at it. A `void` body has no
568
- # courtesy to offer and leaves its out-parameters alone, which is the
569
- # same refusal to work.
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.
570
702
  #
571
703
  # It goes in the file and not in the definition, so that the form a
572
704
  # kernel pastes cannot pick it up whichever way the two forms are
@@ -593,26 +725,33 @@ class CArray
593
725
  :unsigned_power => @uses_unsigned_power,
594
726
  :floor_modulo_float => @uses_floor_modulo_float,
595
727
  :real_arg => @uses_real_arg,
728
+ :real_power_complex => @uses_real_power_complex,
596
729
  :clamp => @clamp_types.dup,
597
730
  :gamma => @gamma_types.dup,
598
731
  :complex => @complex_helpers.dup,
599
732
  :index_check => @uses_index_check,
600
733
  :floor_divide => @uses_floor_divide,
601
- :floor_modulo => @uses_floor_modulo }
734
+ :floor_modulo => @uses_floor_modulo,
735
+ :shift => @uses_shift }
602
736
  end
603
737
 
604
- # One per compiled object, so two functions never share it, and zeroed
605
- # by whoever is about to look -- the same discipline the kernel's own
606
- # error slot keeps. It is written only where the value returned is
607
- # already a stand-in, so a caller that never looks is no worse off than
608
- # 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.
609
748
  def error_flag_declaration
610
749
  "/* Standing at 1 when a division had no divisor, and at the code of\n" \
611
750
  " a `raise` in the body where one was reached -- the numbers a\n" \
612
751
  " kernel reports through its own slot, with the same meanings. A\n" \
613
752
  " subscript on a pointer parameter is not checked here and does not\n" \
614
753
  " appear: it is the caller's business, as it is in C. */\n" \
615
- "int32_t #{ERROR_FLAG} = 0;\n\n"
754
+ "static #{THREAD_LOCAL}int32_t #{ERROR_FLAG} = 0;\n\n"
616
755
  end
617
756
 
618
757
  # The same kernel, wrapped so carray can drive it.
@@ -698,12 +837,14 @@ class CArray
698
837
  @uses_unsigned_power ||= needs[:unsigned_power]
699
838
  @uses_floor_modulo_float ||= needs[:floor_modulo_float]
700
839
  @uses_real_arg ||= needs[:real_arg]
840
+ @uses_real_power_complex ||= needs[:real_power_complex]
701
841
  @clamp_types |= needs[:clamp] || []
702
842
  @gamma_types |= needs[:gamma] || []
703
843
  @complex_helpers |= needs[:complex] || []
704
844
  @uses_index_check ||= needs[:index_check]
705
845
  @uses_floor_divide ||= needs[:floor_divide]
706
846
  @uses_floor_modulo ||= needs[:floor_modulo]
847
+ @uses_shift ||= needs[:shift]
707
848
  # A union rather than an or: two bodies may want a `sort` of one
708
849
  # type and length and a `sum` of another, and the preamble owes one
709
850
  # helper for each. The same shape `:clamp` and `:gamma` take.
@@ -774,11 +915,8 @@ class CArray
774
915
  return 0;
775
916
  }
776
917
  float remainder = fmodf(numerator, denominator);
777
- if ( remainder != 0 ) {
778
- if ( (remainder < 0) != (denominator < 0) ) remainder += denominator;
779
- }
780
- else {
781
- remainder = copysignf(0.0f, denominator);
918
+ if ( remainder != 0 && (remainder < 0) != (denominator < 0) ) {
919
+ remainder += denominator;
782
920
  }
783
921
  return remainder;
784
922
  }
@@ -867,7 +1005,9 @@ class CArray
867
1005
  not in an int64_t, where the cast is undefined -- CArray raises
868
1006
  RangeError storing such an Integer, and so does this. The real
869
1007
  one is for a value that stays a number: 1e20.floor into a
870
- float64 cell is 1e20 in Ruby, and does not pass through int64. */
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. */
871
1011
  static inline double
872
1012
  carray_jit_whole_real (double value, int32_t *error)
873
1013
  {
@@ -877,7 +1017,7 @@ class CArray
877
1017
  else if ( isinf(value) ) {
878
1018
  if ( error ) *error = value > 0 ? #{FLOAT_INFINITY_CODE} : #{FLOAT_NEGATIVE_INFINITY_CODE};
879
1019
  }
880
- return value;
1020
+ return value + 0.0;
881
1021
  }
882
1022
 
883
1023
  static inline int64_t
@@ -998,6 +1138,33 @@ class CArray
998
1138
 
999
1139
  C
1000
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
1001
1168
  if @uses_clamp
1002
1169
  text << <<~C
1003
1170
  /* A window that falls off the array reads the nearest cell it
@@ -1054,10 +1221,10 @@ class CArray
1054
1221
  /* Ruby's `%` floors with its division: the remainder carries the
1055
1222
  sign of the divisor, where C's `%` and fmod carry the sign of
1056
1223
  the dividend. So add the divisor back when the remainder is
1057
- non-zero and disagrees with it in sign -- and, for floats,
1058
- give a zero remainder the divisor's sign, so the rule holds
1059
- without exception. This mirrors CArray's own `:mod` kernel in
1060
- `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.)
1061
1228
 
1062
1229
  A zero divisor is Ruby's rather than CArray's: `3.0 % 0.0` raises
1063
1230
  ZeroDivisionError in Ruby, a float divisor as much as an integer
@@ -1070,6 +1237,7 @@ class CArray
1070
1237
  if ( error ) *error = 1;
1071
1238
  return 0;
1072
1239
  }
1240
+ if ( denominator == -1 ) return 0;
1073
1241
  int64_t remainder = numerator % denominator;
1074
1242
  if ( remainder != 0 && ((remainder < 0) != (denominator < 0)) ) {
1075
1243
  remainder += denominator;
@@ -1085,17 +1253,62 @@ class CArray
1085
1253
  return 0;
1086
1254
  }
1087
1255
  double remainder = fmod(numerator, denominator);
1088
- if ( remainder != 0 ) {
1089
- if ( (remainder < 0) != (denominator < 0) ) remainder += denominator;
1090
- }
1091
- else {
1092
- remainder = copysign(0.0, denominator);
1256
+ if ( remainder != 0 && (remainder < 0) != (denominator < 0) ) {
1257
+ remainder += denominator;
1093
1258
  }
1094
1259
  return remainder;
1095
1260
  }
1096
1261
 
1097
1262
  C
1098
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
1099
1312
  if @uses_floor_divide
1100
1313
  text << <<~C
1101
1314
  /* Ruby and CArray floor integer division and give the remainder the
@@ -1114,6 +1327,9 @@ class CArray
1114
1327
  if ( error ) *error = 1;
1115
1328
  return 0;
1116
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);
1117
1333
  int64_t quotient = numerator / denominator;
1118
1334
  if ( numerator % denominator != 0 && ((numerator < 0) != (denominator < 0)) ) {
1119
1335
  quotient -= 1;
@@ -1528,10 +1744,8 @@ class CArray
1528
1744
  lines.empty? ? "" : lines.join + "\n"
1529
1745
  end
1530
1746
 
1531
- # Which way each axis runs is derived, not chosen: reading a cell the
1532
- # kernel will later write means that cell has to be reached in one
1533
- # particular order, and any other order would read what was never
1534
- # 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.
1535
1749
  # Each axis carries a start, a limit and a step. The step is a compiled
1536
1750
  # constant when it is one, because `i++` is what lets the loop vectorise
1537
1751
  # and that is the case nearly every kernel is in.
@@ -1678,7 +1892,9 @@ class CArray
1678
1892
  # A function returns whatever it returns, whatever happened -- the
1679
1893
  # arrangement its C caller is left with, and the one the division
1680
1894
  # helper already keeps by returning zero from a divide it refused.
1681
- # 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.
1682
1898
  leaving = @in_function && !@returns_nothing ? "return 0;" : "return;"
1683
1899
  "#{indent}if ( #{tests.join(' && ')} ) {\n" \
1684
1900
  "#{indent} #{report}\n" +
@@ -2002,14 +2218,53 @@ class CArray
2002
2218
 
2003
2219
  index = loop_node.index
2004
2220
  step = loop_node.step
2005
- opening = "#{indent}for (int64_t #{index} = #{emit(loop_node.from, :int64)}; " \
2006
- "#{index} #{step.positive? ? '<' : '>'} " \
2007
- "#{emit(loop_node.to, :int64)}; #{stride_step(index, step)}) {\n"
2008
- body = local_declarations(loop_node, indent + " ") +
2221
+ inner = indent + " "
2222
+ prelude, from, trips = loop_trips(loop_node, inner)
2223
+ count = "#{index}__t"
2224
+ body = local_declarations(loop_node, inner + " ") +
2009
2225
  loop_node.statements.map { |statement|
2010
- emit_statement(statement, indent + " ")
2226
+ emit_statement(statement, inner + " ")
2011
2227
  }.join
2012
- opening + inner_loop_guard(indent) + body + "#{indent}}\n"
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]
2013
2268
  end
2014
2269
 
2015
2270
  # The loop is a reduction when its whole body is one local folding a
@@ -2109,7 +2364,6 @@ class CArray
2109
2364
  type = assignment.type
2110
2365
  index = loop_node.index
2111
2366
  base = "#{index}__base"
2112
- limit = "#{index}__end"
2113
2367
  # A lane belongs to the accumulator, so its C name comes the way every
2114
2368
  # local's does.
2115
2369
  lanes = (0...PARTIAL_ACCUMULATORS).map { |lane|
@@ -2118,26 +2372,26 @@ class CArray
2118
2372
  identity = (operator == :* ? ONES : ZEROES).fetch(type)
2119
2373
 
2120
2374
  inner = indent + " "
2121
- text = "#{indent}{\n"
2122
- text += "#{inner}int64_t #{base} = #{emit(loop_node.from, :int64)};\n"
2123
- 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"
2124
2378
  text += "#{inner}#{COMPUTATION_C_TYPES.fetch(type)} #{lanes.first} = #{name}" +
2125
2379
  lanes.drop(1).map { |lane| ", #{lane} = #{identity}" }.join + ";\n"
2126
2380
  rounds = lanes.each_with_index.map { |lane, offset|
2127
2381
  term = lane_expression(assignment.expression, assignment.local, offset)
2128
2382
  "#{inner} {\n" \
2129
- "#{inner} const int64_t #{index} = #{base} + #{offset};\n" \
2383
+ "#{inner} const int64_t #{index} = (int64_t) ((uint64_t) #{from} + #{base} + #{offset});\n" \
2130
2384
  "#{inner} #{lane} = #{emit(term, type)};\n" \
2131
2385
  "#{inner} }\n"
2132
2386
  }.join
2133
- text += "#{inner}for (; #{base} + #{PARTIAL_ACCUMULATORS} <= #{limit}; " \
2387
+ text += "#{inner}for (; #{trips} - #{base} >= #{PARTIAL_ACCUMULATORS}; " \
2134
2388
  "#{base} += #{PARTIAL_ACCUMULATORS}) {\n"
2135
2389
  text += inner_loop_guard(inner) + rounds
2136
2390
  text += "#{inner}}\n"
2137
2391
  text += "#{inner}#{name} = #{combine_partials(lanes, operator)};\n"
2138
- tail = emit_statement(assignment, inner + " ")
2139
- text += "#{inner}for (int64_t #{index} = #{base}; #{index} < #{limit}; " \
2140
- "#{index}++) {\n"
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"
2141
2395
  text += inner_loop_guard(inner) + tail
2142
2396
  text += "#{inner}}\n"
2143
2397
  text + "#{indent}}\n"
@@ -2348,8 +2602,8 @@ class CArray
2348
2602
  "#{indent}#{target} = " \
2349
2603
  "#{cast_to_storage(temporary, type, write.storage)};\n" + mask
2350
2604
  else
2351
- value = cast_to_storage(emit(expression, expression.type),
2352
- expression.type, write.storage)
2605
+ type = complex_storage_of_power(expression, write.storage) || expression.type
2606
+ value = cast_to_storage(emit(expression, type), type, write.storage)
2353
2607
  "#{indent}#{target} = #{value};\n" + mask
2354
2608
  end
2355
2609
  end
@@ -2480,7 +2734,7 @@ class CArray
2480
2734
  "#{emit_mask(node.consequent)} : #{emit_mask(node.alternative)}"
2481
2735
  combine_masks([emit_mask(node.condition), "(#{branches})"])
2482
2736
  when IntegerLiteral, FloatLiteral, IndexVariable, CaptureRead, MaskTest,
2483
- LocalArrayMaskTest, BoundsValue, ZeroLike
2737
+ LocalArrayMaskTest, PointerTest, BoundsValue, ZeroLike
2484
2738
  "0"
2485
2739
  else
2486
2740
  combine_masks(node.children.map { |child| emit_mask(child) })
@@ -2513,12 +2767,21 @@ class CArray
2513
2767
  if real && rounded_real?(expression, real)
2514
2768
  return "#{indent}#{target} = #{emit(expression, real)};\n"
2515
2769
  end
2516
- value = cast_to_storage(emit(expression, expression.type),
2517
- expression.type, storage)
2770
+ type = complex_storage_of_power(expression, storage) || expression.type
2771
+ value = cast_to_storage(emit(expression, type), type, storage)
2518
2772
  "#{indent}#{target} = #{value};\n"
2519
2773
  end
2520
2774
  end
2521
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
+
2522
2785
  # A float cell, by what it computes in: the storage a rounding written
2523
2786
  # straight into keeps as a real number (see #rounded_real?).
2524
2787
  REAL_STORAGE_TYPES = { "float64" => :double, "float32" => :float }.freeze
@@ -2818,6 +3081,15 @@ class CArray
2818
3081
  bare_names.fetch(name) { c_name(name) }
2819
3082
  end
2820
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
+
2821
3093
  # The names this generator writes of its own, beside the kernel's
2822
3094
  # parameters and C's keywords: every decoration of every array the
2823
3095
  # kernel reaches, at every axis it has, and a borrowed function's type.
@@ -2950,6 +3222,12 @@ class CArray
2950
3222
 
2951
3223
  ERROR_FLAG = "carray_jit_error"
2952
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
+
2953
3231
  # A computation type this generator has no C for. Nothing reaches here
2954
3232
  # today -- every type TypeAssignment can assign is named at each of the
2955
3233
  # sites that calls this -- and that is the point: a type added later
@@ -3107,13 +3385,26 @@ class CArray
3107
3385
  # Emits `node` so that its value has type `target`, inserting a cast
3108
3386
  # only where the type actually changes.
3109
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)
3110
3390
  return emit_rounded_real(node, target).first if rounded_real?(node, target)
3111
3391
  widen(*emit_raw(node), node.type, target).first
3112
3392
  end
3113
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
+
3114
3402
  def emit_operand (node, target, parent_precedence, right_side = false)
3403
+ note_unsigned_capture(node, target)
3115
3404
  text, precedence =
3116
- if rounded_real?(node, target)
3405
+ if complex_read_power?(node, target)
3406
+ emit_complex_read_power(node, target)
3407
+ elsif rounded_real?(node, target)
3117
3408
  emit_rounded_real(node, target)
3118
3409
  else
3119
3410
  widen(*emit_raw(node), node.type, target)
@@ -3173,7 +3464,9 @@ class CArray
3173
3464
  [ZEROES.fetch(node.type), LEAF_PRECEDENCE]
3174
3465
  when LocalRead then [local_c_name(node.name, node.binding, node.lane),
3175
3466
  LEAF_PRECEDENCE]
3176
- when CaptureRead then [bare_name(node.name), LEAF_PRECEDENCE]
3467
+ when CaptureRead
3468
+ note_unsigned_capture(node, node.type)
3469
+ [parameter_c_name(node.name), LEAF_PRECEDENCE]
3177
3470
  # A read is widened to the type the kernel computes in, because that
3178
3471
  # is the type the Ruby loop computes in: reading a float32 cell in
3179
3472
  # Ruby gives a Float, and reading an int32 cell gives an Integer that
@@ -3207,6 +3500,8 @@ class CArray
3207
3500
  when MaskTest then emit_mask_test(node)
3208
3501
  when LocalArrayMaskTest then emit_local_array_mask_test(node)
3209
3502
  when NumericPredicate then emit_numeric_predicate(node)
3503
+ when PointerTest
3504
+ ["#{node.name} #{node.null ? '==' : '!='} NULL", PRECEDENCE.fetch(:==)]
3210
3505
  when Clamp then emit_clamp(node)
3211
3506
  when UnaryMinus
3212
3507
  operand, precedence = emit_raw(node.operand)
@@ -3411,6 +3706,24 @@ class CArray
3411
3706
  end
3412
3707
  end
3413
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
+
3414
3727
  # An integer power is squared out rather than sent through pow, whose
3415
3728
  # double result would not be the exact integer Ruby gives.
3416
3729
  #
@@ -3482,6 +3795,8 @@ class CArray
3482
3795
  return emit_integer_division(node) if node.operator == :/ &&
3483
3796
  TypeAssignment::INTEGER_TYPES.include?(node.type)
3484
3797
  return emit_modulo(node) if node.operator == :%
3798
+ return emit_shift(node) if [:<<, :>>].include?(node.operator) &&
3799
+ TypeAssignment::INTEGER_TYPES.include?(node.type)
3485
3800
  return emit_complex_binary(node) if complex_type?(node.type)
3486
3801
 
3487
3802
  operand_type =
@@ -3693,6 +4008,19 @@ class CArray
3693
4008
  "#{emit(node.right, :int64)}, #{error_argument})", LEAF_PRECEDENCE]
3694
4009
  end
3695
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
+
3696
4024
  # `%` floors, so it is not C's `%` -- see the helper above.
3697
4025
  def emit_modulo (node)
3698
4026
  if node.type == :uint64
@@ -3723,11 +4051,23 @@ class CArray
3723
4051
  Math.log2(value).to_i
3724
4052
  end
3725
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.
3726
4057
  def format_integer (value)
3727
- "INT64_C(#{value})"
4058
+ case TypeAssignment.integer_type(value)
4059
+ when :uint64 then "UINT64_C(#{value})"
4060
+ else "INT64_C(#{value})"
4061
+ end
3728
4062
  end
3729
4063
 
3730
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
3731
4071
  # A float literal without the suffix is a double, and one double in an
3732
4072
  # expression takes the whole expression with it -- so the suffix is
3733
4073
  # what keeps a float32 kernel computing in float.