Esempio n. 1
0
    def visit_AugAssign(self, node):

        # Aug assign to a name
        if isinstance(node.target, ast.Name):
            target = Var(node.target.id)
            self.addtype(node.target.id, '*')
            value = self.visit_expr(node.value)
            rhs = Op(node.op.__class__.__name__,
                     target,
                     value,
                     line=node.lineno)
            self.addexpr(target.name, rhs)

        # Aug assign to a index
        elif isinstance(node.target, ast.Subscript):
            if isinstance(node.target.slice, ast.Index):
                var = Var(node.target.value.id)
                right = self.visit_expr(node.value)
                index = self.visit_expr(node.target.slice.value)
                rhs = Op(node.op.__class__.__name__,
                         self.visit(node.target),
                         right,
                         line=node.lineno)
                self.addexpr(
                    var.name,
                    Op('AssignElement', var, index, rhs, line=node.lineno))

            else:
                raise NotSupported(
                    'Subscript assignments only allowed to Indices',
                    line=node.lineno)
        else:
            raise NotSupported('Assignments to {} not supported'.format(
                node.target.__class__.__name__),
                               line=node.lineno)
Esempio n. 2
0
 def visit_Print(self, node):
     '''
     Only used in Python 2.x, ignores destination and newline
     '''
     values_model = map(self.visit_expr, node.values)
     expr = Op('StrAppend', Var(VAR_OUT), *values_model, line=node.lineno)
     self.addexpr(VAR_OUT, expr)
Esempio n. 3
0
    def visit_printf(self, node, args):
        '''
        printf function call
        '''

        # Extract format and args
        if len(args) == 0:
            self.addwarn("'printf' with zero args at line %s" % (
                node.coord.line,))
            fmt = Const('?', line=node.coord.line)
        else:
            if isinstance(args[0], Const):
                fmt = args[0]
                args = args[1:]
            else:
                self.addwarn("First argument of 'printf' at lines %s should \
be a format" % (node.coord.line,))
                fmt = Const('?', line=node.coord.line)

        fmt.value = fmt.value.replace('%lf', '%f')
        fmt.value = fmt.value.replace('%ld', '%d')
        fmt.value = fmt.value.replace('%lld', '%d')

        expr = Op('StrAppend', Var(VAR_OUT),
                  Op('StrFormat', fmt, *args, line=node.coord.line),
                  line=node.coord.line)
        self.addexpr(VAR_OUT, expr)
Esempio n. 4
0
    def ssa(self, fnc):
        '''
        Converts exprs of each loc to SSA form
        '''

        for loc in fnc.locs():

            # Find last appearance of each var
            last = {}
            for i, (var, _) in enumerate(fnc.exprs(loc)):
                last[var] = i

            # Replace non-last appearance by a fresh var
            m = {}
            exprs = []
            for i, (var, expr) in enumerate(fnc.exprs(loc)):

                for v1, v2 in m.items():
                    expr = expr.replace(v1, Var(v2))

                if var == VAR_RET:
                    newvar = var
                else:
                    if last[var] > i:
                        newvar = m[var] = self.ssavar(var)
                    else:
                        m.pop(var, None)
                        newvar = var

                exprs.append((newvar, expr))

            fnc.replaceexprs(loc, exprs)
Esempio n. 5
0
    def optimizeif(self, preloc, condexpr, trueloc, falseloc):
        '''
        Optimized "simple" or "loop-less" if statement
        '''

        # Remove unneded part of the graph
        self.fnc.rmtrans(preloc, True)
        self.loc = preloc

        # Keep track of assigned vars
        varss = set()
        varsl = []
        mt = {}
        mf = {}

        # Add exprs from branches
        def addvars(loc, m):
            for (var, expr) in self.fnc.exprs(loc):
                newvar = self.ssavar(var)

                if var not in varss:
                    varss.add(var)
                    varsl.append(var)

                # Replace vars mapped so far
                for (v1, v2) in m.items():
                    expr = expr.replace(v1, Var(v2))
                expr.original = (var, self.cnt)
                self.addexpr(newvar, expr)

                # Remember replacement
                m[var] = newvar

        addvars(trueloc, mt)
        if falseloc is not None:
            addvars(falseloc, mf)

        # Add condition
        condvar = self.ssavar('$cond')
        self.addexpr(condvar, condexpr.copy())

        # Merge branches
        for var in varsl:
            self.addexpr(
                var,
                Op('ite', Var(condvar), Var(mt.get(var, var)),
                   Var(mf.get(var, var))))
