예제 #1
0
 def visit_Name( s, node ):
   if node.id in s.closure:
     # free var from closure
     obj = s.closure[ node.id ]
     if isinstance( obj, dsl.Component ):
       # Component freevars are an L1 thing.
       if obj is not s.component:
         raise PyMTLSyntaxError( s.blk, node,
           f'Component {obj} is not a sub-component of {s.component}!' )
       ret = bir.Base( obj )
     else:
       # A closure variable could be a loop index. We need to
       # generate per-function closure variable instead of assuming
       # they will have the same value.
       ret = bir.FreeVar( f"{node.id}_at_{s.blk.__name__}", obj )
     ret.ast = node
     return ret
   elif node.id in s.globals:
     # free var from the global name space
     # For now we can still safely assume all upblks will see the same
     # value for a free var from the global space?
     ret = bir.FreeVar( node.id, s.globals[ node.id ] )
     ret.ast = node
     return ret
   raise PyMTLSyntaxError( s.blk, node,
     f'Temporary variable {node.id} is not supported at L1!' )
예제 #2
0
    def visit_Assign(s, node):
        blocking = {
            'CombUpblk': True,
            'SeqUpblk': False,
        }

        if len(node.targets) < 1:
            raise PyMTLSyntaxError(
                s.blk, node,
                'At least one assignment target should be provided!')

        if s._upblk_type not in blocking:
            raise PyMTLSyntaxError(
                s.blk, node,
                'Assignment should be in either a combinational or a sequential update block!'
            )

        value = s.visit(node.value)
        targets = [s.visit(target) for target in node.targets]
        ret = bir.Assign(targets, value, blocking=False)

        # Determine if this is a blocking/non-blocking assignment
        ret.blocking = s.get_blocking(node, ret)

        ret.ast = node
        return ret
예제 #3
0
    def get_call_obj(s, node):
        if hasattr(node, "starargs") and node.starargs:
            raise PyMTLSyntaxError(s.blk, node,
                                   'star argument is not supported!')
        if hasattr(node, "kwargs") and node.kwargs:
            raise PyMTLSyntaxError(s.blk, node,
                                   'double-star argument is not supported!')
        if node.keywords:
            raise PyMTLSyntaxError(s.blk, node,
                                   'keyword argument is not supported!')
        if not isinstance(node.func, ast.Name):
            raise PyMTLSyntaxError(
                s.blk, node, f'{node.func} is called but is not a name!')
        func = node.func

        # Find the corresponding object of node.func field
        # TODO: Support Verilog task?
        # if func in s.mapping:
        # The node.func field corresponds to a member of this class
        # obj = s.mapping[ func ][ 0 ]
        # else:
        try:
            # An object in global namespace is used
            if func.id in s.globals:
                obj = s.globals[func.id]
            # An object in closure is used
            elif func.id in s.closure:
                obj = s.closure[func.id]
            else:
                raise NameError
        except NameError:
            raise PyMTLSyntaxError(s.blk, node,
                                   node.func.id + ' function is not found!')
        return obj
예제 #4
0
    def visit_Subscript(s, node):
        value = s.visit(node.value)
        if isinstance(node.slice, ast.Slice):
            if node.slice.step is not None:
                raise PyMTLSyntaxError(s.blk, node,
                                       'Slice with steps is not supported!')
            lower, upper = s.visit(node.slice)
            ret = bir.Slice(value, lower, upper)
            ret.ast = node
            return ret

        # signal[ index ]
        # index might be a slice object!
        if isinstance(node.slice, ast.Index):
            idx = s.visit(node.slice)
            # If we have a static slice object then use it
            if isinstance(idx, bir.FreeVar) and isinstance(idx.obj, slice):
                slice_obj = idx.obj
                if slice_obj.step is not None:
                    raise PyMTLSyntaxError(
                        s.blk, node, 'Slice with steps is not supported!')
                assert isinstance( slice_obj.start, int ) and \
                       isinstance( slice_obj.stop, int ), \
                    f"start and stop of slice object {slice_obj} must be integers!"
                ret = bir.Slice(value, bir.Number(slice_obj.start),
                                bir.Number(slice_obj.stop))
            # Else this is a real index
            else:
                ret = bir.Index(value, idx)
            ret.ast = node
            return ret

        raise PyMTLSyntaxError(s.blk, node,
                               'Illegal subscript ' + node + ' encountered!')
