bones-compiler 1.1.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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
data/lib/bones/species.rb CHANGED
@@ -26,7 +26,8 @@ module Bones
26
26
  # to:: '31' or '15' or '1'
27
27
  # sum:: '32' or '16' or '3'
28
28
  class Species < Common
29
- attr_reader :name, :inputs, :outputs, :skeleton_name, :settings, :prefix
29
+ attr_reader :name, :inputs, :outputs, :prefix
30
+ attr_accessor :skeleton_name, :settings
30
31
 
31
32
  # Initializes the species with a prefix, inputs and out-
32
33
  # puts. It additionally verifies the correctness of the
@@ -144,7 +145,7 @@ module Bones
144
145
  ((parameters == 'N,N') && (search.parameters.length == 2)) ||
145
146
  ((parameters == 'N,1') && (search.parameters.length == 2) && simplify(sum(search.parameters[1])) == '1') ||
146
147
  ((parameters == '1,N') && (search.parameters.length == 2) && simplify(sum(search.parameters[0])) == '1') ||
147
- ((parameters == simplify(search.parameters.map { |r| sum(r) }.join(','))))
148
+ ((parameters == search.parameters.map { |r| simplify(sum(r)) }.join(',')))
148
149
  condition = condition && true
149
150
  else
150
151
  condition = false
@@ -156,7 +157,7 @@ module Bones
156
157
  if (dimensions == 'D') ||
157
158
  ((dimensions == 'N') && (search.dimensions.length == 1)) ||
158
159
  ((dimensions == 'N,N') && (search.dimensions.length == 2)) ||
159
- ((dimensions == simplify(search.dimensions.map { |r| sum(r) }.join(','))))
160
+ ((dimensions == search.dimensions.map { |r| simplify(sum(r)) }.join(',')))
160
161
  condition = condition && true
161
162
  else
162
163
  condition = false
@@ -46,16 +46,26 @@ module Bones
46
46
 
47
47
  # Method to get the start of a range given a dimension 'n'.
48
48
  # The method returns the proper simplified result, taking
49
- # chunk-sizes into account.
49
+ # chunk/neighbourhood-sizes into account.
50
50
  def from_at(n)
51
- return simplify(from(@dimensions[n]))
51
+ if (neighbourhood?)
52
+ return simplify('('+from(@dimensions[n])+')-('+from(@parameters[n])+')')
53
+ else
54
+ return simplify(from(@dimensions[n]))
55
+ end
52
56
  end
53
57
 
54
58
  # Method to get the end of a range given a dimension 'n'.
55
59
  # The method returns the proper simplified result, taking
56
- # chunk-sizes into account.
60
+ # chunk/neighbourhood-sizes into account.
57
61
  def to_at(n)
58
- return (chunk?) ? simplify('((('+to(@dimensions[n])+'+1)/('+to(@parameters[n])+'+1))-1)') : simplify(to(@dimensions[n]))
62
+ if (chunk?)
63
+ return simplify('((('+to(@dimensions[n])+'+1)/('+to(@parameters[n])+'+1))-1)')
64
+ elsif (neighbourhood?)
65
+ return simplify('('+to(@dimensions[n])+')-('+to(@parameters[n])+')')
66
+ else
67
+ return simplify(to(@dimensions[n]))
68
+ end
59
69
  end
60
70
 
61
71
  # Method to verify if a structure is empty or not (e.g. if
data/lib/castaddon.rb CHANGED
@@ -7,12 +7,17 @@ end
7
7
  require 'rubygems'
8
8
  require 'cast'
9
9
 
10
- # Include the extentions to the CAST gem provided by the author
11
- # of Bones. These extentions provide a significant amount of
12
- # functionality for Bones itself.
13
- require 'castaddon/node.rb'
14
- require 'castaddon/type.rb'
15
- require 'castaddon/index.rb'
10
+ # Include the extentions to the CAST gem provided. These
11
+ # extentions provide a significant amount of functionality
12
+ # for Bones and A-Darwin.
13
+ require 'castaddon/node_common.rb'
14
+ require 'castaddon/node_adarwin.rb'
15
+ if File.exists?('lib/bones.rb')
16
+ require 'castaddon/node_bones.rb'
17
+ require 'castaddon/transformations.rb'
18
+ require 'castaddon/type.rb'
19
+ require 'castaddon/index.rb'
20
+ end
16
21
 
