Beispiel #1
0
 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
Beispiel #2
0
        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
Beispiel #3
0
 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))
Beispiel #4
0
def form_location(sym, base, offset, compression):
    """
  Given the base id (ElemId), offset (Expr) and compression ratio (integer),
  produce an expression for a location::

    location = (base + (off/comp)) rem NUM_CORES
  """
    assert isinstance(base, ast.Elem) or isinstance(base, ast.Expr)
    assert isinstance(offset, ast.Expr)

    if isinstance(base, ast.Expr):
        base = ast.ElemGroup(base)

    # Offset
    loc = offset

    # Apply compression
    #if compression > 1:
    #  loc = ast.ExprBinop('/', ast.ElemGroup(loc),
    #      ast.ExprSingle(ast.ElemNumber(compression)))

    #elem_numcores = ast.ElemId(SYS_NUM_CORES_CONST)
    #elem_numcores.symbol = sym.lookup(SYS_NUM_CORES_CONST)

    # Apply 'rem NUM_CORES' to base + (off/comp)
    loc = ast.ExprSingle(
        ast.ElemGroup(
            ast.ExprBinop('+', base, ast.ExprSingle(ast.ElemGroup(loc)))))
    #ast.ExprBinop('rem', ast.ExprSingle(elem_numcores))

    v = EvalExpr().expr(loc)
    loc = loc if v == None else ast.ExprSingle(ast.ElemNumber(v))

    return loc
Beispiel #5
0
    def subscript_channel(self, indices, tab, stmt, name, expr, chanend,
                          chan_set):
        """
    Expand the use of a channel subscript over a set of iterators and determine
    for each the value of its index and location, and then add this to the
    channel table and corresponding expansion.
    """
        #print(Printer().expr(stmt.location))
        chan_elems = []

        # Iterate over cartesian product of iterator ranges
        ranges = [
            range(x.base_value, x.base_value + x.count_value) for x in indices
        ]
        for x in product(*ranges):

            # Deep copy expressions so we can modify them
            index_expr = copy.deepcopy(expr)
            location_expr = copy.deepcopy(stmt.location)

            # Substitute index variables for values
            index_values = []
            for (y, z) in zip(indices, x):
                index_expr.accept(
                    SubElem(ast.ElemId(y.name), ast.ElemNumber(z)))
                location_expr.accept(
                    SubElem(ast.ElemId(y.name),
                            ast.ElemNumber(z - y.base_value)))
                index_values.append(z)

            # Evaluate the expressions
            index_value = EvalExpr().expr(index_expr)
            location_value = EvalExpr().expr(location_expr)

            # Add to the table
            tab.insert(name, index_value, location_value, chanend, chan_set)

            # Add the expanded channel use to a list
            chan_elems.append(
                ChanElem(index_value, location_value, indices, index_values))

            debug(
                self.debug,
                '  {}[{}] at {} (chanend {})'.format(name, index_value,
                                                     location_value, chanend))

        return chan_elems
Beispiel #6
0
    def single_channel(self, indices, tab, stmt, name, chanend, chan_set):
        """
    Process a single (non-subscripted) channel use by evaluating its location
    and then adding it to the channel table and returning it as an element.
    Single channels may appear only in replicators in the client process of a
    server, hence we evaluate their location over the incident indices.
    """
        #print(Printer().expr(stmt.location))
        if indices:
            elem = ChanElem(None, None, None, None)

            # Iterate over cartesian product of iterator ranges
            ranges = [
                range(x.base_value, x.base_value + x.count_value)
                for x in indices
            ]
            for x in product(*ranges):

                # Deep copy expressions so we can modify them
                location_expr = copy.deepcopy(stmt.location)

                # Substitute index variables for values
                index_values = []
                for (y, z) in zip(indices, x):
                    location_expr.accept(
                        SubElem(ast.ElemId(y.name),
                                ast.ElemNumber(z - y.base_value)))

                # Evaluate the expressions
                location_value = EvalExpr().expr(location_expr)

                # Add to the table
                tab.insert(name, None, location_value, chanend, chan_set)

                # Add the location to the channel element
                elem.add_location(location_value)

                debug(
                    self.debug,
                    '  {} at {} (chanend {})'.format(name, location_value,
                                                     chanend))

            elem.location = elem.locations[0]
            return [elem]

        else:
            location_value = EvalExpr().expr(stmt.location)
            tab.insert(name, None, location_value, chanend, chan_set)
            debug(
                self.debug,
                ' {} at {} (chanend {})'.format(name, location_value, chanend))
            return [ChanElem(None, location_value, None, None)]
Beispiel #7
0
 def gen_single_conn(self, tab, scope, chan):
     """
 Generate a connection for a single channel declaration. 'chan' is a
 ChanElemSet with one element.
 """
     elem = chan.elems[0]
     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))
     # Server-end connections don't need targets
     if chan.symbol.scope == T_SCOPE_SERVER:
         return ast.StmtConnect(chanend, chanid,
                                ast.ExprSingle(ast.ElemNumber(0)),
                                self.connect_type(chan, False))
     # All other connections do
     else:
         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)
         return ast.StmtConnect(chanend, chanid, location,
                                self.connect_type(chan, master))
