diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index d296ee3b42ce1..9ed7fe292fcd5 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -103,6 +103,7 @@ pub struct CodegenCx<'ll, 'tcx> { pub rust_try_fn: Cell>, intrinsics: RefCell>, + pub is_constant_intrinsics: RefCell, (&'ll Type, &'ll Value)>>, /// A counter that is used for generating local symbol names local_gen_sym_counter: Cell, @@ -442,6 +443,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { eh_catch_typeinfo: Cell::new(None), rust_try_fn: Cell::new(None), intrinsics: Default::default(), + is_constant_intrinsics: Default::default(), local_gen_sym_counter: Cell::new(0), renamed_statics: Default::default(), } diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index cf9cf1b70aaa7..3e4d5ddae08b9 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -363,6 +363,15 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { return; } + sym::optimized_to_const => { + let ty = substs.type_at(0); + let ptr = args[0].immediate(); + let llty = self.layout_of(ty).llvm_type(self); + let align = self.align_of(ty); + let load = self.load(llty, ptr, align); + is_constant_intrinsic(self, ty, llty, load) + } + _ if name.as_str().starts_with("simd_") => { match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) { Ok(llval) => llval, @@ -415,6 +424,30 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { } } +fn is_constant_intrinsic<'ll, 'tcx>( + bx: &mut Builder<'_, 'll, 'tcx>, + ty: Ty<'tcx>, + llty: &'ll Type, + value: &'ll Value, +) -> &'ll Value { + let cached = bx.is_constant_intrinsics.borrow().get(&ty).copied(); + let (fn_ty, f) = match cached { + Some(v) => v, + None => { + let fn_ty = bx.type_func(&[llty], bx.type_i1()); + let type_id = bx.tcx.type_id_hash(ty); + let f = bx.declare_cfn( + &format!("llvm.is.constant.{}", type_id), + llvm::UnnamedAddr::No, + fn_ty, + ); + bx.is_constant_intrinsics.borrow_mut().insert(ty, (fn_ty, f)); + (fn_ty, f) + } + }; + bx.call(fn_ty, f, &[value], None) +} + fn try_intrinsic<'ll>( bx: &mut Builder<'_, 'll, '_>, try_func: &'ll Value, diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 3cc237faf695c..dc4e0ed051b5c 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -451,6 +451,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let result = self.raw_eq_intrinsic(&args[0], &args[1])?; self.write_scalar(result, dest)?; } + sym::optimized_to_const => { + self.write_scalar(Scalar::from_bool(true), dest)?; + } _ => return Ok(false), } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index e3ce8105a8b47..d470db2a3858f 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -986,6 +986,7 @@ symbols! { opt_out_copy, optimize, optimize_attribute, + optimized_to_const, optin_builtin_traits, option, option_env, diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs index 0dd8ee88ca2ad..9904306449b79 100644 --- a/compiler/rustc_typeck/src/check/intrinsic.rs +++ b/compiler/rustc_typeck/src/check/intrinsic.rs @@ -102,6 +102,7 @@ pub fn intrinsic_operation_unsafety(intrinsic: Symbol) -> hir::Unsafety { | sym::type_name | sym::forget | sym::black_box + | sym::optimized_to_const | sym::variant_count => hir::Unsafety::Normal, _ => hir::Unsafety::Unsafe, } @@ -397,6 +398,13 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { sym::const_eval_select => (4, vec![param(0), param(1), param(2)], param(3)), + sym::optimized_to_const => { + let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0) }; + let param_ty = + tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)), param(0)); + (1, vec![param_ty], tcx.types.bool) + } + other => { tcx.sess.emit_err(UnrecognizedIntrinsicFunction { span: it.span, name: other }); return; diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index bddbe2b9b0df1..6956e25ab390c 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1972,6 +1972,12 @@ extern "rust-intrinsic" { /// [`std::hint::black_box`]: crate::hint::black_box #[rustc_const_unstable(feature = "const_black_box", issue = "none")] pub fn black_box(dummy: T) -> T; + + /// Determines if the supplied value is a constant or has been folded to a constant during + /// optimization. + #[cfg(not(bootstrap))] + #[rustc_const_unstable(feature = "core_intrinsics", issue = "none")] + pub fn optimized_to_const(value: &T) -> bool; } // Some functions are defined here because they accidentally got made