Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 23 additions & 23 deletions mlx/backend/metal/kernels/copy.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ template <typename T, typename U, int N = WorkPerThread<U>::n>
index *= N;
if (N > 1 && index + N > size) {
for (int i = 0; index + i < size; ++i) {
dst[index + i] = static_cast<U>(src[0]);
dst[index + i] = mlx_cast<U>(src[0]);
}
} else {
for (int i = 0; i < N; ++i) {
dst[index + i] = static_cast<U>(src[0]);
dst[index + i] = mlx_cast<U>(src[0]);
}
}
}
Expand All @@ -27,11 +27,11 @@ template <typename T, typename U, int N = WorkPerThread<U>::n>
index *= N;
if (N > 1 && index + N > size) {
for (int i = 0; index + i < size; ++i) {
dst[index + i] = static_cast<U>(src[index + i]);
dst[index + i] = mlx_cast<U>(src[index + i]);
}
} else {
for (int i = 0; i < N; ++i) {
dst[index + i] = static_cast<U>(src[index + i]);
dst[index + i] = mlx_cast<U>(src[index + i]);
}
}
}
Expand All @@ -46,11 +46,11 @@ template <typename T, typename U, int N = WorkPerThread<U>::n>
int64_t offset = N * (index.x + grid_dim.x * int64_t(index.y));
if (N > 1 && offset + N > size) {
for (int i = 0; offset + i < size; ++i) {
dst[offset + i] = static_cast<U>(src[0]);
dst[offset + i] = mlx_cast<U>(src[0]);
}
} else {
for (int i = 0; i < N; ++i) {
dst[offset + i] = static_cast<U>(src[0]);
dst[offset + i] = mlx_cast<U>(src[0]);
}
}
}
Expand All @@ -65,11 +65,11 @@ template <typename T, typename U, int N = WorkPerThread<U>::n>
int64_t offset = N * (index.x + grid_dim.x * int64_t(index.y));
if (N > 1 && offset + N > size) {
for (int i = 0; offset + i < size; ++i) {
dst[offset + i] = static_cast<U>(src[offset + i]);
dst[offset + i] = mlx_cast<U>(src[offset + i]);
}
} else {
for (int i = 0; i < N; ++i) {
dst[offset + i] = static_cast<U>(src[offset + i]);
dst[offset + i] = mlx_cast<U>(src[offset + i]);
}
}
}
Expand All @@ -81,7 +81,7 @@ template <typename T, typename U, typename IdxT = int64_t>
constant const int64_t& src_stride [[buffer(3)]],
uint index [[thread_position_in_grid]]) {
auto src_idx = elem_to_loc_1<IdxT>(index, src_stride);
dst[index] = static_cast<U>(src[src_idx]);
dst[index] = mlx_cast<U>(src[src_idx]);
}

template <typename T, typename U, typename IdxT = int64_t>
Expand All @@ -93,7 +93,7 @@ template <typename T, typename U, typename IdxT = int64_t>
uint2 grid_dim [[threads_per_grid]]) {
auto src_idx = elem_to_loc_2<IdxT>(index, src_strides);
IdxT dst_idx = index.x + IdxT(grid_dim.x) * index.y;
dst[dst_idx] = static_cast<U>(src[src_idx]);
dst[dst_idx] = mlx_cast<U>(src[src_idx]);
}

template <typename T, typename U, typename IdxT = int64_t>
Expand All @@ -106,7 +106,7 @@ template <typename T, typename U, typename IdxT = int64_t>
auto src_idx = elem_to_loc_3<IdxT>(index, src_strides);
IdxT dst_idx =
index.x + IdxT(grid_dim.x) * (index.y + IdxT(grid_dim.y) * index.z);
dst[dst_idx] = static_cast<U>(src[src_idx]);
dst[dst_idx] = mlx_cast<U>(src[src_idx]);
}

