ikra 0.0.1 → 0.0.2
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/lib/ast/builder.rb +225 -77
- data/lib/ast/host_section_builder.rb +38 -0
- data/lib/ast/interpreter.rb +67 -0
- data/lib/ast/lexical_variables_enumerator.rb +3 -2
- data/lib/ast/nodes.rb +521 -31
- data/lib/ast/printer.rb +116 -18
- data/lib/ast/ssa_generator.rb +192 -0
- data/lib/ast/visitor.rb +235 -21
- data/lib/config/configuration.rb +28 -3
- data/lib/config/os_configuration.rb +62 -9
- data/lib/cpu/cpu_implementation.rb +39 -0
- data/lib/ikra.rb +13 -3
- data/lib/resources/cuda/allocate_device_memory.cpp +5 -0
- data/lib/resources/cuda/allocate_host_memory.cpp +1 -0
- data/lib/resources/cuda/allocate_memcpy_environment_to_device.cpp +11 -0
- data/lib/resources/cuda/ast/assignment.cpp +1 -0
- data/lib/resources/cuda/block_function_head.cpp +7 -1
- data/lib/resources/cuda/entry_point.cpp +47 -0
- data/lib/resources/cuda/env_builder_copy_array.cpp +8 -2
- data/lib/resources/cuda/free_device_memory.cpp +3 -0
- data/lib/resources/cuda/free_memory_for_command.cpp +24 -0
- data/lib/resources/cuda/header.cpp +23 -9
- data/lib/resources/cuda/header_structs.cpp +92 -0
- data/lib/resources/cuda/host_section_block_function_head.cpp +12 -0
- data/lib/resources/cuda/host_section_entry_point.cpp +55 -0
- data/lib/resources/cuda/host_section_free_device_memory.cpp +18 -0
- data/lib/resources/cuda/host_section_launch_parallel_section.cpp +14 -0
- data/lib/resources/cuda/host_section_malloc_memcpy_device_to_host.cpp +10 -0
- data/lib/resources/cuda/kernel.cpp +9 -2
- data/lib/resources/cuda/launch_kernel.cpp +5 -0
- data/lib/resources/cuda/memcpy_device_to_host.cpp +3 -0
- data/lib/resources/cuda/memcpy_device_to_host_expr.cpp +10 -0
- data/lib/resources/cuda/reduce_body.cpp +88 -0
- data/lib/resources/cuda/stencil_array_reconstruction.cpp +2 -0
- data/lib/resources/cuda/stencil_body.cpp +16 -0
- data/lib/resources/cuda/struct_definition.cpp +4 -0
- data/lib/ruby_core/array.rb +34 -0
- data/lib/ruby_core/array_command.rb +313 -0
- data/lib/ruby_core/core.rb +103 -0
- data/lib/ruby_core/interpreter.rb +16 -0
- data/lib/ruby_core/math.rb +32 -0
- data/lib/ruby_core/ruby_integration.rb +256 -0
- data/lib/symbolic/host_section.rb +115 -0
- data/lib/symbolic/input.rb +87 -0
- data/lib/symbolic/input_visitor.rb +68 -0
- data/lib/symbolic/symbolic.rb +793 -117
- data/lib/symbolic/visitor.rb +70 -8
- data/lib/translator/array_command_struct_builder.rb +163 -0
- data/lib/translator/ast_translator.rb +572 -0
- data/lib/translator/block_translator.rb +104 -48
- data/lib/translator/commands/array_combine_command.rb +41 -0
- data/lib/translator/commands/array_identity_command.rb +28 -0
- data/lib/translator/commands/array_index_command.rb +52 -0
- data/lib/translator/commands/array_reduce_command.rb +135 -0
- data/lib/translator/commands/array_stencil_command.rb +129 -0
- data/lib/translator/commands/array_zip_command.rb +30 -0
- data/lib/translator/commands/command_translator.rb +264 -0
- data/lib/translator/cuda_errors.rb +32 -0
- data/lib/translator/environment_builder.rb +263 -0
- data/lib/translator/host_section/array_host_section_command.rb +150 -0
- data/lib/translator/host_section/array_in_host_section_command.rb +41 -0
- data/lib/translator/host_section/ast_translator.rb +14 -0
- data/lib/translator/host_section/parallel_section_invocation_visitor.rb +20 -0
- data/lib/translator/host_section/program_builder.rb +89 -0
- data/lib/translator/input_translator.rb +226 -0
- data/lib/translator/kernel_builder.rb +137 -0
- data/lib/translator/kernel_launcher/for_loop_kernel_launcher.rb +40 -0
- data/lib/translator/kernel_launcher/kernel_launcher.rb +259 -0
- data/lib/translator/kernel_launcher/while_loop_kernel_launcher.rb +38 -0
- data/lib/translator/last_returns_visitor.rb +19 -10
- data/lib/translator/program_builder.rb +197 -0
- data/lib/translator/program_launcher.rb +273 -0
- data/lib/translator/struct_type.rb +55 -0
- data/lib/translator/translator.rb +34 -11
- data/lib/translator/variable_classifier_visitor.rb +56 -0
- data/lib/types/inference/ast_inference.rb +586 -0
- data/lib/types/inference/clear_types_visitor.rb +11 -0
- data/lib/types/inference/command_inference.rb +101 -0
- data/lib/types/inference/input_inference.rb +62 -0
- data/lib/types/{object_tracer.rb → inference/object_tracer.rb} +5 -6
- data/lib/types/inference/ruby_extension.rb +35 -0
- data/lib/types/inference/symbol_table.rb +131 -0
- data/lib/types/types.rb +14 -0
- data/lib/types/types/array_command_type.rb +123 -0
- data/lib/types/types/array_type.rb +137 -0
- data/lib/types/{class_type.rb → types/class_type.rb} +42 -18
- data/lib/types/{primitive_type.rb → types/primitive_type.rb} +20 -7
- data/lib/types/types/ruby_type.rb +88 -0
- data/lib/types/types/struct_type.rb +179 -0
- data/lib/types/types/union_type.rb +239 -0
- metadata +160 -18
- data/lib/ast/method_definition.rb +0 -37
- data/lib/ast/translator.rb +0 -264
- data/lib/resources/cuda/kernel_launcher.cpp +0 -28
- data/lib/scope.rb +0 -166
- data/lib/translator/command_translator.rb +0 -421
- data/lib/translator/local_variables_enumerator.rb +0 -35
- data/lib/translator/method_translator.rb +0 -24
- data/lib/types/array_type.rb +0 -51
- data/lib/types/ruby_extension.rb +0 -67
- data/lib/types/ruby_type.rb +0 -45
- data/lib/types/type_inference.rb +0 -382
- data/lib/types/union_type.rb +0 -155
@@ -0,0 +1,87 @@
|
|
1
|
+
module Ikra
|
2
|
+
module Symbolic
|
3
|
+
# Specifies an input parameter for a parallel section. A parameter might be expanded to
|
4
|
+
# multiple parameters in the generated CUDA code to avoid passing arrays etc.
|
5
|
+
class Input
|
6
|
+
# Returns the access pattern of this input, e.g., `:tid` (single element, identified
|
7
|
+
# by thread ID) or `:entire` (access to entire array is necessary).
|
8
|
+
attr_reader :pattern
|
9
|
+
|
10
|
+
attr_reader :command
|
11
|
+
|
12
|
+
def initialize(pattern:)
|
13
|
+
# Currently supported: :tid, :entire
|
14
|
+
@pattern = pattern
|
15
|
+
end
|
16
|
+
|
17
|
+
def ==(other)
|
18
|
+
return self.class == other.class &&
|
19
|
+
self.pattern == other.pattern &&
|
20
|
+
self.command == other.command
|
21
|
+
end
|
22
|
+
|
23
|
+
def hash
|
24
|
+
return (pattern.hash + command.hash) % 7656781
|
25
|
+
end
|
26
|
+
|
27
|
+
def eql?(other)
|
28
|
+
return self == other
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# A single input value produced by one command.
|
33
|
+
class SingleInput < Input
|
34
|
+
def initialize(command:, pattern:)
|
35
|
+
super(pattern: pattern)
|
36
|
+
|
37
|
+
@command = command
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# An array containing values produced by one previous command.
|
42
|
+
class StencilArrayInput < Input
|
43
|
+
attr_reader :offsets
|
44
|
+
attr_reader :out_of_bounds_value
|
45
|
+
|
46
|
+
def initialize(command:, pattern:, offsets:, out_of_bounds_value:)
|
47
|
+
super(pattern: pattern)
|
48
|
+
|
49
|
+
@command = command
|
50
|
+
@offsets = offsets
|
51
|
+
@out_of_bounds_value = out_of_bounds_value
|
52
|
+
end
|
53
|
+
|
54
|
+
def ==(other)
|
55
|
+
return super(other) &&
|
56
|
+
offsets == other.offsets &&
|
57
|
+
out_of_bounds_value == other.out_of_bounds_value
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class StencilSingleInput < Input
|
62
|
+
attr_reader :offsets
|
63
|
+
attr_reader :out_of_bounds_value
|
64
|
+
|
65
|
+
def initialize(command:, pattern:, offsets:, out_of_bounds_value:)
|
66
|
+
super(pattern: pattern)
|
67
|
+
|
68
|
+
@command = command
|
69
|
+
@offsets = offsets
|
70
|
+
@out_of_bounds_value = out_of_bounds_value
|
71
|
+
end
|
72
|
+
|
73
|
+
def ==(other)
|
74
|
+
return super(other) &&
|
75
|
+
offsets == other.offsets &&
|
76
|
+
out_of_bounds_value == other.out_of_bounds_value
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Similar to [SingleInput], but two values are passed to the block.
|
81
|
+
class ReduceInput < SingleInput
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
require_relative "input_visitor"
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require_relative "input"
|
2
|
+
require_relative "visitor"
|
3
|
+
|
4
|
+
module Ikra
|
5
|
+
module Symbolic
|
6
|
+
class Input
|
7
|
+
def accept(visitor)
|
8
|
+
visitor.visit_input(self, pattern: pattern)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class SingleInput
|
13
|
+
def accept(visitor)
|
14
|
+
visitor.visit_single_input(self, pattern: pattern)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class StencilArrayInput
|
19
|
+
def accept(visitor)
|
20
|
+
visitor.visit_stecil_array_input(self, pattern: pattern)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class StencilSingleInput
|
25
|
+
def accept(visitor)
|
26
|
+
visitor.visit_stencil_single_input(self, pattern: pattern)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class ReduceInput
|
31
|
+
def accept(visitor)
|
32
|
+
visitor.visit_reduce_input(self, pattern: pattern)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class InputVisitor < Visitor
|
37
|
+
def visit_input(input, pattern:)
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
def visit_single_input(input, pattern:)
|
42
|
+
visit_input(input)
|
43
|
+
input.command.accept(self)
|
44
|
+
end
|
45
|
+
|
46
|
+
def visit_stencil_array_input(input, pattern:)
|
47
|
+
visit_input(input)
|
48
|
+
input.command.accept(self)
|
49
|
+
end
|
50
|
+
|
51
|
+
def visit_stencil_single_input(input, pattern:)
|
52
|
+
visit_input(input)
|
53
|
+
input.command.accept(self)
|
54
|
+
end
|
55
|
+
|
56
|
+
def visit_reduce_input(input, pattern:)
|
57
|
+
visit_input(input)
|
58
|
+
input.command.accept(self)
|
59
|
+
end
|
60
|
+
|
61
|
+
def visit_array_command(command)
|
62
|
+
for input in command.input
|
63
|
+
input.accept(self)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/symbolic/symbolic.rb
CHANGED
@@ -1,176 +1,793 @@
|
|
1
1
|
require "set"
|
2
|
-
require_relative "
|
3
|
-
require_relative "../
|
4
|
-
require_relative "../types/
|
5
|
-
require_relative "../types/union_type"
|
6
|
-
require_relative "../types/array_type"
|
2
|
+
require_relative "input"
|
3
|
+
require_relative "../translator/translator"
|
4
|
+
require_relative "../types/types"
|
7
5
|
require_relative "../type_aware_array"
|
8
6
|
require_relative "../parsing"
|
9
7
|
require_relative "../ast/nodes"
|
10
8
|
require_relative "../ast/lexical_variables_enumerator"
|
11
9
|
require_relative "../config/os_configuration"
|
12
10
|
|
13
|
-
Ikra::Configuration.check_software_configuration
|
14
|
-
|
15
11
|
module Ikra
|
16
12
|
module Symbolic
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
13
|
+
DEFAULT_BLOCK_SIZE = 256
|
14
|
+
|
15
|
+
def self.stencil(directions:, distance:)
|
16
|
+
return ["G", directions, distance]
|
17
|
+
end
|
18
|
+
|
19
|
+
module ParallelOperations
|
20
|
+
def preduce(symbol = nil, **options, &block)
|
21
|
+
if symbol == nil && (block != nil || options[:ast] != nil)
|
22
|
+
return ArrayReduceCommand.new(
|
23
|
+
to_command,
|
24
|
+
block,
|
25
|
+
**options)
|
26
|
+
elsif symbol != nil && block == nil
|
27
|
+
ast = AST::BlockDefNode.new(
|
28
|
+
ruby_block: nil,
|
29
|
+
parameters: [:a, :b],
|
30
|
+
body: AST::RootNode.new(single_child:
|
31
|
+
AST::SendNode.new(
|
32
|
+
receiver: AST::LVarReadNode.new(identifier: :a),
|
33
|
+
selector: symbol,
|
34
|
+
arguments: [AST::LVarReadNode.new(identifier: :b)])))
|
35
|
+
|
36
|
+
return ArrayReduceCommand.new(
|
37
|
+
to_command,
|
38
|
+
nil,
|
39
|
+
ast: ast,
|
40
|
+
**options)
|
41
|
+
else
|
42
|
+
raise ArgumentError.new("Either block or symbol expected")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def pstencil(offsets, out_of_range_value, **options, &block)
|
47
|
+
return ArrayStencilCommand.new(
|
48
|
+
to_command,
|
49
|
+
offsets,
|
50
|
+
out_of_range_value,
|
51
|
+
block,
|
52
|
+
**options)
|
53
|
+
end
|
54
|
+
|
55
|
+
def pmap(**options, &block)
|
56
|
+
return pcombine(
|
57
|
+
**options,
|
58
|
+
&block)
|
59
|
+
end
|
60
|
+
|
61
|
+
def pcombine(*others, **options, &block)
|
62
|
+
return ArrayCombineCommand.new(
|
63
|
+
to_command,
|
64
|
+
wrap_in_command(*others),
|
65
|
+
block,
|
66
|
+
**options)
|
67
|
+
end
|
68
|
+
|
69
|
+
def pzip(*others, **options)
|
70
|
+
return ArrayZipCommand.new(
|
71
|
+
to_command,
|
72
|
+
wrap_in_command(*others),
|
73
|
+
**options)
|
74
|
+
end
|
75
|
+
|
76
|
+
def +(other)
|
77
|
+
return pcombine(other) do |a, b|
|
78
|
+
a + b
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def -(other)
|
83
|
+
return pcombine(other) do |a, b|
|
84
|
+
a - b
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def *(other)
|
89
|
+
return pcombine(other) do |a, b|
|
90
|
+
a * b
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def /(other)
|
95
|
+
return pcombine(other) do |a, b|
|
96
|
+
a / b
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def |(other)
|
101
|
+
return pcombine(other) do |a, b|
|
102
|
+
a | b
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def &(other)
|
107
|
+
return pcombine(other) do |a, b|
|
108
|
+
a & b
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def ^(other)
|
113
|
+
return pcombine(other) do |a, b|
|
114
|
+
a ^ b
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def <(other)
|
119
|
+
return pcombine(other) do |a, b|
|
120
|
+
a < b
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def <=(other)
|
125
|
+
return pcombine(other) do |a, b|
|
126
|
+
a <= b
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def >(other)
|
131
|
+
return pcombine(other) do |a, b|
|
132
|
+
a > b
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def >=(other)
|
137
|
+
return pcombine(other) do |a, b|
|
138
|
+
a >= b
|
139
|
+
end
|
140
|
+
end
|
25
141
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
142
|
+
# TODO(springerm): Should implement #== but this could cause trouble when using with
|
143
|
+
# hash maps etc.
|
144
|
+
|
145
|
+
private
|
146
|
+
|
147
|
+
def wrap_in_command(*others)
|
148
|
+
return others.map do |other|
|
149
|
+
other.to_command
|
150
|
+
end
|
30
151
|
end
|
31
152
|
end
|
32
153
|
|
33
154
|
module ArrayCommand
|
155
|
+
include Enumerable
|
156
|
+
include ParallelOperations
|
157
|
+
|
158
|
+
attr_reader :block_size
|
159
|
+
|
160
|
+
# [Fixnum] Returns a unique ID for this command. It is used during name mangling in
|
161
|
+
# the code generator to determine the name of array identifiers (and do other stuff?).
|
162
|
+
attr_reader :unique_id
|
163
|
+
|
164
|
+
# An array of commands that serve as input to this command. The number of input
|
165
|
+
# commands depends on the type of the command.
|
166
|
+
attr_reader :input
|
167
|
+
|
168
|
+
# Indicates if result should be kept on the GPU for further processing.
|
169
|
+
attr_reader :keep
|
170
|
+
|
171
|
+
# This field can only be used if keep is true
|
172
|
+
attr_accessor :gpu_result_pointer
|
34
173
|
|
35
|
-
|
174
|
+
# Returns the block of the parallel section or [nil] if none.
|
175
|
+
attr_reader :block
|
176
|
+
|
177
|
+
# A reference to the AST send node that generated this [ArrayCommand] (if inside a
|
178
|
+
# host section).
|
179
|
+
attr_reader :generator_node
|
36
180
|
|
37
181
|
@@unique_id = 1
|
38
182
|
|
39
|
-
def
|
40
|
-
|
183
|
+
def self.reset_unique_id
|
184
|
+
@@unique_id = 1
|
185
|
+
end
|
41
186
|
|
42
|
-
|
43
|
-
|
44
|
-
@@unique_id += 1
|
187
|
+
def to_s
|
188
|
+
return "[#{self.class.to_s}, size = #{size.to_s}]"
|
45
189
|
end
|
46
190
|
|
47
|
-
def
|
48
|
-
|
49
|
-
|
191
|
+
def initialize(
|
192
|
+
block: nil,
|
193
|
+
block_ast: nil,
|
194
|
+
block_size: nil,
|
195
|
+
keep: nil,
|
196
|
+
generator_node: nil,
|
197
|
+
command_binding: nil)
|
198
|
+
|
199
|
+
super()
|
200
|
+
|
201
|
+
set_unique_id
|
202
|
+
|
203
|
+
# Set instance variables
|
204
|
+
@block_size = block_size
|
205
|
+
@keep = keep
|
206
|
+
@generator_node = generator_node
|
207
|
+
@command_binding = command_binding
|
208
|
+
|
209
|
+
if block != nil and block_ast == nil
|
210
|
+
@block = block
|
211
|
+
elsif block == nil and block_ast != nil
|
212
|
+
@ast = block_ast
|
213
|
+
elsif block != nil and block_ast != nil
|
214
|
+
raise ArgumentError.new("`block` and `block_ast` given. Expected at most one.")
|
50
215
|
end
|
51
|
-
|
52
|
-
@result[index]
|
53
216
|
end
|
217
|
+
|
54
218
|
|
219
|
+
# ----- EQUALITY -----
|
220
|
+
|
221
|
+
# Methods for equality and hash. These methods are required for comparing array
|
222
|
+
# commands for equality. This is necessary because every array command can also
|
223
|
+
# act as a type. Types must be comparable for equality.
|
224
|
+
|
225
|
+
def ==(other)
|
226
|
+
# Important: ArrayCommands may be created over and over during type inference.
|
227
|
+
# It is important that we compare values and not identities!
|
228
|
+
|
229
|
+
return self.class == other.class &&
|
230
|
+
block_size == other.block_size &&
|
231
|
+
input == other.input &&
|
232
|
+
keep == other.keep &&
|
233
|
+
block_def_node == other.block_def_node
|
234
|
+
end
|
235
|
+
|
236
|
+
def hash
|
237
|
+
return (block_size.hash + input.hash + keep.hash + block_def_node.hash) % 7546777
|
238
|
+
end
|
239
|
+
|
240
|
+
def eql?(other)
|
241
|
+
return self == other
|
242
|
+
end
|
243
|
+
|
244
|
+
# ----- EQUALITY END -----
|
245
|
+
|
246
|
+
|
247
|
+
# ----- ARRAY METHODS -----
|
248
|
+
|
249
|
+
def [](index)
|
250
|
+
execute
|
251
|
+
return @result[index]
|
252
|
+
end
|
253
|
+
|
254
|
+
def each(&block)
|
255
|
+
next_index = 0
|
256
|
+
|
257
|
+
while next_index < size
|
258
|
+
yield(self[next_index])
|
259
|
+
next_index += 1
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
def pack(fmt)
|
264
|
+
execute
|
265
|
+
return @result.pack(fmt)
|
266
|
+
end
|
267
|
+
|
268
|
+
# ----- ARRAY END -----
|
269
|
+
|
270
|
+
|
271
|
+
# The class or subclass of [CommandTranslator] that should be used for translating
|
272
|
+
# this command. May be overridden.
|
273
|
+
def command_translator_class
|
274
|
+
return Translator::CommandTranslator
|
275
|
+
end
|
276
|
+
|
55
277
|
def execute
|
56
|
-
@result
|
278
|
+
if @result == nil
|
279
|
+
@result = command_translator_class.translate_command(self).execute
|
280
|
+
end
|
57
281
|
end
|
58
282
|
|
59
283
|
def to_command
|
60
|
-
self
|
284
|
+
return self
|
61
285
|
end
|
62
|
-
|
63
|
-
|
64
|
-
|
286
|
+
|
287
|
+
# This method is executed after execution of the parallel section has finish. The
|
288
|
+
# boolean return value indicates if a change has been registered or not.
|
289
|
+
def post_execute(environment)
|
290
|
+
if keep
|
291
|
+
# The (temporary) result of this command should be kept on the GPU. Store a
|
292
|
+
# pointer to the result in global memory in an instance variable.
|
293
|
+
|
294
|
+
begin
|
295
|
+
@gpu_result_pointer = environment[("prev_" + unique_id.to_s).to_sym].to_i
|
296
|
+
Log.info("Kept pointer for result of command #{unique_id.to_s}: #{@gpu_result_pointer}")
|
297
|
+
return true
|
298
|
+
rescue ArgumentError
|
299
|
+
# No pointer saved for this command. This can happen if the result of this
|
300
|
+
# command was already cached earlier and the cached result of a
|
301
|
+
# computation based on this command was used now.
|
302
|
+
Log.info("No pointer kept for result of command #{unique_id.to_s}.")
|
303
|
+
return false
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
return false
|
308
|
+
end
|
309
|
+
|
310
|
+
def has_previous_result?
|
311
|
+
return !gpu_result_pointer.nil?
|
65
312
|
end
|
66
313
|
|
67
314
|
# Returns a collection of the names of all block parameters.
|
68
315
|
# @return [Array(Symbol)] list of block parameters
|
69
316
|
def block_parameter_names
|
70
|
-
|
71
|
-
param[1]
|
72
|
-
end
|
317
|
+
return block_def_node.parameters
|
73
318
|
end
|
74
319
|
|
75
|
-
# Returns the size (number of elements) of the result, after executing the parallel
|
320
|
+
# Returns the size (number of elements) of the result, after executing the parallel
|
321
|
+
# section.
|
76
322
|
# @return [Fixnum] size
|
77
323
|
def size
|
78
|
-
raise NotImplementedError
|
324
|
+
raise NotImplementedError.new
|
79
325
|
end
|
80
326
|
|
81
|
-
def
|
82
|
-
|
327
|
+
def dimensions
|
328
|
+
# Dimensions are defined in a root command. First input currently determines the
|
329
|
+
# dimensions (even if there are multiple root commands).
|
330
|
+
return input.first.command.dimensions
|
83
331
|
end
|
84
332
|
|
85
333
|
# Returns the abstract syntax tree for a parallel section.
|
86
|
-
def
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
334
|
+
def block_def_node
|
335
|
+
if @ast == nil
|
336
|
+
if block == nil
|
337
|
+
return nil
|
338
|
+
end
|
339
|
+
|
340
|
+
# Get array of block parameter names
|
341
|
+
block_params = block.parameters.map do |param|
|
342
|
+
param[1]
|
343
|
+
end
|
344
|
+
|
345
|
+
parser_local_vars = command_binding.local_variables + block_params
|
346
|
+
source = Parsing.parse_block(block, parser_local_vars)
|
347
|
+
@ast = AST::BlockDefNode.new(
|
348
|
+
parameters: block_params,
|
349
|
+
ruby_block: block, # necessary to get binding
|
350
|
+
body: AST::Builder.from_parser_ast(source))
|
351
|
+
end
|
93
352
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
ast.accept(lexical_vars_enumerator)
|
100
|
-
accessed_variables = lexical_vars_enumerator.lexical_variables
|
353
|
+
# Ensure `return` is there
|
354
|
+
@ast.accept(Translator::LastStatementReturnsVisitor.new)
|
355
|
+
|
356
|
+
return @ast
|
357
|
+
end
|
101
358
|
|
102
|
-
|
103
|
-
|
104
|
-
|
359
|
+
# Returns the binding of this command. It is used to retrieve lexical variables that
|
360
|
+
# are used inside this parallel section.
|
361
|
+
def command_binding
|
362
|
+
if @command_binding != nil
|
363
|
+
return @command_binding
|
364
|
+
elsif block != nil
|
365
|
+
return block.binding
|
366
|
+
else
|
367
|
+
return nil
|
105
368
|
end
|
369
|
+
end
|
106
370
|
|
107
|
-
|
371
|
+
# Returns a collection of lexical variables that are accessed within a parallel
|
372
|
+
# section.
|
373
|
+
# @return [Hash{Symbol => Object}]
|
374
|
+
def lexical_externals
|
375
|
+
if block_def_node != nil && command_binding != nil
|
376
|
+
all_lexical_vars = command_binding.local_variables
|
377
|
+
lexical_vars_enumerator = AST::LexicalVariablesEnumerator.new(all_lexical_vars)
|
378
|
+
block_def_node.accept(lexical_vars_enumerator)
|
379
|
+
accessed_variables = lexical_vars_enumerator.lexical_variables
|
380
|
+
|
381
|
+
result = Hash.new
|
382
|
+
for var_name in accessed_variables
|
383
|
+
result[var_name] = command_binding.local_variable_get(var_name)
|
384
|
+
end
|
385
|
+
|
386
|
+
return result
|
387
|
+
else
|
388
|
+
return {}
|
389
|
+
end
|
108
390
|
end
|
109
391
|
|
110
392
|
# Returns a collection of external objects that are accessed within a parallel section.
|
111
393
|
def externals
|
112
|
-
lexical_externals.keys
|
394
|
+
return lexical_externals.keys
|
113
395
|
end
|
114
396
|
|
115
|
-
|
397
|
+
def set_unique_id
|
398
|
+
# Generate unique ID
|
399
|
+
@unique_id = @@unique_id
|
400
|
+
@@unique_id += 1
|
401
|
+
end
|
116
402
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
403
|
+
def with_index(&block)
|
404
|
+
self.block = block
|
405
|
+
@input.push(SingleInput.new(
|
406
|
+
command: ArrayIndexCommand.new(dimensions: dimensions),
|
407
|
+
pattern: :tid))
|
408
|
+
return self
|
121
409
|
end
|
410
|
+
|
411
|
+
protected
|
412
|
+
|
413
|
+
attr_writer :block
|
122
414
|
end
|
123
415
|
|
124
|
-
class
|
416
|
+
class ArrayIndexCommand
|
125
417
|
include ArrayCommand
|
126
418
|
|
127
|
-
|
128
|
-
|
419
|
+
attr_reader :dimensions
|
420
|
+
attr_reader :size
|
129
421
|
|
130
|
-
|
131
|
-
|
422
|
+
def initialize(block_size: DEFAULT_BLOCK_SIZE, keep: false, dimensions: nil)
|
423
|
+
super(block_size: block_size, keep: keep)
|
424
|
+
|
425
|
+
@dimensions = dimensions
|
426
|
+
@size = dimensions.reduce(:*)
|
427
|
+
|
428
|
+
# No input
|
429
|
+
@input = []
|
430
|
+
end
|
431
|
+
|
432
|
+
def ==(other)
|
433
|
+
return super(other) && dimensions == other.dimensions && size == other.size
|
434
|
+
end
|
435
|
+
end
|
436
|
+
|
437
|
+
class ArrayCombineCommand
|
438
|
+
include ArrayCommand
|
439
|
+
|
440
|
+
def initialize(
|
441
|
+
target,
|
442
|
+
others,
|
443
|
+
block,
|
444
|
+
ast: nil,
|
445
|
+
block_size: DEFAULT_BLOCK_SIZE,
|
446
|
+
keep: false,
|
447
|
+
generator_node: nil,
|
448
|
+
with_index: false,
|
449
|
+
command_binding: nil)
|
450
|
+
|
451
|
+
super(block: block, block_ast: ast, block_size: block_size, keep: keep, generator_node: generator_node, command_binding: command_binding)
|
452
|
+
|
453
|
+
# Read array at position `tid`
|
454
|
+
@input = [SingleInput.new(command: target.to_command, pattern: :tid)] + others.map do |other|
|
455
|
+
SingleInput.new(command: other.to_command, pattern: :tid)
|
456
|
+
end
|
457
|
+
|
458
|
+
if with_index
|
459
|
+
@input.push(SingleInput.new(
|
460
|
+
command: ArrayIndexCommand.new(dimensions: dimensions),
|
461
|
+
pattern: :tid))
|
462
|
+
end
|
132
463
|
end
|
133
464
|
|
134
465
|
def size
|
135
|
-
|
466
|
+
return input.first.command.size
|
136
467
|
end
|
137
468
|
|
138
|
-
|
469
|
+
def ==(other)
|
470
|
+
return super(other) && size == other.size
|
471
|
+
end
|
472
|
+
end
|
139
473
|
|
140
|
-
|
474
|
+
class ArrayZipCommand
|
475
|
+
include ArrayCommand
|
476
|
+
|
477
|
+
def initialize(target, others, **options)
|
478
|
+
super(**options)
|
479
|
+
|
480
|
+
@input = [SingleInput.new(command: target.to_command, pattern: :tid)] + others.map do |other|
|
481
|
+
SingleInput.new(command: other.to_command, pattern: :tid)
|
482
|
+
end
|
483
|
+
end
|
484
|
+
|
485
|
+
def size
|
486
|
+
return input.first.command.size
|
487
|
+
end
|
488
|
+
|
489
|
+
def block_parameter_names
|
490
|
+
# Have to set block parameter names but names are never used
|
491
|
+
return [:irrelevant] * @input.size
|
492
|
+
end
|
493
|
+
|
494
|
+
def ==(other)
|
495
|
+
return super(other) && size == other.size
|
496
|
+
end
|
141
497
|
end
|
142
498
|
|
143
|
-
class
|
499
|
+
class ArrayReduceCommand
|
144
500
|
include ArrayCommand
|
145
|
-
|
146
|
-
attr_reader :target
|
147
501
|
|
148
|
-
def initialize(
|
149
|
-
|
502
|
+
def initialize(
|
503
|
+
target,
|
504
|
+
block,
|
505
|
+
block_size: DEFAULT_BLOCK_SIZE,
|
506
|
+
ast: nil,
|
507
|
+
generator_node: nil,
|
508
|
+
command_binding: nil)
|
150
509
|
|
151
|
-
|
152
|
-
|
510
|
+
super(block: block, block_ast: ast, block_size: block_size, keep: keep, generator_node: generator_node, command_binding: command_binding)
|
511
|
+
|
512
|
+
@input = [ReduceInput.new(command: target.to_command, pattern: :entire)]
|
513
|
+
end
|
514
|
+
|
515
|
+
def execute
|
516
|
+
if input.first.command.size == 0
|
517
|
+
@result = [nil]
|
518
|
+
elsif @input.first.command.size == 1
|
519
|
+
@result = [input.first.command[0]]
|
520
|
+
else
|
521
|
+
@result = super
|
522
|
+
end
|
153
523
|
end
|
154
524
|
|
155
525
|
def size
|
156
|
-
|
526
|
+
return 1
|
157
527
|
end
|
158
|
-
|
528
|
+
|
529
|
+
# Returns the number of elements in the input
|
530
|
+
def input_size
|
531
|
+
return input.first.command.size
|
532
|
+
end
|
533
|
+
|
534
|
+
def ==(other)
|
535
|
+
return super(other) && size == other.size
|
536
|
+
end
|
537
|
+
end
|
538
|
+
|
539
|
+
class ArrayStencilCommand
|
540
|
+
|
541
|
+
# This visitor executes the check_parents_index function on every local variable
|
542
|
+
# If the local variable is the "stencil array" then its indices will get modified/corrected for the 1D array access
|
543
|
+
class FlattenIndexNodeVisitor < AST::Visitor
|
544
|
+
|
545
|
+
attr_reader :offsets
|
546
|
+
attr_reader :name
|
547
|
+
attr_reader :command
|
548
|
+
|
549
|
+
def initialize(name, offsets, command)
|
550
|
+
@name = name
|
551
|
+
@offsets = offsets
|
552
|
+
@command = command
|
553
|
+
end
|
554
|
+
|
555
|
+
def visit_lvar_read_node(node)
|
556
|
+
super(node)
|
557
|
+
check_index(name, offsets, node)
|
558
|
+
end
|
559
|
+
|
560
|
+
def visit_lvar_write_node(node)
|
561
|
+
super(node)
|
562
|
+
check_index(name, offsets, node)
|
563
|
+
end
|
564
|
+
|
565
|
+
|
566
|
+
def check_index(name, offsets, node)
|
567
|
+
if node.identifier == name
|
568
|
+
# This is the array-variable used in the stencil
|
569
|
+
|
570
|
+
send_node = node
|
571
|
+
index_combination = []
|
572
|
+
is_literal = true
|
573
|
+
|
574
|
+
# Build the index off this access in index_combination
|
575
|
+
for i in 0..command.dimensions.size-1
|
576
|
+
send_node = send_node.parent
|
577
|
+
if not (send_node.is_a?(AST::SendNode) && send_node.selector == :[])
|
578
|
+
raise AssertionError.new(
|
579
|
+
"This has to be a SendNode and Array-selector")
|
580
|
+
end
|
581
|
+
index_combination[i] = send_node.arguments.first
|
582
|
+
if not index_combination[i].is_a?(AST::IntLiteralNode)
|
583
|
+
is_literal = false
|
584
|
+
end
|
585
|
+
end
|
586
|
+
|
587
|
+
if is_literal
|
588
|
+
# The index consists of only literals so we can translate it easily by mapping the index onto the offsets
|
589
|
+
|
590
|
+
index_combination = index_combination.map do |x|
|
591
|
+
x.value
|
592
|
+
end
|
593
|
+
|
594
|
+
replacement = AST::IntLiteralNode.new(
|
595
|
+
value: offsets[index_combination])
|
596
|
+
else
|
597
|
+
# This handles the case where non-literals have to be translated with the Ternary Node
|
598
|
+
|
599
|
+
offset_arr = offsets.to_a
|
600
|
+
replacement = AST::IntLiteralNode.new(value: offset_arr[0][1])
|
601
|
+
for i in 1..offset_arr.size-1
|
602
|
+
# Build combination of ternary nodes
|
603
|
+
|
604
|
+
ternary_build = AST::SendNode.new(receiver: AST::IntLiteralNode.new(value: offset_arr[i][0][0]), selector: :==, arguments: [index_combination[0]])
|
605
|
+
for j in 1..index_combination.size-1
|
606
|
+
|
607
|
+
next_eq = AST::SendNode.new(receiver: AST::IntLiteralNode.new(value: offset_arr[i][0][j]), selector: :==, arguments: [index_combination[j]])
|
608
|
+
ternary_build = AST::SendNode.new(receiver: next_eq, selector: :"&&", arguments: [ternary_build])
|
609
|
+
end
|
610
|
+
replacement = AST::TernaryNode.new(condition: ternary_build, true_val: AST::IntLiteralNode.new(value: offset_arr[i][1]), false_val: replacement)
|
611
|
+
end
|
612
|
+
end
|
613
|
+
|
614
|
+
#Replace outer array access with new 1D array access
|
615
|
+
|
616
|
+
send_node.replace(AST::SendNode.new(receiver: node, selector: :[], arguments: [replacement]))
|
617
|
+
end
|
618
|
+
end
|
619
|
+
end
|
620
|
+
|
621
|
+
include ArrayCommand
|
622
|
+
|
623
|
+
attr_reader :offsets
|
624
|
+
attr_reader :out_of_range_value
|
625
|
+
attr_reader :use_parameter_array
|
626
|
+
|
627
|
+
def initialize(
|
628
|
+
target,
|
629
|
+
offsets,
|
630
|
+
out_of_range_value,
|
631
|
+
block,
|
632
|
+
ast: nil,
|
633
|
+
block_size: DEFAULT_BLOCK_SIZE,
|
634
|
+
keep: false,
|
635
|
+
use_parameter_array: true,
|
636
|
+
generator_node: nil,
|
637
|
+
with_index: false,
|
638
|
+
command_binding: nil)
|
639
|
+
|
640
|
+
super(block: block, block_ast: ast, block_size: block_size, keep: keep, generator_node: generator_node, command_binding: command_binding)
|
641
|
+
|
642
|
+
if offsets.first == "G"
|
643
|
+
# A stencil will be generated
|
644
|
+
dims = target.to_command.dimensions.size
|
645
|
+
|
646
|
+
directions = offsets[1]
|
647
|
+
# Directions says how many of the dimensions can be used in the stencil. E.g.: in 2D directions = 1 would relate in a stencil that only has up, down, left, right offsets, but no diagonals
|
648
|
+
distance = offsets[2]
|
649
|
+
# Distance says how many steps can be made into the directions distance = 2 in the example before would mean 1 or 2 up/down/left/right
|
650
|
+
|
651
|
+
if directions > dims
|
652
|
+
raise ArgumentError.new(
|
653
|
+
"Directions should not be higher than the number of dimensions")
|
654
|
+
end
|
655
|
+
|
656
|
+
singles = [0]
|
657
|
+
# Building the numbers that can be part of an offset
|
658
|
+
for i in 1..distance
|
659
|
+
singles = singles + [i] + [-i]
|
660
|
+
end
|
661
|
+
|
662
|
+
offsets = []
|
663
|
+
|
664
|
+
# Iterate all possibilities
|
665
|
+
for i in 0..singles.size**dims-1
|
666
|
+
# Transform current permutation to according string / base representation
|
667
|
+
base = i.to_s(singles.size)
|
668
|
+
|
669
|
+
# Fill up zeroes
|
670
|
+
sizedif = (singles.size**dims-1).to_s(singles.size).size - base.size
|
671
|
+
base = "0" * sizedif + base
|
672
|
+
|
673
|
+
# Check whether offset is allowed (concerning directions)
|
674
|
+
if base.gsub(/[^0]/, "").size >= dims - directions
|
675
|
+
new_offset = []
|
676
|
+
for j in 0..dims-1
|
677
|
+
new_offset.push(singles[base[j].to_i])
|
678
|
+
end
|
679
|
+
offsets.push(new_offset)
|
680
|
+
end
|
681
|
+
end
|
682
|
+
end
|
683
|
+
|
684
|
+
if not offsets.first.is_a?(Array)
|
685
|
+
offsets = offsets.map do |offset|
|
686
|
+
[offset]
|
687
|
+
end
|
688
|
+
end
|
689
|
+
|
690
|
+
# Read more than just one element, fall back to `:entire` for now
|
691
|
+
|
692
|
+
@out_of_range_value = out_of_range_value
|
693
|
+
@use_parameter_array = use_parameter_array
|
694
|
+
|
695
|
+
if use_parameter_array
|
696
|
+
@input = [StencilArrayInput.new(
|
697
|
+
command: target.to_command,
|
698
|
+
pattern: :entire,
|
699
|
+
offsets: offsets,
|
700
|
+
out_of_bounds_value: out_of_range_value)]
|
701
|
+
else
|
702
|
+
@input = [StencilSingleInput.new(
|
703
|
+
command: target.to_command,
|
704
|
+
pattern: :entire,
|
705
|
+
offsets: offsets,
|
706
|
+
out_of_bounds_value: out_of_range_value)]
|
707
|
+
end
|
708
|
+
|
709
|
+
if with_index
|
710
|
+
@input.push(SingleInput.new(
|
711
|
+
command: ArrayIndexCommand.new(dimensions: dimensions),
|
712
|
+
pattern: :tid))
|
713
|
+
end
|
714
|
+
|
715
|
+
# Offsets should be arrays
|
716
|
+
for offset in offsets
|
717
|
+
if !offset.is_a?(Array)
|
718
|
+
raise ArgumentError.new("Array expected but #{offset.class} found")
|
719
|
+
end
|
720
|
+
|
721
|
+
if offset.size != dimensions.size
|
722
|
+
raise ArgumentError.new("#{dimensions.size} indices expected")
|
723
|
+
end
|
724
|
+
end
|
725
|
+
|
726
|
+
@offsets = offsets
|
727
|
+
|
728
|
+
# Translate relative indices to 1D-indicies starting by 0
|
729
|
+
if block_def_node != nil
|
730
|
+
if use_parameter_array
|
731
|
+
offsets_mapped = Hash.new
|
732
|
+
for i in 0..offsets.size-1
|
733
|
+
offsets_mapped[offsets[i]] = i
|
734
|
+
end
|
735
|
+
|
736
|
+
# Do not modify the original AST
|
737
|
+
@ast = block_def_node.clone
|
738
|
+
@ast.accept(FlattenIndexNodeVisitor.new(
|
739
|
+
block_parameter_names.first, offsets_mapped, self))
|
740
|
+
end
|
741
|
+
end
|
742
|
+
end
|
743
|
+
|
744
|
+
def ==(other)
|
745
|
+
return super(other) && offsets == other.offsets &&
|
746
|
+
out_of_range_value == other.out_of_range_value &&
|
747
|
+
use_parameter_array == other.use_parameter_array
|
748
|
+
end
|
749
|
+
|
750
|
+
def size
|
751
|
+
return input.first.command.size
|
752
|
+
end
|
753
|
+
|
754
|
+
def min_offset
|
755
|
+
return offsets.min
|
756
|
+
end
|
757
|
+
|
758
|
+
def max_offset
|
759
|
+
return offsets.max
|
760
|
+
end
|
761
|
+
|
159
762
|
protected
|
160
763
|
|
161
|
-
|
764
|
+
def block=(block)
|
765
|
+
super
|
766
|
+
|
767
|
+
if use_parameter_array
|
768
|
+
offsets_mapped = Hash.new
|
769
|
+
for i in 0..offsets.size-1
|
770
|
+
offsets_mapped[offsets[i]] = i
|
771
|
+
end
|
772
|
+
|
773
|
+
# Do not modify the original AST
|
774
|
+
@ast = block_def_node.clone
|
775
|
+
@ast.accept(FlattenIndexNodeVisitor.new(
|
776
|
+
block_parameter_names.first, offsets_mapped, self))
|
777
|
+
end
|
778
|
+
end
|
162
779
|
end
|
163
780
|
|
164
781
|
class ArraySelectCommand
|
165
782
|
include ArrayCommand
|
166
783
|
|
167
|
-
attr_reader :target
|
168
|
-
|
169
784
|
def initialize(target, block)
|
170
|
-
super
|
785
|
+
super()
|
171
786
|
|
172
|
-
@target = target
|
173
787
|
@block = block
|
788
|
+
|
789
|
+
# One element per thread
|
790
|
+
@input = [SingleInput.new(command: target.to_command, pattern: :tid)]
|
174
791
|
end
|
175
792
|
|
176
793
|
# how to implement SELECT?
|
@@ -182,67 +799,126 @@ module Ikra
|
|
182
799
|
|
183
800
|
attr_reader :target
|
184
801
|
|
185
|
-
Block = Proc.new do |element|
|
186
|
-
element
|
187
|
-
end
|
188
|
-
|
189
802
|
@@unique_id = 1
|
190
803
|
|
191
|
-
def initialize(target)
|
192
|
-
super()
|
193
|
-
|
194
|
-
@target = target
|
804
|
+
def initialize(target, block_size: DEFAULT_BLOCK_SIZE, dimensions: nil)
|
805
|
+
super(block_size: block_size)
|
195
806
|
|
196
807
|
# Ensure that base array cannot be modified
|
197
808
|
target.freeze
|
809
|
+
|
810
|
+
# One thread per array element
|
811
|
+
@target = target
|
812
|
+
@input = [SingleInput.new(command: target, pattern: :tid)]
|
813
|
+
|
814
|
+
@dimensions = dimensions
|
198
815
|
end
|
199
|
-
|
816
|
+
|
200
817
|
def execute
|
201
|
-
|
818
|
+
return input.first.command
|
202
819
|
end
|
203
820
|
|
204
821
|
def size
|
205
|
-
|
822
|
+
return input.first.command.size
|
823
|
+
end
|
824
|
+
|
825
|
+
def dimensions
|
826
|
+
if @dimensions == nil
|
827
|
+
return [size]
|
828
|
+
else
|
829
|
+
return @dimensions
|
830
|
+
end
|
206
831
|
end
|
207
832
|
|
208
|
-
# Returns a collection of external objects that are accessed within a parallel
|
833
|
+
# Returns a collection of external objects that are accessed within a parallel
|
834
|
+
# section. This includes all elements of the base array.
|
209
835
|
def externals
|
210
|
-
lexical_externals.keys +
|
836
|
+
lexical_externals.keys + input.first.command
|
211
837
|
end
|
212
838
|
|
213
839
|
def base_type
|
214
|
-
# TODO: add caching (
|
840
|
+
# TODO: add caching (`input` is frozen)
|
215
841
|
type = Types::UnionType.new
|
216
842
|
|
217
|
-
|
218
|
-
type.
|
843
|
+
input.first.command.each do |element|
|
844
|
+
type.add(element.class.to_ikra_type)
|
219
845
|
end
|
220
846
|
|
221
|
-
type
|
222
|
-
end
|
223
|
-
|
224
|
-
protected
|
225
|
-
|
226
|
-
def block
|
227
|
-
Block
|
847
|
+
return type
|
228
848
|
end
|
229
849
|
end
|
230
850
|
end
|
231
851
|
end
|
232
852
|
|
233
853
|
class Array
|
854
|
+
include Ikra::Symbolic::ParallelOperations
|
855
|
+
|
234
856
|
class << self
|
235
|
-
def pnew(size, &block)
|
236
|
-
|
857
|
+
def pnew(size = nil, **options, &block)
|
858
|
+
if size != nil
|
859
|
+
dimensions = [size]
|
860
|
+
else
|
861
|
+
dimensions = options[:dimensions]
|
862
|
+
end
|
863
|
+
|
864
|
+
map_options = options.dup
|
865
|
+
map_options.delete(:dimensions)
|
866
|
+
|
867
|
+
return Ikra::Symbolic::ArrayIndexCommand.new(
|
868
|
+
dimensions: dimensions, block_size: options[:block_size]).pmap(**map_options, &block)
|
237
869
|
end
|
238
870
|
end
|
239
871
|
|
240
|
-
|
241
|
-
|
872
|
+
# Have to keep the old methods around because sometimes we want to have the original code
|
873
|
+
alias_method :old_plus, :+
|
874
|
+
alias_method :old_minus, :-
|
875
|
+
alias_method :old_mul, :*
|
876
|
+
alias_method :old_or, :|
|
877
|
+
alias_method :old_and, :&
|
878
|
+
|
879
|
+
def +(other)
|
880
|
+
if other.is_a?(Ikra::Symbolic::ArrayCommand)
|
881
|
+
super(other)
|
882
|
+
else
|
883
|
+
return self.old_plus(other)
|
884
|
+
end
|
885
|
+
end
|
886
|
+
|
887
|
+
def -(other)
|
888
|
+
if other.is_a?(Ikra::Symbolic::ArrayCommand)
|
889
|
+
super(other)
|
890
|
+
else
|
891
|
+
return self.old_minus(other)
|
892
|
+
end
|
242
893
|
end
|
243
894
|
|
244
|
-
def
|
245
|
-
Ikra::Symbolic::
|
895
|
+
def *(other)
|
896
|
+
if other.is_a?(Ikra::Symbolic::ArrayCommand)
|
897
|
+
super(other)
|
898
|
+
else
|
899
|
+
return self.old_mul(other)
|
900
|
+
end
|
901
|
+
end
|
902
|
+
|
903
|
+
def |(other)
|
904
|
+
if other.is_a?(Ikra::Symbolic::ArrayCommand)
|
905
|
+
super(other)
|
906
|
+
else
|
907
|
+
return self.old_or(other)
|
908
|
+
end
|
909
|
+
end
|
910
|
+
|
911
|
+
def &(other)
|
912
|
+
if other.is_a?(Ikra::Symbolic::ArrayCommand)
|
913
|
+
super(other)
|
914
|
+
else
|
915
|
+
return self.old_and(other)
|
916
|
+
end
|
917
|
+
end
|
918
|
+
|
919
|
+
def to_command(dimensions: nil)
|
920
|
+
return Ikra::Symbolic::ArrayIdentityCommand.new(self, dimensions: dimensions)
|
246
921
|
end
|
247
922
|
end
|
248
923
|
|
924
|
+
require_relative "host_section"
|