
# Autogenerated by mlir-tblgen; don't manually edit.

from ._ods_common import _cext as _ods_cext
from ._ods_common import (
    equally_sized_accessor as _ods_equally_sized_accessor,
    get_default_loc_context as _ods_get_default_loc_context,
    get_op_results_or_values as _get_op_results_or_values,
    segmented_accessor as _ods_segmented_accessor,
)
_ods_ir = _ods_cext.ir
_ods_cext.globals.register_traceback_file_exclusion(__file__)

import builtins
from typing import Any as _Any, Sequence as _Sequence, Union as _Union, Optional as _Optional
import sys as _sys
if _sys.version_info >= (3, 12):
  from collections.abc import Buffer as _Buffer  # pytype: disable=not-supported-yet
else:
  try:
    from typing_extensions import Buffer as _Buffer
  except ImportError:
    _Buffer = _Any


@_ods_cext.register_dialect
class _Dialect(_ods_ir.Dialect):
  DIALECT_NAMESPACE = "bufferization"

@_ods_cext.register_operation(_Dialect)
class AllocTensorOp(_ods_ir.OpView):
  r"""
  `bufferization.alloc_tensor` materializes an uninitialized tensor with a
  given shape (dynamic or static). It always bufferizes to a new buffer
  allocation of the given shape. The optional `copy` operand specifies the
  contents of the tensors. If no `copy` operand is specified, reading from the
  result of an `alloc_tensor` op yields an undefined value.
  
  If `copy` is specified, no dynamic sizes should be passed, since they are
  the same as the dynamic sizes of the `copy` operand.
  
  `alloc_tensor` is a helper op for bufferization. The operation is provided
  as an anchor that marks the beginning of a new tensor SSA use-def chain. It
  can be used to control in-place bufferization decisions during One-Shot
  Bufferize: The bufferized result of a `bufferization.alloc_tensor` does not
  alias with any other buffer, so it can be used to resolve read-after-write
  conflicts that would have been introduced by the in-place bufferization of
  another op.
  
  The optional `memory_space` attribute specifies the memory space when
  bufferizing this op. The memory space is inferred from `copy` if specified.
  If neither `copy` nor `memory_space` is specified, the default memory space
  is used during bufferization.
  
  The optional `size_hint` operand specifies the number of non-zero elements
  for sparse tensors. The value of `size_hint` should be not less than 1 and
  not larger than the linear size of the corresponding dense tensor type. If
  this requirement is not met, the behavior of the operator is undefined.
  
  Both dense and sparse tensor types are supported. The result of a
  `bufferization.alloc_tensor` is a tensor value that can be used like any
  other tensor value. In practice, it is often used as the "out" operand of
  another op. Sparse tensor allocations should always be used in a local
  construction operation and never escape the function boundary directly.
  
  Example:
  
  ```mlir
  %c = bufferization.alloc_tensor(%d1, %d2) : tensor<?x?xf32, #SparseMatrix>
  %0 = linalg.matmul
    ins(%a, %b: tensor<?x?xf32, #SparseMatrix>, tensor<?x?xf32, #SparseMatrix>)
    outs(%c: tensor<?x?xf32, #SparseMatrix>) -> tensor<?x?xf32, #SparseMatrix>
  return %0 : tensor<?x?xf32, #SparseMatrix>
  ```
  
  ```mlir
  %c = bufferization.alloc_tensor(%d1, %d2) size_hint = %noe
    : tensor<?x?xf32, #SparseMatrix>
  ```
  
  Note: An `alloc_tensor` with a `copy` should also be expressed as an
  `alloc_tensor` without `copy`, followed by a `copy_tensor`.
  """

  OPERATION_NAME = "bufferization.alloc_tensor"

  _ODS_OPERAND_SEGMENTS = [-1,0,0,]

  _ODS_REGIONS = (0, True)

  def __init__(self, result: _ods_ir.Type, dynamic_sizes: _Sequence[_ods_ir.Value[_ods_ir.IndexType]], *, copy: _Optional[_ods_ir.Value] = None, size_hint: _Optional[_ods_ir.Value[_ods_ir.IndexType]] = None, memory_space: _Optional[_Union[_Any, _ods_ir.Attribute]] = None, loc: _Optional[_ods_ir.Location] = None, ip: _Optional[_ods_ir.InsertionPoint] = None):
    operands = []
    attributes = {}
    regions = None
    operands.append(_get_op_results_or_values(dynamic_sizes))
    operands.append(copy)
    operands.append(size_hint)
    _ods_context = _ods_get_default_loc_context(loc)
    if memory_space is not None: attributes["memory_space"] = (memory_space if (
        isinstance(memory_space, _ods_ir.Attribute) or
        not _ods_ir.AttrBuilder.contains('AnyAttr')) else
          _ods_ir.AttrBuilder.get('AnyAttr')(memory_space, context=_ods_context))
    results = []
    results.append(result)
    _ods_successors = None
    super().__init__(self.OPERATION_NAME, self._ODS_REGIONS, self._ODS_OPERAND_SEGMENTS, self._ODS_RESULT_SEGMENTS, attributes=attributes, results=results, operands=operands, successors=_ods_successors, regions=regions, loc=loc, ip=ip)

  @builtins.property
  def dynamic_sizes(self) -> _ods_ir.OpOperandList[_ods_ir.IndexType]:
    operand_range = _ods_segmented_accessor(
         self.operation.operands,
         self.operation.attributes["operandSegmentSizes"], 0)
    return operand_range

  @builtins.property
  def copy(self) -> _Optional[_ods_ir.Value]:
    operand_range = _ods_segmented_accessor(
         self.operation.operands,
         self.operation.attributes["operandSegmentSizes"], 1)
    return operand_range[0] if len(operand_range) > 0 else None

  @builtins.property
  def size_hint(self) -> _Optional[_ods_ir.Value[_ods_ir.IndexType]]:
    operand_range = _ods_segmented_accessor(
         self.operation.operands,
         self.operation.attributes["operandSegmentSizes"], 2)
    return operand_range[0] if len(operand_range) > 0 else None

  @builtins.property
  def memory_space(self) -> _Optional[_ods_ir.Attribute]:
    if "memory_space" not in self.operation.attributes:
      return None
    return self.operation.attributes["memory_space"]

  @memory_space.setter
  def memory_space(self, value: _Optional[_ods_ir.Attribute]):
    if value is not None:
      self.operation.attributes["memory_space"] = value
    elif "memory_space" in self.operation.attributes:
      del self.operation.attributes["memory_space"]

  @memory_space.deleter
  def memory_space(self):
    del self.operation.attributes["memory_space"]

  @builtins.property
  def result(self) -> _ods_ir.OpResult:
    return self.operation.results[0]

