///|
fn WgslIrLowerer::lower_function_atomic_call(
  self : WgslIrLowerer,
  atomic_function : AtomicFunction,
  arguments : Array[@ast.WgslExprNode],
  function : Function,
  scope : WgslIrFunctionScope,
) -> Handle raise WgslIrLowerError {
  let arguments = wgsl_ir_flatten_expression_arguments(arguments)
  let expected = match atomic_function {
    Load => 1
    Store => 2
    Add | Subtract | And | ExclusiveOr | InclusiveOr | Min | Max | Exchange => 2
    CompareExchangeWeak => 3
  }
  if arguments.length() != expected {
    raise UnsupportedExpression(
      "\{wgsl_ir_atomic_function_name(atomic_function)} expects \{expected} arguments",
    )
  }
  if atomic_function == Load {
    guard arguments is [pointer_argument] else {
      raise UnsupportedExpression("atomicLoad expects 1 argument")
    }
    return function.expressions.append(
      Load(
        self.lower_atomic_pointer_argument(pointer_argument, function, scope),
      ),
    )
  }
  let handles : Array[Handle] = []
  for index in 0..
        ignore(
          self.predeclared_struct_type(AtomicCompareExchangeWeakResult(scalar)),
        )
      None => ()
    }
  }
  function.expressions.append(AtomicCall(atomic_function, handles))
}

///|
fn WgslIrLowerer::atomic_call_result_scalar_type(
  self : WgslIrLowerer,
  function : Function,
  arguments : Array[Handle],
) -> Scalar? {
  guard arguments is [pointer, .. rest] else { return None }
  match self.atomic_pointer_scalar_type(function, pointer) {
    Some(scalar) => Some(scalar)
    None =>
      match rest {
        [value, ..] =>
          match self.function_expression_type(function, value) {
            Some(ty) => self.scalar_from_numeric_type_handle(ty)
            None => None
          }
        [] => None
      }
  }
}

///|
fn WgslIrLowerer::lower_atomic_pointer_argument(
  self : WgslIrLowerer,
  argument : @ast.WgslExprNode,
  function : Function,
  scope : WgslIrFunctionScope,
) -> Handle raise WgslIrLowerError {
  match wgsl_ir_address_of_operand_node(argument) {
    Some(target) => self.lower_function_lvalue_node(target, function, scope)
    None => self.lower_function_expression_node(argument, function, scope)
  }
}