예제 #5
0
  def get_call_obj( s, node ):
    if hasattr(node, "starargs") and node.starargs:
      raise PyMTLSyntaxError( s.blk, node, 'star argument is not supported!')
    if hasattr(node, "kwargs") and node.kwargs:
      raise PyMTLSyntaxError( s.blk, node,
        'double-star argument is not supported!')
    if node.keywords:
      raise PyMTLSyntaxError( s.blk, node, 'keyword argument is not supported!')

    obj = s.const_extractor.enter( node.func )
    if obj is not None:
      return obj
    else:
      raise PyMTLSyntaxError( s.blk, node, f'{node.func} function is not found!' )
예제 #6
0
    def visit_Compare(s, node):
        if not type(node.ops[0]) in s.opmap:
            raise PyMTLSyntaxError(
                s.blk, node,
                'Operator ' + str(node.ops[0]) + ' is not supported!')
        if len(node.ops) != 1 or len(node.comparators) != 1:
            raise PyMTLSyntaxError(s.blk, node,
                                   'Comparison can only have 2 operands!')

        op = s.opmap[type(node.ops[0])]
        op.ast = node.ops[0]
        left = s.visit(node.left)
        right = s.visit(node.comparators[0])
        ret = bir.Compare(left, op, right)
        ret.ast = node
        return ret
예제 #7
0
    def visit_Call(s, node):
        """Return behavioral RTLIR of a method call.

    At L3 we need to support the syntax of struct instantiation in upblks.
    This is achieved by function calls like `struct( 1, 2, 0 )`.
    """
        obj = s.get_call_obj(node)
        if is_bitstruct_class(obj):
            fields = obj.__bitstruct_fields__
            nargs = len(node.args)
            nfields = len(fields.keys())
            if nargs == 0:
                # Infer the values of each field by inspecting the object constructed
                # with default arguments
                inst = obj()
                values = [
                    s._datatype_to_bir(getattr(inst, field))
                    for field in fields.keys()
                ]
            else:
                # Otherwise all fields of the struct must be present in the arguments
                if nargs != nfields:
                    raise PyMTLSyntaxError(
                        s.blk, node,
                        f'BitStruct {obj.__name__} has {nfields} fields but {nargs} arguments are given!'
                    )
                values = [s.visit(arg) for arg in node.args]

            ret = bir.StructInst(obj, values)
            ret.ast = node
            return ret

        else:
            return super().visit_Call(node)
예제 #8
0
  def visit_Expr( s, node ):
    """Return the behavioral RTLIR of an expression.

    ast.Expr might be useful when a statement is only a call to a task or
    a non-returning function.
    """
    raise PyMTLSyntaxError(
      s.blk, node, 'Stand-alone expression is not supported yet!' )
예제 #9
0
 def visit_Call(s, node):
     obj = s.get_call_obj(node)
     # At L2 we add bool type but we do not support instantiating a bool
     # value -- that should always be the result of a comparison!
     if obj is rdt.Bool:
         raise PyMTLSyntaxError(
             s.blk, node, 'bool values cannot be instantiated explicitly!')
     return super().visit_Call(node)
예제 #10
0
 def visit_Module( s, node ):
   if len( node.body ) != 1 or \
       not isinstance( node.body[0], ast.FunctionDef ):
     raise PyMTLSyntaxError( s.blk, node,
       'Update blocks should have exactly one FuncDef!' )
   ret = s.visit( node.body[0] )
   ret.ast = node
   return ret
예제 #11
0
 def visit_UnaryOp(s, node):
     if not type(node.op) in s.opmap:
         raise PyMTLSyntaxError(
             s.blk, node, 'Operator ' + str(node.op) + ' is not supported!')
     op = s.opmap[type(node.op)]
     op.ast = node.op
     operand = s.visit(node.operand)
     ret = bir.UnaryOp(op, operand)
     ret.ast = node
     return ret
예제 #12
0
    def visit_Assign(s, node):
        if len(node.targets) != 1:
            raise PyMTLSyntaxError(
                s.blk, node, 'Assigning to multiple targets is not allowed!')

        value = s.visit(node.value)
        target = s.visit(node.targets[0])
        ret = bir.Assign(target, value, blocking=True)
        ret.ast = node
        return ret
예제 #13
0
 def visit_BinOp(s, node):
     left = s.visit(node.left)
     right = s.visit(node.right)
     if not type(node.op) in s.opmap:
         raise PyMTLSyntaxError(
             s.blk, node, 'Operator ' + str(node.op) + ' is not supported!')
     op = s.opmap[type(node.op)]
     op.ast = node.op
     ret = bir.BinOp(left, op, right)
     ret.ast = node
     return ret
