LCOV - code coverage report
Current view: top level - usr/include/x86_64-linux-gnu/qt5/QtCore - qatomic_x86.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 6 6 100.0 %
Date: 2016-11-29 15:07:43 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /****************************************************************************
       2             : **
       3             : ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
       4             : ** Copyright (C) 2011 Thiago Macieira <thiago@kde.org>
       5             : ** Contact: http://www.qt-project.org/legal
       6             : **
       7             : ** This file is part of the QtCore module of the Qt Toolkit.
       8             : **
       9             : ** $QT_BEGIN_LICENSE:LGPL$
      10             : ** Commercial License Usage
      11             : ** Licensees holding valid commercial Qt licenses may use this file in
      12             : ** accordance with the commercial license agreement provided with the
      13             : ** Software or, alternatively, in accordance with the terms contained in
      14             : ** a written agreement between you and Digia.  For licensing terms and
      15             : ** conditions see http://qt.digia.com/licensing.  For further information
      16             : ** use the contact form at http://qt.digia.com/contact-us.
      17             : **
      18             : ** GNU Lesser General Public License Usage
      19             : ** Alternatively, this file may be used under the terms of the GNU Lesser
      20             : ** General Public License version 2.1 as published by the Free Software
      21             : ** Foundation and appearing in the file LICENSE.LGPL included in the
      22             : ** packaging of this file.  Please review the following information to
      23             : ** ensure the GNU Lesser General Public License version 2.1 requirements
      24             : ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
      25             : **
      26             : ** In addition, as a special exception, Digia gives you certain additional
      27             : ** rights.  These rights are described in the Digia Qt LGPL Exception
      28             : ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
      29             : **
      30             : ** GNU General Public License Usage
      31             : ** Alternatively, this file may be used under the terms of the GNU
      32             : ** General Public License version 3.0 as published by the Free Software
      33             : ** Foundation and appearing in the file LICENSE.GPL included in the
      34             : ** packaging of this file.  Please review the following information to
      35             : ** ensure the GNU General Public License version 3.0 requirements will be
      36             : ** met: http://www.gnu.org/copyleft/gpl.html.
      37             : **
      38             : **
      39             : ** $QT_END_LICENSE$
      40             : **
      41             : ****************************************************************************/
      42             : 
      43             : #ifndef QATOMIC_X86_H
      44             : #define QATOMIC_X86_H
      45             : 
      46             : #include <QtCore/qgenericatomic.h>
      47             : 
      48             : QT_BEGIN_NAMESPACE
      49             : 
      50             : #if 0
      51             : // silence syncqt warnings
      52             : QT_END_NAMESPACE
      53             : #pragma qt_sync_skip_header_check
      54             : #pragma qt_sync_stop_processing
      55             : #endif
      56             : 
      57             : #define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_ALWAYS_NATIVE
      58             : #define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_WAIT_FREE
      59             : 
      60             : #define Q_ATOMIC_INT_TEST_AND_SET_IS_ALWAYS_NATIVE
      61             : #define Q_ATOMIC_INT_TEST_AND_SET_IS_WAIT_FREE
      62             : 
      63             : #define Q_ATOMIC_INT_FETCH_AND_STORE_IS_ALWAYS_NATIVE
      64             : #define Q_ATOMIC_INT_FETCH_AND_STORE_IS_WAIT_FREE
      65             : 
      66             : #define Q_ATOMIC_INT_FETCH_AND_ADD_IS_ALWAYS_NATIVE
      67             : #define Q_ATOMIC_INT_FETCH_AND_ADD_IS_WAIT_FREE
      68             : 
      69             : #define Q_ATOMIC_INT32_IS_SUPPORTED
      70             : 
      71             : #define Q_ATOMIC_INT32_REFERENCE_COUNTING_IS_ALWAYS_NATIVE
      72             : #define Q_ATOMIC_INT32_REFERENCE_COUNTING_IS_WAIT_FREE
      73             : 
      74             : #define Q_ATOMIC_INT32_TEST_AND_SET_IS_ALWAYS_NATIVE
      75             : #define Q_ATOMIC_INT32_TEST_AND_SET_IS_WAIT_FREE
      76             : 
      77             : #define Q_ATOMIC_INT32_FETCH_AND_STORE_IS_ALWAYS_NATIVE
      78             : #define Q_ATOMIC_INT32_FETCH_AND_STORE_IS_WAIT_FREE
      79             : 
      80             : #define Q_ATOMIC_INT32_FETCH_AND_ADD_IS_ALWAYS_NATIVE
      81             : #define Q_ATOMIC_INT32_FETCH_AND_ADD_IS_WAIT_FREE
      82             : 
      83             : #define Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE
      84             : #define Q_ATOMIC_POINTER_TEST_AND_SET_IS_WAIT_FREE
      85             : 
      86             : #define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_ALWAYS_NATIVE
      87             : #define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_WAIT_FREE
      88             : 
      89             : #define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_ALWAYS_NATIVE
      90             : #define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_WAIT_FREE
      91             : 
      92             : template <int size> struct QBasicAtomicOps: QGenericAtomicOps<QBasicAtomicOps<size> >
      93             : {
      94             :     static inline Q_DECL_CONSTEXPR bool isReferenceCountingNative() Q_DECL_NOTHROW { return true; }
      95             :     static inline Q_DECL_CONSTEXPR bool isReferenceCountingWaitFree() Q_DECL_NOTHROW { return true; }
      96             :     template <typename T> static bool ref(T &_q_value) Q_DECL_NOTHROW;
      97             :     template <typename T> static bool deref(T &_q_value) Q_DECL_NOTHROW;
      98             : 
      99             :     static inline Q_DECL_CONSTEXPR bool isTestAndSetNative() Q_DECL_NOTHROW { return true; }
     100             :     static inline Q_DECL_CONSTEXPR bool isTestAndSetWaitFree() Q_DECL_NOTHROW { return true; }
     101             :     template <typename T> static bool testAndSetRelaxed(T &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW;
     102             :     template <typename T> static bool
     103             :     testAndSetRelaxed(T &_q_value, T expectedValue, T newValue, T *currentValue) Q_DECL_NOTHROW;
     104             : 
     105             :     static inline Q_DECL_CONSTEXPR bool isFetchAndStoreNative() Q_DECL_NOTHROW { return true; }
     106             :     static inline Q_DECL_CONSTEXPR bool isFetchAndStoreWaitFree() Q_DECL_NOTHROW { return true; }
     107             :     template <typename T> static T fetchAndStoreRelaxed(T &_q_value, T newValue) Q_DECL_NOTHROW;
     108             : 
     109             :     static inline Q_DECL_CONSTEXPR bool isFetchAndAddNative() Q_DECL_NOTHROW { return true; }
     110             :     static inline Q_DECL_CONSTEXPR bool isFetchAndAddWaitFree() Q_DECL_NOTHROW { return true; }
     111             :     template <typename T> static
     112             :     T fetchAndAddRelaxed(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT valueToAdd) Q_DECL_NOTHROW;
     113             : };
     114             : 
     115             : template <typename T> struct QAtomicOps : QBasicAtomicOps<sizeof(T)>
     116             : {
     117             :     typedef T Type;
     118             : };
     119             : 
     120             : #if defined(Q_CC_GNU)
     121             : 
     122             : template<> struct QAtomicOpsSupport<1> { enum { IsSupported = 1 }; };
     123             : template<> struct QAtomicOpsSupport<2> { enum { IsSupported = 1 }; };
     124             : template<> struct QAtomicOpsSupport<8> { enum { IsSupported = 1 }; };
     125             : 
     126             : /*
     127             :  * Guide for the inline assembly below:
     128             :  *
     129             :  * x86 instructions are in the form "{opcode}{length} {source}, {destination}",
     130             :  * where the length is one of the letters "b" (byte), "w" (word, 16-bit), "l"
     131             :  * (dword, 32-bit), "q" (qword, 64-bit).
     132             :  *
     133             :  * In most cases, we can omit the length because it's inferred from one of the
     134             :  * registers. For example, "xchg %0,%1" doesn't need the length suffix because
     135             :  * we can only exchange data of the same size and one of the operands must be a
     136             :  * register.
     137             :  *
     138             :  * The exception is the increment and decrement functions, where we add and
     139             :  * subtract an immediate value (1). For those, we need to specify the length.
     140             :  * GCC and ICC support the syntax "add%z0 $1, %0", where "%z0" expands to the
     141             :  * length of the operand. Unfortunately, clang as of 3.0 doesn't support that.
     142             :  * For that reason, the ref() and deref() functions are rolled out for all
     143             :  * sizes.
     144             :  *
     145             :  * The functions are also rolled out for the 1-byte operations since those
     146             :  * require a special register constraint "q" to force the compiler to schedule
     147             :  * one of the 8-bit registers. It's probably a compiler bug that it tries to
     148             :  * use a register that doesn't exist.
     149             :  *
     150             :  * Finally, 64-bit operations are supported via the cmpxchg8b instruction on
     151             :  * 32-bit processors, via specialisation below.
     152             :  */
     153             : 
     154             : template<> template<typename T> inline
     155             : bool QBasicAtomicOps<1>::ref(T &_q_value) Q_DECL_NOTHROW
     156             : {
     157             :     unsigned char ret;
     158             :     asm volatile("lock\n"
     159             :                  "addb  $1, %0\n"
     160             :                  "setne %1"
     161             :                  : "=m" (_q_value), "=qm" (ret)
     162             :                  : "m" (_q_value)
     163             :                  : "memory");
     164             :     return ret != 0;
     165             : }
     166             : 
     167             : template<> template<typename T> inline
     168             : bool QBasicAtomicOps<2>::ref(T &_q_value) Q_DECL_NOTHROW
     169             : {
     170             :     unsigned char ret;
     171             :     asm volatile("lock\n"
     172             :                  "incw %0\n"
     173             :                  "setne %1"
     174             :                  : "=m" (_q_value), "=qm" (ret)
     175             :                  : "m" (_q_value)
     176             :                  : "memory");
     177             :     return ret != 0;
     178             : }
     179             : 
     180             : template<> template<typename T> inline
     181         132 : bool QBasicAtomicOps<4>::ref(T &_q_value) Q_DECL_NOTHROW
     182             : {
     183             :     unsigned char ret;
     184             :     asm volatile("lock\n"
     185             :                  "addl $1, %0\n"
     186             :                  "setne %1"
     187             :                  : "=m" (_q_value), "=qm" (ret)
     188             :                  : "m" (_q_value)
     189         132 :                  : "memory");
     190         132 :     return ret != 0;
     191             : }
     192             : 
     193             : template<> template <typename T> inline
     194             : bool QBasicAtomicOps<1>::deref(T &_q_value) Q_DECL_NOTHROW
     195             : {
     196             :     unsigned char ret;
     197             :     asm volatile("lock\n"
     198             :                  "subb $1, %0\n"
     199             :                  "setne %1"
     200             :                  : "=m" (_q_value), "=qm" (ret)
     201             :                  : "m" (_q_value)
     202             :                  : "memory");
     203             :     return ret != 0;
     204             : }
     205             : 
     206             : template<> template <typename T> inline
     207             : bool QBasicAtomicOps<2>::deref(T &_q_value) Q_DECL_NOTHROW
     208             : {
     209             :     unsigned char ret;
     210             :     asm volatile("lock\n"
     211             :                  "decw %0\n"
     212             :                  "setne %1"
     213             :                  : "=m" (_q_value), "=qm" (ret)
     214             :                  : "m" (_q_value)
     215             :                  : "memory");
     216             :     return ret != 0;
     217             : }
     218             : template<> template <typename T> inline
     219         349 : bool QBasicAtomicOps<4>::deref(T &_q_value) Q_DECL_NOTHROW
     220             : {
     221             :     unsigned char ret;
     222             :     asm volatile("lock\n"
     223             :                  "subl $1, %0\n"
     224             :                  "setne %1"
     225             :                  : "=m" (_q_value), "=qm" (ret)
     226             :                  : "m" (_q_value)
     227         349 :                  : "memory");
     228         349 :     return ret != 0;
     229             : }
     230             : 
     231             : template<int size> template <typename T> inline
     232             : bool QBasicAtomicOps<size>::testAndSetRelaxed(T &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW
     233             : {
     234             :     unsigned char ret;
     235             :     asm volatile("lock\n"
     236             :                  "cmpxchg %3,%2\n"
     237             :                  "sete %1\n"
     238             :                  : "=a" (newValue), "=qm" (ret), "+m" (_q_value)
     239             :                  : "r" (newValue), "0" (expectedValue)
     240             :                  : "memory");
     241             :     return ret != 0;
     242             : }
     243             : 
     244             : template<> template <typename T> inline
     245             : bool QBasicAtomicOps<1>::testAndSetRelaxed(T &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW
     246             : {
     247             :     unsigned char ret;
     248             :     asm volatile("lock\n"
     249             :                  "cmpxchg %3,%2\n"
     250             :                  "sete %1\n"
     251             :                  : "=a" (newValue), "=qm" (ret), "+m" (_q_value)
     252             :                  : "q" (newValue), "0" (expectedValue)
     253             :                  : "memory");
     254             :     return ret != 0;
     255             : }
     256             : 
     257             : template<int size> template <typename T> inline
     258             : bool QBasicAtomicOps<size>::testAndSetRelaxed(T &_q_value, T expectedValue,
     259             :                                               T newValue, T *currentValue) Q_DECL_NOTHROW
     260             : {
     261             :     unsigned char ret;
     262             :     asm volatile("lock\n"
     263             :                  "cmpxchg %3,%2\n"
     264             :                  "sete %1\n"
     265             :                  : "=a" (newValue), "=qm" (ret), "+m" (_q_value)
     266             :                  : "r" (newValue), "0" (expectedValue)
     267             :                  : "memory");
     268             :     *currentValue = newValue;
     269             :     return ret != 0;
     270             : }
     271             : 
     272             : template<> template <typename T> inline
     273             : bool QBasicAtomicOps<1>::testAndSetRelaxed(T &_q_value, T expectedValue,
     274             :                                            T newValue, T *currentValue) Q_DECL_NOTHROW
     275             : {
     276             :     unsigned char ret;
     277             :     asm volatile("lock\n"
     278             :                  "cmpxchg %3,%2\n"
     279             :                  "sete %1\n"
     280             :                  : "=a" (newValue), "=qm" (ret), "+m" (_q_value)
     281             :                  : "q" (newValue), "0" (expectedValue)
     282             :                  : "memory");
     283             :     *currentValue = newValue;
     284             :     return ret != 0;
     285             : }
     286             : 
     287             : template<int size> template <typename T> inline
     288             : T QBasicAtomicOps<size>::fetchAndStoreRelaxed(T &_q_value, T newValue) Q_DECL_NOTHROW
     289             : {
     290             :     asm volatile("xchg %0,%1"
     291             :                  : "=r" (newValue), "+m" (_q_value)
     292             :                  : "0" (newValue)
     293             :                  : "memory");
     294             :     return newValue;
     295             : }
     296             : 
     297             : template<> template <typename T> inline
     298             : T QBasicAtomicOps<1>::fetchAndStoreRelaxed(T &_q_value, T newValue) Q_DECL_NOTHROW
     299             : {
     300             :     asm volatile("xchg %0,%1"
     301             :                  : "=q" (newValue), "+m" (_q_value)
     302             :                  : "0" (newValue)
     303             :                  : "memory");
     304             :     return newValue;
     305             : }
     306             : 
     307             : template<int size> template <typename T> inline
     308             : T QBasicAtomicOps<size>::fetchAndAddRelaxed(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT valueToAdd) Q_DECL_NOTHROW
     309             : {
     310             :     T result;
     311             :     asm volatile("lock\n"
     312             :                  "xadd %0,%1"
     313             :                  : "=r" (result), "+m" (_q_value)
     314             :                  : "0" (T(valueToAdd * QAtomicAdditiveType<T>::AddScale))
     315             :                  : "memory");
     316             :     return result;
     317             : }
     318             : 
     319             : template<> template <typename T> inline
     320             : T QBasicAtomicOps<1>::fetchAndAddRelaxed(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT valueToAdd) Q_DECL_NOTHROW
     321             : {
     322             :     T result;
     323             :     asm volatile("lock\n"
     324             :                  "xadd %0,%1"
     325             :                  : "=q" (result), "+m" (_q_value)
     326             :                  : "0" (T(valueToAdd * QAtomicAdditiveType<T>::AddScale))
     327             :                  : "memory");
     328             :     return result;
     329             : }
     330             : 
     331             : #define Q_ATOMIC_INT8_IS_SUPPORTED
     332             : 
     333             : #define Q_ATOMIC_INT8_REFERENCE_COUNTING_IS_ALWAYS_NATIVE
     334             : #define Q_ATOMIC_INT8_REFERENCE_COUNTING_IS_WAIT_FREE
     335             : 
     336             : #define Q_ATOMIC_INT8_TEST_AND_SET_IS_ALWAYS_NATIVE
     337             : #define Q_ATOMIC_INT8_TEST_AND_SET_IS_WAIT_FREE
     338             : 
     339             : #define Q_ATOMIC_INT8_FETCH_AND_STORE_IS_ALWAYS_NATIVE
     340             : #define Q_ATOMIC_INT8_FETCH_AND_STORE_IS_WAIT_FREE
     341             : 
     342             : #define Q_ATOMIC_INT8_FETCH_AND_ADD_IS_ALWAYS_NATIVE
     343             : #define Q_ATOMIC_INT8_FETCH_AND_ADD_IS_WAIT_FREE
     344             : 
     345             : #define Q_ATOMIC_INT16_IS_SUPPORTED
     346             : 
     347             : #define Q_ATOMIC_INT16_REFERENCE_COUNTING_IS_ALWAYS_NATIVE
     348             : #define Q_ATOMIC_INT16_REFERENCE_COUNTING_IS_WAIT_FREE
     349             : 
     350             : #define Q_ATOMIC_INT16_TEST_AND_SET_IS_ALWAYS_NATIVE
     351             : #define Q_ATOMIC_INT16_TEST_AND_SET_IS_WAIT_FREE
     352             : 
     353             : #define Q_ATOMIC_INT16_FETCH_AND_STORE_IS_ALWAYS_NATIVE
     354             : #define Q_ATOMIC_INT16_FETCH_AND_STORE_IS_WAIT_FREE
     355             : 
     356             : #define Q_ATOMIC_INT16_FETCH_AND_ADD_IS_ALWAYS_NATIVE
     357             : #define Q_ATOMIC_INT16_FETCH_AND_ADD_IS_WAIT_FREE
     358             : 
     359             : #ifdef Q_PROCESSOR_X86_64
     360             : 
     361             : #define Q_ATOMIC_INT64_IS_SUPPORTED
     362             : 
     363             : #define Q_ATOMIC_INT64_REFERENCE_COUNTING_IS_ALWAYS_NATIVE
     364             : #define Q_ATOMIC_INT64_REFERENCE_COUNTING_IS_WAIT_FREE
     365             : 
     366             : #define Q_ATOMIC_INT64_TEST_AND_SET_IS_ALWAYS_NATIVE
     367             : #define Q_ATOMIC_INT64_TEST_AND_SET_IS_WAIT_FREE
     368             : 
     369             : #define Q_ATOMIC_INT64_FETCH_AND_STORE_IS_ALWAYS_NATIVE
     370             : #define Q_ATOMIC_INT64_FETCH_AND_STORE_IS_WAIT_FREE
     371             : 
     372             : #define Q_ATOMIC_INT64_FETCH_AND_ADD_IS_ALWAYS_NATIVE
     373             : #define Q_ATOMIC_INT64_FETCH_AND_ADD_IS_WAIT_FREE
     374             : 
     375             : // native support for 64-bit types
     376             : template<> template<typename T> inline
     377             : bool QBasicAtomicOps<8>::ref(T &_q_value) Q_DECL_NOTHROW
     378             : {
     379             :     unsigned char ret;
     380             :     asm volatile("lock\n"
     381             :                  "addq $1, %0\n"
     382             :                  "setne %1"
     383             :                  : "=m" (_q_value), "=qm" (ret)
     384             :                  : "m" (_q_value)
     385             :                  : "memory");
     386             :     return ret != 0;
     387             : }
     388             : 
     389             : template<> template <typename T> inline
     390             : bool QBasicAtomicOps<8>::deref(T &_q_value) Q_DECL_NOTHROW
     391             : {
     392             :     unsigned char ret;
     393             :     asm volatile("lock\n"
     394             :                  "subq $1, %0\n"
     395             :                  "setne %1"
     396             :                  : "=m" (_q_value), "=qm" (ret)
     397             :                  : "m" (_q_value)
     398             :                  : "memory");
     399             :     return ret != 0;
     400             : }
     401             : #else
     402             : // i386 architecture, emulate 64-bit support via cmpxchg8b
     403             : template <> struct QBasicAtomicOps<8>: QGenericAtomicOps<QBasicAtomicOps<8> >
     404             : {
     405             :     static inline Q_DECL_CONSTEXPR bool isTestAndSetNative() Q_DECL_NOTHROW { return true; }
     406             :     static inline Q_DECL_CONSTEXPR bool isTestAndSetWaitFree() Q_DECL_NOTHROW { return true; }
     407             :     template <typename T> static inline
     408             :     bool testAndSetRelaxed(T &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW
     409             :     {
     410             : #ifdef __PIC__
     411             : # define EBX_reg "r"
     412             : # define EBX_load(reg) "xchg " reg ", %%ebx\n"
     413             : #else
     414             : # define EBX_reg "b"
     415             : # define EBX_load(reg)
     416             : #endif
     417             :         quint32 highExpectedValue = quint32(newValue >> 32); // ECX
     418             :         asm volatile(EBX_load("%3")
     419             :                      "lock\n"
     420             :                      "cmpxchg8b %0\n"
     421             :                      EBX_load("%3")
     422             :                      "sete %%cl\n"
     423             :                      : "+m" (_q_value), "+c" (highExpectedValue), "+&A" (expectedValue)
     424             :                      : EBX_reg (quint32(newValue & 0xffffffff))
     425             :                      : "memory");
     426             :         // if the comparison failed, expectedValue here contains the current value
     427             :         return quint8(highExpectedValue) != 0;
     428             : #undef EBX_reg
     429             : #undef EBX_load
     430             :     }
     431             : };
     432             : #endif
     433             : 
     434             : #else
     435             : #  error "This compiler for x86 is not supported"
     436             : #endif
     437             : 
     438             : 
     439             : QT_END_NAMESPACE
     440             : 
     441             : #endif // QATOMIC_X86_H

Generated by: LCOV version 1.11