The attached change re-integrates long long support into linux-atomic.c. This is possible due a kernel fix to the LWS syscall and a middle-end fix to expand_atomic_compare_and_swap.
The patch corrects the inverted value returned by __sync_bool_compare_and_swap_##WIDTH. It revises the return value check order in __kernel_cmpxchg2 to improve the fast path. Finally, the return value types used to store results of __kernel_cmpxchg and __kernel_cmpxchg2 have been changed to long to match the type returned by these calls. Tested on hppa-unknown-linux-gn with no regressions. Committed to trunk, gcc-5 and gcc-4.9 branches. Dave -- John David Anglin dave.ang...@bell.net
2015-09-23 John David Anglin <dang...@gcc.gnu.org> * config/pa/linux-atomic.c (__kernel_cmpxchg2): Reorder error checks. (__sync_fetch_and_##OP##_##WIDTH): Change result to match type of __kernel_cmpxchg2. (__sync_##OP##_and_fetch_##WIDTH): Likewise. (__sync_val_compare_and_swap_##WIDTH): Likewise. (__sync_bool_compare_and_swap_##WIDTH): Likewise. (__sync_lock_test_and_set_##WIDTH): Likewise. (__sync_lock_release_##WIDTH): Likewise. (__sync_fetch_and_##OP##_4): Change result to match type of __kernel_cmpxchg. (__sync_##OP##_and_fetch_4): Likewise. (__sync_val_compare_and_swap_4): Likewise. (__sync_bool_compare_and_swap_4): likewise. (__sync_lock_test_and_set_4): Likewise. (__sync_lock_release_4): Likewise. (FETCH_AND_OP_2): Add long long variants. (OP_AND_FETCH_2): Likewise. (COMPARE_AND_SWAP_2 ): Likewise. (SYNC_LOCK_TEST_AND_SET_2): Likewise. (SYNC_LOCK_RELEASE_2): Likewise. (__sync_bool_compare_and_swap_##WIDTH): Correct return. Index: config/pa/linux-atomic.c =================================================================== --- config/pa/linux-atomic.c (revision 227986) +++ config/pa/linux-atomic.c (working copy) @@ -88,12 +88,17 @@ : "i" (2) : "r1", "r20", "r22", "r29", "r31", "fr4", "memory" ); + + /* If the kernel LWS call is successful, lws_ret contains 0. */ + if (__builtin_expect (lws_ret == 0, 1)) + return 0; + if (__builtin_expect (lws_errno == -EFAULT || lws_errno == -ENOSYS, 0)) __builtin_trap (); - /* If the kernel LWS call fails, return EBUSY */ - if (!lws_errno && lws_ret) - lws_errno = -EBUSY; + /* If the kernel LWS call fails with no error, return -EBUSY */ + if (__builtin_expect (!lws_errno, 0)) + return -EBUSY; return lws_errno; } @@ -111,7 +116,7 @@ __sync_fetch_and_##OP##_##WIDTH (TYPE *ptr, TYPE val) \ { \ TYPE tmp, newval; \ - int failure; \ + long failure; \ \ do { \ tmp = __atomic_load_n (ptr, __ATOMIC_SEQ_CST); \ @@ -122,6 +127,13 @@ return tmp; \ } +FETCH_AND_OP_2 (add, , +, long long, 8, 3) +FETCH_AND_OP_2 (sub, , -, long long, 8, 3) +FETCH_AND_OP_2 (or, , |, long long, 8, 3) +FETCH_AND_OP_2 (and, , &, long long, 8, 3) +FETCH_AND_OP_2 (xor, , ^, long long, 8, 3) +FETCH_AND_OP_2 (nand, ~, &, long long, 8, 3) + FETCH_AND_OP_2 (add, , +, short, 2, 1) FETCH_AND_OP_2 (sub, , -, short, 2, 1) FETCH_AND_OP_2 (or, , |, short, 2, 1) @@ -141,7 +153,7 @@ __sync_##OP##_and_fetch_##WIDTH (TYPE *ptr, TYPE val) \ { \ TYPE tmp, newval; \ - int failure; \ + long failure; \ \ do { \ tmp = __atomic_load_n (ptr, __ATOMIC_SEQ_CST); \ @@ -152,6 +164,13 @@ return PFX_OP (tmp INF_OP val); \ } +OP_AND_FETCH_2 (add, , +, long long, 8, 3) +OP_AND_FETCH_2 (sub, , -, long long, 8, 3) +OP_AND_FETCH_2 (or, , |, long long, 8, 3) +OP_AND_FETCH_2 (and, , &, long long, 8, 3) +OP_AND_FETCH_2 (xor, , ^, long long, 8, 3) +OP_AND_FETCH_2 (nand, ~, &, long long, 8, 3) + OP_AND_FETCH_2 (add, , +, short, 2, 1) OP_AND_FETCH_2 (sub, , -, short, 2, 1) OP_AND_FETCH_2 (or, , |, short, 2, 1) @@ -170,7 +189,8 @@ int HIDDEN \ __sync_fetch_and_##OP##_4 (int *ptr, int val) \ { \ - int failure, tmp; \ + int tmp; \ + long failure; \ \ do { \ tmp = __atomic_load_n (ptr, __ATOMIC_SEQ_CST); \ @@ -191,7 +211,8 @@ int HIDDEN \ __sync_##OP##_and_fetch_4 (int *ptr, int val) \ { \ - int tmp, failure; \ + int tmp; \ + long failure; \ \ do { \ tmp = __atomic_load_n (ptr, __ATOMIC_SEQ_CST); \ @@ -216,7 +237,7 @@ TYPE newval) \ { \ TYPE actual_oldval; \ - int fail; \ + long fail; \ \ while (1) \ { \ @@ -236,10 +257,11 @@ __sync_bool_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval, \ TYPE newval) \ { \ - int failure = __kernel_cmpxchg2 (ptr, &oldval, &newval, INDEX); \ - return (failure != 0); \ + long failure = __kernel_cmpxchg2 (ptr, &oldval, &newval, INDEX); \ + return (failure == 0); \ } +COMPARE_AND_SWAP_2 (long long, 8, 3) COMPARE_AND_SWAP_2 (short, 2, 1) COMPARE_AND_SWAP_2 (char, 1, 0) @@ -246,7 +268,8 @@ int HIDDEN __sync_val_compare_and_swap_4 (int *ptr, int oldval, int newval) { - int actual_oldval, fail; + long fail; + int actual_oldval; while (1) { @@ -265,7 +288,7 @@ bool HIDDEN __sync_bool_compare_and_swap_4 (int *ptr, int oldval, int newval) { - int failure = __kernel_cmpxchg (ptr, oldval, newval); + long failure = __kernel_cmpxchg (ptr, oldval, newval); return (failure == 0); } @@ -274,7 +297,7 @@ __sync_lock_test_and_set_##WIDTH (TYPE *ptr, TYPE val) \ { \ TYPE oldval; \ - int failure; \ + long failure; \ \ do { \ oldval = __atomic_load_n (ptr, __ATOMIC_SEQ_CST); \ @@ -284,6 +307,7 @@ return oldval; \ } +SYNC_LOCK_TEST_AND_SET_2 (long long, 8, 3) SYNC_LOCK_TEST_AND_SET_2 (short, 2, 1) SYNC_LOCK_TEST_AND_SET_2 (signed char, 1, 0) @@ -290,7 +314,8 @@ int HIDDEN __sync_lock_test_and_set_4 (int *ptr, int val) { - int failure, oldval; + long failure; + int oldval; do { oldval = __atomic_load_n (ptr, __ATOMIC_SEQ_CST); @@ -304,7 +329,8 @@ void HIDDEN \ __sync_lock_release_##WIDTH (TYPE *ptr) \ { \ - TYPE failure, oldval, zero = 0; \ + TYPE oldval, zero = 0; \ + long failure; \ \ do { \ oldval = __atomic_load_n (ptr, __ATOMIC_SEQ_CST); \ @@ -312,6 +338,7 @@ } while (failure != 0); \ } +SYNC_LOCK_RELEASE_2 (long long, 8, 3) SYNC_LOCK_RELEASE_2 (short, 2, 1) SYNC_LOCK_RELEASE_2 (signed char, 1, 0) @@ -318,7 +345,8 @@ void HIDDEN __sync_lock_release_4 (int *ptr) { - int failure, oldval; + long failure; + int oldval; do { oldval = __atomic_load_n (ptr, __ATOMIC_SEQ_CST);