ikra 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/lib/ast/builder.rb +225 -77
  3. data/lib/ast/host_section_builder.rb +38 -0
  4. data/lib/ast/interpreter.rb +67 -0
  5. data/lib/ast/lexical_variables_enumerator.rb +3 -2
  6. data/lib/ast/nodes.rb +521 -31
  7. data/lib/ast/printer.rb +116 -18
  8. data/lib/ast/ssa_generator.rb +192 -0
  9. data/lib/ast/visitor.rb +235 -21
  10. data/lib/config/configuration.rb +28 -3
  11. data/lib/config/os_configuration.rb +62 -9
  12. data/lib/cpu/cpu_implementation.rb +39 -0
  13. data/lib/ikra.rb +13 -3
  14. data/lib/resources/cuda/allocate_device_memory.cpp +5 -0
  15. data/lib/resources/cuda/allocate_host_memory.cpp +1 -0
  16. data/lib/resources/cuda/allocate_memcpy_environment_to_device.cpp +11 -0
  17. data/lib/resources/cuda/ast/assignment.cpp +1 -0
  18. data/lib/resources/cuda/block_function_head.cpp +7 -1
  19. data/lib/resources/cuda/entry_point.cpp +47 -0
  20. data/lib/resources/cuda/env_builder_copy_array.cpp +8 -2
  21. data/lib/resources/cuda/free_device_memory.cpp +3 -0
  22. data/lib/resources/cuda/free_memory_for_command.cpp +24 -0
  23. data/lib/resources/cuda/header.cpp +23 -9
  24. data/lib/resources/cuda/header_structs.cpp +92 -0
  25. data/lib/resources/cuda/host_section_block_function_head.cpp +12 -0
  26. data/lib/resources/cuda/host_section_entry_point.cpp +55 -0
  27. data/lib/resources/cuda/host_section_free_device_memory.cpp +18 -0
  28. data/lib/resources/cuda/host_section_launch_parallel_section.cpp +14 -0
  29. data/lib/resources/cuda/host_section_malloc_memcpy_device_to_host.cpp +10 -0
  30. data/lib/resources/cuda/kernel.cpp +9 -2
  31. data/lib/resources/cuda/launch_kernel.cpp +5 -0
  32. data/lib/resources/cuda/memcpy_device_to_host.cpp +3 -0
  33. data/lib/resources/cuda/memcpy_device_to_host_expr.cpp +10 -0
  34. data/lib/resources/cuda/reduce_body.cpp +88 -0
  35. data/lib/resources/cuda/stencil_array_reconstruction.cpp +2 -0
  36. data/lib/resources/cuda/stencil_body.cpp +16 -0
  37. data/lib/resources/cuda/struct_definition.cpp +4 -0
  38. data/lib/ruby_core/array.rb +34 -0
  39. data/lib/ruby_core/array_command.rb +313 -0
  40. data/lib/ruby_core/core.rb +103 -0
  41. data/lib/ruby_core/interpreter.rb +16 -0
  42. data/lib/ruby_core/math.rb +32 -0
  43. data/lib/ruby_core/ruby_integration.rb +256 -0
  44. data/lib/symbolic/host_section.rb +115 -0
  45. data/lib/symbolic/input.rb +87 -0
  46. data/lib/symbolic/input_visitor.rb +68 -0
  47. data/lib/symbolic/symbolic.rb +793 -117
  48. data/lib/symbolic/visitor.rb +70 -8
  49. data/lib/translator/array_command_struct_builder.rb +163 -0
  50. data/lib/translator/ast_translator.rb +572 -0
  51. data/lib/translator/block_translator.rb +104 -48
  52. data/lib/translator/commands/array_combine_command.rb +41 -0
  53. data/lib/translator/commands/array_identity_command.rb +28 -0
  54. data/lib/translator/commands/array_index_command.rb +52 -0
  55. data/lib/translator/commands/array_reduce_command.rb +135 -0
  56. data/lib/translator/commands/array_stencil_command.rb +129 -0
  57. data/lib/translator/commands/array_zip_command.rb +30 -0
  58. data/lib/translator/commands/command_translator.rb +264 -0
  59. data/lib/translator/cuda_errors.rb +32 -0
  60. data/lib/translator/environment_builder.rb +263 -0
  61. data/lib/translator/host_section/array_host_section_command.rb +150 -0
  62. data/lib/translator/host_section/array_in_host_section_command.rb +41 -0
  63. data/lib/translator/host_section/ast_translator.rb +14 -0
  64. data/lib/translator/host_section/parallel_section_invocation_visitor.rb +20 -0
  65. data/lib/translator/host_section/program_builder.rb +89 -0
  66. data/lib/translator/input_translator.rb +226 -0
  67. data/lib/translator/kernel_builder.rb +137 -0
  68. data/lib/translator/kernel_launcher/for_loop_kernel_launcher.rb +40 -0
  69. data/lib/translator/kernel_launcher/kernel_launcher.rb +259 -0
  70. data/lib/translator/kernel_launcher/while_loop_kernel_launcher.rb +38 -0
  71. data/lib/translator/last_returns_visitor.rb +19 -10
  72. data/lib/translator/program_builder.rb +197 -0
  73. data/lib/translator/program_launcher.rb +273 -0
  74. data/lib/translator/struct_type.rb +55 -0
  75. data/lib/translator/translator.rb +34 -11
  76. data/lib/translator/variable_classifier_visitor.rb +56 -0
  77. data/lib/types/inference/ast_inference.rb +586 -0
  78. data/lib/types/inference/clear_types_visitor.rb +11 -0
  79. data/lib/types/inference/command_inference.rb +101 -0
  80. data/lib/types/inference/input_inference.rb +62 -0
  81. data/lib/types/{object_tracer.rb → inference/object_tracer.rb} +5 -6
  82. data/lib/types/inference/ruby_extension.rb +35 -0
  83. data/lib/types/inference/symbol_table.rb +131 -0
  84. data/lib/types/types.rb +14 -0
  85. data/lib/types/types/array_command_type.rb +123 -0
  86. data/lib/types/types/array_type.rb +137 -0
  87. data/lib/types/{class_type.rb → types/class_type.rb} +42 -18
  88. data/lib/types/{primitive_type.rb → types/primitive_type.rb} +20 -7
  89. data/lib/types/types/ruby_type.rb +88 -0
  90. data/lib/types/types/struct_type.rb +179 -0
  91. data/lib/types/types/union_type.rb +239 -0
  92. metadata +160 -18
  93. data/lib/ast/method_definition.rb +0 -37
  94. data/lib/ast/translator.rb +0 -264
  95. data/lib/resources/cuda/kernel_launcher.cpp +0 -28
  96. data/lib/scope.rb +0 -166
  97. data/lib/translator/command_translator.rb +0 -421
  98. data/lib/translator/local_variables_enumerator.rb +0 -35
  99. data/lib/translator/method_translator.rb +0 -24
  100. data/lib/types/array_type.rb +0 -51
  101. data/lib/types/ruby_extension.rb +0 -67
  102. data/lib/types/ruby_type.rb +0 -45
  103. data/lib/types/type_inference.rb +0 -382
  104. data/lib/types/union_type.rb +0 -155