@_ods_cext.register_op_adaptor(AllocTensorOp)
class AllocTensorOpAdaptor(_ods_ir.OpAdaptor):
  OPERATION_NAME = "bufferization.alloc_tensor"

  @builtins.property
  def dynamic_sizes(self) -> _ods_ir.OpOperandList[_ods_ir.IndexType]:
    operand_range = _ods_segmented_accessor(
         self.operands,
         self.attributes["operandSegmentSizes"], 0)
    return operand_range

  @builtins.property
  def copy(self) -> _Optional[_ods_ir.Value]:
    operand_range = _ods_segmented_accessor(
         self.operands,
         self.attributes["operandSegmentSizes"], 1)
    return operand_range[0] if len(operand_range) > 0 else None

  @builtins.property
  def size_hint(self) -> _Optional[_ods_ir.Value[_ods_ir.IndexType]]:
    operand_range = _ods_segmented_accessor(
         self.operands,
         self.attributes["operandSegmentSizes"], 2)
    return operand_range[0] if len(operand_range) > 0 else None

  @builtins.property
  def memory_space(self) -> _Optional[_ods_ir.Attribute]:
    if "memory_space" not in self.attributes:
      return None
    return self.attributes["memory_space"]

def alloc_tensor(result: _ods_ir.Type, dynamic_sizes: _Sequence[_ods_ir.Value[_ods_ir.IndexType]], *, copy: _Optional[_ods_ir.Value] = None, size_hint: _Optional[_ods_ir.Value[_ods_ir.IndexType]] = None, memory_space: _Optional[_Union[_Any, _ods_ir.Attribute]] = None, loc: _Optional[_ods_ir.Location] = None, ip: _Optional[_ods_ir.InsertionPoint] = None) -> _ods_ir.OpResult:
  return AllocTensorOp(result=result, dynamic_sizes=dynamic_sizes, copy=copy, size_hint=size_hint, memory_space=memory_space, loc=loc, ip=ip).result

