Пример #1
0
 def visit_AnnAssign(self, node: ast.AnnAssign):
     target = self.visit(node.target)
     value = self.visit(node.value)
     pos = extract_positional_info(node)
     annotation = self.visit(node.annotation)
     if isinstance(annotation, ir.NameRef):
         # Check if type is recognized by name
         type_ = self.symbols.type_by_name.get(annotation.name)
         if type_ is None:
             msg = f"Ignoring unrecognized annotation: {annotation}, line: {pos.line_begin}"
             warnings.warn(msg)
         else:
             ir_type = self.symbols.get_ir_type(type_)
             if isinstance(target, ir.NameRef):
                 sym = self.symbols.lookup(target)
                 existing_type = sym.type_
                 # This is an error, since it's an actual conflict.
                 if existing_type != ir_type:
                     msg = f"IR type from type hint conflicts with existing " \
                           f"(possibly inferred) type {existing_type}, line: {pos.line_begin}"
                     raise CompilerError(msg)
     if node.value is not None:
         # CPython will turn the syntax "var: annotation" into an AnnAssign node
         # with node.value = None. If executed, this won't bind or update the value of var.
         assign = ir.Assign(target, value, pos)
         self.body.append(assign)
Пример #2
0
 def visit_AugAssign(self, node: ast.AugAssign):
     target = self.visit(node.target)
     operand = self.visit(node.value)
     op = binary_in_place_ops.get(type(node.op))
     pos = extract_positional_info(node)
     assign = ir.Assign(target, ir.BinOp(target, operand, op), pos)
     self.body.append(assign)
Пример #3
0
def p_AssignExpr(p):
    """AssignExpr : CondExpr
                  | LValueExpr '=' AssignExpr"""
    # CondExpr
    if len(p) == 2:
        p[0] = p[1]

    # LValueExpr '=' AssignExpr
    elif len(p) == 4:
        p[0] = IR.Assign(p[1], p[3])
Пример #4
0
 def visit_Assign(self, node: ast.Assign):
     # first convert locally to internal IR
     value = self.visit(node.value)
     pos = extract_positional_info(node)
     for target in node.targets:
         # break cascaded assignments into multiple assignments
         target = self.visit(target)
         for subtarget, subvalue in unpack_assignment(target, value, pos):
             subassign = ir.Assign(subtarget, subvalue, pos)
             self.body.append(subassign)
Пример #5
0
def make_single_index_loop(header: ir.ForLoop, symbols):
    """

        Make loop interval of the form (start, stop, step).

        This tries to find a safe method of calculation.

        This assumes (with runtime verification if necessary)
        that 'stop - start' will not overflow.

        References:
            LIVINSKII et. al, Random Testing for C and C++ Compilers with YARPGen
            Dietz et. al, Understanding Integer Overflow in C/C++
            Bachmann et. al, Chains of Recurrences - a method to expedite the evaluation of closed-form functions
            https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html
            https://developercommunity.visualstudio.com/t/please-implement-integer-overflow-detection/409051
            https://numpy.org/doc/stable/user/building.html

    """

    by_iterable = {}
    intervals = set()
    interval_from_iterable = IntervalBuilder()
    for _, iterable in unpack_iterated(header.target, header.iterable):
        interval = interval_from_iterable(iterable)
        by_iterable[iterable] = interval
        intervals.add(interval)

    # loop_interval = _find_shared_interval(intervals)
    loop_start, loop_stop, loop_step = _find_shared_interval(intervals)
    loop_expr = ir.AffineSeq(loop_start, loop_stop, loop_step)
    # Todo: this needs a default setting to avoid excessive casts
    loop_counter = symbols.make_unique_name_like("i", type_=tr.Int32)
    body = []
    pos = header.pos
    simplify_expr = arithmetic_folding()

    for target, iterable in unpack_iterated(header.target, header.iterable):
        (start, _, step) = by_iterable[iterable]
        assert step == loop_step
        assert (start == loop_start) or (loop_start == ir.Zero)
        if step == loop_step:
            if start == loop_start:
                index = loop_counter
            else:
                assert loop_start == ir.Zero
                index = ir.BinOp(loop_counter, start, "+")
        else:
            # loop counter must be normalized
            assert loop_start == ir.Zero
            assert loop_step == ir.One
            index = ir.BinOp(step, loop_counter, "*")
            if start != ir.Zero:
                index = ir.BinOp(start, index, "+")

        value = index if isinstance(iterable, ir.AffineSeq) else ir.Subscript(iterable, index)
        assign = ir.Assign(target, value, pos)
        body.append(assign)

    # Todo: this doesn't hoist initial setup
    body.extend(header.body)
    repl = ir.ForLoop(loop_counter, loop_expr, body, pos)
    return repl
Пример #6
0
 def copy_out(self, append_to, pos):
     assert self.labeler is not None
     for target, value in self.labeler.source_assigns:
         assign = ir.Assign(target, value, pos)
         append_to.append(assign)
Пример #7
0
 def stfld(self, _, field):
     v = self.pop()
     obj = self.pop()
     self.stmt(ir.Assign(ir.Field(obj, field[2].name), v))
Пример #8
0
 def local(self, num, value=None):
     if value is None:
         return ir.Local(num)
     self.stmt(ir.Assign(ir.Local(num), value))