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
53 changes: 36 additions & 17 deletions src/abi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use cranelift_codegen::ir::{
};
use cranelift_codegen::isa::CallConv;
use cranelift_module::ModuleError;
use rustc_abi::{CanonAbi, ExternAbi, X86Call};
use rustc_abi::{Align, CanonAbi, ExternAbi, X86Call};
use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization;
use rustc_codegen_ssa::errors::CompilerBuiltinsCannotCall;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
Expand All @@ -31,6 +31,11 @@ use crate::base::codegen_unwind_terminate;
use crate::debuginfo::EXCEPTION_HANDLER_CLEANUP;
use crate::prelude::*;

pub(super) struct ArgValue<'tcx> {
pub(super) value: Option<CValue<'tcx>>,
pub(super) underaligned_pointee_align: Option<Align>,
}

fn clif_sig_from_fn_abi<'tcx>(
tcx: TyCtxt<'tcx>,
default_call_conv: CallConv,
Expand Down Expand Up @@ -243,10 +248,9 @@ pub(crate) fn codegen_fn_prelude<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, start_
self::returning::codegen_return_param(fx, &ssa_analyzed, &mut block_params_iter);
assert_eq!(fx.local_map.push(ret_place), RETURN_PLACE);

// None means pass_mode == NoPass
enum ArgKind<'tcx> {
Normal(Option<CValue<'tcx>>),
Spread(Vec<Option<CValue<'tcx>>>),
Normal(ArgValue<'tcx>),
Spread(Vec<ArgValue<'tcx>>),
}

// FIXME implement variadics in cranelift
Expand Down Expand Up @@ -280,17 +284,20 @@ pub(crate) fn codegen_fn_prelude<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, start_
let mut params = Vec::new();
for (i, _arg_ty) in tupled_arg_tys.iter().enumerate() {
let arg_abi = arg_abis_iter.next().unwrap();
let param =
cvalue_for_param(fx, Some(local), Some(i), arg_abi, &mut block_params_iter);
params.push(param);
params.push(cvalue_for_param(
fx,
Some(local),
Some(i),
arg_abi,
&mut block_params_iter,
));
}

(local, ArgKind::Spread(params), arg_ty)
} else {
let arg_abi = arg_abis_iter.next().unwrap();
let param =
cvalue_for_param(fx, Some(local), None, arg_abi, &mut block_params_iter);
(local, ArgKind::Normal(param), arg_ty)
let arg = cvalue_for_param(fx, Some(local), None, arg_abi, &mut block_params_iter);
(local, ArgKind::Normal(arg), arg_ty)
}
})
.collect::<Vec<(Local, ArgKind<'tcx>, Ty<'tcx>)>>();
Expand All @@ -299,8 +306,8 @@ pub(crate) fn codegen_fn_prelude<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, start_
if fx.instance.def.requires_caller_location(fx.tcx) {
// Store caller location for `#[track_caller]`.
let arg_abi = arg_abis_iter.next().unwrap();
fx.caller_location =
Some(cvalue_for_param(fx, None, None, arg_abi, &mut block_params_iter).unwrap());
let arg = cvalue_for_param(fx, None, None, arg_abi, &mut block_params_iter);
fx.caller_location = Some(arg.value.unwrap());
}

