Skip to content

Commit ee0ff7e

Browse files
celinvaladpaco-aws
andauthored
Migrate foreign function, compiler-interface and kani-middle modules to use StableMIR (#2959)
We still need internal APIs to handle things like: - **FnAbi:** Support is pending this PR to be merged: rust-lang/rust#119094 - **Filter non-function items:** Also pending a fix on the rust side: rust-lang/rust#119135 - **Checking for reachable functions:** This is not needed in theory, but std lib build fails since it unncovers an existing issue in Kani with a function that was not previously included. I'll create an issue for that. It's unrelated to this change though. - **Function attribute handling** - **Span error** Co-authored-by: Adrian Palacios <[email protected]>
1 parent c28dc5a commit ee0ff7e

File tree

14 files changed

+221
-238
lines changed

14 files changed

+221
-238
lines changed

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

+19-24
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ use crate::kani_middle;
1515
use cbmc::goto_program::{Expr, Location, Stmt, Symbol, Type};
1616
use cbmc::{InternString, InternedString};
1717
use lazy_static::lazy_static;
18-
use rustc_middle::ty::Instance;
1918
use rustc_smir::rustc_internal;
2019
use rustc_target::abi::call::Conv;
21-
use stable_mir::mir::mono::Instance as InstanceStable;
20+
use stable_mir::mir::mono::Instance;
21+
use stable_mir::CrateDef;
2222
use tracing::{debug, trace};
2323

2424
lazy_static! {
@@ -46,15 +46,16 @@ impl<'tcx> GotocCtx<'tcx> {
4646
///
4747
/// For other foreign items, we declare a shim and add to the list of foreign shims to be
4848
/// handled later.
49-
pub fn codegen_foreign_fn(&mut self, instance: InstanceStable) -> &Symbol {
49+
pub fn codegen_foreign_fn(&mut self, instance: Instance) -> &Symbol {
5050
debug!(?instance, "codegen_foreign_function");
51-
let instance = rustc_internal::internal(instance);
52-
let fn_name = self.symbol_name(instance).intern();
51+
let instance_internal = rustc_internal::internal(instance);
52+
let fn_name = self.symbol_name_stable(instance).intern();
5353
if self.symbol_table.contains(fn_name) {
5454
// Symbol has been added (either a built-in CBMC function or a Rust allocation function).
5555
self.symbol_table.lookup(fn_name).unwrap()
5656
} else if RUST_ALLOC_FNS.contains(&fn_name)
57-
|| (self.is_cffi_enabled() && kani_middle::fn_abi(self.tcx, instance).conv == Conv::C)
57+
|| (self.is_cffi_enabled()
58+
&& kani_middle::fn_abi(self.tcx, instance_internal).conv == Conv::C)
5859
{
5960
// Add a Rust alloc lib function as is declared by core.
6061
// When C-FFI feature is enabled, we just trust the rust declaration.
@@ -63,14 +64,8 @@ impl<'tcx> GotocCtx<'tcx> {
6364
// https://github.com/model-checking/kani/issues/2426
6465
self.ensure(fn_name, |gcx, _| {
6566
let typ = gcx.codegen_ffi_type(instance);
66-
Symbol::function(
67-
fn_name,
68-
typ,
69-
None,
70-
gcx.readable_instance_name(instance),
71-
Location::none(),
72-
)
73-
.with_is_extern(true)
67+
Symbol::function(fn_name, typ, None, instance.name(), Location::none())
68+
.with_is_extern(true)
7469
})
7570
} else {
7671
let shim_name = format!("{fn_name}_ffi_shim");
@@ -82,7 +77,7 @@ impl<'tcx> GotocCtx<'tcx> {
8277
&shim_name,
8378
typ,
8479
Some(gcx.codegen_ffi_shim(shim_name.as_str().into(), instance)),
85-
gcx.readable_instance_name(instance),
80+
instance.name(),
8681
Location::none(),
8782
)
8883
})
@@ -96,19 +91,19 @@ impl<'tcx> GotocCtx<'tcx> {
9691
}
9792

9893
/// Generate code for a foreign function shim.
99-
fn codegen_ffi_shim(&mut self, shim_name: InternedString, instance: Instance<'tcx>) -> Stmt {
94+
fn codegen_ffi_shim(&mut self, shim_name: InternedString, instance: Instance) -> Stmt {
10095
debug!(?shim_name, ?instance, sym=?self.symbol_table.lookup(shim_name), "generate_foreign_shim");
10196

102-
let loc = self.codegen_span(&self.tcx.def_span(instance.def_id()));
97+
let loc = self.codegen_span_stable(instance.def.span());
10398
let unsupported_check = self.codegen_ffi_unsupported(instance, loc);
10499
Stmt::block(vec![unsupported_check], loc)
105100
}
106101

107102
/// Generate type for the given foreign instance.
108-
fn codegen_ffi_type(&mut self, instance: Instance<'tcx>) -> Type {
109-
let fn_name = self.symbol_name(instance);
110-
let fn_abi = kani_middle::fn_abi(self.tcx, instance);
111-
let loc = self.codegen_span(&self.tcx.def_span(instance.def_id()));
103+
fn codegen_ffi_type(&mut self, instance: Instance) -> Type {
104+
let fn_name = self.symbol_name_stable(instance);
105+
let fn_abi = kani_middle::fn_abi(self.tcx, rustc_internal::internal(instance));
106+
let loc = self.codegen_span_stable(instance.def.span());
112107
let params = fn_abi
113108
.args
114109
.iter()
@@ -137,15 +132,15 @@ impl<'tcx> GotocCtx<'tcx> {
137132
///
138133
/// This will behave like `codegen_unimplemented_stmt` but print a message that includes
139134
/// the name of the function not supported and the calling convention.
140-
fn codegen_ffi_unsupported(&mut self, instance: Instance<'tcx>, loc: Location) -> Stmt {
141-
let fn_name = &self.symbol_name(instance);
135+
fn codegen_ffi_unsupported(&mut self, instance: Instance, loc: Location) -> Stmt {
136+
let fn_name = &self.symbol_name_stable(instance);
142137
debug!(?fn_name, ?loc, "codegen_ffi_unsupported");
143138

144139
// Save this occurrence so we can emit a warning in the compilation report.
145140
let entry = self.unsupported_constructs.entry("foreign function".into()).or_default();
146141
entry.push(loc);
147142

148-
let call_conv = kani_middle::fn_abi(self.tcx, instance).conv;
143+
let call_conv = kani_middle::fn_abi(self.tcx, rustc_internal::internal(instance)).conv;
149144
let msg = format!("call to foreign \"{call_conv:?}\" function `{fn_name}`");
150145
let url = if call_conv == Conv::C {
151146
"https://github.com/model-checking/kani/issues/2423"

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -1331,7 +1331,7 @@ impl<'tcx> GotocCtx<'tcx> {
13311331
TyKind::RigidTy(RigidTy::Slice(_)) | TyKind::RigidTy(RigidTy::Str) => {
13321332
let unit_t = match ty.kind() {
13331333
TyKind::RigidTy(RigidTy::Slice(et)) => et,
1334-
TyKind::RigidTy(RigidTy::Str) => rustc_internal::stable(self.tcx.types.u8),
1334+
TyKind::RigidTy(RigidTy::Str) => Ty::unsigned_ty(UintTy::U8),
13351335
_ => unreachable!(),
13361336
};
13371337
let unit = self.layout_of_stable(unit_t);

kani-compiler/src/codegen_cprover_gotoc/compiler_interface.rs

+36-44
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use crate::kani_middle::{check_reachable_items, dump_mir_items};
1616
use crate::kani_queries::QueryDb;
1717
use cbmc::goto_program::Location;
1818
use cbmc::irep::goto_binary_serde::write_goto_binary_file;
19-
use cbmc::RoundingMode;
19+
use cbmc::{InternString, RoundingMode};
2020
use cbmc::{InternedString, MachineModel};
2121
use kani_metadata::artifact::convert_type;
2222
use kani_metadata::CompilerArtifactStub;
@@ -32,12 +32,10 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
3232
use rustc_data_structures::temp_dir::MaybeTempDir;
3333
use rustc_errors::{ErrorGuaranteed, DEFAULT_LOCALE_RESOURCE};
3434
use rustc_hir::def_id::LOCAL_CRATE;
35-
use rustc_hir::definitions::DefPathHash;
3635
use rustc_metadata::creader::MetadataLoaderDyn;
3736
use rustc_metadata::fs::{emit_wrapper_file, METADATA_FILENAME};
3837
use rustc_metadata::EncodedMetadata;
3938
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
40-
use rustc_middle::mir::mono::MonoItem;
4139
use rustc_middle::ty::TyCtxt;
4240
use rustc_middle::util::Providers;
4341
use rustc_session::config::{CrateType, OutputFilenames, OutputType};
@@ -46,7 +44,7 @@ use rustc_session::Session;
4644
use rustc_smir::rustc_internal;
4745
use rustc_target::abi::Endian;
4846
use rustc_target::spec::PanicStrategy;
49-
use stable_mir::mir::mono::MonoItem as MonoItemStable;
47+
use stable_mir::mir::mono::{Instance, MonoItem};
5048
use stable_mir::CrateDef;
5149
use std::any::Any;
5250
use std::collections::BTreeMap;
@@ -82,10 +80,10 @@ impl GotocCodegenBackend {
8280
fn codegen_items<'tcx>(
8381
&self,
8482
tcx: TyCtxt<'tcx>,
85-
starting_items: &[MonoItem<'tcx>],
83+
starting_items: &[MonoItem],
8684
symtab_goto: &Path,
8785
machine_model: &MachineModel,
88-
) -> (GotocCtx<'tcx>, Vec<MonoItem<'tcx>>) {
86+
) -> (GotocCtx<'tcx>, Vec<MonoItem>) {
8987
let items = with_timer(
9088
|| collect_reachable_items(tcx, starting_items),
9189
"codegen reachability analysis",
@@ -103,17 +101,13 @@ impl GotocCodegenBackend {
103101
for item in &items {
104102
match *item {
105103
MonoItem::Fn(instance) => {
106-
let instance = rustc_internal::stable(instance);
107104
gcx.call_with_panic_debug_info(
108105
|ctx| ctx.declare_function(instance),
109106
format!("declare_function: {}", instance.name()),
110107
instance.def,
111108
);
112109
}
113-
MonoItem::Static(_) => {
114-
let MonoItemStable::Static(def) = rustc_internal::stable(item) else {
115-
unreachable!()
116-
};
110+
MonoItem::Static(def) => {
117111
gcx.call_with_panic_debug_info(
118112
|ctx| ctx.declare_static(def),
119113
format!("declare_static: {}", def.name()),
@@ -128,7 +122,6 @@ impl GotocCodegenBackend {
128122
for item in &items {
129123
match *item {
130124
MonoItem::Fn(instance) => {
131-
let instance = rustc_internal::stable(instance);
132125
gcx.call_with_panic_debug_info(
133126
|ctx| ctx.codegen_function(instance),
134127
format!(
@@ -139,10 +132,7 @@ impl GotocCodegenBackend {
139132
instance.def,
140133
);
141134
}
142-
MonoItem::Static(_) => {
143-
let MonoItemStable::Static(def) = rustc_internal::stable(item) else {
144-
unreachable!()
145-
};
135+
MonoItem::Static(def) => {
146136
gcx.call_with_panic_debug_info(
147137
|ctx| ctx.codegen_static(def),
148138
format!("codegen_static: {}", def.name()),
@@ -237,28 +227,31 @@ impl CodegenBackend for GotocCodegenBackend {
237227
ReachabilityType::Harnesses => {
238228
// Cross-crate collecting of all items that are reachable from the crate harnesses.
239229
let harnesses = queries.target_harnesses();
240-
let mut items: HashSet<DefPathHash> = HashSet::with_capacity(harnesses.len());
230+
let mut items: HashSet<_> = HashSet::with_capacity(harnesses.len());
241231
items.extend(harnesses);
242-
let harnesses = filter_crate_items(tcx, |_, def_id| {
243-
items.contains(&tcx.def_path_hash(def_id))
232+
let harnesses = filter_crate_items(tcx, |_, instance| {
233+
items.contains(&instance.mangled_name().intern())
244234
});
245235
for harness in harnesses {
246-
let model_path = queries
247-
.harness_model_path(&tcx.def_path_hash(harness.def_id()))
248-
.unwrap();
249-
let (gcx, items) =
250-
self.codegen_items(tcx, &[harness], model_path, &results.machine_model);
251-
results.extend(gcx, items, None);
236+
let model_path =
237+
queries.harness_model_path(&harness.mangled_name()).unwrap();
238+
let (gcx, mono_items) = self.codegen_items(
239+
tcx,
240+
&[MonoItem::Fn(harness)],
241+
model_path,
242+
&results.machine_model,
243+
);
244+
results.extend(gcx, mono_items, None);
252245
}
253246
}
254247
ReachabilityType::Tests => {
255248
// We're iterating over crate items here, so what we have to codegen is the "test description" containing the
256249
// test closure that we want to execute
257250
// TODO: Refactor this code so we can guarantee that the pair (test_fn, test_desc) actually match.
258251
let mut descriptions = vec![];
259-
let harnesses = filter_const_crate_items(tcx, |_, def_id| {
260-
if is_test_harness_description(tcx, def_id) {
261-
descriptions.push(def_id);
252+
let harnesses = filter_const_crate_items(tcx, |_, item| {
253+
if is_test_harness_description(tcx, item.def) {
254+
descriptions.push(item.def);
262255
true
263256
} else {
264257
false
@@ -289,11 +282,15 @@ impl CodegenBackend for GotocCodegenBackend {
289282
}
290283
ReachabilityType::None => {}
291284
ReachabilityType::PubFns => {
292-
let entry_fn = tcx.entry_fn(()).map(|(id, _)| id);
293-
let local_reachable = filter_crate_items(tcx, |_, def_id| {
294-
(tcx.is_reachable_non_generic(def_id) && tcx.def_kind(def_id).is_fn_like())
295-
|| entry_fn == Some(def_id)
296-
});
285+
let main_instance =
286+
stable_mir::entry_fn().map(|main_fn| Instance::try_from(main_fn).unwrap());
287+
let local_reachable = filter_crate_items(tcx, |_, instance| {
288+
let def_id = rustc_internal::internal(instance.def.def_id());
289+
Some(instance) == main_instance || tcx.is_reachable_non_generic(def_id)
290+
})
291+
.into_iter()
292+
.map(MonoItem::Fn)
293+
.collect::<Vec<_>>();
297294
let model_path = base_filename.with_extension(ArtifactType::SymTabGoto);
298295
let (gcx, items) = self.codegen_items(
299296
tcx,
@@ -527,17 +524,17 @@ where
527524
}
528525
}
529526

530-
struct GotoCodegenResults<'tcx> {
527+
struct GotoCodegenResults {
531528
reachability: ReachabilityType,
532529
harnesses: Vec<HarnessMetadata>,
533530
unsupported_constructs: UnsupportedConstructs,
534531
concurrent_constructs: UnsupportedConstructs,
535-
items: Vec<MonoItem<'tcx>>,
532+
items: Vec<MonoItem>,
536533
crate_name: InternedString,
537534
machine_model: MachineModel,
538535
}
539536

540-
impl<'tcx> GotoCodegenResults<'tcx> {
537+
impl GotoCodegenResults {
541538
pub fn new(tcx: TyCtxt, reachability: ReachabilityType) -> Self {
542539
GotoCodegenResults {
543540
reachability,
@@ -585,12 +582,7 @@ impl<'tcx> GotoCodegenResults<'tcx> {
585582
}
586583
}
587584

588-
fn extend(
589-
&mut self,
590-
gcx: GotocCtx,
591-
items: Vec<MonoItem<'tcx>>,
592-
metadata: Option<HarnessMetadata>,
593-
) {
585+
fn extend(&mut self, gcx: GotocCtx, items: Vec<MonoItem>, metadata: Option<HarnessMetadata>) {
594586
let mut items = items;
595587
self.harnesses.extend(metadata);
596588
self.concurrent_constructs.extend(gcx.concurrent_constructs);
@@ -599,7 +591,7 @@ impl<'tcx> GotoCodegenResults<'tcx> {
599591
}
600592

601593
/// Prints a report at the end of the compilation.
602-
fn print_report(&self, tcx: TyCtxt<'tcx>) {
594+
fn print_report(&self, tcx: TyCtxt) {
603595
// Print all unsupported constructs.
604596
if !self.unsupported_constructs.is_empty() {
605597
// Sort alphabetically.
@@ -631,7 +623,7 @@ impl<'tcx> GotoCodegenResults<'tcx> {
631623

632624
// Print some compilation stats.
633625
if tracing::enabled!(tracing::Level::INFO) {
634-
analysis::print_stats(tcx, &self.items);
626+
analysis::print_stats(&self.items);
635627
}
636628
}
637629
}

kani-compiler/src/codegen_cprover_gotoc/utils/names.rs

+3-28
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,9 @@ use crate::codegen_cprover_gotoc::GotocCtx;
77
use cbmc::InternedString;
88
use rustc_hir::def_id::LOCAL_CRATE;
99
use rustc_middle::mir::mono::CodegenUnitNameBuilder;
10-
use rustc_middle::ty::print::with_no_trimmed_paths;
11-
use rustc_middle::ty::{Instance, TyCtxt};
12-
use stable_mir::mir::mono::Instance as InstanceStable;
10+
use rustc_middle::ty::TyCtxt;
11+
use stable_mir::mir::mono::Instance;
1312
use stable_mir::mir::Local;
14-
use tracing::debug;
1513

1614
impl<'tcx> GotocCtx<'tcx> {
1715
/// The full crate name including versioning info
@@ -52,34 +50,11 @@ impl<'tcx> GotocCtx<'tcx> {
5250
format!("{var_name}_init")
5351
}
5452

55-
/// A human readable name in Rust for reference, should not be used as a key.
56-
pub fn readable_instance_name(&self, instance: Instance<'tcx>) -> String {
57-
with_no_trimmed_paths!(self.tcx.def_path_str_with_args(instance.def_id(), instance.args))
58-
}
59-
60-
/// The actual function name used in the symbol table
61-
pub fn symbol_name(&self, instance: Instance<'tcx>) -> String {
62-
let llvm_mangled = self.tcx.symbol_name(instance).name.to_string();
63-
debug!(
64-
"finding function name for instance: {}, debug: {:?}, name: {}, symbol: {}",
65-
instance,
66-
instance,
67-
self.readable_instance_name(instance),
68-
llvm_mangled,
69-
);
70-
71-
let pretty = self.readable_instance_name(instance);
72-
73-
// Make main function a special case in order to support `--function main`
74-
// TODO: Get rid of this: https://github.com/model-checking/kani/issues/2129
75-
if pretty == "main" { pretty } else { llvm_mangled }
76-
}
77-
7853
/// Return the mangled name to be used in the symbol table.
7954
///
8055
/// We special case main function in order to support `--function main`.
8156
// TODO: Get rid of this: https://github.com/model-checking/kani/issues/2129
82-
pub fn symbol_name_stable(&self, instance: InstanceStable) -> String {
57+
pub fn symbol_name_stable(&self, instance: Instance) -> String {
8358
let pretty = instance.name();
8459
if pretty == "main" { pretty } else { instance.mangled_name() }
8560
}

0 commit comments

Comments
 (0)