@_ods_cext.register_operation(_Dialect)
class CloneOp(_ods_ir.OpView):
  r"""
  Clones the data in the input view into an implicitly defined output view.
  
  Usage:
  
  ```mlir
  %arg1 = bufferization.clone %arg0 : memref<?xf32> to memref<?xf32>
  ```
  
  Valid implementations of this operation may alias the input and output
  views or create an actual copy. Mutating the source or result
  of the clone operation after the clone operation thus leads to undefined
  behavior.
  """

  OPERATION_NAME = "bufferization.clone"

  _ODS_REGIONS = (0, True)

  def __init__(self, output: _ods_ir.Type, input: _ods_ir.Value, *, loc: _Optional[_ods_ir.Location] = None, ip: _Optional[_ods_ir.InsertionPoint] = None):
    operands = []
    attributes = {}
    regions = None
    operands.append(input)
    _ods_context = _ods_get_default_loc_context(loc)
    results = []
    results.append(output)
    _ods_successors = None
    super().__init__(self.OPERATION_NAME, self._ODS_REGIONS, self._ODS_OPERAND_SEGMENTS, self._ODS_RESULT_SEGMENTS, attributes=attributes, results=results, operands=operands, successors=_ods_successors, regions=regions, loc=loc, ip=ip)

  @builtins.property
  def input(self) -> _ods_ir.Value:
    return self.operation.operands[0]

  @builtins.property
  def output(self) -> _ods_ir.OpResult:
    return self.operation.results[0]

@_ods_cext.register_op_adaptor(CloneOp)
class CloneOpAdaptor(_ods_ir.OpAdaptor):
  OPERATION_NAME = "bufferization.clone"

  @builtins.property
  def input(self) -> _ods_ir.Value:
    return self.operands[0]

def clone(output: _ods_ir.Type, input: _ods_ir.Value, *, loc: _Optional[_ods_ir.Location] = None, ip: _Optional[_ods_ir.InsertionPoint] = None) -> _ods_ir.OpResult:
  return CloneOp(output=output, input=input, loc=loc, ip=ip).result

