Skip to content

Commit f94b714

Browse files
authored
Migrate intrinsics module to use StableMIR (rust-lang#2939)
This one was fairly straight forward. It still uses a few internal APIs for user friendly errors, for type layout, SIMD information and intrinsic validity.
1 parent a7c239e commit f94b714

File tree

8 files changed

+399
-367
lines changed

8 files changed

+399
-367
lines changed

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

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ impl<'tcx> GotocCtx<'tcx> {
150150

151151
/// Generate a cover statement for code coverage reports.
152152
pub fn codegen_coverage(&self, span: Span) -> Stmt {
153-
let loc = self.codegen_caller_span(&Some(span));
153+
let loc = self.codegen_caller_span(&span);
154154
// Should use Stmt::cover, but currently this doesn't work with CBMC
155155
// unless it is run with '--cover cover' (see
156156
// https://github.com/diffblue/cbmc/issues/6613). So for now use
@@ -214,9 +214,9 @@ impl<'tcx> GotocCtx<'tcx> {
214214
&self,
215215
property_class: PropertyClass,
216216
msg: &str,
217-
span: Option<Span>,
217+
span: SpanStable,
218218
) -> Stmt {
219-
let loc = self.codegen_caller_span(&span);
219+
let loc = self.codegen_caller_span_stable(span);
220220
self.codegen_assert_assume_false(property_class, msg, loc)
221221
}
222222

@@ -228,9 +228,7 @@ impl<'tcx> GotocCtx<'tcx> {
228228
let msg = self.extract_const_message(&fargs[0]).unwrap_or(String::from(
229229
"This is a placeholder message; Kani doesn't support message formatted at runtime",
230230
));
231-
232-
let loc = self.codegen_caller_span_stable(span);
233-
self.codegen_assert_assume_false(PropertyClass::Assertion, &msg, loc)
231+
self.codegen_fatal_error(PropertyClass::Assertion, &msg, span)
234232
}
235233

236234
/// Kani does not currently support all MIR constructs.

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

Lines changed: 331 additions & 301 deletions
Large diffs are not rendered by default.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ impl<'tcx> GotocCtx<'tcx> {
393393
// Check that computing `offset` in bytes would not overflow
394394
let (offset_bytes, bytes_overflow_check) = self.count_in_bytes(
395395
ce2.clone().cast_to(Type::ssize_t()),
396-
rustc_internal::internal(ty),
396+
ty,
397397
Type::ssize_t(),
398398
"offset",
399399
loc,

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

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,20 +33,16 @@ impl<'tcx> GotocCtx<'tcx> {
3333
}
3434

3535
pub fn codegen_caller_span_stable(&self, sp: SpanStable) -> Location {
36-
self.codegen_caller_span(&Some(rustc_internal::internal(sp)))
36+
self.codegen_caller_span(&rustc_internal::internal(sp))
3737
}
3838

3939
/// Get the location of the caller. This will attempt to reach the macro caller.
4040
/// This function uses rustc_span methods designed to returns span for the macro which
4141
/// originally caused the expansion to happen.
4242
/// Note: The API stops backtracing at include! boundary.
43-
pub fn codegen_caller_span(&self, sp: &Option<Span>) -> Location {
44-
if let Some(span) = sp {
45-
let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(*span);
46-
self.codegen_span(&topmost)
47-
} else {
48-
Location::none()
49-
}
43+
pub fn codegen_caller_span(&self, span: &Span) -> Location {
44+
let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(*span);
45+
self.codegen_span(&topmost)
5046
}
5147

5248
pub fn codegen_span_option(&self, sp: Option<Span>) -> Location {

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

Lines changed: 37 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use super::typ::TypeExt;
44
use super::typ::FN_RETURN_VOID_VAR_NAME;
55
use super::PropertyClass;
6+
use crate::codegen_cprover_gotoc::codegen::ty_stable::StableConverter;
67
use crate::codegen_cprover_gotoc::{GotocCtx, VtableCtx};
78
use crate::unwrap_or_return_codegen_unimplemented_stmt;
89
use cbmc::goto_program::{Expr, Location, Stmt, Type};
@@ -18,7 +19,7 @@ use rustc_smir::rustc_internal;
1819
use rustc_span::Span;
1920
use rustc_target::abi::VariantIdx;
2021
use rustc_target::abi::{FieldsShape, Primitive, TagEncoding, Variants};
21-
use stable_mir::mir::Place as PlaceStable;
22+
use stable_mir::mir::{Operand as OperandStable, Place as PlaceStable};
2223
use tracing::{debug, debug_span, trace};
2324

2425
impl<'tcx> GotocCtx<'tcx> {
@@ -68,15 +69,13 @@ impl<'tcx> GotocCtx<'tcx> {
6869
StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(
6970
mir::CopyNonOverlapping { ref src, ref dst, ref count },
7071
)) => {
72+
let operands =
73+
[src, dst, count].map(|op| StableConverter::convert_operand(self, op.clone()));
7174
// Pack the operands and their types, then call `codegen_copy`
72-
let fargs = vec![
73-
self.codegen_operand(src),
74-
self.codegen_operand(dst),
75-
self.codegen_operand(count),
76-
];
77-
let farg_types =
78-
&[self.operand_ty(src), self.operand_ty(dst), self.operand_ty(count)];
79-
self.codegen_copy("copy_nonoverlapping", true, fargs, farg_types, None, location)
75+
let fargs =
76+
operands.iter().map(|op| self.codegen_operand_stable(op)).collect::<Vec<_>>();
77+
let farg_types = operands.map(|op| self.operand_ty_stable(&op));
78+
self.codegen_copy("copy_nonoverlapping", true, fargs, &farg_types, None, location)
8079
}
8180
StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(ref op)) => {
8281
let cond = self.codegen_operand(op).cast_to(Type::bool());
@@ -474,20 +473,20 @@ impl<'tcx> GotocCtx<'tcx> {
474473
/// This is used because we ignore ZST arguments, except for intrinsics.
475474
pub(crate) fn codegen_funcall_args(
476475
&mut self,
477-
args: &[Operand<'tcx>],
476+
args: &[OperandStable],
478477
skip_zst: bool,
479478
) -> Vec<Expr> {
480479
let fargs = args
481480
.iter()
482-
.filter_map(|o| {
483-
let op_ty = self.operand_ty(o);
484-
if op_ty.is_bool() {
485-
Some(self.codegen_operand(o).cast_to(Type::c_bool()))
486-
} else if !self.is_zst(op_ty) || !skip_zst {
487-
Some(self.codegen_operand(o))
481+
.filter_map(|op| {
482+
let op_ty = self.operand_ty_stable(op);
483+
if op_ty.kind().is_bool() {
484+
Some(self.codegen_operand_stable(op).cast_to(Type::c_bool()))
485+
} else if !self.is_zst_stable(op_ty) || !skip_zst {
486+
Some(self.codegen_operand_stable(op))
488487
} else {
489488
// We ignore ZST types.
490-
debug!(arg=?o, "codegen_funcall_args ignore");
489+
debug!(arg=?op, "codegen_funcall_args ignore");
491490
None
492491
}
493492
})
@@ -517,13 +516,26 @@ impl<'tcx> GotocCtx<'tcx> {
517516
span: Span,
518517
) -> Stmt {
519518
debug!(?func, ?args, ?destination, ?span, "codegen_funcall");
520-
if self.is_intrinsic(func) {
521-
return self.codegen_funcall_of_intrinsic(func, args, destination, target, span);
519+
let func_stable = StableConverter::convert_operand(self, func.clone());
520+
let args_stable = args
521+
.iter()
522+
.map(|arg| StableConverter::convert_operand(self, arg.clone()))
523+
.collect::<Vec<_>>();
524+
let destination_stable = StableConverter::convert_place(self, *destination);
525+
526+
if self.is_intrinsic(&func_stable) {
527+
return self.codegen_funcall_of_intrinsic(
528+
&func_stable,
529+
&args_stable,
530+
&destination_stable,
531+
target.map(|bb| bb.index()),
532+
rustc_internal::stable(span),
533+
);
522534
}
523535

524536
let loc = self.codegen_span(&span);
525537
let funct = self.operand_ty(func);
526-
let mut fargs = self.codegen_funcall_args(args, true);
538+
let mut fargs = self.codegen_funcall_args(&args_stable, true);
527539
match &funct.kind() {
528540
ty::FnDef(defid, subst) => {
529541
let instance =
@@ -700,13 +712,13 @@ impl<'tcx> GotocCtx<'tcx> {
700712
/// A MIR [Place] is an L-value (i.e. the LHS of an assignment).
701713
///
702714
/// In Kani, we slightly optimize the special case for Unit and don't assign anything.
703-
pub(crate) fn codegen_expr_to_place_stable(&mut self, p: &PlaceStable, e: Expr) -> Stmt {
704-
if e.typ().is_unit() {
705-
e.as_stmt(Location::none())
715+
pub(crate) fn codegen_expr_to_place_stable(&mut self, place: &PlaceStable, expr: Expr) -> Stmt {
716+
if self.place_ty_stable(place).kind().is_unit() {
717+
expr.as_stmt(Location::none())
706718
} else {
707-
unwrap_or_return_codegen_unimplemented_stmt!(self, self.codegen_place_stable(p))
719+
unwrap_or_return_codegen_unimplemented_stmt!(self, self.codegen_place_stable(place))
708720
.goto_expr
709-
.assign(e, Location::none())
721+
.assign(expr, Location::none())
710722
}
711723
}
712724

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

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ impl<'tcx> GotocCtx<'tcx> {
3333
self.codegen_ty_ref(rustc_internal::internal(ty))
3434
}
3535

36-
pub fn local_ty_stable(&mut self, local: Local) -> Ty {
36+
pub fn local_ty_stable(&self, local: Local) -> Ty {
3737
self.current_fn().body().local_decl(local).unwrap().ty
3838
}
3939

40-
pub fn operand_ty_stable(&mut self, operand: &Operand) -> Ty {
40+
pub fn operand_ty_stable(&self, operand: &Operand) -> Ty {
4141
operand.ty(self.current_fn().body().locals()).unwrap()
4242
}
4343

@@ -89,6 +89,11 @@ impl<'tcx> GotocCtx<'tcx> {
8989
pub fn rvalue_ty_stable(&self, rvalue: &Rvalue) -> Ty {
9090
rvalue.ty(self.current_fn().body().locals()).unwrap()
9191
}
92+
93+
pub fn simd_size_and_type(&self, ty: Ty) -> (u64, Ty) {
94+
let (sz, ty) = rustc_internal::internal(ty).simd_size_and_type(self.tcx);
95+
(sz, rustc_internal::stable(ty))
96+
}
9297
}
9398
/// If given type is a Ref / Raw ref, return the pointee type.
9499
pub fn pointee_type(mir_type: Ty) -> Option<Ty> {
@@ -99,6 +104,14 @@ pub fn pointee_type(mir_type: Ty) -> Option<Ty> {
99104
}
100105
}
101106

107+
/// Convert a type into a user readable type representation.
108+
///
109+
/// This should be replaced by StableMIR `pretty_ty()` after
110+
/// <https://github.com/rust-lang/rust/pull/118364> is merged.
111+
pub fn pretty_ty(ty: Ty) -> String {
112+
rustc_internal::internal(ty).to_string()
113+
}
114+
102115
/// Convert internal rustc's structs into StableMIR ones.
103116
///
104117
/// The body of a StableMIR instance already comes monomorphized, which is different from rustc's

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

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1898,12 +1898,6 @@ fn common_vtable_fields(drop_in_place: Type) -> Vec<DatatypeComponent> {
18981898
fields
18991899
}
19001900

1901-
/// The mir type is a mir pointer type (Ref or RawPtr).
1902-
/// This will return false for all smart pointers. See is_std_pointer for a more complete check.
1903-
pub fn is_pointer(mir_type: Ty) -> bool {
1904-
return pointee_type(mir_type).is_some();
1905-
}
1906-
19071901
/// If given type is a Ref / Raw ref, return the pointee type.
19081902
pub fn pointee_type(mir_type: Ty) -> Option<Ty> {
19091903
match mir_type.kind() {

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

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
// Copyright Kani Contributors
22
// SPDX-License-Identifier: Apache-2.0 OR MIT
33
use super::super::codegen::TypeExt;
4-
use crate::codegen_cprover_gotoc::codegen::typ::{is_pointer, pointee_type};
54
use crate::codegen_cprover_gotoc::GotocCtx;
65
use cbmc::goto_program::{Expr, ExprValue, Location, SymbolTable, Type};
76
use cbmc::{btree_string_map, InternedString};
8-
use rustc_middle::ty::layout::LayoutOf;
9-
use rustc_middle::ty::Ty;
7+
use rustc_middle::ty::TyCtxt;
8+
use rustc_smir::rustc_internal;
9+
use stable_mir::ty::Span;
1010
use tracing::debug;
1111

1212
// Should move into rvalue
@@ -20,21 +20,6 @@ pub fn dynamic_fat_ptr(typ: Type, data: Expr, vtable: Expr, symbol_table: &Symbo
2020
}
2121

2222
impl<'tcx> GotocCtx<'tcx> {
23-
/// Generates an expression `(ptr as usize) % align_of(T) == 0`
24-
/// to determine if a pointer `ptr` with pointee type `T` is aligned.
25-
pub fn is_ptr_aligned(&mut self, typ: Ty<'tcx>, ptr: Expr) -> Expr {
26-
// Ensure `typ` is a pointer, then extract the pointee type
27-
assert!(is_pointer(typ));
28-
let pointee_type = pointee_type(typ).unwrap();
29-
// Obtain the alignment for the pointee type `T`
30-
let layout = self.layout_of(pointee_type);
31-
let align = Expr::int_constant(layout.align.abi.bytes(), Type::size_t());
32-
// Cast the pointer to `usize` and return the alignment expression
33-
let cast_ptr = ptr.cast_to(Type::size_t());
34-
let zero = Type::size_t().zero();
35-
cast_ptr.rem(align).eq(zero)
36-
}
37-
3823
pub fn unsupported_msg(item: &str, url: Option<&str>) -> String {
3924
let mut s = format!("{item} is not currently supported by Kani");
4025
if let Some(url) = url {
@@ -207,3 +192,7 @@ impl<'tcx> GotocCtx<'tcx> {
207192
assert!(component.typ().is_pointer() || component.typ().is_rust_fat_ptr(&self.symbol_table))
208193
}
209194
}
195+
196+
pub fn span_err(tcx: TyCtxt, span: Span, msg: String) {
197+
tcx.sess.span_err(rustc_internal::internal(span), msg);
198+
}

0 commit comments

Comments
 (0)