def visit_AnyComp(self, node, comp_type, *path): node.elt = self.visit(node.elt) name = "{0}_comprehension{1}".format(comp_type, self.count) self.count += 1 args = self.passmanager.gather(ImportedIds, node, self.ctx) self.count_iter = 0 starget = "__target" body = reduce( self.nest_reducer, reversed(node.generators), ast.Expr( ast.Call( reduce(lambda x, y: ast.Attribute(x, y, ast.Load()), path[1:], ast.Name(path[0], ast.Load())), [ast.Name(starget, ast.Load()), node.elt], [], None, None))) # add extra metadata to this node metadata.add(body, metadata.Comprehension(starget)) init = ast.Assign([ast.Name(starget, ast.Store())], ast.Call( ast.Attribute( ast.Name('__builtin__', ast.Load()), comp_type, ast.Load()), [], [], None, None)) result = ast.Return(ast.Name(starget, ast.Load())) sargs = sorted(ast.Name(arg, ast.Param()) for arg in args) fd = ast.FunctionDef(name, ast.arguments(sargs, None, None, []), [init, body, result], []) self.ctx.module.body.append(fd) return ast.Call(ast.Name(name, ast.Load()), [ast.Name(arg.id, ast.Load()) for arg in sargs], [], None, None) # no sharing !
def attach_data(self, node): '''Generic method called for visit_XXXX() with XXXX in GatherOMPData.statements list ''' if self.current: for curr in self.current: md = OMPDirective(curr) metadata.add(node, md) self.current = list() # add a Pass to hold some directives for field_name, field in ast.iter_fields(node): if field_name in GatherOMPData.statement_lists: if(field and isinstance(field[-1], ast.Expr) and self.isompdirective(field[-1].value)): field.append(ast.Pass()) self.generic_visit(node) # add an If to hold scoping OpenMP directives directives = metadata.get(node, OMPDirective) field_names = {n for n, _ in ast.iter_fields(node)} has_no_scope = field_names.isdisjoint(GatherOMPData.statement_lists) if directives and has_no_scope: # some directives create a scope, but the holding stmt may not # artificially create one here if needed sdirective = ''.join(d.s for d in directives) scoping = ('parallel', 'task', 'section') if any(s in sdirective for s in scoping): node = ast.If(ast.Num(1), [node], []) return node
def visit_Module(self, node): """Turn globals assignement to functionDef and visit function defs. """ module_body = list() # Gather top level assigned variables. for stmt in node.body: if not isinstance(stmt, ast.Assign): continue for target in stmt.targets: assert isinstance(target, ast.Name) if target.id in self.to_expand: raise PythranSyntaxError( "Multiple top-level definition of %s." % target.id, target) self.to_expand.add(target.id) for stmt in node.body: if isinstance(stmt, ast.Assign): self.local_decl = set() cst_value = self.visit(stmt.value) for target in stmt.targets: assert isinstance(target, ast.Name) module_body.append( ast.FunctionDef(target.id, ast.arguments([], None, None, []), [ast.Return(value=cst_value)], [])) metadata.add(module_body[-1].body[0], metadata.StaticReturn()) else: self.local_decl = self.passmanager.gather( LocalNameDeclarations, stmt, self.ctx) module_body.append(self.visit(stmt)) node.body = module_body return node
def attach_data(self, node): '''Generic method called for visit_XXXX() with XXXX in GatherOMPData.statements list ''' if self.current: for curr in self.current: md = OMPDirective(curr) metadata.add(node, md) self.current = list() # add a Pass to hold some directives for field_name, field in ast.iter_fields(node): if field_name in GatherOMPData.statement_lists: if(field and isinstance(field[-1], ast.Expr) and self.isompdirective(field[-1].value)): field.append(ast.Pass()) self.generic_visit(node) # add an If to hold scoping OpenMP directives directives = metadata.get(node, OMPDirective) field_names = {n for n, _ in ast.iter_fields(node)} has_no_scope = field_names.isdisjoint(GatherOMPData.statement_lists) if directives and has_no_scope: # some directives create a scope, but the holding stmt may not # artificially create one here if needed sdirective = ''.join(d.s for d in directives) scoping = ('parallel', 'task', 'section') if any(s in sdirective for s in scoping): metadata.clear(node, OMPDirective) node = ast.If(ast.Num(1), [node], []) for directive in directives: metadata.add(node, directive) return node
def visit_FunctionDef(self, node): self.update = True if MODULES['functools'] not in self.global_declarations.values(): import_ = ast.Import([ast.alias('functools', mangle('functools'))]) self.ctx.module.body.insert(0, import_) functools_module = MODULES['functools'] self.global_declarations[mangle('functools')] = functools_module self.ctx.module.body.append(node) former_name = node.name seed = 0 new_name = "pythran_{}{}" while new_name.format(former_name, seed) in self.identifiers: seed += 1 new_name = new_name.format(former_name, seed) self.identifiers.add(new_name) ii = self.gather(ImportedIds, node) binded_args = [ ast.Name(iin, ast.Load(), None, None) for iin in sorted(ii) ] node.args.args = ( [ast.Name(iin, ast.Param(), None, None) for iin in sorted(ii)] + node.args.args) metadata.add(node, metadata.Local()) class Renamer(ast.NodeTransformer): def visit_Call(self, node): self.generic_visit(node) if (isinstance(node.func, ast.Name) and node.func.id == former_name): node.func.id = new_name node.args = ([ ast.Name(iin, ast.Load(), None, None) for iin in sorted(ii) ] + node.args) return node Renamer().visit(node) node.name = new_name self.global_declarations[node.name] = node proxy_call = ast.Name(new_name, ast.Load(), None, None) new_node = ast.Assign([ast.Name(former_name, ast.Store(), None, None)], ast.Call( ast.Attribute( ast.Name(mangle('functools'), ast.Load(), None, None), "partial", ast.Load()), [proxy_call] + binded_args, [], )) self.generic_visit(node) return new_node
def visit_Lambda(self, node): if MODULES['functools'] not in self.global_declarations.values(): import_ = ast.Import([ast.alias('functools', mangle('functools'))]) self.imports.append(import_) functools_module = MODULES['functools'] self.global_declarations[mangle('functools')] = functools_module self.generic_visit(node) forged_name = "{0}_lambda{1}".format(self.prefix, len(self.lambda_functions)) ii = self.gather(ImportedIds, node) ii.difference_update(self.lambda_functions) # remove current lambdas binded_args = [ ast.Name(iin, ast.Load(), None, None) for iin in sorted(ii) ] node.args.args = ( [ast.Name(iin, ast.Param(), None, None) for iin in sorted(ii)] + node.args.args) forged_fdef = ast.FunctionDef(forged_name, copy(node.args), [ast.Return(node.body)], [], None, None) metadata.add(forged_fdef, metadata.Local()) self.lambda_functions.append(forged_fdef) self.global_declarations[forged_name] = forged_fdef proxy_call = ast.Name(forged_name, ast.Load(), None, None) if binded_args: return ast.Call( ast.Attribute( ast.Name(mangle('functools'), ast.Load(), None, None), "partial", ast.Load()), [proxy_call] + binded_args, []) else: return proxy_call
def visit_Lambda(self, node): op = issimpleoperator(node) if op is not None: if mangle('operator') not in self.global_declarations: import_ = ast.Import( [ast.alias('operator', mangle('operator'))]) self.imports.append(import_) operator_module = MODULES['operator'] self.global_declarations[mangle('operator')] = operator_module return ast.Attribute( ast.Name(mangle('operator'), ast.Load(), None, None), op, ast.Load()) self.generic_visit(node) forged_name = "{0}_lambda{1}".format(self.prefix, len(self.lambda_functions)) ii = self.gather(ImportedIds, node) ii.difference_update(self.lambda_functions) # remove current lambdas binded_args = [ ast.Name(iin, ast.Load(), None, None) for iin in sorted(ii) ] node.args.args = ( [ast.Name(iin, ast.Param(), None, None) for iin in sorted(ii)] + node.args.args) for patternname, pattern in self.patterns.items(): if issamelambda(pattern, node): proxy_call = ast.Name(patternname, ast.Load(), None, None) break else: duc = ExtendedDefUseChains() nodepattern = deepcopy(node) duc.visit(ast.Module([ast.Expr(nodepattern)], [])) self.patterns[forged_name] = nodepattern, duc forged_fdef = ast.FunctionDef(forged_name, copy(node.args), [ast.Return(node.body)], [], None, None) metadata.add(forged_fdef, metadata.Local()) self.lambda_functions.append(forged_fdef) self.global_declarations[forged_name] = forged_fdef proxy_call = ast.Name(forged_name, ast.Load(), None, None) if binded_args: if MODULES['functools'] not in self.global_declarations.values(): import_ = ast.Import( [ast.alias('functools', mangle('functools'))]) self.imports.append(import_) functools_module = MODULES['functools'] self.global_declarations[mangle( 'functools')] = functools_module return ast.Call( ast.Attribute( ast.Name(mangle('functools'), ast.Load(), None, None), "partial", ast.Load()), [proxy_call] + binded_args, []) else: return proxy_call
def visit(self, node): """ Add OMPDirective from the old node to the new one. """ old_omp = metadata.get(node, OMPDirective) node = super(DeadCodeElimination, self).visit(node) if not metadata.get(node, OMPDirective): for omp_directive in old_omp: metadata.add(node, omp_directive) return node
def visit_AnyComp(self, node, comp_type, *path): self.update = True node.elt = self.visit(node.elt) name = "{0}_comprehension{1}".format(comp_type, self.count) self.count += 1 args = self.passmanager.gather(ImportedIds, node, self.ctx) self.count_iter = 0 starget = "__target" body = reduce(self.nest_reducer, reversed(node.generators), ast.Expr( ast.Call( reduce(lambda x, y: ast.Attribute(x, y, ast.Load()), path[1:], ast.Name(path[0], ast.Load())), [ast.Name(starget, ast.Load()), node.elt], [], None, None ) ) ) # add extra metadata to this node metadata.add(body, metadata.Comprehension(starget)) init = ast.Assign( [ast.Name(starget, ast.Store())], ast.Call( ast.Attribute( ast.Name('__builtin__', ast.Load()), comp_type, ast.Load() ), [], [], None, None) ) result = ast.Return(ast.Name(starget, ast.Load())) sargs = sorted(ast.Name(arg, ast.Param()) for arg in args) fd = ast.FunctionDef(name, ast.arguments(sargs, None, None, []), [init, body, result], []) self.ctx.module.body.append(fd) return ast.Call( ast.Name(name, ast.Load()), [ast.Name(arg.id, ast.Load()) for arg in sargs], [], None, None ) # no sharing !
def visit_GeneratorExp(self, node): self.update = True node.elt = self.visit(node.elt) name = "generator_expression{0}".format(self.count) self.count += 1 args = self.gather(ImportedIds, node) self.count_iter = 0 body = reduce(self.nest_reducer, reversed(node.generators), ast.Expr(ast.Yield(node.elt))) sargs = [ast.Name(arg, ast.Param(), None, None) for arg in args] fd = ast.FunctionDef(name, ast.arguments(sargs, [], None, [], [], None, []), [body], [], None, None) metadata.add(fd, metadata.Local()) self.ctx.module.body.append(fd) return ast.Call( ast.Name(name, ast.Load(), None, None), [ast.Name(arg.id, ast.Load(), None, None) for arg in sargs], [], ) # no sharing !
def visit_Module(self, node): """Turn globals assignment to functionDef and visit function defs. """ module_body = list() symbols = set() # Gather top level assigned variables. for stmt in node.body: if isinstance(stmt, (ast.Import, ast.ImportFrom)): for alias in stmt.names: name = alias.asname or alias.name symbols.add(name) # no warning here elif isinstance(stmt, ast.FunctionDef): if stmt.name in symbols: raise PythranSyntaxError( "Multiple top-level definition of %s." % stmt.name, stmt) else: symbols.add(stmt.name) if not isinstance(stmt, ast.Assign): continue for target in stmt.targets: if not isinstance(target, ast.Name): raise PythranSyntaxError( "Top-level assignment to an expression.", target) if target.id in self.to_expand: raise PythranSyntaxError( "Multiple top-level definition of %s." % target.id, target) if isinstance(stmt.value, ast.Name): if stmt.value.id in symbols: continue # create aliasing between top level symbols self.to_expand.add(target.id) for stmt in node.body: if isinstance(stmt, ast.Assign): # that's not a global var, but a module/function aliasing if all(isinstance(t, ast.Name) and t.id not in self.to_expand for t in stmt.targets): module_body.append(stmt) continue self.local_decl = set() cst_value = self.visit(stmt.value) for target in stmt.targets: assert isinstance(target, ast.Name) module_body.append( ast.FunctionDef(target.id, ast.arguments([], None, [], [], None, []), [ast.Return(value=cst_value)], [], None)) metadata.add(module_body[-1].body[0], metadata.StaticReturn()) else: self.local_decl = self.passmanager.gather( LocalNameDeclarations, stmt, self.ctx) module_body.append(self.visit(stmt)) node.body = module_body return node
def visit_Compare(self, node): node = self.generic_visit(node) if len(node.ops) > 1: # in case we have more than one compare operator # we generate an auxiliary function # that lazily evaluates the needed parameters imported_ids = self.gather(ImportedIds, node) imported_ids = sorted(imported_ids) binded_args = [ast.Name(i, ast.Load(), None, None) for i in imported_ids] # name of the new function forged_name = "{0}_compare{1}".format(self.prefix, len(self.compare_functions)) # call site call = ast.Call( ast.Name(forged_name, ast.Load(), None, None), binded_args, []) # new function arg_names = [ast.Name(i, ast.Param(), None, None) for i in imported_ids] args = ast.arguments(arg_names, [], None, [], [], None, []) body = [] # iteratively fill the body (yeah, feel your body!) if is_trivially_copied(node.left): prev_holder = node.left else: body.append( ast.Assign( [ast.Name('$0', ast.Store(), None, None)], node.left, None)) prev_holder = ast.Name('$0', ast.Load(), None, None) for i, exp in enumerate(node.comparators): if is_trivially_copied(exp): holder = exp else: body.append(ast.Assign([ast.Name('${}'.format(i+1), ast.Store(), None, None)], exp, None)) holder = ast.Name('${}'.format(i+1), ast.Load(), None, None) cond = ast.Compare(prev_holder, [node.ops[i]], [holder]) body.append( ast.If(cond, [ast.Pass()], [ast.Return(path_to_attr(('builtins', 'False')))])) prev_holder = holder body.append(ast.Return(path_to_attr(('builtins', 'True')))) forged_fdef = ast.FunctionDef(forged_name, args, body, [], None, None) metadata.add(forged_fdef, metadata.Local()) self.compare_functions.append(forged_fdef) return call else: return node
def visit_Module(self, node): """Turn globals assignment to functionDef and visit function defs. """ module_body = list() symbols = set() # Gather top level assigned variables. for stmt in node.body: if isinstance(stmt, (ast.Import, ast.ImportFrom)): for alias in stmt.names: name = alias.asname or alias.name symbols.add(name) # no warning here elif isinstance(stmt, ast.FunctionDef): if stmt.name in symbols: raise PythranSyntaxError( "Multiple top-level definition of %s." % stmt.name, stmt) else: symbols.add(stmt.name) if not isinstance(stmt, ast.Assign): continue for target in stmt.targets: if not isinstance(target, ast.Name): raise PythranSyntaxError( "Top-level assignment to an expression.", target) if target.id in self.to_expand: raise PythranSyntaxError( "Multiple top-level definition of %s." % target.id, target) if isinstance(stmt.value, ast.Name): if stmt.value.id in symbols: continue # create aliasing between top level symbols self.to_expand.add(target.id) for stmt in node.body: if isinstance(stmt, ast.Assign): # that's not a global var, but a module/function aliasing if all( isinstance(t, ast.Name) and t.id not in self.to_expand for t in stmt.targets): module_body.append(stmt) continue self.local_decl = set() cst_value = GlobalTransformer().visit(self.visit(stmt.value)) for target in stmt.targets: assert isinstance(target, ast.Name) module_body.append( ast.FunctionDef( target.id, ast.arguments([], [], None, [], [], None, []), [ast.Return(value=cst_value)], [], None, None)) metadata.add(module_body[-1].body[0], metadata.StaticReturn()) else: self.local_decl = self.gather(LocalNameDeclarations, stmt) module_body.append(self.visit(stmt)) self.update |= bool(self.to_expand) node.body = module_body return node
def nest_reducer(self, x, g): def wrap_in_ifs(node, ifs): return reduce(lambda n, if_: ast.If(if_, [n], []), ifs, node) metadata.add(g.target, metadata.LocalVariable()) return ast.For(g.target, g.iter, [wrap_in_ifs(x, g.ifs)], [])