@_ods_cext.register_operation(_Dialect)
class DeallocOp(_ods_ir.OpView):
  r"""
  This operation deallocates each of the given memrefs if there is no alias
  to that memref in the list of retained memrefs and the corresponding
  condition value is set. This condition can be used to indicate and pass on
  ownership of memref values (or in other words, the responsibility of
  deallocating that memref). If two memrefs alias each other, only one will be
  deallocated to avoid double free situations.
  
  The number of variadic `memref` operands (the memrefs to be deallocated)
  must equal the number of variadic `condition` operands and correspond to
  each other element-wise.
  
  The `memref` operands must be the originally allocated memrefs, however, the
  `retained` memref operands may be arbitrary memrefs.
  
  This operation returns a variadic number of `updatedConditions` operands,
  one updated condition per retained memref. An updated condition indicates
  the ownership of the respective retained memref. It is computed as the
  disjunction of all `conditions` operands where the corresponding to
  `memrefs` operand aliases with the retained memref. If the retained memref
  has no aliases among `memrefs`, the resulting updated condition is 'false'.
  This is because all memrefs that need to be deallocated within one basic
  block should be added to the same `bufferization.dealloc` operation at the
  end of the block; if no aliasing memref is present, then it does not have to
  be deallocated and thus we don't need to claim ownership. If the memrefs to
  be deallocated are split over multiple dealloc operations (e.g., to avoid
  aliasing checks at runtime between the `memref` operands), then the results
  have to be manually combined using an `arith.ori` operation and all of them
  still require the same list of `retained` memref operands unless the
  (potentially empty) set of aliasing memrefs can be determined statically. In
  that case, the `updatedCondition` operand can be replaced accordingly (e.g.,
  by a canonicalizer).
  
  Example:
  ```mlir
  %0:3 = bufferization.dealloc (%a0, %a1 : memref<2xf32>, memref<4xi32>)
    if (%cond0, %cond1) retain (%r0, %r1, %r2 : memref<?xf32>, memref<f64>,
    memref<2xi32>)
  ```
  Deallocation will be called on `%a0` if `%cond0` is 'true' and neither
  `%r0`, `%r1`, or `%r2` are aliases of `%a0`. `%a1` will be deallocated when
  `%cond1` is set to 'true' and none of `%r0`, `%r1`, `%r2`, and `%a0` are
  aliases.
  
  Note that this can be an expensive operation if there are many operands that
  cannot be optimized away. The runtime cost of this operation (assuming that
  nothing is optimized away) is `O(|memrefs|^2+|memrefs|*|retained|)`. The
  cost in terms of memory space is `O(|memrefs|+|retained|)`. As a result, it
  is recommended to place it carefully in the IR such that most operands can
  be optimized away by running the `buffer-deallocation-simplification` pass.
  """

  OPERATION_NAME = "bufferization.dealloc"

  _ODS_OPERAND_SEGMENTS = [-1,-1,-1,]

  _ODS_REGIONS = (0, True)

  def __init__(self, memrefs: _Sequence[_ods_ir.Value], conditions: _Sequence[_ods_ir.Value[_ods_ir.IntegerType]], retained: _Sequence[_ods_ir.Value], *, results: _Optional[_Sequence[_ods_ir.Type]] = None, loc: _Optional[_ods_ir.Location] = None, ip: _Optional[_ods_ir.InsertionPoint] = None):
    operands = []
    attributes = {}
    regions = None
    operands.append(_get_op_results_or_values(memrefs))
    operands.append(_get_op_results_or_values(conditions))
    operands.append(_get_op_results_or_values(retained))
    _ods_context = _ods_get_default_loc_context(loc)
    _ods_successors = None
    super().__init__(self.OPERATION_NAME, self._ODS_REGIONS, self._ODS_OPERAND_SEGMENTS, self._ODS_RESULT_SEGMENTS, attributes=attributes, results=results, operands=operands, successors=_ods_successors, regions=regions, loc=loc, ip=ip)

  @builtins.property
  def memrefs(self) -> _ods_ir.OpOperandList:
    operand_range = _ods_segmented_accessor(
         self.operation.operands,
         self.operation.attributes["operandSegmentSizes"], 0)
    return operand_range

  @builtins.property
  def conditions(self) -> _ods_ir.OpOperandList[_ods_ir.IntegerType]:
    operand_range = _ods_segmented_accessor(
         self.operation.operands,
         self.operation.attributes["operandSegmentSizes"], 1)
    return operand_range

  @builtins.property
  def retained(self) -> _ods_ir.OpOperandList:
    operand_range = _ods_segmented_accessor(
         self.operation.operands,
         self.operation.attributes["operandSegmentSizes"], 2)
    return operand_range

  @builtins.property
  def updatedConditions(self) -> _ods_ir.OpResultList[_ods_ir.IntegerType]:
    _ods_variadic_group_length = len(self.operation.results) - 1 + 1
    return self.operation.results[0:0 + _ods_variadic_group_length]

@_ods_cext.register_op_adaptor(DeallocOp)
class DeallocOpAdaptor(_ods_ir.OpAdaptor):
  OPERATION_NAME = "bufferization.dealloc"

  @builtins.property
  def memrefs(self) -> _ods_ir.OpOperandList:
    operand_range = _ods_segmented_accessor(
         self.operands,
         self.attributes["operandSegmentSizes"], 0)
    return operand_range

  @builtins.property
  def conditions(self) -> _ods_ir.OpOperandList[_ods_ir.IntegerType]:
    operand_range = _ods_segmented_accessor(
         self.operands,
         self.attributes["operandSegmentSizes"], 1)
    return operand_range

  @builtins.property
  def retained(self) -> _ods_ir.OpOperandList:
    operand_range = _ods_segmented_accessor(
         self.operands,
         self.attributes["operandSegmentSizes"], 2)
    return operand_range

def dealloc(memrefs: _Sequence[_ods_ir.Value], conditions: _Sequence[_ods_ir.Value[_ods_ir.IntegerType]], retained: _Sequence[_ods_ir.Value], *, results: _Optional[_Sequence[_ods_ir.Type]] = None, loc: _Optional[_ods_ir.Location] = None, ip: _Optional[_ods_ir.InsertionPoint] = None) -> _Union[_ods_ir.OpResult, _ods_ir.OpResultList, DeallocOp]:
  op = DeallocOp(memrefs=memrefs, conditions=conditions, retained=retained, results=results, loc=loc, ip=ip); results = op.results
  return results if len(results) > 1 else (results[0] if len(results) == 1 else op)

