code: def _tile_broadcast(
      cls,
      op: "DataFrameMerge",
      left: Union[DataFrame, Series],
      right: Union[DataFrame, Series],
  ):
      from .concat import DataFrameConcat
  
      out_df = op.outputs[0]
      out_chunks = []
      if left.chunk_shape[0] < right.chunk_shape[0]:
          # broadcast left
          if op.how == "inner":
              left_chunks = left.chunks
              need_split = False
          else:
              left_on = _prepare_shuffle_on(
                  op.left_index, op.left_on, op.on
              )
              left_chunks = cls._gen_shuffle_chunks(
                  left.chunk_shape, left_on, left
              )
              need_split = True
          # set is_broadcast property
          for c in left_chunks:
              c.is_broadcaster = True
          right_chunks = right.chunks
          for right_chunk in right_chunks:
              merged_chunks = []
              # concat all merged results
              for j, left_chunk in enumerate(left_chunks):
                  merge_op = op.copy().reset_key()
                  if need_split:
                      merge_op.split_info = MergeSplitInfo(
                          "right", j, len(left_chunks)
                      )
                  merged_chunks.append(
                      merge_op.new_chunk(
                          [left_chunk, right_chunk],
                          index=(j, 0),
                          shape=(np.nan, out_df.shape[1]),
                          columns_value=out_df.columns_value,
                      )
                  )
              concat_op = DataFrameConcat(
                  output_types=[OutputType.dataframe]
              )
              out_chunks.append(
                  concat_op.new_chunk(
                      merged_chunks,
                      shape=(np.nan, out_df.shape[1]),
                      dtypes=out_df.dtypes,
                      index=right_chunk.index,
                      index_value=infer_index_value(
                          left_chunks[0].index_value,
                          right_chunk.index_value,
                      ),
                      columns_value=out_df.columns_value,
                  )
              )
          nsplits = ((np.nan,) * len(right.chunks), (out_df.shape[1],))
      else:
          # broadcast right
          if op.how == "inner":
              need_split = False
              right_chunks = right.chunks
          else:
              need_split = True
              right_on = _prepare_shuffle_on(
                  op.right_index, op.right_on, op.on
              )
              right_chunks = cls._gen_shuffle_chunks(
                  right.chunk_shape, right_on, right
              )
          # set is_broadcast property
          for c in right_chunks:
              c.is_broadcaster = True
          left_chunks = left.chunks
          for left_chunk in left_chunks:
              merged_chunks = []
              # concat all merged results
              for j, right_chunk in enumerate(right_chunks):
                  merge_op = op.copy().reset_key()
                  if need_split:
                      merge_op.split_info = MergeSplitInfo(
                          "left", j, len(right_chunks)
                      )
                  merged_chunks.append(
                      merge_op.new_chunk(
                          [left_chunk, right_chunk],
                          shape=(np.nan, out_df.shape[1]),
                          index=(j, 0),
                          columns_value=out_df.columns_value,
                      )
                  )
              concat_op = DataFrameConcat(
                  output_types=[OutputType.dataframe]
              )
              out_chunks.append(
                  concat_op.new_chunk(
                      merged_chunks,
                      shape=(np.nan, out_df.shape[1]),
                      dtypes=out_df.dtypes,
                      index=left_chunk.index,
                      index_value=infer_index_value(
                          left_chunk.index_value,
                          right_chunks[0].index_value,
                      ),
                      columns_value=out_df.columns_value,
                  )
              )
          nsplits = ((np.nan,) * len(left.chunks), (out_df.shape[1],))
  
      new_op = op.copy()
      return new_op.new_dataframes(
          op.inputs,
          out_df.shape,
          nsplits=tuple(tuple(ns) for ns in nsplits),
          chunks=out_chunks,
          dtypes=out_df.dtypes,
          index_value=out_df.index_value,
          columns_value=out_df.columns_value,
      )
  
imports: import itertools
  from collections import namedtuple
  from enum import Enum
  from typing import Any, Dict, List, Optional, Union, Tuple
  import numpy
  import pandas
  from ...None import opcodes
  from ...core import OutputType, recursive_tile, TileStatus
  from ...core.context import get_context
  from ...core.operand import OperandStage, MapReduceOperand
  from ...serialization.serializables import AnyField, BoolField, DictField, StringField, TupleField, KeyField, Int32Field, NamedTupleField
  from ...typing import TileableType
  from ...utils import has_unknown_shape, lazy_import
  from ..base.bloom_filter import filter_by_bloom_filter
  from ..core import DataFrame, Series, DataFrameChunk
  from ..operands import DataFrameOperand, DataFrameOperandMixin, DataFrameShuffleProxy
  from ..utils import auto_merge_chunks, build_concatenated_rows_frame, build_df, parse_index, hash_dataframe_on, infer_index_value, is_cudf
  import logging
label_desc: Use image node_id 9 for calling the DataFrameMerge obj's underlying member method code with example usage: obj._tile_broadcast(cls, op, left, right) and returns: new_op