17
22
  # Modify the NodeArray and NodeChain lists to output correct
18
23
  # code when printed to a file.
@@ -0,0 +1,245 @@
1
+
2
+
3
+ # This is an extension to the CAST Node class. This particular extension is for
4
+ # A-Darwin only methods. These methods are mainly used to extract loops and loop
5
+ # data from the CAST nodes.
6
+ class C::Node
7
+
8
+ # This method retrieves all directly following loops from a node, i.e. the
9
+ # loops belonging to a perfectly nested loop. It is a recursive method: it
10
+ # retrieves a first loop and calls the method again on the body of the loop.
11
+ # It collects all the data in the +loop_data+ array.
12
+ def get_direct_loops(loop_data = [])
13
+
14
+ # Retrieve the next loop
15
+ new_loop = get_single_loop()
16
+
17
+ # Don't continue if the loop is independent of the writes in the code. This
18
+ # is part of the selection process of what loops to be considered inner or
19
+ # outer loops.
20
+ if loop_data.length > 0
21
+ written_indices = self.clone.get_accesses().map do |a|
22
+ (a[:type] == "write") ? a[:indices].map{ |i| i.to_s } : []
23
+ end
24
+ if !written_indices.flatten.uniq.include?(new_loop[:var])
25
+ return loop_data
26
+ end
27
+ end
28
+
29
+ # Push the new loop into the array
30
+ loop_data.push(new_loop)
31
+
32
+ # Check whether the current is actually a loop.
33
+ # TODO: Is this check really needed or is this just a safety net?
34
+ if self.for_statement? && self.stmt
35
+ body = self.stmt.stmts
36
+
37
+ # Check whether or not there is another loop directly following and make
38
+ # sure that the body is not empty.
39
+ if body.length == 1 && body.first.for_statement?
40
+ body.first.get_direct_loops(loop_data)
41
+ end
42
+ end
43
+
44
+ # Return all the loop data
45
+ return loop_data
46
+ end
47
+
48
+ # This method retrieves all array references in the current node. It retrieves
49
+ # information on loops and on if-statements as well. This method is
50
+ # destructive on the current node. It is furthermore called recursively.
51
+ def get_accesses(accesses = [],loop_data = [],if_statements = [])
52
+
53
+ # Iterate over all the nodes
54
+ self.preorder do |node|
55
+
56
+ # A loop has been found. Proceed as follows: 1) store the loop data, 2)
57
+ # call this method recursively on the loop body, and 3) remove the loop
58
+ # body from the node.
59
+ if node.for_statement? && node.stmt
60
+ next_loop_data = loop_data.clone
61
+ next_loop_data.push(node.get_single_loop)
62
+ node.stmt.clone.get_accesses(accesses,next_loop_data,if_statements)
63
+ node.remove_node(node.stmt)
64
+
65
+ # An if-statement has been found. Proceed as follows: 1) store the (one or
66
+ # more) if-statement conditions, 2) call this method recursively on the
67
+ # if-statement body, and 3) remove the if-statement body from the node.
68
+ elsif node.if_statement?
69
+ next_if_statements = if_statements.clone
70
+ node.cond.get_conditions().each do |condition|
71
+ next_if_statements.push(condition)
72
+ end
73
+ node.then.clone.get_accesses(accesses,loop_data,next_if_statements)
74
+ node.remove_node(node.then)
75
+
76
+ # We haven't found an if-statement or loop in the current node, so it
77
+ # implies that we can search for an array reference.
78
+ # TODO: Array references as part of conditions or bounds of loops are not
79
+ # found in this way.
80
+ else
81
+
82
+ # Collect all the writes we have seen so far. This is used to check for
83
+ # references that are 'register' references because they have been
84
+ # written before.
85
+ writes = accesses.map{ |e| e[:access] if e[:type] == 'write' }.flatten
86
+
87
+ # Collect the potential references
88
+ to_search = []
89
+ if node.assignment_expression?
90
+ to_search << [node.lval,'write',true]
91
+ to_search << [node.lval,'read',false] if !node.assign?
92
+ to_search << [node.rval,'read',false]
93
+ elsif node.binary_expression?
94
+ to_search << [node.expr1,'read',false]
95
+ to_search << [node.expr2,'read',false]
96
+ elsif node.declarator? && node.init
97
+ to_search << [node.init,'read',false]
98
+ end
99
+
100
+ # Process the potential references into 'accesses' hashes
101
+ to_search.each do |item|
102
+ if item[2] || (writes & item[0].get_index_nodes().flatten).empty?
103
+ item[0].get_index_nodes().each do |access|
104
+ accesses << {
105
+ :access => access,
106
+ :name => access.get_array_name(),
107
+ :indices => access.get_indices(),
108
+ :type => item[1],
109
+ :loop_data => loop_data,
110
+ :if_statements => if_statements
111
+ }
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
117
+
118
+ # Return the array references as hashes
119
+ return accesses.uniq
120
+ end
121
+
122
+ # This method retrieves the bounds for an if-statement. The method is called
123
+ # recursively if there are multiple conditions.
124
+ # TODO: What about '||' (or) conditions? They are currently handles as '&&'.
125
+ # TODO: Are these all the possibilities (&&,||,>=,>,<=,<) for conditions?
126
+ def get_conditions(results=[])
127
+
128
+ # Recursive call for 'And' (&&) and 'or' (||) compound conditions
129
+ if and? || or?
130
+ expr1.get_conditions(results)
131
+ expr2.get_conditions(results)
132
+
133
+ # Greater than or equal (>=)
134
+ elsif more_or_equal?
135
+ results << [simplify("#{expr1}")+'='+simplify("(#{expr2})"),'']
136
+
137
+ # Greater than (>)
138
+ elsif more?
139
+ results << [simplify("#{expr1}")+'='+simplify("(#{expr2})+1"),'']
140
+
141
+ # Less than or equal (<=)
142
+ elsif less_or_equal?
143
+ results << ['',simplify("#{expr1}")+'='+simplify("(#{expr2})")]
144
+
145
+ # Less than (<)
146
+ elsif less?
147
+ results << ['',simplify("#{expr1}")+'='+simplify("(#{expr2})-1")]
148
+
149
+ # Unsupported conditions
150
+ else
151
+ raise_error("Unsupported if-condition: #{self.to_s}")
152
+ end
153
+ end
154
+
155
+ # This method retrieves a single loop from the current node and collects its
156
+ # data: 1) the loop variable, 2) the lower-bound, 3) the upper-bound, and 4)
157
+ # the loop step.
158
+ # FIXME: For decrementing loops, should the min/max be swapped?
159
+ def get_single_loop()
160
+ loop_datum = { :var => '', :min => '', :max => '', :step => ''}
161
+ if self.for_statement?
162
+
163
+ # Get the loop start condition and the loop variable.
164
+ # TODO: Add support for other types of initialisations, e.g. a declaration
165
+ if self.init.assign?
166
+ loop_datum[:var] = self.init.lval.name
167
+ loop_datum[:min] = self.init.rval.get_value.to_s
168
+ elsif self.init.declaration?
169
+ loop_datum[:var] = self.init.declarators.first.name
170
+ loop_datum[:min] = self.init.declarators.first.init.to_s
171
+ else
172
+ raise_error("Unsupported loop initialization: #{self.init}")
173
+ end
174
+
175
+ # Get the loop's upper-bound condition.
176
+ # TODO: Add support for the unsupported cases.
177
+ var_is_on_left = (self.cond.expr1.get_value == loop_datum[:var])
178
+ loop_datum[:max] = case
179
+ when self.cond.less? then (var_is_on_left) ? simplify("#{self.cond.expr2.get_value}-1") : "unsupported"
180
+ when self.cond.more? then (var_is_on_left) ? "unsupported" : simplify("#{self.cond.expr1.get_value}-1")
181
+ when self.cond.less_or_equal? then (var_is_on_left) ? "#{self.cond.expr2.get_value}" : "unsupported"
182
+ when self.cond.more_or_equal? then (var_is_on_left) ? "unsupported" : "#{self.cond.expr1.get_value}"
183
+ end
184
+ raise_error("Unsupported loop condition: #{self.cond}") if loop_datum[:max] == "unsupported"
185
+
186
+ # Get the loop iterator.
187
+ # TODO: Investigate whether we can handle non-basic cases
188
+ iterator = self.iter.to_s
189
+ loop_datum[:step] = case iterator
190
+ when "#{loop_datum[:var]}++" then '1'
191
+ when "++#{loop_datum[:var]}" then '1'
192
+ when "#{loop_datum[:var]}--" then '-1'
193
+ when "--#{loop_datum[:var]}" then '-1'
194
+ else simplify(self.iter.rval.to_s.gsub(loop_datum[:var],'0'))
195
+ end
196
+ end
197
+ return loop_datum
198
+ end
199
+
200
+ # This method retrieves all loops from a loop nest. The method is based on the
201
+ # +get_single_loop+ method to extract the actual loop information.
202
+ def get_all_loops()
203
+ loops = []
204
+ self.preorder do |node|
205
+ loops << node.get_single_loop() if node.for_statement?
206
+ end
207
+ return loops
208
+ end
209
+
210
+ # This method retrieves all nodes from the current node that are index node.
211
+ # Such nodes represent array references, e.g. in A[i+3], [i+3] is the index
212
+ # node.
213
+ def get_index_nodes()
214
+ nodes = []
215
+ self.preorder do |node|
216
+ nodes << node if node.index? && !node.parent.index?
217
+ end
218
+ return nodes
219
+ end
220
+
221
+ # This method retrieves all indices of index nodes from the current node.
222
+ def get_indices()
223
+ indices = []
224
+ self.postorder do |node|
225
+ indices << node.index if node.index?
226
+ end
227
+ return indices
228
+ end
229
+
230
+ # This method retrieves the name of the array reference.
231
+ def get_array_name()
232
+ self.preorder do |node|
233
+ return node.expr.to_s if node.index? && !node.expr.index?
234
+ end
235
+ end
236
+
237
+ # This method retrieves the value from the current node. The value can be an
238
+ # integer (in case of a constant) or a string (in case of a variable).
239
+ def get_value()
240
+ return self.val if self.intliteral?
241
+ return self.name if self.variable?
242
+ return self.to_s
243
+ end
244
+
245
+ end
@@ -0,0 +1,316 @@
1
+
2
+ # This class provides an extension to the CAST node class, which
3
+ # is a parent class for all other CAST classes. The extension
4
+ # consists of three different types of methods:
5
+ # * Methods starting with +transform_+, handling the major code transformations.
6
+ # * Methods to obtain information on variables, such as their direction and whether they are defined or not.
7
+ # * Helper methods, among others those that indicate whether a node is of a certain class.
8
+ class C::Node
9
+
10
+ # Pre-process method. It currently pre-processes a piece of
11
+ # code (typically the kernel code) to replace particular
12
+ # code structures with others, which can be handled (better)
13
+ # by Bones. For now, the pre-process method performs the
14
+ # following transformations:
15
+ # * Replaces all incrementors (i++) outside for loops with an assignment (i=i+1).
16
+ # * Replaces all decrementors (i--) outside for loops with an assignment (i=i-1).
17
+ def preprocess(conditional=true)
18
+ self.preorder do |node|
19
+ if node.postinc? || node.preinc?
20
+ node.replace_with(C::AssignmentExpression.parse(node.expr.to_s+' = '+node.expr.to_s+' + 1')) unless conditional && node.parent.for_statement?
21
+ elsif node.postdec? || node.predec?
22
+ node.replace_with(C::AssignmentExpression.parse(node.expr.to_s+' = '+node.expr.to_s+' - 1')) unless conditional && node.parent.for_statement?
23
+ end
24
+ end
25
+ end
26
+
27
+ # Method to obtain a list of all functions in the code. If
28
+ # no functions can be found, an empty array is returned. For
29
+ # every function found, the function itself is pushed to the
30
+ # list. This method also makes sure that there is at least one
31
+ # function with the name 'main'. If this is not the case, an
32
+ # error is raised.
33
+ def get_functions
34
+ includes_main = false
35
+ function_list = []
36
+ self.preorder do |node|
37
+ if node.function_definition?
38
+ function_list.push(node)
39
+ includes_main = true if (node.name == 'main' || node.name == Bones::VARIABLE_PREFIX+'main')
40
+ end
41
+ end
42
+ raise_error('No "main"-function detected in the input file') if !includes_main
43
+ return function_list
44
+ end
45
+
46
+ # This method returns the complexity of a piece of code in
47
+ # terms of the amount of ALU operations (multiplications,
48
+ # additions, etc.).
49
+ def get_complexity
50
+ count = 0
51
+ self.preorder do |node|
52
+ count += 1 if node.alu?
53
+ end
54
+ return count
55
+ end
56
+
57
+ # This method returns the type of a variable (e.g. int, float).
58
+ # The method requires the name of a variable as an argument.
59
+ # It first tries to find a declaration for the variable in
60
+ # by walking through the node. If it cannot find it, it will
61
+ # search for a parameter definition from a function call. If
62
+ # that cannot be found either, the method will return 'nil',
63
+ # meaning that the variable is not defined at all in the
64
+ # current node.
65
+ def variable_type(variable_name)
66
+ self.preorder do |node|
67
+ if node.declarator? || node.parameter?
68
+ return node.type if node.name == variable_name
69
+ end
70
+ end
71
+ return nil
72
+ end
73
+
74
+ # This method returns the sizes of a variable as defined
75
+ # at the initialization of the array. There are multiple
76
+ # possibilities:
77
+ # * Static arrays (e.g. int array[12])
78
+ # * Static arrays with defines (e.g. int input[N1][N2][N3])
79
+ # * Variable length arrays (e.g. float temp[n][m])
80
+ # * Dynamically allocated arrays (e.g. int *a = (int *)malloc(size*4))
81
+ def size(variable_name)
82
+ self.preorder do |node|
83
+ if node.declarator? && node.name == variable_name
84
+ if node.indirect_type
85
+ if node.indirect_type.array?
86
+ return node.indirect_type.lengths
87
+ elsif node.indirect_type.pointer?
88
+ node.preorder do |inner_node|
89
+ if inner_node.call? && inner_node.expr.name == 'malloc'
90
+ if !node.indirect_type.type # This is a check to ensure single-pointer only
91
+ string = '('+inner_node.args.to_s+'/sizeof('+node.type.to_s.gsub('*','').strip+'))'
92
+ string.gsub!(/sizeof\(int\)\/sizeof\(int\)/,'1')
93
+ string.gsub!(/sizeof\(unsigned int\)\/sizeof\(unsigned int\)/,'1')
94
+ string.gsub!(/sizeof\(char\)\/sizeof\(char\)/,'1')
95
+ string.gsub!(/sizeof\(unsigned char\)\/sizeof\(unsigned char\)/,'1')
96
+ string.gsub!(/sizeof\(double\)\/sizeof\(double\)/,'1')
97
+ string.gsub!(/sizeof\(float\)\/sizeof\(float\)/,'1')
98
+ return [string]
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+ return []
107
+ end
108
+
109
+ # This is a helper method which calls itself recursively,
110
+ # depending on the dimensions of the variable. It stores
111
+ # the resulting array sizes in an array 'result'.
112
+ def lengths(result = [])
113
+ found = '('+self.length.to_s+')'
114
+ result.push(found)
115
+ return (self.type && self.type.array?) ? self.type.lengths(result) : result
116
+ end
117
+
118
+ # This method returns a list of undefined variables in the
119
+ # node. It walks the node tree until it finds a node that
120
+ # full-fills the following:
121
+ # * The node is a variable (+node.variable?+)
122
+ # * The variable is not in a function call (+!node.parent.call?+)
123
+ # * The variable is not defined in the code (+!self.variable_type(node.name)+)
124
+ def undefined_variables
125
+ variables = []
126
+ self.preorder do |node|
127
+ variables.push(node.name) if (node.variable?) && (!node.parent.call?) && (!self.variable_type(node.name))
128
+ end
129
+ return variables.uniq
130
+ end
131
+
132
+ # This method finds the direction of a variable based on the
133
+ # node information. The direction of a variable can be either:
134
+ # * +in:+ - The variable is accessed read-only.
135
+ # * +out:+ - The variable is accessed write-only.
136
+ #
137
+ # The method takes the name of a variable and walks through
138
+ # the node to search for expressions (assignments and binary
139
+ # expressions). For each expression it takes the first and
140
+ # second part of the expression and stores it in a list.
141
+ # Afterwards, the expressions in the list are analysed for
142
+ # occurrences of the variable.
143
+ #
144
+ # The method raises an error if the variable does not appear
145
+ # at all: it is neither input nor output.
146
+ def direction(variable_name)
147
+ result = {:in => false, :out => false }
148
+ expressions = {:in => [], :out => []}
149
+ output_nodes = []
150
+ self.preorder do |node|
151
+
152
+ # First find out if the current node actually contains the target variable somewhere
153
+ name_match = false
154
+ node.preorder do |match_node|
155
+ name_match = true if (match_node.variable?) && (match_node.name == variable_name)
156
+ end
157
+
158
+ # If there is a match and the current node is of an assignment/binary/declarator type, we can start processing
159
+ if (name_match) && (node.assignment_expression? || node.binary_expression? || node.declarator?)
160
+
161
+ # First find out if this node can be considered an input (see sum/acc/temp register variable problem - chunk/example1 vs chunk/example5)
162
+ possible_input = true
163
+ node.preorder do |test_node|
164
+ output_nodes.each do |output_node|
165
+ possible_input = false if test_node =~ output_node
166
+ end
167
+ end
168
+
169
+ # Store the node's data in a list (input/output lists are separated)
170
+ if node.assignment_expression?
171
+ output_nodes << node.lval
172
+ expressions[:out] << node.lval.remove_index
173
+ expressions[:in] << node.rval if possible_input
174
+ if !node.assign?
175
+ expressions[:in] << node.lval if possible_input
176
+ end
177
+ elsif node.binary_expression?
178
+ expressions[:in] << node.expr1 if possible_input
179
+ expressions[:in] << node.expr2.remove_index if possible_input
180
+ elsif node.declarator? && node.init
181
+ expressions[:in] << node.init if possible_input
182
+ end
183
+ end
184
+ end
185
+
186
+ # Set the result according to the list of nodes
187
+ expressions.each do |key,expression_list|
188
+ expression_list.each do |expression|
189
+ expression.preorder do |node|
190
+ if (node.variable?) && (node.name == variable_name)
191
+ result[key] = true
192
+ end
193
+ end
194
+ end
195
+ end
196
+
197
+ # Return the result
198
+ return Bones::INOUT if result[:in] && result[:out]
199
+ return Bones::INPUT if result[:in]
200
+ return Bones::OUTPUT if result[:out]
201
+ raise_error('Variable "'+variable_name+'" is neither input nor output')
202
+ end
203
+
204
+ # This method walks through the node and finds the first
205
+ # for-loop. If it is found, it returns the contents of the
206
+ # for-loop and the name of the loop variable. Obtaining the
207
+ # loop variable is conditional because it can either be an
208
+ # assignment ('k=0') or a variable definition ('int k=0').
209
+ #
210
+ # The method raises an error when no for-loop can be found.
211
+ # It also raises an error if the loop is not in canonical
212
+ # form.
213
+ def remove_loop(from,to)
214
+ self.preorder do |node|
215
+ if node.for_statement?
216
+ from_statement = (node.init.assign?) ? node.init.rval : node.init.declarators[0].init
217
+ from_loop = (from_statement.variable?) ? from_statement.name : from_statement.to_s
218
+ 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)
219
+ to_loop = to_loop.gsub(/\s/,'')
220
+ to_loop = '('+to_loop+')-1' if node.cond.less?
221
+ to_loop = simplify(to_loop)
222
+ from_loop = simplify(from_loop)
223
+ puts Bones::WARNING+'The loop iterator starts at: "'+from_loop+'" (expected "'+from+'")' if from_loop != from
224
+ puts Bones::WARNING+'The loop iterator ends at: "'+to_loop+'" (expected "'+to+'")' if to_loop != to
225
+ raise_error('The loop increment must be 1') if !(node.iter.unit_increment?)
226
+ name = (node.init.assign?) ? node.init.lval.name : node.init.declarators.first.name
227
+ return node.stmt, name
228
+ end
229
+ end
230
+ raise_error('Unexpected number of for-loops')
231
+ end
232
+
233
+ # This method searches for a target node and checks whether it
234
+ # exists. The input to the method is the target node. The method
235
+ # walks through the node and checks whether:
236
+ # * The node's class is the same as the target class (+node.class == target.class+)
237
+ # * The node has a parent (+node.parent != nil+)
238
+ # * The node is equal to the target node (+node.match?(target)+)
239
+ # If all checks are successful, the method will return the value
240
+ # 'true' immediately. If the target node cannot be found, the
241
+ # method returns 'false'.
242
+ def node_exists?(target)
243
+ self.preorder do |node|
244
+ if (node.class == target.class) && (node.parent != nil) && (node.match?(target))
245
+ return true
246
+ end
247
+ end
248
+ return false
249
+ end
250
+
251
+ # This method searches for a target function call and replaces
252
+ # it with another. Both the target and the replacement function
253
+ # call are given as arguments to the method. The method walks
254
+ # through the node and checks whether:
255
+ # * The node's class is the same as the target class (+node.class == target.class+)
256
+ # * The node has a parent which is a function call (+node.parent.call?+)
257
+ # * The node is equal to the target node (+node.match?(target)+)
258
+ # If all checks are successful, the node will be replaced with
259
+ # the replacement node. The method will continue searching for
260
+ # other occurrences of the function call.
261
+ #
262
+ # The method returns itself.
263
+ def search_and_replace_function_call(target,replacements)
264
+ self.preorder do |node|
265
+ if (node.class == target.class) && (node.parent.call?) && (node.match?(target))
266
+ node.replace_with(replacements)
267
+ end
268
+ end
269
+ return self
270
+ end
271
+
272
+ # This method searches for a target function name and replaces
273
+ # it with another name. Both the target and the replacement
274
+ # name are given as arguments to the method. The method walks
275
+ # through the node and checks whether:
276
+ # * The node's class is a function definition or declaration
277
+ # * The node's name is equal to the target node's name
278
+ # If the checks are successful, the node's name will be replaced
279
+ # The method will continue searching for other occurrences of
280
+ # functions with the same name.
281
+ #
282
+ # The method returns itself.
283
+ def search_and_replace_function_definition(old_name,new_name)
284
+ self.preorder do |node|
285
+ if (node.function_definition? || node.function_declaration?) && (node.name == old_name)
286
+ node.name = new_name
287
+ end
288
+ end
289
+ return self
290
+ end
291
+
292
+ # This method is a small helper function to remove index
293
+ # nodes from a node. It first clones to original node in
294
+ # order to not overwrite it, then walks the node and removes
295
+ # index nodes. Finally, it returns a new node.
296
+ def remove_index
297
+ node_clone = self.clone
298
+ node_clone.preorder do |node|
299
+ node.index.detach if node.index?
300
+ end
301
+ return node_clone
302
+ end
303
+
304
+ # This method checks whether the given code has any conditional
305
+ # statements (if-statements)
306
+ def has_conditional_statements?
307
+ self.preorder do |node|
308
+ if node.if_statement?
309
+ return true
310
+ end
311
+ end
312
+ return false
313
+ end
314
+
315
+ end
316
+