@_ods_cext.register_operation(_Dialect)
class DeallocTensorOp(_ods_ir.OpView):
  r"""
  `bufferization.dealloc_tensor` is a buffer deallocation in tensor land. This
  op can be used for manual buffer deallocation. Some bufferizations (such as
  One-Shot Bufferize) take care of buffer deallocation, in which case this op
  is usually not needed. Details can be found in the documentation of the
  respective bufferization passes.
  
  In case of a dense tensor, this op lowers to a `memref.dealloc` op during
  bufferization.
  
  In case of a sparse tensor, this op releases the underlying sparse storage
  format for a tensor that materialized earlier through a `new` operation, a
  `convert` operation with annotated destination tensor type (unless the
  convert is folded away), or a `bufferization.alloc_tensor` operation. The
  release operation should only be called once for any materialized tensor.
  After this operation, any subsequent `memref` querying operation on the
  tensor returns undefined results.
  
  Example:
  
  ```mlir
  bufferization.dealloc_tensor %tensor : tensor<1024x1024xf64, #CSR>
  ```
  """

  OPERATION_NAME = "bufferization.dealloc_tensor"

  _ODS_REGIONS = (0, True)

  def __init__(self, tensor: _ods_ir.Value, *, loc: _Optional[_ods_ir.Location] = None, ip: _Optional[_ods_ir.InsertionPoint] = None):
    operands = []
    attributes = {}
    regions = None
    operands.append(tensor)
    _ods_context = _ods_get_default_loc_context(loc)
    results = []
    _ods_successors = None
    super().__init__(self.OPERATION_NAME, self._ODS_REGIONS, self._ODS_OPERAND_SEGMENTS, self._ODS_RESULT_SEGMENTS, attributes=attributes, results=results, operands=operands, successors=_ods_successors, regions=regions, loc=loc, ip=ip)

  @builtins.property
  def tensor(self) -> _ods_ir.Value:
    return self.operation.operands[0]

@_ods_cext.register_op_adaptor(DeallocTensorOp)
class DeallocTensorOpAdaptor(_ods_ir.OpAdaptor):
  OPERATION_NAME = "bufferization.dealloc_tensor"

  @builtins.property
  def tensor(self) -> _ods_ir.Value:
    return self.operands[0]

def dealloc_tensor(tensor: _ods_ir.Value, *, loc: _Optional[_ods_ir.Location] = None, ip: _Optional[_ods_ir.InsertionPoint] = None) -> DeallocTensorOp:
  return DeallocTensorOp(tensor=tensor, loc=loc, ip=ip)

