ikra 0.0.1 → 0.0.2

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.
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,11 @@
1
+ module Ikra
2
+ module TypeInference
3
+ class ClearTypesVisitor < AST::Visitor
4
+ def visit_node(node)
5
+ if node.respond_to?(:get_type)
6
+ node.get_type.clear!
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,101 @@
1
+ module Ikra
2
+ module TypeInference
3
+ class CommandInference < Symbolic::Visitor
4
+ def self.process_command(command)
5
+ return command.accept(CommandInference.new)
6
+ end
7
+
8
+ # Processes a parallel section, i.e., a [BlockDefNode]. Performs the following steps:
9
+ # 1. Gather parameter types and names in a hash map.
10
+ # 2. Set lexical variables on [BlockDefNode].
11
+ # 3. Perform type inference, i.e., annotate [BlockDefNode] AST with types.
12
+ # 4. Return result type of the block.
13
+ def process_block(
14
+ block_def_node:,
15
+ lexical_variables: {},
16
+ block_parameters:)
17
+
18
+ # Build hash of parameter name -> type mappings
19
+ block_parameter_types = {}
20
+ for variable in block_parameters
21
+ block_parameter_types[variable.name] = variable.type
22
+ end
23
+
24
+ parameter_types_string = "[" + block_parameter_types.map do |id, type| "#{id}: #{type}" end.join(", ") + "]"
25
+ Log.info("Type inference for block with input types #{parameter_types_string}")
26
+
27
+ # Add information to block_def_node
28
+ block_def_node.parameters_names_and_types = block_parameter_types
29
+
30
+ # Lexical variables
31
+ lexical_variables.each do |name, value|
32
+ block_def_node.lexical_variables_names_and_types[name] = value.ikra_type.to_union_type
33
+ end
34
+
35
+ # Type inference
36
+ type_inference_visitor = TypeInference::Visitor.new
37
+ return_type = type_inference_visitor.process_block(block_def_node)
38
+
39
+ return return_type
40
+ end
41
+
42
+ # Processes all input commands. This is similar to `translate_entire_input`, but it
43
+ # performs only type inference and does not generate any source code.
44
+ def process_entire_input(command)
45
+ input_parameters = command.input.each_with_index.map do |input, index|
46
+ input.get_parameters(
47
+ parent_command: command,
48
+ # Assuming that every input consumes exactly one parameter
49
+ start_eat_params_offset: index)
50
+ end
51
+
52
+ return input_parameters.reduce(:+)
53
+ end
54
+
55
+ # Process block and dependent computations. This method is used for all array
56
+ # commands that do not have a separate Visitor method.
57
+ def visit_array_command(command)
58
+ return process_block(
59
+ block_def_node: command.block_def_node,
60
+ lexical_variables: command.lexical_externals,
61
+ block_parameters: process_entire_input(command))
62
+ end
63
+
64
+ def visit_array_in_host_section_command(command)
65
+ return command.base_type
66
+ end
67
+
68
+ def visit_array_identity_command(command)
69
+ return command.base_type
70
+ end
71
+
72
+ def visit_array_index_command(command)
73
+ num_dims = command.dimensions.size
74
+
75
+ if num_dims > 1
76
+ # Build Ikra struct type
77
+ zipped_type_singleton = Types::ZipStructType.new(
78
+ *([Types::UnionType.create_int] * command.dimensions.size))
79
+ return zipped_type_singleton.to_union_type
80
+ else
81
+ return Types::UnionType.create_int
82
+ end
83
+ end
84
+
85
+ def visit_array_zip_command(command)
86
+ input_types = command.input.each_with_index.map do |input, index|
87
+ input.get_parameters(
88
+ parent_command: command,
89
+ # Assuming that every input consumes exactly one parameter
90
+ start_eat_params_offset: index).map do |variable|
91
+ variable.type
92
+ end
93
+ end.reduce(:+)
94
+
95
+ # Build Ikra struct type
96
+ zipped_type_singleton = Types::ZipStructType.new(*input_types)
97
+ return zipped_type_singleton.to_union_type
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,62 @@
1
+ module Ikra
2
+ module Symbolic
3
+ class Input
4
+ def get_parameters(**kwargs)
5
+ raise NotImplementedError.new
6
+ end
7
+ end
8
+
9
+ class SingleInput < Input
10
+ def get_parameters(parent_command:, start_eat_params_offset: 0)
11
+ return [Translator::Variable.new(
12
+ name: parent_command.block_parameter_names[start_eat_params_offset],
13
+ type: command.result_type)]
14
+ end
15
+ end
16
+
17
+ class ReduceInput < SingleInput
18
+ def get_parameters(parent_command:, start_eat_params_offset: 0)
19
+ # TODO: Fix type inference (sometimes type has to be expanded)
20
+
21
+ return [
22
+ Translator::Variable.new(
23
+ name: parent_command.block_parameter_names[start_eat_params_offset],
24
+ type: command.result_type),
25
+ Translator::Variable.new(
26
+ name: parent_command.block_parameter_names[start_eat_params_offset + 1],
27
+ type: command.result_type)]
28
+ end
29
+ end
30
+
31
+ class StencilArrayInput < Input
32
+ def get_parameters(parent_command:, start_eat_params_offset: 0)
33
+ # Parameters are allocated in a constant-sized array
34
+
35
+ return [Translator::Variable.new(
36
+ name: parent_command.block_parameter_names[start_eat_params_offset],
37
+ type: command.result_type.to_array_type)]
38
+ end
39
+ end
40
+
41
+ class StencilSingleInput < Input
42
+ def get_parameters(parent_command:, start_eat_params_offset: 0)
43
+ # Pass separate parameters
44
+
45
+ # Count number of parameters
46
+ num_parameters = parent_command.offsets.size
47
+
48
+ # Take return type from previous computation
49
+ parameters = []
50
+ for index in start_eat_params_offset...(start_eat_params_offset + num_parameters)
51
+ parameters.push(Translator::Variable.new(
52
+ name: parent_command.block_parameter_names[index],
53
+ type: command.result_type))
54
+ end
55
+
56
+ return parameters
57
+ end
58
+ end
59
+ end
60
+
61
+
62
+ end
@@ -1,9 +1,8 @@
1
1
  require "set"
