ikra 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (220) hide show
  1. checksums.yaml +7 -0
  2. data/lib/ast/builder.rb +100 -0
  3. data/lib/ast/lexical_variables_enumerator.rb +34 -0
  4. data/lib/ast/method_definition.rb +37 -0
  5. data/lib/ast/nodes.rb +208 -0
  6. data/lib/ast/printer.rb +99 -0
  7. data/lib/ast/translator.rb +264 -0
  8. data/lib/ast/visitor.rb +173 -0
  9. data/lib/config/configuration.rb +18 -0
  10. data/lib/config/os_configuration.rb +56 -0
  11. data/lib/entity.rb +11 -0
  12. data/lib/ikra.rb +7 -0
  13. data/lib/parsing.rb +32 -0
  14. data/lib/resources/cuda/block_function_head.cpp +1 -0
  15. data/lib/resources/cuda/env_builder_copy_array.cpp +4 -0
  16. data/lib/resources/cuda/header.cpp +46 -0
  17. data/lib/resources/cuda/kernel.cpp +8 -0
  18. data/lib/resources/cuda/kernel_launcher.cpp +28 -0
  19. data/lib/resources/cuda/soa_header.cpp +4 -0
  20. data/lib/scope.rb +166 -0
  21. data/lib/sourcify/Gemfile +10 -0
  22. data/lib/sourcify/HISTORY.txt +88 -0
  23. data/lib/sourcify/LICENSE +20 -0
  24. data/lib/sourcify/README.rdoc +352 -0
  25. data/lib/sourcify/Rakefile +111 -0
  26. data/lib/sourcify/lib/sourcify.rb +44 -0
  27. data/lib/sourcify/lib/sourcify/common/parser/converter.rb +29 -0
  28. data/lib/sourcify/lib/sourcify/common/parser/raw_scanner/comment.rb +23 -0
  29. data/lib/sourcify/lib/sourcify/common/parser/raw_scanner/counter.rb +43 -0
  30. data/lib/sourcify/lib/sourcify/common/parser/raw_scanner/dstring.rb +58 -0
  31. data/lib/sourcify/lib/sourcify/common/parser/raw_scanner/extensions.rb +140 -0
  32. data/lib/sourcify/lib/sourcify/common/parser/raw_scanner/heredoc.rb +26 -0
  33. data/lib/sourcify/lib/sourcify/common/parser/source_code.rb +45 -0
  34. data/lib/sourcify/lib/sourcify/common/ragel/common.rl +5 -0
  35. data/lib/sourcify/lib/sourcify/common/ragel/expressions.rl +38 -0
  36. data/lib/sourcify/lib/sourcify/common/ragel/machines.rl +317 -0
  37. data/lib/sourcify/lib/sourcify/errors.rb +4 -0
  38. data/lib/sourcify/lib/sourcify/method.rb +138 -0
  39. data/lib/sourcify/lib/sourcify/method/methods.rb +3 -0
  40. data/lib/sourcify/lib/sourcify/method/methods/to_raw_source.rb +30 -0
  41. data/lib/sourcify/lib/sourcify/method/methods/to_sexp.rb +30 -0
  42. data/lib/sourcify/lib/sourcify/method/methods/to_source.rb +30 -0
  43. data/lib/sourcify/lib/sourcify/method/parser.rb +110 -0
  44. data/lib/sourcify/lib/sourcify/method/parser/converter.rb +8 -0
  45. data/lib/sourcify/lib/sourcify/method/parser/raw_scanner.rb +2494 -0
  46. data/lib/sourcify/lib/sourcify/method/parser/raw_scanner.rl +144 -0
  47. data/lib/sourcify/lib/sourcify/method/parser/raw_scanner_extensions.rb +68 -0
  48. data/lib/sourcify/lib/sourcify/method/parser/scanner.rb +52 -0
  49. data/lib/sourcify/lib/sourcify/method/parser/source_code.rb +8 -0
  50. data/lib/sourcify/lib/sourcify/patches.rb +63 -0
  51. data/lib/sourcify/lib/sourcify/proc.rb +183 -0
  52. data/lib/sourcify/lib/sourcify/proc/methods.rb +3 -0
  53. data/lib/sourcify/lib/sourcify/proc/methods/source_location.rb +61 -0
  54. data/lib/sourcify/lib/sourcify/proc/methods/to_raw_source.rb +20 -0
  55. data/lib/sourcify/lib/sourcify/proc/methods/to_sexp.rb +40 -0
  56. data/lib/sourcify/lib/sourcify/proc/methods/to_source.rb +48 -0
  57. data/lib/sourcify/lib/sourcify/proc/parser.rb +51 -0
  58. data/lib/sourcify/lib/sourcify/proc/parser/converter.rb +8 -0
  59. data/lib/sourcify/lib/sourcify/proc/parser/normalizer.rb +43 -0
  60. data/lib/sourcify/lib/sourcify/proc/parser/raw_scanner.rb +2498 -0
  61. data/lib/sourcify/lib/sourcify/proc/parser/raw_scanner.rl +149 -0
  62. data/lib/sourcify/lib/sourcify/proc/parser/raw_scanner_extensions.rb +74 -0
  63. data/lib/sourcify/lib/sourcify/proc/parser/scanner.rb +49 -0
  64. data/lib/sourcify/lib/sourcify/proc/parser/source_code.rb +8 -0
  65. data/lib/sourcify/lib/sourcify/version.rb +3 -0
  66. data/lib/sourcify/sourcify.gemspec +31 -0
  67. data/lib/sourcify/spec/dump_object_space_procs.rb +84 -0
  68. data/lib/sourcify/spec/method/encoding_from_def_end_block_spec.rb +33 -0
  69. data/lib/sourcify/spec/method/encoding_from_define_method_spec.rb +37 -0
  70. data/lib/sourcify/spec/method/others_from_def_end_block_spec.rb +49 -0
  71. data/lib/sourcify/spec/method/others_from_define_method_spec.rb +63 -0
  72. data/lib/sourcify/spec/method/raw_scanner/block_comment_spec.rb +8 -0
  73. data/lib/sourcify/spec/method/raw_scanner/double_colons_spec.rb +8 -0
  74. data/lib/sourcify/spec/method/raw_scanner/double_quote_str_w_interpolation_spec.rb +8 -0
  75. data/lib/sourcify/spec/method/raw_scanner/double_quote_str_wo_interpolation_spec.rb +8 -0
  76. data/lib/sourcify/spec/method/raw_scanner/heredoc_w_indent_spec.rb +8 -0
  77. data/lib/sourcify/spec/method/raw_scanner/heredoc_wo_indent_spec.rb +8 -0
  78. data/lib/sourcify/spec/method/raw_scanner/kw_block_start_alias1_spec.rb +20 -0
  79. data/lib/sourcify/spec/method/raw_scanner/kw_block_start_alias2_spec.rb +20 -0
  80. data/lib/sourcify/spec/method/raw_scanner/per_line_comment_spec.rb +8 -0
  81. data/lib/sourcify/spec/method/raw_scanner/single_quote_str_spec.rb +8 -0
  82. data/lib/sourcify/spec/method/raw_scanner/slash_operator_spec.rb +8 -0
  83. data/lib/sourcify/spec/method/raw_scanner/spec_helper.rb +80 -0
  84. data/lib/sourcify/spec/method/spec_helper.rb +1 -0
  85. data/lib/sourcify/spec/method/to_raw_source_spec.rb +31 -0
  86. data/lib/sourcify/spec/method/to_raw_source_w_specified_strip_enclosure_spec.rb +148 -0
  87. data/lib/sourcify/spec/method/to_sexp_from_def_end_block_w_variables_spec.rb +46 -0
  88. data/lib/sourcify/spec/method/to_sexp_from_def_end_block_within_irb_spec.rb +38 -0
  89. data/lib/sourcify/spec/method/to_sexp_from_def_end_block_within_pry_spec.rb +38 -0
  90. data/lib/sourcify/spec/method/to_sexp_from_define_method_w_multi_blocks_and_specified_attached_to_spec.rb +56 -0
  91. data/lib/sourcify/spec/method/to_sexp_from_define_method_w_variables_spec.rb +52 -0
  92. data/lib/sourcify/spec/method/to_sexp_from_define_method_within_irb_spec.rb +42 -0
  93. data/lib/sourcify/spec/method/to_sexp_from_define_method_within_pry_spec.rb +42 -0
  94. data/lib/sourcify/spec/method/to_sexp_w_specified_strip_enclosure_spec.rb +74 -0
  95. data/lib/sourcify/spec/method/to_source_from_def_end_block_w_19_extras_spec.rb +23 -0
  96. data/lib/sourcify/spec/method/to_source_from_def_end_block_w_nested_begin_spec.rb +35 -0
  97. data/lib/sourcify/spec/method/to_source_from_def_end_block_w_nested_case_spec.rb +35 -0
  98. data/lib/sourcify/spec/method/to_source_from_def_end_block_w_nested_class_spec.rb +51 -0
  99. data/lib/sourcify/spec/method/to_source_from_def_end_block_w_nested_do_end_block_spec.rb +33 -0
  100. data/lib/sourcify/spec/method/to_source_from_def_end_block_w_nested_for_spec.rb +126 -0
  101. data/lib/sourcify/spec/method/to_source_from_def_end_block_w_nested_if_spec.rb +83 -0
  102. data/lib/sourcify/spec/method/to_source_from_def_end_block_w_nested_literal_keyword_spec.rb +141 -0
  103. data/lib/sourcify/spec/method/to_source_from_def_end_block_w_nested_method_spec.rb +33 -0
  104. data/lib/sourcify/spec/method/to_source_from_def_end_block_w_nested_module_spec.rb +59 -0
  105. data/lib/sourcify/spec/method/to_source_from_def_end_block_w_nested_unless_spec.rb +83 -0
  106. data/lib/sourcify/spec/method/to_source_from_def_end_block_w_nested_until_spec.rb +179 -0
  107. data/lib/sourcify/spec/method/to_source_from_def_end_block_w_nested_while_spec.rb +179 -0
  108. data/lib/sourcify/spec/method/to_source_from_def_end_block_w_singleton_method_spec.rb +19 -0
  109. data/lib/sourcify/spec/method/to_source_from_def_end_block_within_irb_spec.rb +30 -0
  110. data/lib/sourcify/spec/method/to_source_from_def_end_block_within_pry_spec.rb +45 -0
  111. data/lib/sourcify/spec/method/to_source_from_def_end_w_multi_blocks_and_many_matches_spec.rb +30 -0
  112. data/lib/sourcify/spec/method/to_source_from_def_end_w_multi_blocks_and_single_match_spec.rb +36 -0
  113. data/lib/sourcify/spec/method/to_source_from_define_method_w_braced_block_spec.rb +113 -0
  114. data/lib/sourcify/spec/method/to_source_from_define_method_w_do_end_block_spec.rb +145 -0
  115. data/lib/sourcify/spec/method/to_source_from_define_method_w_multi_blocks_and_many_matches_spec.rb +56 -0
  116. data/lib/sourcify/spec/method/to_source_from_define_method_w_multi_blocks_and_single_match_spec.rb +73 -0
  117. data/lib/sourcify/spec/method/to_source_from_define_method_w_multi_blocks_and_specified_attached_to_and_many_matches_spec.rb +36 -0
  118. data/lib/sourcify/spec/method/to_source_from_define_method_w_multi_blocks_and_specified_attached_to_and_no_match_spec.rb +36 -0
  119. data/lib/sourcify/spec/method/to_source_from_define_method_w_multi_blocks_and_specified_attached_to_and_single_match_spec.rb +28 -0
  120. data/lib/sourcify/spec/method/to_source_from_define_method_w_multi_blocks_and_specified_attached_to_spec.rb +103 -0
  121. data/lib/sourcify/spec/method/to_source_from_define_method_w_multi_blocks_and_specified_body_matcher_and_many_matches_spec.rb +36 -0
  122. data/lib/sourcify/spec/method/to_source_from_define_method_w_multi_blocks_and_specified_body_matcher_and_no_match_spec.rb +36 -0
  123. data/lib/sourcify/spec/method/to_source_from_define_method_w_multi_blocks_and_specified_body_matcher_and_single_match_spec.rb +28 -0
  124. data/lib/sourcify/spec/method/to_source_from_define_method_w_multi_blocks_and_specified_ignore_nested_spec.rb +36 -0
  125. data/lib/sourcify/spec/method/to_source_from_define_method_within_irb_spec.rb +32 -0
  126. data/lib/sourcify/spec/method/to_source_from_define_method_within_pry_spec.rb +49 -0
  127. data/lib/sourcify/spec/method/to_source_magic_file_var_spec.rb +176 -0
  128. data/lib/sourcify/spec/method/to_source_magic_line_var_spec.rb +298 -0
  129. data/lib/sourcify/spec/method/to_source_w_specified_strip_enclosure_spec.rb +39 -0
  130. data/lib/sourcify/spec/no_method/unsupported_platform_spec.rb +26 -0
  131. data/lib/sourcify/spec/proc/19x_extras.rb +27 -0
  132. data/lib/sourcify/spec/proc/created_on_the_fly_proc_spec.rb +80 -0
  133. data/lib/sourcify/spec/proc/encoding_spec.rb +36 -0
  134. data/lib/sourcify/spec/proc/others_spec.rb +40 -0
  135. data/lib/sourcify/spec/proc/raw_scanner/block_comment_spec.rb +8 -0
  136. data/lib/sourcify/spec/proc/raw_scanner/double_colons_spec.rb +8 -0
  137. data/lib/sourcify/spec/proc/raw_scanner/double_quote_str_w_interpolation_spec.rb +8 -0
  138. data/lib/sourcify/spec/proc/raw_scanner/double_quote_str_wo_interpolation_spec.rb +8 -0
  139. data/lib/sourcify/spec/proc/raw_scanner/heredoc_w_indent_spec.rb +8 -0
  140. data/lib/sourcify/spec/proc/raw_scanner/heredoc_wo_indent_spec.rb +8 -0
  141. data/lib/sourcify/spec/proc/raw_scanner/kw_block_start_alias1_spec.rb +20 -0
  142. data/lib/sourcify/spec/proc/raw_scanner/kw_block_start_alias2_spec.rb +20 -0
  143. data/lib/sourcify/spec/proc/raw_scanner/per_line_comment_spec.rb +8 -0
  144. data/lib/sourcify/spec/proc/raw_scanner/single_quote_str_spec.rb +8 -0
  145. data/lib/sourcify/spec/proc/raw_scanner/slash_operator_spec.rb +8 -0
  146. data/lib/sourcify/spec/proc/raw_scanner/spec_helper.rb +63 -0
  147. data/lib/sourcify/spec/proc/readme +5 -0
  148. data/lib/sourcify/spec/proc/spec_helper.rb +1 -0
  149. data/lib/sourcify/spec/proc/to_raw_source_spec.rb +33 -0
  150. data/lib/sourcify/spec/proc/to_raw_source_w_specified_strip_enclosure_spec.rb +69 -0
  151. data/lib/sourcify/spec/proc/to_sexp_from_multi_blocks_w_specified_attached_to_spec.rb +46 -0
  152. data/lib/sourcify/spec/proc/to_sexp_variables_spec.rb +146 -0
  153. data/lib/sourcify/spec/proc/to_sexp_w_specified_strip_enclosure_spec.rb +60 -0
  154. data/lib/sourcify/spec/proc/to_sexp_within_irb_spec.rb +146 -0
  155. data/lib/sourcify/spec/proc/to_sexp_within_pry_spec.rb +149 -0
  156. data/lib/sourcify/spec/proc/to_source_from_braced_block_w_nested_braced_block_spec.rb +33 -0
  157. data/lib/sourcify/spec/proc/to_source_from_braced_block_w_nested_hash_spec.rb +82 -0
  158. data/lib/sourcify/spec/proc/to_source_from_braced_block_wo_nesting_complication_spec.rb +46 -0
  159. data/lib/sourcify/spec/proc/to_source_from_do_end_block_w_nested_begin_spec.rb +35 -0
  160. data/lib/sourcify/spec/proc/to_source_from_do_end_block_w_nested_case_spec.rb +35 -0
  161. data/lib/sourcify/spec/proc/to_source_from_do_end_block_w_nested_class_spec.rb +89 -0
  162. data/lib/sourcify/spec/proc/to_source_from_do_end_block_w_nested_do_end_block_spec.rb +33 -0
  163. data/lib/sourcify/spec/proc/to_source_from_do_end_block_w_nested_for_spec.rb +132 -0
  164. data/lib/sourcify/spec/proc/to_source_from_do_end_block_w_nested_if_spec.rb +87 -0
  165. data/lib/sourcify/spec/proc/to_source_from_do_end_block_w_nested_literal_keyword_spec.rb +103 -0
  166. data/lib/sourcify/spec/proc/to_source_from_do_end_block_w_nested_method_spec.rb +33 -0
  167. data/lib/sourcify/spec/proc/to_source_from_do_end_block_w_nested_module_spec.rb +49 -0
  168. data/lib/sourcify/spec/proc/to_source_from_do_end_block_w_nested_unless_spec.rb +87 -0
  169. data/lib/sourcify/spec/proc/to_source_from_do_end_block_w_nested_until_spec.rb +189 -0
  170. data/lib/sourcify/spec/proc/to_source_from_do_end_block_w_nested_while_spec.rb +189 -0
  171. data/lib/sourcify/spec/proc/to_source_from_do_end_block_wo_nesting_complication_spec.rb +46 -0
  172. data/lib/sourcify/spec/proc/to_source_from_multi_blocks_w_many_matches_spec.rb +43 -0
  173. data/lib/sourcify/spec/proc/to_source_from_multi_blocks_w_single_match_spec.rb +20 -0
  174. data/lib/sourcify/spec/proc/to_source_from_multi_blocks_w_specified_attached_to_and_many_matches_spec.rb +45 -0
  175. data/lib/sourcify/spec/proc/to_source_from_multi_blocks_w_specified_attached_to_and_no_match_spec.rb +45 -0
  176. data/lib/sourcify/spec/proc/to_source_from_multi_blocks_w_specified_attached_to_and_single_match_spec.rb +22 -0
  177. data/lib/sourcify/spec/proc/to_source_from_multi_blocks_w_specified_attached_to_spec.rb +84 -0
  178. data/lib/sourcify/spec/proc/to_source_from_multi_blocks_w_specified_body_matcher_and_many_matches_spec.rb +45 -0
  179. data/lib/sourcify/spec/proc/to_source_from_multi_blocks_w_specified_body_matcher_and_no_match_spec.rb +45 -0
  180. data/lib/sourcify/spec/proc/to_source_from_multi_blocks_w_specified_body_matcher_and_single_match_spec.rb +22 -0
  181. data/lib/sourcify/spec/proc/to_source_from_multi_blocks_w_specified_ignore_nested_spec.rb +43 -0
  182. data/lib/sourcify/spec/proc/to_source_from_multi_do_end_blocks_w_single_match_spec.rb +31 -0
  183. data/lib/sourcify/spec/proc/to_source_magic_file_var_spec.rb +127 -0
  184. data/lib/sourcify/spec/proc/to_source_magic_line_var_spec.rb +127 -0
  185. data/lib/sourcify/spec/proc/to_source_variables_spec.rb +29 -0
  186. data/lib/sourcify/spec/proc/to_source_w_specified_strip_enclosure_spec.rb +33 -0
  187. data/lib/sourcify/spec/proc/to_source_within_irb_spec.rb +38 -0
  188. data/lib/sourcify/spec/proc/to_source_within_pry_spec.rb +61 -0
  189. data/lib/sourcify/spec/raw_scanner/block_comment_shared_spec.rb +57 -0
  190. data/lib/sourcify/spec/raw_scanner/double_colons_shared_spec.rb +11 -0
  191. data/lib/sourcify/spec/raw_scanner/double_quote_str_w_interpolation_shared_spec.rb +60 -0
  192. data/lib/sourcify/spec/raw_scanner/double_quote_str_wo_interpolation_shared_spec.rb +86 -0
  193. data/lib/sourcify/spec/raw_scanner/heredoc_w_indent_shared_spec.rb +69 -0
  194. data/lib/sourcify/spec/raw_scanner/heredoc_wo_indent_shared_spec.rb +70 -0
  195. data/lib/sourcify/spec/raw_scanner/kw_block_start_alias1_shared_spec.rb +73 -0
  196. data/lib/sourcify/spec/raw_scanner/kw_block_start_alias2_shared_spec.rb +73 -0
  197. data/lib/sourcify/spec/raw_scanner/per_line_comment_shared_spec.rb +32 -0
  198. data/lib/sourcify/spec/raw_scanner/shared_specs.rb +3 -0
  199. data/lib/sourcify/spec/raw_scanner/single_quote_str_shared_spec.rb +79 -0
  200. data/lib/sourcify/spec/raw_scanner/slash_operator_shared_spec.rb +71 -0
  201. data/lib/sourcify/spec/run_build.sh +25 -0
  202. data/lib/sourcify/spec/spec_helper.rb +130 -0
  203. data/lib/symbolic/symbolic.rb +248 -0
  204. data/lib/symbolic/visitor.rb +51 -0
  205. data/lib/translator/block_translator.rb +123 -0
  206. data/lib/translator/command_translator.rb +421 -0
  207. data/lib/translator/last_returns_visitor.rb +57 -0
  208. data/lib/translator/local_variables_enumerator.rb +35 -0
  209. data/lib/translator/method_translator.rb +24 -0
  210. data/lib/translator/translator.rb +49 -0
  211. data/lib/type_aware_array.rb +71 -0
  212. data/lib/types/array_type.rb +51 -0
  213. data/lib/types/class_type.rb +128 -0
  214. data/lib/types/object_tracer.rb +162 -0
  215. data/lib/types/primitive_type.rb +73 -0
  216. data/lib/types/ruby_extension.rb +67 -0
  217. data/lib/types/ruby_type.rb +45 -0
  218. data/lib/types/type_inference.rb +382 -0
  219. data/lib/types/union_type.rb +155 -0
  220. metadata +321 -0
