[OpenMP] libomp: add atomic functions for new OpenMP 5.1 atomics.

Added functions those implement "atomic compare".
Though clang does not use library interfaces to implement OpenMP atomics,
the functions added for consistency.
Also added missed functions for 80-bit floating min/max atomics.

Differential Revision: https://reviews.llvm.org/D110109
This commit is contained in:
AndreyChurbanov 2021-10-13 21:02:18 +03:00
parent 2de43d4202
commit 621d7a75b1
6 changed files with 829 additions and 0 deletions

View File

@ -1221,6 +1221,29 @@ kmp_set_disp_num_buffers 890
__kmpc_atomic_fixed8u_mul_fp
%endif
# OpenMP 5.1 atomics
__kmpc_atomic_float10_max 2139
__kmpc_atomic_float10_min 2140
__kmpc_atomic_float10_max_cpt 2141
__kmpc_atomic_float10_min_cpt 2142
__kmpc_atomic_bool_1_cas 2143
__kmpc_atomic_bool_2_cas 2144
__kmpc_atomic_bool_4_cas 2145
__kmpc_atomic_bool_8_cas 2146
__kmpc_atomic_val_1_cas 2147
__kmpc_atomic_val_2_cas 2148
__kmpc_atomic_val_4_cas 2149
__kmpc_atomic_val_8_cas 2150
__kmpc_atomic_bool_1_cas_cpt 2151
__kmpc_atomic_bool_2_cas_cpt 2152
__kmpc_atomic_bool_4_cas_cpt 2153
__kmpc_atomic_bool_8_cas_cpt 2154
__kmpc_atomic_val_1_cas_cpt 2155
__kmpc_atomic_val_2_cas_cpt 2156
__kmpc_atomic_val_4_cas_cpt 2157
__kmpc_atomic_val_8_cas_cpt 2158
%endif
# end of file #

View File