@@ -0,0 +1,137 @@
1
+ # No explicit `require`s. This file should be includes via types.rb
2
+
3
+ module Ikra
4
+ module Types
5
+ class ArrayType
6
+ include RubyType
7
+
8
+ class << self
9
+ alias_method :new_original, :new
10
+
11
+ # Ensure singleton per class
12
+ def new(inner_type)
13
+ if @cache == nil
14
+ @cache = {}
15
+ @cache.default_proc = proc do |hash, key|
16
+ hash[key] = new_original(key)
17
+ end
18
+ end
19
+
20
+ return @cache[inner_type]
21
+ end
22
+ end
23
+
24
+ attr_reader :inner_type
25
+
26
+ def ==(other)
27
+ return other.class == self.class && other.inner_type == self.inner_type
28
+ end
29
+
30
+ def initialize(inner_type)
31
+ if not inner_type.is_union_type?
32
+ raise AssertionError.new("Union type expected")
33
+ end
34
+
35
+ @inner_type = inner_type
36
+ end
37
+
38
+ def to_s
39
+ return "[#{self.class.to_s}, inner_type = #{inner_type}]"
40
+ end
41
+
42
+ def to_c_type
43
+ return "#{@inner_type.to_c_type} *"
44
+ end
45
+
46
+ def to_ffi_type
47
+ return :pointer
48
+ end
49
+
50
+ def to_ruby_type
51
+ return ::Array
52
+ end
53
+ end
54
+
55
+ class LocationAwareArrayType < ArrayType
56
+ # Determines if the array is allocated on the host or on the device
57
+ attr_reader :location
58
+
59
+ def ==(other)
60
+ return super && self.location == other.location
61
+ end
62
+
63
+ def initialize(inner_type, location)
64
+ @inner_type = inner_type
65
+ @location = location
66
+ end
67
+
68
+ def to_c_type
69
+ return "variable_size_array_t"
70
+ end
71
+ end
72
+
73
+ class LocationAwareVariableSizeArrayType < LocationAwareArrayType
74
+ class << self
75
+ def new(inner_type, location: :device)
76
+ if @cache == nil
77
+ @cache = {}
78
+ @cache.default_proc = Proc.new do |hash, key|
79
+ hash[key] = new_original(*key)
80
+ end
81
+ end
82
+
83
+ return @cache[[inner_type, location]]
84
+ end
85
+ end
86
+
87
+ def to_command
88
+ # No fusion possible here. The first parameter (target) is a reference to the
89
+ # array command struct representing the [ArrayInHostSectionCommand].
90
+ # TODO: The code depends on the template (variable name `cmd` and `input_0`).
91
+ return Symbolic::ArrayInHostSectionCommand.new("((#{@inner_type.to_c_type} *) cmd->input_0)", @inner_type)
92
+ end
93
+ end
94
+
95
+ class LocationAwareFixedSizeArrayType < LocationAwareArrayType
96
+ class << self
97
+ def new(inner_type, dimensions, location: :device)
98
+ if @cache == nil
99
+ @cache = {}
100
+ @cache.default_proc = Proc.new do |hash, key|
101
+ hash[key] = new_original(*key)
102
+ end
103
+ end
104
+
105
+ return @cache[[inner_type, location, dimensions]]
106
+ end
107
+ end
108
+
109
+ attr_reader :dimensions
110
+
111
+ def initialize(inner_type, location, dimensions)
112
+ super(inner_type, location)
113
+ @dimensions = dimensions
114
+ end
115
+
116
+ def to_command
117
+ # No fusion possible here. The first parameter (target) is a reference to the
118
+ # array command struct representing the [ArrayInHostSectionCommand].
119
+ # TODO: The code depends on the template (variable name `cmd` and `input_0`).
120
+ return Symbolic::FixedSizeArrayInHostSectionCommand.new(
121
+ "((#{@inner_type.to_c_type} *) cmd->input_0)", @inner_type, @dimensions)
122
+ end
123
+ end
124
+ end
125
+ end
126
+
127
+ class Array
128
+ def ikra_type
129
+ inner_type = Ikra::Types::UnionType.new
130
+
131
+ self.each do |element|
132
+ inner_type.add(element.ikra_type)
133
+ end
134
+
135
+ return Ikra::Types::ArrayType.new(inner_type)
136
+ end
137
+ end
@@ -1,9 +1,9 @@
1
+ # No explicit `require`s. This file should be includes via types.rb
2
+
1
3
  require "set"
