Ejemplo n.º 1
0
    def stmt_rep(self, node, l):
        node.location = l

        # Calculate total # processes (m) and the next power of two of this (n)
        node.m = reduce(lambda x, y: x * y.count_value, node.indices, 1)

        # Determine f and then set l = g(d_1, d_2, ..., d_k, f)
        k = indices_expr(node.indices)

        # Add to base (if non-zero) and take modulo
        if not (isinstance(l, ast.ElemNumber) and l.value == 0):
            k = ast.ExprBinop('+', l, k)

        self.stmt(node.stmt, k)
Ejemplo n.º 2
0
  def stmt_rep(self, node, l):
    node.location = l
    
    # Calculate total # processes (m) and the next power of two of this (n)
    node.m = reduce(lambda x, y: x*y.count_value, node.indices, 1)
 
    # Determine f and then set l = g(d_1, d_2, ..., d_k, f)
    k = indices_expr(node.indices)
    
    # Add to base (if non-zero) and take modulo
    if not (isinstance(l, ast.ElemNumber) and l.value==0):
      k = ast.ExprBinop('+', l, k)

    self.stmt(node.stmt, k)
Ejemplo n.º 3
0
  def gen_array_conn(self, tab, scope, chan):
    """
    Generate a conncection for an array channel declaration. We must analyse
    the subscript by generating nested conditional statements. 'chan' is a
    ChanElemSet with multiple elements.
    """
    
    def target_loc(chan, elem, scope):
      master = tab.lookup_is_master(chan, elem, scope)
      return (tab.lookup_slave_location(chan.name, elem.index, scope) if master else
          tab.lookup_master_location(chan.name, elem.index, scope))

    def create_single_conn(s, chan, scope, i_elem, elem):
      debug(self.debug, 'New connection for index {}'.format(elem.index))
      master = tab.lookup_is_master(chan, elem, scope)
      if master:
        location = ast.ExprSingle(ast.ElemNumber(
            tab.lookup_slave_location(chan.name, elem.index, scope)))
      else:
        location = ast.ExprSingle(ast.ElemNumber(
            tab.lookup_master_location(chan.name, elem.index, scope)))
      chanend = ast.ElemId(chan.chanend)
      chanend.symbol = Symbol(chan.chanend, self.chanend_type(chan), 
          None, scope=T_SCOPE_PROC)
      connid = tab.lookup_connid(chan.name, elem.index, scope)
      chanid = ast.ExprSingle(ast.ElemNumber(connid))
      cond = ast.ExprBinop('=', i_elem,
          ast.ExprSingle(ast.ElemNumber(elem.indices_value)))
      conn = ast.StmtConnect(chanend, chanid, location, 
          self.connect_type(chan, master))
      return ast.StmtIf(cond, conn, s) if s!=None else conn

    def create_range_conn(s, chan, i_elem, group):
      diff2 = group[0]
      elem0 = group[1][0][0] 
      offset = target_loc(chan, elem0, scope)

      # Form the location expression
      if elem0.indices_value > 0:
        location = ast.ElemGroup(ast.ExprBinop('-', i_elem,
          ast.ExprSingle(ast.ElemNumber(elem0.indices_value))))
      else:
        location = i_elem
      location = ast.ExprBinop('*', ast.ElemNumber(diff2+1),
          ast.ExprSingle(location))
      location = ast.ExprBinop('+', ast.ElemGroup(location), 
          ast.ExprSingle(ast.ElemNumber(offset)))

      chanend = ast.ElemId(chan.chanend)
      chanend.symbol = Symbol(chan.chanend, self.chanend_type(chan), 
          None, scope=T_SCOPE_PROC)
      connid = tab.lookup_connid(chan.name, elem0.index, scope)
      chanid = ast.ExprSingle(ast.ElemNumber(connid))
      begin = elem0.indices_value
      end = group[1][-1][0].indices_value
      cond = ast.ExprBinop('>=', i_elem, 
          ast.ExprSingle(ast.ElemNumber(min(begin, end))))
      master = tab.lookup_is_master(chan, elem0, scope)
      conn = ast.StmtConnect(chanend, chanid, location,
          self.connect_type(chan, master))
      return ast.StmtIf(cond, conn, s) if s else conn

    def create_tree_conn(tab, scope, chan, phase, group_size, base_indices_value, 
        loc_base, loc_diff, connid_min, connid_offset, connid_diff, i_elem):
      location = ast.ExprBinop('-', i_elem,
          ast.ExprSingle(ast.ElemNumber(base_indices_value)))
      location = ast.ExprBinop('/', ast.ElemGroup(location),
          ast.ExprSingle(ast.ElemNumber(group_size)))
      location = ast.ExprBinop('*', ast.ElemNumber(loc_diff), 
          ast.ExprSingle(ast.ElemGroup(location)))
      location = ast.ExprBinop('+', ast.ElemNumber(loc_base),
          ast.ExprSingle(ast.ElemGroup(location)))
      chanend = ast.ElemId(chan.chanend)
      chanend.symbol = Symbol(chan.chanend, self.chanend_type(chan), 
          None, scope=T_SCOPE_PROC)
      elem0 = chan.elems[phase]
      #connid = ast.ExprBinop('+', i_elem,
      #    ast.ExprSingle(ast.ElemNumber(connid_offset)))
      connid = ast.ExprBinop('-', i_elem,
          ast.ExprSingle(ast.ElemNumber(phase)))
      connid = ast.ExprBinop('rem', ast.ElemGroup(connid),
          ast.ExprSingle(ast.ElemNumber(group_size)))
      connid = ast.ExprBinop('*', ast.ElemGroup(connid),
          ast.ExprSingle(ast.ElemNumber(connid_diff)))
      connid = ast.ExprBinop('+', ast.ElemGroup(connid),
          ast.ExprSingle(ast.ElemNumber(connid_min)))
      master = tab.lookup_is_master(chan, elem0, scope)
      return ast.StmtConnect(chanend, connid, location,
          self.connect_type(chan, master))

    def conn_diff_groups(chan, s, i_elem, d=DEBUG_COMPRESSION):
      """
      Compress connecitons based on the difference between differences of
      indices value and destination.
      """
      # Build a list of channel elements and index-dest differences
      diffs = []
      for x in chan.elems:
        diff = target_loc(chan, x, scope) - x.indices_value
        diffs.append((x, diff))

      debug(d, 'Differences for chan {}:'.format(chan.name))
      for (elem, diff) in diffs:
        connid = tab.lookup_connid(chan.name, elem.index, scope)
        debug(d, '  {:>3}: [{}]:{} - {}'.format(elem.indices_value, elem.index,
          connid, diff))

      # Group consecutive elements with a constant second difference
      groups = []
      newgroup = True
      for ((elemA, diffA), (elemB, diffB)) in zip(diffs[:-1], diffs[1:]):
        diff2 = diffB - diffA
        connid = tab.lookup_connid(chan.name, elemB.index, scope)
        master = tab.lookup_is_master(chan, elemB, scope)
        if newgroup:
          groups.append((diff2, [(elemA, diffA)]))
          groupdiff2 = diff2
          groupconnid = tab.lookup_connid(chan.name, elemA.index, scope)
          groupmaster = tab.lookup_is_master(chan, elemA, scope)
          newgroup = False
        if (groupdiff2 == diff2 
            and groupconnid == connid
            and groupmaster == master):
          groups[-1][1].append((elemB, diffB))
        else:
          newgroup = True
      if newgroup:
        groups.append((None, [diffs[-1]]))
        
      debug(d, 'Groups:')
      for x in groups:
        diff2 = x[0]
        elem0 = x[1][0][0]
        offset = target_loc(chan, elem0, scope)
        debug(d, '  diff2:  {}'.format(diff2))
        debug(d, '  offset: {}'.format(offset))
        debug(d, '  base:   {}'.format(elem0.indices_value))
        if len(x[1]) > 1:
          for (i, (elem, diff)) in enumerate(x[1]):
            loc = target_loc(chan, elem, scope)
            computed = ((diff2+1) * (elem.indices_value-elem0.indices_value)) + offset
            assert computed == loc
            debug(d, '    {:>3}: [{:>3}]->{:>3}, diff: {:>3}, computed: {}'.format(
                elem.indices_value, elem.index, loc, diff, computed))
        else:
          debug(d, '    {:>3}: [{:>3}]->{:>3}'.format(
              elem0.indices_value, elem0.index, offset))

      # If compression was inneffective then abort
      if len(groups) == len(chan.elems):
        debug(d, 'Aborting group diff compression.')
        return None
      
      debug(d, 'Diff compression successful.')

      # Construct connection syntax
      s = None
      for x in groups:
        elem0 = x[1][0][0]
        if len(x[1]) == 1:
          s = create_single_conn(s, chan, scope, i_elem, elem0)
        else:
          s = create_range_conn(s, chan, i_elem, x)
      return s

    def conn_tree_groups(chan, s, i_elem, d=DEBUG_COMPRESSION):
      """
      Compress connections based on monotonically increasing or decreasing
      sets with the same target destination. Within a set, connection IDs can
      be monotonically increasing or decreasing.
      """
      locs = []
      debug(d, 'Locations:')
      for x in chan.elems:
        loc = target_loc(chan, x, scope)
        locs.append((x, loc))
        debug(d, '  {:>4} : {}[{}] -> {}'.format(x.indices_value, chan.name, x.index, loc))
       
      # Separate the first odd element if there is one
      phase = 0
      if locs[0][1] != locs[1][1]:
        odd_elem = locs[0][0]
        locs = locs[1:]
        phase = 1

      # Count the group size
      group_size = 1
      while group_size < len(locs) and locs[group_size-1][1] == locs[group_size][1]:
        group_size += 1

      # Only consider connections with more than one group 
      if len(locs) <= group_size+1:
        debug(d, 'Aborting tree compression.')
        return None

      # Set parameters
      loc_diff = locs[group_size][1]-locs[group_size-1][1]
      loc_base = locs[0][1]
      base_indices_value = locs[0][0].indices_value
      connidA = tab.lookup_connid(chan.name, locs[0][0].index, scope)
      connidB = tab.lookup_connid(chan.name, locs[1][0].index, scope)
      connid_min = min(connidA, connidB)
      connid_diff = max(connidA, connidB) - connid_min
      connid_offset = (phase + (1 if connidA > connidB else 0)) % 2
      
      # Print some debug info
      debug(d, 'Attempting tree compression.')
      debug(d, '  Group size:    {}'.format(group_size))
      debug(d, '  Location base: {}'.format(loc_base))
      debug(d, '  Location diff: {}'.format(loc_diff))
      debug(d, '  Base ival:     {}'.format(base_indices_value))
      debug(d, '  ConnID base:   {}'.format(connidA))
      debug(d, '  ConnID diff:   {}'.format(connid_diff))

      # Check each group contains the same location
      debug(d, 'Checking groups...')
      i = 0
      while i*group_size < len(locs):
        debug(d, '  Group {}'.format(i))
        for j in range(1, group_size):
          if locs[i*group_size][1] != locs[(i*group_size)+j][1]:
            debug(d, 'Aborting tree compression.')
            return None
        i += 1
      
      # Check each step between groups has same location and connection diffs
      debug(d, 'Checking diffs...')
      for (i, (x, y)) in enumerate(
          zip(locs[1::group_size], locs[group_size::group_size])):
        debug(d, '  Group {} and {}: {} and {}'.format(i, i+1, y[1], x[1]))
        connidX = tab.lookup_connid(chan.name, x[0].index, scope)
        connidY = tab.lookup_connid(chan.name, y[0].index, scope)
        connid_diff_ = connidX - connidY
        if y[1] - x[1] != loc_diff or connid_diff != connid_diff_:
          debug(d, 'Aborting tree compression.')
          return None

      # Check matching computed location
      debug(d, 'Checking computed...')
      debug(d, 'connid_min = {}'.format(connid_min))
      debug(d, 'connid_off = {}'.format(connid_offset))
      if phase == 1:
        connid = tab.lookup_connid(chan.name, odd_elem.index, scope)
        debug(d, '  {}: connid={}'.format(odd_elem.indices_value, connid))
      for (elem, loc) in locs:
        computed_loc = loc_base + (loc_diff * (math.floor(
            ((elem.indices_value - base_indices_value))/group_size)))
        connid = tab.lookup_connid(chan.name, elem.index, scope)
        #computed_connid = (connid_min + 
        #    ((elem.indices_value + connid_offset) % group_size) * connid_diff)
        computed_connid = (connid_min + 
            ((elem.indices_value - phase) % group_size) * connid_diff)
        debug(d, '  {}: connid={}, loc={} computed({}, {})'
            .format(elem.indices_value, connid, loc, 
              computed_connid, computed_loc))
        assert computed_loc == loc
        assert computed_connid == connid
      
      debug(d, 'Tree compression successful.')

      # Construct connection syntax
      if phase == 0:
        return create_tree_conn(tab, scope, chan, phase, group_size, 
            base_indices_value, loc_base, loc_diff, 
            connid_min, connid_offset, connid_diff, i_elem)
      else:
        s = create_tree_conn(tab, scope, chan, phase, group_size,
            base_indices_value, loc_base, loc_diff, 
            connid_min, connid_offset, connid_diff, i_elem)
        return create_single_conn(s, chan, scope, i_elem, odd_elem)

    def conn_singles(chan, s, i_elem, d=DEBUG_COMPRESSION):
      """
      Create (uncompressed) connections for each case.
      """
      debug(d, 'Creating uncompressed connection range.')
      for x in chan.elems:
        s = create_single_conn(s, chan, scope, i_elem, x)
        debug(d, '  {}: {}[{}]'.format(x.indices_value, chan.name, x.index))
      return s

    # Sort the channel elements into increasing order of indices
    chan.elems = sorted(chan.elems, key=lambda x: x.indices_value)

    # Compress conditional connections and return the AST construction
    i_expr = indices_expr(chan.indices)
    i_elem = ast.ElemId('_i')
    i_elem.symbol = Symbol(i_elem.name, T_VAR_SINGLE, scope=T_SCOPE_BLOCK)
    s = None
    if COMPRESS:
      s = conn_tree_groups(chan, s, i_elem)
      s = conn_diff_groups(chan, s, i_elem) if s==None else s 
    s = conn_singles(chan, s, i_elem) if s==None else s
    s = [ast.StmtAss(i_elem, i_expr), s]
    s = ast.StmtSeq([ast.VarDecl(i_elem.name, T_VAR_SINGLE, None)], s)
    return s