@ -1235,6 +1235,10 @@ MIN_MAX_COMPXCHG(float8, max, kmp_real64, 64, <, 8r, 7,
KMP_ARCH_X86) // __kmpc_atomic_float8_max
MIN_MAX_COMPXCHG(float8, min, kmp_real64, 64, >, 8r, 7,
KMP_ARCH_X86) // __kmpc_atomic_float8_min
MIN_MAX_CRITICAL(float10, max, long double, <, 10r,
1) // __kmpc_atomic_float10_max
MIN_MAX_CRITICAL(float10, min, long double, >, 10r,
1) // __kmpc_atomic_float10_min
#if KMP_HAVE_QUAD
MIN_MAX_CRITICAL(float16, max, QUAD_LEGACY, <, 16r,
1) // __kmpc_atomic_float16_max
@ -2717,6 +2721,10 @@ MIN_MAX_COMPXCHG_CPT(float8, max_cpt, kmp_real64, 64, <,
KMP_ARCH_X86) // __kmpc_atomic_float8_max_cpt
MIN_MAX_COMPXCHG_CPT(float8, min_cpt, kmp_real64, 64, >,
KMP_ARCH_X86) // __kmpc_atomic_float8_min_cpt
MIN_MAX_CRITICAL_CPT(float10, max_cpt, long double, <, 10r,
1) // __kmpc_atomic_float10_max_cpt
MIN_MAX_CRITICAL_CPT(float10, min_cpt, long double, >, 10r,
1) // __kmpc_atomic_float10_min_cpt
#if KMP_HAVE_QUAD
MIN_MAX_CRITICAL_CPT(float16, max_cpt, QUAD_LEGACY, <, 16r,
1) // __kmpc_atomic_float16_max_cpt
@ -3686,6 +3694,168 @@ void __kmpc_atomic_end(void) {
__kmp_release_atomic_lock(&__kmp_atomic_lock, gtid);
}
// OpenMP 5.1 compare and swap
/*!
@param loc Source code location
@param gtid Global thread id
@param x Memory location to operate on
@param e Expected value
@param d Desired value
@return Result of comparison
Implements Compare And Swap atomic operation.
Sample code:
#pragma omp atomic compare update capture
{ r = x == e; if(r) { x = d; } }
*/
bool __kmpc_atomic_bool_1_cas(ident_t *loc, int gtid, char *x, char e, char d) {
return KMP_COMPARE_AND_STORE_ACQ8(x, e, d);
}
bool __kmpc_atomic_bool_2_cas(ident_t *loc, int gtid, short *x, short e,
short d) {
return KMP_COMPARE_AND_STORE_ACQ16(x, e, d);
}
bool __kmpc_atomic_bool_4_cas(ident_t *loc, int gtid, kmp_int32 *x, kmp_int32 e,
kmp_int32 d) {
return KMP_COMPARE_AND_STORE_ACQ32(x, e, d);
}
bool __kmpc_atomic_bool_8_cas(ident_t *loc, int gtid, kmp_int64 *x, kmp_int64 e,
kmp_int64 d) {
return KMP_COMPARE_AND_STORE_ACQ64(x, e, d);
}
/*!
@param loc Source code location
@param gtid Global thread id
@param x Memory location to operate on
@param e Expected value
@param d Desired value
@return Old value of x
Implements Compare And Swap atomic operation.
Sample code:
#pragma omp atomic compare update capture
{ v = x; if (x == e) { x = d; } }
*/
char __kmpc_atomic_val_1_cas(ident_t *loc, int gtid, char *x, char e, char d) {
return KMP_COMPARE_AND_STORE_RET8(x, e, d);
}
short __kmpc_atomic_val_2_cas(ident_t *loc, int gtid, short *x, short e,
short d) {
return KMP_COMPARE_AND_STORE_RET16(x, e, d);
}
kmp_int32 __kmpc_atomic_val_4_cas(ident_t *loc, int gtid, kmp_int32 *x,
kmp_int32 e, kmp_int32 d) {
return KMP_COMPARE_AND_STORE_RET32(x, e, d);
}
kmp_int64 __kmpc_atomic_val_8_cas(ident_t *loc, int gtid, kmp_int64 *x,
kmp_int64 e, kmp_int64 d) {
return KMP_COMPARE_AND_STORE_RET64(x, e, d);
}
/*!
@param loc Source code location
@param gtid Global thread id
@param x Memory location to operate on
@param e Expected value
@param d Desired value
@param pv Captured value location
@return Result of comparison
Implements Compare And Swap + Capture atomic operation.
v gets old valie of x if comparison failed, untouched otherwise.
Sample code:
#pragma omp atomic compare update capture
{ r = x == e; if(r) { x = d; } else { v = x; } }
*/
bool __kmpc_atomic_bool_1_cas_cpt(ident_t *loc, int gtid, char *x, char e,
char d, char *pv) {
char old = KMP_COMPARE_AND_STORE_RET8(x, e, d);
if (old == e)
return true;
KMP_ASSERT(pv != NULL);
*pv = old;
return false;
}
bool __kmpc_atomic_bool_2_cas_cpt(ident_t *loc, int gtid, short *x, short e,
short d, short *pv) {
short old = KMP_COMPARE_AND_STORE_RET16(x, e, d);
if (old == e)
return true;
KMP_ASSERT(pv != NULL);
*pv = old;
return false;
}
bool __kmpc_atomic_bool_4_cas_cpt(ident_t *loc, int gtid, kmp_int32 *x,
kmp_int32 e, kmp_int32 d, kmp_int32 *pv) {
kmp_int32 old = KMP_COMPARE_AND_STORE_RET32(x, e, d);
if (old == e)
return true;
KMP_ASSERT(pv != NULL);
*pv = old;
return false;
}
bool __kmpc_atomic_bool_8_cas_cpt(ident_t *loc, int gtid, kmp_int64 *x,
kmp_int64 e, kmp_int64 d, kmp_int64 *pv) {
kmp_int64 old = KMP_COMPARE_AND_STORE_RET64(x, e, d);
if (old == e)
return true;
KMP_ASSERT(pv != NULL);
*pv = old;
return false;
}
/*!
@param loc Source code location
@param gtid Global thread id
@param x Memory location to operate on
@param e Expected value
@param d Desired value
@param pv Captured value location
@return Old value of x
Implements Compare And Swap + Capture atomic operation.
v gets new valie of x.
Sample code:
#pragma omp atomic compare update capture
{ if (x == e) { x = d; }; v = x; }
*/
char __kmpc_atomic_val_1_cas_cpt(ident_t *loc, int gtid, char *x, char e,
char d, char *pv) {
char old = KMP_COMPARE_AND_STORE_RET8(x, e, d);
KMP_ASSERT(pv != NULL);
*pv = old == e ? d : old;
return old;
}
short __kmpc_atomic_val_2_cas_cpt(ident_t *loc, int gtid, short *x, short e,
short d, short *pv) {
short old = KMP_COMPARE_AND_STORE_RET16(x, e, d);
KMP_ASSERT(pv != NULL);
*pv = old == e ? d : old;
return old;
}
kmp_int32 __kmpc_atomic_val_4_cas_cpt(ident_t *loc, int gtid, kmp_int32 *x,
kmp_int32 e, kmp_int32 d, kmp_int32 *pv) {
kmp_int32 old = KMP_COMPARE_AND_STORE_RET32(x, e, d);
KMP_ASSERT(pv != NULL);
*pv = old == e ? d : old;
return old;
}
kmp_int64 __kmpc_atomic_val_8_cas_cpt(ident_t *loc, int gtid, kmp_int64 *x,
kmp_int64 e, kmp_int64 d, kmp_int64 *pv) {
kmp_int64 old = KMP_COMPARE_AND_STORE_RET64(x, e, d);
KMP_ASSERT(pv != NULL);
*pv = old == e ? d : old;
return old;
}
// End OpenMP 5.1 compare + capture
/*!
@}
*/

View File

