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,103 @@
1
+ module Ikra
2
+ module RubyIntegration
3
+ # TODO: Handle non-singleton types
4
+
5
+ TYPE_INT_COERCE_TO_FLOAT = proc do |recv, other|
6
+ if other.include?(FLOAT_S)
7
+ FLOAT
8
+ elsif other.include?(INT_S)
9
+ INT
10
+ else
11
+ # At least one of the types INT_S or FLOAT_S are required
12
+ raise RuntimeError.new("Operation defined numeric values only (found #{other})")
13
+ end
14
+ end
15
+
16
+ TYPE_INT_RETURN_INT = proc do |recv, other|
17
+ if !other.include?(INT_S)
18
+ raise RuntimeError.new("Operation defined Int values only (found #{other})")
19
+ end
20
+
21
+ INT
22
+ end
23
+
24
+ TYPE_NUMERIC_RETURN_BOOL = proc do |recv, other|
25
+ if !other.include?(INT_S) && !other.include?(FLOAT_S)
26
+ raise RuntimeError.new("Expected type Int or Float, found #{other}")
27
+ end
28
+
29
+ BOOL
30
+ end
31
+
32
+ TYPE_BOOL_RETURN_BOOL = proc do |recv, other|
33
+ if !other.include?(BOOL_S)
34
+ raise RuntimeError.new("Expected type Bool, found #{other}")
35
+ end
36
+
37
+ BOOL
38
+ end
39
+
40
+ # TODO: fix int % float
41
+ implement INT_S, :%, TYPE_INT_COERCE_TO_FLOAT, 1, "(#0 % #N1)"
42
+ implement INT_S, :&, TYPE_INT_RETURN_INT, 1, "(#0 & #I1)"
43
+ implement INT_S, :|, TYPE_INT_RETURN_INT, 1, "(#0 | #I1)"
44
+ implement INT_S, :*, TYPE_INT_COERCE_TO_FLOAT, 1, "(#0 * #N1)"
45
+ # TODO: Find better implementation for Int pow
46
+ implement INT_S, :**, INT, 1, "((int) pow((double) #0, (double) #F1))"
47
+ implement INT_S, :+, TYPE_INT_COERCE_TO_FLOAT, 1, "(#0 + #N1)"
48
+ implement INT_S, :-, TYPE_INT_COERCE_TO_FLOAT, 1, "(#0 - #N1)"
49
+ # TODO: Implement unary -
50
+ implement INT_S, :/, TYPE_INT_COERCE_TO_FLOAT, 1, "(#0 / #N1)"
51
+ implement INT_S, :<, TYPE_NUMERIC_RETURN_BOOL, 1, "(#0 < #N1)"
52
+ implement INT_S, :<<, TYPE_INT_RETURN_INT, 1, "(#0 << #I1)"
53
+ implement INT_S, :<=, TYPE_NUMERIC_RETURN_BOOL, 1, "(#0 <= #N1)"
54
+ # TODO: Implement <=>
55
+ implement INT_S, :==, TYPE_NUMERIC_RETURN_BOOL, 1, "(#0 == #N1)"
56
+ implement INT_S, :"!=", TYPE_NUMERIC_RETURN_BOOL, 1, "(#0 != #N1)"
57
+ implement INT_S, :>, TYPE_NUMERIC_RETURN_BOOL, 1, "(#0 > #N1)"
58
+ implement INT_S, :>=, TYPE_NUMERIC_RETURN_BOOL, 1, "(#0 >= #N1)"
59
+ implement INT_S, :>>, TYPE_INT_RETURN_INT, 1, "(#0 >> #I1)"
60
+ implement INT_S, :"^", TYPE_INT_RETURN_INT, 1, "(#0 ^ IN1)"
61
+
62
+ implement INT_S, :abs, INT, 0, "({ int value = #0; value < 0 ? -value : value; })"
63
+ implement INT_S, :bit_length, INT, 1, "({ int value = #0; (int) ceil(log2f(value < 0 ? -value : value + 1)); })"
64
+ implement INT_S, :div, INT, 1, "((int) (#0 / #I1))"
65
+ implement INT_S, :even?, BOOL, 0, "(#0 % 2 == 0)"
66
+ implement INT_S, :fdiv, FLOAT, 1, "(#0 / #F1)"
67
+ implement INT_S, :magnitude, INT, 0, "({ int value = #0; value < 0 ? -value : value; })"
68
+ implement INT_S, :modulo, TYPE_INT_COERCE_TO_FLOAT, 1, "(#0 % #N1)"
69
+ implement INT_S, :odd?, BOOL, 0, "(#0 % 2 != 0)"
70
+ implement INT_S, :size, INT, 0, "sizeof(int)"
71
+ implement INT_S, :next, INT, 0, "(#0 + 1)"
72
+ implement INT_S, :succ, INT, 0, "(#0 + 1)"
73
+ implement INT_S, :zero?, BOOL, 0, "(#0 == 0)"
74
+ implement INT_S, :to_f, FLOAT, 1, "((float) #0)"
75
+ implement INT_S, :to_i, INT, 1, "#0"
76
+
77
+ implement FLOAT_S, :%, FLOAT, 1, "fmodf(#0, #F1)"
78
+ implement FLOAT_S, :*, FLOAT, 1, "(#0 * #N1)"
79
+ implement FLOAT_S, :**, FLOAT, 1, "powf(#0, #F1)"
80
+ implement FLOAT_S, :+, FLOAT, 1, "(#0 + #N1)"
81
+ implement FLOAT_S, :-, FLOAT, 1, "(#0 - #N1)"
82
+ # TODO: Implement unary -
83
+ implement FLOAT_S, :/, FLOAT, 1, "(#0 / #N1)"
84
+ implement FLOAT_S, :<, TYPE_NUMERIC_RETURN_BOOL, 1, "(#0 < #N1)"
85
+ implement FLOAT_S, :<=, TYPE_NUMERIC_RETURN_BOOL, 1, "(#0 <= #N1)"
86
+ # TODO: Implement <=>
87
+ implement FLOAT_S, :==, TYPE_NUMERIC_RETURN_BOOL, 1, "(#0 == #N1)"
88
+ implement FLOAT_S, :"!=", TYPE_NUMERIC_RETURN_BOOL, 1, "(#0 != #N1)"
89
+ implement FLOAT_S, :>, TYPE_NUMERIC_RETURN_BOOL, 1, "(#0 > #N1)"
90
+ implement FLOAT_S, :>=, TYPE_NUMERIC_RETURN_BOOL, 1, "(#0 >= #N1)"
91
+
92
+ implement FLOAT_S, :abs, FLOAT, 1, "fabsf(#0)"
93
+ implement FLOAT_S, :floor, FLOAT, 1, "floorf(#0)"
94
+ implement FLOAT_S, :to_f, FLOAT, 1, "#0"
95
+ implement FLOAT_S, :to_i, INT, 1, "((int) #0)"
96
+
97
+ implement BOOL_S, :&, TYPE_BOOL_RETURN_BOOL, 1, "(#0 & #B1)"
98
+ implement BOOL_S, :"&&", TYPE_BOOL_RETURN_BOOL, 1, "(#0 && #B1)"
99
+ implement BOOL_S, :"^", TYPE_BOOL_RETURN_BOOL, 1, "(#0 ^ #B1)"
100
+ implement BOOL_S, :|, TYPE_BOOL_RETURN_BOOL, 1, "(#0 | #B1)"
101
+ implement BOOL_S, :"||", TYPE_BOOL_RETURN_BOOL, 1, "(#0 || #B1)"
102
+ end
103
+ end
@@ -0,0 +1,16 @@
1
+ module Ikra
2
+ module RubyIntegration
3
+ # No need to do type inference or code generation, if a method is called on an
4
+ # on an instance of one of these classes.
5
+ INTERPRETER_ONLY_CLS_OBJ = [Ikra::Symbolic.singleton_class]
6
+
7
+
8
+ def self.is_interpreter_only?(type)
9
+ if !type.is_a?(Types::ClassType)
10
+ return false
11
+ end
12
+
13
+ return INTERPRETER_ONLY_CLS_OBJ.include?(type.cls)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,32 @@
1
+ module Ikra
2
+ module RubyIntegration
3
+ MATH = Math.singleton_class.to_ikra_type
4
+
5
+ implement MATH, :acos, FLOAT, 1, "acosf(#F0)", pass_self: false
6
+ implement MATH, :acosh, FLOAT, 1, "acoshf(#F0)", pass_self: false
7
+ implement MATH, :asin, FLOAT, 1, "asinf(#F0)", pass_self: false
8
+ implement MATH, :asinh, FLOAT, 1, "asinhf(#F0)", pass_self: false
9
+ implement MATH, :atan, FLOAT, 1, "atanf(#F0)", pass_self: false
10
+ implement MATH, :atan2, FLOAT, 2, "atan2f(#F0, #F1)", pass_self: false
11
+ implement MATH, :atanh, FLOAT, 1, "atanhf(#F0)", pass_self: false
12
+ implement MATH, :cbrt, FLOAT, 1, "cbrtf(#F0)", pass_self: false
13
+ implement MATH, :cos, FLOAT, 1, "cosf(#F0)", pass_self: false
14
+ implement MATH, :cosh, FLOAT, 1, "coshf(#F0)", pass_self: false
15
+ implement MATH, :erf, FLOAT, 1, "erff(#F0)", pass_self: false
16
+ implement MATH, :erfc, FLOAT, 1, "erfcf(#F0)", pass_self: false
17
+ implement MATH, :exp, FLOAT, 1, "expf(#F0)", pass_self: false
18
+ implement MATH, :gamma, FLOAT, 1, "tgammaf(#F0)", pass_self: false
19
+ implement MATH, :hypot, FLOAT, 2, "hypotf(#F0, #F1)", pass_self: false
20
+ implement MATH, :ldexp, FLOAT, 2, "ldexpf(#F0, #F1)", pass_self: false
21
+ implement MATH, :lgamma, FLOAT, 1, "lgammaf(#F0)", pass_self: false
22
+ implement MATH, :log, FLOAT, 1, "logf(#F0)", pass_self: false
23
+ implement MATH, :log10, FLOAT, 1, "log10f(#F0)", pass_self: false
24
+ implement MATH, :log2, FLOAT, 1, "log2f(#F0)", pass_self: false
25
+ implement MATH, :sin, FLOAT, 1, "sinf(#F0)", pass_self: false
26
+ implement MATH, :sinh, FLOAT, 1, "sinhf(#F0)", pass_self: false
27
+ implement MATH, :sqrt, FLOAT, 1, "sqrtf(#F0)", pass_self: false
28
+ implement MATH, :tan, FLOAT, 1, "tanf(#F0)", pass_self: false
29
+ implement MATH, :tanh, FLOAT, 1, "tanhf(#F0)", pass_self: false
30
+ end
31
+ end
32
+
@@ -0,0 +1,256 @@
1
+ require_relative "../types/types"
2
+
3
+ module Ikra
4
+ module RubyIntegration
5
+ INT = Types::UnionType.create_int
6
+ FLOAT = Types::UnionType.create_float
7
+ BOOL = Types::UnionType.create_bool
8
+
9
+ INT_S = INT.singleton_type
10
+ FLOAT_S = FLOAT.singleton_type
11
+ BOOL_S = BOOL.singleton_type
12
+
13
+ class Implementation
14
+ attr_reader :num_params
15
+ attr_reader :implementation
16
+ attr_reader :pass_self
17
+ attr_reader :return_type
18
+
19
+ # If set to true, all argument should have a singleton type. This is required for
20
+ # operations on ArrayCommands (e.g., pzip).
21
+ attr_reader :expect_singleton_args
22
+
23
+ def initialize(
24
+ num_params:,
25
+ return_type:,
26
+ implementation:,
27
+ pass_self: true,
28
+ expect_singleton_args: false)
29
+
30
+ @num_params = num_params
31
+ @implementation = implementation
32
+ @pass_self = pass_self
33
+ @return_type = return_type
34
+ @expect_singleton_args = expect_singleton_args
35
+ end
36
+ end
37
+
38
+ @@impls = {}
39
+ @@impls.default_proc = proc do |hash, key|
40
+ hash[key] = {}
41
+ end
42
+
43
+ def self.implement(
44
+ rcvr_type,
45
+ method_name,
46
+ return_type,
47
+ num_params,
48
+ impl,
49
+ pass_self: true,
50
+ expect_singleton_args: false)
51
+
52
+ @@impls[rcvr_type][method_name] = Implementation.new(
53
+ num_params: num_params,
54
+ return_type: return_type,
55
+ implementation: impl,
56
+ pass_self: pass_self,
57
+ expect_singleton_args: expect_singleton_args)
58
+ end
59
+
60
+ def self.has_implementation?(rcvr_type, method_name)
61
+ return find_impl(rcvr_type, method_name) != nil
62
+ end
63
+
64
+ def self.should_pass_self?(rcvr_type, method_name)
65
+ return find_impl(rcvr_type, method_name).pass_self
66
+ end
67
+
68
+ def self.expect_singleton_args?(rcvr_type, method_name)
69
+ return find_impl(rcvr_type, method_name).expect_singleton_args
70
+ end
71
+
72
+ # Returns the implementation (CUDA source code snippet) for a method with name
73
+ # [method_name] defined on [rcvr_type].
74
+ #
75
+ # This method also receives references to the receiver AST node and to AST nodes for
76
+ # arguments. In most cases, these AST nodes are directly translated to source code
77
+ # using `translator` (a [Translator::ASTTranslator]). However, if an implementation
78
+ # is given through a block ([Proc]), the implementation might decide to not use the
79
+ # translation (e.g., translation of parallel sections in host sections).
80
+ #
81
+ # [receiver] must have a singleton type.
82
+ def self.get_implementation(receiver, method_name, arguments, translator, result_type)
83
+ impl = find_impl(receiver.get_type.singleton_type, method_name)
84
+ source = impl.implementation
85
+
86
+ if source.is_a?(Proc)
87
+ source = source.call(receiver, method_name, arguments, translator, result_type)
88
+ end
89
+
90
+ sub_code = arguments.map do |arg| arg.accept(translator.expression_translator) end
91
+ sub_types = arguments.map do |arg| arg.get_type end
92
+
93
+ if impl.pass_self
94
+ sub_code.insert(0, receiver.accept(translator.expression_translator))
95
+ sub_types.insert(0, receiver.get_type)
96
+ end
97
+
98
+ sub_indices = (0...source.length).find_all do |index|
99
+ source[index] == "#"
100
+ end
101
+ substitutions = {}
102
+ sub_indices.each do |index|
103
+ if source[index + 1] == "F"
104
+ # Insert float
105
+ arg_index = source[index + 2].to_i
106
+
107
+ if arg_index >= sub_code.size
108
+ raise ArgumentError.new("Argument missing: Expected at least #{arg_index + 1}, found #{sub_code.size}")
109
+ end
110
+
111
+ substitutions["\#F#{arg_index}"] = code_argument(FLOAT_S, sub_types[arg_index], sub_code[arg_index])
112
+ elsif source[index + 1] == "I"
113
+ # Insert integer
114
+ arg_index = source[index + 2].to_i
115
+
116
+ if arg_index >= sub_code.size
117
+ raise ArgumentError.new("Argument missing: Expected at least #{arg_index + 1}, found #{sub_code.size}")
118
+ end
119
+
120
+ substitutions["\#I#{arg_index}"] = code_argument(INT_S, sub_types[arg_index], sub_code[arg_index])
121
+ elsif source[index + 1] == "B"
122
+ # Insert integer
123
+ arg_index = source[index + 2].to_i
124
+
125
+ if arg_index >= sub_code.size
126
+ raise ArgumentError.new("Argument missing: Expected at least #{arg_index + 1}, found #{sub_code.size}")
127
+ end
128
+
129
+ substitutions["\#B#{arg_index}"] = code_argument(BOOL_S, sub_types[arg_index], sub_code[arg_index])
130
+ elsif source[index + 1] == "N"
131
+ # Numeric, coerce integer to float
132
+ arg_index = source[index + 2].to_i
133
+
134
+ if arg_index >= sub_code.size
135
+ raise ArgumentError.new("Argument missing: Expected at least #{arg_index + 1}, found #{sub_code.size}")
136
+ end
137
+
138
+ if sub_types[arg_index].include?(FLOAT_S)
139
+ expected_type = FLOAT_S
140
+ else
141
+ expected_type = INT_S
142
+ end
143
+
144
+ substitutions["\#N#{arg_index}"] = code_argument(expected_type, sub_types[arg_index], sub_code[arg_index])
145
+ else
146
+ arg_index = source[index + 1].to_i
147
+
148
+ if arg_index >= sub_code.size
149
+ raise ArgumentError.new("Argument missing: Expected at least #{arg_index + 1}, found #{sub_code.size}")
150
+ end
151
+
152
+ substitutions["\##{arg_index}"] = sub_code[arg_index]
153
+ end
154
+ end
155
+
156
+ substitutions.each do |key, value|
157
+ # Do not use `gsub!` here!
158
+ source = source.gsub(key, value)
159
+ end
160
+
161
+ return source
162
+ end
163
+
164
+ # Retrieves the return type of a method invocation for receiver type [rcvr_type],
165
+ # selector [method_name], and argument types [arg_types].
166
+ #
167
+ # In addition, this method accepts an optional parameter [node] containing the send node
168
+ # (abstract syntax tree node). That node is passed to type inference procs. This is
169
+ # required for symbolic execution of array commands inside host sections.
170
+ def self.get_return_type(rcvr_type, method_name, *arg_types, send_node: nil)
171
+ return_type = find_impl(rcvr_type, method_name).return_type
172
+ num_params = find_impl(rcvr_type, method_name).num_params
173
+
174
+ if return_type.is_a?(Proc)
175
+ # Return type depends on argument types
176
+ if num_params.is_a?(Fixnum) && num_params != arg_types.size
177
+ raise ArgumentError.new(
178
+ "#{num_params} arguments expected but #{arg_types.size} given")
179
+ elsif num_params.is_a?(Range) && !num_params.include?(arg_types.size)
180
+ raise ArgumentError.new(
181
+ "#{num_params} arguments expected but #{arg_types.size} given")
182
+ else
183
+ if send_node == nil
184
+ return return_type.call(rcvr_type, *arg_types)
185
+ else
186
+ return return_type.call(rcvr_type, *arg_types, send_node: send_node)
187
+ end
188
+ end
189
+ else
190
+ return return_type
191
+ end
192
+ end
193
+
194
+ private
195
+
196
+ def self.code_argument(expected_type, arg_type, code)
197
+ if arg_type.is_singleton?
198
+ if expected_type != arg_type.singleton_type
199
+ # Try to cast
200
+ return "((#{expected_type.to_c_type}) #{code})"
201
+ else
202
+ return code
203
+ end
204
+ else
205
+ # Extract from union type
206
+ result = StringIO.new
207
+
208
+ result << "({ union_t arg = #{code};\n"
209
+ result << " #{expected_type.to_c_type} result;\n"
210
+ result << " switch (arg.class_id) {\n"
211
+
212
+ for type in arg_type
213
+ c_type = expected_type.to_c_type
214
+ result << " case #{type.class_id}:\n"
215
+ # TODO: This works only for primitive types
216
+ result << " result = (#{c_type}) arg.value.#{type.to_c_type}_;\n"
217
+ result << " break;\n"
218
+ end
219
+
220
+ result << " default:\n"
221
+ result << " // TODO: throw exception\n"
222
+ result << " }\n"
223
+ result << " result;\n"
224
+ result << "})"
225
+
226
+ return result.string
227
+ end
228
+ end
229
+
230
+ def self.find_impl(rcvr_type, method_name)
231
+ if @@impls.include?(rcvr_type) && @@impls[rcvr_type].include?(method_name)
232
+ return @@impls[rcvr_type][method_name]
233
+ else
234
+ # Evaluate blocks
235
+ for type_or_block in @@impls.keys
236
+ if type_or_block.is_a?(Proc)
237
+ if type_or_block.call(rcvr_type)
238
+ if @@impls[type_or_block].include?(method_name)
239
+ return @@impls[type_or_block][method_name]
240
+ end
241
+ end
242
+ end
243
+ end
244
+
245
+ # No implementation found
246
+ return nil
247
+ end
248
+ end
249
+ end
250
+ end
251
+
252
+ require_relative "core"
253
+ require_relative "math"
254
+ require_relative "array"
255
+ require_relative "array_command"
256
+ require_relative "interpreter"
@@ -0,0 +1,115 @@
1
+ require_relative "../ast/host_section_builder"
2
+
3
+ module Ikra
4
+ module Symbolic
5
+ # The return value of a host section. For the moment, every host section can only have
6
+ # one result.
7
+ class ArrayHostSectionCommand
8
+ include ArrayCommand
9
+
10
+ attr_reader :block
11
+ attr_reader :section_input
12
+
13
+ def initialize(*section_input, &block)
14
+ @block = block
15
+ @section_input = section_input
16
+ end
17
+
18
+ def size
19
+ execute
20
+ return @result.size
21
+ end
22
+
23
+ # Returns the abstract syntax tree for this section.
24
+ def block_def_node
25
+ if @ast == nil
26
+ # Get array of block parameter names
27
+ block_params = block.parameters.map do |param|
28
+ param[1]
29
+ end
30
+
31
+ parser_local_vars = command_binding.local_variables + block_params
32
+ source = Parsing.parse_block(block, parser_local_vars)
33
+ @ast = AST::BlockDefNode.new(
34
+ parameters: block_params,
35
+ ruby_block: block, # necessary to get binding
36
+ body: AST::HostSectionBuilder.from_parser_ast(source))
37
+ end
38
+
39
+ return @ast
40
+ end
41
+
42
+ def command_translator_class
43
+ return Translator::HostSectionCommandTranslator
44
+ end
45
+
46
+ class Binding
47
+ def local_variables
48
+
49
+ end
50
+ end
51
+ end
52
+
53
+ # An array that that is referenced using C++/CUDA expressions. Such an array does not
54
+ # necessarily have to be present in the Ruby interpreter. Its size does also not have to
55
+ # be known at compile time.
56
+ class ArrayInHostSectionCommand
57
+ include ArrayCommand
58
+
59
+ attr_accessor :target
60
+ attr_accessor :base_type
61
+
62
+ def initialize(target, base_type, block_size: DEFAULT_BLOCK_SIZE)
63
+ super(block_size: block_size)
64
+
65
+ if base_type == nil
66
+ raise AssertionError.new("base_type missing")
67
+ end
68
+
69
+ # One thread per array element
70
+ @input = [SingleInput.new(command: target, pattern: :tid)]
71
+ @base_type = base_type
72
+ end
73
+
74
+ def size
75
+ # Size is not known at compile time. Return a source code string here.
76
+ return "#{input.first.command}->size()"
77
+ end
78
+
79
+ # TODO: Support multiple dimensions
80
+ def dimensions
81
+ return [size]
82
+ end
83
+
84
+ def ==(other)
85
+ return super(other) && base_type == other.base_type
86
+ end
87
+ end
88
+
89
+ class FixedSizeArrayInHostSectionCommand < ArrayInHostSectionCommand
90
+ include ArrayCommand
91
+
92
+ attr_accessor :target
93
+ attr_accessor :base_type
94
+ attr_accessor :dimensions
95
+
96
+ def initialize(target, base_type, dimensions, block_size: DEFAULT_BLOCK_SIZE)
97
+ super(target, base_type, block_size: block_size)
98
+
99
+ @dimensions = dimensions
100
+ end
101
+
102
+ def size
103
+ return dimensions.reduce(:*)
104
+ end
105
+
106
+ def ==(other)
107
+ return super(other) && dimensions == other.dimensions
108
+ end
109
+ end
110
+
111
+ def self.host_section(*section_input, &block)
112
+ return ArrayHostSectionCommand.new(*section_input, &block)
113
+ end
114
+ end
115
+ end