1
Fork 0

Move ArgAbi::pad_i32 into PassMode::Cast.

Because it's only needed for that variant. This shrinks the types and
clarifies the logic.
This commit is contained in:
Nicholas Nethercote 2022-08-25 22:19:38 +10:00
parent b853e8a619
commit f974617bda
14 changed files with 80 additions and 88 deletions

View file

@ -100,7 +100,10 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
} }
_ => unreachable!("{:?}", self.layout.abi), _ => unreachable!("{:?}", self.layout.abi),
}, },
PassMode::Cast(ref cast) => cast_target_to_abi_params(cast), PassMode::Cast(ref cast, pad_i32) => {
assert!(!pad_i32, "padding support not yet implemented");
cast_target_to_abi_params(cast)
}
PassMode::Indirect { attrs, extra_attrs: None, on_stack } => { PassMode::Indirect { attrs, extra_attrs: None, on_stack } => {
if on_stack { if on_stack {
// Abi requires aligning struct size to pointer size // Abi requires aligning struct size to pointer size
@ -145,7 +148,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
} }
_ => unreachable!("{:?}", self.layout.abi), _ => unreachable!("{:?}", self.layout.abi),
}, },
PassMode::Cast(ref cast) => { PassMode::Cast(ref cast, _) => {
(None, cast_target_to_abi_params(cast).into_iter().collect()) (None, cast_target_to_abi_params(cast).into_iter().collect())
} }
PassMode::Indirect { attrs: _, extra_attrs: None, on_stack } => { PassMode::Indirect { attrs: _, extra_attrs: None, on_stack } => {
@ -226,7 +229,7 @@ pub(super) fn adjust_arg_for_abi<'tcx>(
let (a, b) = arg.load_scalar_pair(fx); let (a, b) = arg.load_scalar_pair(fx);
smallvec![a, b] smallvec![a, b]
} }
PassMode::Cast(ref cast) => to_casted_value(fx, arg, cast), PassMode::Cast(ref cast, _) => to_casted_value(fx, arg, cast),
PassMode::Indirect { .. } => { PassMode::Indirect { .. } => {
if is_owned { if is_owned {
match arg.force_stack(fx) { match arg.force_stack(fx) {
@ -284,7 +287,7 @@ pub(super) fn cvalue_for_param<'tcx>(
assert_eq!(block_params.len(), 2, "{:?}", block_params); assert_eq!(block_params.len(), 2, "{:?}", block_params);
Some(CValue::by_val_pair(block_params[0], block_params[1], arg_abi.layout)) Some(CValue::by_val_pair(block_params[0], block_params[1], arg_abi.layout))
} }
PassMode::Cast(ref cast) => { PassMode::Cast(ref cast, _) => {
Some(from_casted_value(fx, &block_params, arg_abi.layout, cast)) Some(from_casted_value(fx, &block_params, arg_abi.layout, cast))
} }
PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => { PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {

View file

@ -13,7 +13,7 @@ pub(super) fn codegen_return_param<'tcx>(
block_params_iter: &mut impl Iterator<Item = Value>, block_params_iter: &mut impl Iterator<Item = Value>,
) -> CPlace<'tcx> { ) -> CPlace<'tcx> {
let (ret_place, ret_param): (_, SmallVec<[_; 2]>) = match fx.fn_abi.as_ref().unwrap().ret.mode { let (ret_place, ret_param): (_, SmallVec<[_; 2]>) = match fx.fn_abi.as_ref().unwrap().ret.mode {
PassMode::Ignore | PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(_) => { PassMode::Ignore | PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(..) => {
let is_ssa = ssa_analyzed[RETURN_PLACE] == crate::analyze::SsaKind::Ssa; let is_ssa = ssa_analyzed[RETURN_PLACE] == crate::analyze::SsaKind::Ssa;
( (
super::make_local_place( super::make_local_place(
@ -75,7 +75,7 @@ pub(super) fn codegen_with_call_return_arg<'tcx>(
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => { PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
unreachable!("unsized return value") unreachable!("unsized return value")
} }
PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(_) => (None, None), PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(..) => (None, None),
}; };
let call_inst = f(fx, return_ptr); let call_inst = f(fx, return_ptr);
@ -92,7 +92,7 @@ pub(super) fn codegen_with_call_return_arg<'tcx>(
ret_place ret_place
.write_cvalue(fx, CValue::by_val_pair(ret_val_a, ret_val_b, ret_arg_abi.layout)); .write_cvalue(fx, CValue::by_val_pair(ret_val_a, ret_val_b, ret_arg_abi.layout));
} }
PassMode::Cast(ref cast) => { PassMode::Cast(ref cast, _) => {
let results = let results =
fx.bcx.inst_results(call_inst).iter().copied().collect::<SmallVec<[Value; 2]>>(); fx.bcx.inst_results(call_inst).iter().copied().collect::<SmallVec<[Value; 2]>>();
let result = let result =
@ -131,7 +131,7 @@ pub(crate) fn codegen_return(fx: &mut FunctionCx<'_, '_, '_>) {
let (ret_val_a, ret_val_b) = place.to_cvalue(fx).load_scalar_pair(fx); let (ret_val_a, ret_val_b) = place.to_cvalue(fx).load_scalar_pair(fx);
fx.bcx.ins().return_(&[ret_val_a, ret_val_b]); fx.bcx.ins().return_(&[ret_val_a, ret_val_b]);
} }
PassMode::Cast(ref cast) => { PassMode::Cast(ref cast, _) => {
let place = fx.get_local_place(RETURN_PLACE); let place = fx.get_local_place(RETURN_PLACE);
let ret_val = place.to_cvalue(fx); let ret_val = place.to_cvalue(fx);
let ret_vals = super::pass_mode::to_casted_value(fx, ret_val, cast); let ret_vals = super::pass_mode::to_casted_value(fx, ret_val, cast);

View file

@ -117,7 +117,7 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
match self.ret.mode { match self.ret.mode {
PassMode::Ignore => cx.type_void(), PassMode::Ignore => cx.type_void(),
PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_gcc_type(cx), PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_gcc_type(cx),
PassMode::Cast(ref cast) => cast.gcc_type(cx), PassMode::Cast(ref cast, _) => cast.gcc_type(cx),
PassMode::Indirect { .. } => { PassMode::Indirect { .. } => {
argument_tys.push(cx.type_ptr_to(self.ret.memory_ty(cx))); argument_tys.push(cx.type_ptr_to(self.ret.memory_ty(cx)));
cx.type_void() cx.type_void()
@ -125,11 +125,6 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
}; };
for arg in self.args.iter() { for arg in self.args.iter() {
// add padding
if arg.pad_i32 {
argument_tys.push(Reg::i32().gcc_type(cx));
}
let arg_ty = match arg.mode { let arg_ty = match arg.mode {
PassMode::Ignore => continue, PassMode::Ignore => continue,
PassMode::Direct(_) => arg.layout.immediate_gcc_type(cx), PassMode::Direct(_) => arg.layout.immediate_gcc_type(cx),
@ -141,7 +136,13 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
PassMode::Indirect { extra_attrs: Some(_), .. } => { PassMode::Indirect { extra_attrs: Some(_), .. } => {
unimplemented!(); unimplemented!();
} }
PassMode::Cast(ref cast) => cast.gcc_type(cx), PassMode::Cast(ref cast, pad_i32) => {
// add padding
if pad_i32 {
argument_tys.push(Reg::i32().gcc_type(cx));
}
cast.gcc_type(cx)
}
PassMode::Indirect { extra_attrs: None, on_stack: true, .. } => { PassMode::Indirect { extra_attrs: None, on_stack: true, .. } => {
on_stack_param_indices.insert(argument_tys.len()); on_stack_param_indices.insert(argument_tys.len());
arg.memory_ty(cx) arg.memory_ty(cx)

View file

@ -130,7 +130,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
sym::volatile_load | sym::unaligned_volatile_load => { sym::volatile_load | sym::unaligned_volatile_load => {
let tp_ty = substs.type_at(0); let tp_ty = substs.type_at(0);
let mut ptr = args[0].immediate(); let mut ptr = args[0].immediate();
if let PassMode::Cast(ty) = &fn_abi.ret.mode { if let PassMode::Cast(ty, _) = &fn_abi.ret.mode {
ptr = self.pointercast(ptr, self.type_ptr_to(ty.gcc_type(self))); ptr = self.pointercast(ptr, self.type_ptr_to(ty.gcc_type(self)));
} }
let load = self.volatile_load(ptr.get_type(), ptr); let load = self.volatile_load(ptr.get_type(), ptr);
@ -320,7 +320,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
}; };
if !fn_abi.ret.is_ignore() { if !fn_abi.ret.is_ignore() {
if let PassMode::Cast(ty) = &fn_abi.ret.mode { if let PassMode::Cast(ty, _) = &fn_abi.ret.mode {
let ptr_llty = self.type_ptr_to(ty.gcc_type(self)); let ptr_llty = self.type_ptr_to(ty.gcc_type(self));
let ptr = self.pointercast(result.llval, ptr_llty); let ptr = self.pointercast(result.llval, ptr_llty);
self.store(llval, ptr, result.align); self.store(llval, ptr, result.align);
@ -416,7 +416,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
else if self.is_unsized_indirect() { else if self.is_unsized_indirect() {
bug!("unsized `ArgAbi` must be handled through `store_fn_arg`"); bug!("unsized `ArgAbi` must be handled through `store_fn_arg`");
} }
else if let PassMode::Cast(ref cast) = self.mode { else if let PassMode::Cast(ref cast, _) = self.mode {
// FIXME(eddyb): Figure out when the simpler Store is safe, clang // FIXME(eddyb): Figure out when the simpler Store is safe, clang
// uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}. // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}.
let can_store_through_cast_ptr = false; let can_store_through_cast_ptr = false;
@ -481,7 +481,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
PassMode::Indirect { extra_attrs: Some(_), .. } => { PassMode::Indirect { extra_attrs: Some(_), .. } => {
OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst); OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst);
}, },
PassMode::Direct(_) | PassMode::Indirect { extra_attrs: None, .. } | PassMode::Cast(_) => { PassMode::Direct(_) | PassMode::Indirect { extra_attrs: None, .. } | PassMode::Cast(..) => {
let next_arg = next(); let next_arg = next();
self.store(bx, next_arg, dst); self.store(bx, next_arg, dst);
}, },

View file

@ -213,7 +213,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
OperandValue::Ref(val, None, self.layout.align.abi).store(bx, dst) OperandValue::Ref(val, None, self.layout.align.abi).store(bx, dst)
} else if self.is_unsized_indirect() { } else if self.is_unsized_indirect() {
bug!("unsized `ArgAbi` must be handled through `store_fn_arg`"); bug!("unsized `ArgAbi` must be handled through `store_fn_arg`");
} else if let PassMode::Cast(cast) = &self.mode { } else if let PassMode::Cast(cast, _) = &self.mode {
// FIXME(eddyb): Figure out when the simpler Store is safe, clang // FIXME(eddyb): Figure out when the simpler Store is safe, clang
// uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}. // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}.
let can_store_through_cast_ptr = false; let can_store_through_cast_ptr = false;
@ -283,7 +283,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
} }
PassMode::Direct(_) PassMode::Direct(_)
| PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } | PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ }
| PassMode::Cast(_) => { | PassMode::Cast(..) => {
let next_arg = next(); let next_arg = next();
self.store(bx, next_arg, dst); self.store(bx, next_arg, dst);
} }
@ -336,7 +336,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
let llreturn_ty = match &self.ret.mode { let llreturn_ty = match &self.ret.mode {
PassMode::Ignore => cx.type_void(), PassMode::Ignore => cx.type_void(),
PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_llvm_type(cx), PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_llvm_type(cx),
PassMode::Cast(cast) => cast.llvm_type(cx), PassMode::Cast(cast, _) => cast.llvm_type(cx),
PassMode::Indirect { .. } => { PassMode::Indirect { .. } => {
llargument_tys.push(cx.type_ptr_to(self.ret.memory_ty(cx))); llargument_tys.push(cx.type_ptr_to(self.ret.memory_ty(cx)));
cx.type_void() cx.type_void()
@ -344,11 +344,6 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
}; };
for arg in args { for arg in args {
// add padding
if arg.pad_i32 {
llargument_tys.push(Reg::i32().llvm_type(cx));
}
let llarg_ty = match &arg.mode { let llarg_ty = match &arg.mode {
PassMode::Ignore => continue, PassMode::Ignore => continue,
PassMode::Direct(_) => arg.layout.immediate_llvm_type(cx), PassMode::Direct(_) => arg.layout.immediate_llvm_type(cx),
@ -364,7 +359,13 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
llargument_tys.push(ptr_layout.scalar_pair_element_llvm_type(cx, 1, true)); llargument_tys.push(ptr_layout.scalar_pair_element_llvm_type(cx, 1, true));
continue; continue;
} }
PassMode::Cast(cast) => cast.llvm_type(cx), PassMode::Cast(cast, pad_i32) => {
// add padding
if *pad_i32 {
llargument_tys.push(Reg::i32().llvm_type(cx));
}
cast.llvm_type(cx)
}
PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => { PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
cx.type_ptr_to(arg.memory_ty(cx)) cx.type_ptr_to(arg.memory_ty(cx))
} }
@ -434,15 +435,12 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
let sret = llvm::CreateStructRetAttr(cx.llcx, self.ret.layout.llvm_type(cx)); let sret = llvm::CreateStructRetAttr(cx.llcx, self.ret.layout.llvm_type(cx));
attributes::apply_to_llfn(llfn, llvm::AttributePlace::Argument(i), &[sret]); attributes::apply_to_llfn(llfn, llvm::AttributePlace::Argument(i), &[sret]);
} }
PassMode::Cast(cast) => { PassMode::Cast(cast, _) => {
cast.attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn); cast.attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn);
} }
_ => {} _ => {}
} }
for arg in self.args.iter() { for arg in self.args.iter() {
if arg.pad_i32 {
apply(&ArgAttributes::new());
}
match &arg.mode { match &arg.mode {
PassMode::Ignore => {} PassMode::Ignore => {}
PassMode::Indirect { attrs, extra_attrs: None, on_stack: true } => { PassMode::Indirect { attrs, extra_attrs: None, on_stack: true } => {
@ -463,7 +461,10 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
apply(a); apply(a);
apply(b); apply(b);
} }
PassMode::Cast(cast) => { PassMode::Cast(cast, pad_i32) => {
if *pad_i32 {
apply(&ArgAttributes::new());
}
apply(&cast.attrs); apply(&cast.attrs);
} }
} }
@ -496,7 +497,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
let sret = llvm::CreateStructRetAttr(bx.cx.llcx, self.ret.layout.llvm_type(bx)); let sret = llvm::CreateStructRetAttr(bx.cx.llcx, self.ret.layout.llvm_type(bx));
attributes::apply_to_callsite(callsite, llvm::AttributePlace::Argument(i), &[sret]); attributes::apply_to_callsite(callsite, llvm::AttributePlace::Argument(i), &[sret]);
} }
PassMode::Cast(cast) => { PassMode::Cast(cast, _) => {
cast.attrs.apply_attrs_to_callsite( cast.attrs.apply_attrs_to_callsite(
llvm::AttributePlace::ReturnValue, llvm::AttributePlace::ReturnValue,
&bx.cx, &bx.cx,
@ -516,9 +517,6 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
} }
} }
for arg in self.args.iter() { for arg in self.args.iter() {
if arg.pad_i32 {
apply(bx.cx, &ArgAttributes::new());
}
match &arg.mode { match &arg.mode {
PassMode::Ignore => {} PassMode::Ignore => {}
PassMode::Indirect { attrs, extra_attrs: None, on_stack: true } => { PassMode::Indirect { attrs, extra_attrs: None, on_stack: true } => {
@ -542,7 +540,10 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
apply(bx.cx, a); apply(bx.cx, a);
apply(bx.cx, b); apply(bx.cx, b);
} }
PassMode::Cast(cast) => { PassMode::Cast(cast, pad_i32) => {
if *pad_i32 {
apply(bx.cx, &ArgAttributes::new());
}
apply(bx.cx, &cast.attrs); apply(bx.cx, &cast.attrs);
} }
} }

View file

@ -161,7 +161,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
sym::volatile_load | sym::unaligned_volatile_load => { sym::volatile_load | sym::unaligned_volatile_load => {
let tp_ty = substs.type_at(0); let tp_ty = substs.type_at(0);
let ptr = args[0].immediate(); let ptr = args[0].immediate();
let load = if let PassMode::Cast(ty) = &fn_abi.ret.mode { let load = if let PassMode::Cast(ty, _) = &fn_abi.ret.mode {
let llty = ty.llvm_type(self); let llty = ty.llvm_type(self);
let ptr = self.pointercast(ptr, self.type_ptr_to(llty)); let ptr = self.pointercast(ptr, self.type_ptr_to(llty));
self.volatile_load(llty, ptr) self.volatile_load(llty, ptr)
@ -374,7 +374,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
}; };
if !fn_abi.ret.is_ignore() { if !fn_abi.ret.is_ignore() {
if let PassMode::Cast(ty) = &fn_abi.ret.mode { if let PassMode::Cast(ty, _) = &fn_abi.ret.mode {
let ptr_llty = self.type_ptr_to(ty.llvm_type(self)); let ptr_llty = self.type_ptr_to(ty.llvm_type(self));
let ptr = self.pointercast(result.llval, ptr_llty); let ptr = self.pointercast(result.llval, ptr_llty);
self.store(llval, ptr, result.align); self.store(llval, ptr, result.align);

View file

@ -339,7 +339,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
} }
} }
PassMode::Cast(cast_ty) => { PassMode::Cast(cast_ty, _) => {
let op = match self.locals[mir::RETURN_PLACE] { let op = match self.locals[mir::RETURN_PLACE] {
LocalRef::Operand(Some(op)) => op, LocalRef::Operand(Some(op)) => op,
LocalRef::Operand(None) => bug!("use of return before def"), LocalRef::Operand(None) => bug!("use of return before def"),
@ -1158,39 +1158,35 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
llargs: &mut Vec<Bx::Value>, llargs: &mut Vec<Bx::Value>,
arg: &ArgAbi<'tcx, Ty<'tcx>>, arg: &ArgAbi<'tcx, Ty<'tcx>>,
) { ) {
// Fill padding with undef value, where applicable. match arg.mode {
if arg.pad_i32 { PassMode::Ignore => return,
llargs.push(bx.const_undef(bx.reg_backend_type(&Reg::i32()))) PassMode::Cast(_, true) => {
} // Fill padding with undef value, where applicable.
llargs.push(bx.const_undef(bx.reg_backend_type(&Reg::i32())));
if arg.is_ignore() { }
return; PassMode::Pair(..) => match op.val {
}
if let PassMode::Pair(..) = arg.mode {
match op.val {
Pair(a, b) => { Pair(a, b) => {
llargs.push(a); llargs.push(a);
llargs.push(b); llargs.push(b);
return; return;
} }
_ => bug!("codegen_argument: {:?} invalid for pair argument", op), _ => bug!("codegen_argument: {:?} invalid for pair argument", op),
} },
} else if arg.is_unsized_indirect() { PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => match op.val {
match op.val {
Ref(a, Some(b), _) => { Ref(a, Some(b), _) => {
llargs.push(a); llargs.push(a);
llargs.push(b); llargs.push(b);
return; return;
} }
_ => bug!("codegen_argument: {:?} invalid for unsized indirect argument", op), _ => bug!("codegen_argument: {:?} invalid for unsized indirect argument", op),
} },
_ => {}
} }
// Force by-ref if we have to load through a cast pointer. // Force by-ref if we have to load through a cast pointer.
let (mut llval, align, by_ref) = match op.val { let (mut llval, align, by_ref) = match op.val {
Immediate(_) | Pair(..) => match arg.mode { Immediate(_) | Pair(..) => match arg.mode {
PassMode::Indirect { .. } | PassMode::Cast(_) => { PassMode::Indirect { .. } | PassMode::Cast(..) => {
let scratch = PlaceRef::alloca(bx, arg.layout); let scratch = PlaceRef::alloca(bx, arg.layout);
op.val.store(bx, scratch); op.val.store(bx, scratch);
(scratch.llval, scratch.align, true) (scratch.llval, scratch.align, true)
@ -1222,7 +1218,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
if by_ref && !arg.is_indirect() { if by_ref && !arg.is_indirect() {
// Have to load the argument, maybe while casting it. // Have to load the argument, maybe while casting it.
if let PassMode::Cast(ty) = &arg.mode { if let PassMode::Cast(ty, _) = &arg.mode {
let llty = bx.cast_backend_type(ty); let llty = bx.cast_backend_type(ty);
let addr = bx.pointercast(llval, bx.type_ptr_to(llty)); let addr = bx.pointercast(llval, bx.type_ptr_to(llty));
llval = bx.load(llty, addr, align.min(arg.layout.align.abi)); llval = bx.load(llty, addr, align.min(arg.layout.align.abi));
@ -1622,7 +1618,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
} }
DirectOperand(index) => { DirectOperand(index) => {
// If there is a cast, we have to store and reload. // If there is a cast, we have to store and reload.
let op = if let PassMode::Cast(_) = ret_abi.mode { let op = if let PassMode::Cast(..) = ret_abi.mode {
let tmp = PlaceRef::alloca(bx, ret_abi.layout); let tmp = PlaceRef::alloca(bx, ret_abi.layout);
tmp.storage_live(bx); tmp.storage_live(bx);
bx.store_arg(&ret_abi, llval, tmp); bx.store_arg(&ret_abi, llval, tmp);

View file

@ -597,7 +597,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}; };
if !fn_abi.ret.is_ignore() { if !fn_abi.ret.is_ignore() {
if let PassMode::Cast(ty) = &fn_abi.ret.mode { if let PassMode::Cast(ty, _) = &fn_abi.ret.mode {
let ptr_llty = bx.type_ptr_to(bx.cast_backend_type(ty)); let ptr_llty = bx.type_ptr_to(bx.cast_backend_type(ty));
let ptr = bx.pointercast(result.llval, ptr_llty); let ptr = bx.pointercast(result.llval, ptr_llty);
bx.store(llval, ptr, result.align); bx.store(llval, ptr, result.align);

View file

@ -283,7 +283,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
for i in 0..tupled_arg_tys.len() { for i in 0..tupled_arg_tys.len() {
let arg = &fx.fn_abi.args[idx]; let arg = &fx.fn_abi.args[idx];
idx += 1; idx += 1;
if arg.pad_i32 { if let PassMode::Cast(_, true) = arg.mode {
llarg_idx += 1; llarg_idx += 1;
} }
let pr_field = place.project_field(bx, i); let pr_field = place.project_field(bx, i);
@ -309,7 +309,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
let arg = &fx.fn_abi.args[idx]; let arg = &fx.fn_abi.args[idx];
idx += 1; idx += 1;
if arg.pad_i32 { if let PassMode::Cast(_, true) = arg.mode {
llarg_idx += 1; llarg_idx += 1;
} }

View file

@ -215,8 +215,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
_ => false, _ => false,
} }
}; };
// Padding must be fully equal.
let pad_compat = || caller_abi.pad_i32 == callee_abi.pad_i32;
// When comparing the PassMode, we have to be smart about comparing the attributes. // When comparing the PassMode, we have to be smart about comparing the attributes.
let arg_attr_compat = |a1: &ArgAttributes, a2: &ArgAttributes| { let arg_attr_compat = |a1: &ArgAttributes, a2: &ArgAttributes| {
// There's only one regular attribute that matters for the call ABI: InReg. // There's only one regular attribute that matters for the call ABI: InReg.
@ -239,7 +237,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
(PassMode::Pair(a1, b1), PassMode::Pair(a2, b2)) => { (PassMode::Pair(a1, b1), PassMode::Pair(a2, b2)) => {
arg_attr_compat(a1, a2) && arg_attr_compat(b1, b2) arg_attr_compat(a1, a2) && arg_attr_compat(b1, b2)
} }
(PassMode::Cast(c1), PassMode::Cast(c2)) => c1 == c2, (PassMode::Cast(c1, pad1), PassMode::Cast(c2, pad2)) => c1 == c2 && pad1 == pad2,
( (
PassMode::Indirect { attrs: a1, extra_attrs: None, on_stack: s1 }, PassMode::Indirect { attrs: a1, extra_attrs: None, on_stack: s1 },
PassMode::Indirect { attrs: a2, extra_attrs: None, on_stack: s2 }, PassMode::Indirect { attrs: a2, extra_attrs: None, on_stack: s2 },
@ -251,7 +249,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
_ => false, _ => false,
}; };
if layout_compat() && pad_compat() && mode_compat() { if layout_compat() && mode_compat() {
return true; return true;
} }
trace!( trace!(

View file

@ -22,10 +22,8 @@ where
let align = arg.layout.align.max(dl.i32_align).min(dl.i64_align).abi; let align = arg.layout.align.max(dl.i32_align).min(dl.i64_align).abi;
if arg.layout.is_aggregate() { if arg.layout.is_aggregate() {
arg.cast_to(Uniform { unit: Reg::i32(), total: size }); let pad_i32 = !offset.is_aligned(align);
if !offset.is_aligned(align) { arg.cast_to_and_pad_i32(Uniform { unit: Reg::i32(), total: size }, pad_i32);
arg.pad_with_i32();
}
} else { } else {
arg.extend_integer_width_to(32); arg.extend_integer_width_to(32);
} }

View file

@ -40,9 +40,10 @@ pub enum PassMode {
/// ///
/// The argument has a layout abi of `ScalarPair`. /// The argument has a layout abi of `ScalarPair`.
Pair(ArgAttributes, ArgAttributes), Pair(ArgAttributes, ArgAttributes),
/// Pass the argument after casting it, to either /// Pass the argument after casting it, to either a single uniform or a
/// a single uniform or a pair of registers. /// pair of registers. The bool indicates if a `Reg::i32()` dummy argument
Cast(Box<CastTarget>), /// is emitted before the real argument.
Cast(Box<CastTarget>, bool),
/// Pass the argument indirectly via a hidden pointer. /// Pass the argument indirectly via a hidden pointer.
/// The `extra_attrs` value, if any, is for the extra data (vtable or length) /// The `extra_attrs` value, if any, is for the extra data (vtable or length)
/// which indicates that it refers to an unsized rvalue. /// which indicates that it refers to an unsized rvalue.
@ -463,10 +464,6 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)] #[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
pub struct ArgAbi<'a, Ty> { pub struct ArgAbi<'a, Ty> {
pub layout: TyAndLayout<'a, Ty>, pub layout: TyAndLayout<'a, Ty>,
/// Dummy argument, which is emitted before the real argument.
pub pad_i32: bool,
pub mode: PassMode, pub mode: PassMode,
} }
@ -486,7 +483,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
Abi::Vector { .. } => PassMode::Direct(ArgAttributes::new()), Abi::Vector { .. } => PassMode::Direct(ArgAttributes::new()),
Abi::Aggregate { .. } => PassMode::Direct(ArgAttributes::new()), Abi::Aggregate { .. } => PassMode::Direct(ArgAttributes::new()),
}; };
ArgAbi { layout, pad_i32: false, mode } ArgAbi { layout, mode }
} }
fn indirect_pass_mode(layout: &TyAndLayout<'a, Ty>) -> PassMode { fn indirect_pass_mode(layout: &TyAndLayout<'a, Ty>) -> PassMode {
@ -548,11 +545,11 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
} }
pub fn cast_to<T: Into<CastTarget>>(&mut self, target: T) { pub fn cast_to<T: Into<CastTarget>>(&mut self, target: T) {
self.mode = PassMode::Cast(Box::new(target.into())); self.mode = PassMode::Cast(Box::new(target.into()), false);
} }
pub fn pad_with_i32(&mut self) { pub fn cast_to_and_pad_i32<T: Into<CastTarget>>(&mut self, target: T, pad_i32: bool) {
self.pad_i32 = true; self.mode = PassMode::Cast(Box::new(target.into()), pad_i32);
} }
pub fn is_indirect(&self) -> bool { pub fn is_indirect(&self) -> bool {
@ -737,6 +734,6 @@ mod size_asserts {
use super::*; use super::*;
use rustc_data_structures::static_assert_size; use rustc_data_structures::static_assert_size;
// These are in alphabetical order, which is easy to maintain. // These are in alphabetical order, which is easy to maintain.
static_assert_size!(ArgAbi<'_, usize>, 64); static_assert_size!(ArgAbi<'_, usize>, 56);
static_assert_size!(FnAbi<'_, usize>, 88); static_assert_size!(FnAbi<'_, usize>, 80);
} }

View file

@ -22,10 +22,8 @@ where
let align = arg.layout.align.max(dl.i32_align).min(dl.i64_align).abi; let align = arg.layout.align.max(dl.i32_align).min(dl.i64_align).abi;
if arg.layout.is_aggregate() { if arg.layout.is_aggregate() {
arg.cast_to(Uniform { unit: Reg::i32(), total: size }); let pad_i32 = !offset.is_aligned(align);
if !offset.is_aligned(align) { arg.cast_to_and_pad_i32(Uniform { unit: Reg::i32(), total: size }, pad_i32);
arg.pad_with_i32();
}
} else { } else {
arg.extend_integer_width_to(32); arg.extend_integer_width_to(32);
} }

View file

@ -81,7 +81,7 @@ where
PassMode::Direct(ref mut attrs) => attrs, PassMode::Direct(ref mut attrs) => attrs,
PassMode::Pair(..) PassMode::Pair(..)
| PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } | PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ }
| PassMode::Cast(_) => { | PassMode::Cast(..) => {
unreachable!("x86 shouldn't be passing arguments by {:?}", arg.mode) unreachable!("x86 shouldn't be passing arguments by {:?}", arg.mode)
} }
}; };