예제 #14
0
 def get_blocking(s, node, bir_node):
     has_tmpvar = any(isinstance(n, bir.TmpVar) for n in bir_node.targets)
     all_tmpvar = all(isinstance(n, bir.TmpVar) for n in bir_node.targets)
     if has_tmpvar and not all_tmpvar:
         raise PyMTLSyntaxError(
             s.blk, node,
             'all targets have to be tmpvars if any target on LHS is a tmpvar!'
         )
     if has_tmpvar:
         return True
     else:
         return super().get_blocking(node, bir_node)
예제 #15
0
  def visit_AugAssign( s, node ):
    """Return the behavioral RTLIR of a non-blocking assignment

    If the given AugAssign is not non-blocking assignment, throw PyMTLSyntaxError
    """
    if isinstance( node.op, ast.LShift ):
      value = s.visit( node.value )
      targets = [ s.visit( node.target ) ]
      ret = bir.Assign( targets, value, blocking = False )
      ret.ast = node
      return ret
    raise PyMTLSyntaxError( s.blk, node,
        'invalid operation: augmented assignment is not non-blocking assignment!' )
예제 #16
0
    def visit_BoolOp(s, node):
        if not type(node.op) in s.opmap:
            raise PyMTLSyntaxError(
                s.blk, node, 'Operator ' + str(node.op) + ' is not supported!')
        op = s.opmap[type(node.op)]
        op.ast = node.op

        values = []
        for value in node.values:
            values.append(s.visit(value))

        ret = bir.BoolOp(op, values)
        ret.ast = node
        return ret
예제 #17
0
    def visit_For(s, node):
        # First fill the loop_var, start, end, step fields
        if node.orelse != []:
            raise PyMTLSyntaxError(s.blk, node,
                                   "for loops cannot have 'else' branch!")
        if not isinstance(node.target, ast.Name):
            raise PyMTLSyntaxError(
                s.blk, node, "The loop index must be a temporary variable!")
        loop_var_name = node.target.id

        # Check whether loop_var_name has been defined before
        if loop_var_name in s.loop_var_env:
            raise PyMTLSyntaxError(
                s.blk, node,
                "Redefinition of loop index " + loop_var_name + "!")

        # Add loop_var to the loop variable environment
        s.loop_var_env.add(loop_var_name)
        var = bir.LoopVarDecl(node.target.id)
        if not isinstance(node.iter, ast.Call):
            raise PyMTLSyntaxError(
                s.blk, node, "for loops can only use range() after 'in'!")
        if node.iter.func.id != 'range':
            raise PyMTLSyntaxError(
                s.blk, node, "for loops can only use range() after 'in'!")
        args = node.iter.args

        if len(args) == 1:
            # range( end )
            start = bir.Number(0)
            end = s.visit(args[0])
            step = bir.Number(1)
        elif len(args) == 2:
            # range( start, end )
            start = s.visit(args[0])
            end = s.visit(args[1])
            step = bir.Number(1)
        elif len(args) == 3:
            # range( start, end, step )
            start = s.visit(args[0])
            end = s.visit(args[1])
            step = s.visit(args[2])
        else:
            raise PyMTLSyntaxError(s.blk, node,
                                   "1~3 arguments should be given to range!")

        # Then visit all statements inside the loop
        body = []
        for body_stmt in node.body:
            body.append(s.visit(body_stmt))

        # Before we return, clear the loop variable in the loop variable
        # environment
        s.loop_var_env.remove(loop_var_name)
        ret = bir.For(var, start, end, step, body)
        ret.ast = node
        return ret
예제 #18
0
 def visit_Name(s, node):
     if node.id in s.closure:
         # free var from closure
         obj = s.closure[node.id]
         if isinstance(obj, dsl.Component):
             # Component freevars are an L1 thing.
             if obj is not s.component:
                 raise PyMTLSyntaxError(
                     s.blk, node,
                     f'Component {obj} is not a sub-component of {s.component}!'
                 )
             ret = bir.Base(obj)
         else:
             ret = bir.FreeVar(node.id, obj)
         ret.ast = node
         return ret
     elif node.id in s.globals:
         # free var from the global name space
         ret = bir.FreeVar(node.id, s.globals[node.id])
         ret.ast = node
         return ret
     raise PyMTLSyntaxError(
         s.blk, node,
         f'Temporary variable {node.id} is not supported at L1!')