Esempio n. 6
0
    def rmtmp(self, fnc):
        '''
        Removes (merges) "tmp" or SSA-generated assignments
        '''

        for loc in fnc.locs():

            m = {}
            exprs = []
            primed = set([])
            lastret = None

            # Remember "real" vars and replace temps
            for var, expr in fnc.exprs(loc):

                expr.prime(primed)

                for v, e in m.items():
                    expr = expr.replace(v, e)

                if var.endswith('&'):
                    m[var] = expr

                else:
                    if var == VAR_RET:
                        lastret = len(exprs)

                    exprs.append((var, expr))
                    primed.add(var)

            # "Merge" return stmts
            nexprs = []
            retexpr = None
            retcond = None
            for i, (var, expr) in enumerate(exprs):
                if var == VAR_RET:
                    tmpretcond = self.getretcond(expr)
                    if tmpretcond is True or retcond is None:
                        retcond = tmpretcond
                    elif tmpretcond is not None and retcond is not True:
                        retcond = Op(self.OROP, retcond, tmpretcond)
                    if retexpr:
                        retexpr = retexpr.replace(VAR_RET, expr)
                    else:
                        retexpr = expr

                    if i == lastret:
                        nexprs.append((var, retexpr))

                else:
                    if retcond is True:
                        continue
                    elif retcond:
                        expr = Op('ite', Op(self.NOTOP, retcond), expr,
                                  Var(var))
                    nexprs.append((var, expr))

            fnc.replaceexprs(loc, nexprs)
Esempio n. 7
0
    def visit_Call(self, node):
        if len(node.keywords) > 0 or node.starargs or node.kwargs:
            raise NotSupported(
                'starargs, kwargs and keyword arguments not supported',
                line=node.lineno)

        if isinstance(node.func, ast.Name):
            if node.func.id in self.BUILTIN_FNCS:
                fncname = node.func.id
                args = list(map(self.visit_expr, node.args))
                return Op(fncname, *args, line=node.lineno)
            else:
                fnc = Var(node.func.id)
                args = list(map(self.visit_expr, node.args))
                return Op('FuncCall', fnc, *args, line=node.lineno)

        elif isinstance(node.func, ast.Num):
            num = self.visit_expr(node.func)
            self.addwarn("Call to a number '%s' on line %s ignored", num,
                         num.line)
            return Const('?')

        elif isinstance(node.func, ast.Attribute):
            attr = node.func.attr
            val = self.visit_expr(node.func.value)
            args = list(map(self.visit_expr, node.args))
            if isinstance(val, Var) and val.name in self.MODULE_NAMES:
                return Op('%s_%s' % (val, attr), *args, line=node.lineno)
            if attr == 'pop':
                if isinstance(val, Var):
                    popvar = self.ssavar('pop#')
                    self.addexpr(popvar, Op(attr, val, *args,
                                            line=node.lineno))
                    self.addexpr(val.name,
                                 Op('GetElement', Var(popvar), Const('0')))
                    return Op('GetElement', Var(popvar), Const('1'))
                else:
                    raise NotSupported('Pop to a non-name list')
            return Op(attr, val, *args, line=node.lineno)

        else:
            raise NotSupported('Call of {} not supported'.format(
                node.func.__class__.__name__),
                               line=node.lineno)
Esempio n. 8
0
    def visit_ID(self, node):
        '''
        ID
        Attrs: name
        '''

        if node.name in self.CONSTS:
            return Const(node.name, line=node.coord.line)

        return Var(node.name, line=node.coord.line)
Esempio n. 9
0
        def addvars(loc, m):
            for (var, expr) in self.fnc.exprs(loc):
                newvar = self.ssavar(var)

                if var not in varss:
                    varss.add(var)
                    varsl.append(var)

                # Replace vars mapped so far
                for (v1, v2) in m.items():
                    expr = expr.replace(v1, Var(v2))
                self.addexpr(newvar, expr)

                # Remember replacement
                m[var] = newvar