@_ods_cext.register_operation(_Dialect)
class MaterializeInDestinationOp(_ods_ir.OpView):
  r"""
  This op indicates that the data of the `source` tensor is guaranteed to
  materialize in `dest`, which can be a tensor or a memref. In case of a
  tensor, `source` materializes in the future buffer of `dest` and a the
  updated destination tensor is returned. If this is not possible, e.g.,
  because the destination tensor is read-only or because its original
  contents are still read later, the input IR fails to bufferize. In case of a
  memref, `source` materializes in `dest`, which is already a buffer. The op
  has no results in that case.
  
  `source`, `dest` and `result` (if present) must have the same runtime shape
  and element type. If the op has a result, the types of `result` and `dest`
  must match exactly (e.g., including any tensor encodings).
  
  By default, this op bufferizes to a memcpy from the future buffer of the
  `source` tensor to the future buffer of the `dest` tensor or to the `dest`
  buffer. However, transformations such as "empty tensor elimination" may
  rewrite IR such that a computation is performed directly in `dest` and no
  memcpy is needed.
  
  If `dest` is a buffer, the `writable` attribute must be specified and the
  `restrict` keyword can be specified. These attributes have the same meaning
  as the respective attributes of `bufferization.to_tensor`.
  
  `writable` indicates that the `dest` buffer is considered writable. It does
  not make sense to materialize a computation in a read-only buffer, so
  `writable` is required.
  
  `restrict` indicates that there is no `bufferization.to_tensor` op and no
  other `bufferization.materialize_in_destination` op with `dest` (or an alias
  thereof) and "restrict". Only ops with this attribute are considered for
  "empty tensor elimination". As part of empty tensor elimination, a new
  `to_tensor` op with `dest` may be inserted and the `restrict` attribute is
  transferred from this op to the new `to_tensor` op. Having "restrict" on
  this op guarantees that performing empty tensor elimination would not create
  invalid IR (i.e., having multiple `to_tensor restrict` with aliasing
  buffers).
  
  Note: `writable` could be removed from this op because it must always be set
  for memref destinations. This op has that attribute to make clear the
  requirements on the `dest` operand in the op assembly format.
  
  Note: If `dest` is a tensor, `tensor.insert_slice` could be used for the
  same purpose, but since tensor dialect ops only indicate *what* should be
  computed but not *where*, it could fold away, causing the computation to
  materialize in a different buffer.
  """

  OPERATION_NAME = "bufferization.materialize_in_destination"

  _ODS_REGIONS = (0, True)

  def __init__(self, result: _Optional[_ods_ir.Type], source: _ods_ir.Value, dest: _ods_ir.Value, *, restrict: _Optional[bool] = None, writable: _Optional[bool] = None, loc: _Optional[_ods_ir.Location] = None, ip: _Optional[_ods_ir.InsertionPoint] = None):
    operands = []
    attributes = {}
    regions = None
    operands.append(source)
    operands.append(dest)
    _ods_context = _ods_get_default_loc_context(loc)
    if bool(restrict): attributes["restrict"] = _ods_ir.UnitAttr.get(
      _ods_get_default_loc_context(loc))
    if bool(writable): attributes["writable"] = _ods_ir.UnitAttr.get(
      _ods_get_default_loc_context(loc))
    results = []
    if result is not None: results.append(result)
    _ods_successors = None
    super().__init__(self.OPERATION_NAME, self._ODS_REGIONS, self._ODS_OPERAND_SEGMENTS, self._ODS_RESULT_SEGMENTS, attributes=attributes, results=results, operands=operands, successors=_ods_successors, regions=regions, loc=loc, ip=ip)

  @builtins.property
  def source(self) -> _ods_ir.Value:
    return self.operation.operands[0]

  @builtins.property
  def dest(self) -> _ods_ir.Value:
    return self.operation.operands[1]

  @builtins.property
  def restrict(self) -> bool:
    return "restrict" in self.operation.attributes

  @restrict.setter
  def restrict(self, value):
    if bool(value):
      self.operation.attributes["restrict"] = _ods_ir.UnitAttr.get()
    elif "restrict" in self.operation.attributes:
      del self.operation.attributes["restrict"]

  @restrict.deleter
  def restrict(self):
    del self.operation.attributes["restrict"]

  @builtins.property
  def writable(self) -> bool:
    return "writable" in self.operation.attributes

  @writable.setter
  def writable(self, value):
    if bool(value):
      self.operation.attributes["writable"] = _ods_ir.UnitAttr.get()
    elif "writable" in self.operation.attributes:
      del self.operation.attributes["writable"]

  @writable.deleter
  def writable(self):
    del self.operation.attributes["writable"]

  @builtins.property
  def result(self) -> _Optional[_ods_ir.OpResult]:
    return None if len(self.operation.results) < 1 else self.operation.results[0]

@_ods_cext.register_op_adaptor(MaterializeInDestinationOp)
class MaterializeInDestinationOpAdaptor(_ods_ir.OpAdaptor):
  OPERATION_NAME = "bufferization.materialize_in_destination"

  @builtins.property
  def source(self) -> _ods_ir.Value:
    return self.operands[0]

  @builtins.property
  def dest(self) -> _ods_ir.Value:
    return self.operands[1]

  @builtins.property
  def restrict(self) -> bool:
    return "restrict" in self.attributes

  @builtins.property
  def writable(self) -> bool:
    return "writable" in self.attributes

def materialize_in_destination(result: _Optional[_ods_ir.Type], source: _ods_ir.Value, dest: _ods_ir.Value, *, restrict: _Optional[bool] = None, writable: _Optional[bool] = None, loc: _Optional[_ods_ir.Location] = None, ip: _Optional[_ods_ir.InsertionPoint] = None) -> _Union[_ods_ir.OpResult, _ods_ir.OpResultList, MaterializeInDestinationOp]:
  op = MaterializeInDestinationOp(result=result, source=source, dest=dest, restrict=restrict, writable=writable, loc=loc, ip=ip); results = op.results
  return results if len(results) > 1 else (results[0] if len(results) == 1 else op)