Beispiel #8
0
def indices_expr(indices):
    """
  Given a set of indices, return an expression computing their combined value.
  """
    dims = [x.count_value for x in indices]
    r = None
    for (i, x) in enumerate(indices):
        c = reduce(lambda x, y: x * y, dims[i + 1:], 1)
        c_expr = ast.ExprSingle(ast.ElemNumber(c))
        eid = ast.ElemId(x.name)
        eid.symbol = Symbol(x.name, T_VAL_SINGLE, None, scope=T_SCOPE_PROC)
        e = ast.ExprBinop('*', eid, c_expr) if c > 1 else ast.ExprSingle(eid)
        r = e if r == None else ast.ExprBinop('+', ast.ElemGroup(r), e)
    return r
Beispiel #9
0
 def stmt_server(self, node, parent, d):
     """
 For server statements the server and client processes are overlaid.
 """
     if node.distribute:
         debug(self.debug, 'd before server = {}'.format(d))
         e = self.stmt(node.server, parent, d)
         debug(self.debug, 'd after server = {}'.format(e))
         node.client = ast.StmtOn(ast.ExprSingle(ast.ElemNumber(d)),
                                  node.client)
         e += self.stmt(node.client, parent, d)
         debug(self.debug, 'd after client = {}'.format(e))
         node.distribute = False
         return e
     else:
         debug(self.debug, 'd before server = {}'.format(d))
         x = self.stmt(node.server, parent, d)
         debug(self.debug, 'd after server = {}'.format(x))
         y = self.stmt(node.client, parent, d)
         debug(self.debug, 'd after client = {}'.format(y))
     return max(x, y)
Beispiel #10
0
 def stmt_par(self, node, parent, d):
     """
 For processes in parallel composition, add 'on' prefixes to provide simple
 compile-time distribution. If any process is already prefixed with an 'on',
 then do not add any (this is mainly for the test cases).
 """
     if node.distribute:
         if any([isinstance(x, ast.StmtOn) for x in node.stmt]):
             self.errorlog.report_error(
                 "parallel composition contains 'on's")
             return 0
         e = self.stmt(node.stmt[0], parent, d)
         debug(self.debug, 'd before par = {}'.format(d))
         for (i, x) in enumerate(node.stmt[1:]):
             node.stmt[i + 1] = ast.StmtOn(
                 ast.ExprSingle(ast.ElemNumber(d + e)), x)
             e += self.stmt(x, parent, d + e)
         debug(self.debug, 'd after par = {}'.format(d))
         node.distribute = False
         return e
     else:
         return 0
Beispiel #11
0
 def stmt_on(self, node, l):
     node.location = l
     # Try and evaluate this 'target' expression
     v = EvalExpr().expr(node.expr)
     k = ast.ExprSingle(ast.ElemNumber(v)) if v != None else l
     self.stmt(node.stmt, k)
Beispiel #12
0
 def defn(self, node):
     node.location = ast.ElemNumber(0)
     if node.name == 'main':
         self.stmt(node.stmt, ast.ExprSingle(node.location))
     else:
         self.stmt(node.stmt, ast.ExprSingle(node.location))
