bones-compiler 1.1.0 → 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (211) hide show
  1. checksums.yaml +15 -0
  2. data/CHANGELOG +37 -0
  3. data/LICENSE +1 -1
  4. data/README.rdoc +95 -70
  5. data/Rakefile +78 -3
  6. data/VERSION +1 -1
  7. data/bin/adarwin +17 -0
  8. data/examples/benchmarks/PolyBench/2mm.c +104 -0
  9. data/examples/benchmarks/{3mm.c → PolyBench/3mm.c} +5 -2
  10. data/examples/benchmarks/{adi.c → PolyBench/adi.c} +6 -3
  11. data/examples/benchmarks/{atax.c → PolyBench/atax.c} +5 -2
  12. data/examples/benchmarks/{bicg.c → PolyBench/bicg.c} +5 -2
  13. data/examples/benchmarks/{cholesky.c → PolyBench/cholesky.c} +3 -0
  14. data/examples/benchmarks/{common.h → PolyBench/common.h} +2 -2
  15. data/examples/benchmarks/{correlation.c → PolyBench/correlation.c} +16 -7
  16. data/examples/benchmarks/{covariance.c → PolyBench/covariance.c} +7 -2
  17. data/examples/benchmarks/{doitgen.c → PolyBench/doitgen.c} +5 -2
  18. data/examples/benchmarks/{durbin.c → PolyBench/durbin.c} +3 -0
  19. data/examples/benchmarks/{dynprog.c → PolyBench/dynprog.c} +3 -0
  20. data/examples/benchmarks/{fdtd-2d-apml.c → PolyBench/fdtd-2d-apml.c} +3 -0
  21. data/examples/benchmarks/{fdtd-2d.c → PolyBench/fdtd-2d.c} +5 -2
  22. data/examples/benchmarks/{floyd-warshall.c → PolyBench/floyd-warshall.c} +3 -0
  23. data/examples/benchmarks/{gemm.c → PolyBench/gemm.c} +5 -2
  24. data/examples/benchmarks/{gemver.c → PolyBench/gemver.c} +5 -2
  25. data/examples/benchmarks/{gesummv.c → PolyBench/gesummv.c} +5 -2
  26. data/examples/benchmarks/{gramschmidt.c → PolyBench/gramschmidt.c} +3 -0
  27. data/examples/benchmarks/{jacobi-1d-imper.c → PolyBench/jacobi-1d-imper.c} +10 -2
  28. data/examples/benchmarks/{jacobi-2d-imper.c → PolyBench/jacobi-2d-imper.c} +8 -3
  29. data/examples/benchmarks/{lu.c → PolyBench/lu.c} +3 -0
  30. data/examples/benchmarks/{ludcmp.c → PolyBench/ludcmp.c} +3 -0
  31. data/examples/benchmarks/{mvt.c → PolyBench/mvt.c} +6 -2
  32. data/examples/benchmarks/{reg_detect.c → PolyBench/reg_detect.c} +3 -0
  33. data/examples/benchmarks/{seidel-2d.c → PolyBench/seidel-2d.c} +3 -0
  34. data/examples/benchmarks/{symm.c → PolyBench/symm.c} +3 -0
  35. data/examples/benchmarks/{syr2k.c → PolyBench/syr2k.c} +5 -2
  36. data/examples/benchmarks/{syrk.c → PolyBench/syrk.c} +7 -4
  37. data/examples/benchmarks/{trisolv.c → PolyBench/trisolv.c} +3 -0
  38. data/examples/benchmarks/{trmm.c → PolyBench/trmm.c} +3 -0
  39. data/examples/benchmarks/Rodinia/cfd.c +180 -0
  40. data/examples/benchmarks/Rodinia/hotspot.c +228 -0
  41. data/examples/benchmarks/Rodinia/kmeans.c +164 -0
  42. data/examples/benchmarks/Rodinia/srad.c +188 -0
  43. data/examples/benchmarks/other/common.h +0 -0
  44. data/examples/benchmarks/other/dct.c +58 -0
  45. data/examples/benchmarks/other/mm.c +50 -0
  46. data/examples/benchmarks/{saxpy.c → other/saxpy.c} +11 -7
  47. data/examples/chunk/{example1.c → example01.c} +0 -0
  48. data/examples/chunk/{example2.c → example02.c} +0 -0
  49. data/examples/chunk/{example3.c → example03.c} +0 -0
  50. data/examples/chunk/{example4.c → example04.c} +0 -0
  51. data/examples/chunk/{example5.c → example05.c} +0 -0
  52. data/examples/chunk/example06.c +45 -0
  53. data/examples/chunk/example07.c +49 -0
  54. data/examples/dependences/example01.c +42 -0
  55. data/examples/dependences/example02.c +40 -0
  56. data/examples/dependences/example03.c +43 -0
  57. data/examples/dependences/example04.c +44 -0
  58. data/examples/dependences/example05.c +42 -0
  59. data/examples/element/{example1.c → example01.c} +0 -0
  60. data/examples/element/{example2.c → example02.c} +2 -2
  61. data/examples/element/{example3.c → example03.c} +0 -0
  62. data/examples/element/{example4.c → example04.c} +0 -0
  63. data/examples/element/{example5.c → example05.c} +0 -0
  64. data/examples/element/{example6.c → example06.c} +0 -0
  65. data/examples/element/{example7.c → example07.c} +0 -0
  66. data/examples/element/{example8.c → example08.c} +0 -0
  67. data/examples/element/{example9.c → example09.c} +0 -0
  68. data/examples/element/example13.c +73 -0
  69. data/examples/fusion/example01.c +68 -0
  70. data/examples/fusion/example02.c +73 -0
  71. data/examples/fusion/example03.c +72 -0
  72. data/examples/fusion/example04.c +61 -0
  73. data/examples/fusion/example05.c +55 -0
  74. data/examples/neighbourhood/{example1.c → example01.c} +0 -0
  75. data/examples/neighbourhood/{example2.c → example02.c} +0 -0
  76. data/examples/neighbourhood/{example3.c → example03.c} +0 -0
  77. data/examples/neighbourhood/{example4.c → example04.c} +0 -0
  78. data/examples/neighbourhood/example05.c +44 -0
  79. data/examples/shared/{example1.c → example01.c} +0 -0
  80. data/examples/shared/{example2.c → example02.c} +0 -0
  81. data/examples/shared/{example3.c → example03.c} +0 -0
  82. data/examples/shared/{example4.c → example04.c} +0 -0
  83. data/examples/shared/{example5.c → example05.c} +0 -0
  84. data/lib/adarwin.rb +62 -0
  85. data/lib/adarwin/dependences.rb +268 -0
  86. data/lib/adarwin/engine.rb +277 -0
  87. data/lib/adarwin/fusion.rb +174 -0
  88. data/lib/adarwin/interval.rb +57 -0
  89. data/lib/adarwin/memorycopies.rb +153 -0
  90. data/lib/adarwin/nest.rb +225 -0
  91. data/lib/adarwin/preprocessor.rb +76 -0
  92. data/lib/adarwin/reference.rb +261 -0
  93. data/lib/bones.rb +4 -55
  94. data/lib/bones/algorithm.rb +77 -40
  95. data/lib/bones/copy.rb +26 -0
  96. data/lib/bones/engine.rb +147 -31
  97. data/lib/bones/preprocessor.rb +92 -12
  98. data/lib/bones/species.rb +4 -3
  99. data/lib/bones/structure.rb +14 -4
  100. data/lib/castaddon.rb +11 -6
  101. data/lib/castaddon/node_adarwin.rb +245 -0
  102. data/lib/castaddon/node_bones.rb +316 -0
  103. data/lib/castaddon/node_common.rb +289 -0
  104. data/lib/castaddon/transformations.rb +236 -0
  105. data/lib/common.rb +216 -0
  106. data/skeletons/CPU-C/common/header.c +3 -0
  107. data/skeletons/CPU-C/common/mem_global.c +0 -0
  108. data/skeletons/CPU-C/common/timer_2_start.c +11 -13
  109. data/skeletons/CPU-C/common/timer_2_stop.c +1 -1
  110. data/skeletons/CPU-C/common/timer_globals.c +29 -0
  111. data/skeletons/CPU-OPENCL-INTEL/common/globals.c +1 -1
  112. data/skeletons/CPU-OPENCL-INTEL/common/header.c +3 -0
  113. data/skeletons/CPU-OPENCL-INTEL/common/mem_copy_D2H.c +7 -2
  114. data/skeletons/CPU-OPENCL-INTEL/common/mem_copy_H2D.c +4 -2
  115. data/skeletons/CPU-OPENCL-INTEL/common/mem_global.c +0 -0
  116. data/skeletons/CPU-OPENCL-INTEL/common/mem_prologue.c +6 -3
  117. data/skeletons/CPU-OPENCL-INTEL/common/timer_2_stop.c +1 -1
  118. data/skeletons/CPU-OPENCL-INTEL/common/timer_globals.c +24 -0
  119. data/skeletons/CPU-OPENMP/common/globals.c +1 -0
  120. data/skeletons/CPU-OPENMP/common/header.c +3 -0
  121. data/skeletons/CPU-OPENMP/common/mem_global.c +0 -0
  122. data/skeletons/CPU-OPENMP/common/timer_1_start.c +0 -12
  123. data/skeletons/CPU-OPENMP/common/timer_2_stop.c +1 -1
  124. data/skeletons/CPU-OPENMP/common/timer_globals.c +33 -0
  125. data/skeletons/GPU-CUDA/common/globals.c +27 -3
  126. data/skeletons/GPU-CUDA/common/header.c +2 -0
  127. data/skeletons/GPU-CUDA/common/mem_async_alloc.c +6 -0
  128. data/skeletons/GPU-CUDA/common/mem_async_copyin.c +6 -0
  129. data/skeletons/GPU-CUDA/common/mem_async_copyout.c +6 -0
  130. data/skeletons/GPU-CUDA/common/mem_async_free.c +6 -0
  131. data/skeletons/GPU-CUDA/common/mem_copy_D2H.c +2 -1
  132. data/skeletons/GPU-CUDA/common/mem_copy_H2D.c +2 -1
  133. data/skeletons/GPU-CUDA/common/mem_global.c +1 -0
  134. data/skeletons/GPU-CUDA/common/mem_prologue.c +1 -2
  135. data/skeletons/GPU-CUDA/common/scheduler.c +86 -0
  136. data/skeletons/GPU-CUDA/common/timer_2_start.c +2 -4
  137. data/skeletons/GPU-CUDA/common/timer_2_stop.c +3 -5
  138. data/skeletons/GPU-CUDA/common/timer_globals.c +26 -0
  139. data/skeletons/GPU-CUDA/kernel/2xN-N-chunk-1-N-to-D-element.kernel.cu +5 -7
  140. data/skeletons/GPU-CUDA/kernel/N-N-chunk-1-N-to-D-element.kernel.cu +4 -6
  141. data/skeletons/GPU-CUDA/kernel/default.host.c +1 -1
  142. data/skeletons/GPU-CUDA/kernel/default.kernel.cu +6 -8
  143. data/skeletons/GPU-CUDA/skeletons.txt +6 -5
  144. data/{examples/benchmarks/2mm.c → test/examples/benchmarks/PolyBench/2mm_species.c} +19 -15
  145. data/test/examples/benchmarks/PolyBench/3mm_species.c +82 -0
  146. data/test/examples/benchmarks/PolyBench/adi_species.c +89 -0
  147. data/test/examples/benchmarks/PolyBench/atax_species.c +69 -0
  148. data/test/examples/benchmarks/PolyBench/bicg_species.c +71 -0
  149. data/test/examples/benchmarks/PolyBench/cholesky_species.c +68 -0
  150. data/test/examples/benchmarks/PolyBench/correlation_species.c +97 -0
  151. data/test/examples/benchmarks/PolyBench/covariance_species.c +78 -0
  152. data/test/examples/benchmarks/PolyBench/doitgen_species.c +67 -0
  153. data/test/examples/benchmarks/PolyBench/durbin_species.c +80 -0
  154. data/test/examples/benchmarks/PolyBench/dynprog_species.c +71 -0
  155. data/test/examples/benchmarks/PolyBench/fdtd-2d-apml_species.c +112 -0
  156. data/test/examples/benchmarks/PolyBench/fdtd-2d_species.c +78 -0
  157. data/test/examples/benchmarks/PolyBench/floyd-warshall_species.c +54 -0
  158. data/test/examples/benchmarks/PolyBench/gemm_species.c +73 -0
  159. data/test/examples/benchmarks/PolyBench/gemver_species.c +93 -0
  160. data/test/examples/benchmarks/PolyBench/gesummv_species.c +68 -0
  161. data/test/examples/benchmarks/PolyBench/gramschmidt_species.c +78 -0
  162. data/test/examples/benchmarks/PolyBench/jacobi-1d-imper_species.c +59 -0
  163. data/test/examples/benchmarks/PolyBench/jacobi-2d-imper_species.c +65 -0
  164. data/test/examples/benchmarks/PolyBench/lu_species.c +57 -0
  165. data/test/examples/benchmarks/PolyBench/ludcmp_species.c +89 -0
  166. data/test/examples/benchmarks/PolyBench/mvt_species.c +69 -0
  167. data/test/examples/benchmarks/PolyBench/reg_detect_species.c +86 -0
  168. data/test/examples/benchmarks/PolyBench/seidel-2d_species.c +53 -0
  169. data/test/examples/benchmarks/PolyBench/symm_species.c +74 -0
  170. data/test/examples/benchmarks/PolyBench/syr2k_species.c +69 -0
  171. data/test/examples/benchmarks/PolyBench/syrk_species.c +66 -0
  172. data/test/examples/benchmarks/PolyBench/trisolv_species.c +61 -0
  173. data/test/examples/benchmarks/PolyBench/trmm_species.c +61 -0
  174. data/test/examples/chunk/example01_species.c +58 -0
  175. data/test/examples/chunk/example02_species.c +48 -0
  176. data/test/examples/chunk/example03_species.c +63 -0
  177. data/test/examples/chunk/example04_species.c +58 -0
  178. data/test/examples/chunk/example05_species.c +56 -0
  179. data/test/examples/chunk/example06_species.c +49 -0
  180. data/test/examples/chunk/example07_species.c +53 -0
  181. data/test/examples/dependences/example01_species.c +46 -0
  182. data/test/examples/dependences/example02_species.c +44 -0
  183. data/test/examples/dependences/example03_species.c +47 -0
  184. data/test/examples/dependences/example04_species.c +48 -0
  185. data/test/examples/dependences/example05_species.c +46 -0
  186. data/test/examples/element/example01_species.c +50 -0
  187. data/test/examples/element/example02_species.c +50 -0
  188. data/test/examples/element/example03_species.c +62 -0
  189. data/test/examples/element/example04_species.c +53 -0
  190. data/test/examples/element/example05_species.c +59 -0
  191. data/test/examples/element/example06_species.c +50 -0
  192. data/test/examples/element/example07_species.c +58 -0
  193. data/test/examples/element/example08_species.c +49 -0
  194. data/test/examples/element/example09_species.c +52 -0
  195. data/test/examples/element/example10_species.c +54 -0
  196. data/test/examples/element/example11_species.c +51 -0
  197. data/test/examples/element/example12_species.c +60 -0
  198. data/test/examples/element/example13_species.c +77 -0
  199. data/test/examples/neighbourhood/example01_species.c +57 -0
  200. data/test/examples/neighbourhood/example02_species.c +56 -0
  201. data/test/examples/neighbourhood/example03_species.c +83 -0
  202. data/test/examples/neighbourhood/example04_species.c +55 -0
  203. data/test/examples/neighbourhood/example05_species.c +48 -0
  204. data/test/examples/shared/example01_species.c +49 -0
  205. data/test/examples/shared/example02_species.c +55 -0
  206. data/test/examples/shared/example03_species.c +59 -0
  207. data/test/examples/shared/example04_species.c +56 -0
  208. data/test/examples/shared/example05_species.c +52 -0
  209. metadata +193 -73
  210. data/examples/benchmarks/overview.txt +0 -38
  211. data/lib/castaddon/node.rb +0 -753
