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
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
+