Esempio n. 10
0
    def visit_Assign(self, node):
        if len(node.targets) != 1:
            raise NotSupported('Only single assignments allowed')

        target = node.targets[0]

        # Assignment to a variable
        if isinstance(target, ast.Name):
            right = self.visit_expr(node.value)
            self.addtype(target.id, '*')
            self.addexpr(target.id, right)

        # Assignment to indexed element
        elif isinstance(target, ast.Subscript):
            if isinstance(target.slice, ast.Index):
                var = Var(target.value.id)
                self.addtype(target.value.id, '*')
                right = self.visit_expr(node.value)
                index = self.visit_expr(target.slice.value)

                self.addexpr(
                    target.value.id,
                    Op('AssignElement', var, index, right, line=right.line))

            else:
                raise NotSupported(
                    'Subscript assignments only allowed to Indices',
                    line=node.lineno)

        # Assignment to a tuple
        elif isinstance(target, ast.Tuple):
            targets = map(self.visit_expr, target.elts)
            right = self.visit_expr(node.value)
            for i, target in enumerate(targets):
                expr = Op('GetElement',
                          right.copy(),
                          Const(str(i)),
                          line=right.line)
                if isinstance(target, Var):
                    self.addexpr(target.name, expr)
                else:
                    raise NotSupported("Tuple non-var assignment",
                                       line=target.line)

        else:
            raise NotSupported('Assignments to {} not supported'.format(
                target.__class__.__name__),
                               line=node.lineno)
Esempio n. 11
0
 def visit_Name(self, node):
     if node.id in self.CONSTS:
         return Const(node.id)
     self.addtype(node.id, '*')
     return Var(node.id)
Esempio n. 12
0
    def visit_For(self, node):
        
        if node.orelse:
            raise NotSupported("For-Else not supported",
                               line=self.getline(node.orelse))
        
        # Iterated expression
        it = self.visit_expr(node.iter)

        # Targets of iteration
        if isinstance(node.target, ast.Name):
            self.addtype(node.target.id, '*')
            targets = [self.visit_expr(node.target)]
        elif isinstance(node.target, ast.Tuple):
            for el in node.target.elts:
                if isinstance(el, ast.Name):
                    self.addtype(el.id, '*')
            targets = map(self.visit_expr, node.target.elts)
        else:
            raise NotSupported(
                'For loop with {} as target'.format(
                    node.target.__class__.__name__),
                line=node.lineno)

        hiddenvar = self.hiddenvarcnt
        self.hiddenvarcnt += 1

        # Set up the iterated variable
        iter_name = 'iter#{}'.format(hiddenvar)
        it_var = Var(iter_name)
        self.addtype(iter_name, '*')

        # Set up the iteration index
        ind_name = 'ind#{}'.format(hiddenvar)
        ind_var = Var(ind_name)
        self.addtype(ind_name, 'int')

        # Add assignments to iterators
        self.addexpr(it_var.name, it)
        self.addexpr(ind_var.name, Const(str(0), line=node.lineno))

        # Condition is ind_var < len(iter_var)
        cond = Op('Lt', ind_var.copy(), Op('len', it_var.copy()),
                  line=node.iter.lineno)
                  
        # Assignments to iterated variable(s)
        prebody = []
        el = Op('GetElement', it_var.copy(), ind_var.copy(),
                line=node.target.lineno)
        if len(targets) == 1:
            prebody.append((targets[0].name, el.copy()))
        else:
            for i, t in enumerate(targets):
                eli = Op('GetElement', el.copy(), Const(str(i)),
                         line=node.target.lineno)
                prebody.append((t.name, eli))
        
        # Add index variable increment
        prebody.append((ind_var.name,
                        Op('Add', ind_var.copy(), Const(str(1)),
                           line=node.iter.lineno)))

        self.visit_loop(node, None, cond, None, node.body, False, 'for',
                        prebody=prebody)
