Skip to content

Commit

Permalink
Auto merge of #124153 - scottmcm:more-placevalue, r=saethlin
Browse files Browse the repository at this point in the history
Refactoring after the `PlaceValue` addition

I added [`PlaceValue`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_ssa/mir/place/struct.PlaceValue.html) in #123775, but kept that one line-by-line simple because it touched so many places.

This goes through to add more helpers & docs, and change some `PlaceRef` to `PlaceValue` where the type didn't need to be included.

No behaviour changes -- the codegen is exactly the same.
  • Loading branch information
bors committed May 12, 2024
2 parents fe03fb9 + 9be16eb commit 8b64adc
Show file tree
Hide file tree
Showing 7 changed files with 152 additions and 127 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_ssa/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
}

if src_f.layout.ty == dst_f.layout.ty {
bx.typed_place_copy(dst_f, src_f);
bx.typed_place_copy(dst_f.val, src_f.val, src_f.layout);
} else {
coerce_unsized_into(bx, src_f, dst_f);
}
Expand Down
15 changes: 7 additions & 8 deletions compiler/rustc_codegen_ssa/src/mir/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1454,9 +1454,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
Some(pointee_align) => cmp::max(pointee_align, arg.layout.align.abi),
None => arg.layout.align.abi,
};
let scratch = PlaceRef::alloca_aligned(bx, arg.layout, required_align);
op.val.store(bx, scratch);
(scratch.val.llval, scratch.val.align, true)
let scratch = PlaceValue::alloca(bx, arg.layout.size, required_align);
op.val.store(bx, scratch.with_type(arg.layout));
(scratch.llval, scratch.align, true)
}
PassMode::Cast { .. } => {
let scratch = PlaceRef::alloca(bx, arg.layout);
Expand All @@ -1475,10 +1475,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
// For `foo(packed.large_field)`, and types with <4 byte alignment on x86,
// alignment requirements may be higher than the type's alignment, so copy
// to a higher-aligned alloca.
let scratch = PlaceRef::alloca_aligned(bx, arg.layout, required_align);
let op_place = PlaceRef { val: op_place_val, layout: op.layout };
bx.typed_place_copy(scratch, op_place);
(scratch.val.llval, scratch.val.align, true)
let scratch = PlaceValue::alloca(bx, arg.layout.size, required_align);
bx.typed_place_copy(scratch, op_place_val, op.layout);
(scratch.llval, scratch.align, true)
} else {
(op_place_val.llval, op_place_val.align, true)
}
Expand Down Expand Up @@ -1567,7 +1566,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
if place_val.llextra.is_some() {
bug!("closure arguments must be sized");
}
let tuple_ptr = PlaceRef { val: place_val, layout: tuple.layout };
let tuple_ptr = place_val.with_type(tuple.layout);
for i in 0..tuple.layout.fields.count() {
let field_ptr = tuple_ptr.project_field(bx, i);
let field = bx.load_operand(field_ptr);
Expand Down
15 changes: 7 additions & 8 deletions compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::operand::{OperandRef, OperandValue};
use super::operand::OperandRef;
use super::place::PlaceRef;
use super::FunctionCx;
use crate::errors;
Expand Down Expand Up @@ -93,9 +93,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
// into the (unoptimized) direct swapping implementation, so we disable it.
|| bx.sess().target.arch == "spirv"
{
let x_place = PlaceRef::new_sized(args[0].immediate(), pointee_layout);
let y_place = PlaceRef::new_sized(args[1].immediate(), pointee_layout);
bx.typed_place_swap(x_place, y_place);
let align = pointee_layout.align.abi;
let x_place = args[0].val.deref(align);
let y_place = args[1].val.deref(align);
bx.typed_place_swap(x_place, y_place, pointee_layout);
return Ok(());
}
}
Expand All @@ -113,15 +114,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
sym::va_end => bx.va_end(args[0].immediate()),
sym::size_of_val => {
let tp_ty = fn_args.type_at(0);
let meta =
if let OperandValue::Pair(_, meta) = args[0].val { Some(meta) } else { None };
let (_, meta) = args[0].val.pointer_parts();
let (llsize, _) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta);
llsize
}
sym::min_align_of_val => {
let tp_ty = fn_args.type_at(0);
let meta =
if let OperandValue::Pair(_, meta) = args[0].val { Some(meta) } else { None };
let (_, meta) = args[0].val.pointer_parts();
let (_, llalign) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta);
llalign
}
Expand Down
47 changes: 36 additions & 11 deletions compiler/rustc_codegen_ssa/src/mir/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ pub enum OperandValue<V> {
ZeroSized,
}