@@ -1,38 +0,0 @@
1
-
2
- == Benchmarks with full parallelism
3
- linear-algebra/kernels/2mm...........2 species...[fully classified]
4
- linear-algebra/kernels/3mm...........3 species...[fully classified]
5
- linear-algebra/kernels/atax..........2 species...[fully classified]
6
- linear-algebra/kernels/bicg..........2 species...[fully classified]
7
- linear-algebra/kernels/doitgen.......2 species...[fully classified]
8
- linear-algebra/kernels/gemm..........1 species...[fully classified]
9
- linear-algebra/kernels/gemver........4 species...[fully classified]
10
- linear-algebra/kernels/gesummv.......1 species...[fully classified]
11
- linear-algebra/kernels/mvt...........2 species...[fully classified]
12
- linear-algebra/kernels/syr2k.........1 species...[fully classified]
13
- linear-algebra/kernels/syrk..........1 species...[fully classified]
14
- stencils/fdtd-2d.....................4 species...[fully classified]
15
- stencils/jacobi-1d-imper.............2 species...[fully classified]
16
- stencils/jacobi-2d-imper.............2 species...[fully classified]
17
-
18
- == Benchmarks with significant parallelism
19
- linear-algebra/kernels/cholesky......3 species...[no outer-loop parallelism, inner-loops only classified]
20
- linear-algebra/kernels/symm..........1 species...[no outer-loop parallelism, inner-loops only classified]
21
- linear-algebra/kernels/trisolv.......1 species...[no outer-loop parallelism, inner-loops only classified]
22
- linear-algebra/kernels/trmm..........1 species...[no outer-loop parallelism, inner-loops only classified]
23
- linear-algebra/solvers/gramschmidt...4 species...[no outer-loop parallelism, inner-loops only classified]
24
- linear-algebra/solvers/lu............3 species...[no outer-loop parallelism, inner-loops only classified]
25
- linear-algebra/solvers/ludcmp........4 species...[no outer-loop parallelism, inner-loops only classified]
26
- datamining/correlation...............5 species...[most parts classified, final part inner-loop only]
27
- datamining/covariance................4 species...[most parts classified, final part inner-loop only]
28
- medley/reg_detect....................2 species...[partly classified, several parts have no parallelism]
29
-
30
- == Benchmarks with very little parallelism
31
- linear-algebra/solvers/durbin........2 species...[partly classified, most parts have no parallelism]
32
- linear-algebra/solvers/dynprog.......1 species...[partly classified, most parts have no parallelism]
33
- stencils/adi.........................2 species...[partly classified, most parts have no parallelism]
34
- stencils/fdtd-ampl...................1 species...[partly classified, most parts have no parallelism]
35
-
36
- == Benchmarks without parallelism
37
- medley/floyd-warshall................0 species...[no parallelism]
38
- stencils/seidel-2d...................0 species...[no parallelism]
@@ -1,753 +0,0 @@
1
- # This class provides an extension to the CAST node class, which
2
- # is a parent class for all other CAST classes. The extension
3
- # consists of three different types of methods:
4
- # * Methods starting with +transform_+, handling the major code transformations.
5
- # * Methods to obtain information on variables, such as their direction and whether they are defined or not.
6
- # * Helper methods, among others those that indicate whether a node is of a certain class.
7
- class C::Node
8
-
9
- # Pre-process method. It currently pre-processes a piece of
10
- # code (typically the kernel code) to replace particular
11
- # code structures with others, which can be handled (better)
12
- # by Bones. For now, the pre-process method performs the
13
- # following transformations:
14
- # * Replaces all incrementors (i++) outside for loops with an assignment (i=i+1).
15
- # * Replaces all decrementors (i--) outside for loops with an assignment (i=i-1).
16
- def preprocess
17
- self.preorder do |node|
18
- if node.postinc? || node.preinc?
19
- node.replace_with(C::AssignmentExpression.parse(node.expr.to_s+' = '+node.expr.to_s+' + 1')) unless node.parent.for_statement?
20
- elsif node.postdec? || node.predec?
21
- node.replace_with(C::AssignmentExpression.parse(node.expr.to_s+' = '+node.expr.to_s+' - 1')) unless node.parent.for_statement?
22
- end
23
- end
24
- end
25
-
26
- # Method to obtain a list of all functions in the code. If
27
- # no functions can be found, an empty array is returned. For
28
- # every function found, the function itself is pushed to the
29
- # list. This method also makes sure that there is at least one
30
- # function with the name 'main'. If this is not the case, an
31
- # error is raised.
32
- def get_functions
33
- includes_main = false
34
- function_list = []
35
- self.preorder do |node|
36
- if node.function_definition?
37
- function_list.push(node)
38
- includes_main = true if (node.name == 'main' || node.name == Bones::VARIABLE_PREFIX+'main')
39
- end
40
- end
41
- raise_error('No "main"-function detected in the input file') if !includes_main
42
- return function_list
43
- end
44
-
45
- # Method to enable the use of local memory for a list of
46
- # array variables which is given as an argument to the method.
47
- # The method walks through the node. First, it checks whether:
48
- # * The node represents an array access (+node.index?+)
49
- # * The node has a parent node (+node.parent+)
50
- # Then, the method loops over all array variables. It checks
51
- # one more thing: whether the array variable's name is the
52
- # same as the name found in the array access node.
53
- #
54
- # If all conditions are met, the method performs two replacements:
55
- # * The variable name is changed to correspond to local memory
56
- # * The index names are changed to correspond to local indices
57
- #
58
- # The method performs the transformation on the node itself.
59
- # Any old data is thus lost.
60
- def transform_use_local_memory(arrays)
61
- self.preorder do |node|
62
- if (node.index?) && (node.parent)
63
- arrays.each do |array|
64
- if node.variable_name == array.name
65
- node.variable_name = Bones::LOCAL_MEMORY+'_'+array.name
66
- array.species.dimensions.each_with_index do |dimension,num_dimension|
67
- node.replace_variable(Bones::GLOBAL_ID+'_'+num_dimension.to_s,Bones::LOCAL_ID+'_'+num_dimension.to_s)
68
- end
69
- end
70
- end
71
- end
72
- end
73
- end
74
-
75
- # This method transforms multi-dimensional arrays into 1D
76
- # arrays. The target array variable list is given as argument.
77
- # The method walks through the node. First, it checks whether:
78
- # * The node represents an array access (+node.index?+)
79
- # * The node has a parent node (+node.parent+)
80
- # Then, the method loops over all array variables. It then
81
- # checks two more things:
82
- # * Whether the given name is the same as the name found in the array access node (+node.variable_name == array.name+)
83
- # * Whether the dimensions of the given array are the same as the dimensions of the node (+node.dimension == array.dimension+)
84
- #
85
- # Then, the method is ready to perform the flattening. It
86
- # first gets the index for the first dimension and then
87
- # iterates over all remaining dimensions. For those dimensions,
88
- # the index is multiplied by the size of the previous
89
- # dimension.
90
- #
91
- # The method performs the transformation on the node itself.
92
- # Any old data is thus lost.
93
- def transform_flatten(array)
94
- self.preorder do |node|
95
- if (node.index?) && (node.parent)
96
- if (node.variable_name == array.name) && (node.dimension == array.dimensions)
97
-
98
- # Compute the new index
99
- results = array.species.dimensions.each_with_index.map { |d,n| '('+node.index_at_dimension(n).to_s+')'+array.factors[n] }
100
- replacement = array.name+'['+results.join(' + ')+']'
101
-
102
- # Replace the node
103
- node.replace_with(C::Index.parse(replacement))
104
- end
105
- end
106
- end
107
- end
108
-
109
- # Method to transform array accesses into register accesses.
110
- # This is only valid for the local loop body and could have
111
- # been done by the actual compiler in a number of cases.
112
- def transform_substitution(array,inout)
113
- replacement = 'register_'+array.name
114
- original_name = ''
115
-
116
- # Change the variable names
117
- self.stmts.preorder do |node|
118
- if (node.index?) && (node.parent)
119
-
120
- # First time replacement
121
- if original_name == ''
122
- if node.variable_name == array.name
123
- node.replace_with(C::Variable.parse(replacement))
124
- original_name = node.to_s
125
- end
126
-
127
- # Second, third, etc. replacement
128
- else
129
- if original_name == node.to_s
130
- node.replace_with(C::Variable.parse(replacement))
131
- end
132
- end
133
- end
134
- end
135
-
136
- # Add prologue and epilogue code
137
- if original_name != ''
138
- if inout
139
- self.stmts[0].insert_prev(C::Declaration.parse(array.type_name+' '+replacement+'='+original_name+';'))
140
- else
141
- self.stmts[0].insert_prev(C::Declaration.parse(array.type_name+' '+replacement+';'))
142
- end
143
- self.stmts[self.stmts.length-1].insert_next(C::ExpressionStatement.parse(original_name+' = '+replacement+';'))
144
- end
145
- end
146
-
147
- # Method to shuffle a 2D array access (e.g. transform from
148
- # A[i][j] into A[j][i]).
149
- def transform_shuffle(arrays)
150
- arrays.each do |array|
151
-
152
- # Change the variable names
153
- self.stmts.preorder do |node|
154
- if (node.index?) && (node.parent)
155
- if node.variable_name == array.name && node.expr.index?
156
- replacement = node.variable_name.to_s+'['+node.index.to_s+']['+node.expr.index.to_s+']'
157
- node.replace_with(C::Index.parse(replacement))
158
- end
159
- end
160
- end
161
-
162
- end
163
- end
164
-
165
- # Method to merge the computations of multiple threads.
166
- def transform_merge_threads(amount,excludes)
167
- self.preorder do |node|
168
- if node.statement?
169
- replacement = C::NodeArray.new
170
- amount.times do |i|
171
- replacement.push(node.clone.rename_variables('_m'+i.to_s,excludes))
172
- end
173
- node.replace_with(replacement)
174
- end
175
- end
176
- end
177
- def rename_variables(suffix,excludes)
178
- self.preorder do |node|
179
- if (node.variable? || node.declarator?) && !(excludes.include?(node.name)) && (!node.parent.call?)
180
- node.name = node.name+suffix
181
- end
182
- end
183
- end
184
-
185
- # This method provides the transformations necessary to
186
- # perform reduction type of operations. The transformations
187
- # involved in this function are on variable names and index
188
- # locations. The argument +id+ specifies which transformation
189
- # to be performed.
190
- #
191
- # Accepted inputs at this point: 2, 3 and 4 (CUDA/OPENCL)
192
- # Also accepted input: 8 (CUDA), 9 (OPENCL) (to create an atomic version of the code)
193
- # TODO: Complete the atomic support, e.g. add support for multiplications and ternary operators
194
- def transform_reduction(input_variable,output_variable,id)
195
-
196
- # Pre-process assign-add type constructions
197
- if self.stmts[0].expr.addassign?
198
- self.stmts[0].expr.replace_with(C::Assign.parse(self.stmts[0].expr.lval.to_s+'='+self.stmts[0].expr.lval.to_s+'+'+self.stmts[0].expr.rval.to_s))
199
- end
200
-
201
- # Create atomic code
202
- if id == 8 || id == 9
203
- function_name = (id == 8) ? 'atomicAdd' : 'atomic_add'
204
- self.preorder do |node|
205
- if node.assign?
206
- if node.lval.index? && node.lval.variable_name == output_variable.name
207
- if node.rval.add?
208
- if node.rval.expr1.variable_name == output_variable.name
209
- node.replace_with(C::Call.parse(function_name+'(&'+node.rval.expr1.to_s+','+node.rval.expr2.to_s+')'))
210
- elsif node.rval.expr2.variable_name == output_variable.name
211
- node.replace_with(C::Call.parse(function_name+'(&'+node.rval.expr2.to_s+','+node.rval.expr1.to_s+')'))
212
- end
213
- elsif node.rval.subtract?
214
- if node.rval.expr1.variable_name == output_variable.name
215
- node.replace_with(C::Call.parse(function_name+'(&'+node.rval.expr1.to_s+',-'+node.rval.expr2.to_s+')'))
216
- elsif node.rval.expr2.variable_name == output_variable.name
217
- node.replace_with(C::Call.parse(function_name+'(&'+node.rval.expr2.to_s+',-'+node.rval.expr1.to_s+')'))
218
- end
219
- else
220
- raise_error('Unsupported atomic reduction operator: '+node.rval.type.inspect)
221
- end
222
- end
223
- end
224
- end
225
- return self
226
- else
227
-
228
- # Split the statement into an operation, the input, and the output
229
- results = []
230
- operation = self.stmts[0].expr.rval.class
231
- [self.stmts[0].expr.rval.expr1.detach,self.stmts[0].expr.rval.expr2.detach].each do |nodes|
232
- nodes.preorder do |node|
233
- if (node.index?)
234
- results[0] = nodes if node.variable_name == input_variable.name
235
- results[1] = nodes if node.variable_name == output_variable.name
236
- end
237
- end
238
- end
239
-
240
- # Process the input part
241
- results[0].preorder do |node|
242
- if (node.index?) && (node.variable_name == input_variable.name)
243
- temporary = C::Variable.parse(Bones::VARIABLE_PREFIX+'temporary')
244
- results[0] = C::Index.parse(Bones::LOCAL_MEMORY+'['+Bones::VARIABLE_PREFIX+'offset_id]') if id == 3
245
- results[0] = temporary if id == 5
246
- if id == 2 || id == 4
247
- if node.parent
248
- node.replace_with(temporary)
249
- else
250
- results[0] = temporary
251
- end
252
- end
253
- end
254
- end
255
-
256
- # Process the output part
257
- results[1] = C::Variable.parse(Bones::PRIVATE_MEMORY) if id == 2 || id == 5
258
- results[1] = C::Index.parse(Bones::LOCAL_MEMORY+'['+Bones::LOCAL_ID+']') if id == 3
259
- results[1] = '0' if id == 4
260
-
261
- # Merge the results together with the operation
262
- return C::Expression.parse(results[1].to_s+'+'+results[0].to_s) if id == 3 || id == 5
263
- case operation.to_s
264
- when 'C::Add' then return C::Expression.parse(results[1].to_s+'+'+results[0].to_s)
265
- when 'C::Subtract' then return C::Expression.parse(results[1].to_s+'-'+results[0].to_s)
266
- else raise_error('Unsupported reduction operation '+operation.to_s+'.')
267
- end
268
- end
269
- end
270
-
271
- # This method returns the complexity of a piece of code in
272
- # terms of the amount of ALU operations (multiplications,
273
- # additions, etc.).
274
- def get_complexity
275
- count = 0
276
- self.preorder do |node|
277
- count += 1 if node.alu?
278
- end
279
- return count
280
- end
281
-
282
- # This method returns the type of a variable (e.g. int, float).
283
- # The method requires the name of a variable as an argument.
284
- # It first tries to find a declaration for the variable in
285
- # by walking through the node. If it cannot find it, it will
286
- # search for a parameter definition from a function call. If
287
- # that cannot be found either, the method will return 'nil',
288
- # meaning that the variable is not defined at all in the
289
- # current node.
290
- def variable_type(variable_name)
291
- self.preorder do |node|
292
- if node.declarator? || node.parameter?
293
- return node.type if node.name == variable_name
294
- end
295
- end
296
- return nil
297
- end
298
-
299
- # This method returns the sizes of a variable as defined
300
- # at the initialization of the array. There are multiple
301
- # possibilities:
302
- # * Static arrays (e.g. int array[12])
303
- # * Static arrays with defines (e.g. int input[N1][N2][N3])
304
- # * Variable length arrays (e.g. float temp[n][m])
305
- # * Dynamically allocated arrays (e.g. int *a = (int *)malloc(size*4))
306
- def size(variable_name)
307
- self.preorder do |node|
308
- if node.declarator? && node.name == variable_name
309
- if node.indirect_type
310
- if node.indirect_type.array?
311
- return node.indirect_type.lengths
312
- elsif node.indirect_type.pointer?
313
- node.preorder do |inner_node|
314
- if inner_node.call? && inner_node.expr.name == 'malloc'
315
- if !node.indirect_type.type # This is a check to ensure single-pointer only
316
- string = '('+inner_node.args.to_s+'/sizeof('+node.type.to_s.gsub('*','').strip+'))'
317
- string.gsub!(/sizeof\(int\)\/sizeof\(int\)/,'1')
318
- string.gsub!(/sizeof\(unsigned int\)\/sizeof\(unsigned int\)/,'1')
319
- string.gsub!(/sizeof\(char\)\/sizeof\(char\)/,'1')
320
- string.gsub!(/sizeof\(unsigned char\)\/sizeof\(unsigned char\)/,'1')
321
- string.gsub!(/sizeof\(double\)\/sizeof\(double\)/,'1')
322
- string.gsub!(/sizeof\(float\)\/sizeof\(float\)/,'1')
323
- return [string]
324
- end
325
- end
326
- end
327
- end
328
- end
329
- end
330
- end
331
- return []
332
- end
333
-
334
- # This is a helper method which calls itself recursively,
335
- # depending on the dimensions of the variable. It stores
336
- # the resulting array sizes in an array 'result'.
337
- def lengths(result = [])
338
- found = '('+self.length.to_s+')'
339
- result.push(found)
340
- return (self.type && self.type.array?) ? self.type.lengths(result) : result
341
- end
342
-
343
- # This method returns a list of undefined variables in the
344
- # node. It walks the node tree until it finds a node that
345
- # full-fills the following:
346
- # * The node is a variable (+node.variable?+)
347
- # * The variable is not in a function call (+!node.parent.call?+)
348
- # * The variable is not defined in the code (+!self.variable_type(node.name)+)
349
- def undefined_variables
350
- variables = []
351
- self.preorder do |node|
352
- variables.push(node.name) if (node.variable?) && (!node.parent.call?) && (!self.variable_type(node.name))
353
- end
354
- return variables.uniq
355
- end
356
-
357
- # This method finds the direction of a variable based on the
358
- # node information. The direction of a variable can be either:
359
- # * +in:+ - The variable is accessed read-only.
360
- # * +out:+ - The variable is accessed write-only.
361
- #
362
- # The method takes the name of a variable and walks through
363
- # the node to search for expressions (assignments and binary
364
- # expressions). For each expression it takes the first and
365
- # second part of the expression and stores it in a list.
366
- # Afterwards, the expressions in the list are analysed for
367
- # occurrences of the variable.
368
- #
369
- # The method raises an error if the variable does not appear
370
- # at all: it is neither input nor output.
371
- def direction(variable_name)
372
- result = {:in => false, :out => false }
373
- expressions = {:in => [], :out => []}
374
- output_nodes = []
375
- self.preorder do |node|
376
-
377
- # First find out if the current node actually contains the target variable somewhere
378
- name_match = false
379
- node.preorder do |match_node|
380
- name_match = true if (match_node.variable?) && (match_node.name == variable_name)
381
- end
382
-
383
- # If there is a match and the current node is of an assignment/binary/declarator type, we can start processing
384
- if (name_match) && (node.assignment_expression? || node.binary_expression? || node.declarator?)
385
-
386
- # First find out if this node can be considered an input (see sum/acc/temp register variable problem - chunk/example1 vs chunk/example5)
387
- possible_input = true
388
- node.preorder do |test_node|
389
- output_nodes.each do |output_node|
390
- possible_input = false if test_node =~ output_node
391
- end
392
- end
393
-
394
- # Store the node's data in a list (input/output lists are separated)
395
- if node.assignment_expression?
396
- output_nodes << node.lval
397
- expressions[:out] << node.lval.remove_index
398
- expressions[:in] << node.rval if possible_input
399
- if !node.assign?
400
- expressions[:in] << node.lval if possible_input
401
- end
402
- elsif node.binary_expression?
403
- expressions[:in] << node.expr1 if possible_input
404
- expressions[:in] << node.expr2.remove_index if possible_input
405
- elsif node.declarator? && node.init
406
- expressions[:in] << node.init if possible_input
407
- end
408
- end
409
- end
410
-
411
- # Set the result according to the list of nodes
412
- expressions.each do |key,expression_list|
413
- expression_list.each do |expression|
414
- expression.preorder do |node|
415
- if (node.variable?) && (node.name == variable_name)
416
- result[key] = true
417
- end
418
- end
419
- end
420
- end
421
-
422
- # Return the result
423
- return Bones::INOUT if result[:in] && result[:out]
424
- return Bones::INPUT if result[:in]
425
- return Bones::OUTPUT if result[:out]
426
- raise_error('Variable "'+variable_name+'" is neither input nor output')
427
- end
428
-
429
- # This method walks through the node and finds the first
430
- # for-loop. If it is found, it returns the contents of the
431
- # for-loop and the name of the loop variable. Obtaining the
432
- # loop variable is conditional because it can either be an
433
- # assignment ('k=0') or a variable definition ('int k=0').
434
- #
435
- # The method raises an error when no for-loop can be found.
436
- # It also raises an error if the loop is not in canonical
437
- # form.
438
- def remove_loop(from,to)
439
- bones_common = Bones::Common.new()
440
- self.preorder do |node|
441
- if node.for_statement?
442
- from_statement = (node.init.assign?) ? node.init.rval : node.init.declarators[0].init
443
- from_loop = (from_statement.variable?) ? from_statement.name : from_statement.to_s
444
- to_loop = (node.cond.expr2.variable?) ? node.cond.expr2.name : ((node.cond.expr2.intliteral?) ? node.cond.expr2.val.to_s : node.cond.expr2.to_s)
445
- to_loop = to_loop.gsub(/\s/,'')
446
- to_loop = '('+to_loop+')-1' if node.cond.less?
447
- to_loop = bones_common.simplify(to_loop)
448
- from_loop = bones_common.simplify(from_loop)
449
- puts Bones::WARNING+'The loop iterator starts at: "'+from_loop+'" (expected "'+from+'")' if from_loop != from
450
- puts Bones::WARNING+'The loop iterator ends at: "'+to_loop+'" (expected "'+to+'")' if to_loop != to
451
- raise_error('The loop increment must be 1') if !(node.iter.unit_increment?)
452
- name = (node.init.assign?) ? node.init.lval.name : node.init.declarators.first.name
453
- return node.stmt, name
454
- end
455
- end
456
- raise_error('Unexpected number of for-loops')
457
- end
458
-
459
- # This method searches for a variable name in the node and
460
- # replaces it with the method's argument, which is given as
461
- # a string. The node itself is modified. The method checks
462
- # whether:
463
- # * The node is a variable (+node.variable?+)
464
- # * The variable has the correct name (+node.name == variable_name+)
465
- # * The variable is not in a function call (+!node.parent.call?+)
466
- def replace_variable(variable_name,replacement)
467
- self.preorder do |node|
468
- node.name = replacement if (node.variable?) && (node.name == variable_name) && (!node.parent.call?)
469
- end
470
- end
471
-
472
- # This method searches for a target node and replaces it with
473
- # a replacement node. Both the target node and the replacement
474
- # node are given as arguments to the method. The method walks
475
- # through the node and checks whether:
476
- # * The node's class is the same as the target class (+node.class == target.class+)
477
- # * The node has a parent (+node.parent != nil+)
478
- # * The node is equal to the target node (+node.match?(target)+)
479
- # If all checks are successful, the node will be replaced with
480
- # the replacement node and the method will return immediately.
481
- #
482
- # The method returns itself if the target node cannot be
483
- # found.
484
- def seach_and_replace_node(target,replacements)
485
- self.preorder do |node|
486
- if (node.class == target.class) && (node.parent != nil) && (node.match?(target))
487
- node.replace_with(replacements)
488
- return self
489
- end
490
- end
491
- return self
492
- end
493
-
494
- # This method searches for a target node and checks whether it
495
- # exists. The input to the method is the target node. The method
496
- # walks through the node and checks whether:
497
- # * The node's class is the same as the target class (+node.class == target.class+)
498
- # * The node has a parent (+node.parent != nil+)
499
- # * The node is equal to the target node (+node.match?(target)+)
500
- # If all checks are successful, the method will return the value
501
- # 'true' immediately. If the target node cannot be found, the
502
- # method returns 'false'.
503
- def node_exists?(target)
504
- self.preorder do |node|
505
- if (node.class == target.class) && (node.parent != nil) && (node.match?(target))
506
- return true
507
- end
508
- end
509
- return false
510
- end
511
-
512
- # This method searches for a target function call and replaces
513
- # it with another. Both the target and the replacement function
514
- # call are given as arguments to the method. The method walks
515
- # through the node and checks whether:
516
- # * The node's class is the same as the target class (+node.class == target.class+)
517
- # * The node has a parent which is a function call (+node.parent.call?+)
518
- # * The node is equal to the target node (+node.match?(target)+)
519
- # If all checks are successful, the node will be replaced with
520
- # the replacement node. The method will continue searching for
521
- # other occurrences of the function call.
522
- #
523
- # The method returns itself.
524
- def seach_and_replace_function_call(target,replacements)
525
- self.preorder do |node|
526
- if (node.class == target.class) && (node.parent.call?) && (node.match?(target))
527
- node.replace_with(replacements)
528
- end
529
- end
530
- return self
531
- end
532
-
533
- # This method searches for a target function name and replaces
534
- # it with another name. Both the target and the replacement
535
- # name are given as arguments to the method. The method walks
536
- # through the node and checks whether:
537
- # * The node's class is a function definition or declaration
538
- # * The node's name is equal to the target node's name
539
- # If the checks are successful, the node's name will be replaced
540
- # The method will continue searching for other occurrences of
541
- # functions with the same name.
542
- #
543
- # The method returns itself.
544
- def seach_and_replace_function_definition(old_name,new_name)
545
- self.preorder do |node|
546
- if (node.function_definition? || node.function_declaration?) && (node.name == old_name)
547
- node.name = new_name
548
- end
549
- end
550
- return self
551
- end
552
-
553
- # This method is a small helper function to remove index
554
- # nodes from a node. It first clones to original node in
555
- # order to not overwrite it, then walks the node and removes
556
- # index nodes. Finally, it returns a new node.
557
- def remove_index
558
- node_clone = self.clone
559
- node_clone.preorder do |node|
560
- node.index.detach if node.index?
561
- end
562
- return node_clone
563
- end
564
-
565
- # This method is a small helper function which simply strips
566
- # any outer brackets from a node. If no outer brackets are
567
- # found, then nothing happens and the node itself is returned.
568
- def strip_brackets
569
- return (self.block?) ? self.stmts : self
570
- end
571
-
572
- # This method returns 'true' if the node is of the 'Variable'
573
- # class. Otherwise, it returns 'false'.
574
- def variable? ; (self.class == C::Variable) end
575
-
576
- # This method returns 'true' if the node is of the 'Array'
577
- # class. Otherwise, it returns 'false'.
578
- def array?
579
- return (self.class == C::Array)
580
- end
581
-
582
- # This method returns 'true' if the node is of the 'Pointer'
583
- # class. Otherwise, it returns 'false'.
584
- def pointer?
585
- return (self.class == C::Pointer)
586
- end
587
-
588
- # This method returns 'true' if the node is of the 'Parameter'
589
- # class. Otherwise, it returns 'false'.
590
- def parameter?
591
- return (self.class == C::Parameter)
592
- end
593
-
594
- # This method returns 'true' if the node is of the 'Declarator'
595
- # class. Otherwise, it returns 'false'.
596
- def declarator?
597
- return (self.class == C::Declarator)
598
- end
599
-
600
- # This method returns 'true' if the node is of the 'Declaration'
601
- # class. Otherwise, it returns 'false'.
602
- def declaration?
603
- return (self.class == C::Declaration)
604
- end
605
-
606
- # This method returns 'true' if the node is of the 'Index'
607
- # class. Otherwise, it returns 'false'.
608
- def index?
609
- return (self.class == C::Index)
610
- end
611
-
612
- # This method returns 'true' if the node is of the 'Call'
613
- # class. Otherwise, it returns 'false'.
614
- def call?
615
- return (self.class == C::Call)
616
- end
617
-
618
- # This method returns 'true' if the node is of the 'FunctionDef'
619
- # class. Otherwise, it returns 'false'.
620
- def function_definition?
621
- return (self.class == C::FunctionDef)
622
- end
623
-
624
- # This method returns 'true' if the node is of the 'Declarator'
625
- # class with its 'indirect_type' equal to 'Function' . Otherwise,
626
- # it returns 'false'.
627
- def function_declaration?
628
- return (self.class == C::Declarator && self.indirect_type.class == C::Function)
629
- end
630
-
631
- # This method returns 'true' if the node is of the 'Block'
632
- # class. Otherwise, it returns 'false'.
633
- def block?
634
- return (self.class == C::Block)
635
- end
636
-
637
- # This method returns 'true' if the node is of the 'For'
638
- # class. Otherwise, it returns 'false'.
639
- def for_statement?
640
- return (self.class == C::For)
641
- end
642
-
643
- # This method returns 'true' if the node is of the 'Less'
644
- # class. Otherwise, it returns 'false'.
645
- def less?
646
- return (self.class == C::Less)
647
- end
648
-
649
- # This method returns 'true' if the node is of the 'Add'
650
- # class. Otherwise, it returns 'false'.
651
- def add?
652
- return (self.class == C::Add)
653
- end
654
-
655
- # This method returns 'true' if the node is of the 'Subtract'
656
- # class. Otherwise, it returns 'false'.
657
- def subtract?
658
- return (self.class == C::Subtract)
659
- end
660
-
661
- # This method returns 'true' if the node is of the 'AddAssign'
662
- # class. Otherwise, it returns 'false'.
663
- def addassign?
664
- return (self.class == C::AddAssign)
665
- end
666
-
667
- # This method returns 'true' if the node is of the 'PostInc'
668
- # class. Otherwise, it returns 'false'.
669
- def postinc?
670
- return (self.class == C::PostInc)
671
- end
672
-
673
- # This method returns 'true' if the node is of the 'PreInc'
674
- # class. Otherwise, it returns 'false'.
675
- def preinc?
676
- return (self.class == C::PreInc)
677
- end
678
-
679
- # This method returns 'true' if the node is of the 'PostDec'
680
- # class. Otherwise, it returns 'false'.
681
- def postdec?
682
- return (self.class == C::PostDec)
683
- end
684
-
685
- # This method returns 'true' if the node is of the 'PreDec'
686
- # class. Otherwise, it returns 'false'.
687
- def predec?
688
- return (self.class == C::PreDec)
689
- end
690
-
691
- # This method returns 'true' if the node is of the 'IntLiteral'
692
- # class. Otherwise, it returns 'false'.
693
- def intliteral?
694
- return (self.class == C::IntLiteral)
695
- end
696
-
697
- # This method returns 'true' if the node is of the 'Assign'
698
- # class. Otherwise, it returns 'false'.
699
- def assign?
700
- return (self.class == C::Assign)
701
- end
702
-
703
- # This method returns 'true' if the node is of the 'Call'
704
- # class. Otherwise, it returns 'false'.
705
- def call?
706
- return (self.class == C::Call)
707
- end
708
-
709
- # This method returns 'true' if the node's class inherits
710
- # from the 'BinaryExpression' class. Otherwise, it returns
711
- # 'false'.
712
- def binary_expression?
713
- return (self.class.superclass == C::BinaryExpression)
714
- end
715
-
716
- # This method returns 'true' if the node's class inherits
717
- # from the 'AssignmentExpression' class. Otherwise, it returns
718
- # 'false'.
719
- def assignment_expression?
720
- return (self.class.superclass == C::AssignmentExpression)
721
- end
722
-
723
- # This method returns 'true' if the node is of the 'PostInc', 'PreInc'
724
- # class or if it is of the 'Assign' class and adds with a value of 1.
725
- # Otherwise, it returns 'false'.
726
- def unit_increment?
727
- return (self.class == C::PostInc) || (self.class == C::PreInc) || (self.class == C::Assign && self.rval.class == C::Add && self.rval.expr2.class == C::IntLiteral && self.rval.expr2.val == 1)
728
- end
729
-
730
- # This method returns 'true' if the node is performing an ALU
731
- # operation. Otherwise, it returns 'false'.
732
- def alu?
733
- return add? || subtract? || addassign? || postinc? || postdec? || preinc? || predec? || binary_expression?
734
- end
735
-
736
- # This method returns 'true' if the node is of the 'ExpressionStatement'
737
- # class. Otherwise, it returns 'false'.
738
- def statement?
739
- return (self.class == C::ExpressionStatement) || (self.class == C::Declaration)
740
- end
741
-
742
- # From this point on are the private methods.
743
- private
744
-
745
- # Override the existing 'indent' method to set the indent size
746
- # manually.
747
- def indent s, levels=1
748
- space = Bones::INDENT
749
- s.gsub(/^/, space)
750
- end
751
-
752
- end
753
-