Skip to content

Commit ce04e4e

Browse files
committed
WIP: Handle some C11 atomic types and operations
1 parent 789a8bd commit ce04e4e

File tree

6 files changed

+75
-10
lines changed

6 files changed

+75
-10
lines changed

c2rust-transpile/src/c_ast/conversion.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ fn parse_cast_kind(kind: &str) -> CastKind {
162162
"BuiltinFnToFnPtr" => CastKind::BuiltinFnToFnPtr,
163163
"ConstCast" => CastKind::ConstCast,
164164
"VectorSplat" => CastKind::VectorSplat,
165+
"AtomicToNonAtomic" => CastKind::AtomicToNonAtomic,
166+
"NonAtomicToAtomic" => CastKind::NonAtomicToAtomic,
165167
k => panic!("Unsupported implicit cast: {}", k),
166168
}
167169
}
@@ -816,8 +818,11 @@ impl ConversionContext {
816818
}
817819

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

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

1769+
// Perhaps as an optimization since atomic_init has no order,
1770+
// clang stores val1 in the position otherwise used for order
1771+
let is_atomic = name == "__c11_atomic_init" || name == "__opencl_atomic_init";
1772+
let val1 = if is_atomic { Some(order) } else { val1 };
1773+
17641774
let e = CExprKind::Atomic {
17651775
typ,
17661776
name,

c2rust-transpile/src/c_ast/iterators.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,8 @@ fn immediate_type_children(kind: &CTypeKind) -> Vec<SomeId> {
293293
| Reference(qtype)
294294
| Attributed(qtype, _)
295295
| BlockPointer(qtype)
296-
| Vector(qtype, _) => {
296+
| Vector(qtype, _)
297+
| Atomic(qtype) => {
297298
intos![qtype.ctype]
298299
}
299300

c2rust-transpile/src/c_ast/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -1214,6 +1214,8 @@ pub enum CastKind {
12141214
BuiltinFnToFnPtr,
12151215
ConstCast,
12161216
VectorSplat,
1217+
AtomicToNonAtomic,
1218+
NonAtomicToAtomic,
12171219
}
12181220

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

16731675
Half,
16741676
BFloat16,
1677+
1678+
// Atomic types (6.7.2.4)
1679+
Atomic(CQualTypeId),
16751680
}
16761681

16771682
impl CTypeKind {

c2rust-transpile/src/convert_type.rs

+1
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,7 @@ impl TypeConverter {
380380
}
381381

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

384385
// ANSI/ISO C-style function
385386
CTypeKind::Function(ret, ref params, is_var, is_noreturn, true) => {

c2rust-transpile/src/translator/atomics.rs

+52-6
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,19 @@ impl<'c> Translation<'c> {
1616
let memorder = &self.ast_context[expr];
1717
let i = match memorder.kind {
1818
CExprKind::Literal(_, CLiteral::Integer(i, _)) => Some(i),
19+
CExprKind::DeclRef(_, decl_id, LRValue::RValue) => {
20+
let decl = self.ast_context.get_decl(&decl_id).unwrap();
21+
match decl.kind {
22+
CDeclKind::EnumConstant { name: _, value: v } => match v {
23+
ConstIntExpr::I(i) => {
24+
assert!(0 <= i);
25+
Some(i as u64)
26+
}
27+
ConstIntExpr::U(u) => Some(u),
28+
},
29+
_ => unimplemented!(),
30+
}
31+
}
1932
_ => None,
2033
}?;
2134
use Ordering::*;
@@ -76,7 +89,7 @@ impl<'c> Translation<'c> {
7689
}
7790

7891
match name {
79-
"__atomic_load" | "__atomic_load_n" => ptr.and_then(|ptr| {
92+
"__atomic_load" | "__atomic_load_n" | "__c11_atomic_load" => ptr.and_then(|ptr| {
8093
let intrinsic_name = format!("atomic_load_{}", order_name(static_order(order)));
8194

8295
self.use_feature("core_intrinsics");
@@ -105,7 +118,7 @@ impl<'c> Translation<'c> {
105118
}
106119
}),
107120

108-
"__atomic_store" | "__atomic_store_n" => {
121+
"__atomic_store" | "__atomic_store_n" | "__c11_atomic_store" => {
109122
let val = val1.expect("__atomic_store must have a val argument");
110123
ptr.and_then(|ptr| {
111124
val.and_then(|val| {
@@ -131,7 +144,25 @@ impl<'c> Translation<'c> {
131144
})
132145
}
133146

134-
"__atomic_exchange" | "__atomic_exchange_n" => {
147+
// NOTE: there is no corresponding __atomic_init builtin in clang
148+
"__c11_atomic_init" => {
149+
let val = val1.expect(&format!("__atomic_init must have a val argument"));
150+
ptr.and_then(|ptr| {
151+
val.and_then(|val| {
152+
let assignment = mk().assign_expr(
153+
mk().unary_expr(UnOp::Deref(Default::default()), ptr),
154+
val,
155+
);
156+
self.convert_side_effects_expr(
157+
ctx,
158+
WithStmts::new_val(assignment),
159+
"Builtin is not supposed to be used",
160+
)
161+
})
162+
})
163+
}
164+
165+
"__atomic_exchange" | "__atomic_exchange_n" | "__c11_atomic_exchange" => {
135166
let val = val1.expect("__atomic_store must have a val argument");
136167
ptr.and_then(|ptr| {
137168
val.and_then(|val| {
@@ -176,10 +207,19 @@ impl<'c> Translation<'c> {
176207
})
177208
}
178209

179-
"__atomic_compare_exchange" | "__atomic_compare_exchange_n" => {
210+
"__atomic_compare_exchange"
211+
| "__atomic_compare_exchange_n"
212+
| "__c11_atomic_compare_exchange_strong" => {
180213
let expected =
181214
val1.expect("__atomic_compare_exchange must have a expected argument");
182215
let desired = val2.expect("__atomic_compare_exchange must have a desired argument");
216+
// Some C11 atomic operations encode the weak property in the name
217+
let weak = match (name, weak) {
218+
("__c11_atomic_compare_exchange_strong", None) => Some(false),
219+
("__c11_atomic_compare_exchange_weak", None) => Some(true),
220+
_ => weak,
221+
};
222+
183223
ptr.and_then(|ptr| {
184224
expected.and_then(|expected| {
185225
desired.and_then(|desired| {
@@ -258,7 +298,13 @@ impl<'c> Translation<'c> {
258298
| "__atomic_fetch_and"
259299
| "__atomic_fetch_xor"
260300
| "__atomic_fetch_or"
261-
| "__atomic_fetch_nand" => {
301+
| "__atomic_fetch_nand"
302+
| "__c11_atomic_fetch_add"
303+
| "__c11_atomic_fetch_sub"
304+
| "__c11_atomic_fetch_and"
305+
| "__c11_atomic_fetch_xor"
306+
| "__c11_atomic_fetch_or"
307+
| "__c11_atomic_fetch_nand" => {
262308
let intrinsic_name = if name.contains("_add") {
263309
"atomic_xadd"
264310
} else if name.contains("_sub") {
@@ -285,7 +331,7 @@ impl<'c> Translation<'c> {
285331
})
286332
}
287333

288-
_ => unimplemented!("atomic not implemented"),
334+
_ => unimplemented!("atomic not implemented: {}", name),
289335
}
290336
}
291337

c2rust-transpile/src/translator/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -4412,6 +4412,8 @@ impl<'c> Translation<'c> {
44124412
CastKind::VectorSplat => Err(TranslationError::generic(
44134413
"TODO vector splat casts not supported",
44144414
)),
4415+
4416+
CastKind::AtomicToNonAtomic | CastKind::NonAtomicToAtomic => Ok(val),
44154417
}
44164418
}
44174419

@@ -4920,7 +4922,7 @@ impl<'c> Translation<'c> {
49204922
Vector(..) => {
49214923
// Handled in `import_simd_typedef`
49224924
}
4923-
TypeOfExpr(_) | BuiltinFn => {}
4925+
TypeOfExpr(_) | BuiltinFn | Atomic(..) => {}
49244926
}
49254927
}
49264928

0 commit comments

Comments
 (0)