@@ -0,0 +1,123 @@
1
+ require_relative "../ast/nodes.rb"
2
+ require_relative "../ast/builder.rb"
3
+ require_relative "../ast/translator.rb"
4
+ require_relative "../types/type_inference"
5
+ require_relative "../types/primitive_type"
6
+ require_relative "../parsing"
7
+ require_relative "../scope"
8
+ require_relative "../ast/printer"
9
+ require_relative "../ast/method_definition"
10
+
11
+ module Ikra
12
+ module Translator
13
+
14
+ # The result of Ruby-to-CUDA translation of a block using {Translator}
15
+ class BlockTranslationResult
16
+
17
+ # @return [String] Generated CUDA source code
18
+ attr_accessor :block_source
19
+
20
+ # @return [UnionType] Return value type of method/block
21
+ attr_accessor :result_type
22
+
23
+ # @return [String] Name of function in CUDA source code
24
+ attr_accessor :function_name
25
+
26
+ # @return [Array<Ikra::AST::MethodDefinition>] Auxiliary methods that are called by this block (including transitive method calls)
27
+ attr_accessor :aux_methods
28
+
29
+ def initialize(c_source:, result_type:, function_name:, aux_methods: [])
30
+ @block_source = c_source
31
+ @result_type = result_type
32
+ @function_name = function_name
33
+ @aux_methods = aux_methods
34
+ end
35
+
36
+ def generated_source
37
+ @aux_methods.map do |meth|
38
+ meth.to_c_source
39
+ end.join("\n\n") + @block_source
40
+ end
41
+ end
42
+
43
+ BlockSelectorDummy = :"<BLOCK>"
44
+
45
+ class << self
46
+ # Translates a Ruby block to CUDA source code.
47
+ # @param [AST::Node] ast abstract syntax tree of the block
48
+ # @param [EnvironmentBuilder] environment_builder environment builder instance collecting information about lexical variables (environment)
49
+ # @param [Hash{Symbol => UnionType}] block_parameter_types types of arguments passed to the block
50
+ # @param [Hash{Symbol => Object}] lexical_variables all lexical variables that are accessed within the block
51
+ # @param [Fixnum] command_id a unique identifier of the block
52
+ # @return [BlockTranslationResult]
53
+ def translate_block(ast:, environment_builder:, command_id:, block_parameter_types: {}, lexical_variables: {})
54
+ parameter_types_string = "[" + block_parameter_types.map do |id, type| "#{id}: #{type}" end.join(", ") + "]"
55
+ Log.info("Translating block with input types #{parameter_types_string}")
56
+
57
+ # Define MethodDefinition for block
58
+ block_def = AST::MethodDefinition.new(
59
+ type: Types::UnionType.new, # TODO: what to pass in here?
60
+ selector: BlockSelectorDummy,
61
+ parameter_variables: block_parameter_types,
62
+ return_type: Types::UnionType.new,
63
+ ast: ast)
64
+
65
+ # Lexical variables
66
+ lexical_variables.each do |name, value|
67
+ block_def.lexical_variables[name] = Types::UnionType.new(value.class.to_ikra_type)
68
+ end
69
+
70
+ # Type inference
71
+ type_inference_visitor = TypeInference::Visitor.new
72
+ return_type = type_inference_visitor.process_method(block_def)
73
+ # The following method returns nested dictionaries, but we only need the values
74
+ aux_methods = type_inference_visitor.methods.values.map do |hash|
75
+ hash.values
76
+ end.flatten
77
+
78
+ # Translate to CUDA/C++ code
79
+ translation_result = ast.translate_statement
80
+
81
+ # Load environment variables
82
+ lexical_variables.each do |name, value|
83
+ type = value.class.to_ikra_type
84
+ mangled_name = environment_builder.add_object(name, value)
85
+ translation_result.prepend("#{type.to_c_type} #{name} = #{Constants::ENV_IDENTIFIER}->#{mangled_name};\n")
86
+ end
87
+
88
+ # Declare local variables
89
+ block_def.local_variables.each do |name, types|
90
+ translation_result.prepend("#{types.singleton_type.to_c_type} #{name};\n")
91
+ end
92
+
93
+ # Function signature
94
+ mangled_name = "_block_k_#{command_id}_"
95
+
96
+ if not return_type.is_singleton?
97
+ raise "Cannot handle polymorphic return types yet"
98
+ end
99
+
100
+ function_parameters = ["environment_t *#{Constants::ENV_IDENTIFIER}"]
101
+ block_parameter_types.each do |param|
102
+ function_parameters.push("#{param[1].to_c_type} #{param[0].to_s}")
103
+ end
104
+
105
+ function_head = Translator.read_file(
106
+ file_name: "block_function_head.cpp",
107
+ replacements: {
108
+ "name" => mangled_name,
109
+ "return_type" => return_type.singleton_type.to_c_type,
110
+ "parameters" => function_parameters.join(", ")})
111
+
112
+ translation_result = function_head + wrap_in_c_block(translation_result)
113
+
114
+ # TODO: handle more than one result type
115
+ BlockTranslationResult.new(
116
+ c_source: translation_result,
117
+ result_type: return_type,
118
+ function_name: mangled_name,
119
+ aux_methods: aux_methods)
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,421 @@
1
+ require "tempfile"
2
+ require "ffi"
3
+ require_relative "translator"
4
+ require_relative "block_translator"
5
+ require_relative "../config/os_configuration"
6
+ require_relative "../symbolic/symbolic"
7
+ require_relative "../symbolic/visitor"
8
+ require_relative "../types/object_tracer"
9
+ require_relative "../config/configuration"
10
+
11
+ module Ikra
12
+ module Translator
13
+
14
+ # Interface for transferring data to the CUDA side using FFI. Builds a struct containing all required objects (including lexical variables). Traces objects.
15
+ class EnvironmentBuilder
16
+
17
+ class UnionTypeStruct < FFI::Struct
18
+ layout :class_id, :int32, :object_id, :int32
19
+ end
20
+
21
+ attr_accessor :objects
22
+ attr_accessor :device_struct_allocation
23
+
24
+ def initialize
25
+ @objects = {}
26
+ @device_struct_allocation = ""
27
+ end
28
+
29
+ # Adds an objects as a lexical variable.
30
+ def add_object(command_id, identifier, object)
31
+ cuda_id = "l#{command_id}_#{identifier}"
32
+ objects[cuda_id] = object
33
+
34
+ update_dev_struct_allocation(cuda_id, object)
35
+
36
+ cuda_id
37
+ end
38
+
39
+ # Adds an object as a base array
40
+ def add_base_array(command_id, object)
41
+ cuda_id = "b#{command_id}_base"
42
+ objects[cuda_id] = object
43
+
44
+ cuda_id_size = "b#{command_id}_size"
45
+ if object.class == FFI::MemoryPointer
46
+ objects[cuda_id_size] = object.size / UnionTypeStruct.size
47
+ else
48
+ objects[cuda_id_size] = object.size
49
+ end
50
+
51
+ # Generate code for copying data to global memory
52
+ update_dev_struct_allocation(cuda_id, object)
53
+
54
+ cuda_id
55
+ end
56
+
57
+ # Add an array for the Structure of Arrays object layout
58
+ def add_soa_array(name, object)
59
+ objects[name] = object
60
+ objects["#{name}_size"] = object.size
61
+
62
+ update_dev_struct_allocation(name, object)
63
+ end
64
+
65
+ def update_dev_struct_allocation(field, object)
66
+ if object.class == Array
67
+ # Allocate new array
68
+ @device_struct_allocation += Translator.read_file(
69
+ file_name: "env_builder_copy_array.cpp",
70
+ replacements: {
71
+ "field" => field,
72
+ "host_env" => Constants::ENV_HOST_IDENTIFIER,
73
+ "dev_env" => Constants::ENV_DEVICE_IDENTIFIER,
74
+ "size_bytes" => (object.first.class.to_ikra_type.c_size * object.size).to_s})
75
+ elsif object.class == FFI::MemoryPointer
76
+ # This is an array of union type structs
77
+ # Allocate new array
78
+ @device_struct_allocation += Translator.read_file(
79
+ file_name: "env_builder_copy_array.cpp",
80
+ replacements: {
81
+ "field" => field,
82
+ "host_env" => Constants::ENV_HOST_IDENTIFIER,
83
+ "dev_env" => Constants::ENV_DEVICE_IDENTIFIER,
84
+ "size_bytes" => object.size.to_s})
85
+ else
86
+ # Nothing to do, this case is handled by mem-copying the struct
87
+ end
88
+ end
89
+
90
+ # Returns the name of the field containing the base array for a certain identity command.
91
+ def self.base_identifier(command_id)
92
+ "b#{command_id}_base"
93
+ end
94
+
95
+ def build_struct_definition
96
+ @objects.freeze
97
+
98
+ struct_def = "struct environment_struct\n{\n"
99
+ @objects.each do |key, value|
100
+ if value.class == FFI::MemoryPointer
101
+ # TODO: can this be an extension method of FFI::MemoryPointer?
102
+ struct_def += " union_t * #{key};\n"
103
+ else
104
+ struct_def += " #{value.class.to_ikra_type_obj(value).to_c_type} #{key};\n"
105
+ end
106
+ end
107
+ struct_def += "};\n"
108
+
109
+ struct_def
110
+ end
111
+
112
+ def build_ffi_type
113
+ struct_layout = []
114
+ @objects.each do |key, value|
115
+ if value.class == FFI::MemoryPointer
116
+ # TODO: can this be an extension method of FFI::MemoryPointer?
117
+ struct_layout += [key.to_sym, :pointer]
118
+ else
119
+ struct_layout += [key.to_sym, value.class.to_ikra_type_obj(value).to_ffi_type]
120
+ end
121
+ end
122
+
123
+ struct_type = Class.new(FFI::Struct)
124
+ struct_type.layout(*struct_layout)
125
+
126
+ struct_type
127
+ end
128
+
129
+ def build_ffi_object
130
+ struct_type = build_ffi_type
131
+ struct = struct_type.new
132
+
133
+ @objects.each do |key, value|
134
+ # TODO: need proper Array handling
135
+ if value.class == Array
136
+ # Check first element to determine type of array
137
+ # TODO: check for polymorphic
138
+ inner_type = value.first.class.to_ikra_type
139
+ array_ptr = FFI::MemoryPointer.new(value.size * inner_type.c_size)
140
+
141
+ if inner_type == Types::PrimitiveType::Int
142
+ array_ptr.put_array_of_int(0, value)
143
+ elsif inner_type == Types::PrimitiveType::Float
144
+ array_ptr.put_array_of_float(0, value)
145
+ else
146
+ raise NotImplementedError
147
+ end
148
+
149
+ struct[key.to_sym] = array_ptr
150
+ else
151
+ struct[key.to_sym] = value
152
+ end
153
+ end
154
+
155
+ struct.to_ptr
156
+ end
157
+
158
+ def [](command_id)
159
+ CurriedBuilder.new(self, command_id)
160
+ end
161
+
162
+ class CurriedBuilder
163
+ def initialize(builder, command_id)
164
+ @builder = builder
165
+ @command_id = command_id
166
+ end
167
+
168
+ def add_object(identifier, object)
169
+ @builder.add_object(@command_id, identifier, object)
170
+ end
171
+
172
+ def add_base_array(object)
173
+ @builder.add_base_array(@command_id, object)
174
+ end
175
+ end
176
+
177
+ def clone
178
+ result = self.class.new
179
+ result.objects = @objects.clone
180
+ result.device_struct_allocation = @device_struct_allocation
181
+ result
182
+ end
183
+ end
184
+
185
+ # Result of translating a {Ikra::Symbolic::ArrayCommand}.
186
+ class CommandTranslationResult
187
+ attr_accessor :environment_builder # @return [EnvironmentBuilder] instance that generates the struct containing accessed lexical variables.
188
+ attr_accessor :generated_source # @return [String] containing the currently generated source code.
189
+ attr_accessor :invocation # @return [String] source code used for invoking the block function.
190
+ attr_accessor :size # @return [Fixnum] number of elements in base array
191
+ attr_accessor :return_type # @return [Types::UnionType] return type of the block.
192
+
193
+ def initialize(environment_builder)
194
+ @environment_builder = environment_builder
195
+ @generated_source = ""
196
+ @invocation = "NULL"
197
+ @return_type = Types::UnionType.new
198
+ @size = 0
199
+
200
+ @so_filename = "" # [String] file name of shared library containing CUDA kernel
201
+ end
202
+
203
+ def result_size
204
+ @size
205
+ end
206
+
207
+ # Compiles CUDA source code and generates a shared library.
208
+ def compile
209
+ # Prepare file replacements
210
+ file_replacements = {} # [Hash{String => String}] contains strings that should be replaced when reading a file
211
+ file_replacements["grid_dim[0]"] = "#{[size / 250, 1].max}"
212
+ file_replacements["grid_dim[1]"] = "1"
213
+ file_replacements["grid_dim[2]"] = "1"
214
+ file_replacements["block_dim[0]"] = "#{size >= 250 ? 250 : size}"
215
+ file_replacements["block_dim[1]"] = "1"
216
+ file_replacements["block_dim[2]"] = "1"
217
+ file_replacements["result_type"] = @return_type.singleton_type.to_c_type
218
+ file_replacements["result_size"] = "#{result_size}"
219
+ file_replacements["block_invocation"] = @invocation
220
+ file_replacements["env_identifier"] = Constants::ENV_IDENTIFIER
221
+ file_replacements["copy_env"] = @environment_builder.device_struct_allocation
222
+ file_replacements["dev_env"] = Constants::ENV_DEVICE_IDENTIFIER
223
+ file_replacements["host_env"] = Constants::ENV_HOST_IDENTIFIER
224
+
225
+ # Generate source code
226
+ source = Translator.read_file(file_name: "header.cpp", replacements: file_replacements) +
227
+ @environment_builder.build_struct_definition +
228
+ @generated_source +
229
+ Translator.read_file(file_name: "kernel.cpp", replacements: file_replacements) +
230
+ Translator.read_file(file_name: "kernel_launcher.cpp", replacements: file_replacements)
231
+
232
+ line_no_digits = Math.log(source.lines.count, 10).ceil
233
+ source_with_line_numbers = source.lines.each_with_index.map do |line, num|
234
+ "[#{(num + 1).to_s.rjust(line_no_digits, "0")}] #{line}"
235
+ end.join("")
236
+
237
+ Log.info("Generated source code:\n#{source_with_line_numbers}")
238
+
239
+ # Write source code to temporary file
240
+ file = Tempfile.new(["ikra_kernel", ".cu"])
241
+ file.write(source)
242
+ file.close
243
+
244
+ # Write to codegen_expect
245
+ if Configuration.codegen_expect_file_name != nil
246
+ expect_file = File.new(Configuration.codegen_expect_file_name, "w+")
247
+ expect_file.write(source)
248
+ expect_file.close
249
+ end
250
+
251
+ # Run compiler
252
+ @so_filename = "#{file.path}.#{Configuration.so_suffix}"
253
+ nvcc_command = Configuration.nvcc_invocation_string(file.path, @so_filename)
254
+
255
+ Log.info("Compiling kernel: #{nvcc_command}")
256
+ time_before = Time.now
257
+ compile_status = %x(#{nvcc_command})
258
+ Log.info("Done, took #{Time.now - time_before} s")
259
+
260
+ if $? != 0
261
+ raise "nvcc failed: #{compile_status}"
262
+ end
263
+ end
264
+
265
+ # Attaches a the compiled shared library via Ruby FFI and invokes the kernel.
266
+ def execute
267
+ if !File.exist?(@so_filename)
268
+ compile
269
+ end
270
+
271
+ time_before = Time.now
272
+ ffi_interface = Module.new
273
+ ffi_interface.extend(FFI::Library)
274
+ ffi_interface.ffi_lib(@so_filename)
275
+ ffi_interface.attach_function(:launch_kernel, [:pointer], :pointer)
276
+ environment_object = @environment_builder.build_ffi_object
277
+ Log.info("FFI transfer time: #{Time.now - time_before} s")
278
+
279
+ time_before = Time.now
280
+ result = ffi_interface.launch_kernel(environment_object)
281
+ Log.info("Kernel time: #{Time.now - time_before} s")
282
+
283
+ if return_type.singleton_type == Types::PrimitiveType::Int
284
+ result.read_array_of_int(result_size)
285
+ elsif return_type.singleton_type == Types::PrimitiveType::Float
286
+ result.read_array_of_float(result_size)
287
+ else
288
+ raise NotImplementedError
289
+ end
290
+ end
291
+ end
292
+
293
+ # A visitor traversing the tree (currently list) of symbolic array commands. Every command is converted into a {CommandTranslationResult} and possibly merged with the result of dependent (previous) results. This is how kernel fusion is implemented.
294
+ class ArrayCommandVisitor < Symbolic::Visitor
295
+
296
+ def initialize(environment_builder)
297
+ @environment_builder = environment_builder
298
+ end
299
+
300
+ def visit_array_new_command(command)
301
+ # create brand new result
302
+ command_translation_result = CommandTranslationResult.new(@environment_builder)
303
+
304
+ block_translation_result = Translator.translate_block(
305
+ ast: command.ast,
306
+ # only one block parameter (int)
307
+ block_parameter_types: {command.block_parameter_names.first => Types::UnionType.create_int},
308
+ environment_builder: @environment_builder[command.unique_id],
309
+ lexical_variables: command.lexical_externals,
310
+ command_id: command.unique_id)
311
+
312
+ command_translation_result.generated_source = block_translation_result.generated_source
313
+
314
+ tid = "threadIdx.x + blockIdx.x * blockDim.x"
315
+ command_translation_result.invocation = "#{block_translation_result.function_name}(#{Constants::ENV_IDENTIFIER}, #{tid})"
316
+ command_translation_result.size = command.size
317
+ command_translation_result.return_type = block_translation_result.result_type
318
+
319
+ command_translation_result
320
+ end
321
+
322
+ def visit_array_identity_command(command)
323
+ # create brand new result
324
+ command_translation_result = CommandTranslationResult.new(@environment_builder)
325
+
326
+ # no source code generation
327
+
328
+ if Configuration::JOB_REORDERING
329
+ reordering_array = command.target.each_with_index.sort do |a, b|
330
+ a.first.class.object_id <=> b.first.class.object_id
331
+ end.map(&:last)
332
+
333
+ # Generate debug output
334
+ dbg_elements = []
335
+ dbg_last = command.target[reordering_array[0]].class
336
+ dbg_counter = 1
337
+
338
+ for idx in 1..(command.target.size - 1)
339
+ dbg_next = command.target[reordering_array[idx]].class
340
+
341
+ if dbg_next == dbg_last
342
+ dbg_counter += 1
343
+ else
344
+ dbg_elements.push("#{dbg_last.to_s} (#{dbg_counter})")
345
+ dbg_last = dbg_next
346
+ dbg_counter = 1
347
+ end
348
+ end
349
+ dbg_elements.push("#{dbg_last.to_s} (#{dbg_counter})")
350
+
351
+ Log.info("Generated job reordering array, resulting in: [#{dbg_elements.join(", ")}]")
352
+
353
+ reordering_array_name = @environment_builder.add_base_array("#{command.unique_id}j", reordering_array)
354
+ command_translation_result.invocation = "#{Constants::ENV_IDENTIFIER}->#{EnvironmentBuilder.base_identifier(command.unique_id)}[#{Constants::ENV_IDENTIFIER}->#{reordering_array_name}[threadIdx.x + blockIdx.x * blockDim.x]]"
355
+ else
356
+ command_translation_result.invocation = "#{Constants::ENV_IDENTIFIER}->#{EnvironmentBuilder.base_identifier(command.unique_id)}[threadIdx.x + blockIdx.x * blockDim.x]"
357
+ end
358
+
359
+ command_translation_result.size = command.size
360
+ command_translation_result.return_type = command.base_type
361
+
362
+ command_translation_result
363
+ end
364
+
365
+ def visit_array_map_command(command)
366
+ dependent_result = super # visit target (dependent) command
367
+ command_translation_result = CommandTranslationResult.new(@environment_builder)
368
+
369
+ block_translation_result = Translator.translate_block(
370
+ ast: command.ast,
371
+ block_parameter_types: {command.block_parameter_names.first => dependent_result.return_type},
372
+ environment_builder: @environment_builder[command.unique_id],
373
+ lexical_variables: command.lexical_externals,
374
+ command_id: command.unique_id)
375
+
376
+ command_translation_result.generated_source = dependent_result.generated_source + "\n\n" + block_translation_result.generated_source
377
+
378
+ command_translation_result.invocation = "#{block_translation_result.function_name}(#{Constants::ENV_IDENTIFIER}, #{dependent_result.invocation})"
379
+ command_translation_result.size = dependent_result.size
380
+ command_translation_result.return_type = block_translation_result.result_type
381
+
382
+ command_translation_result
383
+ end
384
+ end
385
+
386
+ # Retrieves all base arrays and registers them with the {EnvironmentBuilder}. Yhis functionality is in a separate class to avoid scattering with object tracer calls.
387
+ class BaseArrayRegistrator < Symbolic::Visitor
388
+ def initialize(environment_builder, object_tracer)
389
+ @environment_builder = environment_builder
390
+ @object_tracer = object_tracer
391
+ end
392
+
393
+ def visit_array_identity_command(command)
394
+ need_union_type = !command.base_type.is_singleton?
395
+ transformed_base_array = @object_tracer.convert_base_array(command.target, need_union_type)
396
+ @environment_builder.add_base_array(command.unique_id, transformed_base_array)
397
+ end
398
+ end
399
+
400
+ class << self
401
+ def translate_command(command)
402
+ environment_builder = EnvironmentBuilder.new
403
+
404
+ # Run type inference for objects/classes and trace objects
405
+ object_tracer = TypeInference::ObjectTracer.new(command)
406
+ all_objects = object_tracer.trace_all
407
+
408
+ # Translate command
409
+ command_translation_result = command.accept(ArrayCommandVisitor.new(environment_builder))
410
+
411
+ # Add SoA arrays to environment
412
+ object_tracer.register_soa_arrays(environment_builder)
413
+
414
+ # Add base arrays to environment
415
+ command.accept(BaseArrayRegistrator.new(environment_builder, object_tracer))
416
+
417
+ command_translation_result
418
+ end
419
+ end
420
+ end
421
+ end