Skip to content

Commit ac58f2e

Browse files
authored
Rollup merge of rust-lang#87916 - nbdd0121:black_box, r=nagisa
Implement `black_box` using intrinsic Introduce `black_box` intrinsic, as suggested in rust-lang#87590 (comment). This is still codegenned as empty inline assembly for LLVM. For MIR interpretation and cranelift it's treated as identity. cc `@Amanieu` as this is related to inline assembly cc `@bjorn3` for rustc_codegen_cranelift changes cc `@RalfJung` as this affects MIRI r? `@nagisa` I suppose
2 parents d078934 + f98d540 commit ac58f2e

File tree

8 files changed

+51
-14
lines changed

8 files changed

+51
-14
lines changed

compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -1136,6 +1136,11 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
11361136
};
11371137
ret.write_cvalue(fx, CValue::by_val(is_eq_value, ret.layout()));
11381138
};
1139+
1140+
black_box, (c a) {
1141+
// FIXME implement black_box semantics
1142+
ret.write_cvalue(fx, a);
1143+
};
11391144
}
11401145

11411146
if let Some((_, dest)) = destination {

compiler/rustc_codegen_llvm/src/asm.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,7 @@ impl AsmMethods for CodegenCx<'ll, 'tcx> {
425425
}
426426
}
427427

428-
fn inline_asm_call(
428+
pub(crate) fn inline_asm_call(
429429
bx: &mut Builder<'a, 'll, 'tcx>,
430430
asm: &str,
431431
cons: &str,

compiler/rustc_codegen_llvm/src/intrinsic.rs

+26
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::type_of::LayoutLlvmExt;
77
use crate::va_arg::emit_va_arg;
88
use crate::value::Value;
99

10+
use rustc_ast as ast;
1011
use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh};
1112
use rustc_codegen_ssa::common::span_invalid_monomorphization_error;
1213
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
@@ -327,6 +328,31 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
327328
}
328329
}
329330

331+
sym::black_box => {
332+
args[0].val.store(self, result);
333+
334+
// We need to "use" the argument in some way LLVM can't introspect, and on
335+
// targets that support it we can typically leverage inline assembly to do
336+
// this. LLVM's interpretation of inline assembly is that it's, well, a black
337+
// box. This isn't the greatest implementation since it probably deoptimizes
338+
// more than we want, but it's so far good enough.
339+
crate::asm::inline_asm_call(
340+
self,
341+
"",
342+
"r,~{memory}",
343+
&[result.llval],
344+
self.type_void(),
345+
true,
346+
false,
347+
ast::LlvmAsmDialect::Att,
348+
&[span],
349+
)
350+
.unwrap_or_else(|| bug!("failed to generate inline asm call for `black_box`"));
351+
352+
// We have copied the value to `result` already.
353+
return;
354+
}
355+
330356
_ if name_str.starts_with("simd_") => {
331357
match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) {
332358
Ok(llval) => llval,

compiler/rustc_mir/src/interpret/intrinsics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
465465
);
466466
self.copy_op(&self.operand_index(&args[0], index)?, dest)?;
467467
}
468-
sym::likely | sym::unlikely => {
468+
sym::likely | sym::unlikely | sym::black_box => {
469469
// These just return their argument
470470
self.copy_op(&args[0], dest)?;
471471
}

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,7 @@ symbols! {
335335
bitreverse,
336336
bitxor,
337337
bitxor_assign,
338+
black_box,
338339
block,
339340
bool,
340341
borrowck_graphviz_format,

compiler/rustc_typeck/src/check/intrinsic.rs

+3
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ pub fn intrinsic_operation_unsafety(intrinsic: Symbol) -> hir::Unsafety {
102102
| sym::maxnumf64
103103
| sym::type_name
104104
| sym::forget
105+
| sym::black_box
105106
| sym::variant_count => hir::Unsafety::Normal,
106107
_ => hir::Unsafety::Unsafe,
107108
}
@@ -387,6 +388,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
387388
(1, vec![param_ty; 2], tcx.types.bool)
388389
}
389390

391+
sym::black_box => (1, vec![param(0)], param(0)),
392+
390393
other => {
391394
tcx.sess.emit_err(UnrecognizedIntrinsicFunction { span: it.span, name: other });
392395
return;

library/core/src/hint.rs

+8-12
Original file line numberDiff line numberDiff line change
@@ -152,23 +152,19 @@ pub fn spin_loop() {
152152
/// backend used. Programs cannot rely on `black_box` for *correctness* in any way.
153153
///
154154
/// [`std::convert::identity`]: crate::convert::identity
155-
#[cfg_attr(not(miri), inline)]
156-
#[cfg_attr(miri, inline(never))]
155+
#[inline]
157156
#[unstable(feature = "bench_black_box", issue = "64102")]
158-
#[cfg_attr(miri, allow(unused_mut))]
157+
#[cfg_attr(not(bootstrap), allow(unused_mut))]
159158
pub fn black_box<T>(mut dummy: T) -> T {
160-
// We need to "use" the argument in some way LLVM can't introspect, and on
161-
// targets that support it we can typically leverage inline assembly to do
162-
// this. LLVM's interpretation of inline assembly is that it's, well, a black
163-
// box. This isn't the greatest implementation since it probably deoptimizes
164-
// more than we want, but it's so far good enough.
165-
166-
#[cfg(not(miri))] // This is just a hint, so it is fine to skip in Miri.
159+
#[cfg(bootstrap)]
167160
// SAFETY: the inline assembly is a no-op.
168161
unsafe {
169-
// FIXME: Cannot use `asm!` because it doesn't support MIPS and other architectures.
170162
llvm_asm!("" : : "r"(&mut dummy) : "memory" : "volatile");
163+
dummy
171164
}
172165

173-
dummy
166+
#[cfg(not(bootstrap))]
167+
{
168+
crate::intrinsics::black_box(dummy)
169+
}
174170
}

library/core/src/intrinsics.rs

+6
Original file line numberDiff line numberDiff line change
@@ -1933,6 +1933,12 @@ extern "rust-intrinsic" {
19331933
/// which is UB if any of their inputs are `undef`.)
19341934
#[rustc_const_unstable(feature = "const_intrinsic_raw_eq", issue = "none")]
19351935
pub fn raw_eq<T>(a: &T, b: &T) -> bool;
1936+
1937+
/// See documentation of [`std::hint::black_box`] for details.
1938+
///
1939+
/// [`std::hint::black_box`]: crate::hint::black_box
1940+
#[cfg(not(bootstrap))]
1941+
pub fn black_box<T>(dummy: T) -> T;
19361942
}
19371943

19381944
// Some functions are defined here because they accidentally got made

0 commit comments

Comments
 (0)