Add macros for assuming and unreachable code
authorThiago Macieira <thiago.macieira@intel.com>
Sat, 31 Dec 2011 02:15:06 +0000 (00:15 -0200)
committerQt by Nokia <qt-info@nokia.com>
Sat, 24 Mar 2012 18:07:22 +0000 (19:07 +0100)
Use these macros to tell the compiler about conditions that may
happen, so it will generate better code. But do not assume that they
will do anything special.

Change-Id: I89ec4f65f48a9340ccf5ffc4ae4b8c3d8897c8b1
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@nokia.com>
Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
doc/src/snippets/code/src_corelib_global_qglobal.cpp
src/corelib/global/qcompilerdetection.h
src/corelib/global/qglobal.cpp
src/corelib/global/qglobal.h

index 21bea7a..16f6783 100644 (file)
@@ -560,3 +560,26 @@ bool readConfiguration(const QFile &file)
     return true;
 }
 //! [qunlikely]
+
+//! [qunreachable-enum]
+   enum Shapes {
+       Rectangle,
+       Triangle,
+       Circle,
+       NumShapes
+   };
+//! [qunreachable-enum]
+
+//! [qunreachable-switch]
+   switch (shape) {
+       case Rectangle:
+           return rectangle();
+       case Triangle:
+           return triangle();
+       case Circle:
+           return circle();
+       case NumShapes:
+           Q_UNREACHABLE();
+           break;
+   }
+//! [qunreachable-switch]
index f3f0302..c9f5945 100644 (file)
@@ -88,6 +88,8 @@
 #  define Q_NO_TEMPLATE_FRIENDS
 #  define Q_ALIGNOF(type) __alignof(type)
 #  define Q_DECL_ALIGN(n) __declspec(align(n))
+#  define Q_ASSUME(expr) __assume(expr)
+#  define Q_UNREACHABLE() __assume(0)
 /* Intel C++ disguising as Visual C++: the `using' keyword avoids warnings */
 #  if defined(__INTEL_COMPILER)
 #    define Q_CC_INTEL
 #  if defined(__INTEL_COMPILER)
 /* Intel C++ also masquerades as GCC */
 #    define Q_CC_INTEL
+#    define Q_ASSUME(expr)  __assume(expr)
+#    define Q_UNREACHABLE() __assume(0)
 #  elif defined(__clang__)
 /* Clang also masquerades as GCC */
 #    define Q_CC_CLANG
+#    define Q_ASSUME(expr)  if (expr){} else __builtin_unreachable()
+#    define Q_UNREACHABLE() __builtin_unreachable()
 #  else
 /* Plain GCC */
+#    define Q_ASSUME(expr)  if (expr){} else __builtin_unreachable()
+#    define Q_UNREACHABLE() __builtin_unreachable()
 #  endif
 
 #  define Q_ALIGNOF(type)   __alignof__(type)
index 09d1786..f89b0b3 100644 (file)
@@ -1799,6 +1799,63 @@ const QSysInfo::WinVersion QSysInfo::WindowsVersion = QSysInfo::windowsVersion()
 */
 
 /*!
+    \macro void Q_ASSUME(bool expr)
+    \relates <QtGlobal>
+    \since 5.0
+
+    Causes the compiler to assume that \a expr is true. This macro is useful
+    for improving code generation, by providing the compiler with hints about
+    conditions that it would not otherwise know about. However, there is no
+    guarantee that the compiler will actually use those hints.
+
+    This macro could be considered a "lighter" version of \ref Q_ASSERT. While
+    Q_ASSERT will abort the program's execution if the condition is false,
+    Q_ASSUME will tell the compiler not to generate code for those conditions.
+    Therefore, it is important that the assumptions always hold, otherwise
+    undefined behaviour may occur.
+
+    If \a expr is a constantly false condition, Q_ASSUME will tell the compiler
+    that the current code execution cannot be reached. That is, Q_ASSUME(false)
+    is equivalent to Q_UNREACHABLE().
+
+    \note Q_LIKELY() tells the compiler that the expression is likely, but not
+    the only possibility. Q_ASSUME tells the compiler that it is the only
+    possibility.
+
+    \sa Q_ASSERT(), Q_UNREACHABLE(), Q_LIKELY()
+*/
+
+/*!
+    \macro void Q_UNREACHABLE()
+    \relates <QtGlobal>
+    \since 5.0
+
+    Tells the compiler that the current point cannot be reached by any
+    execution, so it may optimise any code paths leading here as dead code, as
+    well as code continuing from here.
+
+    This macro is useful to mark impossible conditions. For example, given the
+    following enum:
+
+    \snippet doc/src/snippets/code/src_corelib_global_qglobal.cpp qunreachable-enum
+
+    One can write a switch table like so:
+
+    \snippet doc/src/snippets/code/src_corelib_global_qglobal.cpp qunreachable-switch
+
+    The advantage of inserting Q_UNREACHABLE() at that point is that the
+    compiler is told not to generate code for a shape variable containing that
+    value. If the macro is missing, the compiler will still generate the
+    necessary comparisons for that value. If the case label were removed, some
+    compilers could produce a warning that some enum values were not checked.
+
+    By using this macro in impossible conditions, code coverage may be improved
+    as dead code paths may be eliminated.
+
+    \sa Q_ASSERT(), Q_ASSUME(), qFatal()
+*/
+
+/*!
     \macro void Q_CHECK_PTR(void *pointer)
     \relates <QtGlobal>
 
index 7341776..7d91fa3 100644 (file)
@@ -163,6 +163,12 @@ namespace QT_NAMESPACE {}
 #ifndef Q_UNLIKELY
 #  define Q_UNLIKELY(x) (x)
 #endif
+#ifndef Q_ASSUME
+#  define Q_ASSUME(expr)
+#endif
+#ifndef Q_UNREACHABLE
+#  define Q_UNREACHABLE()
+#endif
 
 #ifndef Q_ALLOC_SIZE
 #  define Q_ALLOC_SIZE(x)