1use std::fmt;
2
3use rustc_abi as abi;
4use rustc_abi::{
5 Align, BackendRepr, FIRST_VARIANT, FieldIdx, Primitive, Size, TagEncoding, VariantIdx, Variants,
6};
7use rustc_middle::mir::interpret::{Pointer, Scalar, alloc_range};
8use rustc_middle::mir::{self, ConstValue};
9use rustc_middle::ty::Ty;
10use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
11use rustc_middle::{bug, span_bug};
12use rustc_session::config::OptLevel;
13use tracing::{debug, instrument};
14
15use super::place::{PlaceRef, PlaceValue};
16use super::rvalue::transmute_immediate;
17use super::{FunctionCx, LocalRef};
18use crate::common::IntPredicate;
19use crate::traits::*;
20use crate::{MemFlags, size_of_val};
21
22#[derive(Copy, Clone, Debug)]
26pub enum OperandValue<V> {
27 Ref(PlaceValue<V>),
40 Immediate(V),
47 Pair(V, V),
61 ZeroSized,
70}
71
72impl<V: CodegenObject> OperandValue<V> {
73 pub(crate) fn pointer_parts(self) -> (V, Option<V>) {
78 match self {
79 OperandValue::Immediate(llptr) => (llptr, None),
80 OperandValue::Pair(llptr, llextra) => (llptr, Some(llextra)),
81 _ => bug!("OperandValue cannot be a pointer: {self:?}"),
82 }
83 }
84
85 pub(crate) fn deref(self, align: Align) -> PlaceValue<V> {
93 let (llval, llextra) = self.pointer_parts();
94 PlaceValue { llval, llextra, align }
95 }
96
97 pub(crate) fn is_expected_variant_for_type<'tcx, Cx: LayoutTypeCodegenMethods<'tcx>>(
98 &self,
99 cx: &Cx,
100 ty: TyAndLayout<'tcx>,
101 ) -> bool {
102 match self {
103 OperandValue::ZeroSized => ty.is_zst(),
104 OperandValue::Immediate(_) => cx.is_backend_immediate(ty),
105 OperandValue::Pair(_, _) => cx.is_backend_scalar_pair(ty),
106 OperandValue::Ref(_) => cx.is_backend_ref(ty),
107 }
108 }
109}
110
111#[derive(Copy, Clone)]
120pub struct OperandRef<'tcx, V> {
121 pub val: OperandValue<V>,
123
124 pub layout: TyAndLayout<'tcx>,
126}
127
128impl<V: CodegenObject> fmt::Debug for OperandRef<'_, V> {
129 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130 write!(f, "OperandRef({:?} @ {:?})", self.val, self.layout)
131 }
132}
133
134impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
135 pub fn zero_sized(layout: TyAndLayout<'tcx>) -> OperandRef<'tcx, V> {
136 assert!(layout.is_zst());
137 OperandRef { val: OperandValue::ZeroSized, layout }
138 }
139
140 pub(crate) fn from_const<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
141 bx: &mut Bx,
142 val: mir::ConstValue<'tcx>,
143 ty: Ty<'tcx>,
144 ) -> Self {
145 let layout = bx.layout_of(ty);
146
147 let val = match val {
148 ConstValue::Scalar(x) => {
149 let BackendRepr::Scalar(scalar) = layout.backend_repr else {
150 bug!("from_const: invalid ByVal layout: {:#?}", layout);
151 };
152 let llval = bx.scalar_to_backend(x, scalar, bx.immediate_backend_type(layout));
153 OperandValue::Immediate(llval)
154 }
155 ConstValue::ZeroSized => return OperandRef::zero_sized(layout),
156 ConstValue::Slice { data, meta } => {
157 let BackendRepr::ScalarPair(a_scalar, _) = layout.backend_repr else {
158 bug!("from_const: invalid ScalarPair layout: {:#?}", layout);
159 };
160 let a = Scalar::from_pointer(
161 Pointer::new(bx.tcx().reserve_and_set_memory_alloc(data).into(), Size::ZERO),
162 &bx.tcx(),
163 );
164 let a_llval = bx.scalar_to_backend(
165 a,
166 a_scalar,
167 bx.scalar_pair_element_backend_type(layout, 0, true),
168 );
169 let b_llval = bx.const_usize(meta);
170 OperandValue::Pair(a_llval, b_llval)
171 }
172 ConstValue::Indirect { alloc_id, offset } => {
173 let alloc = bx.tcx().global_alloc(alloc_id).unwrap_memory();
174 return Self::from_const_alloc(bx, layout, alloc, offset);
175 }
176 };
177
178 OperandRef { val, layout }
179 }
180
181 fn from_const_alloc<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
182 bx: &mut Bx,
183 layout: TyAndLayout<'tcx>,
184 alloc: rustc_middle::mir::interpret::ConstAllocation<'tcx>,
185 offset: Size,
186 ) -> Self {
187 let alloc_align = alloc.inner().align;
188 assert!(alloc_align >= layout.align.abi);
189
190 let read_scalar = |start, size, s: abi::Scalar, ty| {
191 match alloc.0.read_scalar(
192 bx,
193 alloc_range(start, size),
194 matches!(s.primitive(), abi::Primitive::Pointer(_)),
195 ) {
196 Ok(val) => bx.scalar_to_backend(val, s, ty),
197 Err(_) => bx.const_poison(ty),
198 }
199 };
200
201 match layout.backend_repr {
208 BackendRepr::Scalar(s @ abi::Scalar::Initialized { .. }) => {
209 let size = s.size(bx);
210 assert_eq!(size, layout.size, "abi::Scalar size does not match layout size");
211 let val = read_scalar(offset, size, s, bx.immediate_backend_type(layout));
212 OperandRef { val: OperandValue::Immediate(val), layout }
213 }
214 BackendRepr::ScalarPair(
215 a @ abi::Scalar::Initialized { .. },
216 b @ abi::Scalar::Initialized { .. },
217 ) => {
218 let (a_size, b_size) = (a.size(bx), b.size(bx));
219 let b_offset = (offset + a_size).align_to(b.align(bx).abi);
220 assert!(b_offset.bytes() > 0);
221 let a_val = read_scalar(
222 offset,
223 a_size,
224 a,
225 bx.scalar_pair_element_backend_type(layout, 0, true),
226 );
227 let b_val = read_scalar(
228 b_offset,
229 b_size,
230 b,
231 bx.scalar_pair_element_backend_type(layout, 1, true),
232 );
233 OperandRef { val: OperandValue::Pair(a_val, b_val), layout }
234 }
235 _ if layout.is_zst() => OperandRef::zero_sized(layout),
236 _ => {
237 let init = bx.const_data_from_alloc(alloc);
241 let base_addr = bx.static_addr_of(init, alloc_align, None);
242
243 let llval = bx.const_ptr_byte_offset(base_addr, offset);
244 bx.load_operand(PlaceRef::new_sized(llval, layout))
245 }
246 }
247 }
248
249 pub fn immediate(self) -> V {
252 match self.val {
253 OperandValue::Immediate(s) => s,
254 _ => bug!("not immediate: {:?}", self),
255 }
256 }
257
258 pub fn deref<Cx: CodegenMethods<'tcx>>(self, cx: &Cx) -> PlaceRef<'tcx, V> {
268 if self.layout.ty.is_box() {
269 bug!("dereferencing {:?} in codegen", self.layout.ty);
271 }
272
273 let projected_ty = self
274 .layout
275 .ty
276 .builtin_deref(true)
277 .unwrap_or_else(|| bug!("deref of non-pointer {:?}", self));
278
279 let layout = cx.layout_of(projected_ty);
280 self.val.deref(layout.align.abi).with_type(layout)
281 }
282
283 pub fn immediate_or_packed_pair<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
286 self,
287 bx: &mut Bx,
288 ) -> V {
289 if let OperandValue::Pair(a, b) = self.val {
290 let llty = bx.cx().immediate_backend_type(self.layout);
291 debug!("Operand::immediate_or_packed_pair: packing {:?} into {:?}", self, llty);
292 let mut llpair = bx.cx().const_poison(llty);
294 llpair = bx.insert_value(llpair, a, 0);
295 llpair = bx.insert_value(llpair, b, 1);
296 llpair
297 } else {
298 self.immediate()
299 }
300 }
301
302 pub fn from_immediate_or_packed_pair<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
304 bx: &mut Bx,
305 llval: V,
306 layout: TyAndLayout<'tcx>,
307 ) -> Self {
308 let val = if let BackendRepr::ScalarPair(..) = layout.backend_repr {
309 debug!("Operand::from_immediate_or_packed_pair: unpacking {:?} @ {:?}", llval, layout);
310
311 let a_llval = bx.extract_value(llval, 0);
313 let b_llval = bx.extract_value(llval, 1);
314 OperandValue::Pair(a_llval, b_llval)
315 } else {
316 OperandValue::Immediate(llval)
317 };
318 OperandRef { val, layout }
319 }
320
321 pub(crate) fn extract_field<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
322 &self,
323 fx: &mut FunctionCx<'a, 'tcx, Bx>,
324 bx: &mut Bx,
325 i: usize,
326 ) -> Self {
327 let field = self.layout.field(bx.cx(), i);
328 let offset = self.layout.fields.offset(i);
329
330 if !bx.is_backend_ref(self.layout) && bx.is_backend_ref(field) {
331 if let BackendRepr::SimdVector { count, .. } = self.layout.backend_repr
332 && let BackendRepr::Memory { sized: true } = field.backend_repr
333 && count.is_power_of_two()
334 {
335 assert_eq!(field.size, self.layout.size);
336 let place = PlaceRef::alloca(bx, field);
339 self.val.store(bx, place.val.with_type(self.layout));
340 return bx.load_operand(place);
341 } else {
342 bug!("Non-ref type {self:?} cannot project to ref field type {field:?}");
344 }
345 }
346
347 let val = if field.is_zst() {
348 OperandValue::ZeroSized
349 } else if field.size == self.layout.size {
350 assert_eq!(offset.bytes(), 0);
351 fx.codegen_transmute_operand(bx, *self, field).unwrap_or_else(|| {
352 bug!(
353 "Expected `codegen_transmute_operand` to handle equal-size \
354 field {i:?} projection from {self:?} to {field:?}"
355 )
356 })
357 } else {
358 let (in_scalar, imm) = match (self.val, self.layout.backend_repr) {
359 (OperandValue::Pair(a_llval, b_llval), BackendRepr::ScalarPair(a, b)) => {
361 if offset.bytes() == 0 {
362 assert_eq!(field.size, a.size(bx.cx()));
363 (Some(a), a_llval)
364 } else {
365 assert_eq!(offset, a.size(bx.cx()).align_to(b.align(bx.cx()).abi));
366 assert_eq!(field.size, b.size(bx.cx()));
367 (Some(b), b_llval)
368 }
369 }
370
371 _ => {
372 span_bug!(fx.mir.span, "OperandRef::extract_field({:?}): not applicable", self)
373 }
374 };
375 OperandValue::Immediate(match field.backend_repr {
376 BackendRepr::SimdVector { .. } => imm,
377 BackendRepr::Scalar(out_scalar) => {
378 let Some(in_scalar) = in_scalar else {
379 span_bug!(
380 fx.mir.span,
381 "OperandRef::extract_field({:?}): missing input scalar for output scalar",
382 self
383 )
384 };
385 if in_scalar != out_scalar {
386 let backend = bx.from_immediate(imm);
391 bx.to_immediate_scalar(backend, out_scalar)
392 } else {
393 imm
394 }
395 }
396 BackendRepr::ScalarPair(_, _) | BackendRepr::Memory { .. } => bug!(),
397 })
398 };
399
400 OperandRef { val, layout: field }
401 }
402
403 #[instrument(level = "trace", skip(fx, bx))]
405 pub fn codegen_get_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
406 self,
407 fx: &mut FunctionCx<'a, 'tcx, Bx>,
408 bx: &mut Bx,
409 cast_to: Ty<'tcx>,
410 ) -> V {
411 let dl = &bx.tcx().data_layout;
412 let cast_to_layout = bx.cx().layout_of(cast_to);
413 let cast_to = bx.cx().immediate_backend_type(cast_to_layout);
414
415 if self.layout.is_uninhabited() {
419 return bx.cx().const_poison(cast_to);
420 }
421
422 let (tag_scalar, tag_encoding, tag_field) = match self.layout.variants {
423 Variants::Empty => unreachable!("we already handled uninhabited types"),
424 Variants::Single { index } => {
425 let discr_val =
426 if let Some(discr) = self.layout.ty.discriminant_for_variant(bx.tcx(), index) {
427 discr.val
428 } else {
429 assert_eq!(index, FIRST_VARIANT);
432 0
435 };
436 return bx.cx().const_uint_big(cast_to, discr_val);
437 }
438 Variants::Multiple { tag, ref tag_encoding, tag_field, .. } => {
439 (tag, tag_encoding, tag_field)
440 }
441 };
442
443 let tag_op = match self.val {
445 OperandValue::ZeroSized => bug!(),
446 OperandValue::Immediate(_) | OperandValue::Pair(_, _) => {
447 self.extract_field(fx, bx, tag_field.as_usize())
448 }
449 OperandValue::Ref(place) => {
450 let tag = place.with_type(self.layout).project_field(bx, tag_field.as_usize());
451 bx.load_operand(tag)
452 }
453 };
454 let tag_imm = tag_op.immediate();
455
456 match *tag_encoding {
458 TagEncoding::Direct => {
459 let signed = match tag_scalar.primitive() {
460 Primitive::Int(_, signed) => !tag_scalar.is_bool() && signed,
465 _ => false,
466 };
467 bx.intcast(tag_imm, cast_to, signed)
468 }
469 TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start } => {
470 let (tag, tag_llty) = match tag_scalar.primitive() {
473 Primitive::Pointer(_) => {
475 let t = bx.type_from_integer(dl.ptr_sized_integer());
476 let tag = bx.ptrtoint(tag_imm, t);
477 (tag, t)
478 }
479 _ => (tag_imm, bx.cx().immediate_backend_type(tag_op.layout)),
480 };
481
482 debug_assert_eq!(
486 self.layout
487 .ty
488 .discriminant_for_variant(bx.tcx(), untagged_variant)
489 .unwrap()
490 .val,
491 u128::from(untagged_variant.as_u32()),
492 );
493
494 let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32();
495
496 let (is_niche, tagged_discr, delta) = if relative_max == 0 {
511 let niche_start = bx.cx().const_uint_big(tag_llty, niche_start);
521 let is_niche = bx.icmp(IntPredicate::IntEQ, tag, niche_start);
522 let tagged_discr =
523 bx.cx().const_uint(cast_to, niche_variants.start().as_u32() as u64);
524 (is_niche, tagged_discr, 0)
525 } else {
526 let relative_discr = bx.sub(tag, bx.cx().const_uint_big(tag_llty, niche_start));
529 let cast_tag = bx.intcast(relative_discr, cast_to, false);
530 let is_niche = bx.icmp(
531 IntPredicate::IntULE,
532 relative_discr,
533 bx.cx().const_uint(tag_llty, relative_max as u64),
534 );
535
536 if niche_variants.contains(&untagged_variant)
541 && bx.cx().sess().opts.optimize != OptLevel::No
542 {
543 let impossible =
544 u64::from(untagged_variant.as_u32() - niche_variants.start().as_u32());
545 let impossible = bx.cx().const_uint(tag_llty, impossible);
546 let ne = bx.icmp(IntPredicate::IntNE, relative_discr, impossible);
547 bx.assume(ne);
548 }
549
550 (is_niche, cast_tag, niche_variants.start().as_u32() as u128)
551 };
552
553 let tagged_discr = if delta == 0 {
554 tagged_discr
555 } else {
556 bx.add(tagged_discr, bx.cx().const_uint_big(cast_to, delta))
557 };
558
559 let discr = bx.select(
560 is_niche,
561 tagged_discr,
562 bx.cx().const_uint(cast_to, untagged_variant.as_u32() as u64),
563 );
564
565 discr
571 }
572 }
573 }
574
575 pub(crate) fn builder(
581 layout: TyAndLayout<'tcx>,
582 ) -> Option<OperandRef<'tcx, Result<V, abi::Scalar>>> {
583 let val = match layout.backend_repr {
584 BackendRepr::Memory { .. } if layout.is_zst() => OperandValue::ZeroSized,
585 BackendRepr::Scalar(s) => OperandValue::Immediate(Err(s)),
586 BackendRepr::ScalarPair(a, b) => OperandValue::Pair(Err(a), Err(b)),
587 BackendRepr::Memory { .. } | BackendRepr::SimdVector { .. } => return None,
588 };
589 Some(OperandRef { val, layout })
590 }
591}
592
593impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, Result<V, abi::Scalar>> {
594 pub(crate) fn insert_field<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
595 &mut self,
596 bx: &mut Bx,
597 v: VariantIdx,
598 f: FieldIdx,
599 operand: OperandRef<'tcx, V>,
600 ) {
601 let (expect_zst, is_zero_offset) = if let abi::FieldsShape::Primitive = self.layout.fields {
602 assert!(!self.layout.is_zst());
607 assert_eq!(v, FIRST_VARIANT);
608 let first_field = f == FieldIdx::ZERO;
609 (!first_field, first_field)
610 } else {
611 let variant_layout = self.layout.for_variant(bx.cx(), v);
612 let field_layout = variant_layout.field(bx.cx(), f.as_usize());
613 let field_offset = variant_layout.fields.offset(f.as_usize());
614 (field_layout.is_zst(), field_offset == Size::ZERO)
615 };
616
617 let mut update = |tgt: &mut Result<V, abi::Scalar>, src, from_scalar| {
618 let from_bty = bx.cx().type_from_scalar(from_scalar);
619 let to_scalar = tgt.unwrap_err();
620 let to_bty = bx.cx().type_from_scalar(to_scalar);
621 let imm = transmute_immediate(bx, src, from_scalar, from_bty, to_scalar, to_bty);
622 *tgt = Ok(imm);
623 };
624
625 match (operand.val, operand.layout.backend_repr) {
626 (OperandValue::ZeroSized, _) if expect_zst => {}
627 (OperandValue::Immediate(v), BackendRepr::Scalar(from_scalar)) => match &mut self.val {
628 OperandValue::Immediate(val @ Err(_)) if is_zero_offset => {
629 update(val, v, from_scalar);
630 }
631 OperandValue::Pair(fst @ Err(_), _) if is_zero_offset => {
632 update(fst, v, from_scalar);
633 }
634 OperandValue::Pair(_, snd @ Err(_)) if !is_zero_offset => {
635 update(snd, v, from_scalar);
636 }
637 _ => bug!("Tried to insert {operand:?} into {v:?}.{f:?} of {self:?}"),
638 },
639 (OperandValue::Pair(a, b), BackendRepr::ScalarPair(from_sa, from_sb)) => {
640 match &mut self.val {
641 OperandValue::Pair(fst @ Err(_), snd @ Err(_)) => {
642 update(fst, a, from_sa);
643 update(snd, b, from_sb);
644 }
645 _ => bug!("Tried to insert {operand:?} into {v:?}.{f:?} of {self:?}"),
646 }
647 }
648 _ => bug!("Unsupported operand {operand:?} inserting into {v:?}.{f:?} of {self:?}"),
649 }
650 }
651
652 pub fn build(&self) -> OperandRef<'tcx, V> {
658 let OperandRef { val, layout } = *self;
659
660 let unwrap = |r: Result<V, abi::Scalar>| match r {
661 Ok(v) => v,
662 Err(_) => bug!("OperandRef::build called while fields are missing {self:?}"),
663 };
664
665 let val = match val {
666 OperandValue::ZeroSized => OperandValue::ZeroSized,
667 OperandValue::Immediate(v) => OperandValue::Immediate(unwrap(v)),
668 OperandValue::Pair(a, b) => OperandValue::Pair(unwrap(a), unwrap(b)),
669 OperandValue::Ref(_) => bug!(),
670 };
671 OperandRef { val, layout }
672 }
673}
674
675impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
676 pub fn poison<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
683 bx: &mut Bx,
684 layout: TyAndLayout<'tcx>,
685 ) -> OperandValue<V> {
686 assert!(layout.is_sized());
687 if layout.is_zst() {
688 OperandValue::ZeroSized
689 } else if bx.cx().is_backend_immediate(layout) {
690 let ibty = bx.cx().immediate_backend_type(layout);
691 OperandValue::Immediate(bx.const_poison(ibty))
692 } else if bx.cx().is_backend_scalar_pair(layout) {
693 let ibty0 = bx.cx().scalar_pair_element_backend_type(layout, 0, true);
694 let ibty1 = bx.cx().scalar_pair_element_backend_type(layout, 1, true);
695 OperandValue::Pair(bx.const_poison(ibty0), bx.const_poison(ibty1))
696 } else {
697 let ptr = bx.cx().type_ptr();
698 OperandValue::Ref(PlaceValue::new_sized(bx.const_poison(ptr), layout.align.abi))
699 }
700 }
701
702 pub fn store<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
703 self,
704 bx: &mut Bx,
705 dest: PlaceRef<'tcx, V>,
706 ) {
707 self.store_with_flags(bx, dest, MemFlags::empty());
708 }
709
710 pub fn volatile_store<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
711 self,
712 bx: &mut Bx,
713 dest: PlaceRef<'tcx, V>,
714 ) {
715 self.store_with_flags(bx, dest, MemFlags::VOLATILE);
716 }
717
718 pub fn unaligned_volatile_store<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
719 self,
720 bx: &mut Bx,
721 dest: PlaceRef<'tcx, V>,
722 ) {
723 self.store_with_flags(bx, dest, MemFlags::VOLATILE | MemFlags::UNALIGNED);
724 }
725
726 pub fn nontemporal_store<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
727 self,
728 bx: &mut Bx,
729 dest: PlaceRef<'tcx, V>,
730 ) {
731 self.store_with_flags(bx, dest, MemFlags::NONTEMPORAL);
732 }
733
734 pub(crate) fn store_with_flags<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
735 self,
736 bx: &mut Bx,
737 dest: PlaceRef<'tcx, V>,
738 flags: MemFlags,
739 ) {
740 debug!("OperandRef::store: operand={:?}, dest={:?}", self, dest);
741 match self {
742 OperandValue::ZeroSized => {
743 }
746 OperandValue::Ref(val) => {
747 assert!(dest.layout.is_sized(), "cannot directly store unsized values");
748 if val.llextra.is_some() {
749 bug!("cannot directly store unsized values");
750 }
751 bx.typed_place_copy_with_flags(dest.val, val, dest.layout, flags);
752 }
753 OperandValue::Immediate(s) => {
754 let val = bx.from_immediate(s);
755 bx.store_with_flags(val, dest.val.llval, dest.val.align, flags);
756 }
757 OperandValue::Pair(a, b) => {
758 let BackendRepr::ScalarPair(a_scalar, b_scalar) = dest.layout.backend_repr else {
759 bug!("store_with_flags: invalid ScalarPair layout: {:#?}", dest.layout);
760 };
761 let b_offset = a_scalar.size(bx).align_to(b_scalar.align(bx).abi);
762
763 let val = bx.from_immediate(a);
764 let align = dest.val.align;
765 bx.store_with_flags(val, dest.val.llval, align, flags);
766
767 let llptr = bx.inbounds_ptradd(dest.val.llval, bx.const_usize(b_offset.bytes()));
768 let val = bx.from_immediate(b);
769 let align = dest.val.align.restrict_for_offset(b_offset);
770 bx.store_with_flags(val, llptr, align, flags);
771 }
772 }
773 }
774
775 pub fn store_unsized<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
776 self,
777 bx: &mut Bx,
778 indirect_dest: PlaceRef<'tcx, V>,
779 ) {
780 debug!("OperandRef::store_unsized: operand={:?}, indirect_dest={:?}", self, indirect_dest);
781 let unsized_ty = indirect_dest
783 .layout
784 .ty
785 .builtin_deref(true)
786 .unwrap_or_else(|| bug!("indirect_dest has non-pointer type: {:?}", indirect_dest));
787
788 let OperandValue::Ref(PlaceValue { llval: llptr, llextra: Some(llextra), .. }) = self
789 else {
790 bug!("store_unsized called with a sized value (or with an extern type)")
791 };
792
793 let (size, align) = size_of_val::size_and_align_of_dst(bx, unsized_ty, Some(llextra));
797 let one = bx.const_usize(1);
798 let align_minus_1 = bx.sub(align, one);
799 let size_extra = bx.add(size, align_minus_1);
800 let min_align = Align::ONE;
801 let alloca = bx.dynamic_alloca(size_extra, min_align);
802 let address = bx.ptrtoint(alloca, bx.type_isize());
803 let neg_address = bx.neg(address);
804 let offset = bx.and(neg_address, align_minus_1);
805 let dst = bx.inbounds_ptradd(alloca, offset);
806 bx.memcpy(dst, min_align, llptr, min_align, size, MemFlags::empty());
807
808 let indirect_operand = OperandValue::Pair(dst, llextra);
810 indirect_operand.store(bx, indirect_dest);
811 }
812}
813
814impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
815 fn maybe_codegen_consume_direct(
816 &mut self,
817 bx: &mut Bx,
818 place_ref: mir::PlaceRef<'tcx>,
819 ) -> Option<OperandRef<'tcx, Bx::Value>> {
820 debug!("maybe_codegen_consume_direct(place_ref={:?})", place_ref);
821
822 match self.locals[place_ref.local] {
823 LocalRef::Operand(mut o) => {
824 for elem in place_ref.projection.iter() {
826 match elem {
827 mir::ProjectionElem::Field(f, _) => {
828 assert!(
829 !o.layout.ty.is_any_ptr(),
830 "Bad PlaceRef: destructing pointers should use cast/PtrMetadata, \
831 but tried to access field {f:?} of pointer {o:?}",
832 );
833 o = o.extract_field(self, bx, f.index());
834 }
835 mir::ProjectionElem::Index(_)
836 | mir::ProjectionElem::ConstantIndex { .. } => {
837 let elem = o.layout.field(bx.cx(), 0);
841 if elem.is_zst() {
842 o = OperandRef::zero_sized(elem);
843 } else {
844 return None;
845 }
846 }
847 _ => return None,
848 }
849 }
850
851 Some(o)
852 }
853 LocalRef::PendingOperand => {
854 bug!("use of {:?} before def", place_ref);
855 }
856 LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => {
857 None
860 }
861 }
862 }
863
864 pub fn codegen_consume(
865 &mut self,
866 bx: &mut Bx,
867 place_ref: mir::PlaceRef<'tcx>,
868 ) -> OperandRef<'tcx, Bx::Value> {
869 debug!("codegen_consume(place_ref={:?})", place_ref);
870
871 let ty = self.monomorphized_place_ty(place_ref);
872 let layout = bx.cx().layout_of(ty);
873
874 if layout.is_zst() {
876 return OperandRef::zero_sized(layout);
877 }
878
879 if let Some(o) = self.maybe_codegen_consume_direct(bx, place_ref) {
880 return o;
881 }
882
883 let place = self.codegen_place(bx, place_ref);
886 bx.load_operand(place)
887 }
888
889 pub fn codegen_operand(
890 &mut self,
891 bx: &mut Bx,
892 operand: &mir::Operand<'tcx>,
893 ) -> OperandRef<'tcx, Bx::Value> {
894 debug!("codegen_operand(operand={:?})", operand);
895
896 match *operand {
897 mir::Operand::Copy(ref place) | mir::Operand::Move(ref place) => {
898 self.codegen_consume(bx, place.as_ref())
899 }
900
901 mir::Operand::Constant(ref constant) => {
902 let constant_ty = self.monomorphize(constant.ty());
903 if constant_ty.is_simd() {
906 let layout = bx.layout_of(constant_ty);
909 if let BackendRepr::SimdVector { .. } = layout.backend_repr {
910 let (llval, ty) = self.immediate_const_vector(bx, constant);
911 return OperandRef {
912 val: OperandValue::Immediate(llval),
913 layout: bx.layout_of(ty),
914 };
915 }
916 }
917 self.eval_mir_constant_to_operand(bx, constant)
918 }
919 }
920 }
921}