Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions runtime/mercury_atomic_ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ MR_OUTLINE_DEFN(

MR_OUTLINE_DEFN(
void
MR_atomic_sub_int(volatile MR_Integer *addr, MR_Integer x)
MR_atomic_sub_int(volatile _Atomic MR_Integer *addr, MR_Integer x)
,
{
MR_ATOMIC_SUB_INT_BODY;
Expand Down Expand Up @@ -109,7 +109,7 @@ MR_OUTLINE_DEFN(

MR_OUTLINE_DEFN(
MR_bool
MR_atomic_dec_and_is_zero_int(volatile MR_Integer *addr)
MR_atomic_dec_and_is_zero_int(volatile _Atomic MR_Integer *addr)
,
{
MR_ATOMIC_DEC_AND_IS_ZERO_INT_BODY;
Expand All @@ -118,7 +118,7 @@ MR_OUTLINE_DEFN(

MR_OUTLINE_DEFN(
MR_bool
MR_atomic_dec_and_is_zero_uint(volatile MR_Unsigned *addr)
MR_atomic_dec_and_is_zero_uint(volatile _Atomic MR_Unsigned *addr)
,
{
MR_ATOMIC_DEC_AND_IS_ZERO_UINT_BODY;
Expand Down
74 changes: 63 additions & 11 deletions runtime/mercury_atomic_ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@
#ifndef MERCURY_ATOMIC_OPS_H
#define MERCURY_ATOMIC_OPS_H

#if __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__)
#include <stdatomic.h>
#else
#define _Atomic
#endif
#include "mercury_std.h"

////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -104,7 +109,7 @@ MR_EXTERN_INLINE void MR_atomic_add_uint(volatile MR_Unsigned *addr,
// Atomically subtract the second argument from the memory pointed to by the
// first argument.

MR_EXTERN_INLINE void MR_atomic_sub_int(volatile MR_Integer *addr,
MR_EXTERN_INLINE void MR_atomic_sub_int(volatile _Atomic MR_Integer *addr,
MR_Integer x);

// Increment the word pointed at by the address.
Expand All @@ -120,17 +125,24 @@ MR_EXTERN_INLINE void MR_atomic_dec_int(volatile MR_Integer *addr);
// zero after the decrement.

MR_EXTERN_INLINE MR_bool MR_atomic_dec_and_is_zero_int(
volatile MR_Integer *addr);
volatile _Atomic MR_Integer *addr);
MR_EXTERN_INLINE MR_bool MR_atomic_dec_and_is_zero_uint(
volatile MR_Unsigned *addr);
volatile _Atomic MR_Unsigned *addr);

// For information about GCC's builtins for atomic operations see:
// http://gcc.gnu.org/onlinedocs/gcc-4.2.4/gcc/Atomic-Builtins.html

////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////

#if (defined(MR_CLANG) || (MR_GNUC > 4 || (MR_GNUC == 4 && __GNUC_MINOR__ >= 1))) && \
#if __STD_VERSION__ >= 201112L && !defined(__STD_NO_ATOMICS__)

#define MR_COMPARE_AND_SWAP_WORD_BODY \
do { \
return atomic_compare_exchange_strong(addr, old, new_val); \
} while (0)

#elif (defined(MR_CLANG) || (MR_GNUC > 4 || (MR_GNUC == 4 && __GNUC_MINOR__ >= 1))) && \
!defined(MR_AVOID_COMPILER_INTRINSICS)

// gcc 4.1 and above have builtin atomic operations.
Expand Down Expand Up @@ -189,7 +201,17 @@ MR_EXTERN_INLINE MR_bool MR_atomic_dec_and_is_zero_uint(

////////////////////////////////////////////////////////////////////////////

#if (MR_GNUC > 4 || (MR_GNUC == 4 && __GNUC_MINOR__ >= 1)) && \
#if __STD_VERSION__ >= 201112L && !defined(__STD_NO_ATOMICS__)

#define MR_ATOMIC_ADD_AND_FETCH_WORD_BODY \
do { \
return atomic_fetch_add(addr, addend); \
} while (0)

#define MR_ATOMIC_ADD_AND_FETCH_INT_BODY MR_ATOMIC_ADD_AND_FETCH_WORD_BODY
#define MR_ATOMIC_ADD_AND_FETCH_UINT_BODY MR_ATOMIC_ADD_AND_FETCH_WORD_BODY

#elif (MR_GNUC > 4 || (MR_GNUC == 4 && __GNUC_MINOR__ >= 1)) && \
!defined(MR_AVOID_COMPILER_INTRINSICS)

#define MR_ATOMIC_ADD_AND_FETCH_WORD_BODY \
Expand Down Expand Up @@ -311,7 +333,14 @@ MR_EXTERN_INLINE MR_bool MR_atomic_dec_and_is_zero_uint(

////////////////////////////////////////////////////////////////////////////

#if (defined(MR_CLANG) || defined(MR_GNUC)) && defined(__x86_64__) && \
#if __STDC_VERSION__ >= 201112l && !defined(__STDC_NO_ATOMICS__)

#define MR_ATOMIC_SUB_INT_BODY \
do { \
atomic_fetch_sub(addr, x); \
} while (0)

#elif (defined(MR_CLANG) || defined(MR_GNUC)) && defined(__x86_64__) && \
!defined(MR_AVOID_HANDWRITTEN_ASSEMBLER)

#define MR_ATOMIC_SUB_INT_BODY \
Expand Down Expand Up @@ -345,7 +374,7 @@ MR_EXTERN_INLINE MR_bool MR_atomic_dec_and_is_zero_uint(

#ifdef MR_ATOMIC_SUB_INT_BODY
MR_EXTERN_INLINE void
MR_atomic_sub_int(volatile MR_Integer *addr, MR_Integer x)
MR_atomic_sub_int(volatile _Atomic MR_Integer *addr, MR_Integer x)
{
MR_ATOMIC_SUB_INT_BODY;
}
Expand Down Expand Up @@ -461,7 +490,19 @@ MR_EXTERN_INLINE MR_bool MR_atomic_dec_and_is_zero_uint(
// Note that on x86(_64) we have to use the sub instruction rather than the
// dec instruction because we need it to set the CPU flags.

#if (defined(MR_CLANG) || defined(MR_GNUC)) && defined(__x86_64__) && \
#if __STDC_VERSION__ >= 201112l && !defined(__STDC_NO_ATOMICS__)

#define MR_ATOMIC_DEC_AND_IS_ZERO_WORD_BODY \
do { \
return (atomic_fetch_sub(addr, 1) == 1); \
} while (0)

#define MR_ATOMIC_DEC_AND_IS_ZERO_INT_BODY \
MR_ATOMIC_DEC_AND_IS_ZERO_WORD_BODY
#define MR_ATOMIC_DEC_AND_IS_ZERO_UINT_BODY \
MR_ATOMIC_DEC_AND_IS_ZERO_WORD_BODY

#elif (defined(MR_CLANG) || defined(MR_GNUC)) && defined(__x86_64__) && \
!defined(MR_AVOID_HANDWRITTEN_ASSEMBLER)

// This could be trivially implemented using the __sync_sub_and_fetch compiler
Expand Down Expand Up @@ -519,15 +560,15 @@ MR_EXTERN_INLINE MR_bool MR_atomic_dec_and_is_zero_uint(

#ifdef MR_ATOMIC_DEC_AND_IS_ZERO_INT_BODY
MR_EXTERN_INLINE MR_bool
MR_atomic_dec_and_is_zero_int(volatile MR_Integer *addr)
MR_atomic_dec_and_is_zero_int(volatile _Atomic MR_Integer *addr)
{
MR_ATOMIC_DEC_AND_IS_ZERO_INT_BODY;
}
#endif

#ifdef MR_ATOMIC_DEC_AND_IS_ZERO_UINT_BODY
MR_EXTERN_INLINE MR_bool
MR_atomic_dec_and_is_zero_uint(volatile MR_Unsigned *addr)
MR_atomic_dec_and_is_zero_uint(volatile _Atomic MR_Unsigned *addr)
{
MR_ATOMIC_DEC_AND_IS_ZERO_UINT_BODY;
}
Expand All @@ -542,7 +583,18 @@ MR_EXTERN_INLINE MR_bool MR_atomic_dec_and_is_zero_uint(

// Memory fence operations.

#if ( defined(MR_CLANG) || defined(MR_GNUC) ) && \
#if __STDC_VERSION__ >= 201112l && !defined(__STDC_NO_ATOMICS__)

// Similar to the gcc __sync_* code below, this could be optimized

#define MR_CPU_MFENCE \
do { \
atomic_thread_fence(memory_order_seq_cst); \
} while (0)
#define MR_CPU_SFENCE MR_CPU_MFENCE
#define MR_CPU_LFENCE MR_CPU_MFENCE

#elif ( defined(MR_CLANG) || defined(MR_GNUC) ) && \
( defined(__i386__) || defined(__x86_64__) ) && \
!defined(MR_AVOID_HANDWRITTEN_ASSEMBLER)

Expand Down