@@ -45,6 +45,14 @@ pub enum OperandValue<V> {
45
45
/// as returned by [`LayoutTypeMethods::scalar_pair_element_backend_type`]
46
46
/// with `immediate: true`.
47
47
Pair(V, V),
48
+ /// A value taking no bytes, and which therefore needs no LLVM value at all.
49
+ ///
50
+ /// If you ever need a `V` to pass to something, get a fresh poison value
51
+ /// from [`ConstMethods::const_poison`].
52
+ ///
53
+ /// An `OperandValue` *must* be this variant for any type for which
54
+ /// `is_zst` on its `Layout` returns `true`.
55
+ ZeroSized,
48
56
}
49
57
50
58
/// An `OperandRef` is an "SSA" reference to a Rust value, along with
@@ -71,15 +79,9 @@ impl<V: CodegenObject> fmt::Debug for OperandRef<'_, V> {
71
79
}
72
80
73
81
impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
74
- pub fn new_zst<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
75
- bx: &mut Bx,
76
- layout: TyAndLayout<'tcx>,
77
- ) -> OperandRef<'tcx, V> {
82
+ pub fn zero_sized(layout: TyAndLayout<'tcx>) -> OperandRef<'tcx, V> {
78
83
assert!(layout.is_zst());
79
- OperandRef {
80
- val: OperandValue::Immediate(bx.const_poison(bx.immediate_backend_type(layout))),
81
- layout,
82
- }
84
+ OperandRef { val: OperandValue::ZeroSized, layout }
83
85
}
84
86
85
87
pub fn from_const<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
@@ -97,7 +99,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
97
99
let llval = bx.scalar_to_backend(x, scalar, bx.immediate_backend_type(layout));
98
100
OperandValue::Immediate(llval)
99
101
}
100
- ConstValue::ZeroSized => return OperandRef::new_zst(bx, layout),
102
+ ConstValue::ZeroSized => return OperandRef::zero_sized( layout),
101
103
ConstValue::Slice { data, start, end } => {
102
104
let Abi::ScalarPair(a_scalar, _) = layout.abi else {
103
105
bug!("from_const: invalid ScalarPair layout: {:#?}", layout);
@@ -178,7 +180,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
178
180
);
179
181
OperandRef { val: OperandValue::Pair(a_val, b_val), layout }
180
182
}
181
- _ if layout.is_zst() => OperandRef::new_zst(bx, layout),
183
+ _ if layout.is_zst() => OperandRef::zero_sized( layout),
182
184
_ => {
183
185
// Neither a scalar nor scalar pair. Load from a place
184
186
let init = bx.const_data_from_alloc(alloc);
@@ -216,6 +218,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
216
218
OperandValue::Immediate(llptr) => (llptr, None),
217
219
OperandValue::Pair(llptr, llextra) => (llptr, Some(llextra)),
218
220
OperandValue::Ref(..) => bug!("Deref of by-Ref operand {:?}", self),
221
+ OperandValue::ZeroSized => bug!("Deref of ZST operand {:?}", self),
219
222
};
220
223
let layout = cx.layout_of(projected_ty);
221
224
PlaceRef { llval: llptr, llextra, layout, align: layout.align.abi }
@@ -273,9 +276,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
273
276
274
277
let mut val = match (self.val, self.layout.abi) {
275
278
// If the field is ZST, it has no data.
276
- _ if field.is_zst() => {
277
- return OperandRef::new_zst(bx, field);
278
- }
279
+ _ if field.is_zst() => OperandValue::ZeroSized,
279
280
280
281
// Newtype of a scalar, scalar pair or vector.
281
282
(OperandValue::Immediate(_) | OperandValue::Pair(..), _)
@@ -306,6 +307,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
306
307
};
307
308
308
309
match (&mut val, field.abi) {
310
+ (OperandValue::ZeroSized, _) => {}
309
311
(
310
312
OperandValue::Immediate(llval),
311
313
Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. },
@@ -359,16 +361,18 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
359
361
impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
360
362
/// Returns an `OperandValue` that's generally UB to use in any way.
361
363
///
362
- /// Depending on the `layout`, returns an `Immediate` or `Pair` containing
363
- /// poison value(s), or a `Ref` containing a poison pointer.
364
+ /// Depending on the `layout`, returns `ZeroSized` for ZSTs, an `Immediate` or
365
+ /// `Pair` containing poison value(s), or a `Ref` containing a poison pointer.
364
366
///
365
367
/// Supports sized types only.
366
368
pub fn poison<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
367
369
bx: &mut Bx,
368
370
layout: TyAndLayout<'tcx>,
369
371
) -> OperandValue<V> {
370
372
assert!(layout.is_sized());
371
- if bx.cx().is_backend_immediate(layout) {
373
+ if layout.is_zst() {
374
+ OperandValue::ZeroSized
375
+ } else if bx.cx().is_backend_immediate(layout) {
372
376
let ibty = bx.cx().immediate_backend_type(layout);
373
377
OperandValue::Immediate(bx.const_poison(ibty))
374
378
} else if bx.cx().is_backend_scalar_pair(layout) {
@@ -421,12 +425,11 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
421
425
flags: MemFlags,
422
426
) {
423
427
debug!("OperandRef::store: operand={:?}, dest={:?}", self, dest);
424
- // Avoid generating stores of zero-sized values, because the only way to have a zero-sized
425
- // value is through `undef`, and store itself is useless.
426
- if dest.layout.is_zst() {
427
- return;
428
- }
429
428
match self {
429
+ OperandValue::ZeroSized => {
430
+ // Avoid generating stores of zero-sized values, because the only way to have a zero-sized
431
+ // value is through `undef`/`poison`, and the store itself is useless.
432
+ }
430
433
OperandValue::Ref(r, None, source_align) => {
431
434
if flags.contains(MemFlags::NONTEMPORAL) {
432
435
// HACK(nox): This is inefficient but there is no nontemporal memcpy.
@@ -527,7 +530,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
527
530
// checks in `codegen_consume` and `extract_field`.
528
531
let elem = o.layout.field(bx.cx(), 0);
529
532
if elem.is_zst() {
530
- o = OperandRef::new_zst(bx, elem);
533
+ o = OperandRef::zero_sized( elem);
531
534
} else {
532
535
return None;
533
536
}
@@ -561,7 +564,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
561
564
562
565
// ZSTs don't require any actual memory access.
563
566
if layout.is_zst() {
564
- return OperandRef::new_zst(bx, layout);
567
+ return OperandRef::zero_sized( layout);
565
568
}
566
569
567
570
if let Some(o) = self.maybe_codegen_consume_direct(bx, place_ref) {
0 commit comments