Skip to content

Commit 02f6dd1

Browse files
committed
Use insertvalue and extractvalue instead of memcpy in CastTarget
1 parent 33d3787 commit 02f6dd1

File tree

10 files changed

+680
-422
lines changed

10 files changed

+680
-422
lines changed

compiler/rustc_codegen_llvm/src/abi.rs

+2-32
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
1-
use std::cmp;
2-
31
use libc::c_uint;
42
use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
53
use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue};
64
use rustc_codegen_ssa::traits::*;
7-
use rustc_codegen_ssa::MemFlags;
85
use rustc_middle::ty::layout::LayoutOf;
96
pub(crate) use rustc_middle::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
107
use rustc_middle::ty::Ty;
@@ -215,35 +212,8 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
215212
PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
216213
bug!("unsized `ArgAbi` must be handled through `store_fn_arg`");
217214
}
218-
PassMode::Cast { cast, pad_i32: _ } => {
219-
// The ABI mandates that the value is passed as a different struct representation.
220-
// Spill and reload it from the stack to convert from the ABI representation to
221-
// the Rust representation.
222-
let scratch_size = cast.size(bx);
223-
let scratch_align = cast.align(bx);
224-
// Note that the ABI type may be either larger or smaller than the Rust type,
225-
// due to the presence or absence of trailing padding. For example:
226-
// - On some ABIs, the Rust layout { f64, f32, <f32 padding> } may omit padding
227-
// when passed by value, making it smaller.
228-
// - On some ABIs, the Rust layout { u16, u16, u16 } may be padded up to 8 bytes
229-
// when passed by value, making it larger.
230-
let copy_bytes =
231-
cmp::min(cast.unaligned_size(bx).bytes(), self.layout.size.bytes());
232-
// Allocate some scratch space...
233-
let llscratch = bx.alloca(scratch_size, scratch_align);
234-
bx.lifetime_start(llscratch, scratch_size);
235-
// ...store the value...
236-
bx.store(val, llscratch, scratch_align);
237-
// ... and then memcpy it to the intended destination.
238-
bx.memcpy(
239-
dst.val.llval,
240-
self.layout.align.abi,
241-
llscratch,
242-
scratch_align,
243-
bx.const_usize(copy_bytes),
244-
MemFlags::empty(),
245-
);
246-
bx.lifetime_end(llscratch, scratch_size);
215+
PassMode::Cast { cast, .. } => {
216+
cast.cast_other_abi_to_rust(bx, val, dst.val.llval, self.layout);
247217
}
248218
_ => {
249219
OperandRef::from_immediate_or_packed_pair(bx, val, self.layout).val.store(bx, dst);

compiler/rustc_codegen_ssa/src/mir/block.rs

+35-87
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ use super::{CachedLlbb, FunctionCx, LocalRef};
2323
use crate::base::{self, is_call_from_compiler_builtins_to_upstream_monomorphization};
2424
use crate::common::{self, IntPredicate};
2525
use crate::errors::CompilerBuiltinsCannotCall;
26+
use crate::meth;
2627
use crate::traits::*;
27-
use crate::{meth, MemFlags};
2828

2929
// Indicates if we are in the middle of merging a BB's successor into it. This
3030
// can happen when BB jumps directly to its successor and the successor has no
@@ -462,7 +462,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
462462
}
463463
}
464464

465-
PassMode::Cast { cast: cast_ty, pad_i32: _ } => {
465+
PassMode::Cast { cast, pad_i32: _ } => {
466466
let op = match self.locals[mir::RETURN_PLACE] {
467467
LocalRef::Operand(op) => op,
468468
LocalRef::PendingOperand => bug!("use of return before def"),
@@ -471,23 +471,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
471471
}
472472
LocalRef::UnsizedPlace(_) => bug!("return type must be sized"),
473473
};
474-
let llslot = match op.val {
475-
Immediate(_) | Pair(..) => {
476-
let scratch = PlaceRef::alloca(bx, self.fn_abi.ret.layout);
477-
op.val.store(bx, scratch);
478-
scratch.val.llval
479-
}
480-
Ref(place_val) => {
481-
assert_eq!(
482-
place_val.align, op.layout.align.abi,
483-
"return place is unaligned!"
484-
);
485-
place_val.llval
486-
}
487-
ZeroSized => bug!("ZST return value shouldn't be in PassMode::Cast"),
488-
};
489-
let ty = bx.cast_backend_type(cast_ty);
490-
bx.load(ty, llslot, self.fn_abi.ret.layout.align.abi)
474+
cast.cast_rust_abi_to_other(bx, op)
491475
}
492476
};
493477
bx.ret(llval);
@@ -1460,10 +1444,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
14601444
_ => {}
14611445
}
14621446

