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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +146 -0
- data/README.md +11 -10
- data/carray-jit.gemspec +1 -1
- data/docs/00_Introduction.md +2 -1
- data/docs/02_KernelShapes.md +1 -1
- data/docs/03_SupportedFeatures.md +88 -11
- data/docs/04_Compiling.md +2 -2
- data/docs/05_DesignNotes.md +1 -1
- data/docs/06_Cheatsheet.md +3 -3
- data/docs/07_StepByStep.ja.md +14 -15
- data/docs/07_StepByStep.md +14 -15
- data/docs/08_LanguageReference.md +427 -0
- data/lib/carray/jit/analyzer.rb +144 -7
- data/lib/carray/jit/c_function.rb +359 -21
- data/lib/carray/jit/c_generator.rb +398 -58
- data/lib/carray/jit/compiler.rb +27 -3
- data/lib/carray/jit/expression.rb +271 -33
- data/lib/carray/jit/kernel.rb +17 -4
- data/lib/carray/jit/node.rb +15 -0
- data/lib/carray/jit/type_assignment.rb +53 -1
- data/lib/carray/jit/version.rb +1 -1
- data/lib/carray/jit.rb +7 -33
- metadata +4 -3
|
@@ -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
|
-
|
|
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
|
-
|
|
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 +
|
|
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
|
|
567
|
-
#
|
|
568
|
-
#
|
|
569
|
-
#
|
|
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
|
-
#
|
|
605
|
-
#
|
|
606
|
-
#
|
|
607
|
-
#
|
|
608
|
-
#
|
|
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
|
-
|
|
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
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
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
|
-
|
|
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
|
|
1532
|
-
#
|
|
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
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
body = local_declarations(loop_node,
|
|
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,
|
|
2226
|
+
emit_statement(statement, inner + " ")
|
|
2011
2227
|
}.join
|
|
2012
|
-
|
|
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
|
-
|
|
2122
|
-
text
|
|
2123
|
-
text += "#{inner}
|
|
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 (; #{
|
|
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 (
|
|
2140
|
-
|
|
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
|
-
|
|
2352
|
-
|
|
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
|
-
|
|
2517
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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.
|