Rollup merge of #137953 - RalfJung:simd-intrinsic-masks, r=WaffleLapkin

simd intrinsics with mask: accept unsigned integer masks, and fix some of the errors

It's not clear at all why the mask would have to be signed, it is anyway interpreted bitwise. The backend should just make sure that works no matter the surface-level type; our LLVM backend already does this correctly. The note of "the mask may be widened, which only has the correct behavior for signed integers" explains... nothing? Why can't the code do the widening correctly? If necessary, just cast to the signed type first...

Also while we are at it, fix the errors. For simd_masked_load/store, the errors talked about the "third argument" but they meant the first argument (the mask is the first argument there). They also used the wrong type for `expected_element`.

I have extremely low confidence in the GCC part of this PR.

See [discussion on Zulip](https://rust-lang.zulipchat.com/#narrow/channel/257879-project-portable-simd/topic/On.20the.20sign.20of.20masks)
This commit is contained in:
Chris Denton 2025-04-20 13:02:48 +00:00 committed by GitHub
commit d15c603173
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 119 additions and 148 deletions

View file

@ -1184,18 +1184,6 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
}};
}
/// Returns the bitwidth of the `$ty` argument if it is an `Int` type.
macro_rules! require_int_ty {
($ty: expr, $diag: expr) => {
match $ty {
ty::Int(i) => i.bit_width().unwrap_or_else(|| bx.data_layout().pointer_size.bits()),
_ => {
return_error!($diag);
}
}
};
}
/// Returns the bitwidth of the `$ty` argument if it is an `Int` or `Uint` type.
macro_rules! require_int_or_uint_ty {
($ty: expr, $diag: expr) => {
@ -1485,9 +1473,9 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
m_len == v_len,
InvalidMonomorphization::MismatchedLengths { span, name, m_len, v_len }
);
let in_elem_bitwidth = require_int_ty!(
let in_elem_bitwidth = require_int_or_uint_ty!(
m_elem_ty.kind(),
InvalidMonomorphization::MaskType { span, name, ty: m_elem_ty }
InvalidMonomorphization::MaskWrongElementType { span, name, ty: m_elem_ty }
);
let m_i1s = vector_mask_to_bitmask(bx, args[0].immediate(), in_elem_bitwidth, m_len);
return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate()));
@ -1508,7 +1496,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
// Integer vector <i{in_bitwidth} x in_len>:
let in_elem_bitwidth = require_int_or_uint_ty!(
in_elem.kind(),
InvalidMonomorphization::VectorArgument { span, name, in_ty, in_elem }
InvalidMonomorphization::MaskWrongElementType { span, name, ty: in_elem }
);
let i1xn = vector_mask_to_bitmask(bx, args[0].immediate(), in_elem_bitwidth, in_len);
@ -1732,14 +1720,9 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
}
);
let mask_elem_bitwidth = require_int_ty!(
let mask_elem_bitwidth = require_int_or_uint_ty!(
element_ty2.kind(),
InvalidMonomorphization::ThirdArgElementType {
span,
name,
expected_element: element_ty2,
third_arg: arg_tys[2]
}
InvalidMonomorphization::MaskWrongElementType { span, name, ty: element_ty2 }
);
// Alignment of T, must be a constant integer value:
@ -1834,14 +1817,9 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
}
);
let m_elem_bitwidth = require_int_ty!(
let m_elem_bitwidth = require_int_or_uint_ty!(
mask_elem.kind(),
InvalidMonomorphization::ThirdArgElementType {
span,
name,
expected_element: values_elem,
third_arg: mask_ty,
}
InvalidMonomorphization::MaskWrongElementType { span, name, ty: mask_elem }
);
let mask = vector_mask_to_bitmask(bx, args[0].immediate(), m_elem_bitwidth, mask_len);
@ -1924,14 +1902,9 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
}
);
let m_elem_bitwidth = require_int_ty!(
let m_elem_bitwidth = require_int_or_uint_ty!(
mask_elem.kind(),
InvalidMonomorphization::ThirdArgElementType {
span,
name,
expected_element: values_elem,
third_arg: mask_ty,
}
InvalidMonomorphization::MaskWrongElementType { span, name, ty: mask_elem }
);
let mask = vector_mask_to_bitmask(bx, args[0].immediate(), m_elem_bitwidth, mask_len);
@ -2019,15 +1992,10 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
}
);
// The element type of the third argument must be a signed integer type of any width:
let mask_elem_bitwidth = require_int_ty!(
// The element type of the third argument must be an integer type of any width:
let mask_elem_bitwidth = require_int_or_uint_ty!(
element_ty2.kind(),
InvalidMonomorphization::ThirdArgElementType {
span,
name,
expected_element: element_ty2,
third_arg: arg_tys[2]
}
InvalidMonomorphization::MaskWrongElementType { span, name, ty: element_ty2 }
);
// Alignment of T, must be a constant integer value: