class BOAST::Variable
Constants
- ANNOTATIONS
Attributes
Public Class Methods
# File lib/BOAST/Language/Variable.rb, line 313 def self.from_type(name, type, properties={}) hash = type.to_hash properties.each { |k,v| hash[k] = v } hash[:direction] = nil hash[:dir] = nil return Variable::new(name, type.class, hash) end
Creates a new {Variable} @param [#to_s] name @param [DataType] type @param [Hash] properties a set of named properties. Properties are also propagated to the {DataType}. @option properties [Symbol] :direction (or :dir) can be one of :in, :out or :inout. Specify the intent of the variable. @option properties [Array<Dimension>] :dimension (or :dim) variable is an array rather than a scalar. Dimensions are given in Fortran order (contiguous first). @option properties [Object] :constant (or :const) states that the variable is a constant and give its value. For
Variable
with the :dimension property set must be a {ConstArray} @option properties [Boolean] :restrict specifies that the compiler can assume no aliasing to this array. @option properties [Boolean] :reference specifies that this variable is passed by reference. @option properties [Symbol] :allocate specify that the variable is to be allocated and where. Can only be :heap or :stack for now. @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. @option properties [Boolean] :texture for OpenCL and CUDA. In OpenCL also specifies that a sampler has to be generated to access the array variable. @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). @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. @option properties [Boolean] :deferred_shape for Fortran interface generation mainly see Fortran documentation @option properties [Boolean] :optional for Fortran interface generation mainly see Fortran documentation
# File lib/BOAST/Language/Variable.rb, line 265 def initialize(name, type, properties={}) @name = name.to_s @direction = properties[:direction] or @direction = properties[:dir] @constant = properties[:constant] or @constant = properties[:const] @dimension = properties[:dimension] or @dimension = properties[:dim] @local = properties[:local] or @local = properties[:shared] @texture = properties[:texture] @allocate = properties[:allocate] @restrict = properties[:restrict] @alignment = properties[:align] @deferred_shape = properties[:deferred_shape] @optional = properties[:optional] @reference = properties[:reference] @force_replace_constant = false @replace_constant = properties[:replace_constant] if @texture and lang == CL then @sampler = Variable::new("sampler_#{name}", CustomType,:type_name => "sampler_t" ,:replace_constant => false, :constant => "CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_NONE | CLK_FILTER_NEAREST") else @sampler = nil end @scalar_output = false if @dimension then @dimension = [@dimension].flatten else @scalar_output = true if @direction == :out or @direction == :inout end @type = type::new(properties) @properties = properties end
Public Instance Methods
Indexes a {Variable} with the :dimension (or :dim) property set @param [Array{#to_s, Range, [first, last, step], :all, nil}] args one entry for each {Dimension} of the {Variable}.
* 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}. * [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. * :all, nil: The whole dimension will be used for the slice. But indexing will start at #get_array_start instead of the original index. * #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.
@return [Slice, Index]
# File lib/BOAST/Language/Variable.rb, line 363 def [](*args) slice = false args.each { |a| slice = true if a.kind_of?(Range) or a.kind_of?(Array) or a.kind_of?(Symbol) or a.nil? } if slice then return Slice::new(self, *args) else return Index::new(self, *args) end end
# File lib/BOAST/Language/Variable.rb, line 407 def align if dimension? then if align? or default_align > 1 then a = ( align? ? alignment : 1 ) a = ( a >= default_align ? a : default_align ) return align_c(a) if lang == C return align_fortran(a) if lang == FORTRAN end elsif vector? then return align_fortran(alignment) if lang == FORTRAN end return nil end
# File lib/BOAST/Language/Variable.rb, line 233 def align? alignment end
# File lib/BOAST/Language/Variable.rb, line 188 def alignment return @type.total_size if __vector? and lang == FORTRAN and not @alignment return @alignment end
# File lib/BOAST/Language/Variable.rb, line 421 def alloc( dims = nil, align = get_address_size ) @dimension = [dims].flatten if dims dims = @dimension raise "Cannot allocate array with unknown dimension!" unless dims return alloc_fortran(dims) if lang == FORTRAN return alloc_c(dims, align) if lang == C end
# File lib/BOAST/Language/Variable.rb, line 197 def allocate? @allocate end
# File lib/BOAST/Language/Variable.rb, line 375 def boast_header(lang=C) return decl_texture_s if texture? s = "" s << "const " if constant? or @direction == :in s << @type.decl if dimension? then s << " *" unless (use_vla? and lang != FORTRAN) end if not dimension? and ( lang == FORTRAN or @direction == :out or @direction == :inout or @reference ) then s << " *" end s << " #{@name}" if dimension? and use_vla? and lang != FORTRAN then s << "[" s << @dimension.reverse.collect(&:to_s).join("][") s << "]" end return s end
# File lib/BOAST/Language/Variable.rb, line 193 def constant? @constant end
# File lib/BOAST/Language/Variable.rb, line 299 def copy(name=nil,properties={}) name = @name unless name h = @properties.clone properties.each { |k,v| h[k] = v } return Variable::new(name, @type.class, h) end
# File lib/BOAST/Language/Variable.rb, line 429 def dealloc return dealloc_fortran if lang == FORTRAN return dealloc_c if lang == C end
# File lib/BOAST/Language/Variable.rb, line 402 def decl return decl_fortran if lang == FORTRAN return decl_c if [C, CL, CUDA].include?( lang ) end
# File lib/BOAST/Language/Variable.rb, line 395 def decl_ffi(alloc, lang) return :pointer if lang == FORTRAN and not alloc return :pointer if dimension? return :pointer if @direction == :out or @direction == :inout or @reference and not alloc return @type.decl_ffi end
# File lib/BOAST/Language/Variable.rb, line 237 def deferred_shape? @deferred_shape end
# File lib/BOAST/Language/Variable.rb, line 342 def dereference return copy("*(#{name})", :dimension => nil, :dim => nil, :direction => nil, :dir => nil) if [C, CL, CUDA].include?( lang ) return Index::new(self, *(@dimension.collect { |d| d.start } ) ) if lang == FORTRAN end
# File lib/BOAST/Language/Variable.rb, line 221 def dimension? @dimension end
# File lib/BOAST/Language/Variable.rb, line 217 def force_replace_constant? @force_replace_constant end
# File lib/BOAST/Language/Variable.rb, line 352 def inc return Expression::new("++",self,nil) end
# File lib/BOAST/Language/Variable.rb, line 205 def local? @local end
# File lib/BOAST/Language/Variable.rb, line 152 def method_missing(m, *a, &b) if @type.kind_of?(CStruct) and @type.members[m.to_s] then return struct_reference(type.members[m.to_s]) elsif __vector? and m.to_s[0] == 's' and lang != CUDA then required_set = m.to_s[1..-1].chars.to_a existing_set = [*('0'..'9'),*('a'..'z')].first(@type.vector_length) if required_set.length == required_set.uniq.length and (required_set - existing_set).empty? then return copy(name+"."+m.to_s, :vector_length => m.to_s[1..-1].length) if lang == CL return copy("#{name}(#{existing_set.index(required_set[0])+1})", :vector_length => 1) if lang == FORTRAN return copy("#{name}[#{existing_set.index(required_set[0])}]", :vector_length => 1) if lang == C return super else return super end else return super end end
# File lib/BOAST/Language/Variable.rb, line 229 def optional? @optional end
# File lib/BOAST/Language/Variable.rb, line 241 def reference? @reference end
# File lib/BOAST/Language/Variable.rb, line 213 def replace_constant? @replace_constant end
# File lib/BOAST/Language/Variable.rb, line 209 def restrict? @restrict end
# File lib/BOAST/Language/Variable.rb, line 225 def scalar_output? @scalar_output end
# File lib/BOAST/Language/Variable.rb, line 338 def set(x) return self === Set(x,self) end
# File lib/BOAST/Language/Variable.rb, line 308 def set_align(align) @alignment = align return self end
# File lib/BOAST/Language/Slice.rb, line 222 def slice(*slices) Slice::new(self, *slices) end
# File lib/BOAST/Language/Variable.rb, line 347 def struct_reference(x) return x.copy(name+"."+x.name) if [C, CL, CUDA].include?( lang ) return x.copy(name+"%"+x.name) if lang == FORTRAN end
# File lib/BOAST/Language/Variable.rb, line 201 def texture? @texture end
# File lib/BOAST/Language/Variable.rb, line 323 def to_s if force_replace_constant? or ( ( replace_constant? or replace_constants? ) and constant? and not dimension? ) then s = @constant.to_s + @type.suffix return s end if @scalar_output or @reference and [C, CL, CUDA].include?( lang ) and not decl_module? then return "(*#{name})" end return @name end
# File lib/BOAST/Language/Variable.rb, line 334 def to_var return self end
# File lib/BOAST/Language/Variable.rb, line 245 def vector? __vector? end
Private Instance Methods
# File lib/BOAST/Language/Variable.rb, line 472 def __align? return ( dimension? and (align? or default_align > 1) and (constant? or (allocate? and @allocate != :heap ) ) ) end
# File lib/BOAST/Language/Variable.rb, line 480 def __attr_align? return ( __align? or ( vector? and not @direction ) ) end
# File lib/BOAST/Language/Variable.rb, line 436 def __const? return ( constant? or @direction == :in ) end
# File lib/BOAST/Language/Variable.rb, line 468 def __dimension?(device = false) return ( dimension? and ((local? and not device) or ( ( allocate? and @allocate != :heap ) and not constant?)) ) end
# File lib/BOAST/Language/Variable.rb, line 440 def __global? return ( lang == CL and @direction and dimension? and not (@properties[:register] or @properties[:private] or local?) ) end
# File lib/BOAST/Language/Variable.rb, line 444 def __local? return ( lang == CL and local? ) end
# File lib/BOAST/Language/Variable.rb, line 460 def __pointer?(device = false) return ( ( not dimension? and ( @direction == :out or @direction == :inout or @reference ) ) or __pointer_array?(device) ) end
# File lib/BOAST/Language/Variable.rb, line 456 def __pointer_array?(device = false) return ( dimension? and not constant? and not ( allocate? and @allocate != :heap ) and (not local? or (local? and device)) ) end
# File lib/BOAST/Language/Variable.rb, line 464 def __restrict? return ( restrict? and not decl_module? ) end
# File lib/BOAST/Language/Variable.rb, line 476 def __vector? return ( @type.vector? and @type.vector_length > 1 ) end
# File lib/BOAST/Language/Variable.rb, line 452 def __vla_array? return ( use_vla? and dimension? and not decl_module? ) end
# File lib/BOAST/Language/Variable.rb, line 557 def align_c(a) return FuncCall::new("__assume_aligned", @name, a) end
# File lib/BOAST/Language/Variable.rb, line 561 def align_fortran(a) return Pragma::new("DIR", "ASSUME_ALIGNED", "#{@name}: #{a}") end
# File lib/BOAST/Language/Variable.rb, line 570 def alloc_c( dims, align = get_address_size) ds = dims.collect(&:to_s).reverse.join(")*(") if align > (OS.bits/8) then # check alignment is a power of 2 raise "Invalid alignment #{align}!" if align & (align - 1) != 0 return FuncCall::new(:posix_memalign, address, align, FuncCall::new(:sizeof, @type.decl) * ds) else return self === FuncCall::new(:malloc, FuncCall::new(:sizeof, @type.decl) * ds).cast(self) end end
# File lib/BOAST/Language/Variable.rb, line 565 def alloc_fortran( dims ) dims.unshift( @type.vector_length ) if __vector? return FuncCall::new(:allocate, FuncCall(name, * dims ) ) end
# File lib/BOAST/Language/Variable.rb, line 585 def dealloc_c return FuncCall::new(:free, self) end
# File lib/BOAST/Language/Variable.rb, line 581 def dealloc_fortran return FuncCall::new(:deallocate, self) end
# File lib/BOAST/Language/Variable.rb, line 548 def decl_c s = "" s << indent s << decl_c_s s << finalize output.print s return self end
# File lib/BOAST/Language/Variable.rb, line 484 def decl_c_s(device = false) return decl_texture_s if texture? s = "" s << "const " if __const? s << "__global " if __global? s << "__local " if __local? s << "__shared__ " if __shared?(device) s << @type.decl if __vla_array? then s << " #{@name}[" s << "__restrict__ " if __restrict? s << @dimension.reverse.collect(&:to_s).join("][") s << "]" else s << " *" if __pointer?(device) if __pointer_array?(device) and __restrict? then if lang == CL s << " restrict" else s << " __restrict__" unless use_vla? end end s << " #{@name}" if dimension? and constant? then s << "[]" end if __dimension?(device) then s << "[(" s << @dimension.collect(&:to_s).reverse.join(")*(") s << ")]" end end if __align? and lang != CUDA then a = ( align? ? alignment : 1 ) a = ( a >= default_align ? a : default_align ) s << " __attribute((aligned(#{a})))" end s << " = #{@constant}" if constant? return s end
# File lib/BOAST/Language/Variable.rb, line 589 def decl_fortran s = "" s << indent s << @type.decl s << ", intent(#{@direction})" if @direction s << ", optional" if optional? s << ", allocatable" if allocate? and @allocate == :heap s << ", parameter" if constant? if dimension? or __vector? then s << ", dimension(" if __vector? then s << "#{@type.vector_length}" s << ", " if dimension? end s << @dimension.collect { |d| if deferred_shape? or ( allocate? and @allocate == :heap ) ":" else d.to_s end }.join(", ") if dimension? s << ")" end s << " :: #{@name}" if constant? then @constant.shape = self if dimension? and @constant.kind_of?(ConstArray) s << " = #{@constant}" s << @type.suffix if not dimension? and @type end s << finalize output.print s if ( dimension? and (align? or default_align > 1) and (constant? or ( allocate? and @allocate != :heap ) ) ) or ( vector? and not @direction ) then a = ( align? ? alignment : 1 ) a = ( a >= default_align ? a : default_align ) s = "" s << indent s << "!DIR$ ATTRIBUTES ALIGN: #{a}:: #{name}" s << finalize output.print s end return self end
# File lib/BOAST/Language/Variable.rb, line 525 def decl_texture_s raise LanguageError, "Unsupported language #{lang} for texture!" unless [CL, CUDA].include?( lang ) raise "Write is unsupported for textures!" unless (constant? or @direction == :in) dim_number = 1 if dimension? then dim_number == @dimension.size end raise "Unsupported number of dimension: #{dim_number}!" if dim_number > 3 s = "" if lang == CL then s << "__read_only " if dim_number < 3 then s << "image2d_t " #from OCL 1.2+ image1d_t is defined else s << "image3d_t " end else s << "texture<#{@type.decl}, cudaTextureType#{dim_number}D, cudaReadModeElementType> " end s << @name return s end
# File lib/BOAST/Language/Variable.rb, line 632 def finalize s = "" s << ";" if [C, CL, CUDA].include?( lang ) s << "\n" return s end