assert_eq!(arg_abis_iter.next(), None, "ArgAbi left behind for {:?}", fx.fn_abi);
Expand All @@ -311,7 +318,9 @@ pub(crate) fn codegen_fn_prelude<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, start_
for (local, arg_kind, ty) in func_params {
// While this is normally an optimization to prevent an unnecessary copy when an argument is
// not mutated by the current function, this is necessary to support unsized arguments.
if let ArgKind::Normal(Some(val)) = arg_kind {
if let ArgKind::Normal(ArgValue { value: Some(val), underaligned_pointee_align: None }) =
arg_kind
{
if let Some((addr, meta)) = val.try_to_ptr() {
// Ownership of the value at the backing storage for an argument is passed to the
// callee per the ABI, so it is fine to borrow the backing storage of this argument
Expand All @@ -336,15 +345,25 @@ pub(crate) fn codegen_fn_prelude<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, start_
assert_eq!(fx.local_map.push(place), local);

match arg_kind {
ArgKind::Normal(param) => {
if let Some(param) = param {
ArgKind::Normal(ArgValue { value: Some(param), underaligned_pointee_align }) => {
if underaligned_pointee_align.is_some() {
place.write_cvalue_transmute(fx, param);
} else {
place.write_cvalue(fx, param);
}
}
ArgKind::Normal(ArgValue { value: None, underaligned_pointee_align: _ }) => {}
ArgKind::Spread(params) => {
for (i, param) in params.into_iter().enumerate() {
for (i, ArgValue { value: param, underaligned_pointee_align }) in
params.into_iter().enumerate()
{
if let Some(param) = param {
place.place_field(fx, FieldIdx::new(i)).write_cvalue(fx, param);
let field_place = place.place_field(fx, FieldIdx::new(i));
if underaligned_pointee_align.is_some() {
field_place.write_cvalue_transmute(fx, param);
} else {
field_place.write_cvalue(fx, param);
}
}
}
}
Expand Down
29 changes: 23 additions & 6 deletions src/abi/pass_mode.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
//! Argument passing

use cranelift_codegen::ir::ArgumentPurpose;
use rustc_abi::{Reg, RegKind};
use rustc_abi::{Align, Reg, RegKind};
use rustc_target::callconv::{
ArgAbi, ArgAttributes, ArgExtension as RustcArgExtension, CastTarget, PassMode,
};
use smallvec::{SmallVec, smallvec};

use super::ArgValue;
use crate::prelude::*;
use crate::value_and_place::assert_assignable;

Expand Down Expand Up @@ -284,7 +285,7 @@ pub(super) fn cvalue_for_param<'tcx>(
local_field: Option<usize>,
arg_abi: &ArgAbi<'tcx, Ty<'tcx>>,
block_params_iter: &mut impl Iterator<Item = Value>,
) -> Option<CValue<'tcx>> {
) -> ArgValue<'tcx> {
let block_params = arg_abi
.get_abi_param(fx.tcx)
.into_iter()
Expand All @@ -305,7 +306,8 @@ pub(super) fn cvalue_for_param<'tcx>(
arg_abi.layout,
);

match arg_abi.mode {
let mut underaligned_pointee_align: Option<Align> = None;
let value = match arg_abi.mode {
PassMode::Ignore => None,
PassMode::Direct(_) => {
assert_eq!(block_params.len(), 1, "{:?}", block_params);
Expand All @@ -318,9 +320,22 @@ pub(super) fn cvalue_for_param<'tcx>(
PassMode::Cast { ref cast, .. } => {
Some(from_casted_value(fx, &block_params, arg_abi.layout, cast))
}
PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => {
PassMode::Indirect { attrs, meta_attrs: None, on_stack: _ } => {
assert_eq!(block_params.len(), 1, "{:?}", block_params);
Some(CValue::by_ref(Pointer::new(block_params[0]), arg_abi.layout))
if let Some(pointee_align) = attrs.pointee_align
&& pointee_align < arg_abi.layout.align.abi
&& arg_abi.layout.is_sized()
&& arg_abi.layout.size != Size::ZERO
{
underaligned_pointee_align = Some(pointee_align);
// Underaligned pointer: treat as `[u8; size]` and transmute-copy into the real type.
let len = ty::Const::from_target_usize(fx.tcx, arg_abi.layout.size.bytes());
let bytes_ty = fx.tcx.mk_ty_from_kind(ty::Array(fx.tcx.types.u8, len));
let bytes_layout = fx.layout_of(bytes_ty);
Some(CValue::by_ref(Pointer::new(block_params[0]), bytes_layout))
} else {
Some(CValue::by_ref(Pointer::new(block_params[0]), arg_abi.layout))
}
}
PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
assert_eq!(block_params.len(), 2, "{:?}", block_params);
Expand All @@ -330,5 +345,7 @@ pub(super) fn cvalue_for_param<'tcx>(
arg_abi.layout,
))
}
}
};

ArgValue { value, underaligned_pointee_align }
}
Loading