@@ -2447,6 +2447,72 @@ static long double eval_double(Node *node) {
24472447 return eval_error (node -> tok , "not a compile-time constant" );
24482448}
24492449
2450+ static Node * atomic_op (Node * binary , bool return_old ) {
2451+ // ({
2452+ // T *addr = &obj; T old = *addr; T new;
2453+ // do {
2454+ // new = old op val;
2455+ // } while (!atomic_compare_exchange_strong(addr, &old, new));
2456+ //
2457+ // return_old ? old : new;
2458+ // })
2459+ Token * tok = binary -> tok ;
2460+ Node head = {0 };
2461+ Node * cur = & head ;
2462+
2463+ Obj * addr = new_lvar (NULL , pointer_to (binary -> lhs -> ty ));
2464+ Obj * val = new_lvar (NULL , binary -> rhs -> ty );
2465+ Obj * old = new_lvar (NULL , binary -> lhs -> ty );
2466+ Obj * new = new_lvar (NULL , binary -> lhs -> ty );
2467+
2468+ cur = cur -> next =
2469+ new_unary (ND_EXPR_STMT ,
2470+ new_binary (ND_ASSIGN , new_var_node (addr , tok ),
2471+ new_unary (ND_ADDR , binary -> lhs , tok ), tok ),
2472+ tok );
2473+
2474+ cur = cur -> next =
2475+ new_unary (ND_EXPR_STMT ,
2476+ new_binary (ND_ASSIGN , new_var_node (val , tok ), binary -> rhs , tok ),
2477+ tok );
2478+
2479+ cur = cur -> next =
2480+ new_unary (ND_EXPR_STMT ,
2481+ new_binary (ND_ASSIGN , new_var_node (old , tok ),
2482+ new_unary (ND_DEREF , new_var_node (addr , tok ), tok ), tok ),
2483+ tok );
2484+
2485+ Node * loop = new_node (ND_DO , tok );
2486+ loop -> brk_label = new_unique_name ();
2487+ loop -> cont_label = new_unique_name ();
2488+
2489+ Node * body = new_binary (ND_ASSIGN ,
2490+ new_var_node (new , tok ),
2491+ new_binary (binary -> kind , new_var_node (old , tok ),
2492+ new_var_node (val , tok ), tok ),
2493+ tok );
2494+
2495+ loop -> then = new_node (ND_BLOCK , tok );
2496+ loop -> then -> body = new_unary (ND_EXPR_STMT , body , tok );
2497+
2498+ Node * cas = new_node (ND_CAS , tok );
2499+ cas -> cas_addr = new_var_node (addr , tok );
2500+ cas -> cas_old = new_unary (ND_ADDR , new_var_node (old , tok ), tok );
2501+ cas -> cas_new = new_var_node (new , tok );
2502+ loop -> cond = new_unary (ND_NOT , cas , tok );
2503+
2504+ cur = cur -> next = loop ;
2505+
2506+ if (return_old )
2507+ cur -> next = new_unary (ND_EXPR_STMT , new_var_node (old , tok ), tok );
2508+ else
2509+ cur -> next = new_unary (ND_EXPR_STMT , new_var_node (new , tok ), tok );
2510+
2511+ Node * node = new_node (ND_STMT_EXPR , tok );
2512+ node -> body = head .next ;
2513+ return node ;
2514+ }
2515+
24502516// Convert op= operators to expressions containing an assignment.
24512517//
24522518// In general, `A op= C` is converted to ``tmp = &A, *tmp = *tmp op B`.
@@ -2458,6 +2524,10 @@ static Node *to_assign(Node *binary) {
24582524 add_type (binary -> rhs );
24592525 Token * tok = binary -> tok ;
24602526
2527+ // If A is an atomic type, Convert `A op= B` to atomic_op_fetch(&A, B)
2528+ if (binary -> lhs -> ty -> is_atomic )
2529+ return atomic_op (binary , false);
2530+
24612531 // Convert `A.x op= C` to `tmp = &A, (*tmp).x = (*tmp).x op C`.
24622532 if (is_bitfield (binary -> lhs )) {
24632533 Obj * var = new_lvar (NULL , pointer_to (binary -> lhs -> lhs -> ty ));
@@ -2482,68 +2552,6 @@ static Node *to_assign(Node *binary) {
24822552 return new_binary (ND_CHAIN , expr1 , expr4 , tok );
24832553 }
24842554
2485- // If A is an atomic type, Convert `A op= B` to
2486- //
2487- // ({
2488- // T1 *addr = &A; T2 val = (B); T1 old = *addr; T1 new;
2489- // do {
2490- // new = old op val;
2491- // } while (!atomic_compare_exchange_strong(addr, &old, new));
2492- // new;
2493- // })
2494- if (binary -> lhs -> ty -> is_atomic ) {
2495- Node head = {0 };
2496- Node * cur = & head ;
2497-
2498- Obj * addr = new_lvar (NULL , pointer_to (binary -> lhs -> ty ));
2499- Obj * val = new_lvar (NULL , binary -> rhs -> ty );
2500- Obj * old = new_lvar (NULL , binary -> lhs -> ty );
2501- Obj * new = new_lvar (NULL , binary -> lhs -> ty );
2502-
2503- cur = cur -> next =
2504- new_unary (ND_EXPR_STMT ,
2505- new_binary (ND_ASSIGN , new_var_node (addr , tok ),
2506- new_unary (ND_ADDR , binary -> lhs , tok ), tok ),
2507- tok );
2508-
2509- cur = cur -> next =
2510- new_unary (ND_EXPR_STMT ,
2511- new_binary (ND_ASSIGN , new_var_node (val , tok ), binary -> rhs , tok ),
2512- tok );
2513-
2514- cur = cur -> next =
2515- new_unary (ND_EXPR_STMT ,
2516- new_binary (ND_ASSIGN , new_var_node (old , tok ),
2517- new_unary (ND_DEREF , new_var_node (addr , tok ), tok ), tok ),
2518- tok );
2519-
2520- Node * loop = new_node (ND_DO , tok );
2521- loop -> brk_label = new_unique_name ();
2522- loop -> cont_label = new_unique_name ();
2523-
2524- Node * body = new_binary (ND_ASSIGN ,
2525- new_var_node (new , tok ),
2526- new_binary (binary -> kind , new_var_node (old , tok ),
2527- new_var_node (val , tok ), tok ),
2528- tok );
2529-
2530- loop -> then = new_node (ND_BLOCK , tok );
2531- loop -> then -> body = new_unary (ND_EXPR_STMT , body , tok );
2532-
2533- Node * cas = new_node (ND_CAS , tok );
2534- cas -> cas_addr = new_var_node (addr , tok );
2535- cas -> cas_old = new_unary (ND_ADDR , new_var_node (old , tok ), tok );
2536- cas -> cas_new = new_var_node (new , tok );
2537- loop -> cond = new_unary (ND_NOT , cas , tok );
2538-
2539- cur = cur -> next = loop ;
2540- cur = cur -> next = new_unary (ND_EXPR_STMT , new_var_node (new , tok ), tok );
2541-
2542- Node * node = new_node (ND_STMT_EXPR , tok );
2543- node -> body = head .next ;
2544- return node ;
2545- }
2546-
25472555 // Convert `A op= B` to ``tmp = &A, *tmp = *tmp op B`.
25482556 Obj * var = new_lvar (NULL , pointer_to (binary -> lhs -> ty ));
25492557
@@ -3563,6 +3571,36 @@ static Node *primary(Token **rest, Token *tok) {
35633571 return node ;
35643572 }
35653573
3574+ if (!strncmp (tok -> loc , "__builtin_atomic_fetch_" , 23 )) {
3575+ Token * start = tok ;
3576+ tok = skip (tok -> next , "(" );
3577+ Node * obj = new_unary (ND_DEREF , assign (& tok , tok ), start );
3578+ tok = skip (tok , "," );
3579+ Node * val = assign (& tok , tok );
3580+ * rest = skip (tok , ")" );
3581+
3582+ Node * binary ;
3583+ char * loc = start -> loc + 23 ;
3584+ int len = start -> len - 23 ;
3585+
3586+ if (!strncmp ("add" , loc , len ))
3587+ binary = new_add (obj , val , start );
3588+ else if (!strncmp ("sub" , loc , len ))
3589+ binary = new_sub (obj , val , start );
3590+ else if (!strncmp ("and" , loc , len ))
3591+ binary = new_binary (ND_BITAND , obj , val , start );
3592+ else if (!strncmp ("or" , loc , len ))
3593+ binary = new_binary (ND_BITOR , obj , val , start );
3594+ else if (!strncmp ("xor" , loc , len ))
3595+ binary = new_binary (ND_BITXOR , obj , val , start );
3596+ else
3597+ error_tok (start , "unsupported atomic fetch op" );
3598+
3599+ add_type (binary -> lhs );
3600+ add_type (binary -> rhs );
3601+ return atomic_op (binary , true);
3602+ }
3603+
35663604 if (equal (tok , "__builtin_offsetof" )) {
35673605 tok = skip (tok -> next , "(" );
35683606 Type * ty = typename (& tok , tok );
0 commit comments