Skip to content

Commit b960b46

Browse files
committed
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 #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>
1 parent 461ab85 commit b960b46

File tree

3 files changed

+110
-0
lines changed

3 files changed

+110
-0
lines changed

gcc/rust/backend/rust-compile-intrinsic.cc

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ static tree uninit_handler (Context *ctx, TyTy::FnType *fntype);
8181
static tree move_val_init_handler (Context *ctx, TyTy::FnType *fntype);
8282
static tree assume_handler (Context *ctx, TyTy::FnType *fntype);
8383
static tree discriminant_value_handler (Context *ctx, TyTy::FnType *fntype);
84+
static tree black_box_handler (Context *ctx, TyTy::FnType *fntype);
8485
static tree variant_count_handler (Context *ctx, TyTy::FnType *fntype);
8586

8687
enum class Prefetch
@@ -245,6 +246,7 @@ static const std::map<std::string,
245246
{"try", try_handler (false)},
246247
{"catch_unwind", try_handler (true)},
247248
{"discriminant_value", discriminant_value_handler},
249+
{"black_box", black_box_handler},
248250
{"variant_count", variant_count_handler}};
249251

250252
Intrinsics::Intrinsics (Context *ctx) : ctx (ctx) {}
@@ -1429,6 +1431,55 @@ discriminant_value_handler (Context *ctx, TyTy::FnType *fntype)
14291431
return fndecl;
14301432
}
14311433

1434+
static tree
1435+
black_box_handler (Context *ctx, TyTy::FnType *fntype)
1436+
{
1437+
rust_assert (fntype->get_params ().size () == 1);
1438+
tree lookup = NULL_TREE;
1439+
if (check_for_cached_intrinsic (ctx, fntype, &lookup))
1440+
return lookup;
1441+
1442+
auto fndecl = compile_intrinsic_function (ctx, fntype);
1443+
std::vector<Bvariable *> param_vars;
1444+
compile_fn_params (ctx, fntype, fndecl, &param_vars);
1445+
auto &x_param = param_vars.at (0);
1446+
1447+
if (!Backend::function_set_parameters (fndecl, param_vars))
1448+
return error_mark_node;
1449+
1450+
enter_intrinsic_block (ctx, fndecl);
1451+
1452+
auto expr_x = Backend::var_expression (x_param, UNDEF_LOCATION);
1453+
1454+
tree asm_str = build_string (1, "");
1455+
TREE_TYPE (asm_str)
1456+
= build_array_type (char_type_node, build_index_type (size_int (1)));
1457+
1458+
tree input_constraint = build_string (2, "g");
1459+
TREE_TYPE (input_constraint)
1460+
= build_array_type (char_type_node, build_index_type (size_int (2)));
1461+
tree input_purpose = build_tree_list (NULL_TREE, input_constraint);
1462+
tree input_list = build_tree_list (input_purpose, expr_x);
1463+
1464+
tree clobber_string = build_string (7, "memory");
1465+
TREE_TYPE (clobber_string)
1466+
= build_array_type (char_type_node, build_index_type (size_int (7)));
1467+
tree clobber_list = build_tree_list (NULL_TREE, clobber_string);
1468+
1469+
tree asm_expr = build5 (ASM_EXPR, void_type_node, asm_str, NULL_TREE,
1470+
input_list, clobber_list, NULL_TREE);
1471+
1472+
ASM_VOLATILE_P (asm_expr) = 1;
1473+
ctx->add_statement (asm_expr);
1474+
1475+
auto return_statement
1476+
= Backend::return_statement (fndecl, expr_x, UNDEF_LOCATION);
1477+
ctx->add_statement (return_statement);
1478+
1479+
finalize_intrinsic_block (ctx, fndecl);
1480+
return fndecl;
1481+
}
1482+
14321483
static tree
14331484
variant_count_handler (Context *ctx, TyTy::FnType *fntype)
14341485
{
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// { dg-do compile }
2+
// { dg-options "-O2 -fdump-tree-gimple" }
3+
#![feature(intrinsics, lang_items, no_core)]
4+
#![no_core]
5+
6+
#[lang = "sized"]
7+
pub trait Sized {}
8+
9+
extern "rust-intrinsic" {
10+
pub fn black_box<T>(dummy: T) -> T;
11+
}
12+
13+
pub fn main() {
14+
let _ = unsafe { black_box(42) };
15+
16+
// Scan the gimple dump to ensure the volatile inline assembly was generated
17+
// { dg-final { scan-tree-dump-times "__asm__ __volatile__" 1 "gimple" } }
18+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// { dg-do run }
2+
// { dg-options "-O2" }
3+
#![feature(intrinsics, lang_items, no_core)]
4+
#![no_core]
5+
6+
#[lang = "sized"]
7+
pub trait Sized {}
8+
#[lang = "copy"]
9+
pub trait Copy {}
10+
11+
extern "rust-intrinsic" {
12+
pub fn black_box<T>(dummy: T) -> T;
13+
}
14+
15+
extern "C" {
16+
fn abort();
17+
}
18+
19+
struct MyStruct {
20+
a: i32,
21+
b: i64,
22+
}
23+
24+
pub extern "C" fn main() -> i32 {
25+
26+
let x = 12345;
27+
let y = unsafe { black_box(x) };
28+
29+
if y != 12345 {
30+
unsafe { abort(); }
31+
}
32+
33+
let s1 = MyStruct { a: 10, b: 20 };
34+
let s2 = unsafe { black_box(s1) };
35+
36+
if s2.a != 10 || s2.b != 20 {
37+
unsafe { abort(); }
38+
}
39+
40+
0
41+
}

0 commit comments

Comments
 (0)