Skip to content
Draft
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
51 changes: 51 additions & 0 deletions gcc/rust/backend/rust-compile-intrinsic.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -245,6 +246,7 @@ static const std::map<std::string,
{"try", try_handler (false)},
{"catch_unwind", try_handler (true)},
{"discriminant_value", discriminant_value_handler},
{"black_box", black_box_handler},
{"variant_count", variant_count_handler}};

Intrinsics::Intrinsics (Context *ctx) : ctx (ctx) {}
Expand Down Expand Up @@ -1429,6 +1431,55 @@ discriminant_value_handler (Context *ctx, TyTy::FnType *fntype)
return fndecl;
}

static tree
black_box_handler (Context *ctx, TyTy::FnType *fntype)
{
rust_assert (fntype->get_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<Bvariable *> param_vars;
compile_fn_params (ctx, fntype, fndecl, &param_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)
{
Expand Down
18 changes: 18 additions & 0 deletions gcc/testsuite/rust/compile/intrinsic-black-box.rs
Original file line number Diff line number Diff line change
@@ -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<T>(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" } }
}
41 changes: 41 additions & 0 deletions gcc/testsuite/rust/execute/intrinsic-black-box.rs
Original file line number Diff line number Diff line change
@@ -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<T>(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
}