def _call_function_ex_replace_args_large(
    old_body,
    vararg_stmt,
    new_body,
    search_end,
    func_ir,
    errmsg,
    already_deleted_defs
):
    """
    Extracts the args passed as vararg
    for CALL_FUNCTION_EX. This pass is taken when
    n_args > 30 and the bytecode looks like:

        BUILD_TUPLE # Create a list to append to
        # Start for each argument
        LOAD_FAST  # Load each argument.
        LIST_APPEND # Add the argument to the list
        # End for each argument
        ...
        LIST_TO_TUPLE # Convert the args to a tuple.

    In the IR generated, the tuple is created by concatenating
    together several 1 element tuples to an initial empty tuple.
    We traverse backwards in the IR, collecting args, until we
    find the original empty tuple. For example, the IR might
    look like:

        $orig_tuple = build_tuple(items=[])
        $first_var = build_tuple(items=[Var(arg0, test.py:6)])
        $next_tuple = $orig_tuple + $first_var
        ...
        $final_var = build_tuple(items=[Var(argn, test.py:6)])
        $final_tuple = $prev_tuple + $final_var
        $varargs_var = $final_tuple
    """
    # We traverse to the front of the block to look for the original
    # tuple.
    search_start = 0
    total_args = []
    if (
        isinstance(vararg_stmt, ir.Assign)
        and isinstance(vararg_stmt.value, ir.Var)
    ):
        target_name = vararg_stmt.value.name
        # If there is an initial assignment, delete it
        new_body[search_end] = None
        # Remove the definition.
        _remove_assignment_definition(
            old_body, search_end, func_ir, already_deleted_defs
        )
        search_end -= 1
    else:
        # There must always be an initial assignment
        # https://github.com/numba/numba/blob/59fa2e335be68148b3bd72a29de3ff011430038d/numba/core/interpreter.py#L259-L260
        # If this changes we may need to support this branch.
        raise AssertionError("unreachable")
    # Traverse backwards to find all concatenations
    # until eventually reaching the original empty tuple.
    while search_end >= search_start:
        concat_stmt = old_body[search_end]
        if (
            isinstance(concat_stmt, ir.Assign)
            and concat_stmt.target.name == target_name
            and isinstance(concat_stmt.value, ir.Expr)
            and concat_stmt.value.op == "build_tuple"
            and not concat_stmt.value.items
        ):
            new_body[search_end] = None
            # Remove the definition.
            _remove_assignment_definition(
                old_body, search_end, func_ir, already_deleted_defs
            )
            # If we have reached the build_tuple we exit.
            break
        else:
            # We expect to find another arg to append.
            # The first stmt must be a binop "add"
            if (search_end == search_start) or not (
                isinstance(concat_stmt, ir.Assign)
                and (
                    concat_stmt.target.name
                    == target_name
                )
                and isinstance(
                    concat_stmt.value, ir.Expr
                )
                and concat_stmt.value.op == "binop"
                and concat_stmt.value.fn == operator.add
            ):
                # We cannot handle this format.
                raise UnsupportedBytecodeError(errmsg)
            lhs_name = concat_stmt.value.lhs.name
            rhs_name = concat_stmt.value.rhs.name
            # The previous statement should be a
            # build_tuple containing the arg.
            arg_tuple_stmt = old_body[search_end - 1]
            if not (
                isinstance(arg_tuple_stmt, ir.Assign)
                and isinstance(
                    arg_tuple_stmt.value, ir.Expr
                )
                and (
                    arg_tuple_stmt.value.op
                    == "build_tuple"
                )
                and len(arg_tuple_stmt.value.items) == 1
            ):
                # We cannot handle this format.
                raise UnsupportedBytecodeError(errmsg)
            if arg_tuple_stmt.target.name == lhs_name:
                # The tuple should always be generated on the RHS.
                raise AssertionError("unreachable")
            elif arg_tuple_stmt.target.name == rhs_name:
                target_name = lhs_name
            else:
                # We cannot handle this format.
                raise UnsupportedBytecodeError(errmsg)
            total_args.append(
                arg_tuple_stmt.value.items[0]
            )
            new_body[search_end] = None
            new_body[search_end - 1] = None
            # Remove the definitions.
            _remove_assignment_definition(
                old_body, search_end, func_ir, already_deleted_defs
            )
            _remove_assignment_definition(
                old_body, search_end - 1, func_ir, already_deleted_defs
            )
            search_end -= 2
            # Avoid any space between appends
            keep_looking = True
            while search_end >= search_start and keep_looking:
                next_stmt = old_body[search_end]
                if (
                    isinstance(next_stmt, ir.Assign)
                    and (
                        next_stmt.target.name
                        == target_name
                    )
                ):
                    keep_looking = False
                else:
                    # If the argument is "created" in JIT, then there
                    # will be intermediate operations in between appends.
                    # For example if the next arg after arg4 is pow(arg5, 2),
                    # then the IR would look like:
                    #
                    #   # Appending arg4
                    #   $arg4_tup = build_tuple(items=[arg4])
                    #   $append_var.5 = $append_var.4 + $arg4_tup
                    #
                    #   # Creation of arg5.
                    #   # This is the section that we are skipping.
                    #   $32load_global.20 = global(pow: <built-in function pow>)
                    #   $const36.22 = const(int, 2)
                    #   $call.23 = call $32load_global.20(arg5, $const36.22)
                    #
                    #   # Appending arg5
                    #   $arg5_tup = build_tuple(items=[$call.23])
                    #   $append_var.6 = $append_var.5 + $arg5_tup
                    search_end -= 1
    if search_end == search_start:
        # If we reached the start we never found the build_tuple.
        # We cannot handle this format so raise the
        # original error message.
        raise UnsupportedBytecodeError(errmsg)
    # Reverse the arguments so we get the correct order.
    return total_args[::-1]

    Extracts the args passed as vararg
    for CALL_FUNCTION_EX. This pass is taken when
    n_args > 30 and the bytecode looks like:

        BUILD_TUPLE # Create a list to append to
        # Start for each argument
        LOAD_FAST  # Load each argument.
        LIST_APPEND # Add the argument to the list
        # End for each argument
        ...
        LIST_TO_TUPLE # Convert the args to a tuple.

    In the IR generated, the tuple is created by concatenating
    together several 1 element tuples to an initial empty tuple.
    We traverse backwards in the IR, collecting args, until we
    find the original empty tuple. For example, the IR might
    look like:

        $orig_tuple = build_tuple(items=[])
        $first_var = build_tuple(items=[Var(arg0, test.py:6)])
        $next_tuple = $orig_tuple + $first_var
        ...
        $final_var = build_tuple(items=[Var(argn, test.py:6)])
        $final_tuple = $prev_tuple + $final_var
        $varargs_var = $final_tuple
    
numba/core/interpreter.py