Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100755 236 lines (177 sloc) 5.661 kb
69f7fbe3 » cantora
2012-09-03 initial commit
1 #!/usr/bin/env python
2
3 import argparse
4 import sys
5 import pyc_ast
3e42096c » cantora
2012-09-06 wip too tired
6 import pyc_asm_list
162ac106 » cantora
2012-09-21 pyc_var_analyzer: live_list computation
7 import pyc_var_analyzer
a6afd89c »
2012-09-25 added reg_allocator
8 import pyc_reg_allocator
6067c5c0 »
2012-09-27 fix allocator bug and add asm node debugging
9 import pyc_asm_nodes
c12f5c08 »
2012-10-05 fix for symphony bug
10 import compiler
da2d6469 » cantora
2012-09-06 logger
11 from pyc_log import *
822f3dfb » cantora
2012-09-06 makefile, run.sh plus pop bux fix
12 import os.path
fe468658 »
2012-09-28 timeout in allocator for programs w/ too many vars
13 import time
69f7fbe3 » cantora
2012-09-03 initial commit
14
c12f5c08 »
2012-10-05 fix for symphony bug
15 g_phases = ["ss-list", "asm-node-list"]
16
69f7fbe3 » cantora
2012-09-03 initial commit
17 def opt_parser():
c12f5c08 »
2012-10-05 fix for symphony bug
18 global g_phases
19
69f7fbe3 » cantora
2012-09-03 initial commit
20 parser = argparse.ArgumentParser(description='compile python to x86 assembly.')
da2d6469 » cantora
2012-09-06 logger
21 parser.add_argument('file', nargs='?', type=argparse.FileType('r'), help='file to compile')
69f7fbe3 » cantora
2012-09-03 initial commit
22 parser.add_argument('-c', '--code', help='code to compile')
23 parser.add_argument('-o', '--output', help='output file.')
da2d6469 » cantora
2012-09-06 logger
24 parser.add_argument('-v', '--verbose', action='store_true', help='print debug output.')
c12f5c08 »
2012-10-05 fix for symphony bug
25 parser.add_argument('-p', '--phase', help=('stop and print intermediate compiler result. phases: %s' % ", ".join(g_phases)) )
da2d6469 » cantora
2012-09-06 logger
26
69f7fbe3 » cantora
2012-09-03 initial commit
27 return parser
28
29
30 class MissingOption(Exception):
31 pass
32
33
34 def validate(options):
35 if options.file == None and options.code == None:
36 raise MissingOption('specify either file or code to compile')
37
38
39 def run(options):
c12f5c08 »
2012-10-05 fix for symphony bug
40 global g_phases
69f7fbe3 » cantora
2012-09-03 initial commit
41 #print options
da2d6469 » cantora
2012-09-06 logger
42 validate(options)
43
44 if options.verbose == True:
45 log_set_verbose()
46 else:
47 log_set_quiet()
48
822f3dfb » cantora
2012-09-06 makefile, run.sh plus pop bux fix
49 options.src_type = 'cmdline'
da2d6469 » cantora
2012-09-06 logger
50 options.src = options.code
51 if options.src == None:
52 options.src = options.file.read()
822f3dfb » cantora
2012-09-06 makefile, run.sh plus pop bux fix
53 options.src_type = 'file'
69f7fbe3 » cantora
2012-09-03 initial commit
54
da2d6469 » cantora
2012-09-06 logger
55 if isinstance(options.src, basestring) != True:
56 raise Exception('invalid src variable. type: %s' % (options.src.__class__.__name__) )
69f7fbe3 » cantora
2012-09-03 initial commit
57
c12f5c08 »
2012-10-05 fix for symphony bug
58 if (not options.phase is None) and options.phase not in g_phases:
59 raise Exception('invalid phase variable: %s' % options.phase)
60
da2d6469 » cantora
2012-09-06 logger
61 log(options)
af369874 » cantora
2012-09-13 misc
62 #import parser only now because we want to know if
200dc245 » cantora
2012-09-13 misc parser features
63 #we are verbose or not first.
af369874 » cantora
2012-09-13 misc
64 import pyc_parser
65
da2d6469 » cantora
2012-09-06 logger
66 as_tree = pyc_parser.parse(options.src)
2eb28c42 »
2012-09-25 reg allocator stuff
67 log( lambda : repr(as_tree))
68 log( lambda : pyc_ast.str(as_tree))
69f7fbe3 » cantora
2012-09-03 initial commit
69
fe468658 »
2012-09-28 timeout in allocator for programs w/ too many vars
70 t0 = time.time()
3e42096c » cantora
2012-09-06 wip too tired
71 ss_list = pyc_ast.to_ss_list(as_tree)
da2d6469 » cantora
2012-09-06 logger
72 log("se list: ")
c12f5c08 »
2012-10-05 fix for symphony bug
73 ss_list_str = lambda : "\n".join([repr(ss) for ss in ss_list])
74 if options.phase == 'ss-list':
75 print ss_list_str()
76 exit(0)
77
78 log(ss_list_str)
3e42096c » cantora
2012-09-06 wip too tired
79
080f3cf4 » cantora
2012-09-20 modified pyc_asm_list to use symbolic vars
80 asm_list = pyc_asm_list.from_ss_list(ss_list)
69f7fbe3 » cantora
2012-09-03 initial commit
81
23a8b4e6 »
2012-09-27 fixed empty program bug
82 asm_list = reduce(lambda a,b: a + b, asm_list, [])
c12f5c08 »
2012-10-05 fix for symphony bug
83 asm_list_str = lambda : "\n".join([repr(n) for n in asm_list])
84 if options.phase == 'asm-node-list':
85 print asm_list_str()
86 exit(0)
87
88 log(asm_list_str)
fe468658 »
2012-09-28 timeout in allocator for programs w/ too many vars
89 t_flatten = time.time()
90 #print "flatten time: %d" % (t_flatten - t0)
91
2eb28c42 »
2012-09-25 reg allocator stuff
92 more_alloc_needed = 1
91064f1d »
2012-09-27 big rewrite of allocator
93 adjusted_asm_list = asm_list
c12f5c08 »
2012-10-05 fix for symphony bug
94 allocator = pyc_reg_allocator.Allocator()
7e98aaa6 »
2012-09-28 changed alloc timeout to 20 secs
95 alloc_timeout = 20
2eb28c42 »
2012-09-25 reg allocator stuff
96
97 while more_alloc_needed:
98 log("analyze asm nodes and assign memory locations")
fe468658 »
2012-09-28 timeout in allocator for programs w/ too many vars
99 t0 = time.time()
91064f1d »
2012-09-27 big rewrite of allocator
100 live_list, graph = pyc_var_analyzer.interference_graph(adjusted_asm_list)
fe468658 »
2012-09-28 timeout in allocator for programs w/ too many vars
101 t_graph = time.time()
102 #print "graph time: %d" % (t_graph - t0)
103
104 t0 = time.time()
c12f5c08 »
2012-10-05 fix for symphony bug
105 allocator.allocate(graph, alloc_timeout)
fe468658 »
2012-09-28 timeout in allocator for programs w/ too many vars
106 t_alloc = time.time()
107 #print "alloc time: %d" % (t_alloc - t0)
108
109 #we only want to restrict the time of the first pass
110 #because the subsequent passes may have vars which need
111 #registers
112 alloc_timeout = 0
113
c12f5c08 »
2012-10-05 fix for symphony bug
114 log( lambda : "mem allocation offsets:\n\t%s" % str(allocator.symtbl) )
2eb28c42 »
2012-09-25 reg allocator stuff
115
c12f5c08 »
2012-10-05 fix for symphony bug
116 (more_alloc_needed, adjusted_asm_list) = pyc_reg_allocator.adjust(adjusted_asm_list, allocator.symtbl)
2eb28c42 »
2012-09-25 reg allocator stuff
117
91064f1d »
2012-09-27 big rewrite of allocator
118 log( lambda : "adjusted asm list (more_alloc? = %d):\n\t%s" % (more_alloc_needed, "\n\t".join([("%s" % repr(x) ) for x in adjusted_asm_list])) )
c12f5c08 »
2012-10-05 fix for symphony bug
119
30f0f9a5 » cantora
2012-09-06 convert instruction nodes to actual asm
120 insns = []
822f3dfb » cantora
2012-09-06 makefile, run.sh plus pop bux fix
121 insns.extend(asm_prefix())
122
c12f5c08 »
2012-10-05 fix for symphony bug
123 stacksize = allocator.symtbl.stack()
b8224246 »
2012-09-27 added stack alignment
124 align = 16
a62683ae »
2012-09-25 finished swapping code
125 if stacksize > 0:
b8224246 »
2012-09-27 added stack alignment
126 insns.append("subl\t$%s, %%esp" % (stacksize + (align - (stacksize % align))) )
32f2ffec » cantora
2012-09-11 started parser using PLY
127
c12f5c08 »
2012-10-05 fix for symphony bug
128 insns.extend(format_insn_nodes(adjusted_asm_list, ss_list, allocator.symtbl) )
822f3dfb » cantora
2012-09-06 makefile, run.sh plus pop bux fix
129 insns.extend(asm_suffix())
130
131 output(options, insns)
132
c12f5c08 »
2012-10-05 fix for symphony bug
133 def format_insn_nodes(ins_nodes, ss_list, symtbl):
134 result = []
135 previous = None
136 f = open("/tmp/asdf", "w")
137
138 #for ss in ss_list:
139 # if isinstance(ss, compiler.ast.Assign):
140 # exec(pyc_ast.assign_to_py(ss))
6067c5c0 »
2012-09-27 fix allocator bug and add asm node debugging
141
c12f5c08 »
2012-10-05 fix for symphony bug
142 for ins in ins_nodes:
143 if not isinstance(ins, pyc_asm_nodes.Inst):
144 raise Exception("expected instruction node")
6067c5c0 »
2012-09-27 fix allocator bug and add asm node debugging
145
c12f5c08 »
2012-10-05 fix for symphony bug
146 patched = pyc_reg_allocator.patch_insn(ins, symtbl)
147
148 if patched.is_noop():
149 continue
150
151 s = str(patched)
152 if previous is None or previous.origin != ins.origin:
153 val = ""
154 #if isinstance(ins.origin, compiler.ast.Assign):
155 # x = eval(ins.origin.nodes[0].name)
156 # val = "(%s = %s) " % (ins.origin.nodes[0].name, x)
157 # f.write("%s\n" % x)
158
159 s = "%-20s #%s%s" % (s, val, repr(ins.origin))
160 if False: #(not previous is None) and isinstance(previous.origin, compiler.ast.Assign):
161 result.extend([
162 "push %ecx",
163 "push %edx",
164 "push %eax",
165 "push %s" % pyc_reg_allocator.index_to_loc(symtbl[previous.origin.nodes[0].name]),
166 "call print_int_nl",
167 "pop %eax",
168 "pop %eax",
169 "pop %edx",
170 "pop %ecx"
171 ])
172
173
174
175 previous = ins
176 result.append(s)
6067c5c0 »
2012-09-27 fix allocator bug and add asm node debugging
177
c12f5c08 »
2012-10-05 fix for symphony bug
178 f.close()
179 return result
6067c5c0 »
2012-09-27 fix allocator bug and add asm node debugging
180
822f3dfb » cantora
2012-09-06 makefile, run.sh plus pop bux fix
181 def asm_headers():
182 return [
183 ".text",
184 ".globl main",
185 ".type main, @function",
186 "main:"
187 ]
188
189
190 def asm_prefix():
191 return [
192 "pushl %ebp",
738de725 » cantora
2012-09-07 bug fixes
193 "movl %esp, %ebp"
822f3dfb » cantora
2012-09-06 makefile, run.sh plus pop bux fix
194 ]
195
196 def asm_suffix():
197 return [
198 "movl $0, %eax",
199 "leave",
200 "ret"
201 ]
202
203
204 def output(options, insns):
738de725 » cantora
2012-09-07 bug fixes
205 if options.src_type == 'cmdline' or options.output == '-':
822f3dfb » cantora
2012-09-06 makefile, run.sh plus pop bux fix
206 for hdr in asm_headers():
207 print hdr
208 for ins in insns:
209 print "\t" + ins
210 else:
211
212 output_fname = "%s.s" % os.path.splitext(options.file.name)[0]
213 ofile = open(output_fname, 'w')
214
215 for hdr in asm_headers():
216 ofile.write(hdr + "\n")
217
218 for ins in insns:
219 ofile.write("\t" + ins + "\n")
220
221 ofile.close()
222
223
224
69f7fbe3 » cantora
2012-09-03 initial commit
225
226 if __name__ == "__main__":
227 opt_p = opt_parser()
da2d6469 » cantora
2012-09-06 logger
228 options = opt_p.parse_args()
69f7fbe3 » cantora
2012-09-03 initial commit
229
230 try:
da2d6469 » cantora
2012-09-06 logger
231 run(options)
69f7fbe3 » cantora
2012-09-03 initial commit
232 except MissingOption as e:
233 print e
234 print
235 opt_p.print_help()
236 exit(-1)
237
Something went wrong with that request. Please try again.