1 /*
2  * Distributed under the Boost Software License, Version 1.0.
3  * (See accompanying file LICENSE_1_0.txt or copy at
4  * http://www.boost.org/LICENSE_1_0.txt)
5  *
6  * Copyright (c) 2009 Helge Bahmann
7  * Copyright (c) 2009 Phil Endecott
8  * Copyright (c) 2013 Tim Blechmann
9  * ARM Code by Phil Endecott, based on other architectures.
10  * Copyright (c) 2014, 2020 Andrey Semashev
11  */
12 /*!
13  * \file   atomic/detail/caps_arch_gcc_arm.hpp
14  *
15  * This header defines feature capabilities macros
16  */
17 
18 #ifndef BOOST_ATOMIC_DETAIL_CAPS_ARCH_GCC_ARM_HPP_INCLUDED_
19 #define BOOST_ATOMIC_DETAIL_CAPS_ARCH_GCC_ARM_HPP_INCLUDED_
20 
21 #include <boost/atomic/detail/config.hpp>
22 #include <boost/atomic/detail/platform.hpp>
23 
24 #ifdef BOOST_HAS_PRAGMA_ONCE
25 #pragma once
26 #endif
27 
28 #if defined(__ARMEL__) || \
29     (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || \
30     (defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)) || \
31     defined(BOOST_WINDOWS)
32 #define BOOST_ATOMIC_DETAIL_ARM_LITTLE_ENDIAN
33 #elif defined(__ARMEB__) || \
34     defined(__ARM_BIG_ENDIAN) || \
35     (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || \
36     (defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__))
37 #define BOOST_ATOMIC_DETAIL_ARM_BIG_ENDIAN
38 #else
39 #error "Boost.Atomic: Failed to determine ARM endianness, the target platform is not supported. Please, report to the developers (patches are welcome)."
40 #endif
41 
42 #if defined(__GNUC__) && defined(__arm__) && (BOOST_ATOMIC_DETAIL_ARM_ARCH >= 6)
43 
44 #if BOOST_ATOMIC_DETAIL_ARM_ARCH > 6
45 // ARMv7 and later have dmb instruction
46 #define BOOST_ATOMIC_DETAIL_ARM_HAS_DMB 1
47 #endif
48 
49 #if defined(__ARM_FEATURE_LDREX)
50 
51 #if (__ARM_FEATURE_LDREX & 1)
52 #define BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXB_STREXB 1
53 #endif
54 #if (__ARM_FEATURE_LDREX & 2)
55 #define BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXH_STREXH 1
56 #endif
57 #if (__ARM_FEATURE_LDREX & 8)
58 #define BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXD_STREXD 1
59 #endif
60 
61 #else // defined(__ARM_FEATURE_LDREX)
62 
63 #if !(defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6Z__))
64 
65 // ARMv6k and ARMv7 have 8 and 16-bit ldrex/strex variants, but at least GCC 4.7 fails to compile them. GCC 4.9 is known to work.
66 #if (__GNUC__ * 100 + __GNUC_MINOR__) >= 409
67 #define BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXB_STREXB 1
68 #define BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXH_STREXH 1
69 #endif
70 
71 #if !(((defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6ZK__)) && defined(__thumb__)) || defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7M__))
72 // ARMv6k and ARMv7 except ARMv7-M have 64-bit ldrex/strex variants.
73 // Unfortunately, GCC (at least 4.7.3 on Ubuntu) does not allocate register pairs properly when targeting ARMv6k Thumb,
74 // which is required for ldrexd/strexd instructions, so we disable 64-bit support. When targeting ARMv6k ARM
75 // or ARMv7 (both ARM and Thumb 2) it works as expected.
76 #define BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXD_STREXD 1
77 #endif
78 
79 #endif // !(defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6Z__))
80 
81 #endif // defined(__ARM_FEATURE_LDREX)
82 
83 #endif // defined(__GNUC__) && defined(__arm__) && (BOOST_ATOMIC_DETAIL_ARM_ARCH >= 6)
84 
85 #define BOOST_ATOMIC_INT8_LOCK_FREE 2
86 #define BOOST_ATOMIC_INT16_LOCK_FREE 2
87 #define BOOST_ATOMIC_INT32_LOCK_FREE 2
88 #if defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXD_STREXD)
89 #define BOOST_ATOMIC_INT64_LOCK_FREE 2
90 #endif
91 #define BOOST_ATOMIC_POINTER_LOCK_FREE 2
92 
93 #define BOOST_ATOMIC_THREAD_FENCE 2
94 #define BOOST_ATOMIC_SIGNAL_FENCE 2
95 
96 #endif // BOOST_ATOMIC_DETAIL_CAPS_ARCH_GCC_ARM_HPP_INCLUDED_
97