@_ods_cext.register_operation(_Dialect)
class ToBufferOp(_ods_ir.OpView):
  r"""
  An operation that returns the future buffer of a `tensor`.
  
  ```mlir
  // Result type is memref<4x?xf32, #layout, 0>
  %m = bufferization.to_buffer %t : tensor<4x?xf32> to memref<4x?xf32, #layout, 0>
  ```
  
  This operation is a specialized variant of the built-in
  `unrealized_conversion_cast` and is used to make sure that the IR stays
  valid at any point during the bufferization.
  
  The `read_only` attribute can optionally be set, indicating to the
  bufferization that the buffer returned by this op (or an alias created from
  the returned buffer) will not be written to.
  """

  OPERATION_NAME = "bufferization.to_buffer"

  _ODS_REGIONS = (0, True)

  def __init__(self, buffer: _ods_ir.Type, tensor: _ods_ir.Value, *, read_only: _Optional[bool] = None, loc: _Optional[_ods_ir.Location] = None, ip: _Optional[_ods_ir.InsertionPoint] = None):
    operands = []
    attributes = {}
    regions = None
    operands.append(tensor)
    _ods_context = _ods_get_default_loc_context(loc)
    if bool(read_only): attributes["read_only"] = _ods_ir.UnitAttr.get(
      _ods_get_default_loc_context(loc))
    results = []
    results.append(buffer)
    _ods_successors = None
    super().__init__(self.OPERATION_NAME, self._ODS_REGIONS, self._ODS_OPERAND_SEGMENTS, self._ODS_RESULT_SEGMENTS, attributes=attributes, results=results, operands=operands, successors=_ods_successors, regions=regions, loc=loc, ip=ip)

  @builtins.property
  def tensor(self) -> _ods_ir.Value:
    return self.operation.operands[0]

  @builtins.property
  def read_only(self) -> bool:
    return "read_only" in self.operation.attributes

  @read_only.setter
  def read_only(self, value):
    if bool(value):
      self.operation.attributes["read_only"] = _ods_ir.UnitAttr.get()
    elif "read_only" in self.operation.attributes:
      del self.operation.attributes["read_only"]

  @read_only.deleter
  def read_only(self):
    del self.operation.attributes["read_only"]

  @builtins.property
  def buffer(self) -> _ods_ir.OpResult:
    return self.operation.results[0]

@_ods_cext.register_op_adaptor(ToBufferOp)
class ToBufferOpAdaptor(_ods_ir.OpAdaptor):
  OPERATION_NAME = "bufferization.to_buffer"

  @builtins.property
  def tensor(self) -> _ods_ir.Value:
    return self.operands[0]

  @builtins.property
  def read_only(self) -> bool:
    return "read_only" in self.attributes

def to_buffer(buffer: _ods_ir.Type, tensor: _ods_ir.Value, *, read_only: _Optional[bool] = None, loc: _Optional[_ods_ir.Location] = None, ip: _Optional[_ods_ir.InsertionPoint] = None) -> _ods_ir.OpResult:
  return ToBufferOp(buffer=buffer, tensor=tensor, read_only=read_only, loc=loc, ip=ip).result