예제 #19
0
    def visit_Assign(s, node):

        if len(node.targets) < 1:
            raise PyMTLSyntaxError(
                s.blk, node,
                'At least one assignment target should be provided!')

        value = s.visit(node.value)
        targets = [s.visit(target) for target in node.targets]
        ret = bir.Assign(targets, value, False)  # Need a handle to bir node

        # Determine if this is a blocking/non-blocking assignment
        ret.blocking = s.get_blocking(node, ret)

        ret.ast = node
        return ret
예제 #20
0
    def get_blocking(s, node, bir_node):
        if len(bir_node.targets) == 1:
            if isinstance(bir_node.targets[0], bir.TmpVar):
                return True
            return s._upblk_type is bir.CombUpblk

        has_tmpvar = any(isinstance(n, bir.TmpVar) for n in bir_node.targets)
        all_tmpvar = all(isinstance(n, bir.TmpVar) for n in bir_node.targets)
        if has_tmpvar and not all_tmpvar:
            raise PyMTLSyntaxError(
                s.blk, node,
                'all targets have to be tmpvars if any target on LHS is a tmpvar!'
            )
        if has_tmpvar:
            return True
        else:
            return super().get_blocking(node, bir_node)
예제 #21
0
    def visit_Call(s, node):
        """Return behavioral RTLIR of a method call.

    At L3 we need to support the syntax of struct instantiation in upblks.
    This is achieved by function calls like `struct( 1, 2, 0 )`.
    """
        obj = s.get_call_obj(node)
        if is_bitstruct_class(obj):
            if len(node.args) < 1:
                raise PyMTLSyntaxError(
                    s.blk, node,
                    'at least one value should be provided to struct instantiation!'
                )
            values = [s.visit(arg) for arg in node.args]
            ret = bir.StructInst(obj, values)
            ret.ast = node
            return ret

        else:
            return super().visit_Call(node)
예제 #22
0
  def visit_FunctionDef( s, node ):
    """Return the behavioral RTLIR of function node.

    We do not need to check the decorator list -- the fact that we are
    visiting this node ensures this node was added to the upblk
    dictionary through s.update() (or other PyMTL decorators) earlier!
    """
    # Check the arguments of the function
    if node.args.args or node.args.vararg or node.args.kwarg:
      raise PyMTLSyntaxError( s.blk, node,
        'Update blocks should not have arguments!' )

    # Save the name of the upblk
    s._upblk_name = node.name

    # Get the type of upblk from ._upblk_type variable
    ret = eval( 'bir.' + s._upblk_type + '( node.name, [] )' )
    for stmt in node.body:
      ret.body.append( s.visit( stmt ) )
    ret.ast = node
    return ret
예제 #23
0
    def visit_Name(s, node):
        # temporary variable
        if (not node.id in s.closure) and (not node.id in s.globals):
            # check if is a LoopVar or not
            if node.id in s.loop_var_env:
                ret = bir.LoopVar(node.id)
            elif node.id in s.tmp_var_env:
                ret = bir.TmpVar(node.id, s._upblk_name)
            elif isinstance(node.ctx, ast.Load):
                # trying to load an unregistered tmpvar
                raise PyMTLSyntaxError(
                    s.blk, node,
                    'tmpvar ' + node.id + ' used before assignment!')
            else:
                # This is the first time we see this tmp var
                s.tmp_var_env.add(node.id)
                ret = bir.TmpVar(node.id, s._upblk_name)
            ret.ast = node
            return ret

        else:
            return super().visit_Name(node)
예제 #24
0
 def visit_Break( s, node ):
   raise PyMTLSyntaxError( s.blk, node, 'invalid operation: break' )
예제 #25
0
 def visit_Global( s, node ):
   raise PyMTLSyntaxError( s.blk, node, 'invalid operation: global' )
예제 #26
0
 def visit_Pass( s, node ):
   raise PyMTLSyntaxError( s.blk, node, 'invalid operation: pass' )
예제 #27
0
 def visit_Continue( s, node ):
   raise PyMTLSyntaxError( s.blk, node, 'invalid operation: continue' )
예제 #28
0
 def visit_While( s, node ):
   raise PyMTLSyntaxError( s.blk, node, 'invalid operation: while' )
예제 #29
0
 def visit_BoolOp(s, node):
     raise PyMTLSyntaxError(
         s.blk, node,
         'Boolean operations are not translatable due to inconsistent semantics '
         'between Python and PyMTL. Please consider using bitwise &, |, and ~ instead!'
     )
예제 #30
0
 def visit_ExtSlice( s, node ):
   raise PyMTLSyntaxError( s.blk, node, 'invalid operation: extslice' )