diff --git a/pythran/analyses/__init__.py b/pythran/analyses/__init__.py index 8560129b0..3c149f9b0 100644 --- a/pythran/analyses/__init__.py +++ b/pythran/analyses/__init__.py @@ -9,7 +9,7 @@ import analyses.Foo """ -from .aliases import Aliases, StrictAliases +from .aliases import Aliases, StrictAliases, InterproceduralAliases from .ancestors import Ancestors, AncestorsWithBody from .argument_effects import ArgumentEffects from .argument_read_once import ArgumentReadOnce diff --git a/pythran/analyses/aliases.py b/pythran/analyses/aliases.py index 1266b7cfd..523e7fa98 100644 --- a/pythran/analyses/aliases.py +++ b/pythran/analyses/aliases.py @@ -544,6 +544,11 @@ def visit_DictComp(self, node): # aliasing created by statements + def init_function_alias(self, node): + "each argument is bound to a different identifier" + self.aliases.update((arg.id, {arg}) + for arg in node.args.args) + def visit_FunctionDef(self, node): ''' Initialise aliasing default value before visiting. @@ -558,8 +563,7 @@ def visit_FunctionDef(self, node): self.aliases.update((k, {v}) for k, v in self.global_declarations.items()) - self.aliases.update((arg.id, {arg}) - for arg in node.args.args) + self.init_function_alias(node) self.generic_visit(node) if Aliases.RetId in self.aliases: @@ -612,6 +616,27 @@ def merge_return_aliases(args): node.return_alias = merge_return_aliases + def visit_Assert(self, node): + self.generic_visit(node) + + if not isinstance(node.test, ast.Compare): + return + if len(node.test.ops) != 1: + return + op = node.test.ops[0] + comparator = node.test.comparators[0] + + if not isinstance(node.test.left, ast.Name): + return + if not isinstance(comparator, ast.Name): + return + + if isinstance(op, ast.IsNot): + left_aliases = self.aliases[node.test.left.id] + right_aliases = self.aliases[comparator.id] + self.aliases[node.test.left.id] = self.aliases[node.test.left.id].difference(right_aliases) + right_aliases.difference_update(left_aliases) + def visit_Assign(self, node): r''' Assignment creates aliasing between lhs and rhs @@ -786,3 +811,14 @@ class StrictAliases(Aliases): def get_unbound_value_set(self): return set() + + +class InterproceduralAliases(Aliases): + """ + Gather aliases while assuming two different parameters can point to the same + value + """ + + def init_function_alias(self, node): + self.aliases.update((arg.id, set(node.args.args)) + for arg in node.args.args) diff --git a/pythran/optimizations/fast_gexpr.py b/pythran/optimizations/fast_gexpr.py index c52814f80..9c4d391b5 100644 --- a/pythran/optimizations/fast_gexpr.py +++ b/pythran/optimizations/fast_gexpr.py @@ -1,6 +1,6 @@ """ Optimize a[...] = b[...] + c when we have no conflicting aliasing """ -from pythran.analyses import Aliases +from pythran.analyses import InterproceduralAliases from pythran.passmanager import Transformation import gast as ast @@ -10,7 +10,7 @@ class FastGExpr(Transformation): def __init__(self): self.update = False - super(FastGExpr, self).__init__(Aliases) + super(FastGExpr, self).__init__(InterproceduralAliases) def as_gexpr(self, node): if not isinstance(node, ast.Subscript): @@ -39,7 +39,7 @@ def may_alias(self, gexpr, value): if isinstance(value, ast.Subscript): if not isinstance(value.value, ast.Name): return True - return gexpr[0] in self.aliases[value.value] + return not self.interprocedural_aliases[gexpr[0]].isdisjoint(self.interprocedural_aliases[value.value]) return True