2019-05-17 02:20:14 +01:00
|
|
|
use super::place::PlaceRef;
|
|
|
|
use super::{FunctionCx, LocalRef};
|
2016-06-07 17:28:36 +03:00
|
|
|
|
2023-12-02 12:25:01 +01:00
|
|
|
use crate::size_of_val;
|
2019-02-09 23:31:47 +09:00
|
|
|
use crate::traits::*;
|
|
|
|
use crate::MemFlags;
|
2018-08-07 17:14:40 +02:00
|
|
|
|
2023-09-16 09:36:22 +02:00
|
|
|
use rustc_middle::mir::interpret::{alloc_range, Pointer, Scalar};
|
|
|
|
use rustc_middle::mir::{self, ConstValue};
|
2021-08-30 17:38:27 +03:00
|
|
|
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
|
2020-03-29 16:41:09 +02:00
|
|
|
use rustc_middle::ty::Ty;
|
2023-05-19 15:48:43 +00:00
|
|
|
use rustc_target::abi::{self, Abi, Align, Size};
|
2016-02-18 19:49:45 +02:00
|
|
|
|
2019-05-17 02:20:14 +01:00
|
|
|
use std::fmt;
|
2015-10-21 17:42:25 -04:00
|
|
|
|
2015-11-13 00:12:50 +02:00
|
|
|
/// The representation of a Rust value. The enum variant is in fact
|
|
|
|
/// uniquely determined by the value's type, but is kept as a
|
2015-11-10 22:05:11 +02:00
|
|
|
/// safety check.
|
2018-07-10 13:28:39 +03:00
|
|
|
#[derive(Copy, Clone, Debug)]
|
2018-08-02 17:48:44 +03:00
|
|
|
pub enum OperandValue<V> {
|
2015-11-10 22:05:11 +02:00
|
|
|
/// A reference to the actual operand. The data is guaranteed
|
|
|
|
/// to be valid for the operand's lifetime.
|
2018-08-03 23:50:13 +09:00
|
|
|
/// The second value, if any, is the extra data (vtable or length)
|
|
|
|
/// which indicates that it refers to an unsized rvalue.
|
2023-04-01 01:46:36 -07:00
|
|
|
///
|
|
|
|
/// An `OperandValue` has this variant for types which are neither
|
|
|
|
/// `Immediate` nor `Pair`s. The backend value in this variant must be a
|
|
|
|
/// pointer to the *non*-immediate backend type. That pointee type is the
|
|
|
|
/// one returned by [`LayoutTypeMethods::backend_type`].
|
2018-09-09 01:16:45 +03:00
|
|
|
Ref(V, Option<V>, Align),
|
2023-04-01 01:46:36 -07:00
|
|
|
/// A single LLVM immediate value.
|
|
|
|
///
|
|
|
|
/// An `OperandValue` *must* be this variant for any type for which
|
|
|
|
/// [`LayoutTypeMethods::is_backend_immediate`] returns `true`.
|
|
|
|
/// The backend value in this variant must be the *immediate* backend type,
|
|
|
|
/// as returned by [`LayoutTypeMethods::immediate_backend_type`].
|
2018-08-02 17:48:44 +03:00
|
|
|
Immediate(V),
|
2016-05-25 11:55:44 +03:00
|
|
|
/// A pair of immediate LLVM values. Used by fat pointers too.
|
2023-04-01 01:46:36 -07:00
|
|
|
///
|
|
|
|
/// An `OperandValue` *must* be this variant for any type for which
|
|
|
|
/// [`LayoutTypeMethods::is_backend_scalar_pair`] returns `true`.
|
|
|
|
/// The backend values in this variant must be the *immediate* backend types,
|
|
|
|
/// as returned by [`LayoutTypeMethods::scalar_pair_element_backend_type`]
|
|
|
|
/// with `immediate: true`.
|
2018-08-02 17:48:44 +03:00
|
|
|
Pair(V, V),
|
2023-05-07 03:00:41 -07:00
|
|
|
/// A value taking no bytes, and which therefore needs no LLVM value at all.
|
|
|
|
///
|
|
|
|
/// If you ever need a `V` to pass to something, get a fresh poison value
|
|
|
|
/// from [`ConstMethods::const_poison`].
|
|
|
|
///
|
|
|
|
/// An `OperandValue` *must* be this variant for any type for which
|
2023-08-27 18:12:34 +02:00
|
|
|
/// `is_zst` on its `Layout` returns `true`. Note however that
|
|
|
|
/// these values can still require alignment.
|
2023-05-07 03:00:41 -07:00
|
|
|
ZeroSized,
|
2017-09-20 18:17:23 +03:00
|
|
|
}
|
|
|
|
|
2015-11-13 00:12:50 +02:00
|
|
|
/// An `OperandRef` is an "SSA" reference to a Rust value, along with
|
|
|
|
/// its type.
|
|
|
|
///
|
|
|
|
/// NOTE: unless you know a value's type exactly, you should not
|
|
|
|
/// generate LLVM opcodes acting on it and instead act via methods,
|
2017-06-25 12:41:24 +03:00
|
|
|
/// to avoid nasty edge cases. In particular, using `Builder::store`
|
|
|
|
/// directly is sure to cause problems -- use `OperandRef::store`
|
2016-02-01 11:04:46 +01:00
|
|
|
/// instead.
|
2015-11-03 06:35:09 -05:00
|
|
|
#[derive(Copy, Clone)]
|
2018-08-02 17:48:44 +03:00
|
|
|
pub struct OperandRef<'tcx, V> {
|
2022-11-27 11:15:06 +00:00
|
|
|
/// The value.
|
2018-08-02 17:48:44 +03:00
|
|
|
pub val: OperandValue<V>,
|
2015-10-21 17:42:25 -04:00
|
|
|
|
2022-11-27 11:15:06 +00:00
|
|
|
/// The layout of value, based on its Rust type.
|
2020-03-04 14:50:21 +00:00
|
|
|
pub layout: TyAndLayout<'tcx>,
|
2015-10-21 17:42:25 -04:00
|
|
|
}
|
|
|
|
|
2021-12-13 21:52:35 -05:00
|
|
|
impl<V: CodegenObject> fmt::Debug for OperandRef<'_, V> {
|
2019-02-25 08:52:46 +01:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2017-09-20 18:17:23 +03:00
|
|
|
write!(f, "OperandRef({:?} @ {:?})", self.val, self.layout)
|
2015-11-10 22:05:11 +02:00
|
|
|
}
|
2016-02-18 19:49:45 +02:00
|
|
|
}
|
|
|
|
|
2019-06-14 19:39:39 +03:00
|
|
|
impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
|
2023-05-07 03:00:41 -07:00
|
|
|
pub fn zero_sized(layout: TyAndLayout<'tcx>) -> OperandRef<'tcx, V> {
|
2017-09-20 18:17:23 +03:00
|
|
|
assert!(layout.is_zst());
|
2023-05-07 03:00:41 -07:00
|
|
|
OperandRef { val: OperandValue::ZeroSized, layout }
|
2017-03-08 20:03:04 +02:00
|
|
|
}
|
|
|
|
|
2018-09-20 15:47:22 +02:00
|
|
|
pub fn from_const<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
|
2018-10-05 15:08:49 +02:00
|
|
|
bx: &mut Bx,
|
2023-09-16 09:36:22 +02:00
|
|
|
val: mir::ConstValue<'tcx>,
|
2020-02-15 12:57:46 +13:00
|
|
|
ty: Ty<'tcx>,
|
2019-04-22 13:53:52 +02:00
|
|
|
) -> Self {
|
2020-02-15 12:57:46 +13:00
|
|
|
let layout = bx.layout_of(ty);
|
2018-01-16 09:31:48 +01:00
|
|
|
|
2020-02-15 12:57:46 +13:00
|
|
|
let val = match val {
|
2018-05-20 23:46:30 +02:00
|
|
|
ConstValue::Scalar(x) => {
|
2022-02-19 00:48:49 +01:00
|
|
|
let Abi::Scalar(scalar) = layout.abi else {
|
|
|
|
bug!("from_const: invalid ByVal layout: {:#?}", layout);
|
2018-01-16 09:31:48 +01:00
|
|
|
};
|
2019-03-01 15:03:48 +01:00
|
|
|
let llval = bx.scalar_to_backend(x, scalar, bx.immediate_backend_type(layout));
|
2018-01-16 09:31:48 +01:00
|
|
|
OperandValue::Immediate(llval)
|
|
|
|
}
|
2023-05-07 03:00:41 -07:00
|
|
|
ConstValue::ZeroSized => return OperandRef::zero_sized(layout),
|
2023-09-15 15:59:47 +02:00
|
|
|
ConstValue::Slice { data, meta } => {
|
2022-02-19 00:48:49 +01:00
|
|
|
let Abi::ScalarPair(a_scalar, _) = layout.abi else {
|
|
|
|
bug!("from_const: invalid ScalarPair layout: {:#?}", layout);
|
2018-01-16 09:31:48 +01:00
|
|
|
};
|
2021-07-12 20:29:05 +02:00
|
|
|
let a = Scalar::from_pointer(
|
2023-11-25 18:41:53 +01:00
|
|
|
Pointer::new(bx.tcx().reserve_and_set_memory_alloc(data).into(), Size::ZERO),
|
2021-07-12 20:29:05 +02:00
|
|
|
&bx.tcx(),
|
|
|
|
);
|
2019-03-01 15:03:48 +01:00
|
|
|
let a_llval = bx.scalar_to_backend(
|
2018-01-16 09:31:48 +01:00
|
|
|
a,
|
|
|
|
a_scalar,
|
2019-03-01 15:03:48 +01:00
|
|
|
bx.scalar_pair_element_backend_type(layout, 0, true),
|
2018-01-16 09:31:48 +01:00
|
|
|
);
|
2023-09-15 15:59:47 +02:00
|
|
|
let b_llval = bx.const_usize(meta);
|
2018-01-16 09:31:48 +01:00
|
|
|
OperandValue::Pair(a_llval, b_llval)
|
|
|
|
}
|
2023-09-12 07:49:25 +02:00
|
|
|
ConstValue::Indirect { alloc_id, offset } => {
|
2023-09-11 20:01:48 +02:00
|
|
|
let alloc = bx.tcx().global_alloc(alloc_id).unwrap_memory();
|
2023-05-19 15:48:43 +00:00
|
|
|
return Self::from_const_alloc(bx, layout, alloc, offset);
|
2018-01-16 09:31:48 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-04-22 13:53:52 +02:00
|
|
|
OperandRef { val, layout }
|
2018-01-16 09:31:48 +01:00
|
|
|
}
|
|
|
|
|
2023-05-19 15:48:43 +00:00
|
|
|
fn from_const_alloc<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
|
|
|
|
bx: &mut Bx,
|
|
|
|
layout: TyAndLayout<'tcx>,
|
|
|
|
alloc: rustc_middle::mir::interpret::ConstAllocation<'tcx>,
|
|
|
|
offset: Size,
|
|
|
|
) -> Self {
|
|
|
|
let alloc_align = alloc.inner().align;
|
2023-12-17 22:56:42 +00:00
|
|
|
assert!(alloc_align >= layout.align.abi);
|
2023-05-19 15:48:43 +00:00
|
|
|
|
|
|
|
let read_scalar = |start, size, s: abi::Scalar, ty| {
|
2023-09-23 09:35:44 +00:00
|
|
|
match alloc.0.read_scalar(
|
|
|
|
bx,
|
|
|
|
alloc_range(start, size),
|
|
|
|
/*read_provenance*/ matches!(s.primitive(), abi::Pointer(_)),
|
|
|
|
) {
|
|
|
|
Ok(val) => bx.scalar_to_backend(val, s, ty),
|
|
|
|
Err(_) => bx.const_poison(ty),
|
|
|
|
}
|
2023-05-19 15:48:43 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// It may seem like all types with `Scalar` or `ScalarPair` ABI are fair game at this point.
|
|
|
|
// However, `MaybeUninit<u64>` is considered a `Scalar` as far as its layout is concerned --
|
|
|
|
// and yet cannot be represented by an interpreter `Scalar`, since we have to handle the
|
|
|
|
// case where some of the bytes are initialized and others are not. So, we need an extra
|
|
|
|
// check that walks over the type of `mplace` to make sure it is truly correct to treat this
|
|
|
|
// like a `Scalar` (or `ScalarPair`).
|
|
|
|
match layout.abi {
|
|
|
|
Abi::Scalar(s @ abi::Scalar::Initialized { .. }) => {
|
|
|
|
let size = s.size(bx);
|
|
|
|
assert_eq!(size, layout.size, "abi::Scalar size does not match layout size");
|
2023-12-09 15:53:41 -05:00
|
|
|
let val = read_scalar(offset, size, s, bx.immediate_backend_type(layout));
|
2023-05-19 15:48:43 +00:00
|
|
|
OperandRef { val: OperandValue::Immediate(val), layout }
|
|
|
|
}
|
|
|
|
Abi::ScalarPair(
|
|
|
|
a @ abi::Scalar::Initialized { .. },
|
|
|
|
b @ abi::Scalar::Initialized { .. },
|
|
|
|
) => {
|
|
|
|
let (a_size, b_size) = (a.size(bx), b.size(bx));
|
2023-09-23 09:35:44 +00:00
|
|
|
let b_offset = (offset + a_size).align_to(b.align(bx).abi);
|
2023-05-19 15:48:43 +00:00
|
|
|
assert!(b_offset.bytes() > 0);
|
|
|
|
let a_val = read_scalar(
|
2023-09-23 09:35:44 +00:00
|
|
|
offset,
|
2023-05-19 15:48:43 +00:00
|
|
|
a_size,
|
|
|
|
a,
|
|
|
|
bx.scalar_pair_element_backend_type(layout, 0, true),
|
|
|
|
);
|
|
|
|
let b_val = read_scalar(
|
|
|
|
b_offset,
|
|
|
|
b_size,
|
|
|
|
b,
|
|
|
|
bx.scalar_pair_element_backend_type(layout, 1, true),
|
|
|
|
);
|
|
|
|
OperandRef { val: OperandValue::Pair(a_val, b_val), layout }
|
|
|
|
}
|
2023-05-07 03:00:41 -07:00
|
|
|
_ if layout.is_zst() => OperandRef::zero_sized(layout),
|
2023-05-19 15:48:43 +00:00
|
|
|
_ => {
|
|
|
|
// Neither a scalar nor scalar pair. Load from a place
|
2023-09-12 08:42:36 +02:00
|
|
|
// FIXME: should we cache `const_data_from_alloc` to avoid repeating this for the
|
|
|
|
// same `ConstAllocation`?
|
2023-05-19 15:48:43 +00:00
|
|
|
let init = bx.const_data_from_alloc(alloc);
|
|
|
|
let base_addr = bx.static_addr_of(init, alloc_align, None);
|
|
|
|
|
|
|
|
let llval = bx.const_ptr_byte_offset(base_addr, offset);
|
|
|
|
bx.load_operand(PlaceRef::new_sized(llval, layout))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-18 19:49:45 +02:00
|
|
|
/// Asserts that this operand refers to a scalar and returns
|
|
|
|
/// a reference to its value.
|
2018-09-20 15:47:22 +02:00
|
|
|
pub fn immediate(self) -> V {
|
2016-02-18 19:49:45 +02:00
|
|
|
match self.val {
|
|
|
|
OperandValue::Immediate(s) => s,
|
2016-12-31 04:55:29 +02:00
|
|
|
_ => bug!("not immediate: {:?}", self),
|
2016-02-18 19:49:45 +02:00
|
|
|
}
|
|
|
|
}
|
2016-05-25 11:55:44 +03:00
|
|
|
|
2019-03-01 15:03:48 +01:00
|
|
|
pub fn deref<Cx: LayoutTypeMethods<'tcx>>(self, cx: &Cx) -> PlaceRef<'tcx, V> {
|
2022-05-18 21:49:46 -07:00
|
|
|
if self.layout.ty.is_box() {
|
2024-03-05 11:32:03 +01:00
|
|
|
// Derefer should have removed all Box derefs
|
2022-05-18 21:49:46 -07:00
|
|
|
bug!("dereferencing {:?} in codegen", self.layout.ty);
|
2022-05-13 21:53:03 -07:00
|
|
|
}
|
|
|
|
|
2018-01-28 23:29:40 +02:00
|
|
|
let projected_ty = self
|
|
|
|
.layout
|
|
|
|
.ty
|
|
|
|
.builtin_deref(true)
|
2017-05-18 18:43:52 +03:00
|
|
|
.unwrap_or_else(|| bug!("deref of non-pointer {:?}", self))
|
|
|
|
.ty;
|
2022-05-13 21:53:03 -07:00
|
|
|
|
2017-03-14 01:08:21 +02:00
|
|
|
let (llptr, llextra) = match self.val {
|
2018-07-10 13:28:39 +03:00
|
|
|
OperandValue::Immediate(llptr) => (llptr, None),
|
2022-05-13 21:53:03 -07:00
|
|
|
OperandValue::Pair(llptr, llextra) => (llptr, Some(llextra)),
|
2018-08-03 23:50:13 +09:00
|
|
|
OperandValue::Ref(..) => bug!("Deref of by-Ref operand {:?}", self),
|
2023-05-07 03:00:41 -07:00
|
|
|
OperandValue::ZeroSized => bug!("Deref of ZST operand {:?}", self),
|
2017-03-14 01:08:21 +02:00
|
|
|
};
|
2018-01-05 07:04:08 +02:00
|
|
|
let layout = cx.layout_of(projected_ty);
|
2018-09-09 01:16:45 +03:00
|
|
|
PlaceRef { llval: llptr, llextra, layout, align: layout.align.abi }
|
2017-03-14 01:08:21 +02:00
|
|
|
}
|
|
|
|
|
2017-10-05 04:22:23 +03:00
|
|
|
/// If this operand is a `Pair`, we return an aggregate with the two values.
|
|
|
|
/// For other cases, see `immediate`.
|
2018-09-20 15:47:22 +02:00
|
|
|
pub fn immediate_or_packed_pair<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
|
|
|
|
self,
|
2018-10-05 15:08:49 +02:00
|
|
|
bx: &mut Bx,
|
2018-09-20 15:47:22 +02:00
|
|
|
) -> V {
|
2016-05-25 11:55:44 +03:00
|
|
|
if let OperandValue::Pair(a, b) = self.val {
|
Separate immediate and in-memory ScalarPair representation
Currently, we assume that ScalarPair is always represented using
a two-element struct, both as an immediate value and when stored
in memory.
This currently works fairly well, but runs into problems with
https://github.com/rust-lang/rust/pull/116672, where a ScalarPair
involving an i128 type can no longer be represented as a two-element
struct in memory. For example, the tuple `(i32, i128)` needs to be
represented in-memory as `{ i32, [3 x i32], i128 }` to satisfy
alignment requirement. Using `{ i32, i128 }` instead will result in
the second element being stored at the wrong offset (prior to
LLVM 18).
Resolve this issue by no longer requiring that the immediate and
in-memory type for ScalarPair are the same. The in-memory type
will now look the same as for normal struct types (and will include
padding filler and similar), while the immediate type stays a
simple two-element struct type. This also means that booleans in
immediate ScalarPair are now represented as i1 rather than i8,
just like we do everywhere else.
The core change here is to llvm_type (which now treats ScalarPair
as a normal struct) and immediate_llvm_type (which returns the
two-element struct that llvm_type used to produce). The rest is
fixing things up to no longer assume these are the same. In
particular, this switches places that try to get pointers to the
ScalarPair elements to use byte-geps instead of struct-geps.
2023-12-15 12:14:39 +01:00
|
|
|
let llty = bx.cx().immediate_backend_type(self.layout);
|
2017-10-05 04:22:23 +03:00
|
|
|
debug!("Operand::immediate_or_packed_pair: packing {:?} into {:?}", self, llty);
|
2017-09-15 22:42:23 +03:00
|
|
|
// Reconstruct the immediate aggregate.
|
2023-03-16 14:56:02 +01:00
|
|
|
let mut llpair = bx.cx().const_poison(llty);
|
Separate immediate and in-memory ScalarPair representation
Currently, we assume that ScalarPair is always represented using
a two-element struct, both as an immediate value and when stored
in memory.
This currently works fairly well, but runs into problems with
https://github.com/rust-lang/rust/pull/116672, where a ScalarPair
involving an i128 type can no longer be represented as a two-element
struct in memory. For example, the tuple `(i32, i128)` needs to be
represented in-memory as `{ i32, [3 x i32], i128 }` to satisfy
alignment requirement. Using `{ i32, i128 }` instead will result in
the second element being stored at the wrong offset (prior to
LLVM 18).
Resolve this issue by no longer requiring that the immediate and
in-memory type for ScalarPair are the same. The in-memory type
will now look the same as for normal struct types (and will include
padding filler and similar), while the immediate type stays a
simple two-element struct type. This also means that booleans in
immediate ScalarPair are now represented as i1 rather than i8,
just like we do everywhere else.
The core change here is to llvm_type (which now treats ScalarPair
as a normal struct) and immediate_llvm_type (which returns the
two-element struct that llvm_type used to produce). The rest is
fixing things up to no longer assume these are the same. In
particular, this switches places that try to get pointers to the
ScalarPair elements to use byte-geps instead of struct-geps.
2023-12-15 12:14:39 +01:00
|
|
|
llpair = bx.insert_value(llpair, a, 0);
|
|
|
|
llpair = bx.insert_value(llpair, b, 1);
|
2017-10-05 04:22:23 +03:00
|
|
|
llpair
|
|
|
|
} else {
|
|
|
|
self.immediate()
|
2016-05-25 11:55:44 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-05 04:22:23 +03:00
|
|
|
/// If the type is a pair, we return a `Pair`, otherwise, an `Immediate`.
|
2018-09-20 15:47:22 +02:00
|
|
|
pub fn from_immediate_or_packed_pair<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
|
2018-10-05 15:08:49 +02:00
|
|
|
bx: &mut Bx,
|
2018-09-20 15:47:22 +02:00
|
|
|
llval: V,
|
2020-03-04 14:50:21 +00:00
|
|
|
layout: TyAndLayout<'tcx>,
|
2018-09-20 15:47:22 +02:00
|
|
|
) -> Self {
|
Separate immediate and in-memory ScalarPair representation
Currently, we assume that ScalarPair is always represented using
a two-element struct, both as an immediate value and when stored
in memory.
This currently works fairly well, but runs into problems with
https://github.com/rust-lang/rust/pull/116672, where a ScalarPair
involving an i128 type can no longer be represented as a two-element
struct in memory. For example, the tuple `(i32, i128)` needs to be
represented in-memory as `{ i32, [3 x i32], i128 }` to satisfy
alignment requirement. Using `{ i32, i128 }` instead will result in
the second element being stored at the wrong offset (prior to
LLVM 18).
Resolve this issue by no longer requiring that the immediate and
in-memory type for ScalarPair are the same. The in-memory type
will now look the same as for normal struct types (and will include
padding filler and similar), while the immediate type stays a
simple two-element struct type. This also means that booleans in
immediate ScalarPair are now represented as i1 rather than i8,
just like we do everywhere else.
The core change here is to llvm_type (which now treats ScalarPair
as a normal struct) and immediate_llvm_type (which returns the
two-element struct that llvm_type used to produce). The rest is
fixing things up to no longer assume these are the same. In
particular, this switches places that try to get pointers to the
ScalarPair elements to use byte-geps instead of struct-geps.
2023-12-15 12:14:39 +01:00
|
|
|
let val = if let Abi::ScalarPair(..) = layout.abi {
|
2017-10-05 04:22:23 +03:00
|
|
|
debug!("Operand::from_immediate_or_packed_pair: unpacking {:?} @ {:?}", llval, layout);
|
2016-06-20 23:55:14 +03:00
|
|
|
|
2017-10-05 04:22:23 +03:00
|
|
|
// Deconstruct the immediate aggregate.
|
2018-10-05 15:08:49 +02:00
|
|
|
let a_llval = bx.extract_value(llval, 0);
|
|
|
|
let b_llval = bx.extract_value(llval, 1);
|
Store scalar pair bools as i8 in memory
We represent `bool` as `i1` in a `ScalarPair`, unlike other aggregates,
to optimize IR for checked operators and the like. With this patch, we
still do so when the pair is an immediate value, but we use the `i8`
memory type when the value is loaded or stored as an LLVM aggregate.
So `(bool, bool)` looks like an `{ i1, i1 }` immediate, but `{ i8, i8 }`
in memory. When a pair is a direct function argument, `PassMode::Pair`,
it is still passed using the immediate `i1` type, but as a return value
it will use the `i8` memory type. Also, `bool`-like` enum tags will now
use scalar pairs when possible, where they were previously excluded due
to optimization issues.
2018-06-15 15:47:54 -07:00
|
|
|
OperandValue::Pair(a_llval, b_llval)
|
2017-10-05 04:22:23 +03:00
|
|
|
} else {
|
|
|
|
OperandValue::Immediate(llval)
|
|
|
|
};
|
|
|
|
OperandRef { val, layout }
|
2016-05-25 11:55:44 +03:00
|
|
|
}
|
2017-10-09 19:56:41 +03:00
|
|
|
|
2018-09-20 15:47:22 +02:00
|
|
|
pub fn extract_field<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
|
2018-08-02 17:48:44 +03:00
|
|
|
&self,
|
2018-10-05 15:08:49 +02:00
|
|
|
bx: &mut Bx,
|
2018-09-20 15:47:22 +02:00
|
|
|
i: usize,
|
|
|
|
) -> Self {
|
2018-08-28 17:50:57 +02:00
|
|
|
let field = self.layout.field(bx.cx(), i);
|
2017-10-09 19:56:41 +03:00
|
|
|
let offset = self.layout.fields.offset(i);
|
|
|
|
|
2021-08-29 11:06:55 +02:00
|
|
|
let mut val = match (self.val, self.layout.abi) {
|
2018-05-10 19:24:06 +03:00
|
|
|
// If the field is ZST, it has no data.
|
2023-05-07 03:00:41 -07:00
|
|
|
_ if field.is_zst() => OperandValue::ZeroSized,
|
2017-10-09 19:56:41 +03:00
|
|
|
|
2017-12-13 01:57:56 +02:00
|
|
|
// Newtype of a scalar, scalar pair or vector.
|
2020-04-16 17:38:52 -07:00
|
|
|
(OperandValue::Immediate(_) | OperandValue::Pair(..), _)
|
2017-10-09 19:56:41 +03:00
|
|
|
if field.size == self.layout.size =>
|
|
|
|
{
|
|
|
|
assert_eq!(offset.bytes(), 0);
|
|
|
|
self.val
|
|
|
|
}
|
|
|
|
|
|
|
|
// Extract a scalar component from a pair.
|
2021-08-29 11:06:55 +02:00
|
|
|
(OperandValue::Pair(a_llval, b_llval), Abi::ScalarPair(a, b)) => {
|
2017-10-09 19:56:41 +03:00
|
|
|
if offset.bytes() == 0 {
|
2022-03-03 12:02:12 +00:00
|
|
|
assert_eq!(field.size, a.size(bx.cx()));
|
2017-10-09 19:56:41 +03:00
|
|
|
OperandValue::Immediate(a_llval)
|
|
|
|
} else {
|
2022-03-03 12:02:12 +00:00
|
|
|
assert_eq!(offset, a.size(bx.cx()).align_to(b.align(bx.cx()).abi));
|
|
|
|
assert_eq!(field.size, b.size(bx.cx()));
|
2017-10-09 19:56:41 +03:00
|
|
|
OperandValue::Immediate(b_llval)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// `#[repr(simd)]` types are also immediate.
|
2021-08-29 11:06:55 +02:00
|
|
|
(OperandValue::Immediate(llval), Abi::Vector { .. }) => {
|
2018-09-06 11:57:42 -07:00
|
|
|
OperandValue::Immediate(bx.extract_element(llval, bx.cx().const_usize(i as u64)))
|
2017-10-09 19:56:41 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
_ => bug!("OperandRef::extract_field({:?}): not applicable", self),
|
|
|
|
};
|
|
|
|
|
2021-08-29 11:06:55 +02:00
|
|
|
match (&mut val, field.abi) {
|
2023-05-07 03:00:41 -07:00
|
|
|
(OperandValue::ZeroSized, _) => {}
|
2022-12-15 23:18:25 -08:00
|
|
|
(
|
|
|
|
OperandValue::Immediate(llval),
|
|
|
|
Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. },
|
|
|
|
) => {
|
2020-08-29 18:10:01 +02:00
|
|
|
// Bools in union fields needs to be truncated.
|
|
|
|
*llval = bx.to_immediate(*llval, field);
|
2017-10-09 19:56:41 +03:00
|
|
|
}
|
2020-08-29 18:10:01 +02:00
|
|
|
(OperandValue::Pair(a, b), Abi::ScalarPair(a_abi, b_abi)) => {
|
2020-08-30 13:38:47 +02:00
|
|
|
// Bools in union fields needs to be truncated.
|
2020-08-29 18:10:01 +02:00
|
|
|
*a = bx.to_immediate_scalar(*a, a_abi);
|
|
|
|
*b = bx.to_immediate_scalar(*b, b_abi);
|
2017-10-09 19:56:41 +03:00
|
|
|
}
|
2022-12-15 23:18:25 -08:00
|
|
|
// Newtype vector of array, e.g. #[repr(simd)] struct S([i32; 4]);
|
|
|
|
(OperandValue::Immediate(llval), Abi::Aggregate { sized: true }) => {
|
|
|
|
assert!(matches!(self.layout.abi, Abi::Vector { .. }));
|
|
|
|
|
|
|
|
let llfield_ty = bx.cx().backend_type(field);
|
|
|
|
|
|
|
|
// Can't bitcast an aggregate, so round trip through memory.
|
2023-07-28 20:24:33 -04:00
|
|
|
let llptr = bx.alloca(llfield_ty, field.align.abi);
|
2022-12-15 23:18:25 -08:00
|
|
|
bx.store(*llval, llptr, field.align.abi);
|
2023-07-28 20:24:33 -04:00
|
|
|
*llval = bx.load(llfield_ty, llptr, field.align.abi);
|
2022-12-15 23:18:25 -08:00
|
|
|
}
|
|
|
|
(OperandValue::Immediate(_), Abi::Uninhabited | Abi::Aggregate { sized: false }) => {
|
|
|
|
bug!()
|
|
|
|
}
|
2020-08-29 18:10:01 +02:00
|
|
|
(OperandValue::Pair(..), _) => bug!(),
|
|
|
|
(OperandValue::Ref(..), _) => bug!(),
|
2017-10-09 19:56:41 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
OperandRef { val, layout: field }
|
|
|
|
}
|
2017-09-20 18:17:23 +03:00
|
|
|
}
|
2016-02-11 18:30:34 +02:00
|
|
|
|
2019-06-14 19:39:39 +03:00
|
|
|
impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
|
2023-04-06 13:53:10 -07:00
|
|
|
/// Returns an `OperandValue` that's generally UB to use in any way.
|
|
|
|
///
|
2023-05-07 03:00:41 -07:00
|
|
|
/// Depending on the `layout`, returns `ZeroSized` for ZSTs, an `Immediate` or
|
|
|
|
/// `Pair` containing poison value(s), or a `Ref` containing a poison pointer.
|
2023-04-06 13:53:10 -07:00
|
|
|
///
|
|
|
|
/// Supports sized types only.
|
|
|
|
pub fn poison<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
|
|
|
|
bx: &mut Bx,
|
|
|
|
layout: TyAndLayout<'tcx>,
|
|
|
|
) -> OperandValue<V> {
|
|
|
|
assert!(layout.is_sized());
|
2023-05-07 03:00:41 -07:00
|
|
|
if layout.is_zst() {
|
|
|
|
OperandValue::ZeroSized
|
|
|
|
} else if bx.cx().is_backend_immediate(layout) {
|
2023-04-06 13:53:10 -07:00
|
|
|
let ibty = bx.cx().immediate_backend_type(layout);
|
|
|
|
OperandValue::Immediate(bx.const_poison(ibty))
|
|
|
|
} else if bx.cx().is_backend_scalar_pair(layout) {
|
|
|
|
let ibty0 = bx.cx().scalar_pair_element_backend_type(layout, 0, true);
|
|
|
|
let ibty1 = bx.cx().scalar_pair_element_backend_type(layout, 1, true);
|
|
|
|
OperandValue::Pair(bx.const_poison(ibty0), bx.const_poison(ibty1))
|
|
|
|
} else {
|
2023-07-28 20:24:33 -04:00
|
|
|
let ptr = bx.cx().type_ptr();
|
|
|
|
OperandValue::Ref(bx.const_poison(ptr), None, layout.align.abi)
|
2023-04-06 13:53:10 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-14 17:48:57 +02:00
|
|
|
pub fn store<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
|
|
|
|
self,
|
2018-10-05 15:08:49 +02:00
|
|
|
bx: &mut Bx,
|
2018-09-20 15:47:22 +02:00
|
|
|
dest: PlaceRef<'tcx, V>,
|
2018-09-14 17:48:57 +02:00
|
|
|
) {
|
2018-05-11 12:26:32 +02:00
|
|
|
self.store_with_flags(bx, dest, MemFlags::empty());
|
2018-05-11 11:26:51 +02:00
|
|
|
}
|
|
|
|
|
2018-09-20 15:47:22 +02:00
|
|
|
pub fn volatile_store<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
|
2018-08-07 17:14:40 +02:00
|
|
|
self,
|
2018-10-05 15:08:49 +02:00
|
|
|
bx: &mut Bx,
|
2018-09-20 15:47:22 +02:00
|
|
|
dest: PlaceRef<'tcx, V>,
|
2018-08-07 17:14:40 +02:00
|
|
|
) {
|
2018-05-11 12:26:32 +02:00
|
|
|
self.store_with_flags(bx, dest, MemFlags::VOLATILE);
|
2018-05-11 11:26:51 +02:00
|
|
|
}
|
|
|
|
|
2018-09-20 15:47:22 +02:00
|
|
|
pub fn unaligned_volatile_store<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
|
2018-08-02 17:48:44 +03:00
|
|
|
self,
|
2018-10-05 15:08:49 +02:00
|
|
|
bx: &mut Bx,
|
2018-09-20 15:47:22 +02:00
|
|
|
dest: PlaceRef<'tcx, V>,
|
2018-08-02 17:48:44 +03:00
|
|
|
) {
|
2018-07-14 23:28:39 +01:00
|
|
|
self.store_with_flags(bx, dest, MemFlags::VOLATILE | MemFlags::UNALIGNED);
|
|
|
|
}
|
|
|
|
|
2018-09-20 15:47:22 +02:00
|
|
|
pub fn nontemporal_store<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
|
2018-08-07 17:14:40 +02:00
|
|
|
self,
|
2018-10-05 15:08:49 +02:00
|
|
|
bx: &mut Bx,
|
2018-09-20 15:47:22 +02:00
|
|
|
dest: PlaceRef<'tcx, V>,
|
2018-08-07 17:14:40 +02:00
|
|
|
) {
|
2018-05-11 12:26:32 +02:00
|
|
|
self.store_with_flags(bx, dest, MemFlags::NONTEMPORAL);
|
|
|
|
}
|
|
|
|
|
2024-03-29 00:00:24 -07:00
|
|
|
pub(crate) fn store_with_flags<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
|
2018-07-17 18:26:58 +03:00
|
|
|
self,
|
2018-10-05 15:08:49 +02:00
|
|
|
bx: &mut Bx,
|
2018-09-20 15:47:22 +02:00
|
|
|
dest: PlaceRef<'tcx, V>,
|
2018-07-17 18:26:58 +03:00
|
|
|
flags: MemFlags,
|
|
|
|
) {
|
2017-06-25 12:41:24 +03:00
|
|
|
debug!("OperandRef::store: operand={:?}, dest={:?}", self, dest);
|
2017-09-20 18:17:23 +03:00
|
|
|
match self {
|
2023-05-07 03:00:41 -07:00
|
|
|
OperandValue::ZeroSized => {
|
|
|
|
// Avoid generating stores of zero-sized values, because the only way to have a zero-sized
|
|
|
|
// value is through `undef`/`poison`, and the store itself is useless.
|
|
|
|
}
|
2024-03-29 00:00:24 -07:00
|
|
|
OperandValue::Ref(llval, llextra @ None, source_align) => {
|
2023-12-02 22:25:14 +01:00
|
|
|
assert!(dest.layout.is_sized(), "cannot directly store unsized values");
|
2024-03-29 00:00:24 -07:00
|
|
|
let source_place =
|
|
|
|
PlaceRef { llval, llextra, align: source_align, layout: dest.layout };
|
|
|
|
bx.typed_place_copy_with_flags(dest, source_place, flags);
|
2018-05-11 12:26:32 +02:00
|
|
|
}
|
2018-08-03 23:50:13 +09:00
|
|
|
OperandValue::Ref(_, Some(_), _) => {
|
2018-05-29 00:12:55 +09:00
|
|
|
bug!("cannot directly store unsized values");
|
|
|
|
}
|
2017-06-25 12:41:24 +03:00
|
|
|
OperandValue::Immediate(s) => {
|
2020-08-29 18:10:01 +02:00
|
|
|
let val = bx.from_immediate(s);
|
2018-05-11 12:26:32 +02:00
|
|
|
bx.store_with_flags(val, dest.llval, dest.align, flags);
|
2017-06-25 12:41:24 +03:00
|
|
|
}
|
|
|
|
OperandValue::Pair(a, b) => {
|
2022-02-19 00:48:49 +01:00
|
|
|
let Abi::ScalarPair(a_scalar, b_scalar) = dest.layout.abi else {
|
|
|
|
bug!("store_with_flags: invalid ScalarPair layout: {:#?}", dest.layout);
|
2018-11-28 00:25:40 +01:00
|
|
|
};
|
2022-03-03 12:02:12 +00:00
|
|
|
let b_offset = a_scalar.size(bx).align_to(b_scalar.align(bx).abi);
|
2018-11-28 00:25:40 +01:00
|
|
|
|
2020-08-29 18:10:01 +02:00
|
|
|
let val = bx.from_immediate(a);
|
2018-11-28 00:25:40 +01:00
|
|
|
let align = dest.align;
|
Separate immediate and in-memory ScalarPair representation
Currently, we assume that ScalarPair is always represented using
a two-element struct, both as an immediate value and when stored
in memory.
This currently works fairly well, but runs into problems with
https://github.com/rust-lang/rust/pull/116672, where a ScalarPair
involving an i128 type can no longer be represented as a two-element
struct in memory. For example, the tuple `(i32, i128)` needs to be
represented in-memory as `{ i32, [3 x i32], i128 }` to satisfy
alignment requirement. Using `{ i32, i128 }` instead will result in
the second element being stored at the wrong offset (prior to
LLVM 18).
Resolve this issue by no longer requiring that the immediate and
in-memory type for ScalarPair are the same. The in-memory type
will now look the same as for normal struct types (and will include
padding filler and similar), while the immediate type stays a
simple two-element struct type. This also means that booleans in
immediate ScalarPair are now represented as i1 rather than i8,
just like we do everywhere else.
The core change here is to llvm_type (which now treats ScalarPair
as a normal struct) and immediate_llvm_type (which returns the
two-element struct that llvm_type used to produce). The rest is
fixing things up to no longer assume these are the same. In
particular, this switches places that try to get pointers to the
ScalarPair elements to use byte-geps instead of struct-geps.
2023-12-15 12:14:39 +01:00
|
|
|
bx.store_with_flags(val, dest.llval, align, flags);
|
2018-11-28 00:25:40 +01:00
|
|
|
|
2024-02-24 02:01:41 -05:00
|
|
|
let llptr = bx.inbounds_ptradd(dest.llval, bx.const_usize(b_offset.bytes()));
|
2020-08-29 18:10:01 +02:00
|
|
|
let val = bx.from_immediate(b);
|
2018-11-28 00:25:40 +01:00
|
|
|
let align = dest.align.restrict_for_offset(b_offset);
|
|
|
|
bx.store_with_flags(val, llptr, align, flags);
|
2017-06-25 12:41:24 +03:00
|
|
|
}
|
|
|
|
}
|
2016-02-11 18:30:34 +02:00
|
|
|
}
|
2019-05-17 02:20:14 +01:00
|
|
|
|
2018-09-20 15:47:22 +02:00
|
|
|
pub fn store_unsized<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
|
2018-08-02 17:48:44 +03:00
|
|
|
self,
|
2018-10-05 15:08:49 +02:00
|
|
|
bx: &mut Bx,
|
2018-09-20 15:47:22 +02:00
|
|
|
indirect_dest: PlaceRef<'tcx, V>,
|
2018-08-02 17:48:44 +03:00
|
|
|
) {
|
2018-05-29 00:12:55 +09:00
|
|
|
debug!("OperandRef::store_unsized: operand={:?}, indirect_dest={:?}", self, indirect_dest);
|
|
|
|
// `indirect_dest` must have `*mut T` type. We extract `T` out of it.
|
|
|
|
let unsized_ty = indirect_dest
|
|
|
|
.layout
|
|
|
|
.ty
|
|
|
|
.builtin_deref(true)
|
|
|
|
.unwrap_or_else(|| bug!("indirect_dest has non-pointer type: {:?}", indirect_dest))
|
|
|
|
.ty;
|
2019-12-22 17:42:04 -05:00
|
|
|
|
2021-10-16 03:45:14 +02:00
|
|
|
let OperandValue::Ref(llptr, Some(llextra), _) = self else {
|
2023-12-02 12:25:01 +01:00
|
|
|
bug!("store_unsized called with a sized value (or with an extern type)")
|
2018-05-29 00:12:55 +09:00
|
|
|
};
|
|
|
|
|
2023-05-08 00:00:00 +00:00
|
|
|
// Allocate an appropriate region on the stack, and copy the value into it. Since alloca
|
|
|
|
// doesn't support dynamic alignment, we allocate an extra align - 1 bytes, and align the
|
|
|
|
// pointer manually.
|
2023-12-02 12:25:01 +01:00
|
|
|
let (size, align) = size_of_val::size_and_align_of_dst(bx, unsized_ty, Some(llextra));
|
2023-05-08 00:00:00 +00:00
|
|
|
let one = bx.const_usize(1);
|
|
|
|
let align_minus_1 = bx.sub(align, one);
|
|
|
|
let size_extra = bx.add(size, align_minus_1);
|
|
|
|
let min_align = Align::ONE;
|
|
|
|
let alloca = bx.byte_array_alloca(size_extra, min_align);
|
|
|
|
let address = bx.ptrtoint(alloca, bx.type_isize());
|
|
|
|
let neg_address = bx.neg(address);
|
|
|
|
let offset = bx.and(neg_address, align_minus_1);
|
2024-02-24 02:01:41 -05:00
|
|
|
let dst = bx.inbounds_ptradd(alloca, offset);
|
2023-05-08 00:00:00 +00:00
|
|
|
bx.memcpy(dst, min_align, llptr, min_align, size, MemFlags::empty());
|
2018-05-29 00:12:55 +09:00
|
|
|
|
|
|
|
// Store the allocated region and the extra to the indirect place.
|
2023-05-08 00:00:00 +00:00
|
|
|
let indirect_operand = OperandValue::Pair(dst, llextra);
|
2018-08-07 17:14:40 +02:00
|
|
|
indirect_operand.store(bx, indirect_dest);
|
2018-05-29 00:12:55 +09:00
|
|
|
}
|
2017-06-25 12:41:24 +03:00
|
|
|
}
|
2016-02-11 18:30:34 +02:00
|
|
|
|
2019-06-14 19:39:39 +03:00
|
|
|
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
2018-09-20 15:47:22 +02:00
|
|
|
fn maybe_codegen_consume_direct(
|
|
|
|
&mut self,
|
2018-10-05 15:08:49 +02:00
|
|
|
bx: &mut Bx,
|
2020-03-04 18:25:03 -03:00
|
|
|
place_ref: mir::PlaceRef<'tcx>,
|
2018-09-20 15:47:22 +02:00
|
|
|
) -> Option<OperandRef<'tcx, Bx::Value>> {
|
2019-07-02 20:29:45 +02:00
|
|
|
debug!("maybe_codegen_consume_direct(place_ref={:?})", place_ref);
|
2016-06-09 18:13:16 +03:00
|
|
|
|
2020-01-14 02:10:05 -03:00
|
|
|
match self.locals[place_ref.local] {
|
2023-03-24 20:36:59 -07:00
|
|
|
LocalRef::Operand(mut o) => {
|
2019-12-11 16:50:03 -03:00
|
|
|
// Moves out of scalar and scalar pair fields are trivial.
|
|
|
|
for elem in place_ref.projection.iter() {
|
|
|
|
match elem {
|
|
|
|
mir::ProjectionElem::Field(ref f, _) => {
|
|
|
|
o = o.extract_field(bx, f.index());
|
|
|
|
}
|
|
|
|
mir::ProjectionElem::Index(_)
|
|
|
|
| mir::ProjectionElem::ConstantIndex { .. } => {
|
|
|
|
// ZSTs don't require any actual memory access.
|
|
|
|
// FIXME(eddyb) deduplicate this with the identical
|
|
|
|
// checks in `codegen_consume` and `extract_field`.
|
|
|
|
let elem = o.layout.field(bx.cx(), 0);
|
|
|
|
if elem.is_zst() {
|
2023-05-07 03:00:41 -07:00
|
|
|
o = OperandRef::zero_sized(elem);
|
2019-12-11 16:50:03 -03:00
|
|
|
} else {
|
|
|
|
return None;
|
2019-05-22 05:51:50 +02:00
|
|
|
}
|
|
|
|
}
|
2019-12-11 16:50:03 -03:00
|
|
|
_ => return None,
|
2019-12-11 10:39:24 -03:00
|
|
|
}
|
2016-05-25 11:58:08 +03:00
|
|
|
}
|
2019-12-11 16:50:03 -03:00
|
|
|
|
|
|
|
Some(o)
|
|
|
|
}
|
2023-03-24 20:36:59 -07:00
|
|
|
LocalRef::PendingOperand => {
|
2019-12-11 16:50:03 -03:00
|
|
|
bug!("use of {:?} before def", place_ref);
|
|
|
|
}
|
|
|
|
LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => {
|
|
|
|
// watch out for locals that do not have an
|
|
|
|
// alloca; they are handled somewhat differently
|
|
|
|
None
|
2016-06-09 18:13:16 +03:00
|
|
|
}
|
2019-07-30 00:07:28 +02:00
|
|
|
}
|
2017-10-09 00:38:10 +03:00
|
|
|
}
|
|
|
|
|
2018-09-20 15:47:22 +02:00
|
|
|
pub fn codegen_consume(
|
|
|
|
&mut self,
|
2018-10-05 15:08:49 +02:00
|
|
|
bx: &mut Bx,
|
2020-03-04 18:25:03 -03:00
|
|
|
place_ref: mir::PlaceRef<'tcx>,
|
2018-09-20 15:47:22 +02:00
|
|
|
) -> OperandRef<'tcx, Bx::Value> {
|
2019-07-02 20:29:45 +02:00
|
|
|
debug!("codegen_consume(place_ref={:?})", place_ref);
|
2017-10-09 00:38:10 +03:00
|
|
|
|
2019-07-02 20:29:45 +02:00
|
|
|
let ty = self.monomorphized_place_ty(place_ref);
|
2018-08-28 17:50:57 +02:00
|
|
|
let layout = bx.cx().layout_of(ty);
|
2017-10-09 00:38:10 +03:00
|
|
|
|
|
|
|
// ZSTs don't require any actual memory access.
|
|
|
|
if layout.is_zst() {
|
2023-05-07 03:00:41 -07:00
|
|
|
return OperandRef::zero_sized(layout);
|
2017-10-09 00:38:10 +03:00
|
|
|
}
|
|
|
|
|
2019-07-02 20:29:45 +02:00
|
|
|
if let Some(o) = self.maybe_codegen_consume_direct(bx, place_ref) {
|
2017-10-09 00:38:10 +03:00
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
2017-12-01 14:39:51 +02:00
|
|
|
// for most places, to consume them we just load them
|
2016-06-09 18:13:16 +03:00
|
|
|
// out from their home
|
2019-07-02 20:29:45 +02:00
|
|
|
let place = self.codegen_place(bx, place_ref);
|
2018-10-05 15:08:49 +02:00
|
|
|
bx.load_operand(place)
|
2016-06-09 18:13:16 +03:00
|
|
|
}
|
2016-05-25 11:58:08 +03:00
|
|
|
|
2018-09-20 15:47:22 +02:00
|
|
|
pub fn codegen_operand(
|
|
|
|
&mut self,
|
2018-10-05 15:08:49 +02:00
|
|
|
bx: &mut Bx,
|
2018-09-20 15:47:22 +02:00
|
|
|
operand: &mir::Operand<'tcx>,
|
|
|
|
) -> OperandRef<'tcx, Bx::Value> {
|
2018-05-08 16:10:16 +03:00
|
|
|
debug!("codegen_operand(operand={:?})", operand);
|
2016-06-09 18:13:16 +03:00
|
|
|
|
|
|
|
match *operand {
|
2017-12-01 14:39:51 +02:00
|
|
|
mir::Operand::Copy(ref place) | mir::Operand::Move(ref place) => {
|
2020-01-14 01:51:59 -03:00
|
|
|
self.codegen_consume(bx, place.as_ref())
|
2015-10-21 17:42:25 -04:00
|
|
|
}
|
|
|
|
|
2023-09-11 09:52:45 +02:00
|
|
|
mir::Operand::Constant(ref constant) => self.eval_mir_constant_to_operand(bx, constant),
|
2015-10-21 17:42:25 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|