2
- require_relative "ruby_type"
3
- require_relative "union_type"
4
- require_relative "../sourcify/lib/sourcify"
5
- require_relative "../parsing"
6
- require_relative "../ast/builder"
4
+ require_relative "../../sourcify/lib/sourcify"
5
+ require_relative "../../parsing"
6
+ require_relative "../../ast/builder"
7
7
 
8
8
  module Ikra
9
9
  module Types
@@ -27,6 +27,10 @@ module Ikra
27
27
  end
28
28
  end
29
29
 
30
+ def ==(other)
31
+ return other.class == self.class && other.cls == self.cls
32
+ end
33
+
30
34
  def initialize(cls)
31
35
  @cls = cls
32
36
  @inst_vars_read = Set.new
@@ -71,23 +75,36 @@ module Ikra
71
75
  "obj_id_t"
72
76
  end
73
77
 
78
+ # Generates a class name for [@cls], which is a valid C++ identifier.
79
+ #
80
+ # For example:
81
+ # A --> A
82
+ # #<Class: A> --> singleton_A
83
+ def class_name
84
+ # Handle name generation for singleton classes
85
+ return ruby_name.gsub("\#<Class:", "singleton_").gsub(">", "")
86
+ end
87
+
74
88
  def mangled_method_name(selector)
