[llvm] WIP/POC: Constant Fold Logf128 calls (PR #84501)

Matthew Devereau via llvm-commits llvm-commits at lists.llvm.org
Fri Mar 22 06:14:52 PDT 2024


https://github.com/MDevereau updated https://github.com/llvm/llvm-project/pull/84501

>From 3c2444dc4ebae9564e9aa829b6989e115520520c Mon Sep 17 00:00:00 2001
From: Matt Devereau <matthew.devereau at arm.com>
Date: Mon, 26 Feb 2024 15:32:09 +0000
Subject: [PATCH 1/3] WIP/POC: Constant Fold Logf128 calls

This is a proof of concept/work in progress patch.

This patch enables ConstantFolding of log FP128 calls.

This is achieved by querying with CMake if the host
system has the logf128 symbol available. If so, replace
the runtime call with the compile time constant returned
from logf128.

This approach could be considered controversial as cross-compiled
llvm executables using shared objects may not have the logf128 symbol
available at runtime.

The implementation of logf128 may also yield different results
on different targets, such as x86 using fp80 precision instead
of the full fp128 range on other targets.

This approach relies on unit tests, as more commonplace Clang/C
tests and opt/llc/IR tests are not applicable since they
are ignorant to the result of the compile time CMake check.
---
 llvm/include/llvm/ADT/APFloat.h             | 10 +++
 llvm/include/llvm/ADT/APInt.h               | 15 +++++
 llvm/include/llvm/IR/Constants.h            |  2 +
 llvm/lib/Analysis/CMakeLists.txt            |  6 ++
 llvm/lib/Analysis/ConstantFolding.cpp       | 25 +++++--
 llvm/lib/IR/Constants.cpp                   | 16 +++++
 llvm/lib/Support/APFloat.cpp                | 24 +++++++
 llvm/unittests/Analysis/CMakeLists.txt      |  7 ++
 llvm/unittests/Analysis/ConstantLogf128.cpp | 74 +++++++++++++++++++++
 9 files changed, 175 insertions(+), 4 deletions(-)
 create mode 100644 llvm/unittests/Analysis/ConstantLogf128.cpp

diff --git a/llvm/include/llvm/ADT/APFloat.h b/llvm/include/llvm/ADT/APFloat.h
index 8c247bbcec90a2..1ce50fc6996683 100644
--- a/llvm/include/llvm/ADT/APFloat.h
+++ b/llvm/include/llvm/ADT/APFloat.h
@@ -299,6 +299,7 @@ class IEEEFloat final : public APFloatBase {
   IEEEFloat(const fltSemantics &, integerPart);
   IEEEFloat(const fltSemantics &, uninitializedTag);
   IEEEFloat(const fltSemantics &, const APInt &);
+  explicit IEEEFloat(long double ld);
   explicit IEEEFloat(double d);
   explicit IEEEFloat(float f);
   IEEEFloat(const IEEEFloat &);
@@ -354,6 +355,7 @@ class IEEEFloat final : public APFloatBase {
   Expected<opStatus> convertFromString(StringRef, roundingMode);
   APInt bitcastToAPInt() const;
   double convertToDouble() const;
+  long double convertToQuad() const;
   float convertToFloat() const;
 
   /// @}
@@ -942,6 +944,7 @@ class APFloat : public APFloatBase {
   APFloat(const fltSemantics &Semantics, uninitializedTag)
       : U(Semantics, uninitialized) {}
   APFloat(const fltSemantics &Semantics, const APInt &I) : U(Semantics, I) {}
+  explicit APFloat(long double ld) : U(IEEEFloat(ld), IEEEquad()) {}
   explicit APFloat(double d) : U(IEEEFloat(d), IEEEdouble()) {}
   explicit APFloat(float f) : U(IEEEFloat(f), IEEEsingle()) {}
   APFloat(const APFloat &RHS) = default;
@@ -1218,6 +1221,13 @@ class APFloat : public APFloatBase {
   /// shorter semantics, like IEEEsingle and others.
   double convertToDouble() const;
 
+  /// Converts this APFloat to host float value.
+  ///
+  /// \pre The APFloat must be built using semantics, that can be represented by
+  /// the host float type without loss of precision. It can be IEEEquad and
+  /// shorter semantics, like IEEEdouble and others.
+  long double convertToQuad() const;
+
   /// Converts this APFloat to host float value.
   ///
   /// \pre The APFloat must be built using semantics, that can be represented by
diff --git a/llvm/include/llvm/ADT/APInt.h b/llvm/include/llvm/ADT/APInt.h
index 6c05367cecb1ea..b85f051b4c7c41 100644
--- a/llvm/include/llvm/ADT/APInt.h
+++ b/llvm/include/llvm/ADT/APInt.h
@@ -1663,6 +1663,11 @@ class [[nodiscard]] APInt {
   /// any bit width. Exactly 64 bits will be translated.
   double bitsToDouble() const { return llvm::bit_cast<double>(getWord(0)); }
 
+  long double bitsToQuad() const {
+    __uint128_t ul = ((__uint128_t)U.pVal[1] << 64) + U.pVal[0];
+    return llvm::bit_cast<long double>(ul);
+  }
+
   /// Converts APInt bits to a float
   ///
   /// The conversion does not do a translation from integer to float, it just
@@ -1688,6 +1693,16 @@ class [[nodiscard]] APInt {
     return APInt(sizeof(float) * CHAR_BIT, llvm::bit_cast<uint32_t>(V));
   }
 
+  static APInt longDoubleToBits(long double V) {
+    assert(sizeof(long double) == 16 && "Expected 16 byte long double");
+
+    const uint64_t Words[2] = {
+        static_cast<uint64_t>(V),
+        static_cast<uint64_t>(llvm::bit_cast<__uint128_t>(V) >> 64),
+    };
+    return APInt(sizeof(long double) * CHAR_BIT, 2, Words);
+  }
+
   /// @}
   /// \name Mathematics Operations
   /// @{
diff --git a/llvm/include/llvm/IR/Constants.h b/llvm/include/llvm/IR/Constants.h
index c0ac9a4aa6750c..782359f5445277 100644
--- a/llvm/include/llvm/IR/Constants.h
+++ b/llvm/include/llvm/IR/Constants.h
@@ -289,6 +289,8 @@ class ConstantFP final : public ConstantData {
   /// host double and as the target format.
   static Constant *get(Type *Ty, double V);
 
+  static Constant *get128(Type *Ty, long double V);
+
   /// If Ty is a vector type, return a Constant with a splat of the given
   /// value. Otherwise return a ConstantFP for the given value.
   static Constant *get(Type *Ty, const APFloat &V);
diff --git a/llvm/lib/Analysis/CMakeLists.txt b/llvm/lib/Analysis/CMakeLists.txt
index 35ea03f42f82b1..4473e888afa979 100644
--- a/llvm/lib/Analysis/CMakeLists.txt
+++ b/llvm/lib/Analysis/CMakeLists.txt
@@ -161,3 +161,9 @@ add_llvm_component_library(LLVMAnalysis
   Support
   TargetParser
   )
+
+include(CheckCXXSymbolExists)
+check_cxx_symbol_exists(logf128 math.h HAS_LOGF128)
+if(HAS_LOGF128)
+ target_compile_definitions(LLVMAnalysis PRIVATE HAS_LOGF128)
+endif()
\ No newline at end of file
diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp
index 8b7031e7fe4a6f..11a6307d924d15 100644
--- a/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/llvm/lib/Analysis/ConstantFolding.cpp
@@ -1678,9 +1678,9 @@ bool llvm::canConstantFoldCallTo(const CallBase *Call, const Function *F) {
            Name == "floor" || Name == "floorf" ||
            Name == "fmod" || Name == "fmodf";
   case 'l':
-    return Name == "log" || Name == "logf" ||
-           Name == "log2" || Name == "log2f" ||
-           Name == "log10" || Name == "log10f";
+    return Name == "log" || Name == "logf" || Name == "log2" ||
+           Name == "log2f" || Name == "log10" || Name == "log10f" ||
+           Name == "logl";
   case 'n':
     return Name == "nearbyint" || Name == "nearbyintf";
   case 'p':
@@ -1763,6 +1763,15 @@ inline bool llvm_fenv_testexcept() {
   return false;
 }
 
+Constant *ConstantFoldLogf128(const APFloat &V, Type *Ty) {
+#ifdef HAS_LOGF128
+  long double l = logf128(V.convertToQuad());
+  return ConstantFP::get128(Ty, l);
+#else
+  return nullptr;
+#endif
+}
+
 Constant *ConstantFoldFP(double (*NativeFP)(double), const APFloat &V,
                          Type *Ty) {
   llvm_fenv_clearexcept();
@@ -2094,7 +2103,8 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
     if (IntrinsicID == Intrinsic::canonicalize)
       return constantFoldCanonicalize(Ty, Call, U);
 
-    if (!Ty->isHalfTy() && !Ty->isFloatTy() && !Ty->isDoubleTy())
+    if (!Ty->isHalfTy() && !Ty->isFloatTy() && !Ty->isDoubleTy() &&
+        !Ty->isFP128Ty())
       return nullptr;
 
     // Use internal versions of these intrinsics.
@@ -2209,6 +2219,8 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
     switch (IntrinsicID) {
       default: break;
       case Intrinsic::log:
+        if (Ty->isFP128Ty())
+          return ConstantFoldLogf128(APF, Ty);
         return ConstantFoldFP(log, APF, Ty);
       case Intrinsic::log2:
         // TODO: What about hosts that lack a C99 library?
@@ -2338,6 +2350,11 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
       if (!APF.isNegative() && !APF.isZero() && TLI->has(Func))
         return ConstantFoldFP(log, APF, Ty);
       break;
+    case LibFunc_logl:
+      if (!APF.isNegative() && !APF.isZero() && TLI->has(Func) &&
+          Ty->isFP128Ty())
+        return ConstantFoldLogf128(APF, Ty);
+      break;
     case LibFunc_log2:
     case LibFunc_log2f:
     case LibFunc_log2_finite:
diff --git a/llvm/lib/IR/Constants.cpp b/llvm/lib/IR/Constants.cpp
index e6b92aad392f66..8482fee86c0ac3 100644
--- a/llvm/lib/IR/Constants.cpp
+++ b/llvm/lib/IR/Constants.cpp
@@ -976,6 +976,22 @@ Constant *ConstantFP::get(Type *Ty, double V) {
   return C;
 }
 
+Constant *ConstantFP::get128(Type *Ty, long double V) {
+  LLVMContext &Context = Ty->getContext();
+
+  APFloat FV(V);
+  bool ignored;
+  FV.convert(Ty->getScalarType()->getFltSemantics(),
+             APFloat::rmNearestTiesToEven, &ignored);
+  Constant *C = get(Context, FV);
+
+  // For vectors, broadcast the value.
+  if (VectorType *VTy = dyn_cast<VectorType>(Ty))
+    return ConstantVector::getSplat(VTy->getElementCount(), C);
+
+  return C;
+}
+
 Constant *ConstantFP::get(Type *Ty, const APFloat &V) {
   ConstantFP *C = get(Ty->getContext(), V);
   assert(C->getType() == Ty->getScalarType() &&
diff --git a/llvm/lib/Support/APFloat.cpp b/llvm/lib/Support/APFloat.cpp
index 0a4f5ac01553f1..d822613b2cfb19 100644
--- a/llvm/lib/Support/APFloat.cpp
+++ b/llvm/lib/Support/APFloat.cpp
@@ -3670,6 +3670,13 @@ double IEEEFloat::convertToDouble() const {
   return api.bitsToDouble();
 }
 
+long double IEEEFloat::convertToQuad() const {
+  assert(semantics == (const llvm::fltSemantics *)&semIEEEquad &&
+         "Float semantics are not IEEEquads");
+  APInt api = bitcastToAPInt();
+  return api.bitsToQuad();
+}
+
 /// Integer bit is explicit in this format.  Intel hardware (387 and later)
 /// does not support these bit patterns:
 ///  exponent = all 1's, integer bit 0, significand 0 ("pseudoinfinity")
@@ -3958,6 +3965,10 @@ IEEEFloat::IEEEFloat(double d) {
   initFromAPInt(&semIEEEdouble, APInt::doubleToBits(d));
 }
 
+IEEEFloat::IEEEFloat(long double ld) {
+  initFromAPInt(&semIEEEquad, APInt::longDoubleToBits(ld));
+}
+
 namespace {
   void append(SmallVectorImpl<char> &Buffer, StringRef Str) {
     Buffer.append(Str.begin(), Str.end());
@@ -5265,6 +5276,19 @@ double APFloat::convertToDouble() const {
   return Temp.getIEEE().convertToDouble();
 }
 
+long double APFloat::convertToQuad() const {
+  if (&getSemantics() == (const llvm::fltSemantics *)&semIEEEquad)
+    return getIEEE().convertToQuad();
+  assert(getSemantics().isRepresentableBy(semIEEEquad) &&
+         "Float semantics is not representable by IEEEquad");
+  APFloat Temp = *this;
+  bool LosesInfo;
+  opStatus St = Temp.convert(semIEEEquad, rmNearestTiesToEven, &LosesInfo);
+  assert(!(St & opInexact) && !LosesInfo && "Unexpected imprecision");
+  (void)St;
+  return Temp.getIEEE().convertToQuad();
+}
+
 float APFloat::convertToFloat() const {
   if (&getSemantics() == (const llvm::fltSemantics *)&semIEEEsingle)
     return getIEEE().convertToFloat();
diff --git a/llvm/unittests/Analysis/CMakeLists.txt b/llvm/unittests/Analysis/CMakeLists.txt
index b1aeaa6e71fd4c..796a31cc216812 100644
--- a/llvm/unittests/Analysis/CMakeLists.txt
+++ b/llvm/unittests/Analysis/CMakeLists.txt
@@ -51,6 +51,7 @@ set(ANALYSIS_TEST_SOURCES
   ValueLatticeTest.cpp
   ValueTrackingTest.cpp
   VectorUtilsTest.cpp
+  ConstantLogf128.cpp
   )
 
 set(MLGO_TESTS TFUtilsTest.cpp)
@@ -80,5 +81,11 @@ if(NOT WIN32)
   export_executable_symbols_for_plugins(AnalysisTests)
 endif()
 
+include(CheckCXXSymbolExists)
+check_cxx_symbol_exists(logf128 math.h HAS_LOGF128)
+if(HAS_LOGF128)
+  target_compile_definitions(AnalysisTests PRIVATE HAS_LOGF128)
+endif()
+
 add_subdirectory(InlineAdvisorPlugin)
 add_subdirectory(InlineOrderPlugin)
diff --git a/llvm/unittests/Analysis/ConstantLogf128.cpp b/llvm/unittests/Analysis/ConstantLogf128.cpp
new file mode 100644
index 00000000000000..fc1bcaa3d92641
--- /dev/null
+++ b/llvm/unittests/Analysis/ConstantLogf128.cpp
@@ -0,0 +1,74 @@
+//===- unittests/CodeGen/BufferSourceTest.cpp - MemoryBuffer source tests -===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Analysis/ConstantFolding.h"
+#include "llvm/Analysis/TargetLibraryInfo.h"
+#include "llvm/CodeGen/GlobalISel/CallLowering.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/InstrTypes.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+class ConstantFoldLogf128Fixture
+    : public ::testing ::TestWithParam<std::string> {
+protected:
+  std::string FuncName;
+};
+
+TEST_P(ConstantFoldLogf128Fixture, ConstantFoldLogf128) {
+  LLVMContext Context;
+  IRBuilder<> Builder(Context);
+  Module MainModule("Logf128TestModule", Context);
+  MainModule.setTargetTriple("aarch64-unknown-linux");
+
+  Type *FP128Ty = Type::getFP128Ty(Context);
+  FunctionType *FP128Prototype = FunctionType::get(FP128Ty, false);
+  Function *Logf128TestFunction = Function::Create(
+      FP128Prototype, Function::ExternalLinkage, "logf128test", MainModule);
+  BasicBlock *EntryBlock =
+      BasicBlock::Create(Context, "entry", Logf128TestFunction);
+  Builder.SetInsertPoint(EntryBlock);
+
+  FunctionType *FP128FP128Prototype =
+      FunctionType::get(FP128Ty, {FP128Ty}, false);
+  Constant *Constant2L = ConstantFP::get128(FP128Ty, 2.0L);
+
+  std::string FunctionName = GetParam();
+  Function *Logl = Function::Create(
+      FP128FP128Prototype, Function::ExternalLinkage, FunctionName, MainModule);
+  CallInst *LoglCall = Builder.CreateCall(Logl, Constant2L);
+
+  TargetLibraryInfoImpl TLII(Triple(MainModule.getTargetTriple()));
+  TargetLibraryInfo TLI(TLII, Logf128TestFunction);
+  Constant *FoldResult = ConstantFoldCall(LoglCall, Logl, Constant2L, &TLI);
+
+#ifndef HAS_LOGF128
+  ASSERT_TRUE(FoldResult == nullptr);
+#else
+  auto ConstantLog = dyn_cast<ConstantFP>(FoldResult);
+  ASSERT_TRUE(ConstantLog);
+
+  APFloat APF = ConstantLog->getValueAPF();
+  char LongDoubleHexString[0xFF];
+  unsigned Size =
+      APF.convertToHexString(LongDoubleHexString, 32, true,
+                             APFloatBase::roundingMode::NearestTiesToAway);
+  EXPECT_GT(Size, 0U);
+
+  ASSERT_STREQ(LongDoubleHexString,
+               std::string("0X1.62E42FEFA39E0000000000000000000P-1").c_str());
+#endif
+}
+
+INSTANTIATE_TEST_SUITE_P(ConstantFoldLogf128, ConstantFoldLogf128Fixture,
+                         ::testing::Values("logl", "llvm.log.f128"));
+
+} // end anonymous namespace

>From 511f476c17d256e13ceee8ccb2b04c670fce6189 Mon Sep 17 00:00:00 2001
From: Matt Devereau <matthew.devereau at arm.com>
Date: Tue, 12 Mar 2024 11:55:35 +0000
Subject: [PATCH 2/3] Change long double to float128

Use __float128 for clang and _Float128 for gcc.
Default to long double for other compilers.
---
 llvm/include/llvm/ADT/APFloat.h       |  9 +++++----
 llvm/include/llvm/ADT/APInt.h         | 11 +++++------
 llvm/include/llvm/IR/Constants.h      |  2 +-
 llvm/include/llvm/Support/float128.h  | 20 ++++++++++++++++++++
 llvm/lib/Analysis/ConstantFolding.cpp |  2 +-
 llvm/lib/IR/Constants.cpp             |  2 +-
 llvm/lib/Support/APFloat.cpp          |  6 +++---
 7 files changed, 36 insertions(+), 16 deletions(-)
 create mode 100644 llvm/include/llvm/Support/float128.h

diff --git a/llvm/include/llvm/ADT/APFloat.h b/llvm/include/llvm/ADT/APFloat.h
index 1ce50fc6996683..f3b1f54dc99e90 100644
--- a/llvm/include/llvm/ADT/APFloat.h
+++ b/llvm/include/llvm/ADT/APFloat.h
@@ -19,6 +19,7 @@
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/FloatingPointMode.h"
 #include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/float128.h"
 #include <memory>
 
 #define APFLOAT_DISPATCH_ON_SEMANTICS(METHOD_CALL)                             \
@@ -299,7 +300,7 @@ class IEEEFloat final : public APFloatBase {
   IEEEFloat(const fltSemantics &, integerPart);
   IEEEFloat(const fltSemantics &, uninitializedTag);
   IEEEFloat(const fltSemantics &, const APInt &);
-  explicit IEEEFloat(long double ld);
+  explicit IEEEFloat(float128 ld);
   explicit IEEEFloat(double d);
   explicit IEEEFloat(float f);
   IEEEFloat(const IEEEFloat &);
@@ -355,7 +356,7 @@ class IEEEFloat final : public APFloatBase {
   Expected<opStatus> convertFromString(StringRef, roundingMode);
   APInt bitcastToAPInt() const;
   double convertToDouble() const;
-  long double convertToQuad() const;
+  float128 convertToQuad() const;
   float convertToFloat() const;
 
   /// @}
@@ -944,7 +945,7 @@ class APFloat : public APFloatBase {
   APFloat(const fltSemantics &Semantics, uninitializedTag)
       : U(Semantics, uninitialized) {}
   APFloat(const fltSemantics &Semantics, const APInt &I) : U(Semantics, I) {}
-  explicit APFloat(long double ld) : U(IEEEFloat(ld), IEEEquad()) {}
+  explicit APFloat(float128 ld) : U(IEEEFloat(ld), IEEEquad()) {}
   explicit APFloat(double d) : U(IEEEFloat(d), IEEEdouble()) {}
   explicit APFloat(float f) : U(IEEEFloat(f), IEEEsingle()) {}
   APFloat(const APFloat &RHS) = default;
@@ -1226,7 +1227,7 @@ class APFloat : public APFloatBase {
   /// \pre The APFloat must be built using semantics, that can be represented by
   /// the host float type without loss of precision. It can be IEEEquad and
   /// shorter semantics, like IEEEdouble and others.
-  long double convertToQuad() const;
+  float128 convertToQuad() const;
 
   /// Converts this APFloat to host float value.
   ///
diff --git a/llvm/include/llvm/ADT/APInt.h b/llvm/include/llvm/ADT/APInt.h
index b85f051b4c7c41..ebeedd15051c1d 100644
--- a/llvm/include/llvm/ADT/APInt.h
+++ b/llvm/include/llvm/ADT/APInt.h
@@ -17,6 +17,7 @@
 
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/MathExtras.h"
+#include "llvm/Support/float128.h"
 #include <cassert>
 #include <climits>
 #include <cstring>
@@ -1663,9 +1664,9 @@ class [[nodiscard]] APInt {
   /// any bit width. Exactly 64 bits will be translated.
   double bitsToDouble() const { return llvm::bit_cast<double>(getWord(0)); }
 
-  long double bitsToQuad() const {
+  float128 bitsToQuad() const {
     __uint128_t ul = ((__uint128_t)U.pVal[1] << 64) + U.pVal[0];
-    return llvm::bit_cast<long double>(ul);
+    return llvm::bit_cast<float128>(ul);
   }
 
   /// Converts APInt bits to a float
@@ -1693,14 +1694,12 @@ class [[nodiscard]] APInt {
     return APInt(sizeof(float) * CHAR_BIT, llvm::bit_cast<uint32_t>(V));
   }
 
-  static APInt longDoubleToBits(long double V) {
-    assert(sizeof(long double) == 16 && "Expected 16 byte long double");
-
+  static APInt longDoubleToBits(float128 V) {
     const uint64_t Words[2] = {
         static_cast<uint64_t>(V),
         static_cast<uint64_t>(llvm::bit_cast<__uint128_t>(V) >> 64),
     };
-    return APInt(sizeof(long double) * CHAR_BIT, 2, Words);
+    return APInt(sizeof(float128) * CHAR_BIT, 2, Words);
   }
 
   /// @}
diff --git a/llvm/include/llvm/IR/Constants.h b/llvm/include/llvm/IR/Constants.h
index 782359f5445277..cd37e236df2a93 100644
--- a/llvm/include/llvm/IR/Constants.h
+++ b/llvm/include/llvm/IR/Constants.h
@@ -289,7 +289,7 @@ class ConstantFP final : public ConstantData {
   /// host double and as the target format.
   static Constant *get(Type *Ty, double V);
 
-  static Constant *get128(Type *Ty, long double V);
+  static Constant *get128(Type *Ty, float128 V);
 
   /// If Ty is a vector type, return a Constant with a splat of the given
   /// value. Otherwise return a ConstantFP for the given value.
diff --git a/llvm/include/llvm/Support/float128.h b/llvm/include/llvm/Support/float128.h
new file mode 100644
index 00000000000000..1e48cbdd84d13c
--- /dev/null
+++ b/llvm/include/llvm/Support/float128.h
@@ -0,0 +1,20 @@
+//===-- llvm/Support/float128.h - Compiler abstraction support --*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FLOAT128
+#define LLVM_FLOAT128
+
+#if defined(__clang__)
+typedef __float128 float128;
+#elif defined(__GNUC__) || defined(__GNUG__)
+typedef _Float128 float128;
+#else
+typedef long double float128;
+#endif
+
+#endif // LLVM_FLOAT128
diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp
index 11a6307d924d15..c9d4e8d73c0872 100644
--- a/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/llvm/lib/Analysis/ConstantFolding.cpp
@@ -1765,7 +1765,7 @@ inline bool llvm_fenv_testexcept() {
 
 Constant *ConstantFoldLogf128(const APFloat &V, Type *Ty) {
 #ifdef HAS_LOGF128
-  long double l = logf128(V.convertToQuad());
+  float128 l = logf128(V.convertToQuad());
   return ConstantFP::get128(Ty, l);
 #else
   return nullptr;
diff --git a/llvm/lib/IR/Constants.cpp b/llvm/lib/IR/Constants.cpp
index 8482fee86c0ac3..94ebc0df6b89c8 100644
--- a/llvm/lib/IR/Constants.cpp
+++ b/llvm/lib/IR/Constants.cpp
@@ -976,7 +976,7 @@ Constant *ConstantFP::get(Type *Ty, double V) {
   return C;
 }
 
-Constant *ConstantFP::get128(Type *Ty, long double V) {
+Constant *ConstantFP::get128(Type *Ty, float128 V) {
   LLVMContext &Context = Ty->getContext();
 
   APFloat FV(V);
diff --git a/llvm/lib/Support/APFloat.cpp b/llvm/lib/Support/APFloat.cpp
index d822613b2cfb19..7abbbea3dc22b7 100644
--- a/llvm/lib/Support/APFloat.cpp
+++ b/llvm/lib/Support/APFloat.cpp
@@ -3670,7 +3670,7 @@ double IEEEFloat::convertToDouble() const {
   return api.bitsToDouble();
 }
 
-long double IEEEFloat::convertToQuad() const {
+float128 IEEEFloat::convertToQuad() const {
   assert(semantics == (const llvm::fltSemantics *)&semIEEEquad &&
          "Float semantics are not IEEEquads");
   APInt api = bitcastToAPInt();
@@ -3965,7 +3965,7 @@ IEEEFloat::IEEEFloat(double d) {
   initFromAPInt(&semIEEEdouble, APInt::doubleToBits(d));
 }
 
-IEEEFloat::IEEEFloat(long double ld) {
+IEEEFloat::IEEEFloat(float128 ld) {
   initFromAPInt(&semIEEEquad, APInt::longDoubleToBits(ld));
 }
 
@@ -5276,7 +5276,7 @@ double APFloat::convertToDouble() const {
   return Temp.getIEEE().convertToDouble();
 }
 
-long double APFloat::convertToQuad() const {
+float128 APFloat::convertToQuad() const {
   if (&getSemantics() == (const llvm::fltSemantics *)&semIEEEquad)
     return getIEEE().convertToQuad();
   assert(getSemantics().isRepresentableBy(semIEEEquad) &&

>From 257e1d575f4ac744fe56be6441058bd025fe9e27 Mon Sep 17 00:00:00 2001
From: Matt Devereau <matthew.devereau at arm.com>
Date: Fri, 15 Mar 2024 14:17:40 +0000
Subject: [PATCH 3/3] Add ifdefs to avoid compiling float128 when the host does
 not have fp128

---
 llvm/include/llvm/ADT/APFloat.h             |  8 ++++++
 llvm/include/llvm/ADT/APInt.h               |  4 +++
 llvm/include/llvm/IR/Constants.h            |  2 ++
 llvm/include/llvm/Support/float128.h        |  6 ++---
 llvm/lib/Analysis/ConstantFolding.cpp       | 24 +++++------------
 llvm/lib/IR/Constants.cpp                   |  2 ++
 llvm/lib/Support/APFloat.cpp                |  6 +++++
 llvm/unittests/Analysis/ConstantLogf128.cpp | 29 ++++++++-------------
 8 files changed, 41 insertions(+), 40 deletions(-)

diff --git a/llvm/include/llvm/ADT/APFloat.h b/llvm/include/llvm/ADT/APFloat.h
index f3b1f54dc99e90..bd13e23f0ea649 100644
--- a/llvm/include/llvm/ADT/APFloat.h
+++ b/llvm/include/llvm/ADT/APFloat.h
@@ -300,7 +300,9 @@ class IEEEFloat final : public APFloatBase {
   IEEEFloat(const fltSemantics &, integerPart);
   IEEEFloat(const fltSemantics &, uninitializedTag);
   IEEEFloat(const fltSemantics &, const APInt &);
+#ifdef __FLOAT128__
   explicit IEEEFloat(float128 ld);
+#endif
   explicit IEEEFloat(double d);
   explicit IEEEFloat(float f);
   IEEEFloat(const IEEEFloat &);
@@ -356,7 +358,9 @@ class IEEEFloat final : public APFloatBase {
   Expected<opStatus> convertFromString(StringRef, roundingMode);
   APInt bitcastToAPInt() const;
   double convertToDouble() const;
+#ifdef __FLOAT128__
   float128 convertToQuad() const;
+#endif
   float convertToFloat() const;
 
   /// @}
@@ -945,7 +949,9 @@ class APFloat : public APFloatBase {
   APFloat(const fltSemantics &Semantics, uninitializedTag)
       : U(Semantics, uninitialized) {}
   APFloat(const fltSemantics &Semantics, const APInt &I) : U(Semantics, I) {}
+#ifdef __FLOAT128__
   explicit APFloat(float128 ld) : U(IEEEFloat(ld), IEEEquad()) {}
+#endif
   explicit APFloat(double d) : U(IEEEFloat(d), IEEEdouble()) {}
   explicit APFloat(float f) : U(IEEEFloat(f), IEEEsingle()) {}
   APFloat(const APFloat &RHS) = default;
@@ -1227,7 +1233,9 @@ class APFloat : public APFloatBase {
   /// \pre The APFloat must be built using semantics, that can be represented by
   /// the host float type without loss of precision. It can be IEEEquad and
   /// shorter semantics, like IEEEdouble and others.
+#ifdef __FLOAT128__
   float128 convertToQuad() const;
+#endif
 
   /// Converts this APFloat to host float value.
   ///
diff --git a/llvm/include/llvm/ADT/APInt.h b/llvm/include/llvm/ADT/APInt.h
index ebeedd15051c1d..b7d73107dc0831 100644
--- a/llvm/include/llvm/ADT/APInt.h
+++ b/llvm/include/llvm/ADT/APInt.h
@@ -1664,10 +1664,12 @@ class [[nodiscard]] APInt {
   /// any bit width. Exactly 64 bits will be translated.
   double bitsToDouble() const { return llvm::bit_cast<double>(getWord(0)); }
 
+#ifdef __FLOAT128__
   float128 bitsToQuad() const {
     __uint128_t ul = ((__uint128_t)U.pVal[1] << 64) + U.pVal[0];
     return llvm::bit_cast<float128>(ul);
   }
+#endif
 
   /// Converts APInt bits to a float
   ///
@@ -1694,6 +1696,7 @@ class [[nodiscard]] APInt {
     return APInt(sizeof(float) * CHAR_BIT, llvm::bit_cast<uint32_t>(V));
   }
 
+#ifdef __FLOAT128__
   static APInt longDoubleToBits(float128 V) {
     const uint64_t Words[2] = {
         static_cast<uint64_t>(V),
@@ -1701,6 +1704,7 @@ class [[nodiscard]] APInt {
     };
     return APInt(sizeof(float128) * CHAR_BIT, 2, Words);
   }
+#endif
 
   /// @}
   /// \name Mathematics Operations
diff --git a/llvm/include/llvm/IR/Constants.h b/llvm/include/llvm/IR/Constants.h
index cd37e236df2a93..e924130f66f381 100644
--- a/llvm/include/llvm/IR/Constants.h
+++ b/llvm/include/llvm/IR/Constants.h
@@ -289,7 +289,9 @@ class ConstantFP final : public ConstantData {
   /// host double and as the target format.
   static Constant *get(Type *Ty, double V);
 
+#ifdef __FLOAT128__
   static Constant *get128(Type *Ty, float128 V);
+#endif
 
   /// If Ty is a vector type, return a Constant with a splat of the given
   /// value. Otherwise return a ConstantFP for the given value.
diff --git a/llvm/include/llvm/Support/float128.h b/llvm/include/llvm/Support/float128.h
index 1e48cbdd84d13c..6ff844cd7b35ab 100644
--- a/llvm/include/llvm/Support/float128.h
+++ b/llvm/include/llvm/Support/float128.h
@@ -9,12 +9,10 @@
 #ifndef LLVM_FLOAT128
 #define LLVM_FLOAT128
 
-#if defined(__clang__)
+#if defined(__clang__) && defined(__FLOAT128__)
 typedef __float128 float128;
-#elif defined(__GNUC__) || defined(__GNUG__)
+#elif defined(__FLOAT128__) && (defined(__GNUC__) || defined(__GNUG__))
 typedef _Float128 float128;
-#else
-typedef long double float128;
 #endif
 
 #endif // LLVM_FLOAT128
diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp
index c9d4e8d73c0872..fca22f3ab342b5 100644
--- a/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/llvm/lib/Analysis/ConstantFolding.cpp
@@ -1679,8 +1679,7 @@ bool llvm::canConstantFoldCallTo(const CallBase *Call, const Function *F) {
            Name == "fmod" || Name == "fmodf";
   case 'l':
     return Name == "log" || Name == "logf" || Name == "log2" ||
-           Name == "log2f" || Name == "log10" || Name == "log10f" ||
-           Name == "logl";
+           Name == "log2f" || Name == "log10" || Name == "log10f";
   case 'n':
     return Name == "nearbyint" || Name == "nearbyintf";
   case 'p':
@@ -1763,15 +1762,6 @@ inline bool llvm_fenv_testexcept() {
   return false;
 }
 
-Constant *ConstantFoldLogf128(const APFloat &V, Type *Ty) {
-#ifdef HAS_LOGF128
-  float128 l = logf128(V.convertToQuad());
-  return ConstantFP::get128(Ty, l);
-#else
-  return nullptr;
-#endif
-}
-
 Constant *ConstantFoldFP(double (*NativeFP)(double), const APFloat &V,
                          Type *Ty) {
   llvm_fenv_clearexcept();
@@ -2219,8 +2209,11 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
     switch (IntrinsicID) {
       default: break;
       case Intrinsic::log:
-        if (Ty->isFP128Ty())
-          return ConstantFoldLogf128(APF, Ty);
+        #if defined(__FLOAT128__) && defined (HAS_LOGF128)
+        if (Ty->isFP128Ty()){
+          return ConstantFP::get(Ty, logf128(APF.convertToQuad()));
+        }
+        #endif
         return ConstantFoldFP(log, APF, Ty);
       case Intrinsic::log2:
         // TODO: What about hosts that lack a C99 library?
@@ -2350,11 +2343,6 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
       if (!APF.isNegative() && !APF.isZero() && TLI->has(Func))
         return ConstantFoldFP(log, APF, Ty);
       break;
-    case LibFunc_logl:
-      if (!APF.isNegative() && !APF.isZero() && TLI->has(Func) &&
-          Ty->isFP128Ty())
-        return ConstantFoldLogf128(APF, Ty);
-      break;
     case LibFunc_log2:
     case LibFunc_log2f:
     case LibFunc_log2_finite:
diff --git a/llvm/lib/IR/Constants.cpp b/llvm/lib/IR/Constants.cpp
index 94ebc0df6b89c8..69cdbcaf22b3fc 100644
--- a/llvm/lib/IR/Constants.cpp
+++ b/llvm/lib/IR/Constants.cpp
@@ -976,6 +976,7 @@ Constant *ConstantFP::get(Type *Ty, double V) {
   return C;
 }
 
+#ifdef __FLOAT128__
 Constant *ConstantFP::get128(Type *Ty, float128 V) {
   LLVMContext &Context = Ty->getContext();
 
@@ -991,6 +992,7 @@ Constant *ConstantFP::get128(Type *Ty, float128 V) {
 
   return C;
 }
+#endif
 
 Constant *ConstantFP::get(Type *Ty, const APFloat &V) {
   ConstantFP *C = get(Ty->getContext(), V);
diff --git a/llvm/lib/Support/APFloat.cpp b/llvm/lib/Support/APFloat.cpp
index 7abbbea3dc22b7..6c58a36408c8b7 100644
--- a/llvm/lib/Support/APFloat.cpp
+++ b/llvm/lib/Support/APFloat.cpp
@@ -3670,12 +3670,14 @@ double IEEEFloat::convertToDouble() const {
   return api.bitsToDouble();
 }
 
+#ifdef __FLOAT128__
 float128 IEEEFloat::convertToQuad() const {
   assert(semantics == (const llvm::fltSemantics *)&semIEEEquad &&
          "Float semantics are not IEEEquads");
   APInt api = bitcastToAPInt();
   return api.bitsToQuad();
 }
+#endif
 
 /// Integer bit is explicit in this format.  Intel hardware (387 and later)
 /// does not support these bit patterns:
@@ -3965,9 +3967,11 @@ IEEEFloat::IEEEFloat(double d) {
   initFromAPInt(&semIEEEdouble, APInt::doubleToBits(d));
 }
 
+#ifdef __FLOAT128__
 IEEEFloat::IEEEFloat(float128 ld) {
   initFromAPInt(&semIEEEquad, APInt::longDoubleToBits(ld));
 }
+#endif
 
 namespace {
   void append(SmallVectorImpl<char> &Buffer, StringRef Str) {
@@ -5276,6 +5280,7 @@ double APFloat::convertToDouble() const {
   return Temp.getIEEE().convertToDouble();
 }
 
+#ifdef __FLOAT128__
 float128 APFloat::convertToQuad() const {
   if (&getSemantics() == (const llvm::fltSemantics *)&semIEEEquad)
     return getIEEE().convertToQuad();
@@ -5288,6 +5293,7 @@ float128 APFloat::convertToQuad() const {
   (void)St;
   return Temp.getIEEE().convertToQuad();
 }
+#endif
 
 float APFloat::convertToFloat() const {
   if (&getSemantics() == (const llvm::fltSemantics *)&semIEEEsingle)
diff --git a/llvm/unittests/Analysis/ConstantLogf128.cpp b/llvm/unittests/Analysis/ConstantLogf128.cpp
index fc1bcaa3d92641..7c2efcc6dbb964 100644
--- a/llvm/unittests/Analysis/ConstantLogf128.cpp
+++ b/llvm/unittests/Analysis/ConstantLogf128.cpp
@@ -17,13 +17,8 @@ using namespace llvm;
 
 namespace {
 
-class ConstantFoldLogf128Fixture
-    : public ::testing ::TestWithParam<std::string> {
-protected:
-  std::string FuncName;
-};
-
-TEST_P(ConstantFoldLogf128Fixture, ConstantFoldLogf128) {
+TEST(ConstantFoldLogf128Fixture, ConstantFoldLogf128) {
+#ifdef __FLOAT128__
   LLVMContext Context;
   IRBuilder<> Builder(Context);
   Module MainModule("Logf128TestModule", Context);
@@ -40,15 +35,13 @@ TEST_P(ConstantFoldLogf128Fixture, ConstantFoldLogf128) {
   FunctionType *FP128FP128Prototype =
       FunctionType::get(FP128Ty, {FP128Ty}, false);
   Constant *Constant2L = ConstantFP::get128(FP128Ty, 2.0L);
-
-  std::string FunctionName = GetParam();
-  Function *Logl = Function::Create(
-      FP128FP128Prototype, Function::ExternalLinkage, FunctionName, MainModule);
-  CallInst *LoglCall = Builder.CreateCall(Logl, Constant2L);
+  Function *Logf128 = Function::Create(
+      FP128FP128Prototype, Function::ExternalLinkage, "llvm.log.f128", MainModule);
+  CallInst *Logf128Call = Builder.CreateCall(Logf128, Constant2L);
 
   TargetLibraryInfoImpl TLII(Triple(MainModule.getTargetTriple()));
   TargetLibraryInfo TLI(TLII, Logf128TestFunction);
-  Constant *FoldResult = ConstantFoldCall(LoglCall, Logl, Constant2L, &TLI);
+  Constant *FoldResult = ConstantFoldCall(Logf128Call, Logf128, Constant2L, &TLI);
 
 #ifndef HAS_LOGF128
   ASSERT_TRUE(FoldResult == nullptr);
@@ -64,11 +57,11 @@ TEST_P(ConstantFoldLogf128Fixture, ConstantFoldLogf128) {
   EXPECT_GT(Size, 0U);
 
   ASSERT_STREQ(LongDoubleHexString,
-               std::string("0X1.62E42FEFA39E0000000000000000000P-1").c_str());
+               std::string("0X1.62E42FEFA39EF000000000000000000P-1").c_str());
+#endif //HAS_LOGF128
+#else // __FLOAT128__
+  ASSERT_TRUE(true);
 #endif
 }
 
-INSTANTIATE_TEST_SUITE_P(ConstantFoldLogf128, ConstantFoldLogf128Fixture,
-                         ::testing::Values("logl", "llvm.log.f128"));
-
-} // end anonymous namespace
+}
\ No newline at end of file



More information about the llvm-commits mailing list