Skip to content

Commit 0dc09a7

Browse files
authored
Add support for float_to_int_unchecked (#3660)
This PR adds support for the [`float_to_int_unchecked`](https://doc.rust-lang.org/std/intrinsics/fn.float_to_int_unchecked.html) intrinsic for `f32` and `f64`. Towards #3629 Keeping it as draft till I add more tests. By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.
1 parent b677d6b commit 0dc09a7

File tree

11 files changed

+640
-1
lines changed

11 files changed

+640
-1
lines changed

docs/src/rust-feature-support/intrinsics.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ fabsf32 | Yes | |
156156
fabsf64 | Yes | |
157157
fadd_fast | Yes | |
158158
fdiv_fast | Partial | [#809](https://github.com/model-checking/kani/issues/809) |
159-
float_to_int_unchecked | No | |
159+
float_to_int_unchecked | Partial | [#3629](https://github.com/model-checking/kani/issues/3629) |
160160
floorf32 | Yes | |
161161
floorf64 | Yes | |
162162
fmaf32 | Partial | Results are overapproximated |

kani-compiler/src/codegen_cprover_gotoc/codegen/intrinsic.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,14 @@ impl GotocCtx<'_> {
384384
let binop_stmt = codegen_intrinsic_binop!(div);
385385
self.add_finite_args_checks(intrinsic_str, fargs_clone, binop_stmt, span)
386386
}
387+
Intrinsic::FloatToIntUnchecked => self.codegen_float_to_int_unchecked(
388+
intrinsic_str,
389+
fargs.remove(0),
390+
farg_types[0],
391+
place,
392+
ret_ty,
393+
loc,
394+
),
387395
Intrinsic::FloorF32 => codegen_simple_intrinsic!(Floorf),
388396
Intrinsic::FloorF64 => codegen_simple_intrinsic!(Floor),
389397
Intrinsic::FmafF32 => codegen_simple_intrinsic!(Fmaf),
@@ -1917,6 +1925,57 @@ impl GotocCtx<'_> {
19171925
Stmt::block(vec![non_overlapping_stmt, assign_to_t, assign_to_y, assign_to_x], loc)
19181926
}
19191927
}
1928+
1929+
/// Checks that the floating-point value is:
1930+
/// 1. Finite (i.e. neither infinite nor NaN)
1931+
/// 2. Its truncated value is in range of the target integer
1932+
/// then performs the cast to the target type
1933+
pub fn codegen_float_to_int_unchecked(
1934+
&mut self,
1935+
intrinsic: &str,
1936+
expr: Expr,
1937+
ty: Ty,
1938+
place: &Place,
1939+
res_ty: Ty,
1940+
loc: Location,
1941+
) -> Stmt {
1942+
let finite_check = self.codegen_assert_assume(
1943+
expr.clone().is_finite(),
1944+
PropertyClass::ArithmeticOverflow,
1945+
format!("{intrinsic}: attempt to convert a non-finite value to an integer").as_str(),
1946+
loc,
1947+
);
1948+
1949+
assert!(res_ty.kind().is_integral());
1950+
assert!(ty.kind().is_float());
1951+
let TyKind::RigidTy(integral_ty) = res_ty.kind() else {
1952+
panic!(
1953+
"Expected intrinsic `{}` type to be `RigidTy`, but found: `{:?}`",
1954+
intrinsic, res_ty
1955+
);
1956+
};
1957+
let TyKind::RigidTy(RigidTy::Float(float_type)) = ty.kind() else {
1958+
panic!("Expected intrinsic `{}` type to be `Float`, but found: `{:?}`", intrinsic, ty);
1959+
};
1960+
let mm = self.symbol_table.machine_model();
1961+
let in_range = utils::codegen_in_range_expr(&expr, float_type, integral_ty, mm);
1962+
1963+
let range_check = self.codegen_assert_assume(
1964+
in_range,
1965+
PropertyClass::ArithmeticOverflow,
1966+
format!("{intrinsic}: attempt to convert a value out of range of the target integer")
1967+
.as_str(),
1968+
loc,
1969+
);
1970+
1971+
let int_type = self.codegen_ty_stable(res_ty);
1972+
let cast = expr.cast_to(int_type);
1973+
1974+
Stmt::block(
1975+
vec![finite_check, range_check, self.codegen_expr_to_place_stable(place, cast, loc)],
1976+
loc,
1977+
)
1978+
}
19201979
}
19211980

19221981
fn instance_args(instance: &Instance) -> GenericArgs {

0 commit comments

Comments
 (0)