75
- "_method_#{@cls.to_s}_#{selector}_"
89
+ "_method_#{class_name}_#{selector}_"
76
90
  end
77
91
 
78
92
  def inst_var_array_name(inst_var_name)
79
93
  if inst_var_name.to_s[0] != "@"
80
- raise "Expected instance variable identifier"
94
+ raise AssertionError.new("Expected instance variable identifier")
81
95
  end
82
96
 
83
- "_iv_#{@cls.to_s}_#{inst_var_name.to_s[1..-1]}_"
97
+ "_iv_#{class_name}_#{inst_var_name.to_s[1..-1]}_"
84
98
  end
85
99
 
86
100
  def method_ast(selector)
87
101
  source = Parsing.parse_method(cls.instance_method(selector))
88
- ast = AST::Builder.from_parser_ast(source)
89
- ast.class_owner = @cls
90
- ast
102
+ return AST::Builder.from_parser_ast(source)
103
+ end
104
+
105
+ def method_binding(selector)
106
+ # TODO: Fix binding
107
+ return cls.instance_method(selector).send(:binding)
91
108
  end
92
109
 
93
110
  def method_parameters(selector)
@@ -98,12 +115,13 @@ module Ikra
98
115
  end
99
116
  end
100
117
 
101
- def should_generate_type?
102
- to_ruby_type != Class
118
+ def should_generate_self_arg?
119
+ # Do not generate type for singleton classes
120
+ return !to_ruby_type.is_a?(Module.singleton_class)
103
121
  end
104
122
 
105
123
  def to_s
106
- "<class: #{@cls.to_s}>"
124
+ "<class: #{class_name}>"
107
125
  end
108
126
 
109
127
  def c_size
@@ -117,12 +135,18 @@ end
117
135
  class Object
118
136
  def self.to_ikra_type
119
137
  # TODO: should this method be defined on Class?
120
- Ikra::Types::ClassType.new(self)
138
+ return Ikra::Types::ClassType.new(self)
121
139
  end
122
140
 
123
- # Returns the [Ikra::Types::RubyType] for this class. This version of the method receives the actual object as a parameter. This is necessary for example to determine the exact type of an array (including inner type).
124
- def self.to_ikra_type_obj(object)
125
- to_ikra_type
141
+ # Returns the [Ikra::Types::RubyType] for this object. Instance of the same Ruby class can
142
+ # principally have different Ikra types. Thus, this method is defined as an instance method.
143
+ def ikra_type
144
+ if self.is_a?(Module)
145
+ return self.singleton_class.to_ikra_type
146
+ else
147
+ # TODO: Double check if we always want to have the singleton class?
148
+ return self.class.to_ikra_type
149
+ end
126
150
  end
127
151
  end
128
152
 
@@ -1,4 +1,4 @@
1
- require_relative "ruby_type"
1
+ # No explicit `require`s. This file should be includes via types.rb
2
2
 
3
3
  module Ikra
4
4
  module Types
@@ -6,19 +6,26 @@ module Ikra
6
6
  include RubyType
7
7
 
8
8
  attr_reader :c_size
9
+ attr_reader :class_id
9
10
 
10
- def initialize(c_type, ruby_type, c_size, ffi_type)
11
+ def initialize(c_type, ruby_type, c_size, ffi_type, class_id)
11
12
  @c_type = c_type
12
13
  @ruby_type = ruby_type
13
14
  @c_size = c_size
14
15
  @ffi_type = ffi_type
16
+ @class_id = class_id
15
17
  end
16
18
 
17
- Int = self.new("int", Fixnum, 4, :int)
18
- Float = self.new("float", Float, 4, :float)
19
- Bool = self.new("bool", TrueClass, 1, :bool)
20
- Void = self.new("void", nil, 0, :void)
19
+ Int = self.new("int", Fixnum, 4, :int, 1)
20
+ Float = self.new("float", Float, 4, :float, 2)
21
+ Bool = self.new("bool", TrueClass, 1, :bool, 3)
22
+ Void = self.new("void", nil, 0, :void, 4)
23
+ Nil = self.new("int", NilClass, 4, :int, 5)
21
24
 