template <typename T, typename U, int N = 1, typename IdxT = int64_t>
Expand All @@ -123,14 +123,14 @@ template <typename T, typename U, int N = 1, typename IdxT = int64_t>
if (N == 1) {
IdxT dst_idx =
index.x + grid_dim.x * (index.y + IdxT(grid_dim.y) * index.z);
dst[dst_idx] = static_cast<U>(src[src_idx]);
dst[dst_idx] = mlx_cast<U>(src[src_idx]);
return;
}
auto xshape = src_shape[ndim - 1];
IdxT dst_idx = N * index.x + xshape * (index.y + IdxT(grid_dim.y) * index.z);
auto src_xstride = src_strides[ndim - 1];
for (int i = 0; i < N && (int(N * index.x) + i) < xshape; ++i) {
dst[dst_idx + i] = static_cast<U>(src[src_idx]);
dst[dst_idx + i] = mlx_cast<U>(src[src_idx]);
src_idx += src_xstride;
}
}
Expand All @@ -144,7 +144,7 @@ template <typename T, typename U, typename IdxT = int64_t>
uint index [[thread_position_in_grid]]) {
auto src_idx = elem_to_loc_1<IdxT>(index, src_stride);
auto dst_idx = elem_to_loc_1<IdxT>(index, dst_stride);
dst[dst_idx] = static_cast<U>(src[src_idx]);
dst[dst_idx] = mlx_cast<U>(src[src_idx]);
}

template <typename T, typename U, typename IdxT = int64_t>
Expand All @@ -156,7 +156,7 @@ template <typename T, typename U, typename IdxT = int64_t>
uint2 index [[thread_position_in_grid]]) {
auto src_idx = elem_to_loc_2<IdxT>(index, src_strides);
auto dst_idx = elem_to_loc_2<IdxT>(index, dst_strides);
dst[dst_idx] = static_cast<U>(src[src_idx]);
dst[dst_idx] = mlx_cast<U>(src[src_idx]);
}

template <typename T, typename U, typename IdxT = int64_t>
Expand All @@ -168,7 +168,7 @@ template <typename T, typename U, typename IdxT = int64_t>
uint3 index [[thread_position_in_grid]]) {
auto src_idx = elem_to_loc_3<IdxT>(index, src_strides);
auto dst_idx = elem_to_loc_3<IdxT>(index, dst_strides);
dst[dst_idx] = static_cast<U>(src[src_idx]);
dst[dst_idx] = mlx_cast<U>(src[src_idx]);
}

template <typename T, typename U, int N = 1, typename IdxT = int64_t>
Expand All @@ -187,14 +187,14 @@ template <typename T, typename U, int N = 1, typename IdxT = int64_t>
dst_strides,
ndim);
if (N == 1) {
dst[idx.y] = static_cast<U>(src[idx.x]);
dst[idx.y] = mlx_cast<U>(src[idx.x]);
return;
}
IdxT src_xstride = src_strides[ndim - 1];
IdxT dst_xstride = dst_strides[ndim - 1];
auto xshape = src_shape[ndim - 1];
for (int i = 0; i < N && (int(N * index.x) + i) < xshape; ++i) {
dst[idx.y] = static_cast<U>(src[idx.x]);
dst[idx.y] = mlx_cast<U>(src[idx.x]);
idx.x += src_xstride;
idx.y += dst_xstride;
}
Expand All @@ -211,7 +211,7 @@ template <typename T, typename U, typename IdxT = int64_t>
uint index [[thread_position_in_grid]]) {
auto src_idx = elem_to_loc_1<IdxT>(index, src_stride);
auto dst_idx = elem_to_loc_1<IdxT>(index, dst_stride);
dst[dst_idx + dst_offset] = src[src_idx + src_offset];
dst[dst_idx + dst_offset] = mlx_cast<U>(src[src_idx + src_offset]);
}

template <typename T, typename U, typename IdxT = int64_t>
Expand All @@ -225,7 +225,7 @@ template <typename T, typename U, typename IdxT = int64_t>
uint2 index [[thread_position_in_grid]]) {
auto src_idx = elem_to_loc_2<IdxT>(index, src_strides);
auto dst_idx = elem_to_loc_2<IdxT>(index, dst_strides);
dst[dst_idx + dst_offset] = src[src_idx + src_offset];
dst[dst_idx + dst_offset] = mlx_cast<U>(src[src_idx + src_offset]);
}