Beispiel #13
0
    def distribute_stmt(self, m, elem_t, elem_n, elem_m, base, indices,
                        proc_actuals, formals, pcall):
        """
    Create the distribution process body statement.
    """

        # Setup some useful expressions
        name = self.sig.unique_process_name()
        elem_x = ast.ElemId('_x')
        expr_x = ast.ExprSingle(elem_x)
        expr_t = ast.ExprSingle(elem_t)
        expr_n = ast.ExprSingle(elem_n)
        expr_m = ast.ExprSingle(elem_m)
        elem_base = ast.ElemNumber(base)
        expr_base = ast.ExprSingle(elem_base)

        # Replace ocurrances of index variables i with i = f(_t)
        divisor = m
        for x in indices:
            divisor = floor(divisor / x.count_value)
            # Calculate the index i as a function of _t and the dimensions.
            e = ast.ExprBinop(
                'rem',
                ast.ElemGroup(
                    ast.ExprBinop('/', elem_t,
                                  ast.ExprSingle(ast.ElemNumber(divisor)))),
                ast.ExprSingle(ast.ElemNumber(x.count_value)))
            if x.base_value > 0:
                e = ast.ExprBinop('+', ast.ElemNumber(x.base_value),
                                  ast.ExprSingle(ast.ElemGroup(e)))
            # Then replace it for each ocurrance of i
            for y in pcall.args:
                y.accept(SubElem(ast.ElemId(x.name), ast.ElemGroup(e)))

        d = ast.ExprBinop('+', elem_t, ast.ExprSingle(elem_x))
        d = form_location(self.sym, elem_base, d, 1)

        # Create on the on statement
        on_stmt = ast.StmtOn(
            d,
            ast.StmtPcall(name, [
                ast.ExprBinop('+', elem_t, ast.ExprSingle(elem_x)), expr_x,
                ast.ExprBinop('-', elem_m, ast.ExprSingle(elem_x))
            ] + proc_actuals))
        on_stmt.location = None

        # Conditionally recurse {d()|d()} or d()
        s1 = ast.StmtIf(
            # if m > n/2
            ast.ExprBinop('>', elem_m, ast.ExprSingle(elem_x)),
            # then
            ast.StmtPar(
                [],
                [
                    # on id()+t+n/2 do d(t+n/2, n/2, m-n/2, ...)
                    on_stmt,
                    # d(t, n/2, n/2)
                    ast.StmtPcall(name,
                                  [expr_t, expr_x, expr_x] + proc_actuals),
                ],
                False),
            # else d(t, n/2, m)
            ast.StmtPcall(name, [expr_t, expr_x, expr_m] + proc_actuals))

        # _x = n/2 ; s1
        n_div_2 = ast.ExprBinop('>>', elem_n,
                                ast.ExprSingle(ast.ElemNumber(1)))
        s2 = ast.StmtSeq([], [ast.StmtAss(elem_x, n_div_2), s1])

        # if n = 1 then process() else s1
        s3 = ast.StmtIf(
            ast.ExprBinop('=', elem_n, ast.ExprSingle(ast.ElemNumber(1))),
            pcall, s2)

        # Create the local declarations
        decls = [ast.VarDecl(elem_x.name, T_VAR_SINGLE, None)]

        s4 = ast.StmtSeq(decls, [s3])

        # Create the definition
        d = ast.ProcDef(name, T_PROC, formals, s4)

        return d
Beispiel #14
0
    def transform_rep(self, stmt):
        """
    Convert a replicated parallel statement into a divide-and-conquer form.
     - Return the tuple (process-def, process-call)
    We only allow replicators where their location is known; i.e. stmt.location
    is an Expr(Number(x)).
    """
        assert isinstance(stmt, ast.StmtRep)
        assert isinstance(stmt.stmt, ast.StmtPcall)
        assert isinstance(stmt.location, ast.ExprSingle)
        assert isinstance(stmt.location.elem, ast.ElemNumber)
        pcall = stmt.stmt

        # The context of the procedure call is each variable occurance in the
        # set of arguments.
        context = FreeVars().compute(pcall)

        assert not stmt.m == None
        #assert not stmt.f == None
        n = util.next_power_of_2(stmt.m)

        # Create new variables
        formals = []  # Formals for the new distribution process
        actuals = []  # Actuals for the new distribution process
        proc_actuals = []  # All other live-in variables
        elem_t = ast.ElemId('_t')  # Interval base
        elem_n = ast.ElemId('_n')  # Interval width
        elem_m = ast.ElemId('_m')  # Processes in interval
        #print(Printer().expr(stmt.location))
        base = stmt.location.elem.value

        # Populate the distribution and replicator indices
        formals.append(ast.Param('_t', T_VAL_SINGLE, None))
        formals.append(ast.Param('_n', T_VAL_SINGLE, None))
        formals.append(ast.Param('_m', T_VAL_SINGLE, None))
        actuals.append(ast.ExprSingle(ast.ElemNumber(0)))
        actuals.append(ast.ExprSingle(ast.ElemNumber(n)))
        actuals.append(ast.ExprSingle(ast.ElemNumber(stmt.m)))

        # For each non-index free-variable of the process call
        for x in context - set([x for x in stmt.indices]):

            # Add each unique variable ocurrance from context as a formal param
            formals.append(
                ast.Param(x.name, rep_var_to_param[x.symbol.type],
                          x.symbol.expr))

            # If the actual is an array subscript or slice, we only pass the id.
            if isinstance(x, ast.ElemSlice) or isinstance(x, ast.ElemSub):
                e = ast.ElemId(x.name)
                e.symbol = x.symbol
                proc_actuals.append(ast.ExprSingle(e))
            else:
                proc_actuals.append(ast.ExprSingle(copy.copy(x)))

        # Add the extra actual params to the distribution actuals
        actuals.extend(proc_actuals)

        # Create the process definition and perform semantic analysis to
        # update symbol bindings.
        d = self.distribute_stmt(stmt.m, elem_t, elem_n, elem_m, base,
                                 stmt.indices, proc_actuals, formals, pcall)
        #Printer().defn(d, 0)
        self.sem.defn(d)

        # Create the corresponding call.
        c = ast.StmtPcall(d.name, actuals)
        self.sig.insert(d.type, d)
        return (d, c)
Beispiel #15
0
 def p_elem_number(self, p):
   '''elem : HEXLITERAL
           | DECLITERAL
           | BINLITERAL'''
   p[0] = ast.ElemNumber(p[1], self.coord(p))