25
+ def ==(other)
26
+ return other.is_a?(PrimitiveType) && other.class_id == class_id
27
+ end
28
+
22
29
  def to_ruby_type
23
30
  @ruby_type
24
31
  end
@@ -30,7 +37,7 @@ module Ikra
30
37
  def to_ffi_type
31
38
  @ffi_type
32
39
  end
33
-
40
+
34
41
  def is_primitive?
35
42
  true
36
43
  end
@@ -71,3 +78,9 @@ class FalseClass
71
78
  Ikra::Types::PrimitiveType::Bool
72
79
  end
73
80
  end
81
+
82
+ class NilClass
83
+ def self.to_ikra_type
84
+ Ikra::Types::PrimitiveType::Nil
85
+ end
86
+ end
@@ -0,0 +1,88 @@
1
+ require "set"
2
+
3
+ module Ikra
4
+ module Types
5
+
6
+ # Defines the minimal interface for Ikra types. Instances of {UnionType} are expected in most cases.
7
+ module RubyType
8
+ @@next_class_id = 10
9
+
10
+ def to_str
11
+ return to_s
12
+ end
13
+
14
+ def inspect
15
+ return to_s
16
+ end
17
+
18
+ def to_ruby_type
19
+ raise NotImplementedError
20
+ end
21
+
22
+ def to_c_type
23
+ raise NotImplementedError
24
+ end
25
+
26
+ def is_primitive?
27
+ false
28
+ end
29
+
30
+ def is_union_type?
31
+ false
32
+ end
33
+
34
+ def should_generate_self_arg?
35
+ return true
36
+ end
37
+
38
+ def to_array_type
39
+ # TODO: This should probably not return a union type by default
40
+ return ArrayType.new(self).to_union_type
41
+ end
42
+
43
+ def to_union_type
44
+ return UnionType.new(self)
45
+ end
46
+
47
+ def class_id
48
+ if @class_id == nil
49
+ @class_id = @@next_class_id
50
+ @@next_class_id += 1
51
+ end
52
+
53
+ @class_id
54
+ end
55
+
56
+ def eql?(other)
57
+ return self == other
58
+ end
59
+
60
+ def hash
61
+ # TODO: Implement
62
+ return 0
63
+ end
64
+ end
65
+
66
+ # This type is marker and denotes that an expression should be executed only in the Ruby
67
+ # interpreter. No CUDA code should be generated for such expressions.
68
+ class InterpreterOnlyType
69
+ include RubyType
70
+
71
+ def self.new
72
+ if @singleton_instance == nil
73
+ @singleton_instance = super
74
+ end
75
+
76
+ return @singleton_instance
77
+ end
78
+ end
79
+ end
80
+ end
81
+
82
+ class Array
83
+ def to_type_array_string
84
+ "[" + map do |set|
85
+ set.to_s
86
+ end.join(", ") + "]"
87
+ end
88
+ end
@@ -0,0 +1,179 @@
1
+ # No explicit `require`s. This file should be includes via types.rb
2
+
3
+ require "ffi"
4
+
5
+ module Ikra
6
+ module Types
7
+ # This type represents a C++ struct. It has fields, each of which has
8
+ # a type.
9
+ class StructType
10
+ include RubyType
11
+
12
+ attr_reader :fields
13
+
14
+ class << self
15
+ # Ensure singleton per class
16
+ def new(fields)
17
+ if @cache == nil
18
+ @cache = {}
19
+ end
20
+
21
+ if not @cache.include?(identifier_from_hash(fields))
22
+ @cache[identifier_from_hash(fields)] = super(fields)
23
+ end
24
+
25
+ @cache[identifier_from_hash(fields)]
26
+ end
27
+
28
+ # Generates a unique type identifier based on the types of the struct fields.
29
+ def identifier_from_hash(fields)
30
+ identifier = "indexed_struct_#{fields.size}_lt_"
31
+
32
+ type_parts = fields.map do |key, value|
33
+ value.to_c_type
34
+ end
35
+
36
+ identifier = identifier + type_parts.join("_")
37
+
38
+ return identifier + "_gt_t"
39
+ end
40
+ end
41
+
42
+ def ==(other)
43
+ return other.class == self.class && other.fields == self.fields
44
+ end
45
+
46
+ def initialize(fields)
47
+ fields.each do |key, value|
48
+ if not value.is_union_type?
49
+ raise AssertionError.new("Union type expected for field #{key}")
50
+ end
51
+ end
52
+
53
+ @fields = fields
54
+ end
55
+
56
+ def to_c_type
57
+ return StructType.identifier_from_hash(@fields)
58
+ end
59
+
60
+ def to_ffi_type
61
+ # TODO: Support transfering zipped data back from GPU
62
+ return to_ruby_type
63
+ end
64
+
65
+ def to_ruby_type
66
+ # TODO: general structs
67
+ raise NotImplementedError.new
68
+ end
69
+ end
70
+
71
+ # This type represents the type of an array that is the result of
72
+ # zipping two arrays. [ZipStructType] is similar to [StructType] but
73
+ # can be accessed via indices.
74
+ class ZipStructType < StructType
75
+ class << self
76
+ def new(*types)
77
+ identifiers = Array.new(types.size) do |index|
78
+ :"field_#{index}"
79
+ end
80
+
81
+ super(Hash[identifiers.zip(types)])
82
+ end
83
+ end
84
+
85
+ # Performs type inference for the result of accessing this Zip "Array" by index.
86
+ def get_return_type(selector, *arg_nodes)
87
+ # TODO: Can only handle single cases at the moment. This should eventually forward
88
+ # to Array integration code.
89
+
90
+ if selector != :"[]"
91
+ raise AssertionError.new(
92
+ "Selector not supported for ZipStructType: #{selector}")
93
+ end
94
+
95
+ if arg_nodes.size != 1
96
+ raise AssertionError.new("Expected exactly one argument")
97
+ end
98
+
99
+ if arg_nodes.first.class == AST::IntLiteralNode
100
+ if arg_nodes.first.value >= @fields.size
101
+ raise AssertionError.new(
102
+ "ZipStruct index out of bounds: #{arg_nodes.first.value}")
103
+ end
104
+
105
+ return self[arg_nodes.first.value]
106
+ else
107
+ return get_return_type_non_constant(selector)
108
+ end
109
+ end
110
+
111
+ # Performs type inference for the result of accessing this Zip "Array" by index.
112
+ def get_return_type_non_constant(selector)
113
+ # TODO: Can only handle single cases at the moment. This should eventually forward
114
+ # to Array integration code.
115
+
116
+ # TODO: This code assumes that the all struct elements have the same type
117
+ return self[0]
118
+ end
119
+
120
+ # Returns the type of the element at [index].
121
+ def [](index)
122
+ return @fields[:"field_#{index}"]
123
+ end
124
+
125
+ # A module that provides array-like functionality for FFI Struct types.
126
+ module ZipStruct
127
+ def self.included(base)
128
+ base.include(Enumerable)
129
+ end
130
+
131
+ def [](index)
132
+ # Out of bounds: returns nil
133
+ return super(:"field_#{index}")
134
+ end
135
+
136
+ def []=(index, value)
137
+ # TODO: What should we do if the type of a field changes?
138
+
139
+ # Fill up missing slots with `nil`
140
+ for id in (@fields.size)..index
141
+ super(:"field_{id}", nil)
142
+ end
143
+
144
+ super(:"field_{index}", value)
145
+ return value
146
+ end
147
+
148
+ def each(&block)
149
+ for index in 0...(@fields.size)
150
+ yield(self[index])
151
+ end
152
+ end
153
+ end
154
+
155
+ def to_ruby_type
156
+ # Cache struct types
157
+ if @struct_type == nil
158
+ # Create class
159
+ @struct_type = Class.new(FFI::Struct)
160
+ @struct_type.include(ZipStruct)
161
+
162
+ # Define layout of struct
163
+ var_names = Array.new(@fields.size) do |index|
164
+ :"field_#{index}"
165
+ end
166
+
167
+ var_types = var_names.map do |name|
168
+ @fields[name].to_ffi_type
169
+ end
170
+
171
+ layout = var_names.zip(var_types).flatten
172
+ @struct_type.layout(*layout)
173
+ end
174
+
175
+ return @struct_type
176
+ end
177
+ end
178
+ end
179
+ end