From a0795b32b58b75b0088277f3ef88817298dc2f97 Mon Sep 17 00:00:00 2001 From: Thomas Del Vecchio Date: Thu, 20 May 2021 17:24:13 -0400 Subject: [PATCH] Added argument casting when type is same. --- .../src/gotoc/cbmc/goto_program/builtin.rs | 6 ++- .../src/gotoc/cbmc/goto_program/expr.rs | 37 +++++++++++++++++++ .../src/gotoc/cbmc/goto_program/typ.rs | 11 ++++++ .../rustc_codegen_llvm/src/gotoc/intrinsic.rs | 9 ++++- .../Cast/cast_abstract_args_to_concrete.rs | 35 ++++++++++++++++++ 5 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 rust-tests/cbmc-reg/Cast/cast_abstract_args_to_concrete.rs diff --git a/compiler/rustc_codegen_llvm/src/gotoc/cbmc/goto_program/builtin.rs b/compiler/rustc_codegen_llvm/src/gotoc/cbmc/goto_program/builtin.rs index 6f723bebbf1b..129add00023f 100644 --- a/compiler/rustc_codegen_llvm/src/gotoc/cbmc/goto_program/builtin.rs +++ b/compiler/rustc_codegen_llvm/src/gotoc/cbmc/goto_program/builtin.rs @@ -292,7 +292,11 @@ impl BuiltinFn { Symbol::builtin_function(&self.to_string(), self.param_types(), self.return_type()) } + pub fn as_expr(&self) -> Expr { + self.as_symbol().to_expr() + } + pub fn call(&self, arguments: Vec, loc: Location) -> Expr { - self.as_symbol().to_expr().with_location(loc.clone()).call(arguments).with_location(loc) + self.as_expr().with_location(loc.clone()).call(arguments).with_location(loc) } } diff --git a/compiler/rustc_codegen_llvm/src/gotoc/cbmc/goto_program/expr.rs b/compiler/rustc_codegen_llvm/src/gotoc/cbmc/goto_program/expr.rs index 66519bd0e020..fc3b8760b658 100644 --- a/compiler/rustc_codegen_llvm/src/gotoc/cbmc/goto_program/expr.rs +++ b/compiler/rustc_codegen_llvm/src/gotoc/cbmc/goto_program/expr.rs @@ -416,6 +416,43 @@ impl Expr { } } + /// Casts value to new_typ, only when the current type of value + /// is equivalent to new_typ on the given machine (e.g. i32 -> c_int) + pub fn cast_between_machine_equivalent_types( + value: Expr, + new_typ: &Type, + mm: &MachineModel, + ) -> Expr { + if value.typ() == new_typ { + value + } else { + assert!(value.typ().is_equal_on_machine(new_typ, mm)); + value.cast_to(new_typ.clone()) + } + } + + /// Casts arguments to type of function parameters when the corresponding types + /// are equivalent on the given machine (e.g. i32 -> c_int) + pub fn cast_arguments_to_machine_equivalent_function_parameter_types( + function: &Expr, + mut arguments: Vec, + mm: &MachineModel, + ) -> Vec { + let parameters = function.typ().parameters().unwrap(); + assert!(arguments.len() >= parameters.len()); + let mut rval: Vec<_> = parameters + .iter() + .map(|parameter| { + let argument = arguments.remove(0); + Self::cast_between_machine_equivalent_types(argument, ¶meter.typ(), mm) + }) + .collect(); + + rval.append(&mut arguments); + + rval + } + /// *self: t pub fn dereference(self) -> Self { assert!(self.typ.is_pointer()); diff --git a/compiler/rustc_codegen_llvm/src/gotoc/cbmc/goto_program/typ.rs b/compiler/rustc_codegen_llvm/src/gotoc/cbmc/goto_program/typ.rs index a74b9d550f2e..6d1eee2602ef 100644 --- a/compiler/rustc_codegen_llvm/src/gotoc/cbmc/goto_program/typ.rs +++ b/compiler/rustc_codegen_llvm/src/gotoc/cbmc/goto_program/typ.rs @@ -366,6 +366,17 @@ impl Type { } } + /// Whether self and other have the same concrete type on the given machine + /// (specifically whether they have the same bit-size and signed-ness) + pub fn is_equal_on_machine(&self, other: &Self, mm: &MachineModel) -> bool { + if self == other { + true + } else { + self.native_width(mm) == other.native_width(mm) + && self.is_signed(mm) == other.is_signed(mm) + } + } + pub fn is_float(&self) -> bool { match self { Float => true, diff --git a/compiler/rustc_codegen_llvm/src/gotoc/intrinsic.rs b/compiler/rustc_codegen_llvm/src/gotoc/intrinsic.rs index 429599cb1e2e..14cb15d01051 100644 --- a/compiler/rustc_codegen_llvm/src/gotoc/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/gotoc/intrinsic.rs @@ -83,7 +83,14 @@ impl<'tcx> GotocCtx<'tcx> { // TODO: https://github.com/model-checking/rmc/issues/5 macro_rules! codegen_simple_intrinsic { ($f:ident) => {{ - let e = BuiltinFn::$f.call(fargs, loc); + let mm = self.symbol_table.machine_model(); + let casted_fargs = + Expr::cast_arguments_to_machine_equivalent_function_parameter_types( + &BuiltinFn::$f.as_expr(), + fargs, + mm, + ); + let e = BuiltinFn::$f.call(casted_fargs, loc); self.codegen_expr_to_place(p, e) }}; } diff --git a/rust-tests/cbmc-reg/Cast/cast_abstract_args_to_concrete.rs b/rust-tests/cbmc-reg/Cast/cast_abstract_args_to_concrete.rs new file mode 100644 index 000000000000..659384c9ccdf --- /dev/null +++ b/rust-tests/cbmc-reg/Cast/cast_abstract_args_to_concrete.rs @@ -0,0 +1,35 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 OR MIT + +// This regression test is in response to issue #135. +// The type of the second parameter to powi is a `CInteger`, but +// the type of `2` here is a `u32`. This test ensures that +// rmc automatically casts the `2` to a `CInteger`. + +// More generally, this acts as a stand-in to make sure that +// abstract types (e.g. u32, i32) are automatically casted to +// their corresponding concrete types (e.g. int, float) when necessary. + +// The only function with this issue I could find was `powi` +// for `f32` and `f64`. The only other built-in that uses a +// `c_int` type is `libc::memset`, which seems to work fine, +// but is included here for certainty. +#![feature(rustc_private)] +extern crate libc; + +use std::mem; + +fn main() { + let _x32 = 1.0f32.powi(2); + let _x64 = 1.0f64.powi(2); + + unsafe { + let size: libc::size_t = mem::size_of::(); + let my_num: *mut libc::c_void = libc::malloc(size); + if my_num.is_null() { + panic!("failed to allocate memory"); + } + let my_num2 = libc::memset(my_num, 1, size); + libc::free(my_num); + } +}