@_ods_cext.register_operation(_Dialect)
class ToTensorOp(_ods_ir.OpView):
  r"""
  An operation that creates a tensor from a buffer. The result value is a
  tensor-like type that must match the corresponding buffer-like operand as
  per TensorLikeType::verifyCompatibleBufferType(). For builtins (TensorType
  and BaseMemRefType), this means that shapes and element types match between
  the tensor and the buffer.
  
  The opposite of this op is `to_buffer`. Together, these two ops are
  useful for source/target materializations when doing type conversions
  involving tensors and buffers.
  
  Example:
  
  ```mlir
  // Produces a value of tensor<4x?xf32> type.
  %t = bufferization.to_tensor %m : memref<4x?xf32, #layout, 0> to tensor<4x?xf32>
  ```
  
  If the `writable` unit attribute is set, the produced tensor is considered
  "writable" during bufferization. Otherwise, every OpOperand that bufferizes
  to a write to the future buffer of the resulting tensor (or an alias
  thereof) will bufferize out-of-place to prevent emitting any writes to
  `memref` during bufferization.
  
  The `restrict` unit attribute (similar to the C `restrict` keyword)
  indicates that the produced tensor result is the only way for the tensor
  IR to gain access to the `memref` operand (or an alias thereof). E.g.,
  there must be no other `to_tensor` op with the same or with an aliasing
  `memref` operand.
  
  Note: Only `to_tensor` ops with the `restrict` unit attribute are supported
  by One-Shot Bufferize. Other IR is rejected. (To support `to_tensor`
  without `restrict`, One-Shot Bufferize would have to analyze memref IR.)
  Ops that have incorrect usage of `restrict` may bufferize incorrectly.
  
  Example:
  
  ```
  %t = bufferization.to_tensor %m restrict writable : memref<4xf32> to tensor<4xf32>
  
  // %t is writable, so the tensor.insert may bufferize in-place in the
  // absence of other conflicts.
  %r = tensor.insert %f into %t[%idx] : tensor<4xf32>
  ```
  
  `to_tensor` ops are not bufferized. They are expected to fold away after
  bufferization. If there are non-bufferizable ops in the IR and
  `allowUnknownOps` is set, they may be part of the resulting IR and not fold
  away. However, such IR is no longer bufferizable with One-Shot Bufferize.
  """

  OPERATION_NAME = "bufferization.to_tensor"

  _ODS_REGIONS = (0, True)

  def __init__(self, result: _ods_ir.Type, buffer: _ods_ir.Value, *, restrict: _Optional[bool] = None, writable: _Optional[bool] = None, loc: _Optional[_ods_ir.Location] = None, ip: _Optional[_ods_ir.InsertionPoint] = None):
    operands = []
    attributes = {}
    regions = None
    operands.append(buffer)
    _ods_context = _ods_get_default_loc_context(loc)
    if bool(restrict): attributes["restrict"] = _ods_ir.UnitAttr.get(
      _ods_get_default_loc_context(loc))
    if bool(writable): attributes["writable"] = _ods_ir.UnitAttr.get(
      _ods_get_default_loc_context(loc))
    results = []
    results.append(result)
    _ods_successors = None
    super().__init__(self.OPERATION_NAME, self._ODS_REGIONS, self._ODS_OPERAND_SEGMENTS, self._ODS_RESULT_SEGMENTS, attributes=attributes, results=results, operands=operands, successors=_ods_successors, regions=regions, loc=loc, ip=ip)

  @builtins.property
  def buffer(self) -> _ods_ir.Value:
    return self.operation.operands[0]

  @builtins.property
  def restrict(self) -> bool:
    return "restrict" in self.operation.attributes

  @restrict.setter
  def restrict(self, value):
    if bool(value):
      self.operation.attributes["restrict"] = _ods_ir.UnitAttr.get()
    elif "restrict" in self.operation.attributes:
      del self.operation.attributes["restrict"]

  @restrict.deleter
  def restrict(self):
    del self.operation.attributes["restrict"]

  @builtins.property
  def writable(self) -> bool:
    return "writable" in self.operation.attributes

  @writable.setter
  def writable(self, value):
    if bool(value):
      self.operation.attributes["writable"] = _ods_ir.UnitAttr.get()
    elif "writable" in self.operation.attributes:
      del self.operation.attributes["writable"]

  @writable.deleter
  def writable(self):
    del self.operation.attributes["writable"]

  @builtins.property
  def result(self) -> _ods_ir.OpResult:
    return self.operation.results[0]

@_ods_cext.register_op_adaptor(ToTensorOp)
class ToTensorOpAdaptor(_ods_ir.OpAdaptor):
  OPERATION_NAME = "bufferization.to_tensor"

  @builtins.property
  def buffer(self) -> _ods_ir.Value:
    return self.operands[0]

  @builtins.property
  def restrict(self) -> bool:
    return "restrict" in self.attributes

  @builtins.property
  def writable(self) -> bool:
    return "writable" in self.attributes

def to_tensor(result: _ods_ir.Type, buffer: _ods_ir.Value, *, restrict: _Optional[bool] = None, writable: _Optional[bool] = None, loc: _Optional[_ods_ir.Location] = None, ip: _Optional[_ods_ir.InsertionPoint] = None) -> _ods_ir.OpResult:
  return ToTensorOp(result=result, buffer=buffer, restrict=restrict, writable=writable, loc=loc, ip=ip).result
