Skip to content
Open
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
4 changes: 2 additions & 2 deletions c2rust-transpile/src/translator/atomics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ fn order_suffix(order: Ordering) -> &'static str {
}
}

fn order_ty_name(order: Ordering) -> &'static str {
pub(crate) fn order_ty_name(order: Ordering) -> &'static str {
use Ordering::*;
match order {
SeqCst => "SeqCst",
Expand Down Expand Up @@ -104,7 +104,7 @@ impl<'c> Translation<'c> {
}
}

fn convert_memordering(&self, expr: CExprId) -> Option<Ordering> {
pub(crate) fn convert_memordering(&self, expr: CExprId) -> Option<Ordering> {
let memorder = &self.ast_context.index_unwrap_parens(expr);
let i = match memorder.kind {
CExprKind::Literal(_, CLiteral::Integer(i, _)) => Some(i),
Expand Down
40 changes: 39 additions & 1 deletion c2rust-transpile/src/translator/builtins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@
use super::*;

use crate::format_translation_err;
use crate::translator::atomics::CAtomicBinOp;
use crate::translator::atomics::{order_ty_name, CAtomicBinOp};
use crate::translator::simd::simd_fn_from_builtin_fn;
use c2rust_rust_tools::RustEdition::Edition2024;
use log::warn;
use std::sync::atomic::Ordering::Acquire;
use std::sync::atomic::Ordering::Relaxed;
use std::sync::atomic::Ordering::Release;
use std::sync::atomic::Ordering::SeqCst;

Expand Down Expand Up @@ -525,6 +526,43 @@ impl<'c> Translation<'c> {
)
}

// `__atomic_thread_fence` is a full fence (`atomic_fence`);
// `__atomic_signal_fence` only fences the compiler
// (`compiler_fence`). The order picks the intrinsic at
// compile time, so we only support a constant one. A relaxed fence
// is a no-op (and Rust has no relaxed fence intrinsic), so we drop it.
"__atomic_thread_fence" | "__atomic_signal_fence" => {
let order = self.convert_memordering(args[0]).ok_or_else(|| {
format_translation_err!(
self.ast_context.display_loc(src_loc),
"non-constant memory order argument to {} is not supported",
builtin_name
)
})?;
let call_expr = if order == Relaxed {
mk().tuple_expr(vec![])
} else if builtin_name == "__atomic_thread_fence" {
mk().call_expr(self.atomic_intrinsic_expr("fence", &[order]), vec![])
} else {
let ordering = mk().abs_path_expr(vec![
"core",
"sync",
"atomic",
"Ordering",
order_ty_name(order),
]);
mk().call_expr(
mk().abs_path_expr(vec!["core", "sync", "atomic", "compiler_fence"]),
vec![ordering],
)
};
self.convert_side_effects_expr(
ctx,
WithStmts::new_val(call_expr),
"Builtin is not supposed to be used",
)
}

"__sync_lock_test_and_set_1"
| "__sync_lock_test_and_set_2"
| "__sync_lock_test_and_set_4"
Expand Down
5 changes: 5 additions & 0 deletions c2rust-transpile/tests/snapshots.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,11 @@ fn test_factorial() {
transpile("factorial.c").run();
}

#[test]
fn test_fences() {
transpile("fences.c").run();
}

#[test]
fn test_fn_attrs() {
transpile("fn_attrs.c").run();
Expand Down
13 changes: 13 additions & 0 deletions c2rust-transpile/tests/snapshots/fences.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
void fences(void) {
__atomic_thread_fence(__ATOMIC_RELAXED);
__atomic_thread_fence(__ATOMIC_ACQUIRE);
__atomic_thread_fence(__ATOMIC_RELEASE);
__atomic_thread_fence(__ATOMIC_ACQ_REL);
__atomic_thread_fence(__ATOMIC_SEQ_CST);

__atomic_signal_fence(__ATOMIC_RELAXED);
__atomic_signal_fence(__ATOMIC_ACQUIRE);
__atomic_signal_fence(__ATOMIC_RELEASE);
__atomic_signal_fence(__ATOMIC_ACQ_REL);
__atomic_signal_fence(__ATOMIC_SEQ_CST);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
source: c2rust-transpile/tests/snapshots.rs
expression: cat tests/snapshots/fences.2021.clang15.rs
---
#![allow(
clippy::missing_safety_doc,
dead_code,
non_camel_case_types,
non_snake_case,
non_upper_case_globals,
unused_assignments,
unused_mut
)]
#![feature(core_intrinsics)]
#[no_mangle]
pub unsafe extern "C" fn fences() {
();
::core::intrinsics::atomic_fence_acquire();
::core::intrinsics::atomic_fence_release();
::core::intrinsics::atomic_fence_acqrel();
::core::intrinsics::atomic_fence_seqcst();
();
::core::sync::atomic::compiler_fence(::core::sync::atomic::Ordering::Acquire);
::core::sync::atomic::compiler_fence(::core::sync::atomic::Ordering::Release);
::core::sync::atomic::compiler_fence(::core::sync::atomic::Ordering::AcqRel);
::core::sync::atomic::compiler_fence(::core::sync::atomic::Ordering::SeqCst);
}
pub const __ATOMIC_RELAXED: ::core::ffi::c_int = 0 as ::core::ffi::c_int;
pub const __ATOMIC_ACQUIRE: ::core::ffi::c_int = 2 as ::core::ffi::c_int;
pub const __ATOMIC_RELEASE: ::core::ffi::c_int = 3 as ::core::ffi::c_int;
pub const __ATOMIC_ACQ_REL: ::core::ffi::c_int = 4 as ::core::ffi::c_int;
pub const __ATOMIC_SEQ_CST: ::core::ffi::c_int = 5 as ::core::ffi::c_int;
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
source: c2rust-transpile/tests/snapshots.rs
expression: cat tests/snapshots/fences.2024.clang15.rs
---
#![allow(
clippy::missing_safety_doc,
dead_code,
non_camel_case_types,
non_snake_case,
non_upper_case_globals,
unsafe_op_in_unsafe_fn,
unused_assignments,
unused_mut
)]
#![feature(core_intrinsics)]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn fences() {
();
::core::intrinsics::atomic_fence::<{ ::core::intrinsics::AtomicOrdering::Acquire }>();
::core::intrinsics::atomic_fence::<{ ::core::intrinsics::AtomicOrdering::Release }>();
::core::intrinsics::atomic_fence::<{ ::core::intrinsics::AtomicOrdering::AcqRel }>();
::core::intrinsics::atomic_fence::<{ ::core::intrinsics::AtomicOrdering::SeqCst }>();
();
::core::sync::atomic::compiler_fence(::core::sync::atomic::Ordering::Acquire);
::core::sync::atomic::compiler_fence(::core::sync::atomic::Ordering::Release);
::core::sync::atomic::compiler_fence(::core::sync::atomic::Ordering::AcqRel);
::core::sync::atomic::compiler_fence(::core::sync::atomic::Ordering::SeqCst);
}
pub const __ATOMIC_RELAXED: ::core::ffi::c_int = 0 as ::core::ffi::c_int;
pub const __ATOMIC_ACQUIRE: ::core::ffi::c_int = 2 as ::core::ffi::c_int;
pub const __ATOMIC_RELEASE: ::core::ffi::c_int = 3 as ::core::ffi::c_int;
pub const __ATOMIC_ACQ_REL: ::core::ffi::c_int = 4 as ::core::ffi::c_int;
pub const __ATOMIC_SEQ_CST: ::core::ffi::c_int = 5 as ::core::ffi::c_int;
22 changes: 22 additions & 0 deletions tests/unit/builtins/src/atomics.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,25 @@ void new_atomics(const unsigned buffer_size, int buffer[const])
__atomic_store_n(&x, 0, __ATOMIC_RELAXED);
buffer[i++] = x;
}