Ejemplo n.º 4
0
    def gen_array_conn(self, tab, scope, chan):
        """
    Generate a conncection for an array channel declaration. We must analyse
    the subscript by generating nested conditional statements. 'chan' is a
    ChanElemSet with multiple elements.
    """
        def target_loc(chan, elem, scope):
            master = tab.lookup_is_master(chan, elem, scope)
            return (tab.lookup_slave_location(chan.name, elem.index, scope)
                    if master else tab.lookup_master_location(
                        chan.name, elem.index, scope))

        def create_single_conn(s, chan, scope, i_elem, elem):
            debug(self.debug, 'New connection for index {}'.format(elem.index))
            master = tab.lookup_is_master(chan, elem, scope)
            if master:
                location = ast.ExprSingle(
                    ast.ElemNumber(
                        tab.lookup_slave_location(chan.name, elem.index,
                                                  scope)))
            else:
                location = ast.ExprSingle(
                    ast.ElemNumber(
                        tab.lookup_master_location(chan.name, elem.index,
                                                   scope)))
            chanend = ast.ElemId(chan.chanend)
            chanend.symbol = Symbol(chan.chanend,
                                    self.chanend_type(chan),
                                    None,
                                    scope=T_SCOPE_PROC)
            connid = tab.lookup_connid(chan.name, elem.index, scope)
            chanid = ast.ExprSingle(ast.ElemNumber(connid))
            cond = ast.ExprBinop(
                '=', i_elem,
                ast.ExprSingle(ast.ElemNumber(elem.indices_value)))
            conn = ast.StmtConnect(chanend, chanid, location,
                                   self.connect_type(chan, master))
            return ast.StmtIf(cond, conn, s) if s != None else conn

        def create_range_conn(s, chan, i_elem, group):
            diff2 = group[0]
            elem0 = group[1][0][0]
            offset = target_loc(chan, elem0, scope)

            # Form the location expression
            if elem0.indices_value > 0:
                location = ast.ElemGroup(
                    ast.ExprBinop(
                        '-', i_elem,
                        ast.ExprSingle(ast.ElemNumber(elem0.indices_value))))
            else:
                location = i_elem
            location = ast.ExprBinop('*', ast.ElemNumber(diff2 + 1),
                                     ast.ExprSingle(location))
            location = ast.ExprBinop('+', ast.ElemGroup(location),
                                     ast.ExprSingle(ast.ElemNumber(offset)))

            chanend = ast.ElemId(chan.chanend)
            chanend.symbol = Symbol(chan.chanend,
                                    self.chanend_type(chan),
                                    None,
                                    scope=T_SCOPE_PROC)
            connid = tab.lookup_connid(chan.name, elem0.index, scope)
            chanid = ast.ExprSingle(ast.ElemNumber(connid))
            begin = elem0.indices_value
            end = group[1][-1][0].indices_value
            cond = ast.ExprBinop(
                '>=', i_elem, ast.ExprSingle(ast.ElemNumber(min(begin, end))))
            master = tab.lookup_is_master(chan, elem0, scope)
            conn = ast.StmtConnect(chanend, chanid, location,
                                   self.connect_type(chan, master))
            return ast.StmtIf(cond, conn, s) if s else conn

        def create_tree_conn(tab, scope, chan, phase, group_size,
                             base_indices_value, loc_base, loc_diff,
                             connid_min, connid_offset, connid_diff, i_elem):
            location = ast.ExprBinop(
                '-', i_elem,
                ast.ExprSingle(ast.ElemNumber(base_indices_value)))
            location = ast.ExprBinop(
                '/', ast.ElemGroup(location),
                ast.ExprSingle(ast.ElemNumber(group_size)))
            location = ast.ExprBinop('*', ast.ElemNumber(loc_diff),
                                     ast.ExprSingle(ast.ElemGroup(location)))
            location = ast.ExprBinop('+', ast.ElemNumber(loc_base),
                                     ast.ExprSingle(ast.ElemGroup(location)))
            chanend = ast.ElemId(chan.chanend)
            chanend.symbol = Symbol(chan.chanend,
                                    self.chanend_type(chan),
                                    None,
                                    scope=T_SCOPE_PROC)
            elem0 = chan.elems[phase]
            #connid = ast.ExprBinop('+', i_elem,
            #    ast.ExprSingle(ast.ElemNumber(connid_offset)))
            connid = ast.ExprBinop('-', i_elem,
                                   ast.ExprSingle(ast.ElemNumber(phase)))
            connid = ast.ExprBinop('rem', ast.ElemGroup(connid),
                                   ast.ExprSingle(ast.ElemNumber(group_size)))
            connid = ast.ExprBinop('*', ast.ElemGroup(connid),
                                   ast.ExprSingle(ast.ElemNumber(connid_diff)))
            connid = ast.ExprBinop('+', ast.ElemGroup(connid),
                                   ast.ExprSingle(ast.ElemNumber(connid_min)))
            master = tab.lookup_is_master(chan, elem0, scope)
            return ast.StmtConnect(chanend, connid, location,
                                   self.connect_type(chan, master))

        def conn_diff_groups(chan, s, i_elem, d=DEBUG_COMPRESSION):
            """
      Compress connecitons based on the difference between differences of
      indices value and destination.
      """
            # Build a list of channel elements and index-dest differences
            diffs = []
            for x in chan.elems:
                diff = target_loc(chan, x, scope) - x.indices_value
                diffs.append((x, diff))

            debug(d, 'Differences for chan {}:'.format(chan.name))
            for (elem, diff) in diffs:
                connid = tab.lookup_connid(chan.name, elem.index, scope)
                debug(
                    d,
                    '  {:>3}: [{}]:{} - {}'.format(elem.indices_value,
                                                   elem.index, connid, diff))

            # Group consecutive elements with a constant second difference
            groups = []
            newgroup = True
            for ((elemA, diffA), (elemB, diffB)) in zip(diffs[:-1], diffs[1:]):
                diff2 = diffB - diffA
                connid = tab.lookup_connid(chan.name, elemB.index, scope)
                master = tab.lookup_is_master(chan, elemB, scope)
                if newgroup:
                    groups.append((diff2, [(elemA, diffA)]))
                    groupdiff2 = diff2
                    groupconnid = tab.lookup_connid(chan.name, elemA.index,
                                                    scope)
                    groupmaster = tab.lookup_is_master(chan, elemA, scope)
                    newgroup = False
                if (groupdiff2 == diff2 and groupconnid == connid
                        and groupmaster == master):
                    groups[-1][1].append((elemB, diffB))
                else:
                    newgroup = True
            if newgroup:
                groups.append((None, [diffs[-1]]))

            debug(d, 'Groups:')
            for x in groups:
                diff2 = x[0]
                elem0 = x[1][0][0]
                offset = target_loc(chan, elem0, scope)
                debug(d, '  diff2:  {}'.format(diff2))
                debug(d, '  offset: {}'.format(offset))
                debug(d, '  base:   {}'.format(elem0.indices_value))
                if len(x[1]) > 1:
                    for (i, (elem, diff)) in enumerate(x[1]):
                        loc = target_loc(chan, elem, scope)
                        computed = ((diff2 + 1) *
                                    (elem.indices_value -
                                     elem0.indices_value)) + offset
                        assert computed == loc
                        debug(
                            d,
                            '    {:>3}: [{:>3}]->{:>3}, diff: {:>3}, computed: {}'
                            .format(elem.indices_value, elem.index, loc, diff,
                                    computed))
                else:
                    debug(
                        d, '    {:>3}: [{:>3}]->{:>3}'.format(
                            elem0.indices_value, elem0.index, offset))

            # If compression was inneffective then abort
            if len(groups) == len(chan.elems):
                debug(d, 'Aborting group diff compression.')
                return None

            debug(d, 'Diff compression successful.')

            # Construct connection syntax
            s = None
            for x in groups:
                elem0 = x[1][0][0]
                if len(x[1]) == 1:
                    s = create_single_conn(s, chan, scope, i_elem, elem0)
                else:
                    s = create_range_conn(s, chan, i_elem, x)
            return s

        def conn_tree_groups(chan, s, i_elem, d=DEBUG_COMPRESSION):
            """
      Compress connections based on monotonically increasing or decreasing
      sets with the same target destination. Within a set, connection IDs can
      be monotonically increasing or decreasing.
      """
            locs = []
            debug(d, 'Locations:')
            for x in chan.elems:
                loc = target_loc(chan, x, scope)
                locs.append((x, loc))
                debug(
                    d,
                    '  {:>4} : {}[{}] -> {}'.format(x.indices_value, chan.name,
                                                    x.index, loc))

            # Separate the first odd element if there is one
            phase = 0
            if locs[0][1] != locs[1][1]:
                odd_elem = locs[0][0]
                locs = locs[1:]
                phase = 1

            # Count the group size
            group_size = 1
            while group_size < len(locs) and locs[group_size -
                                                  1][1] == locs[group_size][1]:
                group_size += 1

            # Only consider connections with more than one group
            if len(locs) <= group_size + 1:
                debug(d, 'Aborting tree compression.')
                return None

            # Set parameters
            loc_diff = locs[group_size][1] - locs[group_size - 1][1]
            loc_base = locs[0][1]
            base_indices_value = locs[0][0].indices_value
            connidA = tab.lookup_connid(chan.name, locs[0][0].index, scope)
            connidB = tab.lookup_connid(chan.name, locs[1][0].index, scope)
            connid_min = min(connidA, connidB)
            connid_diff = max(connidA, connidB) - connid_min
            connid_offset = (phase + (1 if connidA > connidB else 0)) % 2

            # Print some debug info
            debug(d, 'Attempting tree compression.')
            debug(d, '  Group size:    {}'.format(group_size))
            debug(d, '  Location base: {}'.format(loc_base))
            debug(d, '  Location diff: {}'.format(loc_diff))
            debug(d, '  Base ival:     {}'.format(base_indices_value))
            debug(d, '  ConnID base:   {}'.format(connidA))
            debug(d, '  ConnID diff:   {}'.format(connid_diff))

            # Check each group contains the same location
            debug(d, 'Checking groups...')
            i = 0
            while i * group_size < len(locs):
                debug(d, '  Group {}'.format(i))
                for j in range(1, group_size):
                    if locs[i * group_size][1] != locs[(i * group_size) +
                                                       j][1]:
                        debug(d, 'Aborting tree compression.')
                        return None
                i += 1

            # Check each step between groups has same location and connection diffs
            debug(d, 'Checking diffs...')
            for (i, (x, y)) in enumerate(
                    zip(locs[1::group_size], locs[group_size::group_size])):
                debug(
                    d, '  Group {} and {}: {} and {}'.format(
                        i, i + 1, y[1], x[1]))
                connidX = tab.lookup_connid(chan.name, x[0].index, scope)
                connidY = tab.lookup_connid(chan.name, y[0].index, scope)
                connid_diff_ = connidX - connidY
                if y[1] - x[1] != loc_diff or connid_diff != connid_diff_:
                    debug(d, 'Aborting tree compression.')
                    return None

            # Check matching computed location
            debug(d, 'Checking computed...')
            debug(d, 'connid_min = {}'.format(connid_min))
            debug(d, 'connid_off = {}'.format(connid_offset))
            if phase == 1:
                connid = tab.lookup_connid(chan.name, odd_elem.index, scope)
                debug(d, '  {}: connid={}'.format(odd_elem.indices_value,
                                                  connid))
            for (elem, loc) in locs:
                computed_loc = loc_base + (loc_diff * (math.floor(
                    ((elem.indices_value - base_indices_value)) / group_size)))
                connid = tab.lookup_connid(chan.name, elem.index, scope)
                #computed_connid = (connid_min +
                #    ((elem.indices_value + connid_offset) % group_size) * connid_diff)
                computed_connid = (connid_min + (
                    (elem.indices_value - phase) % group_size) * connid_diff)
                debug(
                    d, '  {}: connid={}, loc={} computed({}, {})'.format(
                        elem.indices_value, connid, loc, computed_connid,
                        computed_loc))
                assert computed_loc == loc
                assert computed_connid == connid

            debug(d, 'Tree compression successful.')

            # Construct connection syntax
            if phase == 0:
                return create_tree_conn(tab, scope, chan, phase, group_size,
                                        base_indices_value, loc_base, loc_diff,
                                        connid_min, connid_offset, connid_diff,
                                        i_elem)
            else:
                s = create_tree_conn(tab, scope, chan, phase, group_size,
                                     base_indices_value, loc_base, loc_diff,
                                     connid_min, connid_offset, connid_diff,
                                     i_elem)
                return create_single_conn(s, chan, scope, i_elem, odd_elem)

        def conn_singles(chan, s, i_elem, d=DEBUG_COMPRESSION):
            """
      Create (uncompressed) connections for each case.
      """
            debug(d, 'Creating uncompressed connection range.')
            for x in chan.elems:
                s = create_single_conn(s, chan, scope, i_elem, x)
                debug(
                    d, '  {}: {}[{}]'.format(x.indices_value, chan.name,
                                             x.index))
            return s

        # Sort the channel elements into increasing order of indices
        chan.elems = sorted(chan.elems, key=lambda x: x.indices_value)

        # Compress conditional connections and return the AST construction
        i_expr = indices_expr(chan.indices)
        i_elem = ast.ElemId('_i')
        i_elem.symbol = Symbol(i_elem.name, T_VAR_SINGLE, scope=T_SCOPE_BLOCK)
        s = None
        if COMPRESS:
            s = conn_tree_groups(chan, s, i_elem)
            s = conn_diff_groups(chan, s, i_elem) if s == None else s
        s = conn_singles(chan, s, i_elem) if s == None else s
        s = [ast.StmtAss(i_elem, i_expr), s]
        s = ast.StmtSeq([ast.VarDecl(i_elem.name, T_VAR_SINGLE, None)], s)
        return s