Skip to content

Commit b935f37

Browse files
committed
implement carryless_mul
1 parent 5d04477 commit b935f37

15 files changed

Lines changed: 569 additions & 5 deletions

File tree

compiler/rustc_codegen_llvm/src/intrinsic.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,27 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
387387
let pair = self.insert_value(pair, high, 1);
388388
pair
389389
}
390+
391+
// FIXME move into the branch below when LLVM 22 is the lowest version we support.
392+
sym::carryless_mul if crate::llvm_util::get_version() >= (22, 0, 0) => {
393+
let ty = args[0].layout.ty;
394+
if !ty.is_integral() {
395+
tcx.dcx().emit_err(InvalidMonomorphization::BasicIntegerType {
396+
span,
397+
name,
398+
ty,
399+
});
400+
return Ok(());
401+
}
402+
let (size, _) = ty.int_size_and_signed(self.tcx);
403+
let width = size.bits();
404+
let llty = self.type_ix(width);
405+
406+
let lhs = args[0].immediate();
407+
let rhs = args[1].immediate();
408+
self.call_intrinsic("llvm.clmul", &[llty], &[lhs, rhs])
409+
}
410+
390411
sym::ctlz
391412
| sym::ctlz_nonzero
392413
| sym::cttz
@@ -2784,6 +2805,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
27842805
| sym::simd_ctlz
27852806
| sym::simd_ctpop
27862807
| sym::simd_cttz
2808+
| sym::simd_carryless_mul
27872809
| sym::simd_funnel_shl
27882810
| sym::simd_funnel_shr
27892811
) {
@@ -2808,6 +2830,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
28082830
sym::simd_cttz => "llvm.cttz",
28092831
sym::simd_funnel_shl => "llvm.fshl",
28102832
sym::simd_funnel_shr => "llvm.fshr",
2833+
sym::simd_carryless_mul => "llvm.clmul",
28112834
_ => unreachable!(),
28122835
};
28132836
let int_size = in_elem.int_size_and_signed(bx.tcx()).0.bits();
@@ -2833,6 +2856,17 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
28332856
&[vec_ty],
28342857
&[args[0].immediate(), args[1].immediate(), args[2].immediate()],
28352858
)),
2859+
sym::simd_carryless_mul => {
2860+
if crate::llvm_util::get_version() >= (22, 0, 0) {
2861+
Ok(bx.call_intrinsic(
2862+
llvm_intrinsic,
2863+
&[vec_ty],
2864+
&[args[0].immediate(), args[1].immediate()],
2865+
))
2866+
} else {
2867+
span_bug!(span, "`simd_carryless_mul` needs LLVM 22 or higher");
2868+
}
2869+
}
28362870
_ => unreachable!(),
28372871
};
28382872
}

compiler/rustc_codegen_llvm/src/lib.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,14 @@ impl CodegenBackend for LlvmCodegenBackend {
354354
}
355355

356356
fn replaced_intrinsics(&self) -> Vec<Symbol> {
357-
vec![sym::unchecked_funnel_shl, sym::unchecked_funnel_shr, sym::carrying_mul_add]
357+
let mut will_not_use_fallback =
358+
vec![sym::unchecked_funnel_shl, sym::unchecked_funnel_shr, sym::carrying_mul_add];
359+
360+
if llvm_util::get_version() >= (22, 0, 0) {
361+
will_not_use_fallback.push(sym::carryless_mul);
362+
}
363+
364+
will_not_use_fallback
358365
}
359366