Esempio n. 13
0
    def visit_scanf(self, node, args):
        '''
        scanf function call
        '''

        # Check format
        if len(args) == 0:
            self.warn("'scanf' without arguments at line %s (ignored)",
                      node.coord.line)
        else:
            fmt = args[0]

            if isinstance(fmt, Const) and fmt.value[0] == '"' \
               and fmt.value[-1] == '"':
                fmt = fmt.value[1:-1]
                args = args[1:]
            else:
                self.warn("First argument of 'scanf' at line %s should be a \
(string) format (ignored)",
                          node.coord.line)
                fmt = ''
                args = []

        # Extract format arguments
        fs = list(re.findall(
            r'(%((d)|(i)|(li)|(lli)|(ld)|(lld)|(lf)|(f)|(s)|(c)))', fmt))

        # Check argument number
        if len(fs) != len(args):
            self.addwarn("Mismatch between format and number of argument(s)\
of 'scanf' at line %s.",
                         node.coord.line)

            if len(args) > len(fs):
                fs += ['*' for _ in xrange(len(args) - len(fs))]

        # Iterate formats and arguments
        for f, a in zip(fs, args):

            if f:
                f = f[0]

            # Get type from an argument
            if f in ['%d', '%ld', '%i', '%li', '%lli', '%lld']:
                t = 'int'
            elif f in ['%c']:
                t = 'char'
            elif f in ['%s']:
                t = 'string'
            elif f in ['%f', '%lf']:
                t = 'float'
            elif f == '*':
                t = '*'
            else:
                self.addwarn("Invalid 'scanf' format at line %s.",
                             node.coord.line)
                t = '*'

            # Check argument type
            if isinstance(a, Op) and a.name == '&' and len(a.args) == 1:
                a = a.args[0]

            elif isinstance(a, Var) or (isinstance(a, Op) and a.name == '[]'):
                self.addwarn("Forgoten '&' in 'scanf' at line %s?",
                             node.coord.line)

            else:
                raise NotSupported("Argument to scanf: '%s'" % (a,),
                                   line=node.coord.line)

            # Add operations
            rexpr = Op('ListHead', Const(t), Var(VAR_IN), line=node.coord.line)
            if isinstance(a, Var):
                self.addexpr(a.name, rexpr)
            elif isinstance(a, Op) and a.name == '[]' and isinstance(a.args[0],
                                                                     Var):
                self.addexpr(a.args[0].name,
                             Op('ArrayAssign', a.args[0], a.args[1], rexpr,
                                line=node.coord.line))
            else:
                raise NotSupported("Argument to scanf: '%s'" % (a,),
                                   line=node.coord.line)
            self.addexpr(VAR_IN,
                         Op('ListTail', Var(VAR_IN), line=node.coord.line))
