From 43c607383697ab506f9eb0d491ec6348f939e53d Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 8 May 2009 20:45:24 +0200 Subject: 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 --- src/corelib/arch/qatomic_armv6.h | 132 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) 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::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 +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::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 +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::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 +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::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 -- cgit v0.12