Skip to content

Commit

Permalink
WIP: Handle some C11 atomic types and operations
Browse files Browse the repository at this point in the history
  • Loading branch information
thedataking committed Feb 6, 2023
1 parent 789a8bd commit ce04e4e
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 10 deletions.
14 changes: 12 additions & 2 deletions c2rust-transpile/src/c_ast/conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ fn parse_cast_kind(kind: &str) -> CastKind {
"BuiltinFnToFnPtr" => CastKind::BuiltinFnToFnPtr,
"ConstCast" => CastKind::ConstCast,
"VectorSplat" => CastKind::VectorSplat,
"AtomicToNonAtomic" => CastKind::AtomicToNonAtomic,
"NonAtomicToAtomic" => CastKind::NonAtomicToAtomic,
k => panic!("Unsupported implicit cast: {}", k),
}
}
Expand Down Expand Up @@ -816,8 +818,11 @@ impl ConversionContext {
}

TypeTag::TagAtomicType => {
// Next step in atomics implementation: Transfer to a CTypeKind
panic!("C11 Atomics are not implemented in C2Rust yet.");
let qt = from_value(ty_node.extras[0].clone()).expect("Inner type not found");
let qt_new = self.visit_qualified_type(qt);
let atomic_ty = CTypeKind::Atomic(qt_new);
self.add_type(new_id, not_located(atomic_ty));
self.processed_nodes.insert(new_id, OTHER_TYPE);
}

