Add ARM YIELD support to qYieldCpu()

YIELD is ARM's equivalent of x86's PAUSE, available since ARMv6k,
which should be old enough that we can use it unconditionally.

The ARM manual[1] defines the __yield() intrinsic for this, however:

- Clang has __builtin_arm_yield, the naming is compatible with what
  GCC would use, so we use that if available, to avoid having to
  include even more headers.

- GCC (incl. 12) doesn't have __yield() in arm_acle.h or anywhere
  else, and it doesn't seem to have the builtin (yet, one can always
  hope), so we use asm() there.

- Windows doesn't have an arm_acle.h header, but the docs[2] say it
  should have __yield(). Unfortunately, the docs don't say where
  the intrinsic is hiding, but we already include <intrin.h>, and
  godbolt[3] confirms that's sufficient to use __yield(). We could use
  YieldProcessor(), but we'd need to include qt_windows.h, I guess,
  which I'd rather not.

- Integrity doesn't have the arm_acle.h header, we use asm(), here, too.

[1] https://developer.arm.com/documentation/dui0472/k/Compiler-specific-Features/--yield-intrinsic
[2] https://docs.microsoft.com/en-us/cpp/intrinsics/arm-intrinsics?view=msvc-140
[3] https://godbolt.org/z/Evfe79xhE

Pick-to: 6.3
Fixes: QTBUG-103011
Change-Id: Ibf496dfe9949f9a3d24c0dcf75a703c5fdbbb4b8
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Sona Kurazyan <sona.kurazyan@qt.io>
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
This commit is contained in:
Marc Mutz 2022-04-29 12:28:09 +02:00
parent 71322ef361
commit 877c158c59

View File

@ -395,7 +395,7 @@ static inline uint64_t qCpuFeatures()
|| ((qCpuFeatures() & CpuFeature ## feature) == CpuFeature ## feature))
/*
Small wrapper around x86's PAUSE instruction.
Small wrapper around x86's PAUSE and ARM's YIELD instructions.
This is completely different from QThread::yieldCurrentThread(), which is
an OS-level operation that takes the whole thread off the CPU.
@ -420,6 +420,21 @@ static inline void qYieldCpu()
{
#if defined(Q_PROCESSOR_X86)
_mm_pause();
#elif defined(Q_PROCESSOR_ARM)
# if __has_builtin(__builtin_arm_yield) /* e.g. Clang */
__builtin_arm_yield();
# elif defined(Q_OS_INTEGRITY) || \
(defined(Q_CC_GNU) && !defined(Q_CC_CLANG))
/*
- Integrity is missing the arm_acle.h header
- GCC doesn't have __yield() in arm_acle.h
https://stackoverflow.com/a/70076751/134841
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105416
*/
asm volatile("yield"); /* this works everywhere */
# else
__yield(); /* this is what should work everywhere */
# endif
#endif
}