| # ------------------------------------------------------------------------------- |
| # optimizer.py |
| # |
| # Dataflow optimizer |
| # |
| # Copyright (C) 2013, Shinya Takamaeda-Yamazaki |
| # License: Apache 2.0 |
| # ------------------------------------------------------------------------------- |
| from __future__ import absolute_import |
| from __future__ import print_function |
| import sys |
| import os |
| import math |
| |
| import pyverilog.utils.verror as verror |
| import pyverilog.utils.signaltype as signaltype |
| from pyverilog.dataflow.dataflow import * |
| |
| |
| class VerilogOptimizer(object): |
| default_width = 32 |
| compare_ops = ('LessThan', 'GreaterThan', 'LassEq', 'GreaterEq', 'Eq', 'NotEq', 'Eql', 'NotEql') |
| |
| def __init__(self, terms, constlist=None, default_width=32, level=2): |
| self.terms = terms |
| self.constlist = constlist if constlist is not None else {} |
| self.default_width = default_width |
| self.level = level |
| |
| def setConstant(self, name, value): |
| self.constlist[name] = value |
| |
| def resetConstant(self, name): |
| if name in self.constlist: |
| del self.constlist[name] |
| |
| def getConstant(self, name): |
| if not name in self.constlist: |
| raise verror.DefinitionError('constant value not found: %s' % str(name)) |
| return self.constlist[name] |
| |
| def hasConstant(self, name): |
| return name in self.constlist |
| |
| def getConstlist(self): |
| return self.constlist |
| |
| def setTerm(self, name, term): |
| self.terms[name] = term |
| |
| def getTerm(self, name): |
| return self.terms[name] |
| |
| def hasTerm(self, name): |
| return name in self.terms |
| |
| def optimize(self, tree): |
| t = tree |
| for i in range(self.level): |
| t = self.optimizeConstant(t) |
| t = self.optimizeHierarchy(t) |
| return t |
| |
| def optimizeConstant(self, tree): |
| if tree is None: |
| return None |
| if isinstance(tree, DFBranch): |
| condnode = self.optimizeConstant(tree.condnode) |
| truenode = self.optimizeConstant(tree.truenode) |
| falsenode = self.optimizeConstant(tree.falsenode) |
| if isinstance(condnode, DFEvalValue): |
| if self.isCondTrue(condnode): |
| return truenode |
| return falsenode |
| return DFBranch(condnode, truenode, falsenode) |
| |
| if isinstance(tree, DFEvalValue): |
| return tree |
| if isinstance(tree, DFUndefined): |
| return tree |
| if isinstance(tree, DFHighImpedance): |
| return tree |
| if isinstance(tree, DFDelay): |
| raise FormatError('Can not evaluate and optimize a DFDelay') |
| # return tree |
| |
| if isinstance(tree, DFIntConst): |
| if 'x' in tree.value or 'z' in tree.value: |
| return DFUndefined(tree.width()) |
| if 'X' in tree.value or 'Z' in tree.value: |
| return DFUndefined(tree.width()) |
| return DFEvalValue(tree.eval(), tree.width()) |
| if isinstance(tree, DFFloatConst): |
| return DFEvalValue(tree.eval(), self.default_width, isfloat=True) |
| if isinstance(tree, DFStringConst): |
| return DFEvalValue(tree.eval(), None, isstring=True) |
| if isinstance(tree, DFConstant): |
| if 'x' in tree.value or 'z' in tree.value: |
| return DFUndefined() |
| if 'X' in tree.value or 'Z' in tree.value: |
| return DFUndefined() |
| return DFEvalValue(tree.eval(), self.default_width) |
| |
| if isinstance(tree, DFOperator): |
| nextnodes_rslts, all_const = self.evalNextnodes(tree.nextnodes) |
| if all_const: |
| evalop = self.evalOperator(tree.operator, nextnodes_rslts) |
| if evalop is not None: |
| return evalop |
| return DFOperator(tuple(nextnodes_rslts), tree.operator) |
| |
| if isinstance(tree, DFTerminal): |
| if not self.hasConstant(tree.name): |
| return tree |
| msb = self.getTerm(tree.name).msb |
| lsb = self.getTerm(tree.name).lsb |
| const = self.getConstant(tree.name) |
| constwidth = const.width |
| if msb is not None and lsb is not None: |
| msb_val = self.optimizeConstant(msb) |
| lsb_val = self.optimizeConstant(lsb) |
| if isinstance(msb_val, DFEvalValue) and isinstance(lsb_val, DFEvalValue): |
| constwidth = msb_val.value - lsb_val.value + 1 |
| return DFEvalValue(const.value, constwidth) |
| |
| if isinstance(tree, DFConcat): |
| nextnodes_rslts, all_const = self.evalNextnodes(tree.nextnodes) |
| if all_const: |
| evalcc = self.evalConcat(nextnodes_rslts) |
| if evalcc is not None: |
| return evalcc |
| return DFConcat(tuple(nextnodes_rslts)) |
| |
| if isinstance(tree, DFPartselect): |
| var = self.optimizeConstant(tree.var) |
| msb = self.optimizeConstant(tree.msb) |
| lsb = self.optimizeConstant(tree.lsb) |
| if isinstance(var, DFEvalValue) and isinstance(msb, DFEvalValue) and isinstance(msb, DFEvalValue): |
| evalcc = self.evalPartselect(var, msb, lsb) |
| return evalcc |
| return DFPartselect(var, msb, lsb) |
| |
| if isinstance(tree, DFPointer): |
| if not isinstance(tree.var, DFTerminal): |
| return tree |
| term = self.getTerm(tree.var.name) |
| var = self.optimizeConstant(tree.var) |
| ptr = self.optimizeConstant(tree.ptr) |
| if term.dims is not None: |
| return DFPointer(var, ptr) |
| if isinstance(var, DFEvalValue) and isinstance(ptr, DFEvalValue): |
| evalcc = self.evalPointer(var, ptr) |
| return evalcc |
| return DFPointer(var, ptr) |
| |
| if isinstance(tree, DFSyscall): |
| return DFSyscall(tree.syscall, tuple([self.optimizeConstant(n) for n in tree.nextnodes])) |
| |
| raise verror.DefinitionError('Can not optimize the tree: %s %s' % |
| (str(type(tree)), str(tree))) |
| |
| def evalNextnodes(self, nextnodes): |
| ret = [] |
| all_const = True |
| for n in nextnodes: |
| rslt = self.optimizeConstant(n) |
| ret.append(rslt) |
| if not isinstance(rslt, DFEvalValue): |
| all_const = False |
| return tuple(ret), all_const |
| |
| def evalOperator(self, operator, nextnodes): |
| valuelist = [] |
| width = 0 |
| for n in nextnodes: |
| if not isinstance(n, DFEvalValue): |
| return None |
| valuelist.append(n.value) |
| if n.width > width: |
| width = n.width |
| rslt = self._evalOperator(operator, tuple(valuelist), width) |
| return DFEvalValue(rslt, width) |
| |
| def _evalOperator(self, operator, valuelist, width=default_width): |
| if operator == 'Uminus': |
| return -1 * valuelist[0] |
| if operator == 'Ulnot': |
| if valuelist[0] == 0: |
| return 1 |
| return 0 |
| if operator == 'Unot': |
| retval = 0 |
| for i in range(width): |
| if valuelist[0] & (1 << i) == 0: |
| retval |= (1 << i) |
| return retval |
| if operator == 'Uand': |
| for i in range(width): |
| if valuelist[0] & (1 << i) == 0: |
| return 0 |
| return 1 |
| if operator == 'Unand': |
| for i in range(width): |
| if valuelist[0] & (1 << i) == 0: |
| return 1 |
| return 0 |
| if operator == 'Uor': |
| for i in range(width): |
| if valuelist[0] & (1 << i) != 0: |
| return 1 |
| return 0 |
| if operator == 'Unor': |
| for i in range(width): |
| if valuelist[0] & (1 << i) != 0: |
| return 0 |
| return 1 |
| if operator == 'Uxor': |
| rslt = 0 |
| for i in range(width): |
| if valuelist[0] & (1 << i) != 0: |
| rslt = 1 if rslt == 0 else 0 |
| return rslt |
| if operator == 'Uxnor': |
| rslt = 1 |
| for i in range(width): |
| if valuelist[0] & (1 << i) != 0: |
| rslt = 1 if rslt == 0 else 0 |
| return rslt |
| if operator == 'Power': |
| return valuelist[0] ** valuelist[1] |
| if operator == 'Times': |
| return valuelist[0] * valuelist[1] |
| if operator == 'Divide': |
| value = valuelist[0] / valuelist[1] |
| if isinstance(valuelist[0], int) and isinstance(valuelist[1], int): |
| return int(value) |
| return value |
| if operator == 'Mod': |
| return valuelist[0] % valuelist[1] |
| if operator == 'Plus': |
| return valuelist[0] + valuelist[1] |
| if operator == 'Minus': |
| return valuelist[0] - valuelist[1] |
| if operator == 'Sll': |
| return valuelist[0] << valuelist[1] |
| if operator == 'Srl': |
| return valuelist[0] >> valuelist[1] |
| if operator == 'Sra': |
| return valuelist[0] >> valuelist[1] |
| |
| if operator == 'LessThan': |
| return 1 if valuelist[0] < valuelist[1] else 0 |
| if operator == 'GreaterThan': |
| return 1 if valuelist[0] > valuelist[1] else 0 |
| if operator == 'LessEq': |
| return 1 if valuelist[0] <= valuelist[1] else 0 |
| if operator == 'GreaterEq': |
| return 1 if valuelist[0] >= valuelist[1] else 0 |
| if operator == 'Eq': |
| return 1 if valuelist[0] == valuelist[1] else 0 |
| if operator == 'NotEq': |
| return 1 if valuelist[0] != valuelist[1] else 0 |
| if operator == 'Eql': |
| return 1 if valuelist[0] == valuelist[1] else 0 |
| if operator == 'NotEql': |
| return 1 if valuelist[0] != valuelist[1] else 0 |
| if operator == 'And': |
| return valuelist[0] & valuelist[1] |
| if operator == 'Xor': |
| return valuelist[0] ^ valuelist[1] |
| if operator == 'Xnor': |
| return ~(valuelist[0] ^ valuelist[1]) |
| if operator == 'Or': |
| return valuelist[0] | valuelist[1] |
| if operator == 'Land': |
| return 1 if valuelist[0] and valuelist[1] else 0 |
| if operator == 'Lor': |
| return 1 if valuelist[0] or valuelist[1] else 0 |
| return None |
| |
| def getWidth(self, node): |
| if node is None: |
| return self.default_width |
| if isinstance(node, DFUndefined): |
| if node.width is not None: |
| return node.width |
| return self.default_width |
| if isinstance(node, DFHighImpedance): |
| if node.width is not None: |
| return node.width |
| return self.default_width |
| if isinstance(node, DFIntConst): |
| return node.width() |
| if isinstance(node, DFConstant): |
| return self.default_width |
| if isinstance(node, DFEvalValue): |
| if node.width is not None: |
| return node.width |
| return self.default_width |
| if isinstance(node, DFTerminal): |
| term = self.getTerm(node.name) |
| msb = self.optimizeConstant(term.msb).value |
| lsb = self.optimizeConstant(term.lsb).value |
| width = abs(msb - lsb) + 1 |
| return width |
| |
| if isinstance(node, DFBranch): |
| truewidth = self.getWidth(node.truenode) |
| falsewidth = self.getWidth(node.falsenode) |
| return max(truewidth, falsewidth) |
| |
| if isinstance(node, DFPartselect): |
| msb = self.optimizeConstant(node.msb).value |
| lsb = self.optimizeConstant(node.lsb).value |
| width = abs(msb - lsb) + 1 |
| return width |
| if isinstance(node, DFOperator): |
| if node.operator in self.compare_ops: |
| return 1 |
| if node.operator == 'Land' or node.operator == 'Lor': |
| return 1 |
| maxwidth = 0 |
| for n in node.nextnodes: |
| width = self.getWidth(n) |
| if maxwidth < width: |
| maxwidth = width |
| return maxwidth |
| if isinstance(node, DFConcat): |
| sumwidth = 0 |
| for n in node.nextnodes: |
| width = self.getWidth(n) |
| sumwidth += width |
| return sumwidth |
| if isinstance(node, DFPointer): |
| if not isinstance(node.var, DFTerminal): |
| return 1 |
| term = self.getTerm(node.var.name) |
| if term.dims is not None: |
| msb = self.optimizeConstant(term.msb).value |
| lsb = self.optimizeConstant(term.lsb).value |
| width = abs(msb - lsb) + 1 |
| return width |
| return 1 |
| if isinstance(tree, DFSyscall): |
| return self.default_width |
| |
| raise FormatError('Illegal Pointer in getWidth()') |
| |
| def evalConcat(self, nextnodes): |
| concatval = 0 |
| sum_width = 0 |
| for node in nextnodes: |
| width = self.getWidth(node) |
| sum_width += width |
| concatval = (concatval << width) | node.value |
| return DFEvalValue(concatval, sum_width) |
| |
| def isCondTrue(self, cond): |
| if not isinstance(cond, DFEvalValue): |
| raise FormatError('Can not evaluate the branch condition.') |
| if cond.value == 0: |
| return False |
| return True |
| |
| def evalPartselect(self, var, msb, lsb): |
| width = msb.value - lsb.value + 1 |
| partval = var.value >> lsb.value |
| if partval >= 2 ** width: |
| partval = partval % (2 ** width) |
| return DFEvalValue(partval, width) |
| |
| def evalPointer(self, var, ptr): |
| ptrval = (var >> ptr) & 0x1 |
| return DFEvalValue(ptrval, 1) |
| |
| def optimizeHierarchy(self, tree): |
| if tree is None: |
| return None |
| if isinstance(tree, DFIntConst): |
| return tree |
| if isinstance(tree, DFFloatConst): |
| return tree |
| if isinstance(tree, DFStringConst): |
| return tree |
| if isinstance(tree, DFEvalValue): |
| return tree |
| if isinstance(tree, DFUndefined): |
| return tree |
| if isinstance(tree, DFHighImpedance): |
| return tree |
| if isinstance(tree, DFTerminal): |
| return tree |
| if isinstance(tree, DFBranch): |
| condnode = self.optimizeHierarchy(tree.condnode) |
| truenode = self.optimizeHierarchy(tree.truenode) |
| falsenode = self.optimizeHierarchy(tree.falsenode) |
| if isinstance(condnode, DFEvalValue): |
| if self.isCondTrue(condnode): |
| return truenode |
| return falsenode |
| if truenode == falsenode: |
| return truenode |
| return DFBranch(condnode, truenode, falsenode) |
| if isinstance(tree, DFOperator): |
| nextnodes = [] |
| for n in tree.nextnodes: |
| nextnodes.append(self.optimizeHierarchy(n)) |
| ret = DFOperator(tuple(nextnodes), tree.operator) |
| ret = self.replaceOperator(ret) |
| ret = self.mergeIdenticalNodes(ret) |
| ret = self.mergeStaticNodes(ret) |
| ret = self.mergeLandLor(ret) |
| return ret |
| if isinstance(tree, DFPartselect): |
| msb = self.optimizeHierarchy(tree.msb) |
| lsb = self.optimizeHierarchy(tree.lsb) |
| var = self.optimizeHierarchy(tree.var) |
| if isinstance(var, DFConcat) and isinstance(msb, DFEvalValue) and isinstance(lsb, DFEvalValue): |
| return self.takePart(var.nextnodes, msb, lsb) |
| if isinstance(msb, DFEvalValue) and isinstance(lsb, DFEvalValue) and lsb.value == 0 and self.getWidth(var) == (msb.value + 1): |
| return var |
| return DFPartselect(var, msb, lsb) |
| if isinstance(tree, DFPointer): |
| ptr = self.optimizeHierarchy(tree.ptr) |
| var = self.optimizeHierarchy(tree.var) |
| if isinstance(var, DFConcat) and isinstance(ptr, DFEvalValue): |
| return self.takePoint(var.nextnodes, ptr) |
| return DFPointer(var, ptr) |
| if isinstance(tree, DFConcat): |
| nextnodes = [] |
| for n in tree.nextnodes: |
| if isinstance(n, DFConcat): |
| nextnodes.extend(n.nextnodes) |
| continue |
| nextnodes.append(self.optimizeHierarchy(n)) |
| return self.mergeConcat(DFConcat(tuple(nextnodes))) |
| if isinstance(tree, DFSyscall): |
| return DFSyscall(tree.syscall, tuple([self.optimizeHierarchy(n) for n in tree.nextnodes])) |
| |
| raise FormatError('Can not merge due to unrecognized type of tree') |
| |
| def takePoint(self, nextnodes, ptr): |
| return self.takePart(nextnodes, ptr, ptr) |
| |
| def takePart(self, nextnodes, msb, lsb): |
| widlist = [] |
| for n in reversed(nextnodes): # from LSB |
| widlist.append(self.getWidth(n)) |
| lsbcut = min(msb.value, lsb.value) |
| msbcut = max(msb.value, lsb.value) |
| cutwidth = msbcut - lsbcut + 1 |
| |
| widsum = 0 |
| widpos = 1 |
| widoffset = 0 |
| usednodes = [] |
| lsb = -1 |
| msb = -1 |
| lsboffset = -1 |
| msboffset = -1 |
| use = False |
| for w in widlist: # from LSB |
| if lsbcut >= widoffset and lsbcut < widoffset + w: |
| lsb = widoffset |
| lsboffset = lsbcut - lsb |
| use = True |
| if use: |
| widsum += w |
| usednodes.append(self.optimizeConstant(nextnodes[-widpos])) |
| if msbcut >= widoffset and msbcut < widoffset + w: |
| msb = widoffset + w - 1 |
| msboffset = msb - msbcut |
| break |
| widpos += 1 |
| widoffset += w |
| |
| usednodes.reverse() |
| |
| if len(usednodes) == 0: |
| return DFUndefined(cutwidth) |
| if msboffset < 0: |
| if lsboffset == 0: |
| return DFConcat((DFUndefined(cutwidth - widsum),) + tuple(usednodes)) |
| if len(usednodes) == 1: |
| return DFConcat((DFUndefined(cutwidth - widsum + lsboffset), DFPartselect(usednodes[0], DFEvalValue(widsum - 1), DFEvalValue(lsb + lsboffset)))) |
| return DFConcat((DFUndefined(cutwidth - widsum + lsboffset), DFPartselect(DFConcat(tuple(usednodes)), DFEvalValue(widsum - 1), DFEvalValue(lsb + lsboffset)))) |
| if lsboffset == 0 and msboffset == 0: |
| if len(usednodes) == 1: |
| return usednodes[0] |
| return DFConcat(tuple(usednodes)) |
| |
| if len(usednodes) == 1: |
| return DFPartselect(usednodes[0], DFEvalValue(msb - msboffset), DFEvalValue(lsb + lsboffset)) |
| |
| ret_usednodes = [] |
| usednodes_cnt = 0 |
| for node in reversed(usednodes): # from LSB |
| if usednodes_cnt == 0 and lsboffset > 0: |
| lsbval = lsboffset |
| msbval = widlist[usednodes_cnt] - 1 |
| ret_usednodes.append(self.optimizeConstant( |
| DFPartselect(node, DFEvalValue(msbval), DFEvalValue(lsbval)))) |
| elif usednodes_cnt == len(usednodes) - 1 and msboffset > 0: |
| lsbval = 0 |
| msbval = widlist[usednodes_cnt] - msboffset - 1 |
| ret_usednodes.append(self.optimizeConstant( |
| DFPartselect(node, DFEvalValue(msbval), DFEvalValue(lsbval)))) |
| else: |
| ret_usednodes.append(self.optimizeConstant(node)) |
| usednodes_cnt += 1 |
| ret_usednodes.reverse() |
| return DFPartselect(DFConcat(tuple(ret_usednodes)), DFEvalValue(msb - msboffset), DFEvalValue(lsb + lsboffset)) |
| |
| def _isPowerOf2(self, value): |
| if value <= 0: |
| return False |
| p = math.log(value, 2) |
| if p % 1.0 == 0: |
| return True |
| return False |
| |
| def replaceOperator(self, node): |
| if not isinstance(node, DFOperator): |
| return node |
| if (node.operator == 'Times' and |
| (isinstance(node.nextnodes[1], DFEvalValue) and |
| isinstance(node.nextnodes[1].value, int) and |
| self._isPowerOf2(node.nextnodes[1].value))): |
| return DFOperator((node.nextnodes[0], DFEvalValue(int(math.log(node.nextnodes[1].value, 2)))), 'Sll') |
| if (node.operator == 'Times' and |
| (isinstance(node.nextnodes[0], DFEvalValue) and |
| isinstance(node.nextnodes[0].value, int) and |
| self._isPowerOf2(node.nextnodes[0].value))): |
| return DFOperator((node.nextnodes[1], DFEvalValue(int(math.log(node.nextnodes[0].value, 2)))), 'Sll') |
| if (node.operator == 'Divide' |
| and (isinstance(node.nextnodes[1], DFEvalValue) and |
| isinstance(node.nextnodes[1].value, int) and |
| self._isPowerOf2(node.nextnodes[1].value))): |
| return DFOperator((node.nextnodes[0], DFEvalValue(int(math.log(node.nextnodes[1].value, 2)))), 'Sra') |
| return node |
| |
| def mergeConcat(self, concatnode): |
| t = concatnode |
| if isinstance(t, DFConcat): |
| t = self.mergeConcat_constant(t) |
| if isinstance(t, DFConcat): |
| t = self.mergeConcat_undefined(t) |
| if isinstance(t, DFConcat): |
| t = self.mergeConcat_partselect(t) |
| if isinstance(t, DFConcat): |
| t = self.mergeConcat_branch(t) |
| return t |
| |
| def mergeConcat_constant(self, concatnode): |
| ret_nodes = [] |
| constvallist = [] |
| constval = 0 |
| for n in concatnode.nextnodes: |
| if isinstance(n, DFEvalValue): |
| constvallist.append(n) |
| constval = self.evalConcat(tuple(constvallist)) |
| if len(constvallist) > 1: |
| ret_nodes.pop() |
| ret_nodes.append(constval) |
| else: |
| constvallist = [] |
| ret_nodes.append(n) |
| return DFConcat(tuple(ret_nodes)) |
| |
| def mergeConcat_undefined(self, concatnode): |
| ret_nodes = [] |
| width = 0 |
| for n in concatnode.nextnodes: |
| if isinstance(n, DFUndefined): |
| if width > 0: |
| ret_nodes.pop() |
| width += self.getWidth(n) |
| ret_nodes.append(DFUndefined(width)) |
| else: |
| width = 0 |
| ret_nodes.append(n) |
| return DFConcat(tuple(ret_nodes)) |
| |
| def mergeConcat_partselect(self, concatnode): |
| ret_nodes = [] |
| last_node = None |
| for n in concatnode.nextnodes: |
| if last_node is None: |
| pass |
| elif not isinstance(last_node, DFPartselect): |
| pass |
| elif not isinstance(n, DFPartselect): |
| pass |
| elif not isinstance(last_node.var, DFTerminal): |
| pass |
| elif not isinstance(n.var, DFTerminal): |
| pass |
| elif last_node.var.name != n.var.name: |
| pass |
| elif last_node.lsb.value == n.msb.value + 1: |
| ret_nodes.pop() |
| new_node = DFPartselect(last_node.var, last_node.msb, n.lsb) |
| if self.getWidth(last_node.var) == (last_node.msb.value - n.lsb.value + 1): |
| new_node = last_node.var |
| ret_nodes.append(new_node) |
| last_node = new_node |
| continue |
| ret_nodes.append(n) |
| last_node = n |
| if len(ret_nodes) == 1: |
| return ret_nodes[0] |
| return DFConcat(tuple(ret_nodes)) |
| |
| def mergeConcat_branch(self, concatnode): |
| nodelist = [] |
| last_node = None |
| for n in concatnode.nextnodes: |
| if last_node is None: |
| pass |
| elif not isinstance(last_node, DFBranch): |
| pass |
| elif not isinstance(n, DFBranch): |
| pass |
| elif last_node.condnode == n.condnode: |
| truenode_list = (last_node.truenode, n.truenode) |
| falsenode_list = (last_node.falsenode, n.falsenode) |
| new_truenode_list = [] |
| new_falsenode_list = [] |
| pos = 0 |
| for t in truenode_list: |
| if t is None: |
| new_truenode_list.append(DFUndefined(self.getWidth(falsenode_list[pos]))) |
| else: |
| new_truenode_list.append(t) |
| pos += 1 |
| |
| pos = 0 |
| for f in falsenode_list: |
| if f is None: |
| new_falsenode_list.append(DFUndefined(self.getWidth(truenode_list[pos]))) |
| else: |
| new_falsenode_list.append(f) |
| pos += 1 |
| |
| new_node = DFBranch(last_node.condnode, DFConcat( |
| tuple(new_truenode_list)), DFConcat(tuple(new_falsenode_list))) |
| last_node = new_node |
| nodelist.pop() |
| nodelist.append(new_node) |
| continue |
| nodelist.append(n) |
| last_node = n |
| if len(nodelist) == 1: |
| return nodelist[0] |
| return DFConcat(tuple(nodelist)) |
| |
| def mergeIdenticalNodes(self, node): |
| if not isinstance(node, DFOperator): |
| return node |
| if len(node.nextnodes) == 1: |
| return node |
| if not (node.nextnodes[0] == node.nextnodes[1]): |
| return node |
| if node.operator == 'And': |
| return node.nextnodes[0] |
| if node.operator == 'Or': |
| return node.nextnodes[0] |
| if node.operator == 'Land': |
| return node.nextnodes[0] |
| if node.operator == 'Lor': |
| return node.nextnodes[0] |
| if node.operator == 'LessThan': |
| return DFEvalValue(0, 1) # value, width |
| if node.operator == 'GreaterThan': |
| return DFEvalValue(0, 1) |
| if node.operator == 'LessEq': |
| return DFEvalValue(1, 1) |
| if node.operator == 'GreaterEq': |
| return DFEvalValue(1, 1) |
| if node.operator == 'Eq': |
| return DFEvalValue(1, 1) |
| if node.operator == 'NotEq': |
| return DFEvalValue(0, 1) |
| if node.operator == 'Eql': |
| return DFEvalValue(1, 1) |
| if node.operator == 'NotEql': |
| return DFEvalValue(0, 1) |
| return node |
| |
| def mergeStaticNodes(self, node): |
| if not isinstance(node, DFOperator): |
| return node |
| if len(node.nextnodes) == 1: |
| return node |
| |
| left = node.nextnodes[0] |
| right = node.nextnodes[1] |
| |
| if node.operator == 'And': |
| if isinstance(left, DFEvalValue) and left.value == 0: |
| return DFEvalValue(0, self.getWidth(node)) |
| if isinstance(right, DFEvalValue) and right.value == 0: |
| return DFEvalValue(0, self.getWidth(node)) |
| if isinstance(left, DFOperator) and left.operator == 'Unot'\ |
| and left.nextnodes[0] == right: |
| return DFEvalValue(0, self.getWidth(node)) |
| if isinstance(right, DFOperator) and right.operator == 'Unot'\ |
| and right.nextnodes[0] == left: |
| return DFEvalValue(0, self.getWidth(node)) |
| if isinstance(left, DFOperator) and left.operator == 'Ulnot'\ |
| and left.nextnodes[0] == right: |
| if self.getWidth(node) == 1: |
| return DFEvalValue(0, 1) |
| else: |
| return node |
| if isinstance(right, DFOperator) and right.operator == 'Ulnot'\ |
| and right.nextnodes[0] == left: |
| if self.getWidth(node) == 1: |
| return DFEvalValue(0, 1) |
| else: |
| return node |
| return node |
| if node.operator == 'Or': |
| if isinstance(left, DFEvalValue) and left.value == 0: |
| return right |
| if isinstance(right, DFEvalValue) and right.value == 0: |
| return left |
| if isinstance(left, DFOperator) and left.operator == 'Unot'\ |
| and left.nextnodes[0] == right: |
| return DFEvalValue(self._evalOperator('Unot', [0, ], self.getWidth(node)), self.getWidth(node)) |
| if isinstance(right, DFOperator) and right.operator == 'Unot'\ |
| and right.nextnodes[0] == left: |
| return DFEvalValue(self._evalOperator('Unot', [0, ], self.getWidth(node)), self.getWidth(node)) |
| if isinstance(left, DFOperator) and left.operator == 'Ulnot'\ |
| and left.nextnodes[0] == right: |
| if self.getWidth(node) == 1: |
| return DFEvalValue(1, 1) |
| else: |
| return node |
| if isinstance(right, DFOperator) and right.operator == 'Ulnot'\ |
| and right.nextnodes[0] == left: |
| if self.getWidth(node) == 1: |
| return DFEvalValue(1, 1) |
| else: |
| return node |
| return node |
| if node.operator == 'Land': |
| if isinstance(left, DFEvalValue) and left.value == 0: |
| return DFEvalValue(0, 1) |
| if isinstance(right, DFEvalValue) and right.value == 0: |
| return DFEvalValue(0, 1) |
| if isinstance(left, DFEvalValue) and left.value > 0: |
| return right |
| if isinstance(right, DFEvalValue) and right.value > 0: |
| return left |
| if isinstance(left, DFOperator) and left.operator == 'Unot'\ |
| and left.nextnodes[0] == right: |
| if self.getWidth(node) == 1: |
| return DFEvalValue(0, 1) |
| else: |
| return node |
| if isinstance(right, DFOperator) and right.operator == 'Unot'\ |
| and right.nextnodes[0] == left: |
| if self.getWidth(node) == 1: |
| return DFEvalValue(0, 1) |
| else: |
| return node |
| if isinstance(left, DFOperator) and left.operator == 'Ulnot'\ |
| and left.nextnodes[0] == right: |
| return DFEvalValue(0, 1) |
| if isinstance(right, DFOperator) and right.operator == 'Ulnot'\ |
| and right.nextnodes[0] == left: |
| return DFEvalValue(0, 1) |
| if isinstance(left, DFOperator) and left.operator == 'Eq'\ |
| and isinstance(right, DFOperator) and right.operator == 'Eq'\ |
| and left.nextnodes[0] == right.nextnodes[0]\ |
| and isinstance(left.nextnodes[1], DFEvalValue)\ |
| and isinstance(right.nextnodes[1], DFEvalValue)\ |
| and left.nextnodes[1].value != right.nextnodes[1].value: |
| return DFEvalValue(0, 1) |
| if isinstance(left, DFOperator) and left.operator == 'Eq'\ |
| and isinstance(right, DFOperator) and right.operator == 'Eq'\ |
| and left.nextnodes[1] == right.nextnodes[1]\ |
| and isinstance(left.nextnodes[0], DFEvalValue)\ |
| and isinstance(right.nextnodes[0], DFEvalValue)\ |
| and left.nextnodes[0].value != right.nextnodes[0].value: |
| return DFEvalValue(0, 1) |
| if isinstance(left, DFOperator) and left.operator == 'Eq'\ |
| and isinstance(right, DFOperator) and right.operator == 'Eq'\ |
| and left.nextnodes[0] == right.nextnodes[1]\ |
| and isinstance(left.nextnodes[1], DFEvalValue)\ |
| and isinstance(right.nextnodes[0], DFEvalValue)\ |
| and left.nextnodes[1].value != right.nextnodes[0].value: |
| return DFEvalValue(0, 1) |
| if isinstance(left, DFOperator) and left.operator == 'Eq'\ |
| and isinstance(right, DFOperator) and right.operator == 'Eq'\ |
| and left.nextnodes[1] == right.nextnodes[0]\ |
| and isinstance(left.nextnodes[0], DFEvalValue)\ |
| and isinstance(right.nextnodes[1], DFEvalValue)\ |
| and left.nextnodes[0].value != right.nextnodes[1].value: |
| return DFEvalValue(0, 1) |
| if isinstance(left, DFOperator) and left.operator == 'Ulnot'\ |
| and isinstance(left.nextnodes[0], DFOperator) and left.nextnodes[0].operator == 'Eq'\ |
| and isinstance(right, DFOperator) and right.operator == 'Eq'\ |
| and left.nextnodes[0].nextnodes[0] == right.nextnodes[0]\ |
| and isinstance(left.nextnodes[0].nextnodes[1], DFEvalValue)\ |
| and isinstance(right.nextnodes[1], DFEvalValue)\ |
| and left.nextnodes[0].nextnodes[1].value != right.nextnodes[1].value: |
| return right |
| if isinstance(left, DFOperator) and left.operator == 'Ulnot'\ |
| and isinstance(left.nextnodes[0], DFOperator) and left.nextnodes[0].operator == 'Eq'\ |
| and isinstance(right, DFOperator) and right.operator == 'Eq'\ |
| and left.nextnodes[0].nextnodes[1] == right.nextnodes[0]\ |
| and isinstance(left.nextnodes[0].nextnodes[0], DFEvalValue)\ |
| and isinstance(right.nextnodes[1], DFEvalValue)\ |
| and left.nextnodes[0].nextnodes[0].value != right.nextnodes[1].value: |
| return right |
| if isinstance(right, DFOperator) and right.operator == 'Ulnot'\ |
| and isinstance(right.nextnodes[0], DFOperator) and right.nextnodes[0].operator == 'Eq'\ |
| and isinstance(left, DFOperator) and left.operator == 'Eq'\ |
| and right.nextnodes[0].nextnodes[0] == left.nextnodes[0]\ |
| and isinstance(right.nextnodes[0].nextnodes[1], DFEvalValue)\ |
| and isinstance(left.nextnodes[1], DFEvalValue)\ |
| and right.nextnodes[0].nextnodes[1].value != left.nextnodes[1].value: |
| return left |
| if isinstance(right, DFOperator) and right.operator == 'Ulnot'\ |
| and isinstance(right.nextnodes[0], DFOperator) and right.nextnodes[0].operator == 'Eq'\ |
| and isinstance(left, DFOperator) and left.operator == 'Eq'\ |
| and right.nextnodes[0].nextnodes[1] == left.nextnodes[0]\ |
| and isinstance(right.nextnodes[0].nextnodes[0], DFEvalValue)\ |
| and isinstance(left.nextnodes[1], DFEvalValue)\ |
| and right.nextnodes[0].nextnodes[0].value != left.nextnodes[1].value: |
| return left |
| return node |
| if node.operator == 'Lor': |
| if isinstance(left, DFEvalValue) and left.value == 0: |
| return right |
| if isinstance(right, DFEvalValue) and right.value == 0: |
| return left |
| if isinstance(left, DFEvalValue) and left.value > 0: |
| return DFEvalValue(1, 1) |
| if isinstance(right, DFEvalValue) and right.value > 0: |
| return DFEvalValue(1, 1) |
| if isinstance(left, DFOperator) and left.operator == 'Unot'\ |
| and left.nextnodes[0] == right: |
| return DFEvalValue(1, 1) |
| if isinstance(right, DFOperator) and right.operator == 'Unot'\ |
| and right.nextnodes[0] == left: |
| return DFEvalValue(1, 1) |
| if isinstance(left, DFOperator) and left.operator == 'Ulnot'\ |
| and left.nextnodes[0] == right: |
| return DFEvalValue(1, 1) |
| if isinstance(right, DFOperator) and right.operator == 'Ulnot'\ |
| and right.nextnodes[0] == left: |
| return DFEvalValue(1, 1) |
| if isinstance(left, DFOperator) and left.operator == 'Land'\ |
| and isinstance(right, DFOperator) and right.operator == 'Land'\ |
| and isinstance(left.nextnodes[0], DFOperator) and left.nextnodes[0].operator == 'Ulnot'\ |
| and left.nextnodes[0].nextnodes[0] == right.nextnodes[0]\ |
| and left.nextnodes[1] == right.nextnodes[1]: |
| return left.nextnodes[1] |
| if isinstance(left, DFOperator) and left.operator == 'Land'\ |
| and isinstance(right, DFOperator) and right.operator == 'Land'\ |
| and isinstance(left.nextnodes[1], DFOperator) and left.nextnodes[1].operator == 'Ulnot'\ |
| and left.nextnodes[1].nextnodes[0] == right.nextnodes[0]\ |
| and left.nextnodes[0] == right.nextnodes[1]: |
| return left.nextnodes[0] |
| if isinstance(right, DFOperator) and right.operator == 'Land'\ |
| and isinstance(left, DFOperator) and left.operator == 'Land'\ |
| and isinstance(right.nextnodes[0], DFOperator) and right.nextnodes[0].operator == 'Ulnot'\ |
| and right.nextnodes[0].nextnodes[0] == left.nextnodes[0]\ |
| and right.nextnodes[1] == left.nextnodes[1]: |
| return right.nextnodes[1] |
| if isinstance(right, DFOperator) and right.operator == 'Land'\ |
| and isinstance(left, DFOperator) and left.operator == 'Land'\ |
| and isinstance(right.nextnodes[1], DFOperator) and right.nextnodes[1].operator == 'Ulnot'\ |
| and right.nextnodes[1].nextnodes[0] == left.nextnodes[0]\ |
| and right.nextnodes[0] == left.nextnodes[1]: |
| return right.nextnodes[0] |
| return node |
| return node |
| |
| def mergeLandLor(self, node): |
| return self.mergeLor(node) |
| |
| def mergeLand(self, node): |
| ret = self._mergeLand(node) |
| if isinstance(ret, tuple): |
| retnode = None |
| for r in ret: |
| if retnode is None: |
| retnode = r |
| else: |
| retnode = DFOperator((retnode, r), 'Land') |
| return retnode |
| return ret |
| |
| def _mergeLand(self, node): |
| if not isinstance(node, DFOperator): |
| return node |
| if node.operator != 'Land': |
| return node |
| left = self._mergeLand(node.nextnodes[0]) |
| right = self._mergeLand(node.nextnodes[1]) |
| landlist = [] |
| if isinstance(left, tuple): |
| landlist.extend(left) |
| else: |
| landlist.append(left) |
| if isinstance(right, tuple): |
| landlist.extend(right) |
| else: |
| landlist.append(right) |
| ret_list = [] |
| ret_exist_list = [] |
| for l in landlist: |
| s = l |
| not_s = l.nextnodes[0] if isinstance( |
| l, DFOperator) and l.operator == 'Ulnot' else DFOperator((l,), 'Ulnot') |
| if not_s in ret_exist_list: |
| return (DFEvalValue(0, 1),) |
| if not (s in ret_exist_list): |
| ret_list.append(l) |
| ret_exist_list.append(s) |
| return tuple(sorted(ret_list, key=lambda x: x.tocode(), reverse=True)) |
| |
| def mergeLor(self, node): |
| ret = self._mergeLor(node) |
| if isinstance(ret, tuple): |
| retnode = None |
| for r in ret: |
| if retnode is None: |
| retnode = r |
| else: |
| retnode = DFOperator((retnode, r), 'Lor') |
| return retnode |
| return ret |
| |
| def _mergeLor(self, node): |
| if not isinstance(node, DFOperator): |
| return node |
| if node.operator == 'Land': |
| return self.mergeLand(node) |
| if node.operator != 'Lor': |
| return node |
| left = self._mergeLor(node.nextnodes[0]) |
| right = self._mergeLor(node.nextnodes[1]) |
| landlist = [] |
| if isinstance(left, tuple): |
| landlist.extend(left) |
| else: |
| landlist.append(left) |
| if isinstance(right, tuple): |
| landlist.extend(right) |
| else: |
| landlist.append(right) |
| ret_list = [] |
| ret_exist_list = [] |
| for l in landlist: |
| s = l |
| not_s = l.nextnodes[0] if isinstance( |
| l, DFOperator) and l.operator == 'Ulnot' else DFOperator((l,), 'Ulnot') |
| if not_s in ret_exist_list: |
| return (DFEvalValue(1, 1),) |
| if not (s in ret_exist_list): |
| ret_list.append(l) |
| ret_exist_list.append(s) |
| return tuple(sorted(ret_list, key=lambda x: x.tocode(), reverse=True)) |
| |
| # ------------------------------------------------------------------------------- |
| |
| |
| class VerilogDataflowOptimizer(VerilogOptimizer): |
| def __init__(self, terms, binddict): |
| VerilogOptimizer.__init__(self, terms, {}) |
| self.binddict = binddict |
| self.resolved_terms = {} |
| self.resolved_binddict = {} |
| |
| def getResolvedTerms(self): |
| return self.resolved_terms |
| |
| def getResolvedBinddict(self): |
| return self.resolved_binddict |
| |
| def getConstlist(self): |
| return self.constlist |
| |
| def getTerm(self, name): |
| return self.terms[name] |
| |
| def resolveConstant(self): |
| # 2-pass |
| for bk, bv in sorted(self.binddict.items(), key=lambda x: len(x[0])): |
| termtype = self.getTerm(bk).termtype |
| if signaltype.isParameter(termtype) or signaltype.isLocalparam(termtype): |
| rslt = self.optimizeConstant(bv[0].tree) |
| if isinstance(rslt, DFEvalValue): |
| self.constlist[bk] = rslt |
| |
| for bk, bv in sorted(self.binddict.items(), key=lambda x: len(x[0])): |
| termtype = self.getTerm(bk).termtype |
| if signaltype.isParameter(termtype) or signaltype.isLocalparam(termtype): |
| rslt = self.optimizeConstant(bv[0].tree) |
| if isinstance(rslt, DFEvalValue): |
| self.constlist[bk] = rslt |
| |
| self.resolved_binddict = copy.deepcopy(self.binddict) |
| for bk, bv in sorted(self.binddict.items(), key=lambda x: len(x[0])): |
| new_bindlist = [] |
| for bind in bv: |
| new_bind = copy.deepcopy(bind) |
| if bk in self.constlist: |
| new_bind.tree = self.constlist[bk] |
| new_bindlist.append(new_bind) |
| self.resolved_binddict[bk] = new_bindlist |
| |
| self.resolved_terms = copy.deepcopy(self.terms) |
| for tk, tv in sorted(self.resolved_terms.items(), key=lambda x: len(x[0])): |
| if tv.msb is not None: |
| rslt = self.optimizeConstant(tv.msb) |
| self.resolved_terms[tk].msb = rslt |
| if tv.lsb is not None: |
| rslt = self.optimizeConstant(tv.lsb) |
| self.resolved_terms[tk].lsb = rslt |
| if tv.dims is not None: |
| dims = [] |
| for l, r in tv.dims: |
| l = self.optimizeConstant(l) |
| r = self.optimizeConstant(r) |
| dims.append((l, r)) |
| self.resolved_terms[tk].dims = tuple(dims) |