class GenLLVM(object): # see create_codewriter() below function_count = {} def __init__(self, translator, standalone): # reset counters Node.nodename_count = {} self.eci = ExternalCompilationInfo() self.standalone = standalone self.translator = translator self.config = translator.config def gen_source(self, func): self._checkpoint("before gen source") codewriter = self.setup(func) codewriter.header_comment("Extern code") codewriter.write_lines(self.llcode) codewriter.header_comment("Type declarations") for typ_decl in self.db.gettypedefnodes(): typ_decl.writetypedef(codewriter) codewriter.header_comment("Function prototypes") for node in self.db.getnodes(): if hasattr(node, 'writedecl'): node.writedecl(codewriter) codewriter.header_comment("Prebuilt constants") for node in self.db.getnodes(): # XXX tmp if hasattr(node, "writeglobalconstants"): node.writeglobalconstants(codewriter) self._checkpoint("before definitions") codewriter.header_comment('Suppport definitions') codewriter.write_lines(extfunctions, patch=True) codewriter.header_comment('Startup definition') self.write_startup_impl(codewriter) codewriter.header_comment("Function definitions") for node in self.db.getnodes(): if hasattr(node, 'writeimpl'): node.writeimpl(codewriter) self._debug(codewriter) codewriter.comment("End of file") codewriter.close() self._checkpoint('done') return self.filename def setup(self, func): """ setup all nodes create c file for externs create ll file for c file create codewriter """ if self.standalone: func = augment_entrypoint(self.translator, func) # XXX please dont ask! from pypy.translator.c.genc import CStandaloneBuilder cbuild = CStandaloneBuilder(self.translator, func, config=self.config) c_db = cbuild.generate_graphs_for_llinterp() self.db = Database(self, self.translator) self.db.gcpolicy = GcPolicy.new(self.db, self.config) self.db.gctransformer = c_db.gctransformer # get entry point entry_point = self.get_entry_point(func) self._checkpoint('get_entry_point') # set up all nodes self.db.setup_all() self.entrynode = self.db.set_entrynode(entry_point) self._checkpoint('setup_all all nodes') # set up externs nodes self.setup_externs(c_db, self.db) self.db.setup_all() self._checkpoint('setup_all externs') self._print_node_stats() # open file & create codewriter codewriter, self.filename = self.create_codewriter() self._checkpoint('open file and create codewriter') # create ll file from c code self.generate_ll_externs(codewriter) return codewriter def setup_externs(self, c_db, db): # XXX this should be done via augmenting entrypoint exctransformer = c_db.exctransformer for obj in [ exctransformer.rpyexc_occured_ptr.value, exctransformer.rpyexc_fetch_type_ptr.value, exctransformer.rpyexc_clear_ptr.value ]: db.prepare_constant(lltype.typeOf(obj), obj) def get_entry_point(self, func): assert func is not None self.entrypoint = func bk = self.translator.annotator.bookkeeper ptr = getfunctionptr(bk.getdesc(func).getuniquegraph()) c = inputconst(lltype.typeOf(ptr), ptr) self.db.prepare_arg(c) # ensure unqiue entry node name for testing entry_node = self.db.obj2node[c.value._obj] name = entry_node.name if name in self.function_count: self.function_count[name] += 1 Node.nodename_count[name] = self.function_count[name] + 1 name += '_%d' % self.function_count[name] entry_node.name = name else: self.function_count[name] = 1 self.entry_name = name[6:] return c.value._obj def generate_ll_externs(self, codewriter): all = [] for node in self.db.getnodes(): eci = getattr(node, 'compilation_info', None) if eci: all.append(eci) self.eci = self.eci.merge(*all) ccode = generate_c(self.db, self.entrynode, self.eci, self.standalone) self.llcode = generate_ll(ccode, self.eci) self.eci = self.eci.convert_sources_to_files(being_main=True) def create_codewriter(self): # prevent running the same function twice in a test filename = udir.join(self.entry_name).new(ext='.ll') f = open(str(filename), 'w') if self.standalone: return CodeWriter(f, self.db), filename else: return CodeWriter(f, self.db, linkage=''), filename def write_startup_impl(self, codewriter): open_decl = "i8* @LLVM_RPython_StartupCode()" codewriter.openfunc(open_decl) for node in self.db.getnodes(): node.writesetupcode(codewriter) codewriter.ret("i8*", "null") codewriter.closefunc() def compile_module(self): assert not self.standalone modname, dirpath = buildllvm.Builder(self).make_module() mod, wrap_fun = self.get_module(modname, dirpath) return mod, wrap_fun def get_module(self, modname, dirpath): if self.config.translation.llvm.isolate: mod = Isolate((dirpath, modname)) else: from pypy.translator.tool.cbuild import import_module_from_directory mod = import_module_from_directory(dirpath, modname) wrap_fun = getattr(mod, 'entrypoint') return mod, wrap_fun def compile_standalone(self, exe_name): assert self.standalone return buildllvm.Builder(self).make_standalone(exe_name) def _checkpoint(self, msg=None): if not self.config.translation.llvm.logging: return if msg: t = (time.time() - self.starttime) log('\t%s took %02dm%02ds' % (msg, t / 60, t % 60)) else: log('GenLLVM:') self.starttime = time.time() def _print_node_stats(self): # disable node stats output if not self.config.translation.llvm.logging: return nodecount = {} for node in self.db.getnodes(): typ = type(node) try: nodecount[typ] += 1 except: nodecount[typ] = 1 stats = [(count, str(typ)) for typ, count in nodecount.iteritems()] stats.sort() for s in stats: log('STATS %s' % str(s)) def _debug(self, codewriter): if self.config.translation.llvm.debug: if self.db.debugstringnodes: codewriter.header_comment("Debug string") for node in self.db.debugstringnodes: node.writeglobalconstants(codewriter) print "Start" print self.db.dump_pbcs() print "End"