BOAST 1.0.9 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,17 @@
1
+ module BOAST
2
+
3
+ class CodeBlock < Proc
4
+ include PrivateStateAccessor
5
+ include Inspectable
6
+ extend Functor
7
+
8
+ attr_accessor :options
9
+
10
+ def initialize(options = {},&block)
11
+ @options = options
12
+ super(&block)
13
+ end
14
+
15
+ end
16
+
17
+ end
@@ -0,0 +1,38 @@
1
+ module BOAST
2
+
3
+ class Comment
4
+ extend Functor
5
+ include PrivateStateAccessor
6
+ include Inspectable
7
+ attr_reader :comment
8
+
9
+ def initialize(string)
10
+ @comment = string
11
+ end
12
+
13
+ def to_s_fortran
14
+ s = ""
15
+ @comment.each_line { |l| s += "! #{l}" }
16
+ return s
17
+ end
18
+
19
+ def to_s_c
20
+ s = ""
21
+ @comment.each_line { |l| s += "/* #{l.delete("\n")} */\n" }
22
+ return s
23
+ end
24
+
25
+ def to_s
26
+ return to_s_fortran if get_lang == FORTRAN
27
+ return to_s_c if [C,CL,CUDA].include?(get_lang)
28
+ end
29
+
30
+ def pr
31
+ s = to_s
32
+ output.puts s
33
+ return self
34
+ end
35
+
36
+ end
37
+
38
+ end
@@ -4,6 +4,8 @@ module BOAST
4
4
  include PrivateStateAccessor
5
5
  include Inspectable
6
6
 
7
+ attr_accessor :args
8
+
7
9
  def self.inherited(child)
8
10
  child.extend Functor
9
11
  end
@@ -23,6 +25,11 @@ module BOAST
23
25
  EOF
24
26
  end
25
27
 
28
+ def [](*args)
29
+ @args = args
30
+ return self
31
+ end
32
+
26
33
  end
27
34
 
28
35
  end
@@ -0,0 +1,7 @@
1
+ module BOAST
2
+ class Error < StandardError
3
+ end
4
+
5
+ class LanguageError < Error
6
+ end
7
+ end
@@ -2,16 +2,15 @@ module BOAST
2
2
 
3
3
  module_function
4
4
 
5
- def Return(value)
6
- return Expression("return",nil, value)
7
- end
8
-
9
5
  class Expression
10
6
  include PrivateStateAccessor
11
7
  include Arithmetic
12
8
  include Inspectable
13
9
  extend Functor
14
10
  include TypeTransition
11
+ include Annotation
12
+
13
+ ANNOTATIONS = [:operator, :operand1, :operand2]
15
14
 
16
15
  attr_reader :operator
17
16
  attr_reader :operand1
@@ -23,7 +22,7 @@ module BOAST
23
22
  end
24
23
 
25
24
  def to_s_base(op1, op2, oper, return_type = nil)
26
- return oper.to_s(op1, op2, return_type) if not oper.kind_of?(String)
25
+ return oper.string(op1, op2, return_type) unless oper.kind_of?(String)
27
26
  s = ""
28
27
  if op1 then
29
28
  s += "(" if (oper == "*" or oper == "/")
@@ -1,15 +1,27 @@
1
1
  module BOAST
2
2
 
3
3
  class For < ControlStructure
4
+ include Annotation
5
+ ANNOTATIONS = [ :iterator, :begin, :end, :step, :operator ]
4
6
 
5
7
  attr_reader :iterator
6
8
  attr_reader :begin
7
9
  attr_reader :end
8
10
  attr_reader :step
11
+ attr_accessor :block
12
+
13
+ def unroll?
14
+ return !!@unroll
15
+ end
16
+
17
+ def unroll=(val)
18
+ @unroll = val
19
+ end
9
20
 
10
21
  def initialize(i, b, e, options={}, &block)
11
22
  default_options = {:step => 1}
12
23
  default_options.update( options )
24
+ @options = options
13
25
  @iterator = i
14
26
  @begin = b
15
27
  @end = e
@@ -17,6 +29,8 @@ module BOAST
17
29
  @operator = "<="
