@contextmanager
def loop_chain(name, num_unroll=1, tile_size=0):
    """Analyze the sub-trace of loops lazily evaluated in this contextmanager ::

        [loop_0, loop_1, ..., loop_n-1]

    and produce a new sub-trace (``m <= n``) ::

        [fused_loops_0, fused_loops_1, ..., fused_loops_m-1, peel_loops]

    which is eventually inserted in the global trace of :class:`ParLoop` objects.

    That is, sub-sequences of :class:`ParLoop` objects are potentially replaced by
    new :class:`ParLoop` objects representing the fusion or the tiling of the
    original trace slice.

    :param name: identifier of the loop chain
    :param num_unroll: in a time stepping loop, the length of the loop chain
                       is given by ``num_loops * num_unroll``, where ``num_loops``
                       is the number of loops per time loop iteration. Therefore,
                       setting this value to a number greater than 1 enables
                       fusing/tiling longer loop chains (optional, defaults to 1).
    :param tile_size: suggest a tile size in case loop tiling is used (optional).
                      If ``0`` is passed in, only soft fusion is performed.
    """
    from base import _trace
    trace = _trace._trace
    stamp = trace[-1:]

    yield

    if num_unroll < 1:
        return

    start_point = trace.index(stamp[0])+1 if stamp else 0
    extracted_loop_chain = trace[start_point:]

    # Unroll the loop chain /num_unroll/ times before fusion/tiling
    total_loop_chain = loop_chain.unrolled_loop_chain + extracted_loop_chain
    if len(total_loop_chain) / len(extracted_loop_chain) == num_unroll:
        start_point = trace.index(total_loop_chain[0])
        trace[start_point:] = fuse(name, total_loop_chain, tile_size)
        loop_chain.unrolled_loop_chain = []
    else:
        loop_chain.unrolled_loop_chain.extend(extracted_loop_chain)
dataset/ETHPy150Open OP2/PyOP2/pyop2/fusion.py/loop_chain/original