BOAST 1.3.5 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/BOAST.gemspec +1 -1
  3. data/LICENSE +13 -1
  4. data/README.md +62 -13
  5. data/lib/BOAST.rb +3 -1
  6. data/lib/BOAST/Language/ARMCPUID_by_name.rb +3752 -0
  7. data/lib/BOAST/Language/Algorithm.rb +4 -24
  8. data/lib/BOAST/Language/Architectures.rb +5 -0
  9. data/lib/BOAST/Language/Arithmetic.rb +38 -5
  10. data/lib/BOAST/Language/BOAST_OpenCL.rb +7 -8
  11. data/lib/BOAST/Language/Case.rb +10 -3
  12. data/lib/BOAST/Language/Config.rb +36 -12
  13. data/lib/BOAST/Language/ControlStructure.rb +7 -3
  14. data/lib/BOAST/Language/DataTypes.rb +6 -0
  15. data/lib/BOAST/Language/Expression.rb +26 -2
  16. data/lib/BOAST/Language/For.rb +59 -30
  17. data/lib/BOAST/Language/FuncCall.rb +9 -5
  18. data/lib/BOAST/Language/Functors.rb +1 -1
  19. data/lib/BOAST/Language/HighLevelOperators.rb +172 -0
  20. data/lib/BOAST/Language/If.rb +25 -9
  21. data/lib/BOAST/Language/Index.rb +5 -5
  22. data/lib/BOAST/Language/Intrinsics.rb +40 -27
  23. data/lib/BOAST/Language/OpenMP.rb +1 -0
  24. data/lib/BOAST/Language/Operators.rb +221 -34
  25. data/lib/BOAST/Language/Parens.rb +3 -2
  26. data/lib/BOAST/Language/Procedure.rb +18 -5
  27. data/lib/BOAST/Language/Slice.rb +176 -44
  28. data/lib/BOAST/Language/Variable.rb +99 -56
  29. data/lib/BOAST/Language/While.rb +18 -3
  30. data/lib/BOAST/Language/{CPUID_by_name.rb → X86CPUID_by_name.rb} +0 -0
  31. data/lib/BOAST/Optimization/Optimization.rb +2 -0
  32. data/lib/BOAST/Runtime/AffinityProbe.rb +7 -3
  33. data/lib/BOAST/Runtime/CKernel.rb +3 -0
  34. data/lib/BOAST/Runtime/CRuntime.rb +4 -0
  35. data/lib/BOAST/Runtime/CompiledRuntime.rb +404 -77
  36. data/lib/BOAST/Runtime/Compilers.rb +44 -18
  37. data/lib/BOAST/Runtime/Config.rb +9 -0
  38. data/lib/BOAST/Runtime/EnergyProbe.rb +19 -3
  39. data/lib/BOAST/Runtime/FFIRuntime.rb +23 -0
  40. data/lib/BOAST/Runtime/FORTRANRuntime.rb +1 -1
  41. data/lib/BOAST/Runtime/MAQAO.rb +29 -0
  42. data/lib/BOAST/Runtime/NonRegression.rb +64 -3
  43. data/lib/BOAST/Runtime/OpenCLRuntime.rb +16 -6
  44. data/lib/BOAST/Runtime/Probe.rb +21 -1
  45. metadata +5 -3
@@ -6,12 +6,13 @@ module BOAST
6
6
 
7
7
  def register_funccall(name, options = {})
8
8
  sym = name.to_sym
9
+ ret = options[:return] ? options[:return] : options[:returns]
9
10
  FUNCCALLS[sym] = {}
10
11
  FUNCCALLS[sym][:parameters] = options[:parameters]
11
- FUNCCALLS[sym][:returns] = options[:returns]
12
+ FUNCCALLS[sym][:return] = ret
12
13
  s =<<EOF
13
14
  def self.#{name}(*args)
