1use std::assert_matches::assert_matches;
2
3use arrayvec::ArrayVec;
4use rustc_abi::{self as abi, FIRST_VARIANT, FieldIdx};
5use rustc_middle::ty::adjustment::PointerCoercion;
6use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout};
7use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
8use rustc_middle::{bug, mir, span_bug};
9use rustc_session::config::OptLevel;
10use rustc_span::{DUMMY_SP, Span};
11use tracing::{debug, instrument};
12
13use super::operand::{OperandRef, OperandValue};
14use super::place::PlaceRef;
15use super::{FunctionCx, LocalRef};
16use crate::common::IntPredicate;
17use crate::traits::*;
18use crate::{MemFlags, base};
19
20impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
21 #[instrument(level = "trace", skip(self, bx))]
22 pub(crate) fn codegen_rvalue(
23 &mut self,
24 bx: &mut Bx,
25 dest: PlaceRef<'tcx, Bx::Value>,
26 rvalue: &mir::Rvalue<'tcx>,
27 ) {
28 match *rvalue {
29 mir::Rvalue::Use(ref operand) => {
30 let cg_operand = self.codegen_operand(bx, operand);
31 cg_operand.val.store(bx, dest);
34 }
35
36 mir::Rvalue::Cast(
37 mir::CastKind::PointerCoercion(PointerCoercion::Unsize, _),
38 ref source,
39 _,
40 ) => {
41 if bx.cx().is_backend_scalar_pair(dest.layout) {
44 let temp = self.codegen_rvalue_operand(bx, rvalue);
47 temp.val.store(bx, dest);
48 return;
49 }
50
51 let operand = self.codegen_operand(bx, source);
56 match operand.val {
57 OperandValue::Pair(..) | OperandValue::Immediate(_) => {
58 debug!("codegen_rvalue: creating ugly alloca");
65 let scratch = PlaceRef::alloca(bx, operand.layout);
66 scratch.storage_live(bx);
67 operand.val.store(bx, scratch);
68 base::coerce_unsized_into(bx, scratch, dest);
69 scratch.storage_dead(bx);
70 }
71 OperandValue::Ref(val) => {
72 if val.llextra.is_some() {
73 bug!("unsized coercion on an unsized rvalue");
74 }
75 base::coerce_unsized_into(bx, val.with_type(operand.layout), dest);
76 }
77 OperandValue::ZeroSized => {
78 bug!("unsized coercion on a ZST rvalue");
79 }
80 }
81 }
82
83 mir::Rvalue::Cast(mir::CastKind::Transmute, ref operand, _ty) => {
84 let src = self.codegen_operand(bx, operand);
85 self.codegen_transmute(bx, src, dest);
86 }
87
88 mir::Rvalue::Repeat(ref elem, count) => {
89 let cg_elem = self.codegen_operand(bx, elem);
90
91 if dest.layout.is_zst() {
93 return;
94 }
95
96 let try_init_all_same = |bx: &mut Bx, v| {
97 let start = dest.val.llval;
98 let size = bx.const_usize(dest.layout.size.bytes());
99
100 if let Some(int) = bx.cx().const_to_opt_u128(v, false) {
102 let bytes = &int.to_le_bytes()[..cg_elem.layout.size.bytes_usize()];
103 let first = bytes[0];
104 if bytes[1..].iter().all(|&b| b == first) {
105 let fill = bx.cx().const_u8(first);
106 bx.memset(start, fill, size, dest.val.align, MemFlags::empty());
107 return true;
108 }
109 }
110
111 let v = bx.from_immediate(v);
113 if bx.cx().val_ty(v) == bx.cx().type_i8() {
114 bx.memset(start, v, size, dest.val.align, MemFlags::empty());
115 return true;
116 }
117 false
118 };
119
120 match cg_elem.val {
121 OperandValue::Immediate(v) => {
122 if try_init_all_same(bx, v) {
123 return;
124 }
125 }
126 _ => (),
127 }
128
129 let count = self
130 .monomorphize(count)
131 .try_to_target_usize(bx.tcx())
132 .expect("expected monomorphic const in codegen");
133
134 bx.write_operand_repeatedly(cg_elem, count, dest);
135 }
136
137 mir::Rvalue::Aggregate(ref kind, ref operands)
140 if !matches!(**kind, mir::AggregateKind::RawPtr(..)) =>
141 {
142 let (variant_index, variant_dest, active_field_index) = match **kind {
143 mir::AggregateKind::Adt(_, variant_index, _, _, active_field_index) => {
144 let variant_dest = dest.project_downcast(bx, variant_index);
145 (variant_index, variant_dest, active_field_index)
146 }
147 _ => (FIRST_VARIANT, dest, None),
148 };
149 if active_field_index.is_some() {
150 assert_eq!(operands.len(), 1);
151 }
152 for (i, operand) in operands.iter_enumerated() {
153 let op = self.codegen_operand(bx, operand);
154 if !op.layout.is_zst() {
156 let field_index = active_field_index.unwrap_or(i);
157 let field = if let mir::AggregateKind::Array(_) = **kind {
158 let llindex = bx.cx().const_usize(field_index.as_u32().into());
159 variant_dest.project_index(bx, llindex)
160 } else {
161 variant_dest.project_field(bx, field_index.as_usize())
162 };
163 op.val.store(bx, field);
164 }
165 }
166 dest.codegen_set_discr(bx, variant_index);
167 }
168
169 _ => {
170 assert!(self.rvalue_creates_operand(rvalue, DUMMY_SP));
171 let temp = self.codegen_rvalue_operand(bx, rvalue);
172 temp.val.store(bx, dest);
173 }
174 }
175 }
176
177 fn codegen_transmute(
178 &mut self,
179 bx: &mut Bx,
180 src: OperandRef<'tcx, Bx::Value>,
181 dst: PlaceRef<'tcx, Bx::Value>,
182 ) {
183 assert!(src.layout.is_sized());
185 assert!(dst.layout.is_sized());
186
187 if let Some(val) = self.codegen_transmute_operand(bx, src, dst.layout) {
188 val.store(bx, dst);
189 return;
190 }
191
192 match src.val {
193 OperandValue::Ref(..) | OperandValue::ZeroSized => {
194 span_bug!(
195 self.mir.span,
196 "Operand path should have handled transmute \
197 from {src:?} to place {dst:?}"
198 );
199 }
200 OperandValue::Immediate(..) | OperandValue::Pair(..) => {
201 src.val.store(bx, dst.val.with_type(src.layout));
204 }
205 }
206 }
207
208 pub(crate) fn codegen_transmute_operand(
213 &mut self,
214 bx: &mut Bx,
215 operand: OperandRef<'tcx, Bx::Value>,
216 cast: TyAndLayout<'tcx>,
217 ) -> Option<OperandValue<Bx::Value>> {
218 if operand.layout.size != cast.size
220 || operand.layout.is_uninhabited()
221 || cast.is_uninhabited()
222 {
223 if !operand.layout.is_uninhabited() {
224 bx.abort();
227 }
228
229 return Some(OperandValue::poison(bx, cast));
232 }
233
234 let operand_kind = self.value_kind(operand.layout);
235 let cast_kind = self.value_kind(cast);
236
237 match operand.val {
238 OperandValue::Ref(source_place_val) => {
239 assert_eq!(source_place_val.llextra, None);
240 assert_matches!(operand_kind, OperandValueKind::Ref);
241 Some(bx.load_operand(source_place_val.with_type(cast)).val)
244 }
245 OperandValue::ZeroSized => {
246 let OperandValueKind::ZeroSized = operand_kind else {
247 bug!("Found {operand_kind:?} for operand {operand:?}");
248 };
249 if let OperandValueKind::ZeroSized = cast_kind {
250 Some(OperandValue::ZeroSized)
251 } else {
252 None
253 }
254 }
255 OperandValue::Immediate(imm) => {
256 let OperandValueKind::Immediate(from_scalar) = operand_kind else {
257 bug!("Found {operand_kind:?} for operand {operand:?}");
258 };
259 if let OperandValueKind::Immediate(to_scalar) = cast_kind
260 && from_scalar.size(self.cx) == to_scalar.size(self.cx)
261 {
262 let from_backend_ty = bx.backend_type(operand.layout);
263 let to_backend_ty = bx.backend_type(cast);
264 Some(OperandValue::Immediate(self.transmute_immediate(
265 bx,
266 imm,
267 from_scalar,
268 from_backend_ty,
269 to_scalar,
270 to_backend_ty,
271 )))
272 } else {
273 None
274 }
275 }
276 OperandValue::Pair(imm_a, imm_b) => {
277 let OperandValueKind::Pair(in_a, in_b) = operand_kind else {
278 bug!("Found {operand_kind:?} for operand {operand:?}");
279 };
280 if let OperandValueKind::Pair(out_a, out_b) = cast_kind
281 && in_a.size(self.cx) == out_a.size(self.cx)
282 && in_b.size(self.cx) == out_b.size(self.cx)
283 {
284 let in_a_ibty = bx.scalar_pair_element_backend_type(operand.layout, 0, false);
285 let in_b_ibty = bx.scalar_pair_element_backend_type(operand.layout, 1, false);
286 let out_a_ibty = bx.scalar_pair_element_backend_type(cast, 0, false);
287 let out_b_ibty = bx.scalar_pair_element_backend_type(cast, 1, false);
288 Some(OperandValue::Pair(
289 self.transmute_immediate(bx, imm_a, in_a, in_a_ibty, out_a, out_a_ibty),
290 self.transmute_immediate(bx, imm_b, in_b, in_b_ibty, out_b, out_b_ibty),
291 ))
292 } else {
293 None
294 }
295 }
296 }
297 }
298
299 fn cast_immediate(
304 &self,
305 bx: &mut Bx,
306 mut imm: Bx::Value,
307 from_scalar: abi::Scalar,
308 from_backend_ty: Bx::Type,
309 to_scalar: abi::Scalar,
310 to_backend_ty: Bx::Type,
311 ) -> Option<Bx::Value> {
312 use abi::Primitive::*;
313
314 self.assume_scalar_range(bx, imm, from_scalar, from_backend_ty);
319
320 imm = match (from_scalar.primitive(), to_scalar.primitive()) {
321 (Int(_, is_signed), Int(..)) => bx.intcast(imm, to_backend_ty, is_signed),
322 (Float(_), Float(_)) => {
323 let srcsz = bx.cx().float_width(from_backend_ty);
324 let dstsz = bx.cx().float_width(to_backend_ty);
325 if dstsz > srcsz {
326 bx.fpext(imm, to_backend_ty)
327 } else if srcsz > dstsz {
328 bx.fptrunc(imm, to_backend_ty)
329 } else {
330 imm
331 }
332 }
333 (Int(_, is_signed), Float(_)) => {
334 if is_signed {
335 bx.sitofp(imm, to_backend_ty)
336 } else {
337 bx.uitofp(imm, to_backend_ty)
338 }
339 }
340 (Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty),
341 (Int(_, is_signed), Pointer(..)) => {
342 let usize_imm = bx.intcast(imm, bx.cx().type_isize(), is_signed);
343 bx.inttoptr(usize_imm, to_backend_ty)
344 }
345 (Float(_), Int(_, is_signed)) => bx.cast_float_to_int(is_signed, imm, to_backend_ty),
346 _ => return None,
347 };
348 Some(imm)
349 }
350
351 fn transmute_immediate(
357 &self,
358 bx: &mut Bx,
359 mut imm: Bx::Value,
360 from_scalar: abi::Scalar,
361 from_backend_ty: Bx::Type,
362 to_scalar: abi::Scalar,
363 to_backend_ty: Bx::Type,
364 ) -> Bx::Value {
365 assert_eq!(from_scalar.size(self.cx), to_scalar.size(self.cx));
366
367 if from_scalar == to_scalar && from_backend_ty == to_backend_ty {
371 return imm;
372 }
373
374 use abi::Primitive::*;
375 imm = bx.from_immediate(imm);
376
377 self.assume_scalar_range(bx, imm, from_scalar, from_backend_ty);
387
388 imm = match (from_scalar.primitive(), to_scalar.primitive()) {
389 (Int(..) | Float(_), Int(..) | Float(_)) => bx.bitcast(imm, to_backend_ty),
390 (Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty),
391 (Int(..), Pointer(..)) => bx.ptradd(bx.const_null(bx.type_ptr()), imm),
392 (Pointer(..), Int(..)) => {
393 bx.ptrtoint(imm, to_backend_ty)
395 }
396 (Float(_), Pointer(..)) => {
397 let int_imm = bx.bitcast(imm, bx.cx().type_isize());
398 bx.ptradd(bx.const_null(bx.type_ptr()), int_imm)
399 }
400 (Pointer(..), Float(_)) => {
401 let int_imm = bx.ptrtoint(imm, bx.cx().type_isize());
403 bx.bitcast(int_imm, to_backend_ty)
404 }
405 };
406
407 self.assume_scalar_range(bx, imm, to_scalar, to_backend_ty);
413
414 imm = bx.to_immediate_scalar(imm, to_scalar);
415 imm
416 }
417
418 fn assume_scalar_range(
419 &self,
420 bx: &mut Bx,
421 imm: Bx::Value,
422 scalar: abi::Scalar,
423 backend_ty: Bx::Type,
424 ) {
425 if matches!(self.cx.sess().opts.optimize, OptLevel::No) || scalar.is_always_valid(self.cx) {
426 return;
427 }
428
429 match scalar.primitive() {
430 abi::Primitive::Int(..) => {
431 let range = scalar.valid_range(self.cx);
432 bx.assume_integer_range(imm, backend_ty, range);
433 }
434 abi::Primitive::Pointer(abi::AddressSpace::DATA)
435 if !scalar.valid_range(self.cx).contains(0) =>
436 {
437 bx.assume_nonnull(imm);
438 }
439 abi::Primitive::Pointer(..) | abi::Primitive::Float(..) => {}
440 }
441 }
442
443 pub(crate) fn codegen_rvalue_unsized(
444 &mut self,
445 bx: &mut Bx,
446 indirect_dest: PlaceRef<'tcx, Bx::Value>,
447 rvalue: &mir::Rvalue<'tcx>,
448 ) {
449 debug!(
450 "codegen_rvalue_unsized(indirect_dest.llval={:?}, rvalue={:?})",
451 indirect_dest.val.llval, rvalue
452 );
453
454 match *rvalue {
455 mir::Rvalue::Use(ref operand) => {
456 let cg_operand = self.codegen_operand(bx, operand);
457 cg_operand.val.store_unsized(bx, indirect_dest);
458 }
459
460 _ => bug!("unsized assignment other than `Rvalue::Use`"),
461 }
462 }
463
464 pub(crate) fn codegen_rvalue_operand(
465 &mut self,
466 bx: &mut Bx,
467 rvalue: &mir::Rvalue<'tcx>,
468 ) -> OperandRef<'tcx, Bx::Value> {
469 assert!(
470 self.rvalue_creates_operand(rvalue, DUMMY_SP),
471 "cannot codegen {rvalue:?} to operand",
472 );
473
474 match *rvalue {
475 mir::Rvalue::Cast(ref kind, ref source, mir_cast_ty) => {
476 let operand = self.codegen_operand(bx, source);
477 debug!("cast operand is {:?}", operand);
478 let cast = bx.cx().layout_of(self.monomorphize(mir_cast_ty));
479
480 let val = match *kind {
481 mir::CastKind::PointerExposeProvenance => {
482 assert!(bx.cx().is_backend_immediate(cast));
483 let llptr = operand.immediate();
484 let llcast_ty = bx.cx().immediate_backend_type(cast);
485 let lladdr = bx.ptrtoint(llptr, llcast_ty);
486 OperandValue::Immediate(lladdr)
487 }
488 mir::CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer, _) => {
489 match *operand.layout.ty.kind() {
490 ty::FnDef(def_id, args) => {
491 let instance = ty::Instance::resolve_for_fn_ptr(
492 bx.tcx(),
493 bx.typing_env(),
494 def_id,
495 args,
496 )
497 .unwrap();
498 OperandValue::Immediate(bx.get_fn_addr(instance))
499 }
500 _ => bug!("{} cannot be reified to a fn ptr", operand.layout.ty),
501 }
502 }
503 mir::CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_), _) => {
504 match *operand.layout.ty.kind() {
505 ty::Closure(def_id, args) => {
506 let instance = Instance::resolve_closure(
507 bx.cx().tcx(),
508 def_id,
509 args,
510 ty::ClosureKind::FnOnce,
511 );
512 OperandValue::Immediate(bx.cx().get_fn_addr(instance))
513 }
514 _ => bug!("{} cannot be cast to a fn ptr", operand.layout.ty),
515 }
516 }
517 mir::CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer, _) => {
518 operand.val
520 }
521 mir::CastKind::PointerCoercion(PointerCoercion::Unsize, _) => {
522 assert!(bx.cx().is_backend_scalar_pair(cast));
523 let (lldata, llextra) = operand.val.pointer_parts();
524 let (lldata, llextra) =
525 base::unsize_ptr(bx, lldata, operand.layout.ty, cast.ty, llextra);
526 OperandValue::Pair(lldata, llextra)
527 }
528 mir::CastKind::PointerCoercion(
529 PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer, _
530 ) => {
531 bug!("{kind:?} is for borrowck, and should never appear in codegen");
532 }
533 mir::CastKind::PtrToPtr
534 if bx.cx().is_backend_scalar_pair(operand.layout) =>
535 {
536 if let OperandValue::Pair(data_ptr, meta) = operand.val {
537 if bx.cx().is_backend_scalar_pair(cast) {
538 OperandValue::Pair(data_ptr, meta)
539 } else {
540 OperandValue::Immediate(data_ptr)
542 }
543 } else {
544 bug!("unexpected non-pair operand");
545 }
546 }
547 mir::CastKind::PointerCoercion(PointerCoercion::DynStar, _) => {
548 let (lldata, llextra) = operand.val.pointer_parts();
549 let (lldata, llextra) =
550 base::cast_to_dyn_star(bx, lldata, operand.layout, cast.ty, llextra);
551 OperandValue::Pair(lldata, llextra)
552 }
553 | mir::CastKind::IntToInt
554 | mir::CastKind::FloatToInt
555 | mir::CastKind::FloatToFloat
556 | mir::CastKind::IntToFloat
557 | mir::CastKind::PtrToPtr
558 | mir::CastKind::FnPtrToPtr
559 | mir::CastKind::PointerWithExposedProvenance => {
563 let imm = operand.immediate();
564 let operand_kind = self.value_kind(operand.layout);
565 let OperandValueKind::Immediate(from_scalar) = operand_kind else {
566 bug!("Found {operand_kind:?} for operand {operand:?}");
567 };
568 let from_backend_ty = bx.cx().immediate_backend_type(operand.layout);
569
570 assert!(bx.cx().is_backend_immediate(cast));
571 let to_backend_ty = bx.cx().immediate_backend_type(cast);
572 if operand.layout.is_uninhabited() {
573 let val = OperandValue::Immediate(bx.cx().const_poison(to_backend_ty));
574 return OperandRef { val, layout: cast };
575 }
576 let cast_kind = self.value_kind(cast);
577 let OperandValueKind::Immediate(to_scalar) = cast_kind else {
578 bug!("Found {cast_kind:?} for operand {cast:?}");
579 };
580
581 self.cast_immediate(bx, imm, from_scalar, from_backend_ty, to_scalar, to_backend_ty)
582 .map(OperandValue::Immediate)
583 .unwrap_or_else(|| {
584 bug!("Unsupported cast of {operand:?} to {cast:?}");
585 })
586 }
587 mir::CastKind::Transmute => {
588 self.codegen_transmute_operand(bx, operand, cast).unwrap_or_else(|| {
589 bug!("Unsupported transmute-as-operand of {operand:?} to {cast:?}");
590 })
591 }
592 };
593 OperandRef { val, layout: cast }
594 }
595
596 mir::Rvalue::Ref(_, bk, place) => {
597 let mk_ref = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| {
598 Ty::new_ref(tcx, tcx.lifetimes.re_erased, ty, bk.to_mutbl_lossy())
599 };
600 self.codegen_place_to_pointer(bx, place, mk_ref)
601 }
602
603 mir::Rvalue::CopyForDeref(place) => {
604 self.codegen_operand(bx, &mir::Operand::Copy(place))
605 }
606 mir::Rvalue::RawPtr(kind, place) => {
607 let mk_ptr = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| {
608 Ty::new_ptr(tcx, ty, kind.to_mutbl_lossy())
609 };
610 self.codegen_place_to_pointer(bx, place, mk_ptr)
611 }
612
613 mir::Rvalue::Len(place) => {
614 let size = self.evaluate_array_len(bx, place);
615 OperandRef {
616 val: OperandValue::Immediate(size),
617 layout: bx.cx().layout_of(bx.tcx().types.usize),
618 }
619 }
620
621 mir::Rvalue::BinaryOp(op_with_overflow, box (ref lhs, ref rhs))
622 if let Some(op) = op_with_overflow.overflowing_to_wrapping() =>
623 {
624 let lhs = self.codegen_operand(bx, lhs);
625 let rhs = self.codegen_operand(bx, rhs);
626 let result = self.codegen_scalar_checked_binop(
627 bx,
628 op,
629 lhs.immediate(),
630 rhs.immediate(),
631 lhs.layout.ty,
632 );
633 let val_ty = op.ty(bx.tcx(), lhs.layout.ty, rhs.layout.ty);
634 let operand_ty = Ty::new_tup(bx.tcx(), &[val_ty, bx.tcx().types.bool]);
635 OperandRef { val: result, layout: bx.cx().layout_of(operand_ty) }
636 }
637 mir::Rvalue::BinaryOp(op, box (ref lhs, ref rhs)) => {
638 let lhs = self.codegen_operand(bx, lhs);
639 let rhs = self.codegen_operand(bx, rhs);
640 let llresult = match (lhs.val, rhs.val) {
641 (
642 OperandValue::Pair(lhs_addr, lhs_extra),
643 OperandValue::Pair(rhs_addr, rhs_extra),
644 ) => self.codegen_wide_ptr_binop(
645 bx,
646 op,
647 lhs_addr,
648 lhs_extra,
649 rhs_addr,
650 rhs_extra,
651 lhs.layout.ty,
652 ),
653
654 (OperandValue::Immediate(lhs_val), OperandValue::Immediate(rhs_val)) => self
655 .codegen_scalar_binop(
656 bx,
657 op,
658 lhs_val,
659 rhs_val,
660 lhs.layout.ty,
661 rhs.layout.ty,
662 ),
663
664 _ => bug!(),
665 };
666 OperandRef {
667 val: OperandValue::Immediate(llresult),
668 layout: bx.cx().layout_of(op.ty(bx.tcx(), lhs.layout.ty, rhs.layout.ty)),
669 }
670 }
671
672 mir::Rvalue::UnaryOp(op, ref operand) => {
673 let operand = self.codegen_operand(bx, operand);
674 let is_float = operand.layout.ty.is_floating_point();
675 let (val, layout) = match op {
676 mir::UnOp::Not => {
677 let llval = bx.not(operand.immediate());
678 (OperandValue::Immediate(llval), operand.layout)
679 }
680 mir::UnOp::Neg => {
681 let llval = if is_float {
682 bx.fneg(operand.immediate())
683 } else {
684 bx.neg(operand.immediate())
685 };
686 (OperandValue::Immediate(llval), operand.layout)
687 }
688 mir::UnOp::PtrMetadata => {
689 assert!(operand.layout.ty.is_raw_ptr() || operand.layout.ty.is_ref(),);
690 let (_, meta) = operand.val.pointer_parts();
691 assert_eq!(operand.layout.fields.count() > 1, meta.is_some());
692 if let Some(meta) = meta {
693 (OperandValue::Immediate(meta), operand.layout.field(self.cx, 1))
694 } else {
695 (OperandValue::ZeroSized, bx.cx().layout_of(bx.tcx().types.unit))
696 }
697 }
698 };
699 assert!(
700 val.is_expected_variant_for_type(self.cx, layout),
701 "Made wrong variant {val:?} for type {layout:?}",
702 );
703 OperandRef { val, layout }
704 }
705
706 mir::Rvalue::Discriminant(ref place) => {
707 let discr_ty = rvalue.ty(self.mir, bx.tcx());
708 let discr_ty = self.monomorphize(discr_ty);
709 let operand = self.codegen_consume(bx, place.as_ref());
710 let discr = operand.codegen_get_discr(self, bx, discr_ty);
711 OperandRef {
712 val: OperandValue::Immediate(discr),
713 layout: self.cx.layout_of(discr_ty),
714 }
715 }
716
717 mir::Rvalue::NullaryOp(ref null_op, ty) => {
718 let ty = self.monomorphize(ty);
719 let layout = bx.cx().layout_of(ty);
720 let val = match null_op {
721 mir::NullOp::SizeOf => {
722 assert!(bx.cx().type_is_sized(ty));
723 let val = layout.size.bytes();
724 bx.cx().const_usize(val)
725 }
726 mir::NullOp::AlignOf => {
727 assert!(bx.cx().type_is_sized(ty));
728 let val = layout.align.abi.bytes();
729 bx.cx().const_usize(val)
730 }
731 mir::NullOp::OffsetOf(fields) => {
732 let val = bx
733 .tcx()
734 .offset_of_subfield(bx.typing_env(), layout, fields.iter())
735 .bytes();
736 bx.cx().const_usize(val)
737 }
738 mir::NullOp::UbChecks => {
739 let val = bx.tcx().sess.ub_checks();
740 bx.cx().const_bool(val)
741 }
742 mir::NullOp::ContractChecks => {
743 let val = bx.tcx().sess.contract_checks();
744 bx.cx().const_bool(val)
745 }
746 };
747 let tcx = self.cx.tcx();
748 OperandRef {
749 val: OperandValue::Immediate(val),
750 layout: self.cx.layout_of(null_op.ty(tcx)),
751 }
752 }
753
754 mir::Rvalue::ThreadLocalRef(def_id) => {
755 assert!(bx.cx().tcx().is_static(def_id));
756 let layout = bx.layout_of(bx.cx().tcx().static_ptr_ty(def_id, bx.typing_env()));
757 let static_ = if !def_id.is_local() && bx.cx().tcx().needs_thread_local_shim(def_id)
758 {
759 let instance = ty::Instance {
760 def: ty::InstanceKind::ThreadLocalShim(def_id),
761 args: ty::GenericArgs::empty(),
762 };
763 let fn_ptr = bx.get_fn_addr(instance);
764 let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty());
765 let fn_ty = bx.fn_decl_backend_type(fn_abi);
766 let fn_attrs = if bx.tcx().def_kind(instance.def_id()).has_codegen_attrs() {
767 Some(bx.tcx().codegen_fn_attrs(instance.def_id()))
768 } else {
769 None
770 };
771 bx.call(fn_ty, fn_attrs, Some(fn_abi), fn_ptr, &[], None, Some(instance))
772 } else {
773 bx.get_static(def_id)
774 };
775 OperandRef { val: OperandValue::Immediate(static_), layout }
776 }
777 mir::Rvalue::Use(ref operand) => self.codegen_operand(bx, operand),
778 mir::Rvalue::Repeat(..) => bug!("{rvalue:?} in codegen_rvalue_operand"),
779 mir::Rvalue::Aggregate(_, ref fields) => {
780 let ty = rvalue.ty(self.mir, self.cx.tcx());
781 let ty = self.monomorphize(ty);
782 let layout = self.cx.layout_of(ty);
783
784 let mut inputs = ArrayVec::<Bx::Value, 2>::new();
787 let mut input_scalars = ArrayVec::<abi::Scalar, 2>::new();
788 for field_idx in layout.fields.index_by_increasing_offset() {
789 let field_idx = FieldIdx::from_usize(field_idx);
790 let op = self.codegen_operand(bx, &fields[field_idx]);
791 let values = op.val.immediates_or_place().left_or_else(|p| {
792 bug!("Field {field_idx:?} is {p:?} making {layout:?}");
793 });
794 let scalars = self.value_kind(op.layout).scalars().unwrap();
795 assert_eq!(values.len(), scalars.len());
796 inputs.extend(values);
797 input_scalars.extend(scalars);
798 }
799
800 let output_scalars = self.value_kind(layout).scalars().unwrap();
801 itertools::izip!(&mut inputs, input_scalars, output_scalars).for_each(
802 |(v, in_s, out_s)| {
803 if in_s != out_s {
804 *v = bx.from_immediate(*v);
807 *v = bx.to_immediate_scalar(*v, out_s);
808 }
809 },
810 );
811
812 let val = OperandValue::from_immediates(inputs);
813 assert!(
814 val.is_expected_variant_for_type(self.cx, layout),
815 "Made wrong variant {val:?} for type {layout:?}",
816 );
817 OperandRef { val, layout }
818 }
819 mir::Rvalue::ShallowInitBox(ref operand, content_ty) => {
820 let operand = self.codegen_operand(bx, operand);
821 let val = operand.immediate();
822
823 let content_ty = self.monomorphize(content_ty);
824 let box_layout = bx.cx().layout_of(Ty::new_box(bx.tcx(), content_ty));
825
826 OperandRef { val: OperandValue::Immediate(val), layout: box_layout }
827 }
828 mir::Rvalue::WrapUnsafeBinder(ref operand, binder_ty) => {
829 let operand = self.codegen_operand(bx, operand);
830 let binder_ty = self.monomorphize(binder_ty);
831 let layout = bx.cx().layout_of(binder_ty);
832 OperandRef { val: operand.val, layout }
833 }
834 }
835 }
836
837 fn evaluate_array_len(&mut self, bx: &mut Bx, place: mir::Place<'tcx>) -> Bx::Value {
838 if let Some(index) = place.as_local()
841 && let LocalRef::Operand(op) = self.locals[index]
842 && let ty::Array(_, n) = op.layout.ty.kind()
843 {
844 let n = n.try_to_target_usize(bx.tcx()).expect("expected monomorphic const in codegen");
845 return bx.cx().const_usize(n);
846 }
847 let cg_value = self.codegen_place(bx, place.as_ref());
849 cg_value.len(bx.cx())
850 }
851
852 fn codegen_place_to_pointer(
854 &mut self,
855 bx: &mut Bx,
856 place: mir::Place<'tcx>,
857 mk_ptr_ty: impl FnOnce(TyCtxt<'tcx>, Ty<'tcx>) -> Ty<'tcx>,
858 ) -> OperandRef<'tcx, Bx::Value> {
859 let cg_place = self.codegen_place(bx, place.as_ref());
860 let val = cg_place.val.address();
861
862 let ty = cg_place.layout.ty;
863 assert!(
864 if bx.cx().tcx().type_has_metadata(ty, bx.cx().typing_env()) {
865 matches!(val, OperandValue::Pair(..))
866 } else {
867 matches!(val, OperandValue::Immediate(..))
868 },
869 "Address of place was unexpectedly {val:?} for pointee type {ty:?}",
870 );
871
872 OperandRef { val, layout: self.cx.layout_of(mk_ptr_ty(self.cx.tcx(), ty)) }
873 }
874
875 fn codegen_scalar_binop(
876 &mut self,
877 bx: &mut Bx,
878 op: mir::BinOp,
879 lhs: Bx::Value,
880 rhs: Bx::Value,
881 lhs_ty: Ty<'tcx>,
882 rhs_ty: Ty<'tcx>,
883 ) -> Bx::Value {
884 let is_float = lhs_ty.is_floating_point();
885 let is_signed = lhs_ty.is_signed();
886 match op {
887 mir::BinOp::Add => {
888 if is_float {
889 bx.fadd(lhs, rhs)
890 } else {
891 bx.add(lhs, rhs)
892 }
893 }
894 mir::BinOp::AddUnchecked => {
895 if is_signed {
896 bx.unchecked_sadd(lhs, rhs)
897 } else {
898 bx.unchecked_uadd(lhs, rhs)
899 }
900 }
901 mir::BinOp::Sub => {
902 if is_float {
903 bx.fsub(lhs, rhs)
904 } else {
905 bx.sub(lhs, rhs)
906 }
907 }
908 mir::BinOp::SubUnchecked => {
909 if is_signed {
910 bx.unchecked_ssub(lhs, rhs)
911 } else {
912 bx.unchecked_usub(lhs, rhs)
913 }
914 }
915 mir::BinOp::Mul => {
916 if is_float {
917 bx.fmul(lhs, rhs)
918 } else {
919 bx.mul(lhs, rhs)
920 }
921 }
922 mir::BinOp::MulUnchecked => {
923 if is_signed {
924 bx.unchecked_smul(lhs, rhs)
925 } else {
926 bx.unchecked_umul(lhs, rhs)
927 }
928 }
929 mir::BinOp::Div => {
930 if is_float {
931 bx.fdiv(lhs, rhs)
932 } else if is_signed {
933 bx.sdiv(lhs, rhs)
934 } else {
935 bx.udiv(lhs, rhs)
936 }
937 }
938 mir::BinOp::Rem => {
939 if is_float {
940 bx.frem(lhs, rhs)
941 } else if is_signed {
942 bx.srem(lhs, rhs)
943 } else {
944 bx.urem(lhs, rhs)
945 }
946 }
947 mir::BinOp::BitOr => bx.or(lhs, rhs),
948 mir::BinOp::BitAnd => bx.and(lhs, rhs),
949 mir::BinOp::BitXor => bx.xor(lhs, rhs),
950 mir::BinOp::Offset => {
951 let pointee_type = lhs_ty
952 .builtin_deref(true)
953 .unwrap_or_else(|| bug!("deref of non-pointer {:?}", lhs_ty));
954 let pointee_layout = bx.cx().layout_of(pointee_type);
955 if pointee_layout.is_zst() {
956 lhs
959 } else {
960 let llty = bx.cx().backend_type(pointee_layout);
961 if !rhs_ty.is_signed() {
962 bx.inbounds_nuw_gep(llty, lhs, &[rhs])
963 } else {
964 bx.inbounds_gep(llty, lhs, &[rhs])
965 }
966 }
967 }
968 mir::BinOp::Shl | mir::BinOp::ShlUnchecked => {
969 let rhs = base::build_shift_expr_rhs(bx, lhs, rhs, op == mir::BinOp::ShlUnchecked);
970 bx.shl(lhs, rhs)
971 }
972 mir::BinOp::Shr | mir::BinOp::ShrUnchecked => {
973 let rhs = base::build_shift_expr_rhs(bx, lhs, rhs, op == mir::BinOp::ShrUnchecked);
974 if is_signed { bx.ashr(lhs, rhs) } else { bx.lshr(lhs, rhs) }
975 }
976 mir::BinOp::Ne
977 | mir::BinOp::Lt
978 | mir::BinOp::Gt
979 | mir::BinOp::Eq
980 | mir::BinOp::Le
981 | mir::BinOp::Ge => {
982 if is_float {
983 bx.fcmp(base::bin_op_to_fcmp_predicate(op), lhs, rhs)
984 } else {
985 bx.icmp(base::bin_op_to_icmp_predicate(op, is_signed), lhs, rhs)
986 }
987 }
988 mir::BinOp::Cmp => {
989 use std::cmp::Ordering;
990 assert!(!is_float);
991 let pred = |op| base::bin_op_to_icmp_predicate(op, is_signed);
992 if bx.cx().tcx().sess.opts.optimize == OptLevel::No {
993 let is_gt = bx.icmp(pred(mir::BinOp::Gt), lhs, rhs);
1000 let gtext = bx.zext(is_gt, bx.type_i8());
1001 let is_lt = bx.icmp(pred(mir::BinOp::Lt), lhs, rhs);
1002 let ltext = bx.zext(is_lt, bx.type_i8());
1003 bx.unchecked_ssub(gtext, ltext)
1004 } else {
1005 let is_lt = bx.icmp(pred(mir::BinOp::Lt), lhs, rhs);
1008 let is_ne = bx.icmp(pred(mir::BinOp::Ne), lhs, rhs);
1009 let ge = bx.select(
1010 is_ne,
1011 bx.cx().const_i8(Ordering::Greater as i8),
1012 bx.cx().const_i8(Ordering::Equal as i8),
1013 );
1014 bx.select(is_lt, bx.cx().const_i8(Ordering::Less as i8), ge)
1015 }
1016 }
1017 mir::BinOp::AddWithOverflow
1018 | mir::BinOp::SubWithOverflow
1019 | mir::BinOp::MulWithOverflow => {
1020 bug!("{op:?} needs to return a pair, so call codegen_scalar_checked_binop instead")
1021 }
1022 }
1023 }
1024
1025 fn codegen_wide_ptr_binop(
1026 &mut self,
1027 bx: &mut Bx,
1028 op: mir::BinOp,
1029 lhs_addr: Bx::Value,
1030 lhs_extra: Bx::Value,
1031 rhs_addr: Bx::Value,
1032 rhs_extra: Bx::Value,
1033 _input_ty: Ty<'tcx>,
1034 ) -> Bx::Value {
1035 match op {
1036 mir::BinOp::Eq => {
1037 let lhs = bx.icmp(IntPredicate::IntEQ, lhs_addr, rhs_addr);
1038 let rhs = bx.icmp(IntPredicate::IntEQ, lhs_extra, rhs_extra);
1039 bx.and(lhs, rhs)
1040 }
1041 mir::BinOp::Ne => {
1042 let lhs = bx.icmp(IntPredicate::IntNE, lhs_addr, rhs_addr);
1043 let rhs = bx.icmp(IntPredicate::IntNE, lhs_extra, rhs_extra);
1044 bx.or(lhs, rhs)
1045 }
1046 mir::BinOp::Le | mir::BinOp::Lt | mir::BinOp::Ge | mir::BinOp::Gt => {
1047 let (op, strict_op) = match op {
1049 mir::BinOp::Lt => (IntPredicate::IntULT, IntPredicate::IntULT),
1050 mir::BinOp::Le => (IntPredicate::IntULE, IntPredicate::IntULT),
1051 mir::BinOp::Gt => (IntPredicate::IntUGT, IntPredicate::IntUGT),
1052 mir::BinOp::Ge => (IntPredicate::IntUGE, IntPredicate::IntUGT),
1053 _ => bug!(),
1054 };
1055 let lhs = bx.icmp(strict_op, lhs_addr, rhs_addr);
1056 let and_lhs = bx.icmp(IntPredicate::IntEQ, lhs_addr, rhs_addr);
1057 let and_rhs = bx.icmp(op, lhs_extra, rhs_extra);
1058 let rhs = bx.and(and_lhs, and_rhs);
1059 bx.or(lhs, rhs)
1060 }
1061 _ => {
1062 bug!("unexpected wide ptr binop");
1063 }
1064 }
1065 }
1066
1067 fn codegen_scalar_checked_binop(
1068 &mut self,
1069 bx: &mut Bx,
1070 op: mir::BinOp,
1071 lhs: Bx::Value,
1072 rhs: Bx::Value,
1073 input_ty: Ty<'tcx>,
1074 ) -> OperandValue<Bx::Value> {
1075 let (val, of) = match op {
1076 mir::BinOp::Add | mir::BinOp::Sub | mir::BinOp::Mul => {
1078 let oop = match op {
1079 mir::BinOp::Add => OverflowOp::Add,
1080 mir::BinOp::Sub => OverflowOp::Sub,
1081 mir::BinOp::Mul => OverflowOp::Mul,
1082 _ => unreachable!(),
1083 };
1084 bx.checked_binop(oop, input_ty, lhs, rhs)
1085 }
1086 _ => bug!("Operator `{:?}` is not a checkable operator", op),
1087 };
1088
1089 OperandValue::Pair(val, of)
1090 }
1091
1092 pub(crate) fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>, span: Span) -> bool {
1093 match *rvalue {
1094 mir::Rvalue::Cast(mir::CastKind::Transmute, ref operand, cast_ty) => {
1095 let operand_ty = operand.ty(self.mir, self.cx.tcx());
1096 let cast_layout = self.cx.layout_of(self.monomorphize(cast_ty));
1097 let operand_layout = self.cx.layout_of(self.monomorphize(operand_ty));
1098
1099 match (self.value_kind(operand_layout), self.value_kind(cast_layout)) {
1100 (OperandValueKind::Ref, _) => true,
1102
1103 (OperandValueKind::ZeroSized, OperandValueKind::ZeroSized) => true,
1105
1106 (OperandValueKind::ZeroSized, _) | (_, OperandValueKind::ZeroSized) => false,
1108
1109 (OperandValueKind::Immediate(..) | OperandValueKind::Pair(..), OperandValueKind::Ref) => false,
1111
1112 (OperandValueKind::Immediate(a), OperandValueKind::Immediate(b)) =>
1115 a.size(self.cx) == b.size(self.cx),
1116 (OperandValueKind::Pair(a0, a1), OperandValueKind::Pair(b0, b1)) =>
1117 a0.size(self.cx) == b0.size(self.cx) && a1.size(self.cx) == b1.size(self.cx),
1118
1119 (OperandValueKind::Immediate(..), OperandValueKind::Pair(..)) |
1122 (OperandValueKind::Pair(..), OperandValueKind::Immediate(..)) => false,
1123 }
1124 }
1125 mir::Rvalue::Ref(..) |
1126 mir::Rvalue::CopyForDeref(..) |
1127 mir::Rvalue::RawPtr(..) |
1128 mir::Rvalue::Len(..) |
1129 mir::Rvalue::Cast(..) | mir::Rvalue::ShallowInitBox(..) | mir::Rvalue::BinaryOp(..) |
1132 mir::Rvalue::UnaryOp(..) |
1133 mir::Rvalue::Discriminant(..) |
1134 mir::Rvalue::NullaryOp(..) |
1135 mir::Rvalue::ThreadLocalRef(_) |
1136 mir::Rvalue::Use(..) |
1137 mir::Rvalue::WrapUnsafeBinder(..) => true,
1139 mir::Rvalue::Repeat(..) => false,
1142 mir::Rvalue::Aggregate(ref kind, _) => {
1143 let allowed_kind = match **kind {
1144 mir::AggregateKind::RawPtr(..) => true,
1146 mir::AggregateKind::Array(..) => false,
1147 mir::AggregateKind::Tuple => true,
1148 mir::AggregateKind::Adt(def_id, ..) => {
1149 let adt_def = self.cx.tcx().adt_def(def_id);
1150 adt_def.is_struct() && !adt_def.repr().simd()
1151 }
1152 mir::AggregateKind::Closure(..) => true,
1153 mir::AggregateKind::Coroutine(..) | mir::AggregateKind::CoroutineClosure(..) => false,
1155 };
1156 allowed_kind && {
1157 let ty = rvalue.ty(self.mir, self.cx.tcx());
1158 let ty = self.monomorphize(ty);
1159 let layout = self.cx.spanned_layout_of(ty, span);
1160 !self.cx.is_backend_ref(layout)
1161 }
1162 }
1163 }
1164
1165 }
1167
1168 fn value_kind(&self, layout: TyAndLayout<'tcx>) -> OperandValueKind {
1170 if layout.is_zst() {
1171 OperandValueKind::ZeroSized
1172 } else if self.cx.is_backend_immediate(layout) {
1173 assert!(!self.cx.is_backend_scalar_pair(layout));
1174 OperandValueKind::Immediate(match layout.backend_repr {
1175 abi::BackendRepr::Scalar(s) => s,
1176 abi::BackendRepr::SimdVector { element, .. } => element,
1177 x => span_bug!(self.mir.span, "Couldn't translate {x:?} as backend immediate"),
1178 })
1179 } else if self.cx.is_backend_scalar_pair(layout) {
1180 let abi::BackendRepr::ScalarPair(s1, s2) = layout.backend_repr else {
1181 span_bug!(
1182 self.mir.span,
1183 "Couldn't translate {:?} as backend scalar pair",
1184 layout.backend_repr,
1185 );
1186 };
1187 OperandValueKind::Pair(s1, s2)
1188 } else {
1189 OperandValueKind::Ref
1190 }
1191 }
1192}
1193
1194#[derive(Debug, Copy, Clone)]
1197enum OperandValueKind {
1198 Ref,
1199 Immediate(abi::Scalar),
1200 Pair(abi::Scalar, abi::Scalar),
1201 ZeroSized,
1202}
1203
1204impl OperandValueKind {
1205 fn scalars(self) -> Option<ArrayVec<abi::Scalar, 2>> {
1206 Some(match self {
1207 OperandValueKind::ZeroSized => ArrayVec::new(),
1208 OperandValueKind::Immediate(a) => ArrayVec::from_iter([a]),
1209 OperandValueKind::Pair(a, b) => [a, b].into(),
1210 OperandValueKind::Ref => return None,
1211 })
1212 }
1213}