t => panic!(
Expand Down Expand Up @@ -1761,6 +1766,11 @@ impl ConversionContext {
let typ = node.type_id.expect("Expected expression to have type");
let typ = self.visit_qualified_type(typ);

// Perhaps as an optimization since atomic_init has no order,
// clang stores val1 in the position otherwise used for order
let is_atomic = name == "__c11_atomic_init" || name == "__opencl_atomic_init";
let val1 = if is_atomic { Some(order) } else { val1 };

let e = CExprKind::Atomic {
typ,
name,
Expand Down
3 changes: 2 additions & 1 deletion c2rust-transpile/src/c_ast/iterators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,8 @@ fn immediate_type_children(kind: &CTypeKind) -> Vec<SomeId> {
| Reference(qtype)
| Attributed(qtype, _)
| BlockPointer(qtype)
| Vector(qtype, _) => {
| Vector(qtype, _)
| Atomic(qtype) => {
intos![qtype.ctype]
}

Expand Down
5 changes: 5 additions & 0 deletions c2rust-transpile/src/c_ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1214,6 +1214,8 @@ pub enum CastKind {
BuiltinFnToFnPtr,
ConstCast,
VectorSplat,
AtomicToNonAtomic,
NonAtomicToAtomic,
}

/// Represents a unary operator in C (6.5.3 Unary operators) and GNU C extensions
Expand Down Expand Up @@ -1672,6 +1674,9 @@ pub enum CTypeKind {

Half,
BFloat16,

// Atomic types (6.7.2.4)
Atomic(CQualTypeId),
}

impl CTypeKind {
Expand Down
1 change: 1 addition & 0 deletions c2rust-transpile/src/convert_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,7 @@ impl TypeConverter {
}

CTypeKind::Attributed(ty, _) => self.convert(ctxt, ty.ctype),
CTypeKind::Atomic(ty) => self.convert(ctxt, ty.ctype),

// ANSI/ISO C-style function
CTypeKind::Function(ret, ref params, is_var, is_noreturn, true) => {
Expand Down
58 changes: 52 additions & 6 deletions c2rust-transpile/src/translator/atomics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,19 @@ impl<'c> Translation<'c> {
let memorder = &self.ast_context[expr];
let i = match memorder.kind {
CExprKind::Literal(_, CLiteral::Integer(i, _)) => Some(i),
CExprKind::DeclRef(_, decl_id, LRValue::RValue) => {
let decl = self.ast_context.get_decl(&decl_id).unwrap();
match decl.kind {
CDeclKind::EnumConstant { name: _, value: v } => match v {
ConstIntExpr::I(i) => {
assert!(0 <= i);
Some(i as u64)
}
ConstIntExpr::U(u) => Some(u),
},
_ => unimplemented!(),
}
}
_ => None,
}?;
use Ordering::*;
Expand Down Expand Up @@ -76,7 +89,7 @@ impl<'c> Translation<'c> {
}

match name {
"__atomic_load" | "__atomic_load_n" => ptr.and_then(|ptr| {
"__atomic_load" | "__atomic_load_n" | "__c11_atomic_load" => ptr.and_then(|ptr| {
let intrinsic_name = format!("atomic_load_{}", order_name(static_order(order)));

self.use_feature("core_intrinsics");
Expand Down Expand Up @@ -105,7 +118,7 @@ impl<'c> Translation<'c> {
}
}),

"__atomic_store" | "__atomic_store_n" => {
"__atomic_store" | "__atomic_store_n" | "__c11_atomic_store" => {
let val = val1.expect("__atomic_store must have a val argument");
ptr.and_then(|ptr| {
val.and_then(|val| {
Expand All @@ -131,7 +144,25 @@ impl<'c> Translation<'c> {
})
}

"__atomic_exchange" | "__atomic_exchange_n" => {
// NOTE: there is no corresponding __atomic_init builtin in clang
"__c11_atomic_init" => {
let val = val1.expect(&format!("__atomic_init must have a val argument"));
ptr.and_then(|ptr| {
val.and_then(|val| {
let assignment = mk().assign_expr(
mk().unary_expr(UnOp::Deref(Default::default()), ptr),
val,
);
self.convert_side_effects_expr(
ctx,
WithStmts::new_val(assignment),
"Builtin is not supposed to be used",
)
})
})
}

"__atomic_exchange" | "__atomic_exchange_n" | "__c11_atomic_exchange" => {
let val = val1.expect("__atomic_store must have a val argument");
ptr.and_then(|ptr| {
val.and_then(|val| {
Expand Down Expand Up @@ -176,10 +207,19 @@ impl<'c> Translation<'c> {
})
}

"__atomic_compare_exchange" | "__atomic_compare_exchange_n" => {
"__atomic_compare_exchange"
| "__atomic_compare_exchange_n"
| "__c11_atomic_compare_exchange_strong" => {
let expected =
val1.expect("__atomic_compare_exchange must have a expected argument");
let desired = val2.expect("__atomic_compare_exchange must have a desired argument");
// Some C11 atomic operations encode the weak property in the name
let weak = match (name, weak) {
("__c11_atomic_compare_exchange_strong", None) => Some(false),
("__c11_atomic_compare_exchange_weak", None) => Some(true),
_ => weak,
};

ptr.and_then(|ptr| {
expected.and_then(|expected| {
desired.and_then(|desired| {
Expand Down Expand Up @@ -258,7 +298,13 @@ impl<'c> Translation<'c> {
| "__atomic_fetch_and"
| "__atomic_fetch_xor"
| "__atomic_fetch_or"
| "__atomic_fetch_nand" => {
| "__atomic_fetch_nand"
| "__c11_atomic_fetch_add"
| "__c11_atomic_fetch_sub"
| "__c11_atomic_fetch_and"
| "__c11_atomic_fetch_xor"
| "__c11_atomic_fetch_or"
| "__c11_atomic_fetch_nand" => {
let intrinsic_name = if name.contains("_add") {
"atomic_xadd"
} else if name.contains("_sub") {
Expand All @@ -285,7 +331,7 @@ impl<'c> Translation<'c> {
})
}

_ => unimplemented!("atomic not implemented"),
_ => unimplemented!("atomic not implemented: {}", name),
}
}

Expand Down
4 changes: 3 additions & 1 deletion c2rust-transpile/src/translator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4412,6 +4412,8 @@ impl<'c> Translation<'c> {
CastKind::VectorSplat => Err(TranslationError::generic(
"TODO vector splat casts not supported",
)),

CastKind::AtomicToNonAtomic | CastKind::NonAtomicToAtomic => Ok(val),
}
}

Expand Down Expand Up @@ -4920,7 +4922,7 @@ impl<'c> Translation<'c> {
Vector(..) => {
// Handled in `import_simd_typedef`
}
TypeOfExpr(_) | BuiltinFn => {}
TypeOfExpr(_) | BuiltinFn | Atomic(..) => {}
}
}

Expand Down

0 comments on commit ce04e4e

Please sign in to comment.