@ -578,6 +578,10 @@ void __kmpc_atomic_float8_max(ident_t *id_ref, int gtid, kmp_real64 *lhs,
kmp_real64 rhs);
void __kmpc_atomic_float8_min(ident_t *id_ref, int gtid, kmp_real64 *lhs,
kmp_real64 rhs);
void __kmpc_atomic_float10_max(ident_t *id_ref, int gtid, long double *lhs,
long double rhs);
void __kmpc_atomic_float10_min(ident_t *id_ref, int gtid, long double *lhs,
long double rhs);
#if KMP_HAVE_QUAD
void __kmpc_atomic_float16_max(ident_t *id_ref, int gtid, QUAD_LEGACY *lhs,
QUAD_LEGACY rhs);
@ -1254,6 +1258,12 @@ kmp_real64 __kmpc_atomic_float8_max_cpt(ident_t *id_ref, int gtid,
kmp_real64 __kmpc_atomic_float8_min_cpt(ident_t *id_ref, int gtid,
kmp_real64 *lhs, kmp_real64 rhs,
int flag);
long double __kmpc_atomic_float10_max_cpt(ident_t *id_ref, int gtid,
long double *lhs, long double rhs,
int flag);
long double __kmpc_atomic_float10_min_cpt(ident_t *id_ref, int gtid,
long double *lhs, long double rhs,
int flag);
#if KMP_HAVE_QUAD
QUAD_LEGACY __kmpc_atomic_float16_max_cpt(ident_t *id_ref, int gtid,
QUAD_LEGACY *lhs, QUAD_LEGACY rhs,
@ -1756,6 +1766,78 @@ long double __kmpc_atomic_float10_div_cpt_rev_fp(ident_t *id_ref, int gtid,
// End of OpenMP 4.0 capture
// OpenMP 5.1 compare and swap
/*
__kmpc_atomic_bool_1_cas
__kmpc_atomic_bool_2_cas
__kmpc_atomic_bool_4_cas
__kmpc_atomic_bool_8_cas
__kmpc_atomic_val_1_cas
__kmpc_atomic_val_2_cas
__kmpc_atomic_val_4_cas
__kmpc_atomic_val_8_cas
__kmpc_atomic_bool_1_cas_cpt
__kmpc_atomic_bool_2_cas_cpt
__kmpc_atomic_bool_4_cas_cpt
__kmpc_atomic_bool_8_cas_cpt
__kmpc_atomic_val_1_cas_cpt
__kmpc_atomic_val_2_cas_cpt
__kmpc_atomic_val_4_cas_cpt
__kmpc_atomic_val_8_cas_cpt
*/
// In all interfaces of CAS (Compare And Swap):
// r is the boolean result of comparison
// x is memory location to operate on
// e is expected (old) value
// d is desired (new) value
// pv is pointer to captured value v whose location may coincide with e
// { r = x == e; if(r) { x = d; } }
// functions return result of comparison
bool __kmpc_atomic_bool_1_cas(ident_t *loc, int gtid, char *x, char e, char d);
bool __kmpc_atomic_bool_2_cas(ident_t *loc, int gtid, short *x, short e,
short d);
bool __kmpc_atomic_bool_4_cas(ident_t *loc, int gtid, kmp_int32 *x, kmp_int32 e,
kmp_int32 d);
bool __kmpc_atomic_bool_8_cas(ident_t *loc, int gtid, kmp_int64 *x, kmp_int64 e,
kmp_int64 d);
// { v = x; if (x == e) { x = d; } }
// functions return old value
char __kmpc_atomic_val_1_cas(ident_t *loc, int gtid, char *x, char e, char d);
short __kmpc_atomic_val_2_cas(ident_t *loc, int gtid, short *x, short e,
short d);
kmp_int32 __kmpc_atomic_val_4_cas(ident_t *loc, int gtid, kmp_int32 *x,
kmp_int32 e, kmp_int32 d);
kmp_int64 __kmpc_atomic_val_8_cas(ident_t *loc, int gtid, kmp_int64 *x,
kmp_int64 e, kmp_int64 d);
// { r = x == e; if(r) { x = d; } else { v = x; } }
// v gets old value if comparison failed, untouched otherwise
// functions return result of comparison
bool __kmpc_atomic_bool_1_cas_cpt(ident_t *loc, int gtid, char *x, char e,
char d, char *pv);
bool __kmpc_atomic_bool_2_cas_cpt(ident_t *loc, int gtid, short *x, short e,
short d, short *pv);
bool __kmpc_atomic_bool_4_cas_cpt(ident_t *loc, int gtid, kmp_int32 *x,
kmp_int32 e, kmp_int32 d, kmp_int32 *pv);
bool __kmpc_atomic_bool_8_cas_cpt(ident_t *loc, int gtid, kmp_int64 *x,
kmp_int64 e, kmp_int64 d, kmp_int64 *pv);
// { if (x == e) { x = d; }; v = x; }
// v gets old value if comparison failed, new value otherwise
// functions return old value
char __kmpc_atomic_val_1_cas_cpt(ident_t *loc, int gtid, char *x, char e,
char d, char *pv);
short __kmpc_atomic_val_2_cas_cpt(ident_t *loc, int gtid, short *x, short e,
short d, short *pv);
kmp_int32 __kmpc_atomic_val_4_cas_cpt(ident_t *loc, int gtid, kmp_int32 *x,
kmp_int32 e, kmp_int32 d, kmp_int32 *pv);
kmp_int64 __kmpc_atomic_val_8_cas_cpt(ident_t *loc, int gtid, kmp_int64 *x,
kmp_int64 e, kmp_int64 d, kmp_int64 *pv);
// End OpenMP 5.1 compare + capture
#endif // KMP_ARCH_X86 || KMP_ARCH_X86_64
/* ------------------------------------------------------------------------ */

View File

@ -0,0 +1,180 @@
// RUN: %libomp-compile-and-run
#include <stdio.h>
#include <stdbool.h>
#include <omp.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef void* ident_t;
extern bool
__kmpc_atomic_bool_1_cas(ident_t *loc, int gtid, char *x, char e, char d);
extern bool
__kmpc_atomic_bool_2_cas(ident_t *loc, int gtid, short *x, short e, short d);
extern bool
__kmpc_atomic_bool_4_cas(ident_t *loc, int gtid, int *x, int e, int d);
extern bool
__kmpc_atomic_bool_8_cas(ident_t *loc, int gtid, long long *x, long long e,
long long d);
extern char
__kmpc_atomic_val_1_cas(ident_t *loc, int gtid, char *x, char e, char d);
extern short
__kmpc_atomic_val_2_cas(ident_t *loc, int gtid, short *x, short e, short d);
extern int
__kmpc_atomic_val_4_cas(ident_t *loc, int gtid, int *x, int e, int d);
extern long long
__kmpc_atomic_val_8_cas(ident_t *loc, int gtid, long long *x, long long e,
long long d);
#ifdef __cplusplus
}
#endif
int main() {
int ret = 0;
bool r;
char c0 = 1;
char c1 = 2;
char c2 = 3;
char co = 2;
char cc = 0;
short s0 = 11;
short s1 = 12;
short s2 = 13;
short so = 12;
short sc = 0;
int i0 = 211;
int i1 = 212;
int i2 = 213;
int io = 212;
int ic = 0;
long long l0 = 3111;
long long l1 = 3112;
long long l2 = 3113;
long long lo = 3112;
long long lc = 0;
// initialize OpenMP runtime library
omp_set_dynamic(0);
// #pragma omp atomic compare update capture
// { r = x == e; if(r) { x = d; } }
// char, co == c1 initially, co == c2 finally
r = __kmpc_atomic_bool_1_cas(NULL, 0, &co, c0, c2); // no-op
if (co != c1) {
ret++; printf("Error bool_1_cas no-op: %d != %d\n", co, c1); }
if (r) { ret++; printf("Error bool_1_cas no-op ret: %d\n", r); }
r = __kmpc_atomic_bool_1_cas(NULL, 0, &co, c1, c2);
if (co != c2) {
ret++; printf("Error bool_1_cas: %d != %d\n", co, c2); }
if (!r) { ret++; printf("Error bool_1_cas ret: %d\n", r); }
// short
r = __kmpc_atomic_bool_2_cas(NULL, 0, &so, s0, s2); // no-op
if (so != s1) {
ret++; printf("Error bool_2_cas no-op: %d != %d\n", so, s1); }
if (r) { ret++; printf("Error bool_2_cas no-op ret: %d\n", r); }
r = __kmpc_atomic_bool_2_cas(NULL, 0, &so, s1, s2);
if (so != s2) {
ret++; printf("Error bool_2_cas: %d != %d\n", so, s2); }
if (!r) { ret++; printf("Error bool_2_cas ret: %d\n", r); }
// int
r = __kmpc_atomic_bool_4_cas(NULL, 0, &io, i0, i2); // no-op
if (io != i1) {
ret++; printf("Error bool_4_cas no-op: %d != %d\n", io, i1); }
if (r) { ret++; printf("Error bool_4_cas no-op ret: %d\n", r); }
r = __kmpc_atomic_bool_4_cas(NULL, 0, &io, i1, i2);
if (io != i2) {
ret++; printf("Error bool_4_cas: %d != %d\n", io, i2); }
if (!r) { ret++; printf("Error bool_4_cas ret: %d\n", r); }
// long long
r = __kmpc_atomic_bool_8_cas(NULL, 0, &lo, l0, l2); // no-op
if (lo != l1) {
ret++; printf("Error bool_8_cas no-op: %lld != %lld\n", lo, l1); }
if (r) { ret++; printf("Error bool_8_cas no-op ret: %d\n", r); }
r = __kmpc_atomic_bool_8_cas(NULL, 0, &lo, l1, l2);
if (lo != l2) {
ret++; printf("Error bool_8_cas: %lld != %lld\n", lo, l2); }
if (!r) { ret++; printf("Error bool_8_cas ret: %d\n", r); }
// #pragma omp atomic compare update capture
// { v = x; if (x == e) { x = d; } }
// char, co == c2 initially, co == c1 finally
cc = __kmpc_atomic_val_1_cas(NULL, 0, &co, c0, c1); // no-op
if (co != c2) {
ret++; printf("Error val_1_cas no-op: %d != %d\n", co, c2); }
if (cc != c2) {
ret++; printf("Error val_1_cas no-op ret: %d != %d\n", cc, c2); }
cc = __kmpc_atomic_val_1_cas(NULL, 0, &co, c2, c1);
if (co != c1) {
ret++; printf("Error val_1_cas: %d != %d\n", co, c1); }
if (cc != c2) { ret++; printf("Error val_1_cas ret: %d != %d\n", cc, c2); }
// short
sc = __kmpc_atomic_val_2_cas(NULL, 0, &so, s0, s1); // no-op
if (so != s2) {
ret++; printf("Error val_2_cas no-op: %d != %d\n", so, s2); }
if (sc != s2) {
ret++; printf("Error val_2_cas no-op ret: %d != %d\n", sc, s2); }
sc = __kmpc_atomic_val_2_cas(NULL, 0, &so, s2, s1);
if (so != s1) {
ret++; printf("Error val_2_cas: %d != %d\n", so, s1); }
if (sc != s2) {
ret++; printf("Error val_2_cas ret: %d != %d\n", sc, s2); }
// int
ic = __kmpc_atomic_val_4_cas(NULL, 0, &io, i0, i1); // no-op
if (io != i2) {
ret++; printf("Error val_4_cas no-op: %d != %d\n", io, i2); }
if (ic != i2) {
ret++; printf("Error val_4_cas no-op ret: %d != %d\n", ic, i2); }
ic = __kmpc_atomic_val_4_cas(NULL, 0, &io, i2, i1);
if (io != i1) {
ret++; printf("Error val_4_cas: %d != %d\n", io, i1); }
if (ic != i2) {
ret++; printf("Error val_4_cas ret: %d != %d\n", ic, i2); }
// long long
lc = __kmpc_atomic_val_8_cas(NULL, 0, &lo, l0, l1); // no-op
if (lo != l2) {
ret++; printf("Error val_8_cas no-op: %lld != %lld\n", lo, l2); }
if (lc != l2) {
ret++; printf("Error val_8_cas no-op ret: %lld != %lld\n", lc, l2); }
lc = __kmpc_atomic_val_8_cas(NULL, 0, &lo, l2, l1);
if (lo != l1) {
ret++; printf("Error val_8_cas: %lld != %lld\n", lo, l1); }
if (lc != l2) {
ret++; printf("Error val_8_cas ret: %lld != %lld\n", lc, l2); }
// check in parallel
i0 = 1;
i1 = 0;
for (io = 0; io < 5; ++io) {
#pragma omp parallel num_threads(2) private(i2, ic, r)
{
if (omp_get_thread_num() == 0) {
// th0 waits for th1 to increment i1, then th0 increments i0
#pragma omp atomic read
i2 = i1;
ic = __kmpc_atomic_val_4_cas(NULL, 0, &i0, i2, i2 + 1);
while(ic != i2) {
#pragma omp atomic read
i2 = i1;
ic = __kmpc_atomic_val_4_cas(NULL, 0, &i0, i2, i2 + 1);
}
} else {
// th1 increments i1 if it is equal to i0 - 1, letting th0 to proceed
r = 0;
while(!r) {
#pragma omp atomic read
i2 = i0;
r = __kmpc_atomic_bool_4_cas(NULL, 0, &i1, i2 - 1, i2);
}
}
}
}
if (i0 != 6 || i1 != 5) {
ret++;
printf("Error in parallel, %d != %d or %d != %d\n", i0, 6, i1, 5);
}
if (ret == 0)
printf("passed\n");
return ret;
}

View File

@ -0,0 +1,219 @@
// RUN: %libomp-compile-and-run
#include <stdio.h>
#include <stdbool.h>
#include <omp.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef void* ident_t;
extern bool
__kmpc_atomic_bool_1_cas_cpt(ident_t *loc, int gtid, char *x, char e, char d,
char *pv);
extern bool
__kmpc_atomic_bool_2_cas_cpt(ident_t *loc, int gtid, short *x, short e, short d,
short *pv);
extern bool
__kmpc_atomic_bool_4_cas_cpt(ident_t *loc, int gtid, int *x, int e, int d,
int *pv);
extern bool
__kmpc_atomic_bool_8_cas_cpt(ident_t *loc, int gtid, long long *x, long long e,
long long d, long long *pv);
extern char
__kmpc_atomic_val_1_cas_cpt(ident_t *loc, int gtid, char *x, char e, char d,
char *pv);
extern short
__kmpc_atomic_val_2_cas_cpt(ident_t *loc, int gtid, short *x, short e, short d,
short *pv);
extern int
__kmpc_atomic_val_4_cas_cpt(ident_t *loc, int gtid, int *x, int e, int d,
int *pv);
extern long long
__kmpc_atomic_val_8_cas_cpt(ident_t *loc, int gtid, long long *x, long long e,
long long d, long long *pv);
#ifdef __cplusplus
}
#endif
int main() {
int ret = 0;
bool r;
char c0 = 1;
char c1 = 2;
char c2 = 3;
char co = 2;
char cc = 0;
char cv = 0;
short s0 = 11;
short s1 = 12;
short s2 = 13;
short so = 12;
short sc = 0;
short sv = 0;
int i0 = 211;
int i1 = 212;
int i2 = 213;
int io = 212;
int ic = 0;
int iv = 0;
long long l0 = 3111;
long long l1 = 3112;
long long l2 = 3113;
long long lo = 3112;
long long lc = 0;
long long lv = 0;
// initialize OpenMP runtime library
omp_set_dynamic(0);
// #pragma omp atomic compare update capture
// { r = x == e; if(r) { x = d; } else { v = x; } }
// char, co == c1 initially, co == c2 finally
r = __kmpc_atomic_bool_1_cas_cpt(NULL, 0, &co, c0, c2, &cv); // no-op
if (co != c1) {
ret++; printf("Error bool_1_cas_cpt no-op: %d != %d\n", co, c1); }
if (cv != co) {
ret++; printf("Error bool_1_cas_cpt no-op cpt: %d != %d\n", cv, co); }
if (r) { ret++; printf("Error bool_1_cas_cpt no-op ret: %d\n", r); }
cv = 0;
r = __kmpc_atomic_bool_1_cas_cpt(NULL, 0, &co, c1, c2, &cv);
if (co != c2) { ret++; printf("Error bool_1_cas_cpt: %d != %d\n", co, c2); }
if (cv != 0) { ret++; printf("Error bool_1_cas_cpt cpt: %d != %d\n", cv, 0); }
if (!r) { ret++; printf("Error bool_1_cas_cpt ret: %d\n", r); }
// short
r = __kmpc_atomic_bool_2_cas_cpt(NULL, 0, &so, s0, s2, &sv); // no-op
if (so != s1) {
ret++; printf("Error bool_2_cas_cpt no-op: %d != %d\n", so, s1); }
if (sv != so) {
ret++; printf("Error bool_2_cas_cpt no-op cpt: %d != %d\n", sv, so); }
if (r) { ret++; printf("Error bool_2_cas_cpt no-op ret: %d\n", r); }
sv = 0;
r = __kmpc_atomic_bool_2_cas_cpt(NULL, 0, &so, s1, s2, &sv);
if (so != s2) { ret++; printf("Error bool_2_cas_cpt: %d != %d\n", so, s2); }
if (sv != 0) { ret++; printf("Error bool_2_cas_cpt cpt: %d != %d\n", sv, 0); }
if (!r) { ret++; printf("Error bool_2_cas_cpt ret: %d\n", r); }
// int
r = __kmpc_atomic_bool_4_cas_cpt(NULL, 0, &io, i0, i2, &iv); // no-op
if (io != i1) {
ret++; printf("Error bool_4_cas_cpt no-op: %d != %d\n", io, i1); }
if (iv != io) {
ret++; printf("Error bool_4_cas_cpt no-op cpt: %d != %d\n", iv, io); }
if (r) { ret++; printf("Error bool_4_cas_cpt no-op ret: %d\n", r); }
iv = 0;
r = __kmpc_atomic_bool_4_cas_cpt(NULL, 0, &io, i1, i2, &iv);
if (io != i2) { ret++; printf("Error bool_4_cas_cpt: %d != %d\n", io, i2); }
if (iv != 0) { ret++; printf("Error bool_4_cas_cpt cpt: %d != %d\n", iv, 0); }
if (!r) { ret++; printf("Error bool_4_cas_cpt ret: %d\n", r); }
// long long
r = __kmpc_atomic_bool_8_cas_cpt(NULL, 0, &lo, l0, l2, &lv); // no-op
if (lo != l1) {
ret++; printf("Error bool_8_cas_cpt no-op: %lld != %lld\n", lo, l1); }
if (lv != lo) {
ret++; printf("Error bool_8_cas_cpt no-op cpt: %lld != %lld\n", lv, lo); }
if (r) { ret++; printf("Error bool_8_cas_cpt no-op ret: %d\n", r); }
lv = 0;
r = __kmpc_atomic_bool_8_cas_cpt(NULL, 0, &lo, l1, l2, &lv);
if (lo != l2) {
ret++; printf("Error bool_8_cas_cpt: %lld != %lld\n", lo, l2); }
if (lv != 0) { // should not be assigned
ret++; printf("Error bool_8_cas_cpt cpt: %lld != %d\n", lv, 0); }
if (!r) { ret++; printf("Error bool_8_cas_cpt ret: %d\n", r); }
// #pragma omp atomic compare update capture
// { if (x == e) { x = d; }; v = x; }
// char, co == c2 initially, co == c1 finally
cc = __kmpc_atomic_val_1_cas_cpt(NULL, 0, &co, c0, c1, &cv); // no-op
if (co != c2) {
ret++; printf("Error val_1_cas_cpt no-op: %d != %d\n", co, c2); }
if (cv != c2) {
ret++; printf("Error val_1_cas_cpt no-op cpt: %d != %d\n", cv, c2); }
if (cc != c2) {
ret++; printf("Error val_1_cas_cpt no-op ret: %d != %d\n", cc, c2); }
cc = __kmpc_atomic_val_1_cas_cpt(NULL, 0, &co, c2, c1, &cv);
if (co != c1) { ret++; printf("Error val_1_cas_cpt: %d != %d\n", co, c1); }
if (cv != c1) { ret++; printf("Error val_1_cas_cpt cpt: %d != %d\n", cv, c1); }
if (cc != c2) { ret++; printf("Error val_1_cas_cpt ret: %d != %d\n", cc, c2); }
// short
sc = __kmpc_atomic_val_2_cas_cpt(NULL, 0, &so, s0, s1, &sv); // no-op
if (so != s2) {
ret++; printf("Error val_2_cas_cpt no-op: %d != %d\n", so, s2); }
if (sv != s2) {
ret++; printf("Error val_2_cas_cpt no-op cpt: %d != %d\n", sv, s2); }
if (sc != s2) {
ret++; printf("Error val_2_cas_cpt no-op ret: %d != %d\n", sc, s2); }
sc = __kmpc_atomic_val_2_cas_cpt(NULL, 0, &so, s2, s1, &sv);
if (so != s1) { ret++; printf("Error val_2_cas_cpt: %d != %d\n", so, s1); }
if (sv != s1) { ret++; printf("Error val_2_cas_cpt cpt: %d != %d\n", sv, s1); }
if (sc != s2) { ret++; printf("Error val_2_cas_cpt ret: %d != %d\n", sc, s2); }
// int
ic = __kmpc_atomic_val_4_cas_cpt(NULL, 0, &io, i0, i1, &iv); // no-op
if (io != i2) {
ret++; printf("Error val_4_cas_cpt no-op: %d != %d\n", io, i2); }
if (iv != i2) {
ret++; printf("Error val_4_cas_cpt no-op cpt: %d != %d\n", iv, i2); }
if (ic != i2) {
ret++; printf("Error val_4_cas_cpt no-op ret: %d != %d\n", ic, i2); }
ic = __kmpc_atomic_val_4_cas_cpt(NULL, 0, &io, i2, i1, &iv);
if (io != i1) { ret++; printf("Error val_4_cas_cpt: %d != %d\n", io, i1); }
if (iv != i1) { ret++; printf("Error val_4_cas_cpt cpt: %d != %d\n", io, i1); }
if (ic != i2) { ret++; printf("Error val_4_cas_cpt ret: %d != %d\n", ic, i2); }
// long long
lc = __kmpc_atomic_val_8_cas_cpt(NULL, 0, &lo, l0, l1, &lv); // no-op
if (lo != l2) {
ret++; printf("Error val_8_cas_cpt no-op: %lld != %lld\n", lo, l2); }
if (lv != l2) {
ret++; printf("Error val_8_cas_cpt no-op cpt: %lld != %lld\n", lv, l2); }
if (lc != l2) {
ret++; printf("Error val_8_cas_cpt no-op ret: %lld != %lld\n", lc, l2); }
lc = __kmpc_atomic_val_8_cas_cpt(NULL, 0, &lo, l2, l1, &lv);
if (lo != l1) { ret++; printf("Error val_8_cas_cpt: %lld != %lld\n", lo, l1); }
if (lv != l1) {
ret++; printf("Error val_8_cas_cpt cpt: %lld != %lld\n", lv, l1); }
if (lc != l2) {
ret++; printf("Error val_8_cas_cpt ret: %lld != %lld\n", lc, l2); }
// check in parallel
i0 = 1;
i1 = 0;
for (io = 0; io < 5; ++io) {
#pragma omp parallel num_threads(2) private(i2, ic, r, iv)
{
if (omp_get_thread_num() == 0) {
// th0 waits for th1 to increment i1, then th0 increments i0
#pragma omp atomic read
i2 = i1;
ic = __kmpc_atomic_val_4_cas_cpt(NULL, 0, &i0, i2, i2 + 1, &iv);
while(ic != i2) {
if (iv != ic) {
ret++;
printf("Error 1 in parallel cpt, %d != %d\n", iv, ic);
}
#pragma omp atomic read
i2 = i1;
ic = __kmpc_atomic_val_4_cas_cpt(NULL, 0, &i0, i2, i2 + 1, &iv);
}
if (iv != i2 + 1) {
ret++;
printf("Error 2 in parallel cpt, %d != %d\n", iv, i2 + 1);
}
} else {
// th1 increments i1 if it is equal to i0 - 1, letting th0 to proceed
r = 0;
while(!r) {
#pragma omp atomic read
i2 = i0;
r = __kmpc_atomic_bool_4_cas_cpt(NULL, 0, &i1, i2 - 1, i2, &iv);
}
}
}
}
if (i0 != 6 || i1 != 5) {
ret++;
printf("Error in parallel, %d != %d or %d != %d\n", i0, 6, i1, 5);
}
if (ret == 0)
printf("passed\n");
return ret;
}

View File

@ -0,0 +1,155 @@
// RUN: %libomp-compile -mlong-double-80 && %libomp-run
// UNSUPPORTED: gcc
#include <stdio.h>
#include <omp.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef void* ident_t;
extern void __kmpc_atomic_float10_max(ident_t *id_ref, int gtid,
long double *lhs, long double rhs);
extern void __kmpc_atomic_float10_min(ident_t *id_ref, int gtid,
long double *lhs, long double rhs);
extern long double __kmpc_atomic_float10_max_cpt(ident_t *id_ref, int gtid,
long double *lhs,
long double rhs, int flag);
extern long double __kmpc_atomic_float10_min_cpt(ident_t *id_ref, int gtid,
long double *lhs,
long double rhs, int flag);
#ifdef __cplusplus
}
#endif
int main() {
int ret = 0;
long double s = 012.3456; // small
long double e = 123.4567; // middle
long double d = 234.5678; // big
long double x = 123.4567; // object
long double v = 0.; // captured value
// initialize OpenMP runtime library
omp_set_num_threads(4);
// max
// #pragma omp atomic compare update
// if (x < d) x = d;
__kmpc_atomic_float10_max(NULL, 0, &x, d);
if (x != d) {
ret++;
printf("Error max: %Lf != %Lf\n", x, d);
}
__kmpc_atomic_float10_max(NULL, 0, &x, s); // no-op
if (x != d) {
ret++;
printf("Error max: %Lf != %Lf\n", x, d);
}
// min
// #pragma omp atomic compare update
// if (x > s) x = s;
__kmpc_atomic_float10_min(NULL, 0, &x, s);
if (x != s) {
ret++;
printf("Error min: %Lf != %Lf\n", x, s);
}
__kmpc_atomic_float10_min(NULL, 0, &x, e); // no-op
if (x != s) {
ret++;
printf("Error min: %Lf != %Lf\n", x, s);
}
// max_cpt old
// #pragma omp atomic compare update capture
// { v = x; if (x < d) x = d; }
v = __kmpc_atomic_float10_max_cpt(NULL, 0, &x, d, 0);
if (x != d) {
ret++;
printf("Error max_cpt obj: %Lf != %Lf\n", x, d);
}
if (v != s) {
ret++;
printf("Error max_cpt cpt: %Lf != %Lf\n", v, s);
}
v = __kmpc_atomic_float10_max_cpt(NULL, 0, &x, e, 0); // no-op
if (x != d) {
ret++;
printf("Error max_cpt obj: %Lf != %Lf\n", x, d);
}
if (v != d) {
ret++;
printf("Error max_cpt cpt: %Lf != %Lf\n", v, d);
}
// min_cpt old
// #pragma omp atomic compare update capture
// { v = x; if (x > d) x = d; }
v = __kmpc_atomic_float10_min_cpt(NULL, 0, &x, s, 0);
if (x != s) {
ret++;
printf("Error min_cpt obj: %Lf != %Lf\n", x, s);
}
if (v != d) {
ret++;
printf("Error min_cpt cpt: %Lf != %Lf\n", v, d);
}
v = __kmpc_atomic_float10_min_cpt(NULL, 0, &x, e, 0); // no-op
if (x != s) {
ret++;
printf("Error max_cpt obj: %Lf != %Lf\n", x, s);
}
if (v != s) {
ret++;
printf("Error max_cpt cpt: %Lf != %Lf\n", v, s);
}
// max_cpt new
// #pragma omp atomic compare update capture
// { if (x < d) x = d; v = x; }
v = __kmpc_atomic_float10_max_cpt(NULL, 0, &x, d, 1);
if (x != d) {
ret++;
printf("Error max_cpt obj: %Lf != %Lf\n", x, d);
}
if (v != d) {
ret++;
printf("Error max_cpt cpt: %Lf != %Lf\n", v, d);
}
v = __kmpc_atomic_float10_max_cpt(NULL, 0, &x, e, 1); // no-op
if (x != d) {
ret++;
printf("Error max_cpt obj: %Lf != %Lf\n", x, d);
}
if (v != d) {
ret++;
printf("Error max_cpt cpt: %Lf != %Lf\n", v, d);
}
// min_cpt new
// #pragma omp atomic compare update capture
// { if (x > d) x = d; v = x; }
v = __kmpc_atomic_float10_min_cpt(NULL, 0, &x, s, 1);
if (x != s) {
ret++;
printf("Error min_cpt obj: %Lf != %Lf\n", x, s);
}
if (v != s) {
ret++;
printf("Error min_cpt cpt: %Lf != %Lf\n", v, s);
}
v = __kmpc_atomic_float10_min_cpt(NULL, 0, &x, e, 1); // no-op
if (x != s) {
ret++;
printf("Error max_cpt obj: %Lf != %Lf\n", x, s);
}
if (v != s) {
ret++;
printf("Error max_cpt cpt: %Lf != %Lf\n", v, s);
}
if (ret == 0)
printf("passed\n");
return ret;
}