18
30
  @block = block
19
31
  @openmp = default_options[:openmp]
32
+ @unroll = default_options[:unroll]
33
+ @args = default_options[:args]
20
34
  if @openmp then
21
35
  if @openmp.kind_of?(Hash) then
22
36
  @openmp = OpenMP::For(@openmp)
@@ -62,39 +76,55 @@ module BOAST
62
76
  return s
63
77
  end
64
78
 
65
- def unroll(*args)
79
+ # def u(s = 2)
80
+ # return [For::new(@iterator, @begin, @end - (@step*s - 1), @options.dup.update( { :step => (@step*s) } ), &@block),
81
+ # For::new(@iterator, @begin.to_var + ((@end - @begin + 1)/(@step*s))*(@step*s), @end, @options, &@block) ]
82
+ # end
83
+ #
84
+ def unroll
85
+ opts = @options.clone
86
+ opts[:unroll] = true
87
+ return For::new(@iterator, @begin, @end, opts, &block)
88
+ end
89
+
90
+ def pr_unroll(*args)
66
91
  raise "Block not given!" if not @block
67
- push_env( :replace_constants => true )
68
92
  begin
69
- if @begin.kind_of?(Variable) then
70
- start = @begin.constant
71
- elsif @begin.kind_of?(Expression) then
72
- start = eval "#{@begin}"
73
- else
74
- start = @begin.to_i
75
- end
76
- if @end.kind_of?(Variable) then
77
- e = @end.constant
78
- elsif @end.kind_of?(Expression) then
79
- e = eval "#{@end}"
80
- else
81
- e = @end.to_i
82
- end
83
- if @step.kind_of?(Variable) then
84
- step = @step.constant
85
- elsif @step.kind_of?(Expression) then
86
- step = eval "#{@step}"
87
- else
88
- step = @step.to_i
93
+ begin
94
+ push_env( :replace_constants => true )
95
+ if @begin.kind_of?(Variable) then
96
+ start = @begin.constant
97
+ elsif @begin.kind_of?(Expression) then
98
+ start = eval "#{@begin}"
99
+ else
100
+ start = @begin.to_i
101
+ end
102
+ if @end.kind_of?(Variable) then
103
+ e = @end.constant
104
+ elsif @end.kind_of?(Expression) then
105
+ e = eval "#{@end}"
106
+ else
107
+ e = @end.to_i
108
+ end
109
+ if @step.kind_of?(Variable) then
110
+ step = @step.constant
111
+ elsif @step.kind_of?(Expression) then
112
+ step = eval "#{@step}"
113
+ else
114
+ step = @step.to_i
115
+ end
116
+ raise "Invalid bounds (not constants)!" if not ( start and e and step )
117
+ ensure
118
+ pop_env( :replace_constants )
89
119
  end
90
- raise "Invalid bounds (not constants)!" if not ( start and e and step )
91
120
  rescue Exception => ex
92
- if not ( start and e and step ) then
93
- pop_env( :replace_constants )
94
- return pr(*args) if not ( start and e and step )
121
+ open
122
+ if @block then
123
+ @block.call(*args)
124
+ close
95
125
  end
126
+ return self
96
127
  end
97
- pop_env( :replace_constants )
98
128
  range = start..e
99
129
  @iterator.force_replace_constant = true
