-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathLQICM.py
executable file
·108 lines (89 loc) · 4.15 KB
/
LQICM.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
from __future__ import print_function
import sys
import os
from pycparser import parse_file, c_generator, c_ast
from peel import loop_peel
from dependency import compute_dependencies
sys.path.extend([".", ".."])
class Loop:
"""This class defines a Loop object """
def __init__(self, loop_node, parent, is_opt, inner_loops):
""" Initialize attributes for Loop """
self.loop_node = loop_node # the AST node of the loop being optimized
self.parent = parent # tuple(node of parent, index of the command)
self.is_opt = is_opt # whether loop is optimized or not
self.inner_loops = inner_loops # list of nested loops
class LoopVisitor:
"""This class is used for visiting c_ast nodes to find and store Loops"""
def __init__(self):
self.values = []
def visit(self, node, parent=None, i=-1):
if isinstance(node, (c_ast.DoWhile, c_ast.While, c_ast.For)):
self.loop(node, parent, i)
else:
for (j, (_, child)) in enumerate(node.children()):
self.visit(child, node, j)
def loop(self, node, parent, i):
loop_visit = LoopVisitor()
loop_visit.visit(node.stmt)
loop = Loop(node, (parent, i), False, loop_visit.values)
self.values.append(loop)
if isinstance(node, (c_ast.DoWhile, c_ast.For)):
convert(loop)
def convert(node):
loop_node = node.loop_node
parent_index = node.parent[1] # index in the AST of the original loop
node.parent[0].block_items.pop(parent_index) # remove the original loop from AST
body = [] # list of new AST nodes for each peel
original_body = []
if loop_node.stmt.block_items is not None:
original_body = loop_node.stmt.block_items
if isinstance(loop_node, c_ast.For):
if loop_node.init is not None:
body.append(loop_node.init.decls[0]) # add the initialization of the loop var before the loop
if loop_node.next is not None:
loop_node.stmt = c_ast.Compound(
original_body + [loop_node.next]) # add the inc/dec of the loop var at the end of the body
body.append(c_ast.While(loop_node.cond, loop_node.stmt))
if isinstance(loop_node,
c_ast.DoWhile): # if loop is a DoWhile, add the commands of the first peel outside of the loop
for i in original_body: # add each command to the modified AST
body.append(i)
body.append(c_ast.While(loop_node.cond, c_ast.Compound(original_body)))
for i in body: # add new nodes to the modified AST
node.parent[0].block_items.insert(parent_index, i)
parent_index = parent_index + 1
node.parent = (node.parent[0], parent_index - 1) # update the parent
def opt(loop):
"""Finds the inner-most loop that can be optimized and peels it """
for inner_loop in loop.inner_loops:
if not inner_loop.is_opt:
opt(inner_loop) # optimize the inner loop if it has not been opimized yet
(graph, list_deg) = compute_dependencies(loop.loop_node.stmt.block_items) # compute the dependencies of the loop
loop_peel(graph, list_deg, loop) # peel the loop based on its dependencies
return graph, list_deg
def visit_ast(ast):
"""Creates a LoopVisitor object to find the loops in a program """
loop_visit = LoopVisitor()
loop_visit.visit(ast)
return loop_visit.values # list of all the outer-most loops in a program
def optimize(filename):
""" Parses the file and modifies the AST"""
ast = parse_file(filename, use_cpp=True, cpp_path="gcc", cpp_args=['-E']) # replace cpp with gcc to remove comments
loops = visit_ast(ast)
loop_count = len(loops)
deps = []
for i in range(loop_count):
deps.append(opt(loops[i]))
loops = visit_ast(ast)
generator = c_generator.CGenerator()
newast = generator.visit(ast)
with open(os.path.join('./output/', "opt_" + os.path.basename(filename)), "w") as text_file:
print(format(newast), file=text_file)
return deps
if __name__ == "__main__":
if len(sys.argv) > 1:
optimize(sys.argv[1])
else:
import doctest
doctest.testfile("test_examples.txt", raise_on_error=True)