impl<V> OperandValue<V> {
impl<V: CodegenObject> OperandValue<V> {
/// If this is ZeroSized/Immediate/Pair, return an array of the 0/1/2 values.
/// If this is Ref, return the place.
#[inline]
Expand All @@ -86,6 +86,30 @@ impl<V> OperandValue<V> {
};
OperandValue::Pair(a, b)
}

/// Treat this value as a pointer and return the data pointer and
/// optional metadata as backend values.
///
/// If you're making a place, use [`Self::deref`] instead.
pub fn pointer_parts(self) -> (V, Option<V>) {
match self {
OperandValue::Immediate(llptr) => (llptr, None),
OperandValue::Pair(llptr, llextra) => (llptr, Some(llextra)),
_ => bug!("OperandValue cannot be a pointer: {self:?}"),
}
}

/// Treat this value as a pointer and return the place to which it points.
///
/// The pointer immediate doesn't inherently know its alignment,
/// so you need to pass it in. If you want to get it from a type's ABI
/// alignment, then maybe you want [`OperandRef::deref`] instead.
///
/// This is the inverse of [`PlaceValue::address`].
pub fn deref(self, align: Align) -> PlaceValue<V> {
let (llval, llextra) = self.pointer_parts();
PlaceValue { llval, llextra, align }
}
}

/// An `OperandRef` is an "SSA" reference to a Rust value, along with
Expand Down Expand Up @@ -235,6 +259,15 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
}
}

/// Asserts that this operand is a pointer (or reference) and returns
/// the place to which it points. (This requires no code to be emitted
/// as we represent places using the pointer to the place.)
///
/// This uses [`Ty::builtin_deref`] to include the type of the place and
/// assumes the place is aligned to the pointee's usual ABI alignment.
///
/// If you don't need the type, see [`OperandValue::pointer_parts`]
/// or [`OperandValue::deref`].
pub fn deref<Cx: LayoutTypeMethods<'tcx>>(self, cx: &Cx) -> PlaceRef<'tcx, V> {
if self.layout.ty.is_box() {
// Derefer should have removed all Box derefs
Expand All @@ -247,15 +280,8 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
.builtin_deref(true)
.unwrap_or_else(|| bug!("deref of non-pointer {:?}", self));

let (llptr, llextra) = match self.val {
OperandValue::Immediate(llptr) => (llptr, None),
OperandValue::Pair(llptr, llextra) => (llptr, Some(llextra)),
OperandValue::Ref(..) => bug!("Deref of by-Ref operand {:?}", self),
OperandValue::ZeroSized => bug!("Deref of ZST operand {:?}", self),
};
let layout = cx.layout_of(projected_ty);
let val = PlaceValue { llval: llptr, llextra, align: layout.align.abi };
PlaceRef { val, layout }
self.val.deref(layout.align.abi).with_type(layout)
}

/// If this operand is a `Pair`, we return an aggregate with the two values.
Expand Down Expand Up @@ -448,8 +474,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
if val.llextra.is_some() {
bug!("cannot directly store unsized values");
}
let source_place = PlaceRef { val, layout: dest.layout };
bx.typed_place_copy_with_flags(dest, source_place, flags);
bx.typed_place_copy_with_flags(dest.val, val, dest.layout, flags);
}
OperandValue::Immediate(s) => {
let val = bx.from_immediate(s);
Expand Down
87 changes: 51 additions & 36 deletions compiler/rustc_codegen_ssa/src/mir/place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@ use rustc_middle::mir;
use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
use rustc_middle::ty::{self, Ty};
use rustc_target::abi::{Align, FieldsShape, Int, Pointer, TagEncoding};
use rustc_target::abi::{Align, FieldsShape, Int, Pointer, Size, TagEncoding};
use rustc_target::abi::{VariantIdx, Variants};

/// The location and extra runtime properties of the place.
///
/// Typically found in a [`PlaceRef`] or an [`OperandValue::Ref`].
///
/// As a location in memory, this has no specific type. If you want to
/// load or store it using a typed operation, use [`Self::with_type`].
#[derive(Copy, Clone, Debug)]
pub struct PlaceValue<V> {
/// A pointer to the contents of the place.
Expand All @@ -35,6 +38,41 @@ impl<V: CodegenObject> PlaceValue<V> {
pub fn new_sized(llval: V, align: Align) -> PlaceValue<V> {
PlaceValue { llval, llextra: None, align }
}

/// Allocates a stack slot in the function for a value
/// of the specified size and alignment.
///
/// The allocation itself is untyped.
pub fn alloca<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx, Value = V>>(
bx: &mut Bx,
size: Size,
align: Align,
) -> PlaceValue<V> {
let llval = bx.alloca(size, align);
PlaceValue::new_sized(llval, align)
}

/// Creates a `PlaceRef` to this location with the given type.
pub fn with_type<'tcx>(self, layout: TyAndLayout<'tcx>) -> PlaceRef<'tcx, V> {
debug_assert!(
layout.is_unsized() || layout.abi.is_uninhabited() || self.llextra.is_none(),
"Had pointer metadata {:?} for sized type {layout:?}",
self.llextra,
);
PlaceRef { val: self, layout }
}

/// Gets the pointer to this place as an [`OperandValue::Immediate`]
/// or, for those needing metadata, an [`OperandValue::Pair`].
///
/// This is the inverse of [`OperandValue::deref`].
pub fn address(self) -> OperandValue<V> {
if let Some(llextra) = self.llextra {
OperandValue::Pair(self.llval, llextra)
} else {
OperandValue::Immediate(self.llval)
}
}
}

