11use crate :: format_translation_err;
2+ use itertools:: repeat_n;
3+ use std:: sync:: atomic:: Ordering ;
24
35use super :: * ;
4- use std:: sync:: atomic:: Ordering ;
6+
7+ fn order_suffix ( order : Ordering ) -> & ' static str {
8+ use Ordering :: * ;
9+ match order {
10+ SeqCst => "seqcst" ,
11+ AcqRel => "acqrel" ,
12+ Acquire => "acquire" ,
13+ Release => "release" ,
14+ Relaxed => "relaxed" ,
15+ _ => unreachable ! (
16+ "new variants added to `{}`" ,
17+ std:: any:: type_name:: <Ordering >( )
18+ ) ,
19+ }
20+ }
21+
22+ fn order_ty_name ( order : Ordering ) -> & ' static str {
23+ use Ordering :: * ;
24+ match order {
25+ SeqCst => "SeqCst" ,
26+ AcqRel => "AcqRel" ,
27+ Acquire => "Acquire" ,
28+ Release => "Release" ,
29+ Relaxed => "Relaxed" ,
30+ _ => unreachable ! (
31+ "new variants added to `{}`" ,
32+ std:: any:: type_name:: <Ordering >( )
33+ ) ,
34+ }
35+ }
536
637impl < ' c > Translation < ' c > {
38+ fn atomic_intrinsic_expr_edition_2021 (
39+ & self ,
40+ base_name : & str ,
41+ orders : & [ Ordering ] ,
42+ ) -> Box < Expr > {
43+ let prefix = [ "atomic" , base_name] ;
44+ let suffix = orders. iter ( ) . map ( |& order| order_suffix ( order) ) ;
45+ let intrinsic_name = prefix. iter ( ) . copied ( ) . chain ( suffix) . join ( "_" ) ;
46+ mk ( ) . abs_path_expr ( vec ! [ "core" , "intrinsics" , & intrinsic_name] )
47+ }
48+
49+ fn atomic_intrinsic_expr_edition_2024 (
50+ & self ,
51+ base_name : & str ,
52+ orders : & [ Ordering ] ,
53+ ) -> Box < Expr > {
54+ let num_ty_params = match base_name {
55+ "fence" => 0 ,
56+ "load" | "store" | "xchg" | "cxchg" | "cxchgweak" => 1 ,
57+ "xadd" | "xsub" | "or" | "xor" | "nand" | "and" => 2 ,
58+ _ => unimplemented ! ( "unknown atomic intrinsic: {base_name}" ) ,
59+ } ;
60+
61+ let args = repeat_n ( "_" . to_owned ( ) , num_ty_params)
62+ . chain ( orders. iter ( ) . map ( |& order| {
63+ let order = order_ty_name ( order) ;
64+ format ! ( "{{ ::core::intrinsics::AtomicOrdering::{order} }}" )
65+ } ) )
66+ . join ( ", " ) ;
67+ let path = format ! ( "::core::intrinsics::atomic_{base_name}::<{args}>" ) ;
68+ // `mk()`/`Builder` doesn't seem to support const generic expressions,
69+ // so re-parsing with `syn` is simpler.
70+ let expr = syn:: parse_str :: < Expr > ( & path)
71+ . unwrap_or_else ( |_| panic ! ( "failed to parse intrinsic path: {path}" ) ) ;
72+ Box :: new ( expr)
73+ }
74+
75+ pub fn atomic_intrinsic_expr ( & self , base_name : & str , orders : & [ Ordering ] ) -> Box < Expr > {
76+ assert ! ( matches!(
77+ orders,
78+ & [ _ /* order */ ] | & [ _ /* order_succ */ , _ /* order_fail */ ]
79+ ) ) ;
80+
81+ self . use_feature ( "core_intrinsics" ) ;
82+ if self . tcfg . edition < Edition2024 {
83+ self . atomic_intrinsic_expr_edition_2021 ( base_name, orders)
84+ } else {
85+ self . atomic_intrinsic_expr_edition_2024 ( base_name, orders)
86+ }
87+ }
88+
89+ fn atomic_intrinsic_cxchg_expr (
90+ & self ,
91+ weak : bool ,
92+ order_succ : Ordering ,
93+ order_fail : Ordering ,
94+ ) -> Box < Expr > {
95+ let base = if weak { "cxchgweak" } else { "cxchg" } ;
96+ self . atomic_intrinsic_expr ( base, & [ order_succ, order_fail] )
97+ }
98+
799 fn convert_constant_bool ( & self , expr : CExprId ) -> Option < bool > {
8100 let val = self . ast_context . unwrap_cast_expr ( expr) ;
9101 match self . ast_context . index ( val) . kind {
@@ -70,28 +162,11 @@ impl<'c> Translation<'c> {
70162 } )
71163 }
72164
73- fn order_name ( order : Ordering ) -> & ' static str {
74- use Ordering :: * ;
75- match order {
76- SeqCst => "seqcst" ,
77- AcqRel => "acqrel" ,
78- Acquire => "acquire" ,
79- Release => "release" ,
80- Relaxed => "relaxed" ,
81- _ => unreachable ! (
82- "new variants added to `{}`" ,
83- std:: any:: type_name:: <Ordering >( )
84- ) ,
85- }
86- }
87-
88165 match name {
89166 "__atomic_load" | "__atomic_load_n" | "__c11_atomic_load" => ptr. and_then ( |ptr| {
90- let intrinsic_name = format ! ( "atomic_load_{}" , order_name ( static_order( order) ) ) ;
167+ let order = static_order ( order) ;
91168
92- self . use_feature ( "core_intrinsics" ) ;
93-
94- let atomic_load = mk ( ) . abs_path_expr ( vec ! [ "core" , "intrinsics" , & intrinsic_name] ) ;
169+ let atomic_load = self . atomic_intrinsic_expr ( "load" , & [ order] ) ;
95170 let call = mk ( ) . call_expr ( atomic_load, vec ! [ ptr] ) ;
96171 if name == "__atomic_load" {
97172 let ret = val1. expect ( "__atomic_load should have a ret argument" ) ;
@@ -116,16 +191,11 @@ impl<'c> Translation<'c> {
116191 } ) ,
117192
118193 "__atomic_store" | "__atomic_store_n" | "__c11_atomic_store" => {
194+ let order = static_order ( order) ;
119195 let val = val1. expect ( "__atomic_store must have a val argument" ) ;
120196 ptr. and_then ( |ptr| {
121197 val. and_then ( |val| {
122- let intrinsic_name =
123- format ! ( "atomic_store_{}" , order_name( static_order( order) ) ) ;
124-
125- self . use_feature ( "core_intrinsics" ) ;
126-
127- let atomic_store =
128- mk ( ) . abs_path_expr ( vec ! [ "core" , "intrinsics" , & intrinsic_name] ) ;
198+ let atomic_store = self . atomic_intrinsic_expr ( "store" , & [ order] ) ;
129199 let val = if name == "__atomic_store" {
130200 mk ( ) . unary_expr ( UnOp :: Deref ( Default :: default ( ) ) , val)
131201 } else {
@@ -160,16 +230,11 @@ impl<'c> Translation<'c> {
160230 }
161231
162232 "__atomic_exchange" | "__atomic_exchange_n" | "__c11_atomic_exchange" => {
233+ let order = static_order ( order) ;
163234 let val = val1. expect ( "__atomic_store must have a val argument" ) ;
164235 ptr. and_then ( |ptr| {
165236 val. and_then ( |val| {
166- let intrinsic_name =
167- format ! ( "atomic_xchg_{}" , order_name( static_order( order) ) ) ;
168-
169- self . use_feature ( "core_intrinsics" ) ;
170-
171- let fn_path =
172- mk ( ) . abs_path_expr ( vec ! [ "core" , "intrinsics" , & intrinsic_name] ) ;
237+ let fn_path = self . atomic_intrinsic_expr ( "xchg" , & [ order] ) ;
173238 let val = if name == "__atomic_exchange" {
174239 mk ( ) . unary_expr ( UnOp :: Deref ( Default :: default ( ) ) , val)
175240 } else {
@@ -218,14 +283,15 @@ impl<'c> Translation<'c> {
218283 _ => weak,
219284 } ;
220285
286+ let order = static_order ( order) ;
287+ let order_fail = static_order ( order_fail) ;
288+ let weak = static_order ( weak) ;
289+
221290 ptr. and_then ( |ptr| {
222291 expected. and_then ( |expected| {
223292 desired. and_then ( |desired| {
224- let weak = static_order ( weak) ;
225- let order = static_order ( order) ;
226- let order_fail = static_order ( order_fail) ;
227293 use Ordering :: * ;
228- let intrinsic_name = match ( order, order_fail) {
294+ let ( order , order_fail ) = match ( order, order_fail) {
229295 ( _, Release | AcqRel ) => None ,
230296 ( SeqCst , SeqCst | Acquire | Relaxed )
231297 | ( AcqRel , Acquire | Relaxed )
@@ -237,12 +303,6 @@ impl<'c> Translation<'c> {
237303
238304 ( _, _) => unreachable ! ( "Did we not handle a case above??" ) ,
239305 }
240- . map ( |( order, order_fail) | {
241- let weak = if weak { "weak" } else { "" } ;
242- let order = order_name ( order) ;
243- let order_fail = order_name ( order_fail) ;
244- format ! ( "atomic_cxchg{weak}_{order}_{order_fail}" )
245- } )
246306 . ok_or_else ( || {
247307 format_translation_err ! (
248308 self . ast_context
@@ -251,7 +311,6 @@ impl<'c> Translation<'c> {
251311 )
252312 } ) ?;
253313
254- self . use_feature ( "core_intrinsics" ) ;
255314 let expected =
256315 mk ( ) . unary_expr ( UnOp :: Deref ( Default :: default ( ) ) , expected) ;
257316 let desired = match name {
@@ -262,7 +321,7 @@ impl<'c> Translation<'c> {
262321 } ;
263322
264323 let atomic_cxchg =
265- mk ( ) . abs_path_expr ( vec ! [ "core" , "intrinsics" , & intrinsic_name ] ) ;
324+ self . atomic_intrinsic_cxchg_expr ( weak , order , order_fail ) ;
266325 let call =
267326 mk ( ) . call_expr ( atomic_cxchg, vec ! [ ptr, expected. clone( ) , desired] ) ;
268327 let res_name = self . renamer . borrow_mut ( ) . fresh ( ) ;
@@ -305,28 +364,27 @@ impl<'c> Translation<'c> {
305364 | "__c11_atomic_fetch_or"
306365 | "__c11_atomic_fetch_nand" => {
307366 let intrinsic_name = if name. contains ( "_add" ) {
308- "atomic_xadd "
367+ "xadd "
309368 } else if name. contains ( "_sub" ) {
310- "atomic_xsub "
369+ "xsub "
311370 } else if name. contains ( "_or" ) {
312- "atomic_or "
371+ "or "
313372 } else if name. contains ( "_xor" ) {
314- "atomic_xor "
373+ "xor "
315374 } else if name. contains ( "_nand" ) {
316- "atomic_nand "
375+ "nand "
317376 } else {
318- "atomic_and "
377+ "and "
319378 } ;
320379
321- let intrinsic_suffix = order_name ( static_order ( order) ) ;
322- let intrinsic_name = format ! ( "{intrinsic_name}_{intrinsic_suffix}" ) ;
380+ let order = static_order ( order) ;
323381
324382 let fetch_first =
325383 name. starts_with ( "__atomic_fetch" ) || name. starts_with ( "__c11_atomic_fetch" ) ;
326384 let val = val1. expect ( "__atomic arithmetic operations must have a val argument" ) ;
327385 ptr. and_then ( |ptr| {
328386 val. and_then ( |val| {
329- self . convert_atomic_op ( ctx, & intrinsic_name, ptr, val, fetch_first)
387+ self . convert_atomic_op ( ctx, intrinsic_name, order , ptr, val, fetch_first)
330388 } )
331389 } )
332390 }
@@ -338,16 +396,16 @@ impl<'c> Translation<'c> {
338396 pub ( crate ) fn convert_atomic_cxchg (
339397 & self ,
340398 ctx : ExprContext ,
341- intrinsic_name : & str ,
399+ weak : bool ,
400+ order_succ : Ordering ,
401+ order_fail : Ordering ,
342402 dst : Box < Expr > ,
343403 old_val : Box < Expr > ,
344404 src_val : Box < Expr > ,
345405 returns_val : bool ,
346406 ) -> TranslationResult < WithStmts < Box < Expr > > > {
347- self . use_feature ( "core_intrinsics" ) ;
348-
349407 // Emit `atomic_cxchg(a0, a1, a2).idx`
350- let atomic_cxchg = mk ( ) . abs_path_expr ( vec ! [ "core" , "intrinsics" , intrinsic_name ] ) ;
408+ let atomic_cxchg = self . atomic_intrinsic_cxchg_expr ( weak , order_succ , order_fail ) ;
351409 let call = mk ( ) . call_expr ( atomic_cxchg, vec ! [ dst, old_val, src_val] ) ;
352410 let field_idx = if returns_val { 0 } else { 1 } ;
353411 let call_expr = mk ( ) . anon_field_expr ( call, field_idx) ;
@@ -361,15 +419,14 @@ impl<'c> Translation<'c> {
361419 pub ( crate ) fn convert_atomic_op (
362420 & self ,
363421 ctx : ExprContext ,
364- func_name : & str ,
422+ base_name : & str ,
423+ order : Ordering ,
365424 dst : Box < Expr > ,
366425 src : Box < Expr > ,
367426 fetch_first : bool ,
368427 ) -> TranslationResult < WithStmts < Box < Expr > > > {
369- self . use_feature ( "core_intrinsics" ) ;
370-
371428 // Emit `atomic_func(a0, a1) (op a1)?`
372- let atomic_func = mk ( ) . abs_path_expr ( vec ! [ "core" , "intrinsics" , func_name ] ) ;
429+ let atomic_func = self . atomic_intrinsic_expr ( base_name , & [ order ] ) ;
373430
374431 if fetch_first {
375432 let call_expr = mk ( ) . call_expr ( atomic_func, vec ! [ dst, src] ) ;
@@ -379,20 +436,14 @@ impl<'c> Translation<'c> {
379436 "Builtin is not supposed to be used" ,
380437 )
381438 } else {
382- let ( binary_op, is_nand) = if func_name. starts_with ( "atomic_xadd" ) {
383- ( BinOp :: Add ( Default :: default ( ) ) , false )
384- } else if func_name. starts_with ( "atomic_xsub" ) {
385- ( BinOp :: Sub ( Default :: default ( ) ) , false )
386- } else if func_name. starts_with ( "atomic_or" ) {
387- ( BinOp :: BitOr ( Default :: default ( ) ) , false )
388- } else if func_name. starts_with ( "atomic_xor" ) {
389- ( BinOp :: BitXor ( Default :: default ( ) ) , false )
390- } else if func_name. starts_with ( "atomic_nand" ) {
391- ( BinOp :: BitAnd ( Default :: default ( ) ) , true )
392- } else if func_name. starts_with ( "atomic_and" ) {
393- ( BinOp :: BitAnd ( Default :: default ( ) ) , false )
394- } else {
395- panic ! ( "Unexpected atomic intrinsic name: {}" , func_name)
439+ let ( binary_op, is_nand) = match base_name {
440+ "xadd" => ( BinOp :: Add ( Default :: default ( ) ) , false ) ,
441+ "xsub" => ( BinOp :: Sub ( Default :: default ( ) ) , false ) ,
442+ "or" => ( BinOp :: BitOr ( Default :: default ( ) ) , false ) ,
443+ "xor" => ( BinOp :: BitXor ( Default :: default ( ) ) , false ) ,
444+ "nand" => ( BinOp :: BitAnd ( Default :: default ( ) ) , true ) ,
445+ "and" => ( BinOp :: BitAnd ( Default :: default ( ) ) , false ) ,
446+ _ => panic ! ( "Unexpected atomic intrinsic base name: {base_name}" ) ,
396447 } ;
397448
398449 // Since the value of `arg1` is used twice, we need to copy
0 commit comments