From 09ce68aede661dc61819332cec5cb82218fd91e7 Mon Sep 17 00:00:00 2001
From: Nils Kohl <nils.kohl@fau.de>
Date: Mon, 20 Mar 2023 10:20:37 +0100
Subject: [PATCH] Half precision support for gcc.

---
 CMakeLists.txt                          | 29 +++++++++++++++++++------
 apps/tools/MixedPrecision/CheckFP16.cpp |  8 +++----
 src/core/DataTypes.h                    | 17 ++++++++-------
 3 files changed, 35 insertions(+), 19 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 54b37fb1e..b6962d6dc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1256,13 +1256,28 @@ endif()
 ##  Half precision
 ##
 ############################################################################################################################
-if ( WALBERLA_BUILD_WITH_HALF_PRECISION_SUPPORT )
-    message( STATUS "Configuring with *experimental* half precision (float16) support. You better know what you are doing." )
-    if ( NOT WALBERLA_OPTIMIZE_FOR_LOCALHOST )
-        message( WARNING "[WALBERLA_BUILD_WITH_HALF_PRECISION_SUPPORT] "
-                          "You are not optimizing for localhost. Linker errors could occur. Consider also enabling WALBERLA_OPTIMIZE_FOR_LOCALHOST!" )
-    endif()
-endif()
+if (WALBERLA_BUILD_WITH_HALF_PRECISION_SUPPORT)
+    if (WALBERLA_CXX_COMPILER_IS_GNU OR WALBERLA_CXX_COMPILER_IS_CLANG)
+        message(STATUS "Configuring with *experimental* half precision (float16) support. You better know what you are doing.")
+        if (WALBERLA_CXX_COMPILER_IS_GNU AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12.0.0)
+            message(WARNING "[WALBERLA_BUILD_WITH_HALF_PRECISION_SUPPORT] "
+                    "Half precision support for gcc has only been tested with version >= 12. "
+                    "You are using a previous version - it may not work correctly.")
+        endif ()
+        if (WALBERLA_CXX_COMPILER_IS_CLANG AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15.0.0)
+            message(WARNING "[WALBERLA_BUILD_WITH_HALF_PRECISION_SUPPORT] "
+                    "Half precision support for clang has only been tested with version >= 15. "
+                    "You are using a previous version - it may not work correctly.")
+        endif ()
+        if (NOT WALBERLA_OPTIMIZE_FOR_LOCALHOST)
+            message(WARNING "[WALBERLA_BUILD_WITH_HALF_PRECISION_SUPPORT] "
+                    "You are not optimizing for localhost. Linker errors could occur. Consider also enabling WALBERLA_OPTIMIZE_FOR_LOCALHOST!")
+        endif ()
+    else ()
+        message(FATAL_ERROR "[WALBERLA_BUILD_WITH_HALF_PRECISION_SUPPORT] "
+                "Half precision support is currently only available for gcc and clang.")
+    endif ()
+endif ()
 
 ############################################################################################################################
 # Documentation Generation
diff --git a/apps/tools/MixedPrecision/CheckFP16.cpp b/apps/tools/MixedPrecision/CheckFP16.cpp
index 24e29e1cf..7c84676de 100644
--- a/apps/tools/MixedPrecision/CheckFP16.cpp
+++ b/apps/tools/MixedPrecision/CheckFP16.cpp
@@ -77,8 +77,8 @@ int main(int argc, char** argv)
    WALBERLA_LOG_INFO_ON_ROOT("   Casting and output compiles.")
 
    WALBERLA_LOG_INFO_ON_ROOT(" - Basic arithmetic check: ")
-   float16 x   = 1.2f16;
-   float16 y   = -1.8f16;
+   auto x   = float16(1.2);
+   auto y   = float16(-1.8);
    float64 z   = -0.6;
    float16 sum = x + y;
    WALBERLA_LOG_INFO_ON_ROOT("     " << (double) x << " + " << (double) y << " == " << (float64) (x + y) << "")
@@ -113,11 +113,11 @@ int main(int argc, char** argv)
 
    std::vector< float64 > v64(vsize, 0.01);
    std::vector< float32 > v32(vsize, 0.01f);
-   std::vector< float16 > v16(vsize, 0.01f16);
+   std::vector< float16 > v16(vsize, float16(0.01));
 
    std::vector< float64 > vv64(vsize, 0.02);
    std::vector< float32 > vv32(vsize, 0.02f);
-   std::vector< float16 > vv16(vsize, 0.02f16);
+   std::vector< float16 > vv16(vsize, float16(0.02));
 
    std::vector< float64 > r64(vsize);
    std::vector< float32 > r32(vsize);
diff --git a/src/core/DataTypes.h b/src/core/DataTypes.h
index 951e1413d..bae5b7651 100644
--- a/src/core/DataTypes.h
+++ b/src/core/DataTypes.h
@@ -167,7 +167,6 @@ using real_t = double;
 using real_t = float;
 #endif
 
-
 /// Half precision support. Experimental. Use carefully.
 ///
 /// This feature is experimental, since it strictly depends on the underlying architecture and compiler support.
@@ -176,19 +175,21 @@ using real_t = float;
 /// Only bandwidth bound code may therefore benefit. None of this is guaranteed, and may change in the future.
 ///
 #ifdef WALBERLA_BUILD_WITH_HALF_PRECISION_SUPPORT
-#ifdef WALBERLA_CXX_COMPILER_IS_CLANG
+#   if defined(WALBERLA_CXX_COMPILER_IS_CLANG) || defined(WALBERLA_CXX_COMPILER_IS_GNU)
 /// Clang version must be 15 or higher for x86 half precision support.
+/// GCC version must be 12 or higher for x86 half precision support.
 /// Also support seems to require SSE, so ensure that respective instruction sets are enabled.
 /// See
 ///   https://clang.llvm.org/docs/LanguageExtensions.html#half-precision-floating-point
+///   https://gcc.gnu.org/onlinedocs/gcc/Half-Precision.html
 /// for more information.
-using half = _Float16;
-#else
-static_assert( false, "Attempting to built walberla with half precision support.\n"
-                      "However, the compiler you chose is not suited for that, or we simply have not implemented "
-                      "support for half precision and your compiler." )
-#endif
+using half    = _Float16;
 using float16 = half;
+#   else
+static_assert(false, "\n\n### Attempting to built walberla with half precision support.\n"
+                     "### However, the compiler you chose is not suited for that, or we simply have not implemented "
+                     "support for half precision and your compiler.\n");
+#   endif
 #endif
 using float32 = float;
 using float64 = double;
-- 
GitLab