MCPcopy Create free account
hub / github.com/Rust-GPU/rust-gpu / fptoint_sat

Method fptoint_sat

crates/rustc_codegen_spirv/src/builder/builder_methods.rs:457–633  ·  view source on GitHub ↗
(
        &mut self,
        signed: bool,
        val: SpirvValue,
        dest_ty: <Self as BackendTypes>::Type,
    )

Source from the content-addressed store, hash-verified

455 }
456
457 fn fptoint_sat(
458 &mut self,
459 signed: bool,
460 val: SpirvValue,
461 dest_ty: <Self as BackendTypes>::Type,
462 ) -> SpirvValue {
463 // This uses the old llvm emulation to implement saturation
464
465 let src_ty = self.cx.val_ty(val);
466 let (float_ty, int_ty) = if self.cx.type_kind(src_ty) == TypeKind::Vector {
467 assert_eq!(
468 self.cx.vector_length(src_ty),
469 self.cx.vector_length(dest_ty)
470 );
471 (self.cx.element_type(src_ty), self.cx.element_type(dest_ty))
472 } else {
473 (src_ty, dest_ty)
474 };
475 let int_width = self.cx().int_width(int_ty);
476 let float_width = self.cx().float_width(float_ty);
477 // LLVM's fpto[su]i returns undef when the input x is infinite, NaN, or does not fit into the
478 // destination integer type after rounding towards zero. This `undef` value can cause UB in
479 // safe code (see issue #10184), so we implement a saturating conversion on top of it:
480 // Semantically, the mathematical value of the input is rounded towards zero to the next
481 // mathematical integer, and then the result is clamped into the range of the destination
482 // integer type. Positive and negative infinity are mapped to the maximum and minimum value of
483 // the destination integer type. NaN is mapped to 0.
484 //
485 // Define f_min and f_max as the largest and smallest (finite) floats that are exactly equal to
486 // a value representable in int_ty.
487 // They are exactly equal to int_ty::{MIN,MAX} if float_ty has enough significand bits.
488 // Otherwise, int_ty::MAX must be rounded towards zero, as it is one less than a power of two.
489 // int_ty::MIN, however, is either zero or a negative power of two and is thus exactly
490 // representable. Note that this only works if float_ty's exponent range is sufficiently large.
491 // f16 or 256 bit integers would break this property. Right now the smallest float type is f32
492 // with exponents ranging up to 127, which is barely enough for i128::MIN = -2^127.
493 // On the other hand, f_max works even if int_ty::MAX is greater than float_ty::MAX. Because
494 // we're rounding towards zero, we just get float_ty::MAX (which is always an integer).
495 // This already happens today with u128::MAX = 2^128 - 1 > f32::MAX.
496 let int_max = |signed: bool, int_width: u64| -> u128 {
497 let shift_amount = 128 - int_width;
498 if signed {
499 i128::MAX as u128 >> shift_amount
500 } else {
501 u128::MAX >> shift_amount
502 }
503 };
504 let int_min = |signed: bool, int_width: u64| -> i128 {
505 if signed {
506 i128::MIN >> (128 - int_width)
507 } else {
508 0
509 }
510 };
511
512 let compute_clamp_bounds_single = |signed: bool, int_width: u64| -> (u128, u128) {
513 let rounded_min =
514 ieee::Single::from_i128_r(int_min(signed, int_width), Round::TowardZero);

Callers 2

fptoui_satMethod · 0.80
fptosi_satMethod · 0.80

Calls 15

val_tyMethod · 0.80
type_kindMethod · 0.80
element_typeMethod · 0.80
int_widthMethod · 0.80
cxMethod · 0.80
float_widthMethod · 0.80
const_u32Method · 0.80
const_u64Method · 0.80
bitcastMethod · 0.80
const_uint_bigMethod · 0.80
const_uintMethod · 0.80
vector_splatMethod · 0.80

Tested by

no test coverage detected