ikra 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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"
|