Skip to main content

rustc_codegen_ssa/mir/
place.rs

1use std::ops::Deref as _;
2
3use rustc_abi::{
4    Align, BackendRepr, FieldIdx, FieldsShape, Size, TagEncoding, VariantIdx, Variants,
5};
6use rustc_middle::mir;
7use rustc_middle::mir::PlaceTy;
8use rustc_middle::mir::interpret::Scalar;
9use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout};
10use rustc_middle::ty::{self, Ty};
11use rustc_span::{DUMMY_SP, bug};
12use tracing::{debug, instrument};
13
14use super::operand::OperandValue;
15use super::{FunctionCx, LocalRef};
16use crate::common::IntPredicate;
17use crate::size_of_val;
18use crate::traits::*;
19
20/// The location and extra runtime properties of the place.
21///
22/// Typically found in a [`PlaceRef`] or an [`OperandValue::Ref`].
23///
24/// As a location in memory, this has no specific type. If you want to
25/// load or store it using a typed operation, use [`Self::with_type`].
26#[derive(#[automatically_derived]
impl<V: ::core::marker::Copy> ::core::marker::Copy for PlaceValue<V> { }Copy, #[automatically_derived]
impl<V: ::core::clone::Clone> ::core::clone::Clone for PlaceValue<V> {
    #[inline]
    fn clone(&self) -> Self {
        PlaceValue {
            llval: ::core::clone::Clone::clone(&self.llval),
            llextra: ::core::clone::Clone::clone(&self.llextra),
            align: ::core::clone::Clone::clone(&self.align),
        }
    }
}Clone, #[automatically_derived]
impl<V: ::core::fmt::Debug> ::core::fmt::Debug for PlaceValue<V> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field3_finish(f, "PlaceValue",
            "llval", &self.llval, "llextra", &self.llextra, "align",
            &&self.align)
    }
}Debug)]
27pub struct PlaceValue<V> {
28    /// A pointer to the contents of the place.
29    pub llval: V,
30
31    /// This place's extra data if it is unsized, or `None` if null.
32    pub llextra: Option<V>,
33
34    /// The alignment we know for this place.
35    pub align: Align,
36}
37
38impl<V: CodegenObject> PlaceValue<V> {
39    /// Constructor for the ordinary case of `Sized` types.
40    ///
41    /// Sets `llextra` to `None`.
42    pub fn new_sized(llval: V, align: Align) -> PlaceValue<V> {
43        PlaceValue { llval, llextra: None, align }
44    }
45
46    /// Allocates a stack slot in the function for a value
47    /// of the specified size and alignment.
48    ///
49    /// The allocation itself is untyped.
50    pub fn alloca<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx, Value = V>>(
51        bx: &mut Bx,
52        size: Size,
53        align: Align,
54    ) -> PlaceValue<V> {
55        let llval = bx.alloca(size, align);
56        PlaceValue::new_sized(llval, align)
57    }
58
59    /// Creates a `PlaceRef` to this location with the given type.
60    pub fn with_type<'tcx>(self, layout: TyAndLayout<'tcx>) -> PlaceRef<'tcx, V> {
61        if !(layout.is_unsized() || layout.is_uninhabited() || self.llextra.is_none())
    {
    {
        ::core::panicking::panic_fmt(format_args!("Had pointer metadata {0:?} for sized type {1:?}",
                self.llextra, layout));
    }
};assert!(
62            layout.is_unsized() || layout.is_uninhabited() || self.llextra.is_none(),
63            "Had pointer metadata {:?} for sized type {layout:?}",
64            self.llextra,
65        );
66        PlaceRef { val: self, layout }
67    }
68
69    /// Gets the pointer to this place as an [`OperandValue::Immediate`]
70    /// or, for those needing metadata, an [`OperandValue::Pair`].
71    ///
72    /// This is the inverse of [`OperandValue::deref`].
73    pub fn address(self) -> OperandValue<V> {
74        if let Some(llextra) = self.llextra {
75            OperandValue::Pair(self.llval, llextra)
76        } else {
77            OperandValue::Immediate(self.llval)
78        }
79    }
80}
81
82#[derive(#[automatically_derived]
impl<'tcx, V: ::core::marker::Copy> ::core::marker::Copy for PlaceRef<'tcx, V>
    {
}Copy, #[automatically_derived]
impl<'tcx, V: ::core::clone::Clone> ::core::clone::Clone for PlaceRef<'tcx, V>
    {
    #[inline]
    fn clone(&self) -> Self {
        PlaceRef {
            val: ::core::clone::Clone::clone(&self.val),
            layout: ::core::clone::Clone::clone(&self.layout),
        }
    }
}Clone, #[automatically_derived]
impl<'tcx, V: ::core::fmt::Debug> ::core::fmt::Debug for PlaceRef<'tcx, V> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f, "PlaceRef",
            "val", &self.val, "layout", &&self.layout)
    }
}Debug)]
83pub struct PlaceRef<'tcx, V> {
84    /// The location and extra runtime properties of the place.
85    pub val: PlaceValue<V>,
86
87    /// The monomorphized type of this place, including variant information.
88    ///
89    /// You probably shouldn't use the alignment from this layout;
90    /// rather you should use the `.val.align` of the actual place,
91    /// which might be different from the type's normal alignment.
92    pub layout: TyAndLayout<'tcx>,
93}
94
95impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
96    pub fn new_sized(llval: V, layout: TyAndLayout<'tcx>) -> PlaceRef<'tcx, V> {
97        PlaceRef::new_sized_aligned(llval, layout, layout.align.abi)
98    }
99
100    pub fn new_sized_aligned(
101        llval: V,
102        layout: TyAndLayout<'tcx>,
103        align: Align,
104    ) -> PlaceRef<'tcx, V> {
105        if !layout.is_sized() {
    ::core::panicking::panic("assertion failed: layout.is_sized()")
};assert!(layout.is_sized());
106        PlaceValue::new_sized(llval, align).with_type(layout)
107    }
108
109    // FIXME(eddyb) pass something else for the name so no work is done
110    // unless LLVM IR names are turned on (e.g. for `--emit=llvm-ir`).
111    pub fn alloca<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
112        bx: &mut Bx,
113        layout: TyAndLayout<'tcx>,
114    ) -> Self {
115        // FIXME(rustc_scalable_vector/stdarch_aarch64_sve): Scalable vectors aren't actually sized,
116        // but we pretend they are. Here we have to hack around that.
117        if layout.peel_transparent_wrappers_from_non_1zst(bx).deref().is_scalable_vector() {
118            Self::alloca_scalable(bx, layout)
119        } else {
120            Self::alloca_size(bx, layout.size, layout)
121        }
122    }
123
124    pub fn alloca_size<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
125        bx: &mut Bx,
126        size: Size,
127        layout: TyAndLayout<'tcx>,
128    ) -> Self {
129        if !layout.is_sized() {
    {
        ::core::panicking::panic_fmt(format_args!("tried to statically allocate unsized place"));
    }
};assert!(layout.is_sized(), "tried to statically allocate unsized place");
130        PlaceValue::alloca(bx, size, layout.align.abi).with_type(layout)
131    }
132
133    /// Returns a place for an indirect reference to an unsized place.
134    // FIXME(eddyb) pass something else for the name so no work is done
135    // unless LLVM IR names are turned on (e.g. for `--emit=llvm-ir`).
136    pub fn alloca_unsized_indirect<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
137        bx: &mut Bx,
138        layout: TyAndLayout<'tcx>,
139    ) -> Self {
140        if !layout.is_unsized() {
    {
        ::core::panicking::panic_fmt(format_args!("tried to allocate indirect place for sized values"));
    }
};assert!(layout.is_unsized(), "tried to allocate indirect place for sized values");
141        let ptr_ty = Ty::new_mut_ptr(bx.cx().tcx(), layout.ty);
142        let ptr_layout = bx.cx().layout_of(ptr_ty);
143        Self::alloca(bx, ptr_layout)
144    }
145
146    pub fn len<Cx: ConstCodegenMethods<Value = V>>(&self, cx: &Cx) -> V {
147        if let FieldsShape::Array { count, .. } = self.layout.fields {
148            if self.layout.is_unsized() {
149                {
    match (&count, &0) {
        (left_val, right_val) => {
            if !(*left_val == *right_val) {
                let kind = ::core::panicking::AssertKind::Eq;
                ::core::panicking::assert_failed(kind, &*left_val,
                    &*right_val, ::core::option::Option::None);
            }
        }
    }
};assert_eq!(count, 0);
150                self.val.llextra.unwrap()
151            } else {
152                cx.const_usize(count)
153            }
154        } else {
155            ::rustc_span::macros::bug_impl(None,
    format_args!("unexpected layout `{0:#?}` in PlaceRef::len", self.layout),
    Location::caller())bug!("unexpected layout `{:#?}` in PlaceRef::len", self.layout)
156        }
157    }
158
159    fn alloca_scalable<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
160        bx: &mut Bx,
161        layout: TyAndLayout<'tcx>,
162    ) -> Self {
163        PlaceValue::new_sized(
164            // FIXME why is this peeling at all? The LLVM type should be the same for the
165            // transparent wrapper and the inner type.
166            bx.alloca_with_ty(layout.peel_transparent_wrappers_from_non_1zst(bx)),
167            layout.align.abi,
168        )
169        .with_type(layout)
170    }
171}
172
173impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
174    /// Access a field, at a point when the value's case is known.
175    pub fn project_field<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
176        self,
177        bx: &mut Bx,
178        ix: usize,
179    ) -> Self {
180        let field = self.layout.field(bx.cx(), ix);
181        let offset = self.layout.fields.offset(ix);
182        let effective_field_align = self.val.align.restrict_for_offset(offset);
183
184        // `simple` is called when we don't need to adjust the offset to
185        // the dynamic alignment of the field.
186        let mut simple = || {
187            let llval = if offset.bytes() == 0 {
188                self.val.llval
189            } else {
190                bx.inbounds_ptradd(self.val.llval, bx.const_usize(offset.bytes()))
191            };
192            let val = PlaceValue {
193                llval,
194                llextra: if bx.cx().tcx().type_has_metadata(field.ty, bx.cx().typing_env()) {
195                    self.val.llextra
196                } else {
197                    None
198                },
199                align: effective_field_align,
200            };
201            val.with_type(field)
202        };
203
204        // Simple cases, which don't need DST adjustment:
205        //   * known alignment - sized types, `[T]`, `str`
206        //   * offset 0 -- rounding up to alignment cannot change the offset
207        // Note that looking at `field.align` is incorrect since that is not necessarily equal
208        // to the dynamic alignment of the type.
209        match field.ty.kind() {
210            _ if field.is_sized() => return simple(),
211            ty::Slice(..) | ty::Str => return simple(),
212            _ if offset.bytes() == 0 => return simple(),
213            _ => {}
214        }
215
216        // We need to get the pointer manually now.
217        // We do this by casting to a `*i8`, then offsetting it by the appropriate amount.
218        // We do this instead of, say, simply adjusting the pointer from the result of a GEP
219        // because the field may have an arbitrary alignment in the LLVM representation.
220        //
221        // To demonstrate:
222        //
223        //     struct Foo<T: ?Sized> {
224        //         x: u16,
225        //         y: T
226        //     }
227        //
228        // The type `Foo<Foo<Trait>>` is represented in LLVM as `{ u16, { u16, u8 }}`, meaning that
229        // the `y` field has 16-bit alignment.
230
231        let meta = self.val.llextra;
232
233        let unaligned_offset = bx.cx().const_usize(offset.bytes());
234
235        // Get the alignment of the field. No span is available here to blame a layout error on.
236        let (_, mut unsized_align) =
237            size_of_val::size_and_align_of_dst(bx, field.ty, meta, DUMMY_SP);
238
239        // For packed types, we need to cap alignment.
240        if let ty::Adt(def, _) = self.layout.ty.kind()
241            && let Some(packed) = def.repr().pack
242        {
243            let packed = bx.const_usize(packed.bytes());
244            let cmp = bx.icmp(IntPredicate::IntULT, unsized_align, packed);
245            unsized_align = bx.select(cmp, unsized_align, packed)
246        }
247
248        // Bump the unaligned offset up to the appropriate alignment
249        let offset = round_up_const_value_to_alignment(bx, unaligned_offset, unsized_align);
250
251        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/080cc27146389dbb5c8772c476b1937be9c6110f/compiler/rustc_codegen_ssa/src/mir/place.rs:251",
                        "rustc_codegen_ssa::mir::place", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/080cc27146389dbb5c8772c476b1937be9c6110f/compiler/rustc_codegen_ssa/src/mir/place.rs"),
                        ::tracing_core::__macro_support::Option::Some(251u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_codegen_ssa::mir::place"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("struct_field_ptr: DST field offset: {0:?}",
                                                    offset) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!("struct_field_ptr: DST field offset: {:?}", offset);
252
253        // Adjust pointer.
254        let ptr = bx.inbounds_ptradd(self.val.llval, offset);
255        let val =
256            PlaceValue { llval: ptr, llextra: self.val.llextra, align: effective_field_align };
257        val.with_type(field)
258    }
259
260    /// Sets the discriminant for a new value of the given case of the given
261    /// representation.
262    pub fn codegen_set_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
263        &self,
264        bx: &mut Bx,
265        variant_index: VariantIdx,
266    ) {
267        match codegen_tag_value(bx.cx(), variant_index, self.layout) {
268            Err(UninhabitedVariantError) => {
269                // We play it safe by using a well-defined `abort`, but we could go for immediate UB
270                // if that turns out to be helpful.
271                bx.abort_immediate();
272            }
273            Ok(Some((tag_field, imm))) => {
274                let tag_place = self.project_field(bx, tag_field.as_usize());
275                OperandValue::Immediate(imm).store(bx, tag_place);
276            }
277            Ok(None) => {}
278        }
279    }
280
281    pub fn project_index<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
282        &self,
283        bx: &mut Bx,
284        llindex: V,
285    ) -> Self {
286        // Statically compute the offset if we can, otherwise just use the element size,
287        // as this will yield the lowest alignment.
288        let layout = self.layout.field(bx, 0);
289        let offset = if let Some(llindex) = bx.const_to_opt_uint(llindex) {
290            layout.size.checked_mul(llindex, bx).unwrap_or(layout.size)
291        } else {
292            layout.size
293        };
294
295        let llval = bx.inbounds_nuw_gep(bx.cx().backend_type(layout), self.val.llval, &[llindex]);
296        let align = self.val.align.restrict_for_offset(offset);
297        PlaceValue::new_sized(llval, align).with_type(layout)
298    }
299
300    pub fn project_downcast<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
301        &self,
302        bx: &mut Bx,
303        variant_index: VariantIdx,
304    ) -> Self {
305        let mut downcast = *self;
306        downcast.layout = self.layout.for_variant(bx.cx(), variant_index);
307        downcast
308    }
309
310    pub fn project_type<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
311        &self,
312        bx: &mut Bx,
313        ty: Ty<'tcx>,
314    ) -> Self {
315        let mut downcast = *self;
316        downcast.layout = bx.cx().layout_of(ty);
317        downcast
318    }
319
320    pub fn storage_live<Bx: BuilderMethods<'a, 'tcx, Value = V>>(&self, bx: &mut Bx) {
321        bx.lifetime_start(self.val.llval, self.layout.size);
322    }
323
324    pub fn storage_dead<Bx: BuilderMethods<'a, 'tcx, Value = V>>(&self, bx: &mut Bx) {
325        bx.lifetime_end(self.val.llval, self.layout.size);
326    }
327
328    /// The same place, but with [`PlaceValue::align`] lowered to [`Align::ONE`].
329    pub fn unaligned(self) -> Self {
330        let Self { val, layout } = self;
331        let val = PlaceValue { align: Align::ONE, ..val };
332        Self { val, layout }
333    }
334}
335
336impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
337    {}
#[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("codegen_place",
                                    "rustc_codegen_ssa::mir::place", ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("/rustc-dev/080cc27146389dbb5c8772c476b1937be9c6110f/compiler/rustc_codegen_ssa/src/mir/place.rs"),
                                    ::tracing_core::__macro_support::Option::Some(337u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_codegen_ssa::mir::place"),
                                    ::tracing_core::field::FieldSet::new(&[{
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("place_ref")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("place_ref");
                                                        NAME.as_str()
                                                    }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&place_ref)
                                                            as &dyn ::tracing::field::Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: PlaceRef<'tcx, Bx::Value> =
                loop {};
            return __tracing_attr_fake_return;
        }
        {
            let cx = self.cx;
            let tcx = self.cx.tcx();
            let mut base = 0;
            let mut cg_base =
                match self.locals[place_ref.local] {
                    LocalRef::Place(place) => place,
                    LocalRef::UnsizedPlace(place) =>
                        bx.load_operand(place).deref(cx),
                    LocalRef::Operand(..) => {
                        if place_ref.is_indirect_first_projection() {
                            base = 1;
                            let cg_base =
                                self.codegen_consume(bx,
                                    mir::PlaceRef {
                                        projection: &place_ref.projection[..0],
                                        ..place_ref
                                    });
                            cg_base.deref(bx.cx())
                        } else {
                            ::rustc_span::macros::bug_impl(None,
                                format_args!("using operand local {0:?} as place",
                                    place_ref), Location::caller());
                        }
                    }
                    LocalRef::PendingOperand => {
                        ::rustc_span::macros::bug_impl(None,
                            format_args!("using still-pending operand local {0:?} as place",
                                place_ref), Location::caller());
                    }
                };
            for elem in place_ref.projection[base..].iter() {
                cg_base =
                    match *elem {
                        mir::ProjectionElem::Deref =>
                            bx.load_operand(cg_base).deref(bx.cx()),
                        mir::ProjectionElem::PhantomDeref => {
                            ::rustc_span::macros::bug_impl(None,
                                format_args!("encountered PhantomDeref in codegen"),
                                Location::caller())
                        }
                        mir::ProjectionElem::Field(ref field, _) => {
                            if !!cg_base.layout.ty.is_any_ptr() {
                                {
                                    ::core::panicking::panic_fmt(format_args!("Bad PlaceRef: destructing pointers should use cast/PtrMetadata, but tried to access field {0:?} of pointer {1:?}",
                                            field, cg_base));
                                }
                            };
                            cg_base.project_field(bx, field.index())
                        }
                        mir::ProjectionElem::OpaqueCast(ty) => {
                            ::rustc_span::macros::bug_impl(None,
                                format_args!("encountered OpaqueCast({0}) in codegen", ty),
                                Location::caller())
                        }
                        mir::ProjectionElem::UnwrapUnsafeBinder(ty) => {
                            cg_base.project_type(bx, self.monomorphize(ty))
                        }
                        mir::ProjectionElem::Index(index) => {
                            let index = &mir::Operand::Copy(mir::Place::from(index));
                            let index = self.codegen_operand(bx, index);
                            let llindex = index.immediate();
                            cg_base.project_index(bx, llindex)
                        }
                        mir::ProjectionElem::ConstantIndex {
                            offset, from_end: false, min_length: _ } => {
                            let lloffset = bx.cx().const_usize(offset);
                            cg_base.project_index(bx, lloffset)
                        }
                        mir::ProjectionElem::ConstantIndex {
                            offset, from_end: true, min_length: _ } => {
                            let lloffset = bx.cx().const_usize(offset);
                            let lllen = cg_base.len(bx.cx());
                            let llindex = bx.sub(lllen, lloffset);
                            cg_base.project_index(bx, llindex)
                        }
                        mir::ProjectionElem::Subslice { from, to, from_end } => {
                            let mut subslice =
                                cg_base.project_index(bx, bx.cx().const_usize(from));
                            let projected_ty =
                                PlaceTy::from_ty(cg_base.layout.ty).projection_ty(tcx,
                                        *elem).ty;
                            subslice.layout =
                                bx.cx().layout_of(self.monomorphize(projected_ty));
                            if subslice.layout.is_unsized() {
                                if !from_end {
                                    {
                                        ::core::panicking::panic_fmt(format_args!("slice subslices should be `from_end`"));
                                    }
                                };
                                subslice.val.llextra =
                                    Some(bx.sub(cg_base.val.llextra.unwrap(),
                                            bx.cx().const_usize(from + to)));
                            }
                            subslice
                        }
                        mir::ProjectionElem::Downcast(_, v) =>
                            cg_base.project_downcast(bx, v),
                    };
            }
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("event /rustc-dev/080cc27146389dbb5c8772c476b1937be9c6110f/compiler/rustc_codegen_ssa/src/mir/place.rs:420",
                                    "rustc_codegen_ssa::mir::place", ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("/rustc-dev/080cc27146389dbb5c8772c476b1937be9c6110f/compiler/rustc_codegen_ssa/src/mir/place.rs"),
                                    ::tracing_core::__macro_support::Option::Some(420u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_codegen_ssa::mir::place"),
                                    ::tracing_core::field::FieldSet::new(&["message"],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::EVENT)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let enabled =
                    ::tracing::Level::DEBUG <=
                                ::tracing::level_filters::STATIC_MAX_LEVEL &&
                            ::tracing::Level::DEBUG <=
                                ::tracing::level_filters::LevelFilter::current() &&
                        {
                            let interest = __CALLSITE.interest();
                            !interest.is_never() &&
                                ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                    interest)
                        };
                if enabled {
                    (|value_set: ::tracing::field::ValueSet|
                                {
                                    let meta = __CALLSITE.metadata();
                                    ::tracing::Event::dispatch(meta, &value_set);
                                    ;
                                })({
                            #[allow(unused_imports)]
                            use ::tracing::field::{debug, display, Value};
                            __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("codegen_place(place={0:?}) => {1:?}",
                                                                place_ref, cg_base) as &dyn ::tracing::field::Value))])
                        });
                } else { ; }
            };
            cg_base
        }
    }
}#[instrument(level = "trace", skip(self, bx))]
338    pub fn codegen_place(
339        &mut self,
340        bx: &mut Bx,
341        place_ref: mir::PlaceRef<'tcx>,
342    ) -> PlaceRef<'tcx, Bx::Value> {
343        let cx = self.cx;
344        let tcx = self.cx.tcx();
345
346        let mut base = 0;
347        let mut cg_base = match self.locals[place_ref.local] {
348            LocalRef::Place(place) => place,
349            LocalRef::UnsizedPlace(place) => bx.load_operand(place).deref(cx),
350            LocalRef::Operand(..) => {
351                if place_ref.is_indirect_first_projection() {
352                    base = 1;
353                    let cg_base = self.codegen_consume(
354                        bx,
355                        mir::PlaceRef { projection: &place_ref.projection[..0], ..place_ref },
356                    );
357                    cg_base.deref(bx.cx())
358                } else {
359                    bug!("using operand local {:?} as place", place_ref);
360                }
361            }
362            LocalRef::PendingOperand => {
363                bug!("using still-pending operand local {:?} as place", place_ref);
364            }
365        };
366        for elem in place_ref.projection[base..].iter() {
367            cg_base = match *elem {
368                mir::ProjectionElem::Deref => bx.load_operand(cg_base).deref(bx.cx()),
369                mir::ProjectionElem::PhantomDeref => {
370                    bug!("encountered PhantomDeref in codegen")
371                }
372                mir::ProjectionElem::Field(ref field, _) => {
373                    assert!(
374                        !cg_base.layout.ty.is_any_ptr(),
375                        "Bad PlaceRef: destructing pointers should use cast/PtrMetadata, \
376                         but tried to access field {field:?} of pointer {cg_base:?}",
377                    );
378                    cg_base.project_field(bx, field.index())
379                }
380                mir::ProjectionElem::OpaqueCast(ty) => {
381                    bug!("encountered OpaqueCast({ty}) in codegen")
382                }
383                mir::ProjectionElem::UnwrapUnsafeBinder(ty) => {
384                    cg_base.project_type(bx, self.monomorphize(ty))
385                }
386                mir::ProjectionElem::Index(index) => {
387                    let index = &mir::Operand::Copy(mir::Place::from(index));
388                    let index = self.codegen_operand(bx, index);
389                    let llindex = index.immediate();
390                    cg_base.project_index(bx, llindex)
391                }
392                mir::ProjectionElem::ConstantIndex { offset, from_end: false, min_length: _ } => {
393                    let lloffset = bx.cx().const_usize(offset);
394                    cg_base.project_index(bx, lloffset)
395                }
396                mir::ProjectionElem::ConstantIndex { offset, from_end: true, min_length: _ } => {
397                    let lloffset = bx.cx().const_usize(offset);
398                    let lllen = cg_base.len(bx.cx());
399                    let llindex = bx.sub(lllen, lloffset);
400                    cg_base.project_index(bx, llindex)
401                }
402                mir::ProjectionElem::Subslice { from, to, from_end } => {
403                    let mut subslice = cg_base.project_index(bx, bx.cx().const_usize(from));
404                    let projected_ty =
405                        PlaceTy::from_ty(cg_base.layout.ty).projection_ty(tcx, *elem).ty;
406                    subslice.layout = bx.cx().layout_of(self.monomorphize(projected_ty));
407
408                    if subslice.layout.is_unsized() {
409                        assert!(from_end, "slice subslices should be `from_end`");
410                        subslice.val.llextra = Some(
411                            bx.sub(cg_base.val.llextra.unwrap(), bx.cx().const_usize(from + to)),
412                        );
413                    }
414
415                    subslice
416                }
417                mir::ProjectionElem::Downcast(_, v) => cg_base.project_downcast(bx, v),
418            };
419        }
420        debug!("codegen_place(place={:?}) => {:?}", place_ref, cg_base);
421        cg_base
422    }
423
424    pub fn monomorphized_place_ty(&self, place_ref: mir::PlaceRef<'tcx>) -> Ty<'tcx> {
425        let tcx = self.cx.tcx();
426        let place_ty = place_ref.ty(self.mir, tcx);
427        self.monomorphize(place_ty.ty)
428    }
429}
430
431fn round_up_const_value_to_alignment<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
432    bx: &mut Bx,
433    value: Bx::Value,
434    align: Bx::Value,
435) -> Bx::Value {
436    // In pseudo code:
437    //
438    //     if value & (align - 1) == 0 {
439    //         value
440    //     } else {
441    //         (value & !(align - 1)) + align
442    //     }
443    //
444    // Usually this is written without branches as
445    //
446    //     (value + align - 1) & !(align - 1)
447    //
448    // But this formula cannot take advantage of constant `value`. E.g. if `value` is known
449    // at compile time to be `1`, this expression should be optimized to `align`. However,
450    // optimization only holds if `align` is a power of two. Since the optimizer doesn't know
451    // that `align` is a power of two, it cannot perform this optimization.
452    //
453    // Instead we use
454    //
455    //     value + (-value & (align - 1))
456    //
457    // Since `align` is used only once, the expression can be optimized. For `value = 0`
458    // its optimized to `0` even in debug mode.
459    //
460    // NB: The previous version of this code used
461    //
462    //     (value + align - 1) & -align
463    //
464    // Even though `-align == !(align - 1)`, LLVM failed to optimize this even for
465    // `value = 0`. Bug report: https://bugs.llvm.org/show_bug.cgi?id=48559
466    let one = bx.const_usize(1);
467    let align_minus_1 = bx.sub(align, one);
468    let neg_value = bx.neg(value);
469    let offset = bx.and(neg_value, align_minus_1);
470    bx.add(value, offset)
471}
472
473/// Calculates the value that needs to be stored to mark the discriminant.
474///
475/// This might be `None` for a `struct` or a niched variant (like `Some(&3)`).
476///
477/// If it's `Some`, it returns the value to store and the field in which to
478/// store it. Note that this value is *not* the same as the discriminant, in
479/// general, as it might be a niche value or have a different size.
480///
481/// It might also be an `Err` because the variant is uninhabited.
482pub(super) fn codegen_tag_value<'tcx, V>(
483    cx: &impl CodegenMethods<'tcx, Value = V>,
484    variant_index: VariantIdx,
485    layout: TyAndLayout<'tcx>,
486) -> Result<Option<(FieldIdx, V)>, UninhabitedVariantError> {
487    // By checking uninhabited-ness first we don't need to worry about types
488    // like `(u32, !)` which are single-variant but weird.
489    if layout.is_variant_uninhabited(variant_index) {
490        return Err(UninhabitedVariantError);
491    }
492
493    Ok(match layout.variants {
494        Variants::Empty => {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("we already handled uninhabited types")));
}unreachable!("we already handled uninhabited types"),
495        Variants::Single { index } => {
496            {
    match (&index, &variant_index) {
        (left_val, right_val) => {
            if !(*left_val == *right_val) {
                let kind = ::core::panicking::AssertKind::Eq;
                ::core::panicking::assert_failed(kind, &*left_val,
                    &*right_val, ::core::option::Option::None);
            }
        }
    }
};assert_eq!(index, variant_index);
497            None
498        }
499
500        Variants::Multiple { tag_encoding: TagEncoding::Direct, tag_field, .. } => {
501            let discr = layout.ty.discriminant_for_variant(cx.tcx(), variant_index);
502            let to = discr.unwrap().val;
503            let tag_layout = layout.field(cx, tag_field.as_usize());
504            let tag_llty = cx.immediate_backend_type(tag_layout);
505            let imm = cx.const_uint_big(tag_llty, to);
506            Some((tag_field, imm))
507        }
508        Variants::Multiple {
509            tag_encoding: TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start },
510            tag_field,
511            ..
512        } => {
513            if variant_index != untagged_variant {
514                let niche_layout = layout.field(cx, tag_field.as_usize());
515                let niche_llty = cx.immediate_backend_type(niche_layout);
516                let BackendRepr::Scalar(scalar) = niche_layout.backend_repr else {
517                    ::rustc_span::macros::bug_impl(None,
    format_args!("expected a scalar placeref for the niche"),
    Location::caller());bug!("expected a scalar placeref for the niche");
518                };
519                // We are supposed to compute `niche_value.wrapping_add(niche_start)` wrapping
520                // around the `niche`'s type.
521                // The easiest way to do that is to do wrapping arithmetic on `u128` and then
522                // masking off any extra bits that occur because we did the arithmetic with too many bits.
523                let niche_value = variant_index.as_u32() - niche_variants.start.as_u32();
524                let niche_value = (niche_value as u128).wrapping_add(niche_start);
525                let niche_value = niche_value & niche_layout.size.unsigned_int_max();
526
527                let niche_llval = cx.scalar_to_backend(
528                    Scalar::from_uint(niche_value, niche_layout.size),
529                    scalar,
530                    niche_llty,
531                );
532                Some((tag_field, niche_llval))
533            } else {
534                None
535            }
536        }
537    })
538}
539
540#[derive(#[automatically_derived]
impl ::core::fmt::Debug for UninhabitedVariantError {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "UninhabitedVariantError")
    }
}Debug)]
541pub(super) struct UninhabitedVariantError;