14
- return FuncCall(#{sym.inspect}, *args#{options[:returns] ? ", returns: FUNCCALLS[#{sym.inspect}][:returns]" : ""})
15
+ return FuncCall(#{sym.inspect}, *args#{ ret ? ", return: FUNCCALLS[#{sym.inspect}][:return]" : ""})
15
16
  end
16
17
  EOF
17
18
  eval s
@@ -20,7 +20,8 @@ module BOAST
20
20
  # @param [Hash] properties set of named properties for the Procedure.
21
21
  # @option properties [Array<Variables>] :constants list of constant variables that are used in the Procedure. (see parameter in Fortran).
22
22
  # @option properties [Array<#to_s>] :headers list of headers that need to be included in order to compile the Procedure
23
- # @option propertirs [Variable] :return a Variable that will be returned. Procedure becomes a function, return type is the same as the returned variable. The variable will be declared at the start of the procedure.
23
+ # @option properties [Variable] :return a Variable that will be returned. Procedure becomes a function, return type is the same as the returned variable. The variable will be declared at the start of the procedure.
24
+ # @option properties [Procedure] :functions sub functions used by this Procedure (FORTRAN return type of functions are problematic)
24
25
  def initialize(name, parameters=[], properties={}, &block)
25
26
  @name = name
26
27
  @parameters = parameters
@@ -42,8 +43,8 @@ module BOAST
42
43
 
43
44
  def call(*parameters)
44
45
  prefix = ""
45
- prefix += "call " if lang==FORTRAN
46
- f = FuncCall::new(@name, *parameters)
46
+ prefix += "call " if lang==FORTRAN and @properties[:return].nil?
47
+ f = FuncCall::new(@name, *parameters, :return => @properties[:return] )
47
48
  f.prefix = prefix
48
49
  return f
49
50
  end
@@ -54,9 +55,9 @@ module BOAST
54
55
  end
55
56
 
56
57
  # Returns a {CKernel} with the Procedure as entry point.
57
- def ckernel
58
+ def ckernel(* args)
58
59
  old_output = output
59
- k = CKernel::new
60
+ k = CKernel::new(* args)
60
61
  k.procedure = self
61
62
  self.pr
62
63
  set_output( old_output )
@@ -87,6 +88,13 @@ module BOAST
87
88
  return to_s_fortran if lang==FORTRAN
88
89
  end
89
90
 
91
+ protected
92
+
93
+ def fortran_type
94
+ raise "No return type for procedure!" unless @properties[:return]
95
+ output.puts indent + "#{@properties[:return].type.decl} :: #{@name}"
96
+ end
97
+
90
98
  private
91
99
 
92
100
  def decl_fortran
@@ -209,6 +217,11 @@ module BOAST
209
217
  align = p.align
210
218
  BOAST::pr align if align
211
219
  }
220
+ if @properties[:functions] then
221
+ @properties[:functions].each { |f|
222
+ f.fortran_type
223
+ }
224
+ end
212
225
  if @properties[:return] then
213
226
  BOAST::decl @properties[:return]
214
227
  end
@@ -1,16 +1,123 @@
1
1
  module BOAST
2
2
 
3
- class Slice
4
- include PrivateStateAccessor
5
- include Inspectable
3
+ class Slice < Expression
4
+ class SliceItem
5
+ include PrivateStateAccessor
6
+ include Inspectable
7
+
8
+ attr_reader :first
9
+ attr_reader :last
10
+ attr_reader :step
11
+ attr_reader :length
12
+
13
+ def all?
14
+ @first.nil?
15
+ end
16
+
17
+ def scalar?
18
+ not all? and @last.nil?
19
+ end
20
+
21
+ def initialize(slice)
22
+ @first = nil
23
+ @last = nil
24
+ @step = nil
25
+ if slice.kind_of?(SliceItem) then
26
+ copy_slice!(slice)
27
+ elsif slice.kind_of?(Range) then
28
+ @first = slice.first
29
+ @last = slice.last
30
+ @last = Expression::new(Subtraction, @last, 1) if slice.exclude_end?
31
+ @length = Expression::new(Subtraction, @last, @first)
32
+ @length = @length + 1
33
+ elsif slice.kind_of?(Array) then
34
+ @first = slice [0] if slice.length > 0
35
+ @last = slice [1] if slice.length > 1
36
+ @step = slice [2] if slice.length > 2
37
+ @length = Expression::new(Subtraction, @last, @first)
38
+ @length = @length / @step if @step
39
+ @length = @length + 1
40
+ elsif slice.kind_of?(Symbol) then
41
+ raise "Invalid Slice item: #{slice.inspect}!" if slice != :all
42
+ else
43
+ @first = slice
44
+ end
45
+ end
46
+
47
+ def copy_slice!(slice)
48
+ @first = slice.first
49
+ @last = slice.last
50
+ @step = slice.step
51
+ @length = slice.length
52
+ self
53
+ end
54
+
55
+ def recurse!(s, d)
56
+ if all? then
57
+ copy_slice!(s)
58
+ else
59
+ @first = Expression::new(Subtraction, @first, get_array_start)
60
+ @first = @first * s.step if s.step
61
+ if s.all? then
62
+ @first = Expression::new(Addition, d.start, @first )
63
+ else
64
+ @first = Expression::new(Addition, s.first, @first )
65
+ end
66
+ if not scalar? then
67
+ if s.step then
68
+ if @step then
69
+ @step = Expression::new(Multiplication, @step, s.step)
70
+ else
71
+ @step = s.step
72
+ end
73
+ end
74
+ @last = @first + (@length-1)*@step
75
+ end
76
+ end
77
+ return self
78
+ end
79
+
80
+ def to_a
81
+ a = []
82
+ a.push @first if @first
83
+ a.push @last if @last
84
+ a.push @step if @step
85
+ return a
86
+ end
87
+
88
+ end
89
+
6
90
  attr_reader :source
7
91
  attr_reader :slices
92
+ attr_accessor :alignment
8
93
 
9
94
  def initialize(source, *slices)
10
95
  raise "Cannot slice a non array Variable!" if not source.dimension?
11
96
  raise "Invalid slice!" if slices.length != source.dimension.length
12
97
  @source = source
13
- @slices = slices
98
+ @slices = slices.collect{ |s| SliceItem::new(s) }
99
+ end
100
+
101
+ def dimension?
102
+ true
103
+ end
104
+
105
+ def dimension
106
+ dims = []
107
+ slices.each_with_index { |slice, i|
108
+ if not slice.scalar? then
109
+ if slice.all? then
110
+ if source.dimension[i].size then
111
+ dims.push Dimension::new( source.dimension[i].size )
112
+ else
113
+ dims.push Dimension::new
114
+ end
115
+ else
116
+ dims.push Dimension::new( slice.length )
117
+ end
118
+ end
119
+ }
120
+ return dims
14
121
  end
15
122
 
16
123
  def to_s
@@ -27,60 +134,85 @@ module BOAST
27
134
  return self
28
135
  end
29
136
 
137
+ def align?
138
+ return !!@alignment
139
+ end
140
+
141
+ def set_align(align)
142
+ @alignment = align
143
+ return self
144
+ end
145
+
146
+ def to_var
147
+ var = @source.copy("#{self}", :const => nil, :constant => nil, :dim => nil, :dimension => nil, :direction => nil, :dir => nil, :align => alignment)
148
+ return var
149
+ end
150
+
151
+ # Indexes a {Slice}
152
+ # @param [Array{#to_s, Range, [first, last, step], :all, nil}] args one entry for each {SliceItem} of the {Slice}.
153
+ # * Range: if an index is a Range, the result will be a {Slice}. The Range can be exclusive. The first and last item of the Range will be considered first and last index in the corresponding {SliceItem}.
154
+ # * [first, last, step]: if an index is an Array, the result will be a {Slice}. The first and last item of the array will be considered first and last index in the corresponding {SliceItem}. If a step is given the range will be iterated by step.
155
+ # * :all, nil: The whole corresponding {SliceItem} will be used for the slice.
156
+ # * #to_s: If an index is none of the above it will be considered a scalar index. If all indexes are scalar an {Index} will be returned.
157
+ # @return [Slice, Index]
158
+ def [](*args)
159
+ slice = false
160
+ args.each { |a|
161
+ slice = true if a.kind_of?(Range) or a.kind_of?(Array) or a.kind_of?(Symbol) or a.nil?
162
+ }
163
+ new_args = []
164
+ slices.each_with_index { |s, i|
165
+ if not s.scalar?
166
+ raise "Invalid slice!" if args.length == 0
167
+ new_arg = SliceItem::new(args.shift)
168
+ new_arg.recurse!(s, @source.dimension[i])
169
+ new_args.push new_arg
170
+ else
171
+ new_args.push s
172
+ end
173
+ }
174
+ if slice then
175
+ return Slice::new(@source, *new_args)
176
+ else
177
+ return Index::new(@source, *(new_args.collect(&:first)))
178
+ end
179
+ end
180
+
30
181
  private
31
182
 
32
183
  def to_s_c
33
- s = "#{@source}["
34
184
  dims = @source.dimension.reverse
35
- slices = @slices.reverse
36
- slices_to_c = []
37
- slices.each_index { |indx|
38
- slice = slices[indx]
39
- if slice.kind_of?(Array) then
40
- if slice.length == 0 then
41
- slices_to_c.push(":")
42
- elsif slice.length == 1 then
43
- slices_to_c.push("#{Expression::new(Substraction, slice[0], dims[indx].start)}")
44
- else
45
- start, finish, step = slice
46
- start_c = Expression::new(Substraction, start, dims[indx].start)
47
- length = Expression::new(Substraction, finish, start) + 1
48
- slices_to_c.push("#{start_c}:#{length}")
49
- end
50
- elsif slice.kind_of?(Range) then
51
- start = slice.first
52
- finish = slice.last
53
- start_c = Expression::new(Substraction, start, dims[indx].start)
54
- length = Expression::new(Substraction, finish, start)
55
- length = length + 1 unless slice.exclude_end?
56
- slices_to_c.push("#{start_c}:#{length}")
57
- elsif slice then
58
- slices_to_c.push("#{Expression::new(Substraction, slice, dims[indx].start)}")
185
+ slices_to_c = @slices.reverse.each_with_index.collect { |slice, indx|
186
+ if slice.all? then
187
+ ":"
59
188
  else
60
- slices_to_c.push(":")
189
+ start = Expression::new(Subtraction, slice.first, dims[indx].start)
190
+ s = "#{start}"
191
+ if not slice.scalar? then
192
+ s += ":#{slice.length}"
193
+ # s += ":#{slice.step}" if slice.step
194
+ raise "Slice don't support step in C!" if slice.step
195
+ end
196
+ s
61
197
  end
62
198
  }
63
- return s + slices_to_c.join("][") + "]"
199
+ return "#{@source}[#{slices_to_c.join("][")}]"
64
200
  end
65
201
 
66
202
  def to_s_fortran
67
203
  slices_to_fortran = @slices.collect { |slice|
68
- if slice then
69
- if slice.kind_of?(Range) then
70
- "#{slice.first}:#{slice.last}#{slice.exclude_end? ? " - 1" : "" }"
71
- else
72
- sl = [slice].flatten
73
- if sl.length > 0 then
74
- sl.join(":")
75
- else
76
- ":"
77
- end
78
- end
79
- else
204
+ if slice.all? then
80
205
  ":"
206
+ else
207
+ s = "#{slice.first}"
208
+ if not slice.scalar? then
209
+ s += ":#{slice.last}"
210
+ s += ":#{slice.step}" if slice.step
211
+ end
212
+ s
81
213
  end
82
214
  }
83
- return "#{source}(#{slices_to_fortran.join(",")})"
215
+ return "#{@source}(#{slices_to_fortran.join(", ")})"
84
216
  end
85
217
 
86
218
  end
@@ -26,7 +26,7 @@ module BOAST
26
26
  begin
27
27
  @size = v2-v1+1
28
28
  rescue
29
- @size = Expression::new(Substraction, v2, v1) + 1
29
+ @size = Expression::new(Subtraction, v2, v1) + 1
30
30
  end
31
31
  else
32
32
  @size = v1
@@ -149,21 +149,22 @@ module BOAST
149
149
  include Annotation
150
150
  ANNOTATIONS = [ :name, :type, :dimension ]
151
151
 
152
- alias_method :orig_method_missing, :method_missing
153
-
154
152
  def method_missing(m, *a, &b)
155
153
  if @type.methods.include?(:members) and @type.members[m.to_s] then
156
154
  return struct_reference(type.members[m.to_s])
157
- elsif @type.methods.include?(:vector_length) and @type.vector_length > 1 and m.to_s[0] == 's' and lang == CL then
155
+ elsif __vector? and m.to_s[0] == 's' and lang != CUDA then
158
156
  required_set = m.to_s[1..-1].chars.to_a
159
157
  existing_set = [*('0'..'9'),*('a'..'z')].first(@type.vector_length)
160
158
  if required_set.length == required_set.uniq.length and (required_set - existing_set).empty? then
161
- return copy(name+"."+m.to_s, :vector_length => m.to_s[1..-1].length)
159
+ return copy(name+"."+m.to_s, :vector_length => m.to_s[1..-1].length) if lang == CL
160
+ return copy("#{name}(#{existing_set.index(required_set[0])+1})", :vector_length => 1) if lang == FORTRAN
161
+ return copy("#{name}[#{existing_set.index(required_set[0])}]", :vector_length => 1) if lang == C
162
+ super
162
163
  else
163
- return orig_method_missing(m, *a, &b)
164
+ super
164
165
  end
165
166
  else
166
- return orig_method_missing(m, *a, &b)
167
+ super
167
168
  end
168
169
  end
169
170
 
@@ -180,60 +181,69 @@ module BOAST
180
181
  attr_reader :deferred_shape
181
182
  attr_reader :optional
182
183
  attr_accessor :reference
183
- attr_accessor :alignment
184
+ attr_writer :alignment
184
185
  attr_accessor :replace_constant
185
186
  attr_accessor :force_replace_constant
186
187
 
188
+ def alignment
189
+ return @type.total_size if __vector? and lang == FORTRAN and not @alignment
190
+ return @alignment
191
+ end
192
+
187
193
  def constant?
188
- !!@constant
194
+ @constant
189
195
  end
190
196
 
191
197
  def allocate?
192
- !!@allocate
198
+ @allocate
193
199
  end
194
200
 
195
201
  def texture?
196
- !!@texture
202
+ @texture
197
203
  end
198
204
 
199
205
  def local?
200
- !!@local
206
+ @local
201
207
  end
202
208
 
203
209
  def restrict?
204
- !!@restrict
210
+ @restrict
205
211
  end
206
212
 
207
213
  def replace_constant?
208
- !!@replace_constant
214
+ @replace_constant
209
215
  end
210
216
 
211
217
  def force_replace_constant?
212
- !!@force_replace_constant
218
+ @force_replace_constant
213
219
  end
214
220
 
215
221
  def dimension?
216
- !!@dimension
222
+ @dimension
217
223
  end
218
224
 
219
225
  def scalar_output?
220
- !!@scalar_output
226
+ @scalar_output
221
227
  end
222
228
 
223
229
  def optional?
224
- !!@optional
230
+ @optional
225
231
  end
226
232
 
227
233
  def align?
228
- !!@alignment
234
+ alignment
229
235
  end
230
236
 
231
237
  def deferred_shape?
232
- !!@deferred_shape
238
+ @deferred_shape
233
239
  end
234
240
 
235
241
  def reference?
236
- !!@reference
242
+ @reference
243
+ end
244
+
245
+ def vector?
246
+ __vector?
237
247
  end
238
248
 
239
249
  # Creates a new {Variable}
@@ -248,16 +258,24 @@ module BOAST
248
258
  # @option properties [Symbol] :allocate specify that the variable is to be allocated and where. Can only be *:heap* or *:stack* for now.
249
259
  # @option properties [Boolean] :local indicates that the variable is to be allocated on the __local space of OpenCL devices or __shared__ space of CUDA devices. In C or FORTRAN this has the same effect as *:allocate* => *:stack*.
250
260
  # @option properties [Boolean] :texture for OpenCL and CUDA. In OpenCL also specifies that a sampler has to be generated to access the array variable.
251
- # @option properties [Integer] :align specifies the alignment the variable will be declared/allocated with if allocated or is supposed to have if it is coming from another context.
261
+ # @option properties [Integer] :align specifies the alignment the variable will be declared/allocated with if allocated or is supposed to have if it is coming from another context (in bytes).
252
262
  # @option properties [Boolean] :replace_constant specifies that for scalar constants this variable should be replaced by its constant value. For constant arrays, the value of the array will be replaced if the index can be determined at evaluation.
253
263
  # @option properties [Boolean] :deferred_shape for Fortran interface generation mainly see Fortran documentation
254
264
  # @option properties [Boolean] :optional for Fortran interface generation mainly see Fortran documentation
255
265
  def initialize(name, type, properties={})
256
266
  @name = name.to_s
257
- @direction = properties[:direction] ? properties[:direction] : properties[:dir]
258
- @constant = properties[:constant] ? properties[:constant] : properties[:const]
259
- @dimension = properties[:dimension] ? properties[:dimension] : properties[:dim]
260
- @local = properties[:local] ? properties[:local] : properties[:shared]
267
+ @direction = properties[:direction]
268
+ @direction = properties[:dir] unless @direction
269
+
270
+ @constant = properties[:constant]
271
+ @constant = properties[:const] unless @constant
272
+
273
+ @dimension = properties[:dimension]
274
+ @dimension = properties[:dim] unless @dimension
275
+
276
+ @local = properties[:local]
277
+ @local = properties[:shared] unless @local
278
+
261
279
  @texture = properties[:texture]
262
280
  @allocate = properties[:allocate]
263
281
  @restrict = properties[:restrict]
@@ -266,24 +284,23 @@ module BOAST
266
284
  @optional = properties[:optional]
267
285
  @reference = properties[:reference]
268
286
  @force_replace_constant = false
269
- if not properties[:replace_constant].nil? then
270
- @replace_constant = properties[:replace_constant]
271
- else
272
- @replace_constant = true
273
- end
287
+ @replace_constant = properties[:replace_constant]
288
+
274
289
  if @texture and lang == CL then
275
290
  @sampler = Variable::new("sampler_#{name}", CustomType,:type_name => "sampler_t" ,:replace_constant => false, :constant => "CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_NONE | CLK_FILTER_NEAREST")
276
291
  else
277
292
  @sampler = nil
278
293
  end
279
- @type = type::new(properties)
280
- @properties = properties
281
- if (@direction == :out or @direction == :inout) and not dimension? then
282
- @scalar_output = true
294
+
295
+ @scalar_output = false
296
+ if @dimension then
297
+ @dimension = [@dimension].flatten
283
298
  else
284
- @scalar_output = false
299
+ @scalar_output = true if @direction == :out or @direction == :inout
285
300
  end
286
- @dimension = [@dimension].flatten if dimension?
301
+
302
+ @type = type::new(properties)
303
+ @properties = properties
287
304
  end
288
305
 
289
306
  def copy(name=nil,properties={})
@@ -343,8 +360,23 @@ module BOAST
343
360
  return Expression::new("++",self,nil)
344
361
  end
345
362
 
363
+ # Indexes a {Variable} with the :dimension (or :dim) property set
364
+ # @param [Array{#to_s, Range, [first, last, step], :all, nil}] args one entry for each {Dimension} of the {Variable}.
365
+ # * Range: if an index is a Range, the result will be a {Slice}. The Range can be exclusive. The first and last item of the Range will be considered first and last index in the corresponding {Dimension}.
366
+ # * [first, last, step]: if an index is an Array, the result will be a {Slice}. The first and last item of the array will be considered first and last index in the corresponding {Dimension}. If a step is given the range will be iterated by step.
367
+ # * :all, nil: The whole dimension will be used for the slice. But indexing will start at #get_array_start instead of the original index.
368
+ # * #to_s: If an index is none of the above it will be considered a scalar index. If all indexes are scalar an {Index} will be returned.
369
+ # @return [Slice, Index]
346
370
  def [](*args)
347
- return Index::new(self,*args)
371
+ slice = false
372
+ args.each { |a|
373
+ slice = true if a.kind_of?(Range) or a.kind_of?(Array) or a.kind_of?(Symbol) or a.nil?
374
+ }
375
+ if slice then
376
+ return Slice::new(self, *args)
377
+ else
378
+ return Index::new(self, *args)
379
+ end
348
380
  end
349
381
 
350
382
  def boast_header(lang=C)
@@ -389,6 +421,8 @@ module BOAST
389
421
  return align_c(a) if lang == C
390
422
  return align_fortran(a) if lang == FORTRAN
391
423
  end
424
+ elsif vector? then
425
+ return align_fortran(alignment) if lang == FORTRAN
392
426
  end
393
427
  return nil
394
428
  end
@@ -409,43 +443,47 @@ module BOAST
409
443
  private
410
444
 
411
445
  def __const?
412
- return !!( constant? or @direction == :in )
446
+ return ( constant? or @direction == :in )
413
447
  end
414
448
 
415
449
  def __global?
416
- return !!( lang == CL and @direction and dimension? and not (@properties[:register] or @properties[:private] or local?) )
450
+ return ( lang == CL and @direction and dimension? and not (@properties[:register] or @properties[:private] or local?) )
417
451
  end
418
452
 
419
453
  def __local?
420
- return !!( lang == CL and local? )
454
+ return ( lang == CL and local? )
421
455
  end
422
456
 
423
457
  def __shared?(device = false)
424
- return !!( lang == CUDA and local? and not device )
458
+ return ( lang == CUDA and local? and not device )
425
459
  end
426
460
 
427
461
  def __vla_array?
428
- return !!( use_vla? and dimension? and not decl_module? )
462
+ return ( use_vla? and dimension? and not decl_module? )
429
463
  end
430
464
 
431
465
  def __pointer_array?(device = false)
432
- return !!( dimension? and not constant? and not ( allocate? and @allocate != :heap ) and (not local? or (local? and device)) )
466
+ return ( dimension? and not constant? and not ( allocate? and @allocate != :heap ) and (not local? or (local? and device)) )
433
467
  end
434
468
 
435
469
  def __pointer?(device = false)
436
- return !!( ( not dimension? and ( @direction == :out or @direction == :inout or @reference ) ) or __pointer_array?(device) )
470
+ return ( ( not dimension? and ( @direction == :out or @direction == :inout or @reference ) ) or __pointer_array?(device) )
437
471
  end
438
472
 
439
473
  def __restrict?
440
- return !!( restrict? and not decl_module? )
474
+ return ( restrict? and not decl_module? )
441
475
  end
442
476
 
443
477
  def __dimension?(device = false)
444
- return !!( dimension? and ((local? and not device) or ( ( allocate? and @allocate != :heap ) and not constant?)) )
478
+ return ( dimension? and ((local? and not device) or ( ( allocate? and @allocate != :heap ) and not constant?)) )
445
479
  end
446
480
 
447
481
  def __align?
448
- return !!( dimension? and (align? or default_align > 1) and (constant? or (allocate? and @allocate != :heap ) ) )
482
+ return ( dimension? and (align? or default_align > 1) and (constant? or (allocate? and @allocate != :heap ) ) )
483
+ end
484
+
485
+ def __vector?
486
+ return ( @type.vector? and @type.vector_length > 1 )
449
487
  end
450
488
 
451
489
  def decl_c_s(device = false)
@@ -531,18 +569,19 @@ module BOAST
531
569
  return Pragma::new("DIR", "ASSUME_ALIGNED", "#{@name}: #{a}")
532
570
  end
533
571
 
534
- def alloc_fortran( dims = nil )
572
+ def alloc_fortran( dims )
573
+ dims.unshift( @type.vector_length ) if __vector?
535
574
  return FuncCall::new(:allocate, FuncCall(name, * dims ) )
536
575
  end
537
576
 
538
- def alloc_c( dims = nil, align = get_address_size)
539
- d = dims.collect { |d| d.to_s }.reverse.join(")*(")
577
+ def alloc_c( dims, align = get_address_size)
578
+ ds = dims.collect { |d| d.to_s }.reverse.join(")*(")
540
579
  if align > (OS.bits/8) then
541
580
  # check alignment is a power of 2
542
581
  raise "Invalid alignment #{align}!" if align & (align - 1) != 0
543
- return FuncCall::new(:posix_memalign, address, align, FuncCall::new(:sizeof, @type.decl) * d)
582
+ return FuncCall::new(:posix_memalign, address, align, FuncCall::new(:sizeof, @type.decl) * ds)
544
583
  else
545
- return self === FuncCall::new(:malloc, FuncCall::new(:sizeof, @type.decl) * d).cast(self)
584
+ return self === FuncCall::new(:malloc, FuncCall::new(:sizeof, @type.decl) * ds).cast(self)
546
585
  end
547
586
  end
548
587
 
@@ -562,15 +601,19 @@ module BOAST
562
601
  s += ", optional" if optional?
563
602
  s += ", allocatable" if allocate? and @allocate == :heap
564
603
  s += ", parameter" if constant?
565
- if dimension? then
604
+ if dimension? or __vector? then
566
605
  s += ", dimension("
606
+ if __vector? then
607
+ s += "#{@type.vector_length}"
608
+ s += ", " if dimension?
609
+ end
567
610
  s += @dimension.collect { |d|
568
611
  if deferred_shape? or ( allocate? and @allocate == :heap )
569
612
  ":"
570
613
  else
571
614
  d.to_s
572
615
  end
573
- }.join(", ")
616
+ }.join(", ") if dimension?
574
617
  s += ")"
575
618
  end
576
619
  s += " :: #{@name}"
@@ -581,7 +624,7 @@ module BOAST
581
624
  end
582
625
  s += finalize
583
626
  output.print s
584
- if dimension? and (align? or default_align > 1) and (constant? or ( allocate? and @allocate != :heap ) ) then
627
+ if ( dimension? and (align? or default_align > 1) and (constant? or ( allocate? and @allocate != :heap ) ) ) or ( vector? and not @direction ) then
585
628
  a = ( align? ? alignment : 1 )
586
629
  a = ( a >= default_align ? a : default_align )
587
630
  s = ""