diff options
author | Thiago Macieira <thiago.macieira@nokia.com> | 2009-05-08 18:45:24 (GMT) |
---|---|---|
committer | axis <qt-info@nokia.com> | 2009-11-13 10:57:50 (GMT) |
commit | 43c607383697ab506f9eb0d491ec6348f939e53d (patch) | |
tree | 9c2d1838a70adfad4e5f2ac6a30df9bd518b2fec | |
parent | aeac586476a6e47c7a8a6aa2121bfe39a29d8458 (diff) | |
download | Qt-43c607383697ab506f9eb0d491ec6348f939e53d.zip Qt-43c607383697ab506f9eb0d491ec6348f939e53d.tar.gz Qt-43c607383697ab506f9eb0d491ec6348f939e53d.tar.bz2 |
Add the ARMv6 inline assembly code for compiling with RVCT.
This is basically a copy & paste of the GCC inline assembly above,
switched to the RVCT inline assembly model (which is actually easier
to write and understand).
I verified that this code compiles and assembles as expected. The
output generated by RVCT is pretty much on the mark. However, I have
not executed this code yet to see if it performs as expected.
To be noted:
- when expanding the inline template code, RVCT may be tempted to
switch your entire function to ARM mode. Should we add
__attribute__((noinline)) to prevent that?
- There's no equivalent to GCC inline assembler's clobber, especially
of "memory". Also, there's no "volatile" qualifier to the
assembly. Does the compiler know it can't reorder the code? Does it
know it shouldn't trust the value of the memory after this? My test
indicates the code is fine...
Reviewed-By: Shane Kearns
-rw-r--r-- | src/corelib/arch/qatomic_armv6.h | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/src/corelib/arch/qatomic_armv6.h b/src/corelib/arch/qatomic_armv6.h index 6eb9a7b..28655df 100644 --- a/src/corelib/arch/qatomic_armv6.h +++ b/src/corelib/arch/qatomic_armv6.h @@ -259,6 +259,138 @@ Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddOrdered(qptrdiff valueTo #else // This is Q_CC_RVCT +// RVCT inline assembly documentation: +// http://www.keil.com/support/man/docs/armcc/armcc_chdcffdb.htm +// RVCT embedded assembly documentation: +// http://www.keil.com/support/man/docs/armcc/armcc_chddbeib.htm + +// save our pragma state and switch to ARM mode +#pragma push +#pragma arm + +inline bool QBasicAtomicInt::ref() +{ + register int newValue; + register int result; + retry: + __asm { + ldrex newValue, [&_q_value] + add newValue, newValue, #1 + strex result, newValue, [&_q_value] + teq result, #0 + bne retry + } + return newValue != 0; +} + +inline bool QBasicAtomicInt::deref() +{ + register int newValue; + register int result; + retry: + __asm { + ldrex newValue, [&_q_value] + sub newValue, newValue, #1 + strex result, newValue, [&_q_value] + teq result, #0 + bne retry + } + return newValue != 0; +} + +inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue) +{ + register int result; + retry: + __asm { + ldrex result, [&_q_value] + eors result, result, expectedValue + strexeq result, newValue, [&_q_value] + teqeq result, #1 + beq retry + } + return result == 0; +} + +inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue) +{ + register int originalValue; + register int result; + retry: + __asm { + ldrex originalValue, [&_q_value] + strex result, newValue, [&_q_value] + teq result, #0 + bne retry + } + return originalValue; +} + +inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd) +{ + register int originalValue; + register int newValue; + register int result; + retry: + __asm { + ldrex originalValue, [&_q_value] + add newValue, originalValue, valueToAdd + strex result, newValue, [&_q_value] + teq result, #0 + bne retry + } + return originalValue; +} + +template <typename T> +Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetOrdered(T *expectedValue, T *newValue) +{ + register T *result; + retry: + __asm { + ldrex result, [&_q_value] + eors result, result, expectedValue + strexeq result, newValue, [&_q_value] + teqeq result, #1 + beq retry + } + return result == 0; +} + +template <typename T> +Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreOrdered(T *newValue) +{ + register T *originalValue; + register int result; + retry: + __asm { + ldrex originalValue, [&_q_value] + strex result, newValue, [&_q_value] + teq result, #0 + bne retry + } + return originalValue; +} + +template <typename T> +Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddOrdered(qptrdiff valueToAdd) +{ + register T *originalValue; + register T *newValue; + register int result; + retry: + __asm { + ldrex originalValue, [&_q_value] + add newValue, originalValue, valueToAdd * sizeof(T) + strex result, newValue, [&_q_value] + teq result, #0 + bne retry + } + return originalValue; +} + +// go back to the previous pragma state (probably Thumb mode) +#pragma pop #endif // common code |