Esempio n. 14
0
    def potential(self, f1, f2, loc1, var1, loc2):

        varp1 = prime(var1)
        expr1 = self.E1[loc1][var1]
        isid = (isinstance(expr1, Var) and expr1.name == var1
                and expr1.primed == False)
        tree1 = self.T1[loc1][var1]
        vars1 = list(set(map(unprimes, expr1.vars())) | set([var1]))
        vars1.sort()

        V1 = list(self.V1 - set(['-']))
        V1.sort()
        V2 = list(self.V2)
        V2.sort()

        for var2 in V2:

            sofar = set()

            # Special vars can be only mapped to special vars
            if (var1 in SPECIAL_VARS or var2 in SPECIAL_VARS) and var1 != var2:
                continue

            # other special variables
            if var2 != '*':
                if var1.startswith('ind#') != var2.startswith('ind#'):
                    continue
                if var1.startswith('iter#') != var2.startswith('iter#'):
                    continue

            # Params can only be mapped to params
            if ((var1 in self.pmap or var2 in self.pmap.keys())
                    and var2 != self.pmap.get(var1)):
                continue

            # Cannot delete new variable
            if var1 == '-' and var2 == '*':
                continue

            expr2 = self.E2[loc2][var2]
            tree2 = self.T2[loc2][var2]
            vars2 = list(set(map(unprimes, expr2.vars())) | set([var2]))
            vars2.sort()

            # (0) Deletes are special
            if var1 == '-':
                delexpr = Var(var2)
                deltree = self.totree(delexpr)
                delcost = self.distance(tree2, deltree, {var2: var2})
                if delcost:
                    yield ([(var1, var2)], delcost, (), None)
                continue

            # (1) Generate corrects (if not new variable)
            if var2 != '*':
                for m in self.one_to_ones(vars2, V1, var2, var1):
                    m = [(s2, s1) for (s1, s2) in m]
                    ok = True
                    for mem1 in self.trace.get(f1.name, {}).get(loc1, []):
                        val1 = mem1.get(varp1)

                        if isundef(val1) and (var1 != VAR_RET):
                            continue

                        if isinstance(val1, str) and self.cleanstrings:
                            val1 = val1.strip()

                        mem2 = {v2: mem1.get(v1) for (v1, v2) in m}
                        mem2.update(
                            {prime(v2): mem1.get(prime(v1))
                             for (v1, v2) in m})
                        try:
                            val2 = self.inter.execute(expr2, mem2)
                            if isinstance(val2, str) and self.cleanstrings:
                                val2 = val2.strip()

                            if not equals(val2, val1):
                                ok = False
                                break
                        except RuntimeErr:
                            ok = False
                            break
                    if ok:
                        order = self.getorder(var2, expr2,
                                              {v: v
                                               for v in vars2})
                        if order is None:
                            assert False, 'order error %s %s' % (var2, expr2)
                        ms = list(m)
                        ms.sort()
                        sofar.add((tuple(ms), tuple(order)))
                        yield (m, 0, set(order), None)

            # (2) Generate repairs
            tmprepairs = {}
            #for rexpr, rtree in zip([self.E1[loc1][var1]], [self.T1[loc1][var1]]):
            for idx, ((rexpr, _), rtree) in enumerate(
                    zip(self.ER[loc1][var1], self.TR[loc1][var1])):

                risid = (isinstance(rexpr, Var) and rexpr.name == var1
                         and rexpr.primed == False)
                rvars = list(set(map(unprimes, rexpr.vars())) | set([var1]))

                for m in self.one_to_ones(rvars, V2, var1, var2):
                    order = self.getorder(var2, rexpr, dict(m))

                    if order is None:
                        self.debug(
                            'skipping repair %s := %s (%s) because impossible order',
                            var1, expr1, m)
                        continue

                    if risid and var2 == '*':
                        cost = 0
                    else:
                        cost = self.distance(tree2, rtree, dict(m))

                    # Account for *declaring* a new variable
                    if var2 == '*' and loc1 == 1:
                        cost += 1

                    ms = list(m)
                    ms.sort()

                    tms = tuple(ms)
                    torder = tuple(order)

                    if (tms, torder) in sofar:
                        continue

                    # From each 'm'-'order' pair we first remember all pairs
                    # and later yield only the one with the smallest cost
                    # since other ones have no sense
                    tmp = (tms, torder)
                    if tmp not in tmprepairs:
                        tmprepairs[tmp] = []
                    tmprepairs[tmp].append((cost, (m, cost, set(order), idx)))

                    #yield (m, cost, set(order))

            for treps in tmprepairs.values():
                treps.sort()
                #print treps[0][1]
                yield treps[0][1]
Esempio n. 15
0
def query_transformation_initiated_at(query):
    args0, args1 = query.args

    args0args0 = args0.args[0]

    return query(args0(args0args0, Var('X')), args1)
Esempio n. 16
0
def query_transformation_happens_at(query):
    args0, _, args2 = query.args

    return query(args0, Var('X'), args2)
Esempio n. 17
0
    def visit_For(self, node):

        if node.orelse:
            raise NotSupported("For-Else not supported",
                               line=self.getline(node.orelse))

        # Iterated expression
        it = self.visit_expr(node.iter)

        # Targets of iteration
        if isinstance(node.target, ast.Name):
            targets = [self.visit_expr(node.target)]
        elif isinstance(node.target, ast.Tuple):
            targets = map(self.visit_expr, node.target.elts)
        else:
            raise NotSupported('For loop with {} as target'.format(
                node.target.__class__.__name__),
                               line=node.lineno)

        hiddenvar = self.hiddenvarcnt
        self.hiddenvarcnt += 1

        # Set up the iterated variable
        iter_name = 'iter#{}'.format(hiddenvar)
        it_var = Var(iter_name)
        self.addtype(iter_name, '*')

        # Set up the iteration index
        ind_name = 'ind#{}'.format(hiddenvar)
        ind_var = Var(ind_name)
        self.addtype(ind_name, 'int')

        # Add assignments to iterators
        self.addexpr(it_var.name, it)
        self.addexpr(ind_var.name, Const(str(0), line=node.lineno))

        # Condition is ind_var < len(iter_var)
        cond = Op('Lt',
                  ind_var.copy(),
                  Op('len', it_var.copy()),
                  line=node.iter.lineno)

        # Assignments to iterated variable(s)
        prebody = []
        el = Op('GetElement',
                it_var.copy(),
                ind_var.copy(),
                line=node.target.lineno)
        if len(targets) == 1:
            prebody.append((targets[0].name, el.copy()))
        else:
            for i, t in enumerate(targets):
                eli = Op('GetElement',
                         el.copy(),
                         Const(str(i)),
                         line=node.target.lineno)
                prebody.append((t.name, eli))

        # Add index variable increment
        prebody.append((ind_var.name,
                        Op('Add',
                           ind_var.copy(),
                           Const(str(1)),
                           line=node.iter.lineno)))

        self.visit_loop(node,
                        None,
                        cond,
                        None,
                        node.body,
                        False,
                        'for',
                        prebody=prebody)