void fences(const unsigned buffer_size, int buffer[const])
Comment thread
thedataking marked this conversation as resolved.
{
int i = 0, x = 34;
// Full memory fences (`__atomic_thread_fence`) and compiler-only fences
// (`__atomic_signal_fence`), across every memory order. A relaxed fence is
// a no-op. Fences have no observable effect here; this just exercises that
// each one transpiles and compiles.
__atomic_thread_fence(__ATOMIC_RELAXED); buffer[i++] = ++x;
__atomic_thread_fence(__ATOMIC_ACQUIRE); buffer[i++] = ++x;
__atomic_thread_fence(__ATOMIC_RELEASE); buffer[i++] = ++x;
__atomic_thread_fence(__ATOMIC_ACQ_REL); buffer[i++] = ++x;
__atomic_thread_fence(__ATOMIC_SEQ_CST); buffer[i++] = ++x;

__atomic_signal_fence(__ATOMIC_RELAXED); buffer[i++] = ++x;
__atomic_signal_fence(__ATOMIC_ACQUIRE); buffer[i++] = ++x;
__atomic_signal_fence(__ATOMIC_RELEASE); buffer[i++] = ++x;
__atomic_signal_fence(__ATOMIC_ACQ_REL); buffer[i++] = ++x;
__atomic_signal_fence(__ATOMIC_SEQ_CST); buffer[i++] = ++x;

__sync_synchronize(); buffer[i++] = ++x;
}
18 changes: 17 additions & 1 deletion tests/unit/builtins/src/test_builtins.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! feature_core_intrinsics, feature_raw_ref_op

use crate::alloca::rust_alloca_hello;
use crate::atomics::{rust_atomics_entry, rust_new_atomics};
use crate::atomics::{rust_atomics_entry, rust_fences, rust_new_atomics};
use crate::math::{rust_ffs, rust_ffsl, rust_ffsll, rust_isfinite, rust_isinf_sign, rust_isnan};
use crate::mem_x_fns::{rust_assume_aligned, rust_mem_x};
use crate::overflow::rust_overflow_builtins;
Expand All @@ -12,6 +12,7 @@ unsafe extern "C" {
fn alloca_hello() -> c_int;
fn atomics_entry(_: c_uint, _: *mut c_int);
fn new_atomics(_: c_uint, _: *mut c_int);
fn fences(_: c_uint, _: *mut c_int);
fn mem_x(_: *const c_char, _: *mut c_char);
fn ffs(_: c_int) -> c_int;
fn ffsl(_: c_long) -> c_int;
Expand Down Expand Up @@ -79,6 +80,21 @@ pub fn test_overflow_builtins() {
}
}

#[test]
pub fn test_fences() {
let mut buffer = [0; BUFFER_SIZE];
let mut rust_buffer = [0; BUFFER_SIZE];

unsafe {
fences(BUFFER_SIZE as u32, buffer.as_mut_ptr());
rust_fences(BUFFER_SIZE as u32, rust_buffer.as_mut_ptr());
}

for index in 0..BUFFER_SIZE {
assert_eq!(buffer[index], rust_buffer[index]);
}
}

#[test]
pub fn test_mem_fns() {
let const_string = "I am ten!\0";
Expand Down
Loading