2 use crate::mir
::operand
::OperandRef
;
5 use rustc_middle
::mir
::interpret
::ErrorHandled
;
6 use rustc_middle
::ty
::layout
::HasTyCtxt
;
7 use rustc_middle
::ty
::{self, Ty}
;
8 use rustc_target
::abi
::Abi
;
10 use super::FunctionCx
;
12 impl<'a
, 'tcx
, Bx
: BuilderMethods
<'a
, 'tcx
>> FunctionCx
<'a
, 'tcx
, Bx
> {
13 pub fn eval_mir_constant_to_operand(
16 constant
: &mir
::ConstOperand
<'tcx
>,
17 ) -> OperandRef
<'tcx
, Bx
::Value
> {
18 let val
= self.eval_mir_constant(constant
);
19 let ty
= self.monomorphize(constant
.ty());
20 OperandRef
::from_const(bx
, val
, ty
)
23 pub fn eval_mir_constant(&self, constant
: &mir
::ConstOperand
<'tcx
>) -> mir
::ConstValue
<'tcx
> {
24 // `MirUsedCollector` visited all constants before codegen began, so if we got here there
25 // can be no more constants that fail to evaluate.
26 self.monomorphize(constant
.const_
)
27 .eval(self.cx
.tcx(), ty
::ParamEnv
::reveal_all(), Some(constant
.span
))
28 .expect("erroneous constant not captured by required_consts")
31 /// This is a convenience helper for `simd_shuffle_indices`. It has the precondition
32 /// that the given `constant` is an `Const::Unevaluated` and must be convertible to
33 /// a `ValTree`. If you want a more general version of this, talk to `wg-const-eval` on zulip.
35 /// Note that this function is cursed, since usually MIR consts should not be evaluated to valtrees!
36 pub fn eval_unevaluated_mir_constant_to_valtree(
38 constant
: &mir
::ConstOperand
<'tcx
>,
39 ) -> Result
<Option
<ty
::ValTree
<'tcx
>>, ErrorHandled
> {
40 let uv
= match self.monomorphize(constant
.const_
) {
41 mir
::Const
::Unevaluated(uv
, _
) => uv
.shrink(),
42 mir
::Const
::Ty(c
) => match c
.kind() {
43 // A constant that came from a const generic but was then used as an argument to old-style
44 // simd_shuffle (passing as argument instead of as a generic param).
45 rustc_type_ir
::ConstKind
::Value(valtree
) => return Ok(Some(valtree
)),
46 other
=> span_bug
!(constant
.span
, "{other:#?}"),
48 // We should never encounter `Const::Val` unless MIR opts (like const prop) evaluate
49 // a constant and write that value back into `Operand`s. This could happen, but is unlikely.
50 // Also: all users of `simd_shuffle` are on unstable and already need to take a lot of care
51 // around intrinsics. For an issue to happen here, it would require a macro expanding to a
52 // `simd_shuffle` call without wrapping the constant argument in a `const {}` block, but
53 // the user pass through arbitrary expressions.
54 // FIXME(oli-obk): replace the magic const generic argument of `simd_shuffle` with a real
55 // const generic, and get rid of this entire function.
56 other
=> span_bug
!(constant
.span
, "{other:#?}"),
58 let uv
= self.monomorphize(uv
);
59 self.cx
.tcx().const_eval_resolve_for_typeck(
60 ty
::ParamEnv
::reveal_all(),
66 /// process constant containing SIMD shuffle indices
67 pub fn simd_shuffle_indices(
70 constant
: &mir
::ConstOperand
<'tcx
>,
71 ) -> (Bx
::Value
, Ty
<'tcx
>) {
72 let ty
= self.monomorphize(constant
.ty());
74 .eval_unevaluated_mir_constant_to_valtree(constant
)
78 let field_ty
= ty
.builtin_index().unwrap();
79 let values
: Vec
<_
> = val
83 if let Some(prim
) = field
.try_to_scalar() {
84 let layout
= bx
.layout_of(field_ty
);
85 let Abi
::Scalar(scalar
) = layout
.abi
else {
86 bug
!("from_const: invalid ByVal layout: {:#?}", layout
);
88 bx
.scalar_to_backend(prim
, scalar
, bx
.immediate_backend_type(layout
))
90 bug
!("simd shuffle field {:?}", field
)
94 bx
.const_struct(&values
, false)
97 bx
.tcx().sess
.emit_err(errors
::ShuffleIndicesEvaluation { span: constant.span }
);
98 // We've errored, so we don't have to produce working code.
99 let llty
= bx
.backend_type(bx
.layout_of(ty
));