template <typename T, typename U, typename IdxT = int64_t>
Expand All @@ -239,7 +239,7 @@ template <typename T, typename U, typename IdxT = int64_t>
uint3 index [[thread_position_in_grid]]) {
auto src_idx = elem_to_loc_3<IdxT>(index, src_strides);
auto dst_idx = elem_to_loc_3<IdxT>(index, dst_strides);
dst[dst_idx + dst_offset] = src[src_idx + src_offset];
dst[dst_idx + dst_offset] = mlx_cast<U>(src[src_idx + src_offset]);
}

template <typename T, typename U, int N = 1, typename IdxT = int64_t>
Expand All @@ -262,14 +262,14 @@ template <typename T, typename U, int N = 1, typename IdxT = int64_t>
dst_strides,
ndim);
if (N == 1) {
dst[idx.y] = src[idx.x];
dst[idx.y] = mlx_cast<U>(src[idx.x]);
return;
}
IdxT src_xstride = src_strides[ndim - 1];
IdxT dst_xstride = dst_strides[ndim - 1];
auto xshape = src_shape[ndim - 1];
for (int i = 0; i < N && (int(N * index.x) + i) < xshape; ++i) {
dst[idx.y] = src[idx.x];
dst[idx.y] = mlx_cast<U>(src[idx.x]);
idx.x += src_xstride;
idx.y += dst_xstride;
}
Expand Down
4 changes: 2 additions & 2 deletions mlx/backend/metal/kernels/reduction/reduce_all.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ template <

for (IdxT b = 0; b < blocks; b++) {
for (int i = 0; i < N_READS; i++) {
total = op(static_cast<U>(in[i]), total);
total = op(mlx_cast<U>(in[i]), total);
}
in += lsize.x * N_READS;
}
if (extra > 0) {
for (int i = 0; i < extra; i++) {
total = op(static_cast<U>(in[i]), total);
total = op(mlx_cast<U>(in[i]), total);
}
}

