Skip to content
Merged
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
34 changes: 27 additions & 7 deletions src/abi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ use crate::base::codegen_unwind_terminate;
use crate::debuginfo::EXCEPTION_HANDLER_CLEANUP;
use crate::prelude::*;

struct ArgValue<'tcx> {
value: CValue<'tcx>,
is_underaligned_pointee: bool,
}

fn clif_sig_from_fn_abi<'tcx>(
tcx: TyCtxt<'tcx>,
default_call_conv: CallConv,
Expand Down Expand Up @@ -245,8 +250,8 @@ pub(crate) fn codegen_fn_prelude<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, start_

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

// FIXME implement variadics in cranelift
Expand Down Expand Up @@ -299,8 +304,12 @@ 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 param = cvalue_for_param(fx, None, None, arg_abi, &mut block_params_iter).unwrap();
assert!(
!param.is_underaligned_pointee,
"caller location argument should not be underaligned",
);
fx.caller_location = Some(param.value);
}

assert_eq!(arg_abis_iter.next(), None, "ArgAbi left behind for {:?}", fx.fn_abi);
Expand All @@ -311,7 +320,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(Some(ArgValue { value: val, is_underaligned_pointee: false })) =
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 @@ -338,13 +349,22 @@ pub(crate) fn codegen_fn_prelude<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, start_
match arg_kind {
ArgKind::Normal(param) => {
if let Some(param) = param {
place.write_cvalue(fx, param);
if param.is_underaligned_pointee {
place.write_cvalue_transmute(fx, param.value);
} else {
place.write_cvalue(fx, param.value);
}
}
}
ArgKind::Spread(params) => {
for (i, param) 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 param.is_underaligned_pointee {
field_place.write_cvalue_transmute(fx, param.value);
} else {
field_place.write_cvalue(fx, param.value);
}
}
}
}
Expand Down
41 changes: 27 additions & 14 deletions src/abi/pass_mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use rustc_target::callconv::{
};
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>> {
) -> Option<ArgValue<'tcx>> {
let block_params = arg_abi
.get_abi_param(fx.tcx)
.into_iter()
Expand All @@ -305,30 +306,42 @@ pub(super) fn cvalue_for_param<'tcx>(
arg_abi.layout,
);

match arg_abi.mode {
PassMode::Ignore => None,
let value = match arg_abi.mode {
PassMode::Ignore => return None,
PassMode::Direct(_) => {
assert_eq!(block_params.len(), 1, "{:?}", block_params);
Some(CValue::by_val(block_params[0], arg_abi.layout))
CValue::by_val(block_params[0], arg_abi.layout)
}
PassMode::Pair(_, _) => {
assert_eq!(block_params.len(), 2, "{:?}", block_params);
Some(CValue::by_val_pair(block_params[0], block_params[1], arg_abi.layout))
CValue::by_val_pair(block_params[0], block_params[1], arg_abi.layout)
}
PassMode::Cast { ref cast, .. } => {
Some(from_casted_value(fx, &block_params, arg_abi.layout, cast))
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 pointer: treat as `[u8; size]` and transmute-copy into the real type.
let bytes_ty = Ty::new_array(fx.tcx, fx.tcx.types.u8, arg_abi.layout.size.bytes());
let bytes_layout = fx.layout_of(bytes_ty);
return Some(ArgValue {
value: CValue::by_ref(Pointer::new(block_params[0]), bytes_layout),
is_underaligned_pointee: true,
});
} else {
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);
Some(CValue::by_ref_unsized(
Pointer::new(block_params[0]),
block_params[1],
arg_abi.layout,
))
CValue::by_ref_unsized(Pointer::new(block_params[0]), block_params[1], arg_abi.layout)
}
}
};

Some(ArgValue { value, is_underaligned_pointee: false })
}
Loading