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.
- checksums.yaml +15 -0
- data/CHANGELOG +37 -0
- data/LICENSE +1 -1
- data/README.rdoc +95 -70
- data/Rakefile +78 -3
- data/VERSION +1 -1
- data/bin/adarwin +17 -0
- data/examples/benchmarks/PolyBench/2mm.c +104 -0
- data/examples/benchmarks/{3mm.c → PolyBench/3mm.c} +5 -2
- data/examples/benchmarks/{adi.c → PolyBench/adi.c} +6 -3
- data/examples/benchmarks/{atax.c → PolyBench/atax.c} +5 -2
- data/examples/benchmarks/{bicg.c → PolyBench/bicg.c} +5 -2
- data/examples/benchmarks/{cholesky.c → PolyBench/cholesky.c} +3 -0
- data/examples/benchmarks/{common.h → PolyBench/common.h} +2 -2
- data/examples/benchmarks/{correlation.c → PolyBench/correlation.c} +16 -7
- data/examples/benchmarks/{covariance.c → PolyBench/covariance.c} +7 -2
- data/examples/benchmarks/{doitgen.c → PolyBench/doitgen.c} +5 -2
- data/examples/benchmarks/{durbin.c → PolyBench/durbin.c} +3 -0
- data/examples/benchmarks/{dynprog.c → PolyBench/dynprog.c} +3 -0
- data/examples/benchmarks/{fdtd-2d-apml.c → PolyBench/fdtd-2d-apml.c} +3 -0
- data/examples/benchmarks/{fdtd-2d.c → PolyBench/fdtd-2d.c} +5 -2
- data/examples/benchmarks/{floyd-warshall.c → PolyBench/floyd-warshall.c} +3 -0
- data/examples/benchmarks/{gemm.c → PolyBench/gemm.c} +5 -2
- data/examples/benchmarks/{gemver.c → PolyBench/gemver.c} +5 -2
- data/examples/benchmarks/{gesummv.c → PolyBench/gesummv.c} +5 -2
- data/examples/benchmarks/{gramschmidt.c → PolyBench/gramschmidt.c} +3 -0
- data/examples/benchmarks/{jacobi-1d-imper.c → PolyBench/jacobi-1d-imper.c} +10 -2
- data/examples/benchmarks/{jacobi-2d-imper.c → PolyBench/jacobi-2d-imper.c} +8 -3
- data/examples/benchmarks/{lu.c → PolyBench/lu.c} +3 -0
- data/examples/benchmarks/{ludcmp.c → PolyBench/ludcmp.c} +3 -0
- data/examples/benchmarks/{mvt.c → PolyBench/mvt.c} +6 -2
- data/examples/benchmarks/{reg_detect.c → PolyBench/reg_detect.c} +3 -0
- data/examples/benchmarks/{seidel-2d.c → PolyBench/seidel-2d.c} +3 -0
- data/examples/benchmarks/{symm.c → PolyBench/symm.c} +3 -0
- data/examples/benchmarks/{syr2k.c → PolyBench/syr2k.c} +5 -2
- data/examples/benchmarks/{syrk.c → PolyBench/syrk.c} +7 -4
- data/examples/benchmarks/{trisolv.c → PolyBench/trisolv.c} +3 -0
- data/examples/benchmarks/{trmm.c → PolyBench/trmm.c} +3 -0
- data/examples/benchmarks/Rodinia/cfd.c +180 -0
- data/examples/benchmarks/Rodinia/hotspot.c +228 -0
- data/examples/benchmarks/Rodinia/kmeans.c +164 -0
- data/examples/benchmarks/Rodinia/srad.c +188 -0
- data/examples/benchmarks/other/common.h +0 -0
- data/examples/benchmarks/other/dct.c +58 -0
- data/examples/benchmarks/other/mm.c +50 -0
- data/examples/benchmarks/{saxpy.c → other/saxpy.c} +11 -7
- data/examples/chunk/{example1.c → example01.c} +0 -0
- data/examples/chunk/{example2.c → example02.c} +0 -0
- data/examples/chunk/{example3.c → example03.c} +0 -0
- data/examples/chunk/{example4.c → example04.c} +0 -0
- data/examples/chunk/{example5.c → example05.c} +0 -0
- data/examples/chunk/example06.c +45 -0
- data/examples/chunk/example07.c +49 -0
- data/examples/dependences/example01.c +42 -0
- data/examples/dependences/example02.c +40 -0
- data/examples/dependences/example03.c +43 -0
- data/examples/dependences/example04.c +44 -0
- data/examples/dependences/example05.c +42 -0
- data/examples/element/{example1.c → example01.c} +0 -0
- data/examples/element/{example2.c → example02.c} +2 -2
- data/examples/element/{example3.c → example03.c} +0 -0
- data/examples/element/{example4.c → example04.c} +0 -0
- data/examples/element/{example5.c → example05.c} +0 -0
- data/examples/element/{example6.c → example06.c} +0 -0
- data/examples/element/{example7.c → example07.c} +0 -0
- data/examples/element/{example8.c → example08.c} +0 -0
- data/examples/element/{example9.c → example09.c} +0 -0
- data/examples/element/example13.c +73 -0
- data/examples/fusion/example01.c +68 -0
- data/examples/fusion/example02.c +73 -0
- data/examples/fusion/example03.c +72 -0
- data/examples/fusion/example04.c +61 -0
- data/examples/fusion/example05.c +55 -0
- data/examples/neighbourhood/{example1.c → example01.c} +0 -0
- data/examples/neighbourhood/{example2.c → example02.c} +0 -0
- data/examples/neighbourhood/{example3.c → example03.c} +0 -0
- data/examples/neighbourhood/{example4.c → example04.c} +0 -0
- data/examples/neighbourhood/example05.c +44 -0
- data/examples/shared/{example1.c → example01.c} +0 -0
- data/examples/shared/{example2.c → example02.c} +0 -0
- data/examples/shared/{example3.c → example03.c} +0 -0
- data/examples/shared/{example4.c → example04.c} +0 -0
- data/examples/shared/{example5.c → example05.c} +0 -0
- data/lib/adarwin.rb +62 -0
- data/lib/adarwin/dependences.rb +268 -0
- data/lib/adarwin/engine.rb +277 -0
- data/lib/adarwin/fusion.rb +174 -0
- data/lib/adarwin/interval.rb +57 -0
- data/lib/adarwin/memorycopies.rb +153 -0
- data/lib/adarwin/nest.rb +225 -0
- data/lib/adarwin/preprocessor.rb +76 -0
- data/lib/adarwin/reference.rb +261 -0
- data/lib/bones.rb +4 -55
- data/lib/bones/algorithm.rb +77 -40
- data/lib/bones/copy.rb +26 -0
- data/lib/bones/engine.rb +147 -31
- data/lib/bones/preprocessor.rb +92 -12
- data/lib/bones/species.rb +4 -3
- data/lib/bones/structure.rb +14 -4
- data/lib/castaddon.rb +11 -6
- data/lib/castaddon/node_adarwin.rb +245 -0
- data/lib/castaddon/node_bones.rb +316 -0
- data/lib/castaddon/node_common.rb +289 -0
- data/lib/castaddon/transformations.rb +236 -0
- data/lib/common.rb +216 -0
- data/skeletons/CPU-C/common/header.c +3 -0
- data/skeletons/CPU-C/common/mem_global.c +0 -0
- data/skeletons/CPU-C/common/timer_2_start.c +11 -13
- data/skeletons/CPU-C/common/timer_2_stop.c +1 -1
- data/skeletons/CPU-C/common/timer_globals.c +29 -0
- data/skeletons/CPU-OPENCL-INTEL/common/globals.c +1 -1
- data/skeletons/CPU-OPENCL-INTEL/common/header.c +3 -0
- data/skeletons/CPU-OPENCL-INTEL/common/mem_copy_D2H.c +7 -2
- data/skeletons/CPU-OPENCL-INTEL/common/mem_copy_H2D.c +4 -2
- data/skeletons/CPU-OPENCL-INTEL/common/mem_global.c +0 -0
- data/skeletons/CPU-OPENCL-INTEL/common/mem_prologue.c +6 -3
- data/skeletons/CPU-OPENCL-INTEL/common/timer_2_stop.c +1 -1
- data/skeletons/CPU-OPENCL-INTEL/common/timer_globals.c +24 -0
- data/skeletons/CPU-OPENMP/common/globals.c +1 -0
- data/skeletons/CPU-OPENMP/common/header.c +3 -0
- data/skeletons/CPU-OPENMP/common/mem_global.c +0 -0
- data/skeletons/CPU-OPENMP/common/timer_1_start.c +0 -12
- data/skeletons/CPU-OPENMP/common/timer_2_stop.c +1 -1
- data/skeletons/CPU-OPENMP/common/timer_globals.c +33 -0
- data/skeletons/GPU-CUDA/common/globals.c +27 -3
- data/skeletons/GPU-CUDA/common/header.c +2 -0
- data/skeletons/GPU-CUDA/common/mem_async_alloc.c +6 -0
- data/skeletons/GPU-CUDA/common/mem_async_copyin.c +6 -0
- data/skeletons/GPU-CUDA/common/mem_async_copyout.c +6 -0
- data/skeletons/GPU-CUDA/common/mem_async_free.c +6 -0
- data/skeletons/GPU-CUDA/common/mem_copy_D2H.c +2 -1
- data/skeletons/GPU-CUDA/common/mem_copy_H2D.c +2 -1
- data/skeletons/GPU-CUDA/common/mem_global.c +1 -0
- data/skeletons/GPU-CUDA/common/mem_prologue.c +1 -2
- data/skeletons/GPU-CUDA/common/scheduler.c +86 -0
- data/skeletons/GPU-CUDA/common/timer_2_start.c +2 -4
- data/skeletons/GPU-CUDA/common/timer_2_stop.c +3 -5
- data/skeletons/GPU-CUDA/common/timer_globals.c +26 -0
- data/skeletons/GPU-CUDA/kernel/2xN-N-chunk-1-N-to-D-element.kernel.cu +5 -7
- data/skeletons/GPU-CUDA/kernel/N-N-chunk-1-N-to-D-element.kernel.cu +4 -6
- data/skeletons/GPU-CUDA/kernel/default.host.c +1 -1
- data/skeletons/GPU-CUDA/kernel/default.kernel.cu +6 -8
- data/skeletons/GPU-CUDA/skeletons.txt +6 -5
- data/{examples/benchmarks/2mm.c → test/examples/benchmarks/PolyBench/2mm_species.c} +19 -15
- data/test/examples/benchmarks/PolyBench/3mm_species.c +82 -0
- data/test/examples/benchmarks/PolyBench/adi_species.c +89 -0
- data/test/examples/benchmarks/PolyBench/atax_species.c +69 -0
- data/test/examples/benchmarks/PolyBench/bicg_species.c +71 -0
- data/test/examples/benchmarks/PolyBench/cholesky_species.c +68 -0
- data/test/examples/benchmarks/PolyBench/correlation_species.c +97 -0
- data/test/examples/benchmarks/PolyBench/covariance_species.c +78 -0
- data/test/examples/benchmarks/PolyBench/doitgen_species.c +67 -0
- data/test/examples/benchmarks/PolyBench/durbin_species.c +80 -0
- data/test/examples/benchmarks/PolyBench/dynprog_species.c +71 -0
- data/test/examples/benchmarks/PolyBench/fdtd-2d-apml_species.c +112 -0
- data/test/examples/benchmarks/PolyBench/fdtd-2d_species.c +78 -0
- data/test/examples/benchmarks/PolyBench/floyd-warshall_species.c +54 -0
- data/test/examples/benchmarks/PolyBench/gemm_species.c +73 -0
- data/test/examples/benchmarks/PolyBench/gemver_species.c +93 -0
- data/test/examples/benchmarks/PolyBench/gesummv_species.c +68 -0
- data/test/examples/benchmarks/PolyBench/gramschmidt_species.c +78 -0
- data/test/examples/benchmarks/PolyBench/jacobi-1d-imper_species.c +59 -0
- data/test/examples/benchmarks/PolyBench/jacobi-2d-imper_species.c +65 -0
- data/test/examples/benchmarks/PolyBench/lu_species.c +57 -0
- data/test/examples/benchmarks/PolyBench/ludcmp_species.c +89 -0
- data/test/examples/benchmarks/PolyBench/mvt_species.c +69 -0
- data/test/examples/benchmarks/PolyBench/reg_detect_species.c +86 -0
- data/test/examples/benchmarks/PolyBench/seidel-2d_species.c +53 -0
- data/test/examples/benchmarks/PolyBench/symm_species.c +74 -0
- data/test/examples/benchmarks/PolyBench/syr2k_species.c +69 -0
- data/test/examples/benchmarks/PolyBench/syrk_species.c +66 -0
- data/test/examples/benchmarks/PolyBench/trisolv_species.c +61 -0
- data/test/examples/benchmarks/PolyBench/trmm_species.c +61 -0
- data/test/examples/chunk/example01_species.c +58 -0
- data/test/examples/chunk/example02_species.c +48 -0
- data/test/examples/chunk/example03_species.c +63 -0
- data/test/examples/chunk/example04_species.c +58 -0
- data/test/examples/chunk/example05_species.c +56 -0
- data/test/examples/chunk/example06_species.c +49 -0
- data/test/examples/chunk/example07_species.c +53 -0
- data/test/examples/dependences/example01_species.c +46 -0
- data/test/examples/dependences/example02_species.c +44 -0
- data/test/examples/dependences/example03_species.c +47 -0
- data/test/examples/dependences/example04_species.c +48 -0
- data/test/examples/dependences/example05_species.c +46 -0
- data/test/examples/element/example01_species.c +50 -0
- data/test/examples/element/example02_species.c +50 -0
- data/test/examples/element/example03_species.c +62 -0
- data/test/examples/element/example04_species.c +53 -0
- data/test/examples/element/example05_species.c +59 -0
- data/test/examples/element/example06_species.c +50 -0
- data/test/examples/element/example07_species.c +58 -0
- data/test/examples/element/example08_species.c +49 -0
- data/test/examples/element/example09_species.c +52 -0
- data/test/examples/element/example10_species.c +54 -0
- data/test/examples/element/example11_species.c +51 -0
- data/test/examples/element/example12_species.c +60 -0
- data/test/examples/element/example13_species.c +77 -0
- data/test/examples/neighbourhood/example01_species.c +57 -0
- data/test/examples/neighbourhood/example02_species.c +56 -0
- data/test/examples/neighbourhood/example03_species.c +83 -0
- data/test/examples/neighbourhood/example04_species.c +55 -0
- data/test/examples/neighbourhood/example05_species.c +48 -0
- data/test/examples/shared/example01_species.c +49 -0
- data/test/examples/shared/example02_species.c +55 -0
- data/test/examples/shared/example03_species.c +59 -0
- data/test/examples/shared/example04_species.c +56 -0
- data/test/examples/shared/example05_species.c +52 -0
- metadata +193 -73
- data/examples/benchmarks/overview.txt +0 -38
- 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, :
|
|
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 ==
|
|
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 ==
|
|
160
|
+
((dimensions == search.dimensions.map { |r| simplify(sum(r)) }.join(',')))
|
|
160
161
|
condition = condition && true
|
|
161
162
|
else
|
|
162
163
|
condition = false
|
data/lib/bones/structure.rb
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
require 'castaddon/
|
|
14
|
-
require 'castaddon/
|
|
15
|
-
|
|
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
|
+
|