Expand Down
14 changes: 7 additions & 7 deletions mlx/backend/metal/kernels/reduction/reduce_col.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ template <typename T, typename U, typename Op, typename IdxT, int NDIMS>
row = in + loop.location();
if (safe) {
for (int i = 0; i < n_reads; i++) {
totals[i] = op(static_cast<U>(row[i]), totals[i]);
totals[i] = op(mlx_cast<U>(row[i]), totals[i]);
}
} else {
U vals[n_reads];
for (int i = 0; i < n_reads; i++) {
vals[i] =
(column + i < reduction_stride) ? static_cast<U>(row[i]) : op.init;
(column + i < reduction_stride) ? mlx_cast<U>(row[i]) : op.init;
}
for (int i = 0; i < n_reads; i++) {
totals[i] = op(vals[i], totals[i]);
Expand Down Expand Up @@ -125,7 +125,7 @@ template <typename T, typename U, typename Op, typename IdxT, int NDIMS>
for (IdxT r = gid.z * lsize.y + lid.y; r < total_rows;
r += lsize.y * gsize.z) {
row = in + loop.location();
total = op(static_cast<U>(*row), total);
total = op(mlx_cast<U>(*row), total);
loop.next(lsize.y * gsize.z, reduce_shape, reduce_strides);
}

Expand Down Expand Up @@ -207,13 +207,13 @@ template <

if (safe) {
for (int i = 0; i < n_reads; i++) {
totals[i] = op(static_cast<U>(row[i]), totals[i]);
totals[i] = op(mlx_cast<U>(row[i]), totals[i]);
}
} else {
U vals[n_reads];
for (int i = 0; i < n_reads; i++) {
vals[i] =
(column + i < reduction_stride) ? static_cast<U>(row[i]) : op.init;
(column + i < reduction_stride) ? mlx_cast<U>(row[i]) : op.init;
}
for (int i = 0; i < n_reads; i++) {
totals[i] = op(vals[i], totals[i]);
Expand Down Expand Up @@ -352,13 +352,13 @@ template <

if (safe) {
for (int i = 0; i < n_reads; i++) {
totals[i] = op(static_cast<U>(row[i]), totals[i]);
totals[i] = op(mlx_cast<U>(row[i]), totals[i]);
}
} else {
U vals[n_reads];
for (int i = 0; i < n_reads; i++) {
vals[i] =
(column + i < reduction_stride) ? static_cast<U>(row[i]) : op.init;
(column + i < reduction_stride) ? mlx_cast<U>(row[i]) : op.init;
}
for (int i = 0; i < n_reads; i++) {
totals[i] = op(vals[i], totals[i]);
Expand Down
6 changes: 3 additions & 3 deletions mlx/backend/metal/kernels/reduction/reduce_row.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ METAL_FUNC void per_thread_row_reduce(
for (int i = 0; i < blocks; i++) {
for (int j = 0; j < N_WRITES; j++) {
for (int i = 0; i < N_READS; i++) {
totals[j] = op(static_cast<U>(inputs[j][i]), totals[j]);
totals[j] = op(mlx_cast<U>(inputs[j][i]), totals[j]);
}

inputs[j] += lsize_x * N_READS;
Expand All @@ -46,13 +46,13 @@ METAL_FUNC void per_thread_row_reduce(
if (index + N_READS <= extra) {
for (int j = 0; j < N_WRITES; j++) {
for (int i = 0; i < N_READS; i++) {
totals[j] = op(static_cast<U>(inputs[j][i]), totals[j]);
totals[j] = op(mlx_cast<U>(inputs[j][i]), totals[j]);
}
}
} else {
for (int j = 0; j < N_WRITES; j++) {
for (int i = 0; index + i < extra; i++) {
totals[j] = op(static_cast<U>(inputs[j][i]), totals[j]);
totals[j] = op(mlx_cast<U>(inputs[j][i]), totals[j]);
}
}
}
Expand Down
29 changes: 29 additions & 0 deletions mlx/backend/metal/kernels/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -446,3 +446,32 @@ template <typename T, typename U>
struct ConditionalType<true, T, U> {
using type = T;
};

///////////////////////////////////////////////////////////////////////////////
// Type casting utils
///////////////////////////////////////////////////////////////////////////////

template <typename U, typename T>
inline U mlx_cast(T val) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In cuda backend there is a similar utility named cast_to, I think we can use the same name here.

return static_cast<U>(val);
}

template <>
inline bool mlx_cast<bool, float>(float val) {
return (as_type<uint32_t>(val) & 0x7FFFFFFF) != 0;
}

template <>
inline bool mlx_cast<bool, bfloat16_t>(bfloat16_t val) {
return (as_type<uint16_t>(val) & 0x7FFF) != 0;
}

template <>
inline bool mlx_cast<bool, half>(half val) {
return (as_type<uint16_t>(val) & 0x7FFF) != 0;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

float16 does not seem to need this, should add a test.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, looks like half values are not affected in MSL. Thanks for the suggestion.

}

template <>
inline bool mlx_cast<bool, complex64_t>(complex64_t val) {
return mlx_cast<bool, float>(val.real) || mlx_cast<bool, float>(val.imag);
}
11 changes: 11 additions & 0 deletions python/tests/test_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -1299,6 +1299,17 @@ def test_any(self):
self.assertEqual(mx.any(a, axis=0).tolist(), [True, False])
self.assertEqual(mx.any(a, axis=1).tolist(), [True, False])

def test_subnormal_bool_cast(self):
f32_sub = mx.array(np.array([0x00000001], dtype=np.uint32)).view(mx.float32)
bf16_sub = mx.array(np.array([0x0001], dtype=np.uint16)).view(mx.bfloat16)

self.assertTrue(f32_sub.astype(mx.bool_).item())
self.assertTrue(bf16_sub.astype(mx.bool_).item())
self.assertTrue(mx.any(f32_sub).item())
self.assertTrue(mx.any(bf16_sub).item())
self.assertTrue(mx.all(f32_sub).item())
self.assertTrue(mx.all(bf16_sub).item())

def test_stop_gradient(self):
def func(x):
return mx.sum(2 * x + mx.stop_gradient(3 * x))
Expand Down
Loading