360367
fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Box<dyn Any> {

compiler/rustc_hir_analysis/src/check/intrinsic.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
8282
| sym::bswap
8383
| sym::caller_location
8484
| sym::carrying_mul_add
85+
| sym::carryless_mul
8586
| sym::ceilf16
8687
| sym::ceilf32
8788
| sym::ceilf64
@@ -564,6 +565,7 @@ pub(crate) fn check_intrinsic_type(
564565
(1, 0, vec![param(0), param(0)], param(0))
565566
}
566567
sym::saturating_add | sym::saturating_sub => (1, 0, vec![param(0), param(0)], param(0)),
568+
sym::carryless_mul => (1, 0, vec![param(0), param(0)], param(0)),
567569
sym::fadd_fast | sym::fsub_fast | sym::fmul_fast | sym::fdiv_fast | sym::frem_fast => {
568570
(1, 0, vec![param(0), param(0)], param(0))
569571
}
@@ -711,7 +713,8 @@ pub(crate) fn check_intrinsic_type(
711713
| sym::simd_fmin
712714
| sym::simd_fmax
713715
| sym::simd_saturating_add
714-
| sym::simd_saturating_sub => (1, 0, vec![param(0), param(0)], param(0)),
716+
| sym::simd_saturating_sub
717+
| sym::simd_carryless_mul => (1, 0, vec![param(0), param(0)], param(0)),
715718
sym::simd_arith_offset => (2, 0, vec![param(0), param(1)], param(0)),
716719
sym::simd_neg
717720
| sym::simd_bswap

compiler/rustc_span/src/symbol.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,7 @@ symbols! {
648648
caller_location,
649649
capture_disjoint_fields,
650650
carrying_mul_add,
651+
carryless_mul,
651652
catch_unwind,
652653
cause,
653654
cdylib,
@@ -2093,6 +2094,7 @@ symbols! {
20932094
simd_bitmask,
20942095
simd_bitreverse,
20952096
simd_bswap,
2097+
simd_carryless_mul,
20962098
simd_cast,
20972099
simd_cast_ptr,
20982100
simd_ceil,

library/core/src/intrinsics/fallback.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,3 +218,38 @@ macro_rules! impl_funnel_shifts {
218218
impl_funnel_shifts! {
219219
u8, u16, u32, u64, u128, usize
220220
}
221+
222+
#[rustc_const_unstable(feature = "core_intrinsics_fallbacks", issue = "none")]
223+
pub const trait CarrylessMul: Copy + 'static {
224+
/// See [`super::carryless_mul`]; we just need the trait indirection to handle
225+
/// different types since calling intrinsics with generics doesn't work.
226+
fn carryless_mul(self, rhs: Self) -> Self;
227+
}
228+
229+
macro_rules! impl_carryless_mul{
230+
($($type:ident),*) => {$(
231+
#[rustc_const_unstable(feature = "core_intrinsics_fallbacks", issue = "none")]
232+
impl const CarrylessMul for $type {
233+
#[inline]
234+
fn carryless_mul(self, rhs: Self) -> Self {
235+
let mut result = 0;
236+
let mut i = 0;
237+
238+
while i < $type::BITS {
239+
// If the i-th bit in rhs is set.
240+
if (rhs >> i) & 1 != 0 {
241+
// Then xor the result with `self` shifted to the left by i positions.
242+
result ^= self << i;
243+
}
244+
i += 1;
245+
}
246+
247+
result
248+
}
249+
}
250+
)*};
251+
}
252+
253+
impl_carryless_mul! {
254+
u8, u16, u32, u64, u128, usize
255+
}

library/core/src/intrinsics/mod.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2178,6 +2178,19 @@ pub const unsafe fn unchecked_funnel_shr<T: [const] fallback::FunnelShift>(
21782178
unsafe { a.unchecked_funnel_shr(b, shift) }
21792179
}
21802180

2181+
/// Carryless multiply.
2182+
///
2183+
/// Safe versions of this intrinsic are available on the integer primitives
2184+
/// via the `carryless_mul` method. For example, [`u32::carryless_mul`].
2185+
#[rustc_intrinsic]
2186+
#[rustc_nounwind]
2187+
#[rustc_const_unstable(feature = "uint_carryless_mul", issue = "152080")]
2188+
#[unstable(feature = "uint_carryless_mul", issue = "152080")]
2189+
#[miri::intrinsic_fallback_is_spec]
2190+
pub const fn carryless_mul<T: [const] fallback::CarrylessMul>(a: T, b: T) -> T {
2191+
a.carryless_mul(b)
2192+
}
2193+
21812194
/// This is an implementation detail of [`crate::ptr::read`] and should
21822195
/// not be used anywhere else. See its comments for why this exists.
21832196
///

library/core/src/intrinsics/simd.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,18 @@ pub const unsafe fn simd_funnel_shl<T>(a: T, b: T, shift: T) -> T;
162162
#[rustc_nounwind]
163163
pub const unsafe fn simd_funnel_shr<T>(a: T, b: T, shift: T) -> T;
164164

165+
/// Compute the carry-less product.
166+
///
167+
/// This is similar to long multiplication except that the carry is discarded.
168+
///
169+
/// This operation can be used to model multiplication in `GF(2)[X]`, the polynomial
170+
/// ring over `GF(2)`.
171+
///
172+
/// `T` must be a vector of integers.
173+
#[rustc_intrinsic]
174+
#[rustc_nounwind]
175+
pub unsafe fn simd_carryless_mul<T>(a: T, b: T) -> T;
176+
165177
/// "And"s vectors elementwise.
166178
///
167179
/// `T` must be a vector of integers.

library/core/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@
170170
#![feature(trait_alias)]
171171
#![feature(transparent_unions)]
172172
#![feature(try_blocks)]
173+
#![feature(uint_carryless_mul)]
173174
#![feature(unboxed_closures)]
174175
#![feature(unsized_fn_params)]
175176
#![feature(with_negative_coherence)]

0 commit comments

Comments
 (0)