Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement black_box using intrinsic #87916

Merged
merged 1 commit into from
Aug 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1136,6 +1136,11 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
};
ret.write_cvalue(fx, CValue::by_val(is_eq_value, ret.layout()));
};

black_box, (c a) {
// FIXME implement black_box semantics
ret.write_cvalue(fx, a);
};
}

if let Some((_, dest)) = destination {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_llvm/src/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ impl AsmMethods for CodegenCx<'ll, 'tcx> {
}
}

fn inline_asm_call(
pub(crate) fn inline_asm_call(
bx: &mut Builder<'a, 'll, 'tcx>,
asm: &str,
cons: &str,
Expand Down
26 changes: 26 additions & 0 deletions compiler/rustc_codegen_llvm/src/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::type_of::LayoutLlvmExt;
use crate::va_arg::emit_va_arg;
use crate::value::Value;

use rustc_ast as ast;
use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh};
use rustc_codegen_ssa::common::span_invalid_monomorphization_error;
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
Expand Down Expand Up @@ -327,6 +328,31 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
}
}

sym::black_box => {
args[0].val.store(self, result);

// We need to "use" the argument in some way LLVM can't introspect, and on
// targets that support it we can typically leverage inline assembly to do
// this. LLVM's interpretation of inline assembly is that it's, well, a black
// box. This isn't the greatest implementation since it probably deoptimizes
// more than we want, but it's so far good enough.
crate::asm::inline_asm_call(
self,
"",
"r,~{memory}",
&[result.llval],
self.type_void(),
true,
false,
ast::LlvmAsmDialect::Att,
&[span],
)
.unwrap_or_else(|| bug!("failed to generate inline asm call for `black_box`"));

// We have copied the value to `result` already.
return;
}

_ if name_str.starts_with("simd_") => {
match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) {
Ok(llval) => llval,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir/src/interpret/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
);
self.copy_op(&self.operand_index(&args[0], index)?, dest)?;
}
sym::likely | sym::unlikely => {
sym::likely | sym::unlikely | sym::black_box => {
// These just return their argument
self.copy_op(&args[0], dest)?;
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ symbols! {
bitreverse,
bitxor,
bitxor_assign,
black_box,
block,
bool,
borrowck_graphviz_format,
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_typeck/src/check/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ pub fn intrinsic_operation_unsafety(intrinsic: Symbol) -> hir::Unsafety {
| sym::maxnumf64
| sym::type_name
| sym::forget
| sym::black_box
| sym::variant_count => hir::Unsafety::Normal,
_ => hir::Unsafety::Unsafe,
}
Expand Down Expand Up @@ -387,6 +388,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
(1, vec![param_ty; 2], tcx.types.bool)
}

sym::black_box => (1, vec![param(0)], param(0)),

other => {
tcx.sess.emit_err(UnrecognizedIntrinsicFunction { span: it.span, name: other });
return;
Expand Down
20 changes: 8 additions & 12 deletions library/core/src/hint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,23 +152,19 @@ pub fn spin_loop() {
/// backend used. Programs cannot rely on `black_box` for *correctness* in any way.
///
/// [`std::convert::identity`]: crate::convert::identity
#[cfg_attr(not(miri), inline)]
#[cfg_attr(miri, inline(never))]
#[inline]
#[unstable(feature = "bench_black_box", issue = "64102")]
#[cfg_attr(miri, allow(unused_mut))]
#[cfg_attr(not(bootstrap), allow(unused_mut))]
pub fn black_box<T>(mut dummy: T) -> T {
// We need to "use" the argument in some way LLVM can't introspect, and on
// targets that support it we can typically leverage inline assembly to do
// this. LLVM's interpretation of inline assembly is that it's, well, a black
// box. This isn't the greatest implementation since it probably deoptimizes
// more than we want, but it's so far good enough.

#[cfg(not(miri))] // This is just a hint, so it is fine to skip in Miri.
#[cfg(bootstrap)]
// SAFETY: the inline assembly is a no-op.
unsafe {
// FIXME: Cannot use `asm!` because it doesn't support MIPS and other architectures.
llvm_asm!("" : : "r"(&mut dummy) : "memory" : "volatile");
dummy
}

dummy
#[cfg(not(bootstrap))]
{
crate::intrinsics::black_box(dummy)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Longer-term we might even want to directly reexport the intrinsic instead of using a wrapper function... but that's blocked on the fn ptr reification PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess that's also blocked by path component stability

Copy link
Member

@RalfJung RalfJung Aug 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, we already reexport transmute and probably will reexport copy/copy_nonoverlapping soon (we did but it was reverted due to the fn ptr reification problem).

So, while the lack of path component stability is a problem, it's not necessarily a blocker.

Anyway, even the exported function is currently still unstable; this is a discussion to be had at stabilization time.

}
}
6 changes: 6 additions & 0 deletions library/core/src/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1933,6 +1933,12 @@ extern "rust-intrinsic" {
/// which is UB if any of their inputs are `undef`.)
#[rustc_const_unstable(feature = "const_intrinsic_raw_eq", issue = "none")]
pub fn raw_eq<T>(a: &T, b: &T) -> bool;

/// See documentation of [`std::hint::black_box`] for details.
///
/// [`std::hint::black_box`]: crate::hint::black_box
#[cfg(not(bootstrap))]
pub fn black_box<T>(dummy: T) -> T;
}

// Some functions are defined here because they accidentally got made
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/sanitize/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// run-fail
// error-pattern: MemorySanitizer: use-of-uninitialized-value
// error-pattern: Uninitialized value was created by an allocation
// error-pattern: in the stack frame of function 'random'
// error-pattern: in the stack frame of function 'main'
//
// This test case intentionally limits the usage of the std,
// since it will be linked with an uninstrumented version of it.
Expand Down