Skip to content

Commit 62a00f3

Browse files
committed
Fix atomic_fetch_op return value
as reported by rui314/chibicc#101
1 parent 4ff76a9 commit 62a00f3

File tree

2 files changed

+110
-72
lines changed

2 files changed

+110
-72
lines changed

include/stdatomic.h

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,17 @@ typedef enum {
3434
#define atomic_load_explicit(addr, order) (*(addr))
3535
#define atomic_store_explicit(addr, val, order) (*(addr) = (val))
3636

37-
#define atomic_fetch_add(obj, val) (*(obj) += (val))
38-
#define atomic_fetch_sub(obj, val) (*(obj) -= (val))
39-
#define atomic_fetch_or(obj, val) (*(obj) |= (val))
40-
#define atomic_fetch_xor(obj, val) (*(obj) ^= (val))
41-
#define atomic_fetch_and(obj, val) (*(obj) &= (val))
37+
#define atomic_fetch_add(addr, val) __builtin_atomic_fetch_add(addr, val)
38+
#define atomic_fetch_sub(addr, val) __builtin_atomic_fetch_sub(addr, val)
39+
#define atomic_fetch_or(addr, val) __builtin_atomic_fetch_or(addr, val)
40+
#define atomic_fetch_xor(addr, val) __builtin_atomic_fetch_xor(addr, val)
41+
#define atomic_fetch_and(addr, val) __builtin_atomic_fetch_and(addr, val)
4242

43-
#define atomic_fetch_add_explicit(obj, val, order) (*(obj) += (val))
44-
#define atomic_fetch_sub_explicit(obj, val, order) (*(obj) -= (val))
45-
#define atomic_fetch_or_explicit(obj, val, order) (*(obj) |= (val))
46-
#define atomic_fetch_xor_explicit(obj, val, order) (*(obj) ^= (val))
47-
#define atomic_fetch_and_explicit(obj, val, order) (*(obj) &= (val))
43+
#define atomic_fetch_add_explicit(addr, val, order) __builtin_atomic_fetch_add(addr, val)
44+
#define atomic_fetch_sub_explicit(addr, val, order) __builtin_atomic_fetch_sub(addr, val)
45+
#define atomic_fetch_or_explicit(addr, val, order) __builtin_atomic_fetch_or(addr, val)
46+
#define atomic_fetch_xor_explicit(addr, val, order) __builtin_atomic_fetch_xor(addr, val)
47+
#define atomic_fetch_and_explicit(addr, val, order) __builtin_atomic_fetch_and(addr, val)
4848

4949
#define atomic_compare_exchange_weak(p, old, new) \
5050
__builtin_compare_and_swap((p), (old), (new))

parse.c

Lines changed: 100 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)