100
130
  range.step(step) { |i|
@@ -116,6 +146,8 @@ module BOAST
116
146
  end
117
147
 
118
148
  def pr(*args)
149
+ args = @args if args.length == 0 and @args
150
+ return pr_unroll(*args) if unroll?
119
151
  open
120
152
  if @block then
121
153
  @block.call(*args)
@@ -5,24 +5,18 @@ module BOAST
5
5
  attr_reader :conditions
6
6
 
7
7
  def initialize(*conditions, &block)
8
+ raise "Illegal if construct!" if conditions.size == 0
9
+ conditions.push(block) if block
8
10
  @conditions = []
9
11
  @blocks = []
10
- if conditions.size == 0 then
11
- raise "Illegal if construct!"
12
- elsif conditions.size == 1 then
13
- @conditions.push(conditions[0])
14
- @blocks.push(block)
15
- elsif conditions.size.even? then
16
- (0..conditions.size-1).step(2) { |i|
17
- @conditions[i/2] = conditions[i]
18
- @blocks[i/2] = conditions[i+1]
19
- }
12
+ if conditions.size == 1 then
13
+ @conditions.push conditions.shift
20
14
  else
21
- (0..conditions.size-2).step(2) { |i|
22
- @conditions[i/2] = conditions[i]
23
- @blocks[i/2] = conditions[i+1]
24
- }
25
- @blocks.push(conditions.last)
15
+ while conditions.size >= 2 do
16
+ @conditions.push conditions.shift
17
+ @blocks.push conditions.shift
18
+ end
19
+ @blocks.push conditions.shift if conditions.size > 0
26
20
  end
27
21
  end
28
22
 
@@ -63,7 +57,7 @@ module BOAST
63
57
  end
64
58
 
65
59
  def open
66
- s=""
60
+ s = ""
67
61
  s += indent
68
62
  s += to_s
69
63
  output.puts s
@@ -72,11 +66,12 @@ module BOAST
72
66
  end
73
67
 
74
68
  def pr(*args)
69
+ args = @args if args.length == 0 and @args
75
70
  if @blocks.size > 0 then
76
71
  increment_indent_level
77
72
  @blocks.each_index { |indx|
78
73
  decrement_indent_level
79
- s=""
74
+ s = ""
80
75
  s += indent
81
76
  s += to_s(indx)
82
77
  output.puts s
@@ -3,19 +3,19 @@ module BOAST
3
3
  class Index < Expression
4
4
  attr_reader :source
5
5
  attr_reader :indexes
6
- attr_accessor :align
6
+ attr_accessor :alignment
7
7
 
8
- def initialize(source, indexes)
8
+ def initialize(source, *indexes)
9
9
  @source = source
10
10
  @indexes = indexes
11
11
  end
12
12
 
13
13
  def align?
14
- return !!@align
14
+ return !!@alignment
15
15
  end
16
16
 
17
17
  def to_var
18
- var = @source.copy("#{self}", :const => nil, :constant => nil, :dim => nil, :dimension => nil, :direction => nil, :dir => nil, :align => align)
18
+ var = @source.copy("#{self}", :const => nil, :constant => nil, :dim => nil, :dimension => nil, :direction => nil, :dir => nil, :align => alignment)
19
19
  return var
20
20
  end
21
21
 
@@ -60,7 +60,7 @@ module BOAST
60
60
  end
61
61
 
62
62
  def to_s_texture
63
- raise "Unsupported language #{lang} for texture!" if not [CL, CUDA].include?( lang )
63
+ raise LanguageError, "Unsupported language #{lang} for texture!" if not [CL, CUDA].include?( lang )
64
64
  raise "Write is unsupported for textures!" if not ( @source.constant or @source.direction == :in )
65
65
  dim_number = 1
66
66
  if @source.dimension then
@@ -21,71 +21,77 @@ module BOAST
21
21
  INSTRUCTIONS = {}
22
22
  INSTRUCTIONS.update(X86CPUID_by_name)
23
23
 
24
+ class IntrinsicsError < Error
25
+ end
26
+
27
+ class InternalIntrinsicsError < Error
28
+ end
29
+
24
30
  module Intrinsics
25
31
  extend PrivateStateAccessor
26
32
  INTRINSICS = Hash::new { |h, k| h[k] = Hash::new { |h2, k2| h2[k2] = {} } }
27
33
  CONVERSIONS = Hash::new { |h, k| h[k] = Hash::new { |h2, k2| h2[k2] = {} } }
28
34
 
29
- def supported(intr_symbol, type, type2=nil)
30
- instruction = intrinsics(intr_symbol, type, type2)
31
- return false unless instruction
35
+ def intrinsics_by_vector_name(intr_symbol, type, type2=nil)
36
+ if type2 then
37
+ instruction = INTRINSICS[get_architecture][intr_symbol][type][type2]
38
+ else
39
+ instruction = INTRINSICS[get_architecture][intr_symbol][type]
40
+ end
41
+ raise IntrinsicsError, "Unsupported operation #{intr_symbol} for #{type}#{type2 ? "and #{type2}" : ""} on #{get_architecture_name}!" unless instruction
42
+ supported = false
32
43
  INSTRUCTIONS[instruction.to_s].each { |flag|
33
- return true if MODELS[get_model].include?(flag)
44
+ supported = true if MODELS[get_model].include?(flag)
34
45
  }
35
- return false
36
- end
37
-
38
- module_function :supported
39
-
40
- def intrinsics_by_vector_name(intr_symbol, type, type2=nil)
41
- return INTRINSICS[get_architecture][intr_symbol][type][type2] if type2
42
- return INTRINSICS[get_architecture][intr_symbol][type]
46
+ raise IntrinsicsError, "Unsupported operation #{intr_symbol} for #{type}#{type2 ? "and #{type2}" : ""} on #{get_model}! (requires #{INSTRUCTIONS[instruction.to_s].join(" or ")})" unless supported
47
+ return instruction
43
48
  end
44
49
 
45
50
  module_function :intrinsics_by_vector_name
46
51
 
47
52
  def intrinsics(intr_symbol, type, type2=nil)
48
- return INTRINSICS[get_architecture][intr_symbol][get_vector_name(type)][get_vector_name(type2)] if type2
49
- return INTRINSICS[get_architecture][intr_symbol][get_vector_name(type)]
53
+ return intrinsics_by_vector_name(intr_symbol, get_vector_name(type), type2 ? get_vector_name(type2) : nil)
50
54
  end
51
55
 
52
56
  module_function :intrinsics
53
57
 
54
58
  def get_conversion_path(type_dest, type_orig)
55
- return CONVERSIONS[get_architecture][get_vector_name(type_dest)][get_vector_name(type_orig)]
59
+ conversion_path = CONVERSIONS[get_architecture][get_vector_name(type_dest)][get_vector_name(type_orig)]
60
+ raise IntrinsicsError, "Unavailable conversion from #{get_vector_name(type_orig)} to #{get_vector_name(type_dest)} on #{get_architecture_name}!" unless conversion_path
61
+ return conversion_path
56
62
  end
57
63
 
58
64
  module_function :get_conversion_path
59
65
 
60
66
  def get_vector_decl_X86( data_type )
61
- raise "Unsupported vector size on X86: #{data_type.total_size*8}!" unless [64,128,256].include?( data_type.total_size*8 )
67
+ raise IntrinsicsError, "Unsupported vector size on X86: #{data_type.total_size*8}!" unless [64,128,256].include?( data_type.total_size*8 )
62
68
  s = "__m#{data_type.total_size*8}"
63
69
  case data_type
64
70
  when Int
65
- raise "Unsupported data size for int vector on X86: #{data_type.size*8}!" unless [1,2,4,8].include?( data_type.size )
71
+ raise IntrinsicsError, "Unsupported data size for int vector on X86: #{data_type.size*8}!" unless [1,2,4,8].include?( data_type.size )
66
72
  return s+= "#{data_type.total_size*8>64 ? "i" : ""}"
67
73
  when Real
68
74
  return s if data_type.size == 4
69
75
  return s += "d" if data_type.size == 8
70
- raise "Unsupported data size for real vector on X86: #{data_type.size*8}!"
76
+ raise IntrinsicsError, "Unsupported data size for real vector on X86: #{data_type.size*8}!"
71
77
  else
72
- raise "Unsupported data type #{data_type} for vector!"
78
+ raise IntrinsicsError, "Unsupported data type #{data_type} for vector on X86!"
73
79
  end
74
80
  end
75
81
 
76
82
  module_function :get_vector_decl_X86
77
83
 
78
84
  def get_vector_decl_ARM( data_type )
79
- raise "Unsupported vector size on ARM: #{data_type.total_size*8}!" unless [64,128].include?( data_type.total_size*8 )
85
+ raise IntrinsicsError, "Unsupported vector size on ARM: #{data_type.total_size*8}!" unless [64,128].include?( data_type.total_size*8 )
80
86
  case data_type
81
87
  when Int
82
- raise "Unsupported data size for int vector on ARM: #{data_type.size*8}!" unless [1,2,4,8].include?( data_type.size )
88
+ raise IntrinsicsError, "Unsupported data size for int vector on ARM: #{data_type.size*8}!" unless [1,2,4,8].include?( data_type.size )
83
89
  return get_vector_name( data_type ).to_s
84
90
  when Real
85
- raise "Unsupported data size for real vector on ARM: #{data_type.size*8}!" if data_type.size != 4
91
+ raise IntrinsicsError, "Unsupported data size for real vector on ARM: #{data_type.size*8}!" if data_type.size != 4
86
92
  return get_vector_name( data_type ).to_s
87
93
  else
88
- raise "Unsupported data type #{data_type} for vector on ARM!"
94
+ raise IntrinsicsError, "Unsupported data type #{data_type} for vector on ARM!"
89
95
  end
90
96
  end
91
97
 
@@ -113,7 +119,7 @@ module BOAST
113
119
  when Real
114
120
  s += "float"
115
121
  else
116
- raise "Undefined vector type!"
122
+ raise InternalIntrinsicsError, "Undefined vector type!"
117
123
  end
118
124
  s += "#{type.size*8}"
119
125
  s += "x#{type.vector_length}_t"
@@ -132,12 +138,12 @@ module BOAST
132
138
  when :unsigned
133
139
  s += "uint"
134
140
  else
135
- raise "Invalid sign!"
141
+ raise InternalIntrinsicsError, "Invalid sign!"
136
142
  end
137
143
  when :float
138
144
  s += "float"
139
145
  else
140
- raise "Invalid type!"
146
+ raise InternalIntrinsicsError, "Invalid type!"
141
147
  end
142
148
  s += "#{size}"
143
149
  s += "x#{vector_size/size}_t"
@@ -156,12 +162,12 @@ module BOAST
156
162
  when :unsigned
157
163
  s += "u"
158
164
  else
159
- raise "Invalid sign!"
165
+ raise InternalIntrinsicsError, "Invalid sign!"
160
166
  end
161
167
  when :float
162
168
  s += "f"
163
169
  else
164
- raise "Invalid type!"
170
+ raise InternalIntrinsicsError, "Invalid type!"
165
171
  end
166
172
  s += "#{size}"
167
173
  return s
@@ -181,7 +187,7 @@ module BOAST
181
187
  when :unsigned
182
188
  s += "u"
183
189
  else
184
- raise "Invalid sign!"
190
+ raise InternalIntrinsicsError, "Invalid sign!"
185
191
  end
186
192
  s += "#{size}"
187
193
  when :float
@@ -192,10 +198,10 @@ module BOAST
192
198
  when 64
193
199
  s += "d"
194
200
  else
195
- raise "Invalid size!"
201
+ raise InternalIntrinsicsError, "Invalid size!"
196
202
  end
197
203
  else
198
- raise "Invalid type!"
204
+ raise InternalIntrinsicsError, "Invalid type!"
199
205
  end
200
206
  return s
201
207
  end
@@ -234,7 +240,7 @@ module BOAST
234
240
  sizes = []
235
241
  sizes.push( 32, 64 ) if vector_size > 64
236
242
  sizes.each { |size|
237
- [[:ADD, "add"], [:SUB, "sub"], [:MUL, "mul"], [:DIV, "div"],
243
+ [[:ADD, "add"], [:SUB, "sub"], [:MUL, "mul"], [:DIV, "div"], [:POW, "pow"],
238
244
  [:FMADD, "fmadd"], [:FMSUB, "fmsub"], [:FNMADD, "fnmadd"], [:FNMSUB, "fnmsub"],
239
245
  [:ADDSUB, "addsub"], [:FMADDSUB, "fmaddsub"], [:FMSUBADD, "fmsubadd"],
240
246
  [:LOAD, "loadu"], [:LOADA, "load"], [:MASKLOAD, "maskload"],