Esempio n. 18
0
    def potential(self, f1, f2, loc1, var1, loc2):

        varp1 = prime(var1)
        expr1 = self.E1[loc1][var1]
        isid = isinstance(expr1, Var) and expr1.name == var1
        tree1 = self.T1[loc1][var1]
        vars1 = list(set(map(unprimes, expr1.vars())) | set([var1]))
        vars1.sort()

        V1 = list(self.V1 - set(['-']))
        V1.sort()
        V2 = list(self.V2)
        V2.sort()

        for var2 in V2:

            sofar = set()

            # Special vars can be only mapped to special vars
            if (var1 in SPECIAL_VARS or var2 in SPECIAL_VARS) and var1 != var2:
                continue

            # Params can only be mapped to params
            if var1 in self.pmap and var2 != self.pmap[var1]:
                continue

            # Cannot delete new variable
            if var1 == '-' and var2 == '*':
                continue

            expr2 = self.E2[loc2][var2]
            tree2 = self.T2[loc2][var2]
            vars2 = list(set(map(unprimes, expr2.vars())) | set([var2]))
            vars2.sort()

            # (0) Deletes are special
            if var1 == '-':
                delexpr = Var(var2)
                deltree = self.totree(delexpr)
                delcost = self.distance(tree2, deltree, {var2: var2})
                if delcost:
                    yield ([(var1, var2)], delcost, ())
                continue

            # (1) Generate corrects (if not new variable)
            if var2 != '*':
                for m in self.one_to_ones(vars2, V1, var2, var1):
                    m = [(s2, s1) for (s1, s2) in m]
                    ok = True
                    for mem1 in self.trace.get(f1.name, {}).get(loc1, []):
                        val1 = mem1.get(varp1)

                        if isundef(val1):
                            continue

                        if isinstance(val1, str) and self.cleanstrings:
                            val1 = val1.strip()

                        mem2 = {v2: mem1.get(v1) for (v1, v2) in m}
                        mem2.update(
                            {prime(v2): mem1.get(prime(v1))
                             for (v1, v2) in m})
                        try:
                            val2 = self.inter.execute(expr2, mem2)
                            if isinstance(val2, str) and self.cleanstrings:
                                val2 = val2.strip()

                            if val2 != val1:
                                ok = False
                                break
                        except RuntimeErr:
                            ok = False
                            break
                    if ok:
                        order = self.getorder(var2, expr2,
                                              {v: v
                                               for v in vars2})
                        if order is None:
                            assert False, 'order error %s %s' % (var2, expr2)
                        ms = list(m)
                        ms.sort()
                        sofar.add((tuple(ms), tuple(order)))
                        yield (m, 0, set(order))

            # (2) Generate repairs
            for m in self.one_to_ones(vars1, V2, var1, var2):
                order = self.getorder(var2, expr1, dict(m))
                if order is None:
                    self.debug(
                        'skipping repair %s := %s (%s) because \
impossible order', var1, expr1, m)
                    continue
                if isid and var2 == '*':
                    cost = 0
                else:
                    cost = self.distance(tree2, tree1, dict(m))

                # Account for *declaring* a new variable
                if var2 == '*' and loc1 == 1:
                    cost += 1

                ms = list(m)
                ms.sort()
                if (tuple(ms), tuple(order)) in sofar:
                    continue
                yield (m, cost, set(order))