1463-
// Force by-ref if we have to load through a cast pointer.
1464-
let (mut llval, align, by_ref) = match op.val {
1465-
Immediate(_) | Pair(..) => match arg.mode {
1466-
PassMode::Indirect { attrs, .. } => {
1447+
let llval = match arg.mode {
1448+
PassMode::Indirect { attrs, on_stack, .. } => match op.val {
1449+
Immediate(_) | Pair(..) => {
14671450
// Indirect argument may have higher alignment requirements than the type's alignment.
14681451
// This can happen, e.g. when passing types with <4 byte alignment on the stack on x86.
14691452
let required_align = match attrs.pointee_align {
@@ -1472,17 +1455,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
14721455
};
14731456
let scratch = PlaceValue::alloca(bx, arg.layout.size, required_align);
14741457
op.val.store(bx, scratch.with_type(arg.layout));
1475-
(scratch.llval, scratch.align, true)
1476-
}
1477-
PassMode::Cast { .. } => {
1478-
let scratch = PlaceRef::alloca(bx, arg.layout);
1479-
op.val.store(bx, scratch);
1480-
(scratch.val.llval, scratch.val.align, true)
1458+
scratch.llval
14811459
}
1482-
_ => (op.immediate_or_packed_pair(bx), arg.layout.align.abi, false),
1483-
},
1484-
Ref(op_place_val) => match arg.mode {
1485-
PassMode::Indirect { attrs, .. } => {
1460+
Ref(op_place_val) => {
14861461
let required_align = match attrs.pointee_align {
14871462
Some(pointee_align) => cmp::max(pointee_align, arg.layout.align.abi),
14881463
None => arg.layout.align.abi,
@@ -1493,15 +1468,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
14931468
// to a higher-aligned alloca.
14941469
let scratch = PlaceValue::alloca(bx, arg.layout.size, required_align);
14951470
bx.typed_place_copy(scratch, op_place_val, op.layout);
1496-
(scratch.llval, scratch.align, true)
1471+
scratch.llval
14971472
} else {
1498-
(op_place_val.llval, op_place_val.align, true)
1473+
op_place_val.llval
14991474
}
15001475
}
1501-
_ => (op_place_val.llval, op_place_val.align, true),
1502-
},
1503-
ZeroSized => match arg.mode {
1504-
PassMode::Indirect { on_stack, .. } => {
1476+
ZeroSized => {
15051477
if on_stack {
15061478
// It doesn't seem like any target can have `byval` ZSTs, so this assert
15071479
// is here to replace a would-be untested codepath.
@@ -1511,59 +1483,35 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
15111483
// a pointer for `repr(C)` structs even when empty, so get
15121484
// one from an `alloca` (which can be left uninitialized).
15131485
let scratch = PlaceRef::alloca(bx, arg.layout);
1514-
(scratch.val.llval, scratch.val.align, true)
1486+
scratch.val.llval
15151487
}
1516-
_ => bug!("ZST {op:?} wasn't ignored, but was passed with abi {arg:?}"),
15171488
},
1518-
};
1519-
1520-
if by_ref && !arg.is_indirect() {
1521-
// Have to load the argument, maybe while casting it.
1522-
if let PassMode::Cast { cast, pad_i32: _ } = &arg.mode {
1523-
// The ABI mandates that the value is passed as a different struct representation.
1524-
// Spill and reload it from the stack to convert from the Rust representation to
1525-
// the ABI representation.
1526-
let scratch_size = cast.size(bx);
1527-
let scratch_align = cast.align(bx);
1528-
// Note that the ABI type may be either larger or smaller than the Rust type,
1529-
// due to the presence or absence of trailing padding. For example:
1530-
// - On some ABIs, the Rust layout { f64, f32, <f32 padding> } may omit padding
1531-
// when passed by value, making it smaller.
1532-
// - On some ABIs, the Rust layout { u16, u16, u16 } may be padded up to 8 bytes
1533-
// when passed by value, making it larger.
1534-
let copy_bytes = cmp::min(cast.unaligned_size(bx).bytes(), arg.layout.size.bytes());
1535-
// Allocate some scratch space...
1536-
let llscratch = bx.alloca(scratch_size, scratch_align);
1537-
bx.lifetime_start(llscratch, scratch_size);
1538-
// ...memcpy the value...
1539-
bx.memcpy(
1540-
llscratch,
1541-
scratch_align,
1542-
llval,
1543-
align,
1544-
bx.const_usize(copy_bytes),
1545-
MemFlags::empty(),
1546-
);
1547-
// ...and then load it with the ABI type.
1548-
let cast_ty = bx.cast_backend_type(cast);
1549-
llval = bx.load(cast_ty, llscratch, scratch_align);
1550-
bx.lifetime_end(llscratch, scratch_size);
1551-
} else {
1552-
// We can't use `PlaceRef::load` here because the argument
1553-
// may have a type we don't treat as immediate, but the ABI
1554-
// used for this call is passing it by-value. In that case,
1555-
// the load would just produce `OperandValue::Ref` instead
1556-
// of the `OperandValue::Immediate` we need for the call.
1557-
llval = bx.load(bx.backend_type(arg.layout), llval, align);
1558-
if let abi::Abi::Scalar(scalar) = arg.layout.abi {
1559-
if scalar.is_bool() {
1489+
PassMode::Cast { ref cast, .. } => cast.cast_rust_abi_to_other(bx, op),
1490+
_ => match op.val {
1491+
Immediate(_) | Pair(..) => op.immediate_or_packed_pair(bx),
1492+
Ref(op_place_val) => {
1493+
// We can't use `PlaceRef::load` here because the argument
1494+
// may have a type we don't treat as immediate, but the ABI
1495+
// used for this call is passing it by-value. In that case,
1496+
// the load would just produce `OperandValue::Ref` instead
1497+
// of the `OperandValue::Immediate` we need for the call.
1498+
let mut llval = bx.load(
1499+
bx.backend_type(arg.layout),
1500+
op_place_val.llval,
1501+
op_place_val.align,
1502+
);
1503+
if let abi::Abi::Scalar(scalar) = arg.layout.abi
1504+
&& scalar.is_bool()
1505+
{
15601506
bx.range_metadata(llval, WrappingRange { start: 0, end: 1 });
15611507
}
1508+
// We store bools as `i8` so we need to truncate to `i1`.
1509+
llval = bx.to_immediate(llval, arg.layout);
1510+
llval
15621511
}
1563-
// We store bools as `i8` so we need to truncate to `i1`.
1564-
llval = bx.to_immediate(llval, arg.layout);
1565-
}
1566-
}
1512+
ZeroSized => bug!("ZST {op:?} wasn't ignored, but was passed with abi {arg:?}"),
1513+
},
1514+
};
15671515

15681516
llargs.push(llval);
15691517
}

compiler/rustc_codegen_ssa/src/mir/mod.rs

+4-14
Original file line numberDiff line numberDiff line change
@@ -229,20 +229,10 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
229229
let layout = start_bx.layout_of(fx.monomorphize(decl.ty));
230230
assert!(!layout.ty.has_erasable_regions());
231231

232-
if local == mir::RETURN_PLACE {
233-
match fx.fn_abi.ret.mode {
234-
PassMode::Indirect { .. } => {
235-
debug!("alloc: {:?} (return place) -> place", local);
236-
let llretptr = start_bx.get_param(0);
237-
return LocalRef::Place(PlaceRef::new_sized(llretptr, layout));
238-
}
239-
PassMode::Cast { ref cast, .. } => {
240-
debug!("alloc: {:?} (return place) -> place", local);
241-
let size = cast.size(&start_bx);
242-
return LocalRef::Place(PlaceRef::alloca_size(&mut start_bx, size, layout));
243-
}
244-
_ => {}
245-
};
232+
if local == mir::RETURN_PLACE && fx.fn_abi.ret.is_indirect() {
233+
debug!("alloc: {:?} (return place) -> place", local);
234+
let llretptr = start_bx.get_param(0);
235+
return LocalRef::Place(PlaceRef::new_sized(llretptr, layout));
246236
}
247237

248238
if memory_locals.contains(local) {

0 commit comments

Comments
 (0)