#[derive(Copy, Clone, Debug)]
Expand All @@ -52,9 +90,7 @@ pub struct PlaceRef<'tcx, V> {

impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
pub fn new_sized(llval: V, layout: TyAndLayout<'tcx>) -> PlaceRef<'tcx, V> {
assert!(layout.is_sized());
let val = PlaceValue::new_sized(llval, layout.align.abi);
PlaceRef { val, layout }
PlaceRef::new_sized_aligned(llval, layout, layout.align.abi)
}

pub fn new_sized_aligned(
Expand All @@ -63,27 +99,17 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
align: Align,
) -> PlaceRef<'tcx, V> {
assert!(layout.is_sized());
let val = PlaceValue::new_sized(llval, align);
PlaceRef { val, layout }
PlaceValue::new_sized(llval, align).with_type(layout)
}

// FIXME(eddyb) pass something else for the name so no work is done
// unless LLVM IR names are turned on (e.g. for `--emit=llvm-ir`).
pub fn alloca<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
bx: &mut Bx,
layout: TyAndLayout<'tcx>,
) -> Self {
Self::alloca_aligned(bx, layout, layout.align.abi)
}

pub fn alloca_aligned<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
bx: &mut Bx,
layout: TyAndLayout<'tcx>,
align: Align,
) -> Self {
assert!(layout.is_sized(), "tried to statically allocate unsized place");
let tmp = bx.alloca(layout.size, align);
Self::new_sized_aligned(tmp, layout, align)
PlaceValue::alloca(bx, layout.size, layout.align.abi).with_type(layout)
}

/// Returns a place for an indirect reference to an unsized place.
Expand Down Expand Up @@ -132,18 +158,12 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
} else {
bx.inbounds_ptradd(self.val.llval, bx.const_usize(offset.bytes()))
};
PlaceRef {
val: PlaceValue {
let val = PlaceValue {
llval,
llextra: if bx.cx().type_has_metadata(field.ty) {
self.val.llextra
} else {
None
},
llextra: if bx.cx().type_has_metadata(field.ty) { self.val.llextra } else { None },
align: effective_field_align,
},
layout: field,
}
};
val.with_type(field)
};

// Simple cases, which don't need DST adjustment:
Expand Down Expand Up @@ -198,7 +218,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
let ptr = bx.inbounds_ptradd(self.val.llval, offset);
let val =
PlaceValue { llval: ptr, llextra: self.val.llextra, align: effective_field_align };
PlaceRef { val, layout: field }
val.with_type(field)
}

/// Obtain the actual discriminant of a value.
Expand Down Expand Up @@ -387,18 +407,13 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
layout.size
};

PlaceRef {
val: PlaceValue {
llval: bx.inbounds_gep(
let llval = bx.inbounds_gep(
bx.cx().backend_type(self.layout),
self.val.llval,
&[bx.cx().const_usize(0), llindex],
),
llextra: None,
align: self.val.align.restrict_for_offset(offset),
},
layout,
}
);
let align = self.val.align.restrict_for_offset(offset);
PlaceValue::new_sized(llval, align).with_type(layout)
}

pub fn project_downcast<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
Expand Down
Loading

0 comments on commit 8b64adc

Please sign in to comment.