From 163d43b7c64d0f863174478e0ec094cd93041edc Mon Sep 17 00:00:00 2001 From: jayant chauhan <0001jayant@gmail.com> Date: Tue, 3 Mar 2026 01:43:29 +0530 Subject: [PATCH] intrinsic: Add black_box intrinsic This patch implements the `black_box` intrinsic, which is used to prevent the compiler from optimizing away a piece of code. It maps to an empty volatile inline assembly block with a memory clobber and a general input constraint, matching the behavior expected by the standard library. Addresses Rust-GCC/gccrs#3372 gcc/rust/ChangeLog: * backend/rust-compile-intrinsic.cc (black_box_handler): New handler. gcc/testsuite/ChangeLog: * rust/compile/intrinsic-black-box.rs: New test. * rust/execute/intrinsic-black-box.rs: New test. Signed-off-by: Jayant Chauhan <0001jayant@gmail.com> --- gcc/rust/backend/rust-compile-intrinsic.cc | 51 +++++++++++++++++++ .../rust/compile/intrinsic-black-box.rs | 18 +++++++ .../rust/execute/intrinsic-black-box.rs | 41 +++++++++++++++ 3 files changed, 110 insertions(+) create mode 100644 gcc/testsuite/rust/compile/intrinsic-black-box.rs create mode 100644 gcc/testsuite/rust/execute/intrinsic-black-box.rs diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc b/gcc/rust/backend/rust-compile-intrinsic.cc index 450a86979208..34b36c8b7c7e 100644 --- a/gcc/rust/backend/rust-compile-intrinsic.cc +++ b/gcc/rust/backend/rust-compile-intrinsic.cc @@ -81,6 +81,7 @@ static tree uninit_handler (Context *ctx, TyTy::FnType *fntype); static tree move_val_init_handler (Context *ctx, TyTy::FnType *fntype); static tree assume_handler (Context *ctx, TyTy::FnType *fntype); static tree discriminant_value_handler (Context *ctx, TyTy::FnType *fntype); +static tree black_box_handler (Context *ctx, TyTy::FnType *fntype); static tree variant_count_handler (Context *ctx, TyTy::FnType *fntype); enum class Prefetch @@ -245,6 +246,7 @@ static const std::mapget_params ().size () == 1); + tree lookup = NULL_TREE; + if (check_for_cached_intrinsic (ctx, fntype, &lookup)) + return lookup; + + auto fndecl = compile_intrinsic_function (ctx, fntype); + std::vector param_vars; + compile_fn_params (ctx, fntype, fndecl, ¶m_vars); + auto &x_param = param_vars.at (0); + + if (!Backend::function_set_parameters (fndecl, param_vars)) + return error_mark_node; + + enter_intrinsic_block (ctx, fndecl); + + auto expr_x = Backend::var_expression (x_param, UNDEF_LOCATION); + + tree asm_str = build_string (1, ""); + TREE_TYPE (asm_str) + = build_array_type (char_type_node, build_index_type (size_int (1))); + + tree input_constraint = build_string (2, "g"); + TREE_TYPE (input_constraint) + = build_array_type (char_type_node, build_index_type (size_int (2))); + tree input_purpose = build_tree_list (NULL_TREE, input_constraint); + tree input_list = build_tree_list (input_purpose, expr_x); + + tree clobber_string = build_string (7, "memory"); + TREE_TYPE (clobber_string) + = build_array_type (char_type_node, build_index_type (size_int (7))); + tree clobber_list = build_tree_list (NULL_TREE, clobber_string); + + tree asm_expr = build5 (ASM_EXPR, void_type_node, asm_str, NULL_TREE, + input_list, clobber_list, NULL_TREE); + + ASM_VOLATILE_P (asm_expr) = 1; + ctx->add_statement (asm_expr); + + auto return_statement + = Backend::return_statement (fndecl, expr_x, UNDEF_LOCATION); + ctx->add_statement (return_statement); + + finalize_intrinsic_block (ctx, fndecl); + return fndecl; +} + static tree variant_count_handler (Context *ctx, TyTy::FnType *fntype) { diff --git a/gcc/testsuite/rust/compile/intrinsic-black-box.rs b/gcc/testsuite/rust/compile/intrinsic-black-box.rs new file mode 100644 index 000000000000..eaa03fcde437 --- /dev/null +++ b/gcc/testsuite/rust/compile/intrinsic-black-box.rs @@ -0,0 +1,18 @@ +// { dg-do compile } +// { dg-options "-O2 -fdump-tree-gimple" } +#![feature(intrinsics, lang_items, no_core)] +#![no_core] + +#[lang = "sized"] +pub trait Sized {} + +extern "rust-intrinsic" { + pub fn black_box(dummy: T) -> T; +} + +pub fn main() { + let _ = unsafe { black_box(42) }; + + // Scan the gimple dump to ensure the volatile inline assembly was generated + // { dg-final { scan-tree-dump-times "__asm__ __volatile__" 1 "gimple" } } +} \ No newline at end of file diff --git a/gcc/testsuite/rust/execute/intrinsic-black-box.rs b/gcc/testsuite/rust/execute/intrinsic-black-box.rs new file mode 100644 index 000000000000..d831ac7058f2 --- /dev/null +++ b/gcc/testsuite/rust/execute/intrinsic-black-box.rs @@ -0,0 +1,41 @@ +// { dg-do run } +// { dg-options "-O2" } +#![feature(intrinsics, lang_items, no_core)] +#![no_core] + +#[lang = "sized"] +pub trait Sized {} +#[lang = "copy"] +pub trait Copy {} + +extern "rust-intrinsic" { + pub fn black_box(dummy: T) -> T; +} + +extern "C" { + fn abort(); +} + +struct MyStruct { + a: i32, + b: i64, +} + +pub extern "C" fn main() -> i32 { + + let x = 12345; + let y = unsafe { black_box(x) }; + + if y != 12345 { + unsafe { abort(); } + } + + let s1 = MyStruct { a: 10, b: 20 }; + let s2 = unsafe { black_box(s1) }; + + if s2.a != 10 || s2.b != 20 { + unsafe { abort(); } + } + + 0 +} \ No newline at end of file