Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions docs/src/rust-feature-support/intrinsics.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,7 @@ exp2f32 | Partial | Results are overapproximated |
exp2f64 | Partial | Results are overapproximated |
expf32 | Partial | Results are overapproximated |
expf64 | Partial | Results are overapproximated |
fabsf32 | Yes | |
fabsf64 | Yes | |
fabs | Yes | |
fadd_fast | Yes | |
fdiv_fast | Partial | [#809](https://github.com/model-checking/kani/issues/809) |
float_to_int_unchecked | Yes | |
Expand All @@ -172,12 +171,12 @@ log2f32 | Partial | Results are overapproximated |
log2f64 | Partial | Results are overapproximated |
logf32 | Partial | Results are overapproximated |
logf64 | Partial | Results are overapproximated |
maxnumf32 | Yes | |
maxnumf64 | Yes | |
maximum_number_nsz_f32 | Yes | |
maximum_number_nsz_f64 | Yes | |
align_of | Yes | |
align_of_val | Yes | |
minnumf32 | Yes | |
minnumf64 | Yes | |
minimum_number_nsz_f32 | Yes | |
minimum_number_nsz_f64 | Yes | |
move_val_init | No | |
mul_with_overflow | Yes | |
needs_drop | Yes | |
Expand Down
54 changes: 27 additions & 27 deletions kani-compiler/src/codegen_aeneas_llbc/compiler_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use rustc_codegen_ssa::back::archive::{
};
use rustc_codegen_ssa::back::link::link_binary;
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_codegen_ssa::{CodegenResults, CrateInfo};
use rustc_codegen_ssa::{CompiledModules, CrateInfo};
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_errors::ErrorGuaranteed;
use rustc_hir::def_id::{DefId as InternalDefId, LOCAL_CRATE};
Expand All @@ -40,7 +40,6 @@ use rustc_public::{CrateDef, DefId};
use rustc_session::Session;
use rustc_session::config::{CrateType, OutputFilenames, OutputType};
use rustc_session::output::out_filename;
use rustc_target::spec::Arch;
use std::any::Any;
use std::fs::File;
use std::path::Path;
Expand Down Expand Up @@ -199,7 +198,15 @@ impl CodegenBackend for LlbcCodegenBackend {
"kani-llbc"
}

fn codegen_crate(&self, tcx: TyCtxt) -> Box<dyn Any> {
fn target_cpu(&self, sess: &Session) -> String {
match sess.opts.cg.target_cpu {
Some(ref name) => name,
None => sess.target.cpu.as_ref(),
}
.to_owned()
}

fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>, _crate_info: &CrateInfo) -> Box<dyn Any> {
let ret_val = rustc_internal::run(tcx, || {
// Queries shouldn't change today once codegen starts.
let queries = QUERY_DB.with(|db| db.borrow().clone());
Expand Down Expand Up @@ -279,7 +286,7 @@ impl CodegenBackend for LlbcCodegenBackend {
// To avoid overriding the metadata for its verification, we skip this step when
// reachability is None, even because there is nothing to record.
}
codegen_results(tcx)
codegen_results()
});
ret_val.unwrap()
}
Expand All @@ -289,8 +296,9 @@ impl CodegenBackend for LlbcCodegenBackend {
ongoing_codegen: Box<dyn Any>,
_sess: &Session,
_filenames: &OutputFilenames,
) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>) {
match ongoing_codegen.downcast::<(CodegenResults, FxIndexMap<WorkProductId, WorkProduct>)>()
) -> (CompiledModules, FxIndexMap<WorkProductId, WorkProduct>) {
match ongoing_codegen
.downcast::<(CompiledModules, FxIndexMap<WorkProductId, WorkProduct>)>()
{
Ok(val) => *val,
Err(val) => panic!("unexpected error: {:?}", (*val).type_id()),
Expand All @@ -314,21 +322,23 @@ impl CodegenBackend for LlbcCodegenBackend {
fn link(
&self,
sess: &Session,
codegen_results: CodegenResults,
compiled_modules: CompiledModules,
crate_info: CrateInfo,
rustc_metadata: EncodedMetadata,
outputs: &OutputFilenames,
) {
let requested_crate_types = &codegen_results.crate_info.crate_types.clone();
let local_crate_name = codegen_results.crate_info.local_crate_name;
let requested_crate_types = crate_info.crate_types.clone();
let local_crate_name = crate_info.local_crate_name;
link_binary(
sess,
&ArArchiveBuilderBuilder,
codegen_results,
compiled_modules,
crate_info,
rustc_metadata,
outputs,
self.name(),
);
for crate_type in requested_crate_types {
for crate_type in &requested_crate_types {
let out_fname = out_filename(sess, *crate_type, outputs, local_crate_name);
let out_path = out_fname.as_path();
debug!(?crate_type, ?out_path, "link");
Expand Down Expand Up @@ -362,23 +372,13 @@ fn contract_metadata_for_harness(
}

/// Return a struct that contains information about the codegen results as expected by `rustc`.
fn codegen_results(tcx: TyCtxt) -> Box<dyn Any> {
///
/// Kani produces no object files, so the module lists are empty. `rustc` now builds the `CrateInfo`
/// itself and passes it to `codegen_crate` and `link`, so there is nothing crate-specific to report
/// here.
fn codegen_results() -> Box<dyn Any> {
let work_products = FxIndexMap::<WorkProductId, WorkProduct>::default();
Box::new((
CodegenResults {
modules: vec![],
allocator_module: None,
crate_info: CrateInfo::new(
tcx,
match tcx.sess.target.arch {
Arch::X86_64 => "x86_64".to_string(),
Arch::AArch64 => "aarch64".to_string(),
_ => format!("{:?}", tcx.sess.target.arch).to_lowercase(),
},
),
},
work_products,
))
Box::new((CompiledModules { modules: vec![], allocator_module: None }, work_products))
}

/// Execute the provided function and measure the clock time it took for its execution.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use std::collections::HashSet;

use crate::codegen_cprover_gotoc::GotocCtx;
use crate::codegen_cprover_gotoc::codegen::PropertyClass;
use crate::kani_middle::nonnull_pointee;
use crate::unwrap_or_return_codegen_unimplemented_stmt;
use cbmc::goto_program::{Expr, Location, Stmt, Symbol, Type};
use cbmc::{InternString, InternedString};
Expand Down Expand Up @@ -168,16 +169,18 @@ impl GotocCtx<'_, '_> {
.map(|(idx, arg)| {
let arg_name = format!("{fn_name}::param_{idx}");
let base_name = format!("param_{idx}");
// `core::ptr::Alignment` is `repr(transparent)` over a `repr(usize)`
// `core::mem::Alignment` is `repr(transparent)` over a `repr(usize)`
// enum (ABI-identical to `usize`). As of nightly-2026-02-16 the Rust
// allocation shims (`__rust_alloc` etc.) take their alignment argument
// as `Alignment` rather than `usize`. Its goto type is not `size_t`,
// which would mismatch the `size_t` parameters of the C definitions in
// `kani_lib.c` at link time, leaving the allocator body unlinked (so it
// havocs and may "fail", making the OOM path reachable). Represent it as
// `size_t` for FFI so the definitions link.
let arg_type = if is_ptr_alignment(arg.ty) {
let arg_type = if is_alignment(arg.ty) {
Type::size_t()
} else if let Some(pointee) = nonnull_pointee(arg.ty) {
self.codegen_ty_stable(pointee).to_pointer()
} else {
self.codegen_ty_stable(arg.ty)
};
Expand Down Expand Up @@ -224,16 +227,25 @@ impl GotocCtx<'_, '_> {
}
}

/// Returns `true` if `ty` is `core::ptr::Alignment`.
/// Returns `true` if `ty` is the standard library's `Alignment`, under either the `core` or `std`
/// path and under either the `mem` module (as of nightly-2026-03-21) or the `ptr` module (before).
///
/// That type is `repr(transparent)` over a `repr(usize)` enum and is therefore
/// ABI-identical to `usize`, but its goto type is not `size_t`. We treat it as
/// `size_t` in foreign (FFI) signatures so that Rust's allocation shims match the
/// `size_t`-typed definitions in `kani_lib.c`.
fn is_ptr_alignment(ty: rustc_public::ty::Ty) -> bool {
fn is_alignment(ty: rustc_public::ty::Ty) -> bool {
Comment thread
feliperodri marked this conversation as resolved.
matches!(
ty.kind(),
TyKind::RigidTy(RigidTy::Adt(def, _))
if matches!(def.name().as_str(), "core::ptr::Alignment" | "std::ptr::Alignment")
if matches!(
def.name().as_str(),
// The type moved from `ptr` to `mem` in nightly-2026-03-21; both paths are matched
// so that this keeps working across the move.
"core::mem::Alignment"
| "std::mem::Alignment"
| "core::ptr::Alignment"
| "std::ptr::Alignment"
)
)
}
48 changes: 28 additions & 20 deletions kani-compiler/src/codegen_cprover_gotoc/compiler_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use rustc_codegen_ssa::back::archive::{
};
use rustc_codegen_ssa::back::link::link_binary;
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_codegen_ssa::{CodegenResults, CrateInfo, TargetConfig};
use rustc_codegen_ssa::{CompiledModules, CrateInfo, TargetConfig};
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_hir::def_id::{DefId as InternalDefId, LOCAL_CRATE};
use rustc_metadata::EncodedMetadata;
Expand Down Expand Up @@ -325,7 +325,15 @@ impl CodegenBackend for GotocCodegenBackend {
}
}

fn codegen_crate(&self, tcx: TyCtxt) -> Box<dyn Any> {
fn target_cpu(&self, sess: &Session) -> String {
match sess.opts.cg.target_cpu {
Some(ref name) => name,
None => sess.target.cpu.as_ref(),
}
.to_owned()
}

fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>, _crate_info: &CrateInfo) -> Box<dyn Any> {
let ret_val = rustc_internal::run(tcx, || {
super::utils::init();

Expand Down Expand Up @@ -372,7 +380,7 @@ impl CodegenBackend for GotocCodegenBackend {

// If reachability is None, just return early as we'll do no codegen.
if reachability == ReachabilityType::None {
return codegen_results(tcx, &results.machine_model);
return codegen_results();
}

// Create an empty thread pool. We will set the size later once we
Expand Down Expand Up @@ -484,7 +492,7 @@ impl CodegenBackend for GotocCodegenBackend {
);
}
}
codegen_results(tcx, &results.machine_model)
codegen_results()
});
ret_val.unwrap()
}
Expand All @@ -494,8 +502,9 @@ impl CodegenBackend for GotocCodegenBackend {
ongoing_codegen: Box<dyn Any>,
_sess: &Session,
_filenames: &OutputFilenames,
) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>) {
match ongoing_codegen.downcast::<(CodegenResults, FxIndexMap<WorkProductId, WorkProduct>)>()
) -> (CompiledModules, FxIndexMap<WorkProductId, WorkProduct>) {
match ongoing_codegen
.downcast::<(CompiledModules, FxIndexMap<WorkProductId, WorkProduct>)>()
{
Ok(val) => *val,
Err(val) => panic!("unexpected error: {:?}", (*val).type_id()),
Expand All @@ -513,18 +522,20 @@ impl CodegenBackend for GotocCodegenBackend {
fn link(
&self,
sess: &Session,
codegen_results: CodegenResults,
compiled_modules: CompiledModules,
crate_info: CrateInfo,
rustc_metadata: EncodedMetadata,
outputs: &OutputFilenames,
) {
let requested_crate_types = &codegen_results.crate_info.crate_types.clone();
let local_crate_name = codegen_results.crate_info.local_crate_name;
let requested_crate_types = crate_info.crate_types.clone();
let local_crate_name = crate_info.local_crate_name;
// Create the rlib if one was requested.
if requested_crate_types.contains(&CrateType::Rlib) {
link_binary(
sess,
&ArArchiveBuilderBuilder,
codegen_results,
compiled_modules,
crate_info,
rustc_metadata,
outputs,
self.name(),
Expand All @@ -534,7 +545,7 @@ impl CodegenBackend for GotocCodegenBackend {
// But override all the other outputs.
// Note: Do this after `link_binary` call, since it may write to the object files
// and override the json we are creating.
for crate_type in requested_crate_types {
for crate_type in &requested_crate_types {
let out_fname = out_filename(sess, *crate_type, outputs, local_crate_name);
let out_path = out_fname.as_path();
debug!(?crate_type, ?out_path, "link");
Expand Down Expand Up @@ -624,16 +635,13 @@ fn check_options(session: &Session) {
}

/// Return a struct that contains information about the codegen results as expected by `rustc`.
fn codegen_results(tcx: TyCtxt, machine: &MachineModel) -> Box<dyn Any> {
///
/// Kani produces no object files, so the module lists are empty. `rustc` now builds the `CrateInfo`
/// itself and passes it to `codegen_crate` and `link`, so there is nothing crate-specific to report
/// here.
fn codegen_results() -> Box<dyn Any> {
let work_products = FxIndexMap::<WorkProductId, WorkProduct>::default();
Box::new((
CodegenResults {
modules: vec![],
allocator_module: None,
crate_info: CrateInfo::new(tcx, machine.architecture.clone()),
},
work_products,
))
Box::new((CompiledModules { modules: vec![], allocator_module: None }, work_products))
}

pub fn write_file<T>(base_path: &Path, file_type: ArtifactType, source: &T, pretty: bool)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ use rustc_public::mir::Body;
use rustc_public::mir::mono::Instance;
use rustc_public::ty::Allocation;
use rustc_span::Span;
use rustc_span::source_map::respan;
use rustc_span::respan;
use rustc_target::callconv::FnAbi;
use std::collections::{BTreeMap, HashMap, HashSet};
use std::fmt::Debug;
Expand Down
34 changes: 14 additions & 20 deletions kani-compiler/src/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,16 @@ impl Intrinsic {
assert_sig_matches!(sig, RigidTy::RawPtr(_, Mutability::Mut), RigidTy::Uint(UintTy::U8), RigidTy::Uint(UintTy::Usize) => RigidTy::Tuple(_));
Self::WriteBytes
}
// `fabs` is generic over the float type as of nightly-2026-03-21, where it used to be
// one intrinsic per width (`fabsf32` and friends). Recover the width from the signature
// so that codegen can keep using the width-specific CBMC builtins.
"fabs" => match sig.inputs()[0].kind() {
Comment thread
feliperodri marked this conversation as resolved.
TyKind::RigidTy(RigidTy::Float(FloatTy::F16)) => Self::FabsF16,
TyKind::RigidTy(RigidTy::Float(FloatTy::F32)) => Self::FabsF32,
TyKind::RigidTy(RigidTy::Float(FloatTy::F64)) => Self::FabsF64,
TyKind::RigidTy(RigidTy::Float(FloatTy::F128)) => Self::FabsF128,
other => unreachable!("Unexpected `fabs` argument type: {other:?}"),
},
_ => try_match_atomic(intrinsic_instance)
.or_else(|| try_match_simd(intrinsic_instance))
.or_else(|| try_match_f32(intrinsic_instance))
Expand Down Expand Up @@ -675,14 +685,6 @@ fn try_match_f32(intrinsic_instance: &Instance) -> Option<Intrinsic> {
assert_sig_matches!(sig, RigidTy::Float(FloatTy::F32) => RigidTy::Float(FloatTy::F32));
Some(Intrinsic::ExpF32)
}
"fabsf16" => {
assert_sig_matches!(sig, RigidTy::Float(FloatTy::F16) => RigidTy::Float(FloatTy::F16));
Some(Intrinsic::FabsF16)
}
"fabsf32" => {
assert_sig_matches!(sig, RigidTy::Float(FloatTy::F32) => RigidTy::Float(FloatTy::F32));
Some(Intrinsic::FabsF32)
}
"floorf32" => {
assert_sig_matches!(sig, RigidTy::Float(FloatTy::F32) => RigidTy::Float(FloatTy::F32));
Some(Intrinsic::FloorF32)
Expand All @@ -703,11 +705,11 @@ fn try_match_f32(intrinsic_instance: &Instance) -> Option<Intrinsic> {
assert_sig_matches!(sig, RigidTy::Float(FloatTy::F32) => RigidTy::Float(FloatTy::F32));
Some(Intrinsic::LogF32)
}
"maxnumf32" => {
"maximum_number_nsz_f32" => {
assert_sig_matches!(sig, RigidTy::Float(FloatTy::F32), RigidTy::Float(FloatTy::F32) => RigidTy::Float(FloatTy::F32));
Some(Intrinsic::MaxNumF32)
}
"minnumf32" => {
"minimum_number_nsz_f32" => {
assert_sig_matches!(sig, RigidTy::Float(FloatTy::F32), RigidTy::Float(FloatTy::F32) => RigidTy::Float(FloatTy::F32));
Some(Intrinsic::MinNumF32)
}
Expand Down Expand Up @@ -769,14 +771,6 @@ fn try_match_f64(intrinsic_instance: &Instance) -> Option<Intrinsic> {
assert_sig_matches!(sig, RigidTy::Float(FloatTy::F64) => RigidTy::Float(FloatTy::F64));
Some(Intrinsic::ExpF64)
}
"fabsf64" => {
assert_sig_matches!(sig, RigidTy::Float(FloatTy::F64) => RigidTy::Float(FloatTy::F64));
Some(Intrinsic::FabsF64)
}
"fabsf128" => {
assert_sig_matches!(sig, RigidTy::Float(FloatTy::F128) => RigidTy::Float(FloatTy::F128));
Some(Intrinsic::FabsF128)
}
"floorf64" => {
assert_sig_matches!(sig, RigidTy::Float(FloatTy::F64) => RigidTy::Float(FloatTy::F64));
Some(Intrinsic::FloorF64)
Expand All @@ -797,11 +791,11 @@ fn try_match_f64(intrinsic_instance: &Instance) -> Option<Intrinsic> {
assert_sig_matches!(sig, RigidTy::Float(FloatTy::F64) => RigidTy::Float(FloatTy::F64));
Some(Intrinsic::LogF64)
}
"maxnumf64" => {
"maximum_number_nsz_f64" => {
assert_sig_matches!(sig, RigidTy::Float(FloatTy::F64), RigidTy::Float(FloatTy::F64) => RigidTy::Float(FloatTy::F64));
Some(Intrinsic::MaxNumF64)
}
"minnumf64" => {
"minimum_number_nsz_f64" => {
assert_sig_matches!(sig, RigidTy::Float(FloatTy::F64), RigidTy::Float(FloatTy::F64) => RigidTy::Float(FloatTy::F64));
Some(Intrinsic::MinNumF64)
}
Expand Down
Loading
Loading