Skip to content

Commit 9190831

Browse files
Migrate static handling and most of the operand codegen code to StableMIR (rust-lang#2931)
Migrate most of the operand code generation to use StableMIR APIs, and static handling. This change is so far the one that required some re-work, since constants in StableMIR differ a bit from internal APIs. In the Rust compiler internal APIs, constant values can be using either: Scalar, Slice, Indirect (represented by an Allocation), and ZST. In the StableAPIs, a constant value is always represented with an Allocation. To avoid making changes to the final gotoc, we generate code for allocations in two steps, we first try to generate just a regular constant literal if the constant is small (similar logic to handling the Scalar internal type). For more complex cases, we create an allocation and read from it, similar to how Indirect / Slice internal handling used to work. --------- Co-authored-by: Zyad Hassan <88045115+zhassan-aws@users.noreply.github.com>
1 parent 9090db3 commit 9190831

File tree

17 files changed

+496
-513
lines changed

17 files changed

+496
-513
lines changed

Diff for: cprover_bindings/src/goto_program/expr.rs

+28
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,34 @@ impl Expr {
627627
expr!(IntConstant(i), typ)
628628
}
629629

630+
pub fn ssize_constant(i: i128, symbol_table: &SymbolTable) -> Self {
631+
match symbol_table.machine_model().pointer_width {
632+
32 => {
633+
let val = BigInt::from(i as i32);
634+
expr!(IntConstant(val), Type::ssize_t())
635+
}
636+
64 => {
637+
let val = BigInt::from(i as i64);
638+
expr!(IntConstant(val), Type::ssize_t())
639+
}
640+
i => unreachable!("Expected 32 or 64 bits pointer width, but got `{i}`"),
641+
}
642+
}
643+
644+
pub fn size_constant(i: u128, symbol_table: &SymbolTable) -> Self {
645+
match symbol_table.machine_model().pointer_width {
646+
32 => {
647+
let val = BigInt::from(i as u32);
648+
expr!(IntConstant(val), Type::size_t())
649+
}
650+
64 => {
651+
let val = BigInt::from(i as u64);
652+
expr!(IntConstant(val), Type::size_t())
653+
}
654+
i => unreachable!("Expected 32 or 64 bits pointer width, but got `{i}`"),
655+
}
656+
}
657+
630658
pub fn typecheck_call(function: &Expr, arguments: &[Expr]) -> bool {
631659
// For variadic functions, all named arguments must match the type of their formal param.
632660
// Extra arguments (e.g the ... args) can have any type.

Diff for: kani-compiler/src/codegen_cprover_gotoc/codegen/foreign_function.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ use cbmc::goto_program::{Expr, Location, Stmt, Symbol, Type};
1616
use cbmc::{InternString, InternedString};
1717
use lazy_static::lazy_static;
1818
use rustc_middle::ty::Instance;
19+
use rustc_smir::rustc_internal;
1920
use rustc_target::abi::call::Conv;
21+
use stable_mir::mir::mono::Instance as InstanceStable;
2022
use tracing::{debug, trace};
2123

2224
lazy_static! {
@@ -44,8 +46,9 @@ impl<'tcx> GotocCtx<'tcx> {
4446
///
4547
/// For other foreign items, we declare a shim and add to the list of foreign shims to be
4648
/// handled later.
47-
pub fn codegen_foreign_fn(&mut self, instance: Instance<'tcx>) -> &Symbol {
49+
pub fn codegen_foreign_fn(&mut self, instance: InstanceStable) -> &Symbol {
4850
debug!(?instance, "codegen_foreign_function");
51+
let instance = rustc_internal::internal(instance);
4952
let fn_name = self.symbol_name(instance).intern();
5053
if self.symbol_table.contains(fn_name) {
5154
// Symbol has been added (either a built-in CBMC function or a Rust allocation function).

Diff for: kani-compiler/src/codegen_cprover_gotoc/codegen/intrinsic.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use rustc_middle::mir::{BasicBlock, Operand, Place};
1212
use rustc_middle::ty::layout::{LayoutOf, ValidityRequirement};
1313
use rustc_middle::ty::{self, Ty};
1414
use rustc_middle::ty::{Instance, InstanceDef};
15+
use rustc_smir::rustc_internal;
1516
use rustc_span::Span;
1617
use tracing::debug;
1718

@@ -233,14 +234,14 @@ impl<'tcx> GotocCtx<'tcx> {
233234
// Intrinsics which encode a value known during compilation
234235
macro_rules! codegen_intrinsic_const {
235236
() => {{
236-
let value = self
237-
.tcx
238-
.const_eval_instance(ty::ParamEnv::reveal_all(), instance, span)
239-
.unwrap();
237+
let place = rustc_internal::stable(p);
238+
let place_ty = self.place_ty_stable(&place);
239+
let stable_instance = rustc_internal::stable(instance);
240+
let alloc = stable_instance.try_const_eval(place_ty).unwrap();
240241
// We assume that the intrinsic has type checked at this point, so
241242
// we can use the place type as the expression type.
242-
let e = self.codegen_const_value(value, self.place_ty(p), span.as_ref());
243-
self.codegen_expr_to_place(p, e)
243+
let e = self.codegen_allocation(&alloc, place_ty, rustc_internal::stable(span));
244+
self.codegen_expr_to_place_stable(&place, e)
244245
}};
245246
}
246247

Diff for: kani-compiler/src/codegen_cprover_gotoc/codegen/operand.rs

+315-466
Large diffs are not rendered by default.

Diff for: kani-compiler/src/codegen_cprover_gotoc/codegen/place.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ impl<'tcx> GotocCtx<'tcx> {
369369
match ty.kind() {
370370
// A local that is itself a FnDef, like Fn::call_once
371371
TyKind::RigidTy(RigidTy::FnDef(def, args)) => {
372-
Some(self.codegen_fndef_stable(def, &args, None))
372+
Some(self.codegen_fndef(def, &args, None))
373373
}
374374
// A local can be pointer to a FnDef, like Fn::call and Fn::call_mut
375375
TyKind::RigidTy(RigidTy::RawPtr(inner, _)) => self

Diff for: kani-compiler/src/codegen_cprover_gotoc/codegen/rvalue.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ impl<'tcx> GotocCtx<'tcx> {
162162
fn codegen_rvalue_len(&mut self, p: &Place<'tcx>) -> Expr {
163163
let pt = self.place_ty(p);
164164
match pt.kind() {
165-
ty::Array(_, sz) => self.codegen_const(*sz, None),
165+
ty::Array(_, sz) => self.codegen_const_internal(*sz, None),
166166
ty::Slice(_) => unwrap_or_return_codegen_unimplemented!(self, self.codegen_place(p))
167167
.fat_ptr_goto_expr
168168
.unwrap()
@@ -761,7 +761,7 @@ impl<'tcx> GotocCtx<'tcx> {
761761
Rvalue::ThreadLocalRef(def_id) => {
762762
// Since Kani is single-threaded, we treat a thread local like a static variable:
763763
self.store_concurrent_construct("thread local (replaced by static variable)", loc);
764-
self.codegen_static_pointer(*def_id, true)
764+
self.codegen_thread_local_pointer(*def_id)
765765
}
766766
// A CopyForDeref is equivalent to a read from a place at the codegen level.
767767
// https://github.com/rust-lang/rust/blob/1673f1450eeaf4a5452e086db0fe2ae274a0144f/compiler/rustc_middle/src/mir/syntax.rs#L1055
@@ -1006,7 +1006,7 @@ impl<'tcx> GotocCtx<'tcx> {
10061006
.unwrap();
10071007
// We need to handle this case in a special way because `codegen_operand` compiles FnDefs to dummy structs.
10081008
// (cf. the function documentation)
1009-
self.codegen_func_expr(instance, None).address_of()
1009+
self.codegen_func_expr_internal(instance, None).address_of()
10101010
}
10111011
_ => unreachable!(),
10121012
},
@@ -1017,7 +1017,7 @@ impl<'tcx> GotocCtx<'tcx> {
10171017
Instance::resolve_closure(self.tcx, *def_id, args, ty::ClosureKind::FnOnce)
10181018
.expect("failed to normalize and resolve closure during codegen")
10191019
.polymorphize(self.tcx);
1020-
self.codegen_func_expr(instance, None).address_of()
1020+
self.codegen_func_expr_internal(instance, None).address_of()
10211021
} else {
10221022
unreachable!("{:?} cannot be cast to a fn ptr", operand)
10231023
}
@@ -1384,7 +1384,7 @@ impl<'tcx> GotocCtx<'tcx> {
13841384
(ty::Array(src_elt_type, src_elt_count), ty::Slice(dst_elt_type)) => {
13851385
// Cast to a slice fat pointer.
13861386
assert_eq!(src_elt_type, dst_elt_type);
1387-
let dst_goto_len = self.codegen_const(*src_elt_count, None);
1387+
let dst_goto_len = self.codegen_const_internal(*src_elt_count, None);
13881388
let src_pointee_ty = pointee_type(coerce_info.src_ty).unwrap();
13891389
let dst_data_expr = if src_pointee_ty.is_array() {
13901390
src_goto_expr.cast_to(self.codegen_ty(*src_elt_type).to_pointer())

Diff for: kani-compiler/src/codegen_cprover_gotoc/codegen/span.rs

+5
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ impl<'tcx> GotocCtx<'tcx> {
2727
Some(loc.end_col),
2828
)
2929
}
30+
31+
pub fn codegen_span_option_stable(&self, sp: Option<SpanStable>) -> Location {
32+
sp.map_or(Location::none(), |span| self.codegen_span_stable(span))
33+
}
34+
3035
pub fn codegen_caller_span_stable(&self, sp: SpanStable) -> Location {
3136
self.codegen_caller_span(&Some(rustc_internal::internal(sp)))
3237
}

Diff for: kani-compiler/src/codegen_cprover_gotoc/codegen/statement.rs

+13-2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use rustc_smir::rustc_internal;
1818
use rustc_span::Span;
1919
use rustc_target::abi::VariantIdx;
2020
use rustc_target::abi::{FieldsShape, Primitive, TagEncoding, Variants};
21+
use stable_mir::mir::Place as PlaceStable;
2122
use tracing::{debug, debug_span, trace};
2223

2324
impl<'tcx> GotocCtx<'tcx> {
@@ -346,7 +347,7 @@ impl<'tcx> GotocCtx<'tcx> {
346347
// Non-virtual, direct drop_in_place call
347348
assert!(!matches!(drop_instance.def, InstanceDef::Virtual(_, _)));
348349

349-
let func = self.codegen_func_expr(drop_instance, None);
350+
let func = self.codegen_func_expr_internal(drop_instance, None);
350351
// The only argument should be a self reference
351352
let args = vec![place_ref];
352353

@@ -567,7 +568,7 @@ impl<'tcx> GotocCtx<'tcx> {
567568
| InstanceDef::CloneShim(..) => {
568569
// We need to handle FnDef items in a special way because `codegen_operand` compiles them to dummy structs.
569570
// (cf. the function documentation)
570-
let func_exp = self.codegen_func_expr(instance, None);
571+
let func_exp = self.codegen_func_expr_internal(instance, None);
571572
vec![
572573
self.codegen_expr_to_place(destination, func_exp.call(fargs))
573574
.with_location(loc),
@@ -697,6 +698,16 @@ impl<'tcx> GotocCtx<'tcx> {
697698
/// A MIR [Place] is an L-value (i.e. the LHS of an assignment).
698699
///
699700
/// In Kani, we slightly optimize the special case for Unit and don't assign anything.
701+
pub(crate) fn codegen_expr_to_place_stable(&mut self, p: &PlaceStable, e: Expr) -> Stmt {
702+
if e.typ().is_unit() {
703+
e.as_stmt(Location::none())
704+
} else {
705+
unwrap_or_return_codegen_unimplemented_stmt!(self, self.codegen_place_stable(p))
706+
.goto_expr
707+
.assign(e, Location::none())
708+
}
709+
}
710+
700711
pub(crate) fn codegen_expr_to_place(&mut self, p: &Place<'tcx>, e: Expr) -> Stmt {
701712
if self.place_ty(p).is_unit() {
702713
e.as_stmt(Location::none())

Diff for: kani-compiler/src/codegen_cprover_gotoc/codegen/static_var.rs

+13-14
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@
55
66
use crate::codegen_cprover_gotoc::GotocCtx;
77
use cbmc::goto_program::Symbol;
8-
use rustc_hir::def_id::DefId;
9-
use rustc_middle::mir::mono::MonoItem;
10-
use rustc_middle::ty::{GenericArgs, Instance};
8+
use stable_mir::mir::mono::{Instance, StaticDef};
9+
use stable_mir::CrateDef;
1110
use tracing::debug;
1211

1312
impl<'tcx> GotocCtx<'tcx> {
@@ -16,24 +15,24 @@ impl<'tcx> GotocCtx<'tcx> {
1615
/// Note that each static variable have their own location in memory. Per Rust documentation:
1716
/// "statics declare global variables. These represent a memory address."
1817
/// Source: <https://rust-lang.github.io/rfcs/0246-const-vs-static.html>
19-
pub fn codegen_static(&mut self, def_id: DefId, item: MonoItem<'tcx>) {
18+
pub fn codegen_static(&mut self, def: StaticDef) {
2019
debug!("codegen_static");
21-
let alloc = self.tcx.eval_static_initializer(def_id).unwrap();
22-
let symbol_name = item.symbol_name(self.tcx).to_string();
23-
self.codegen_alloc_in_memory(alloc.inner(), symbol_name);
20+
let alloc = def.eval_initializer().unwrap();
21+
let symbol_name = Instance::from(def).mangled_name();
22+
self.codegen_alloc_in_memory(alloc, symbol_name);
2423
}
2524

2625
/// Mutates the Goto-C symbol table to add a forward-declaration of the static variable.
27-
pub fn declare_static(&mut self, def_id: DefId, item: MonoItem<'tcx>) {
26+
pub fn declare_static(&mut self, def: StaticDef) {
27+
let instance = Instance::from(def);
2828
// Unique mangled monomorphized name.
29-
let symbol_name = item.symbol_name(self.tcx).to_string();
29+
let symbol_name = instance.mangled_name();
3030
// Pretty name which may include function name.
31-
let pretty_name = Instance::new(def_id, GenericArgs::empty()).to_string();
32-
debug!(?symbol_name, ?pretty_name, "declare_static {}", item);
31+
let pretty_name = instance.name();
32+
debug!(?def, ?symbol_name, ?pretty_name, "declare_static");
3333

34-
let typ = self.codegen_ty(self.tcx.type_of(def_id).instantiate_identity());
35-
let span = self.tcx.def_span(def_id);
36-
let location = self.codegen_span(&span);
34+
let typ = self.codegen_ty_stable(instance.ty());
35+
let location = self.codegen_span_stable(def.span());
3736
let symbol = Symbol::static_variable(symbol_name.clone(), symbol_name, typ, location)
3837
.with_is_hidden(false) // Static items are always user defined.
3938
.with_pretty_name(pretty_name);

Diff for: kani-compiler/src/codegen_cprover_gotoc/codegen/ty_stable.rs

+60-4
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@ use crate::codegen_cprover_gotoc::GotocCtx;
1010
use cbmc::goto_program::Type;
1111
use rustc_middle::mir;
1212
use rustc_middle::mir::visit::{MutVisitor, NonUseContext, PlaceContext};
13-
use rustc_middle::mir::Place as PlaceInternal;
14-
use rustc_middle::ty::{Ty as TyInternal, TyCtxt};
13+
use rustc_middle::mir::{Operand as OperandInternal, Place as PlaceInternal};
14+
use rustc_middle::ty::{self, Const as ConstInternal, Ty as TyInternal, TyCtxt};
1515
use rustc_smir::rustc_internal;
16-
use stable_mir::mir::{Local, Place};
17-
use stable_mir::ty::{RigidTy, Ty, TyKind};
16+
use stable_mir::mir::mono::Instance;
17+
use stable_mir::mir::{Local, Operand, Place};
18+
use stable_mir::ty::{Const, RigidTy, Ty, TyKind};
1819

1920
impl<'tcx> GotocCtx<'tcx> {
2021
pub fn place_ty_stable(&self, place: &Place) -> Ty {
@@ -28,6 +29,31 @@ impl<'tcx> GotocCtx<'tcx> {
2829
pub fn local_ty_stable(&mut self, local: Local) -> Ty {
2930
self.current_fn().body().local_decl(local).unwrap().ty
3031
}
32+
33+
pub fn operand_ty_stable(&mut self, operand: &Operand) -> Ty {
34+
operand.ty(self.current_fn().body().locals()).unwrap()
35+
}
36+
37+
pub fn is_zst_stable(&self, ty: Ty) -> bool {
38+
self.is_zst(rustc_internal::internal(ty))
39+
}
40+
41+
pub fn codegen_fndef_type_stable(&mut self, instance: Instance) -> Type {
42+
let func = self.symbol_name_stable(instance);
43+
self.ensure_struct(
44+
format!("{func}::FnDefStruct"),
45+
format!("{}::FnDefStruct", instance.name()),
46+
|_, _| vec![],
47+
)
48+
}
49+
50+
pub fn fn_sig_of_instance_stable(&self, instance: Instance) -> ty::PolyFnSig<'tcx> {
51+
self.fn_sig_of_instance(rustc_internal::internal(instance))
52+
}
53+
54+
pub fn use_fat_pointer_stable(&self, pointer_ty: Ty) -> bool {
55+
self.use_fat_pointer(rustc_internal::internal(pointer_ty))
56+
}
3157
}
3258
/// If given type is a Ref / Raw ref, return the pointee type.
3359
pub fn pointee_type(mir_type: Ty) -> Option<Ty> {
@@ -59,6 +85,18 @@ impl<'a, 'tcx> StableConverter<'a, 'tcx> {
5985
);
6086
rustc_internal::stable(place)
6187
}
88+
89+
pub fn convert_operand(gcx: &'a GotocCtx<'tcx>, mut operand: OperandInternal<'tcx>) -> Operand {
90+
let mut converter = StableConverter { gcx };
91+
converter.visit_operand(&mut operand, mir::Location::START);
92+
rustc_internal::stable(operand)
93+
}
94+
95+
pub fn convert_constant(gcx: &'a GotocCtx<'tcx>, mut constant: ConstInternal<'tcx>) -> Const {
96+
let mut converter = StableConverter { gcx };
97+
converter.visit_ty_const(&mut constant, mir::Location::START);
98+
rustc_internal::stable(constant)
99+
}
62100
}
63101

64102
impl<'a, 'tcx> MutVisitor<'tcx> for StableConverter<'a, 'tcx> {
@@ -69,4 +107,22 @@ impl<'a, 'tcx> MutVisitor<'tcx> for StableConverter<'a, 'tcx> {
69107
fn visit_ty(&mut self, ty: &mut TyInternal<'tcx>, _: mir::visit::TyContext) {
70108
*ty = self.gcx.monomorphize(*ty);
71109
}
110+
111+
fn visit_ty_const(&mut self, ct: &mut ty::Const<'tcx>, _location: mir::Location) {
112+
*ct = self.gcx.monomorphize(*ct);
113+
}
114+
115+
fn visit_constant(&mut self, constant: &mut mir::ConstOperand<'tcx>, location: mir::Location) {
116+
let const_ = self.gcx.monomorphize(constant.const_);
117+
let val = match const_.eval(self.gcx.tcx, ty::ParamEnv::reveal_all(), None) {
118+
Ok(v) => v,
119+
Err(mir::interpret::ErrorHandled::Reported(..)) => return,
120+
Err(mir::interpret::ErrorHandled::TooGeneric(..)) => {
121+
unreachable!("Failed to evaluate instance constant: {:?}", const_)
122+
}
123+
};
124+
let ty = constant.ty();
125+
constant.const_ = mir::Const::Val(val, ty);
126+
self.super_constant(constant, location);
127+
}
72128
}

Diff for: kani-compiler/src/codegen_cprover_gotoc/codegen/typ.rs

+3-7
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use rustc_middle::ty::{
1818
UintTy, VariantDef, VtblEntry,
1919
};
2020
use rustc_middle::ty::{List, TypeFoldable};
21+
use rustc_smir::rustc_internal;
2122
use rustc_span::def_id::DefId;
2223
use rustc_target::abi::{
2324
Abi::Vector, FieldIdx, FieldsShape, Integer, LayoutS, Primitive, Size, TagEncoding,
@@ -680,7 +681,7 @@ impl<'tcx> GotocCtx<'tcx> {
680681
}
681682

682683
fn codegen_ty_raw_array(&mut self, elem_ty: Ty<'tcx>, len: Const<'tcx>) -> Type {
683-
let size = self.codegen_const(len, None).int_constant_value().unwrap();
684+
let size = self.codegen_const_internal(len, None).int_constant_value().unwrap();
684685
let elemt = self.codegen_ty(elem_ty);
685686
elemt.array_of(size)
686687
}
@@ -1323,12 +1324,7 @@ impl<'tcx> GotocCtx<'tcx> {
13231324
///
13241325
/// For details, see <https://github.com/model-checking/kani/pull/1338>
13251326
pub fn codegen_fndef_type(&mut self, instance: Instance<'tcx>) -> Type {
1326-
let func = self.symbol_name(instance);
1327-
self.ensure_struct(
1328-
format!("{func}::FnDefStruct"),
1329-
format!("{}::FnDefStruct", self.readable_instance_name(instance)),
1330-
|_, _| vec![],
1331-
)
1327+
self.codegen_fndef_type_stable(rustc_internal::stable(instance))
13321328
}
13331329

13341330
/// codegen for struct

Diff for: kani-compiler/src/codegen_cprover_gotoc/compiler_interface.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ use rustc_session::Session;
4646
use rustc_smir::rustc_internal;
4747
use rustc_target::abi::Endian;
4848
use rustc_target::spec::PanicStrategy;
49+
use stable_mir::mir::mono::MonoItem as MonoItemStable;
4950
use std::any::Any;
5051
use std::collections::BTreeMap;
5152
use std::collections::HashSet;
@@ -111,8 +112,11 @@ impl GotocCodegenBackend {
111112
);
112113
}
113114
MonoItem::Static(def_id) => {
115+
let MonoItemStable::Static(def) = rustc_internal::stable(item) else {
116+
unreachable!()
117+
};
114118
gcx.call_with_panic_debug_info(
115-
|ctx| ctx.declare_static(def_id, *item),
119+
|ctx| ctx.declare_static(def),
116120
format!("declare_static: {def_id:?}"),
117121
def_id,
118122
);
@@ -136,8 +140,11 @@ impl GotocCodegenBackend {
136140
);
137141
}
138142
MonoItem::Static(def_id) => {
143+
let MonoItemStable::Static(def) = rustc_internal::stable(item) else {
144+
unreachable!()
145+
};
139146
gcx.call_with_panic_debug_info(
140-
|ctx| ctx.codegen_static(def_id, *item),
147+
|ctx| ctx.codegen_static(def),
141148
format!("codegen_static: {def_id:?}"),
142149
def_id,
143150
);

0 commit comments

Comments
 (0)