Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for float_to_int_unchecked #3660

Merged
merged 12 commits into from
Nov 6, 2024
2 changes: 1 addition & 1 deletion docs/src/rust-feature-support/intrinsics.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ fabsf32 | Yes | |
fabsf64 | Yes | |
fadd_fast | Yes | |
fdiv_fast | Partial | [#809](https://github.com/model-checking/kani/issues/809) |
float_to_int_unchecked | No | |
float_to_int_unchecked | Partial | [#3629](https://github.com/model-checking/kani/issues/3629) |
floorf32 | Yes | |
floorf64 | Yes | |
fmaf32 | Partial | Results are overapproximated |
Expand Down
59 changes: 59 additions & 0 deletions kani-compiler/src/codegen_cprover_gotoc/codegen/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,14 @@ impl GotocCtx<'_> {
let binop_stmt = codegen_intrinsic_binop!(div);
self.add_finite_args_checks(intrinsic_str, fargs_clone, binop_stmt, span)
}
Intrinsic::FloatToIntUnchecked => self.codegen_float_to_int_unchecked(
intrinsic_str,
fargs.remove(0),
farg_types[0],
place,
ret_ty,
loc,
),
Intrinsic::FloorF32 => codegen_simple_intrinsic!(Floorf),
Intrinsic::FloorF64 => codegen_simple_intrinsic!(Floor),
Intrinsic::FmafF32 => codegen_simple_intrinsic!(Fmaf),
Expand Down Expand Up @@ -1917,6 +1925,57 @@ impl GotocCtx<'_> {
Stmt::block(vec![non_overlapping_stmt, assign_to_t, assign_to_y, assign_to_x], loc)
}
}

/// Checks that the floating-point value is:
/// 1. Finite (i.e. neither infinite nor NaN)
/// 2. Its truncated value is in range of the target integer
/// then performs the cast to the target type
pub fn codegen_float_to_int_unchecked(
&mut self,
intrinsic: &str,
expr: Expr,
ty: Ty,
place: &Place,
res_ty: Ty,
loc: Location,
) -> Stmt {
let finite_check = self.codegen_assert_assume(
expr.clone().is_finite(),
PropertyClass::ArithmeticOverflow,
format!("{intrinsic}: attempt to convert a non-finite value to an integer").as_str(),
loc,
);

assert!(res_ty.kind().is_integral());
assert!(ty.kind().is_float());
let TyKind::RigidTy(integral_ty) = res_ty.kind() else {
panic!(
"Expected intrinsic `{}` type to be `RigidTy`, but found: `{:?}`",
intrinsic, res_ty
);
};
let TyKind::RigidTy(RigidTy::Float(float_type)) = ty.kind() else {
panic!("Expected intrinsic `{}` type to be `Float`, but found: `{:?}`", intrinsic, ty);
};
let mm = self.symbol_table.machine_model();
let in_range = utils::codegen_in_range_expr(&expr, float_type, integral_ty, mm);

let range_check = self.codegen_assert_assume(
in_range,
PropertyClass::ArithmeticOverflow,
format!("{intrinsic}: attempt to convert a value out of range of the target integer")
.as_str(),
loc,
);

let int_type = self.codegen_ty_stable(res_ty);
let cast = expr.cast_to(int_type);

Stmt::block(
vec![finite_check, range_check, self.codegen_expr_to_place_stable(place, cast, loc)],
loc,
)
}
}

fn instance_args(instance: &Instance) -> GenericArgs {
Expand Down
Loading
Loading