carray-jit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.yardopts +10 -0
- data/CHANGELOG.md +84 -0
- data/LICENSE +21 -0
- data/README.md +88 -0
- data/bin/carray-jit +194 -0
- data/carray-jit.gemspec +41 -0
- data/docs/00_Introduction.md +40 -0
- data/docs/01_GettingStarted.md +80 -0
- data/docs/02_KernelShapes.md +397 -0
- data/docs/03_SupportedFeatures.md +595 -0
- data/docs/04_Compiling.md +234 -0
- data/docs/05_DesignNotes.md +136 -0
- data/docs/06_Cheatsheet.md +177 -0
- data/examples/README.md +56 -0
- data/examples/applications/game_of_life.rb +161 -0
- data/examples/applications/heat_equation.rb +117 -0
- data/examples/applications/kepler.rb +178 -0
- data/examples/applications/mandelbrot.rb +151 -0
- data/examples/applications/moving_average.rb +124 -0
- data/examples/applications/partial_sums.rb +141 -0
- data/examples/applications/point_cloud.rb +110 -0
- data/examples/applications/quicksort.rb +118 -0
- data/examples/applications/recursion.rb +121 -0
- data/examples/applications/relaxation.rb +115 -0
- data/examples/applications/sensor_gaps.rb +118 -0
- data/examples/applications/sieve.rb +95 -0
- data/examples/applications/sobel_edges.rb +80 -0
- data/examples/features/01_element_wise.rb +69 -0
- data/examples/features/02_stencil.rb +40 -0
- data/examples/features/03_recurrence.rb +50 -0
- data/examples/features/04_thomas.rb +81 -0
- data/examples/features/05_reduction.rb +90 -0
- data/examples/features/06_jit_contract.rb +58 -0
- data/examples/features/07_masks.rb +55 -0
- data/examples/features/08_views.rb +46 -0
- data/examples/features/09_inspecting.rb +55 -0
- data/examples/features/10_complex.rb +107 -0
- data/examples/features/11_c_functions.rb +260 -0
- data/examples/features/12_sweep.rb +139 -0
- data/examples/features/13_cscalar.rb +80 -0
- data/examples/features/14_stencil_window.rb +106 -0
- data/examples/features/15_loops.rb +148 -0
- data/examples/features/16_raising.rb +69 -0
- data/ext/carray_jit_access/carray_jit_access.c +460 -0
- data/ext/carray_jit_access/extconf.rb +8 -0
- data/lib/carray/jit/analyzer.rb +1847 -0
- data/lib/carray/jit/block_reader.rb +139 -0
- data/lib/carray/jit/c_function.rb +777 -0
- data/lib/carray/jit/c_generator.rb +2305 -0
- data/lib/carray/jit/compiler.rb +468 -0
- data/lib/carray/jit/errors.rb +37 -0
- data/lib/carray/jit/expression.rb +202 -0
- data/lib/carray/jit/kernel.rb +509 -0
- data/lib/carray/jit/node.rb +573 -0
- data/lib/carray/jit/sweep.rb +97 -0
- data/lib/carray/jit/type_assignment.rb +811 -0
- data/lib/carray/jit/version.rb +5 -0
- data/lib/carray/jit.rb +1210 -0
- metadata +139 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
require "prism"
|
|
2
|
+
|
|
3
|
+
class CArray
|
|
4
|
+
module JIT
|
|
5
|
+
|
|
6
|
+
# Recovers the source of a Proc so that a real block can be compiled.
|
|
7
|
+
#
|
|
8
|
+
# Ruby does not hand back a Proc's source, but it does say exactly where
|
|
9
|
+
# the block sits: RubyVM::InstructionSequence carries a :code_location of
|
|
10
|
+
# [first_line, first_column, last_line, last_column]. Columns are what
|
|
11
|
+
# make this usable -- Proc#source_location gives only a line, which cannot
|
|
12
|
+
# tell two blocks on one line apart.
|
|
13
|
+
#
|
|
14
|
+
# RubyVM::AbstractSyntaxTree.of would be the obvious route and does not
|
|
15
|
+
# work: since Ruby 3.4 the default parser is Prism, and it refuses with
|
|
16
|
+
# "cannot get AST for ISEQ compiled by prism".
|
|
17
|
+
module BlockReader
|
|
18
|
+
|
|
19
|
+
class << self
|
|
20
|
+
|
|
21
|
+
# Returns [Prism node for the block, its source text, where it was
|
|
22
|
+
# written]. The third is for the generated C to say what it came
|
|
23
|
+
# from: a hash names a kernel, a file and a line explain it.
|
|
24
|
+
def read (block)
|
|
25
|
+
unless defined?(RubyVM::InstructionSequence)
|
|
26
|
+
raise Unsupported,
|
|
27
|
+
"this Ruby has no RubyVM::InstructionSequence; " \
|
|
28
|
+
"pass the kernel as `source:` instead"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
sequence = RubyVM::InstructionSequence.of(block)
|
|
32
|
+
unless sequence
|
|
33
|
+
raise Unsupported,
|
|
34
|
+
"the block has no instruction sequence (defined in C?); " \
|
|
35
|
+
"pass the kernel as `source:` instead"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
location = code_location(sequence)
|
|
39
|
+
source = script_source(sequence)
|
|
40
|
+
node = locate(source, location)
|
|
41
|
+
[node, extract(source, location), origin(sequence, location)]
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def origin (sequence, location)
|
|
47
|
+
path = begin
|
|
48
|
+
sequence.absolute_path || sequence.path
|
|
49
|
+
rescue NoMethodError
|
|
50
|
+
nil
|
|
51
|
+
end
|
|
52
|
+
path ? "#{path}:#{location[0]}" : nil
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def code_location (sequence)
|
|
56
|
+
location = sequence.to_a[4][:code_location]
|
|
57
|
+
unless location
|
|
58
|
+
raise Unsupported,
|
|
59
|
+
"this Ruby does not report a code location for blocks; " \
|
|
60
|
+
"pass the kernel as `source:` instead"
|
|
61
|
+
end
|
|
62
|
+
location
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# script_lines is present when the code was compiled with
|
|
66
|
+
# RubyVM.keep_script_lines set, which covers eval'd blocks; otherwise
|
|
67
|
+
# the file is read back.
|
|
68
|
+
def script_source (sequence)
|
|
69
|
+
lines = begin
|
|
70
|
+
sequence.script_lines
|
|
71
|
+
rescue NoMethodError
|
|
72
|
+
nil
|
|
73
|
+
end
|
|
74
|
+
return lines.join if lines
|
|
75
|
+
|
|
76
|
+
path = sequence.absolute_path
|
|
77
|
+
if path && File.file?(path)
|
|
78
|
+
return File.read(path)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
raise Unsupported,
|
|
82
|
+
"the block's source is not available " \
|
|
83
|
+
"(defined in eval or in a console?); " \
|
|
84
|
+
"pass the kernel as `source:`, or set " \
|
|
85
|
+
"RubyVM.keep_script_lines = true before defining it"
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def locate (source, location)
|
|
89
|
+
first_line, first_column, = location
|
|
90
|
+
result = Prism.parse(source)
|
|
91
|
+
unless result.success?
|
|
92
|
+
raise Unsupported, "the file holding the block does not parse"
|
|
93
|
+
end
|
|
94
|
+
node = find(result.value, first_line, first_column)
|
|
95
|
+
unless node
|
|
96
|
+
raise Unsupported,
|
|
97
|
+
"could not find the block at line #{first_line}, " \
|
|
98
|
+
"column #{first_column}; " \
|
|
99
|
+
"has the file changed since it was loaded?"
|
|
100
|
+
end
|
|
101
|
+
node
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def find (node, line, column)
|
|
105
|
+
if block_like?(node) &&
|
|
106
|
+
node.location.start_line == line &&
|
|
107
|
+
node.location.start_column == column
|
|
108
|
+
return node
|
|
109
|
+
end
|
|
110
|
+
node.compact_child_nodes.each do |child|
|
|
111
|
+
found = find(child, line, column)
|
|
112
|
+
return found if found
|
|
113
|
+
end
|
|
114
|
+
nil
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def block_like? (node)
|
|
118
|
+
node.is_a?(Prism::BlockNode) || node.is_a?(Prism::LambdaNode)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def extract (source, location)
|
|
122
|
+
first_line, first_column, last_line, last_column = location
|
|
123
|
+
lines = source.lines
|
|
124
|
+
if first_line == last_line
|
|
125
|
+
lines[first_line - 1][first_column...last_column]
|
|
126
|
+
else
|
|
127
|
+
body = lines[(first_line - 1)...last_line]
|
|
128
|
+
body[0] = body[0][first_column..]
|
|
129
|
+
body[-1] = body[-1][0...last_column]
|
|
130
|
+
body.join
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
end
|
|
139
|
+
end
|