def match_mems(self, match, loc, mem1, mem2, V1): # Go through all variables for var1 in V1 | SPECIAL_VARS: # Ignored vars if self.ignoreret and var1 == VAR_RET: continue if self.ignoreio and var1 in [VAR_IN, VAR_OUT]: continue # If var1 not matched yet, build a list of potential matches if var1 not in match: if var1 in SPECIAL_VARS: match[var1] = set([var1]) else: match[var1] = { var2 for var2 in mem2.keys() if not isprimed(var2) } # Check list of potential matches newmatch = set([]) varp1 = prime(var1) for var2 in match[var1]: varp2 = prime(var2) # Get values val1 = mem1.get(varp1, UndefValue()) val2 = mem2.get(varp2, UndefValue()) # Debug vars if self.debugvar == '%s-%s' % (loc, var1): self.debug('VAR %s = %s', var1, val1) self.debug('VAR %s = %s', var2, val2) if isundef(val1) or val1 == val2: self.debug('VAR equal') else: self.debug('VAR unequal') self.debug('') # Check if equal # TODO: Different equality? if isundef(val1) or val1 == val2: newmatch.add(var2) # If no match for then done if len(newmatch) == 0: self.debug("Couldn find match for %s-%s", loc, var1) return False # Otherwise replace with new matches else: match[var1] = newmatch return True
def islarge(self): ''' Decides if generated repair is large (new variable, new statement, swapped statements) ''' for fnc, (m, repairs, sm) in self.results.items(): for rep in repairs: loc1 = rep.loc1 var1 = rep.var1 var2 = rep.var2 expr1 = rep.expr1 loc2 = sm[loc1] # Added/deleted variable if var2 == '*': return True if var1 == '-': return False # Added stmt if self.spec.getfnc(fnc).hasexpr(loc1, var1) \ and (not self.impl.getfnc(fnc).hasexpr(loc2, var2)): return True # Swapped stmts #expr1 = self.spec.getfnc(fnc).getexpr(loc1, var1) expr2 = self.impl.getfnc(fnc).getexpr(loc2, var2) vars1 = expr1.vars() vars2 = expr2.vars() for var1 in vars1: if isprimed(var1): var1 = unprime(var1) var2m = m[var1] var2mp = prime(var2m) if var2m in vars2 and var2mp not in vars2: return True else: var2m = m[var1] var2mp = prime(var2m) if var2mp in vars2 and var2m not in vars2: return True # Nothing found return False
def execute_FuncCall(self, f, mem): name = f.args[0].name try: fnc = self.getfnc(name) except KeyError: raise RuntimeErr("Unknown function: '%s'" % (name, )) args = map(lambda x: self.execute(x, mem), f.args[1:]) newmem = { VAR_IN: mem.get(VAR_IN, UndefValue()), VAR_OUT: mem.get(VAR_OUT, UndefValue()), } if len(fnc.params) != len(args): raise RuntimeErr("Wrong number of args: expected %s, got %s" % (len(fnc.params), len(args))) for (var, _), arg in zip(fnc.params, args): newmem[var] = deepcopy(arg) oldfnc = self.fnc oldloc = self.loc trace = self.execute(fnc, newmem) self.fnc = oldfnc self.loc = oldloc return trace[-1][2].get(prime(VAR_RET), self.DEFAULT_RETURN)
def execute_FuncCall(self, f, mem): name = f.args[0].name try: fnc = self.getfnc(name) except KeyError: raise RuntimeErr("Unknown function: '%s'" % (name,)) args = map(lambda x: self.execute(x, mem), f.args[1:]) newmem = { VAR_IN: mem.get(VAR_IN, UndefValue()), VAR_OUT: mem.get(VAR_OUT, UndefValue()), } if len(fnc.params) != len(args): raise RuntimeErr("Wrong number of args: expected %s, got %s" % ( len(fnc.params), len(args) )) for (var, _), arg in zip(fnc.params, args): newmem[var] = deepcopy(arg) oldfnc = self.fnc oldloc = self.loc trace = self.execute(fnc, newmem) self.fnc = oldfnc self.loc = oldloc return trace[-1][2].get(prime(VAR_RET), self.DEFAULT_RETURN)
def procmem(self, mem): newmem = dict() for var, val in mem.items(): if isprimed(var): var = unprime(var) newmem[var] = deepcopy(val) else: varp = prime(var) if varp not in mem: newmem[var] = deepcopy(val) mem[varp] = deepcopy(val) return newmem, mem
def execute_Function(self, fnc, mem): self.fnc = fnc.name self.loc = fnc.initloc while True: # Execute all exprs for (var, expr) in fnc.exprs(self.loc): val = self.execute(expr, mem) if var == VAR_COND: val = not not val varp = prime(var) vtype = (fnc.rettype if var == VAR_RET else (fnc.gettype(var) or '*')) mem[varp] = self.convert(val, vtype) if var == VAR_RET and not isundef(val): break # Save memory (newmem, mem) = self.procmem(mem) self.trace.append((self.fnc, self.loc, mem)) mem = newmem # Check return if not isundef(mem.get(VAR_RET, UndefValue())): break # Find new location numtrans = fnc.numtrans(self.loc) if numtrans == 0: # Done break elif numtrans == 1: # Trivially choose True self.loc = fnc.trans(self.loc, True) else: self.loc = fnc.trans(self.loc, mem.get(VAR_COND)) return self.trace
def f(l1, l2): if not l1: return 0 if (not l2) else 1 if not l2: return 0 if (not l1) else 1 (t1, v1) = l1 (t2, v2) = l2 if t1 != t2: return 1 if t2 == 'V': if isprimed(v2): v2 = prime(m.get(unprime(v2), 'X')) else: v2 = m.get(v2, 'X') return 0 if v1 == v2 else 1
def gethint(self, expr1, expr2, first=False): ''' Tries to generate some useful hints ''' # Output if self.isout(expr1): return self.getouthint(expr1, expr2) # Constant if isinstance(expr1, Const): if isinstance(expr2, Const): if expr1.value != expr2.value: return "use the constant '%s' intead of '%s'" % ( expr1.value, expr2.value, ) else: return elif isinstance(expr2, Var): return "use some constant instead of the variable '%s'" % ( expr2.name, ) else: if first: return 'use a just constant' else: return # Check for changing an order of statement vars1 = expr1.vars() vars2 = expr2.vars() for var1 in vars1: if isprimed(var1): if unprime(var1) in vars2: return "try changing the order of statements by moving it after the assignment to '%s', or vice-versa" % ( unprime(var1), ) else: if prime(var1) in vars2: return "try changing the order of statements by moving it before the assignment to '%s', or vice-versa" % ( var1, ) # Different variable name if isinstance(expr1, Var): if isinstance(expr2, Var): if expr1.name != expr2.name: if expr1.name.startswith('$new'): return "use a different variable instead of '%s'" % ( expr2.name, ) else: return "use the variable '%s', instead of '%s'" % ( expr1.name, expr2.name, ) else: return else: if isinstance(expr2, Const): return "replace the constant '%s' by some variable" % ( expr2.value, ) if first: return 'use just a variable' else: return # Operation comparison if isinstance(expr1, Op): if isinstance(expr2, Op): # Operators for opname, ops in self.opdefs: if expr1.name in ops and len(expr1.args) == 2: if expr2.name in ops and len(expr2.args) == 2: same1 = self.issame(expr1.args[0], expr2.args[0]) same2 = self.issame(expr1.args[1], expr2.args[1]) # Different operators if same1 and same2 and expr1.name != expr2.name: return "use a different %s operator instead of '%s'" % ( opname, expr2.name, ) # Different right side if same1 and expr1.name == expr2.name: h = self.gethint(expr1.args[1], expr2.args[1]) if h: return h # Different left side if same2 and expr1.name == expr2.name: h = self.gethint(expr1.args[0], expr2.args[0]) if h: return h # if first and expr1.name == expr2.name: # h1 = self.gethint(expr1.args[0], expr2.args[0]) # h2 = self.gethint(expr1.args[1], expr2.args[1]) # if h1 and h2: # return '%s and %s' % (h1, h2) if first and expr1.name == 'ite': h = self.ite_hint(expr1, expr2) if h: return h # Nothing else to do, except to generate a template if first: t = self.gettemplate(expr1, expr2, outer=True) if t: return self.templatetext(t)
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]
def match_mems(self, match, loc, mem1, mem2, V1): V2 = ({var2 for var2 in mem2.keys() if not isprimed(var2)} - SPECIAL_VARS) if self.bijective: if len(V1 | SPECIAL_VARS) != len(V2 | SPECIAL_VARS): self.debug('Not bijective - different number of variables') return False # Go through all variables for var1 in V1 | SPECIAL_VARS: # Ignored vars if self.ignoreret and var1 == VAR_RET: continue if self.ignoreio and var1 in [VAR_IN, VAR_OUT]: continue # If var1 not matched yet, build a list of potential matches if var1 not in match: if var1 in SPECIAL_VARS: match[var1] = set([var1]) else: match[var1] = set(V2) # Check list of potential matches newmatch = set([]) varp1 = prime(var1) for var2 in match[var1]: varp2 = prime(var2) if var1.startswith('ind#') != var2.startswith('ind#'): continue if var1.startswith('iter#') != var2.startswith('iter#'): continue # Get values val1 = mem1.get(varp1, UndefValue()) val2 = mem2.get(varp2, UndefValue()) # Debug vars if self.debugvar == '%s-%s' % (loc, var1): self.debug('VAR %s = %s', var1, val1) self.debug('VAR %s = %s', var2, val2) if isundef(val1) or equals(val1, val2): self.debug('VAR equal') else: self.debug('VAR unequal') self.debug('') # Check if equal if isundef(val1) or equals(val1, val2): newmatch.add(var2) # If no match for then done if len(newmatch) == 0: self.debug("Couldn find match for %s-%s", loc, var1) return False # Otherwise replace with new matches else: match[var1] = newmatch return True
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]
def gethint(self, expr1, expr2, first=False): ''' Tries to generate some useful hints ''' # Output if self.isout(expr1): return self.getouthint(expr1, expr2) # Constant if isinstance(expr1, Const): if isinstance(expr2, Const): if expr1.value != expr2.value: return "use the constant '%s' intead of '%s'" % ( expr1.value, expr2.value,) else: return elif isinstance(expr2, Var): return "use some constant instead of the variable '%s'" % (expr2.name,) else: if first: return 'use a just constant' else: return # Check for changing an order of statement vars1 = expr1.vars() vars2 = expr2.vars() for var1 in vars1: if isprimed(var1): if unprime(var1) in vars2: return "try changing the order of statements by moving it after the assignment to '%s', or vice-versa" % (unprime(var1),) else: if prime(var1) in vars2: return "try changing the order of statements by moving it before the assignment to '%s', or vice-versa" % (var1,) # Different variable name if isinstance(expr1, Var): if isinstance(expr2, Var): if expr1.name != expr2.name: if expr1.name.startswith('$new'): return "use a different variable instead of '%s'" % ( expr2.name,) else: return "use the variable '%s', instead of '%s'" % ( expr1.name, expr2.name,) else: return else: if isinstance(expr2, Const): return "replace the constant '%s' by some variable" % (expr2.value,) if first: return 'use just a variable' else: return # Operation comparison if isinstance(expr1, Op): if isinstance(expr2, Op): # Operators for opname, ops in self.opdefs: if expr1.name in ops and len(expr1.args) == 2: if expr2.name in ops and len(expr2.args) == 2: same1 = self.issame(expr1.args[0], expr2.args[0]) same2 = self.issame(expr1.args[1], expr2.args[1]) # Different operators if same1 and same2 and expr1.name != expr2.name: return "use a different %s operator instead of '%s'" % ( opname, expr2.name,) # Different right side if same1 and expr1.name == expr2.name: h = self.gethint(expr1.args[1], expr2.args[1]) if h: return h # Different left side if same2 and expr1.name == expr2.name: h = self.gethint(expr1.args[0], expr2.args[0]) if h: return h # if first and expr1.name == expr2.name: # h1 = self.gethint(expr1.args[0], expr2.args[0]) # h2 = self.gethint(expr1.args[1], expr2.args[1]) # if h1 and h2: # return '%s and %s' % (h1, h2) if first and expr1.name == 'ite': h = self.ite_hint(expr1, expr2) if h: return h # Nothing else to do, except to generate a template if first: t = self.gettemplate(expr1, expr2, outer=True) if t: return self.templatetext(t)
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))