2
2
  require "ffi"
3
- require_relative "../entity"
4
- require_relative "class_type"
5
- require_relative "../symbolic/symbolic"
6
- require_relative "../translator/command_translator"
3
+ require_relative "../../entity"
4
+ require_relative "../../symbolic/symbolic"
5
+ require_relative "../../translator/commands/command_translator"
7
6
 
8
7
  module Ikra
9
8
  module TypeInference
@@ -48,10 +47,10 @@ module Ikra
48
47
 
49
48
  object.instance_variables.each do |inst_var_name|
50
49
  value = object.instance_variable_get(inst_var_name)
51
- value_type = value.class.to_ikra_type
50
+ value_type = value.ikra_type
52
51
 
53
52
  # Gather type information
54
- object.class.to_ikra_type.inst_vars_types[inst_var_name].expand_with_singleton_type(value_type)
53
+ object.ikra_type.inst_vars_types[inst_var_name].add(value_type)
55
54
 
56
55
  if value.class.include?(Entity)
57
56
  # Keep tracing this object
@@ -0,0 +1,35 @@
1
+ # No explicit `require`s. This file should be includes via types.rb
2
+
3
+ require "set"
4
+
5
+ class Fixnum
6
+ class << self
7
+ def to_ikra_type
8
+ Ikra::Types::PrimitiveType::Int
9
+ end
10
+ end
11
+ end
12
+
13
+ class Float
14
+ class << self
15
+ def to_ikra_type
16
+ Ikra::Types::PrimitiveType::Float
17
+ end
18
+ end
19
+ end
20
+
21
+ class TrueClass
22
+ class << self
23
+ def to_ikra_type
24
+ Ikra::Types::PrimitiveType::Bool
25
+ end
26
+ end
27
+ end
28
+
29
+ class FalseClass
30
+ class << self
31
+ def to_ikra_type
32
+ Ikra::Types::PrimitiveType::Bool
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,131 @@
1
+ # No explicit `require`s. This file should be includes via types.rb
2
+
3
+ module Ikra
4
+ module TypeInference
5
+ # This is a symbol table that stores type information about variables. Ruby has a "flat"
6
+ # variable scope in method, i.e., variables defined in loop bodies, if statement bodies,
7
+ # or begin nodes are also visible outside of them.
8
+ #
9
+ # Every method/block has its own symbol table.
10
+ class SymbolTable
11
+
12
+ # Represents a lexical or local variable. Variables have a type and can read and/or
13
+ # written, all of which is stored in this class.
14
+ class Variable
15
+ attr_reader :type
16
+
17
+ # Determines the kind of the variables: lexial or local
18
+ attr_reader :kind
19
+
20
+ attr_accessor :read
21
+ attr_accessor :written
22
+
23
+ def initialize(type: Types::UnionType.new, kind: :local)
24
+ @type = type.dup
25
+ @kind = kind
26
+ @read = false
27
+ @written = false
28
+ end
29
+ end
30
+
31
+ attr_reader :return_type
32
+
33
+ # For debug purposes
34
+ attr_reader :symbols
35
+
36
+ def initialize
37
+ # This is a mapping from variable names to Variable instances.
38
+ @symbols = {}
39
+ @return_type = Types::UnionType.new
40
+ end
41
+
42
+ def clear!
43
+ @symbols = {}
44
+ end
45
+
46
+ def [](variable_name)
47
+ if !has_variable?(variable_name)
48
+ raise AssertionError.new("Variable #{variable_name} not defined")
49
+ end
50
+
51
+ return @symbols[variable_name].type
52
+ end
53
+
54
+ def read!(variable_name)
55
+ if !has_variable?(variable_name)
56
+ raise AssertionError.new(
57
+ "Variable #{variable_name} read but not found in symbol table")
58
+ end
59
+
60
+ @symbols[variable_name].read = true
61
+ end
62
+
63
+ def written!(variable_name)
64
+ if !has_variable?(variable_name)
65
+ raise AssertionError.new(
66
+ "Variable #{variable_name} written but not found in symbol table")
67
+ end
68
+
69
+ @symbols[variable_name].written = true
70
+ end
71
+
72
+ def read_variables
73
+ return @symbols.select do |k, v|
74
+ v.read
75
+ end.keys
76
+ end
77
+
78
+ def written_variables
79
+ return @symbols.select do |k, v|
80
+ v.written
81
+ end.keys
82
+ end
83
+
84
+ def read_and_written_variables
85
+ return read_variables + written_variables
86
+ end
87
+
88
+ def expand_type(variable_name, type)
89
+ if !has_variable?(variable_name)
90
+ raise AssertionError.new(
91
+ "Attempt to expand type of variable #{variable_name} but not found in " +
92
+ " symbol table")
93
+ end
94
+
95
+ @symbols[variable_name].type.expand(type)
96
+ end
97
+
98
+ def expand_return_type(type)
99
+ @return_type.expand(type)
100
+ end
101
+
102
+ def return_type
103
+ return @return_type
104
+ end
105
+
106
+ # Declares a local variable. This method should be used only for regular local
107
+ # variables (not parameters). Does not shadow lexical variables.
108
+ def ensure_variable_declared(variable_name, type: Types::UnionType.new, kind: :local)
109
+ if !has_variable?(variable_name)
110
+ declare_variable(variable_name, type: type, kind: kind)
111
+ else
112
+ # Extend type of variable
113
+ expand_type(variable_name, type)
114
+ end
115
+ end
116
+
117
+ # Declares a local variable and overwrites (shadows) existing variables
118
+ # (lexical variables). Use this method for method/block parameters.
119
+ def declare_variable(variable_name, type: Types::UnionType.new, kind: :local)
120
+ @symbols[variable_name] = Variable.new(type: Types::UnionType.new, kind: kind)
121
+ expand_type(variable_name, type)
122
+ end
123
+
124
+ private
125
+
126
+ def has_variable?(variable_name)
127
+ return @symbols.include?(variable_name)
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,14 @@
1
+ require_relative "types/ruby_type"
2
+ require_relative "types/array_type"
3
+ require_relative "types/class_type"
4
+ require_relative "types/primitive_type"
5
+ require_relative "types/union_type"
6
+ require_relative "types/struct_type"
7
+ require_relative "types/array_command_type"
8
+
9
+ require_relative "inference/object_tracer"
10
+ require_relative "inference/ruby_extension"
11
+ require_relative "inference/symbol_table"
12
+ require_relative "inference/ast_inference"
13
+ require_relative "inference/input_inference"
14
+ require_relative "inference/command_inference"
@@ -0,0 +1,123 @@
1
+ require "weakref"
2
+
3
+ module Ikra
4
+ module Symbolic
5
+ module ArrayCommand
6
+ include Types::RubyType
7
+
8
+ def self.included(base)
9
+ base.extend(ClassMethods)
10
+ end
11
+
12
+ module ClassMethods
13
+ # TODO: Check what was wrong with the subclassed Hash...
14
+ class WeakCache
15
+ def initialize
16
+ @values = []
17
+ end
18
+
19
+ def get_value(value)
20
+ @values.delete_if do |obj|
21
+ begin
22
+ if obj == value
23
+ return obj.__getobj__
24
+ end
25
+ rescue WeakRef::RefError
26
+ true
27
+ end
28
+ end
29
+
30
+ raise RuntimeError.new("Value not found")
31
+ end
32
+
33
+ def add_value(value)
34
+ @values.push(WeakRef.new(value))
35
+ end
36
+
37
+ def include?(value)
38
+ @values.delete_if do |obj|
39
+ begin
40
+ if obj == value
41
+ return true
42
+ end
43
+ rescue WeakRef::RefError
44
+ true
45
+ end
46
+ end
47
+
48
+ return false
49
+ end
50
+ end
51
+
52
+ class NormalCache
53
+ def initialize
54
+ @values = []
55
+ end
56
+
57
+ def get_value(value)
58
+ for el in @values
59
+ if el == value
60
+ return el
61
+ end
62
+ end
63
+
64
+ raise RuntimeError.new("Value not found")
65
+ end
66
+
67
+ def add_value(value)
68
+ @values.push(value)
69
+ end
70
+
71
+ def include?(value)
72
+ return @values.include?(value)
73
+ end
74
+ end
75
+
76
+ # Ensure that ArrayCommands are singletons. Otherwise, we have a problem, because
77
+ # two equal commands can have different class IDs.
78
+ def new(*args, **kwargs, &block)
79
+ if @cache == nil
80
+ @cache = WeakCache.new
81
+ end
82
+
83
+ new_command = super
84
+
85
+ if @cache.include?(new_command)
86
+ return @cache.get_value(new_command)
87
+ else
88
+ @cache.add_value(new_command)
89
+ return new_command
90
+ end
91
+ end
92
+ end
93
+
94
+ def to_c_type
95
+ return "#{Translator::ArrayCommandStructBuilder.struct_name(self)} *"
96
+ end
97
+
98
+ def to_ffi_type
99
+ # TODO: This method is probably not required?
100
+ return :pointer
101
+ end
102
+
103
+ def to_ruby_type
104
+ return ArrayCommand
105
+ end
106
+
107
+ # Every [ArrayCommand] has itself as an Ikra type. This integrates well with the
108
+ # current type inference approach and `ruby_core`.
109
+ def ikra_type
110
+ return self
111
+ end
112
+
113
+ def result_type
114
+ # Result cache should be cached, just like the result itself
115
+ if @result_type == nil
116
+ @result_type = TypeInference::CommandInference.process_command(self)
117
+ end
118
+
119
+ return @result_type
120
+ end
121
+ end
122
+ end
123
+ end