From af0331385f5564d1a6785c100576f52c601bbeef Mon Sep 17 00:00:00 2001 From: Matt Devereau Date: Mon, 26 Feb 2024 15:32:09 +0000 Subject: [PATCH 1/9] 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 deb74cb2fdeb1..0226a787b355a 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 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 8d3c029b2e7e9..76fbdd779d9cd 100644 --- a/llvm/include/llvm/ADT/APInt.h +++ b/llvm/include/llvm/ADT/APInt.h @@ -1670,6 +1670,11 @@ class [[nodiscard]] APInt { /// any bit width. Exactly 64 bits will be translated. double bitsToDouble() const { return llvm::bit_cast(getWord(0)); } + long double bitsToQuad() const { + __uint128_t ul = ((__uint128_t)U.pVal[1] << 64) + U.pVal[0]; + return llvm::bit_cast(ul); + } + /// Converts APInt bits to a float /// /// The conversion does not do a translation from integer to float, it just @@ -1695,6 +1700,16 @@ class [[nodiscard]] APInt { return APInt(sizeof(float) * CHAR_BIT, llvm::bit_cast(V)); } + static APInt longDoubleToBits(long double V) { + assert(sizeof(long double) == 16 && "Expected 16 byte long double"); + + const uint64_t Words[2] = { + static_cast(V), + static_cast(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 4290ef4486c6f..d43ff0bbe36a1 100644 --- a/llvm/include/llvm/IR/Constants.h +++ b/llvm/include/llvm/IR/Constants.h @@ -290,6 +290,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 474b8d20fde16..3d443cef2e65c 100644 --- a/llvm/lib/Analysis/CMakeLists.txt +++ b/llvm/lib/Analysis/CMakeLists.txt @@ -159,3 +159,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 749374a3aa48a..73faf00898575 100644 --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -1673,9 +1673,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': @@ -1758,6 +1758,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(); @@ -2089,7 +2098,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. @@ -2204,6 +2214,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? @@ -2333,6 +2345,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 a5fb497f54ed1..050addf43e789 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(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 0a4f5ac01553f..d822613b2cfb1 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 &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 b1aeaa6e71fd4..796a31cc21681 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 0000000000000..fc1bcaa3d9264 --- /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 { +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(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 d959ed9bd0d0697d8142e1f8ae6e3d93e71912e2 Mon Sep 17 00:00:00 2001 From: Matt Devereau Date: Tue, 12 Mar 2024 11:55:35 +0000 Subject: [PATCH 2/9] 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 0226a787b355a..4253e08ead198 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 #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 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 76fbdd779d9cd..36d2b449deb86 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 #include #include @@ -1670,9 +1671,9 @@ class [[nodiscard]] APInt { /// any bit width. Exactly 64 bits will be translated. double bitsToDouble() const { return llvm::bit_cast(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(ul); + return llvm::bit_cast(ul); } /// Converts APInt bits to a float @@ -1700,14 +1701,12 @@ class [[nodiscard]] APInt { return APInt(sizeof(float) * CHAR_BIT, llvm::bit_cast(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(V), static_cast(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 d43ff0bbe36a1..ece9d02ac6927 100644 --- a/llvm/include/llvm/IR/Constants.h +++ b/llvm/include/llvm/IR/Constants.h @@ -290,7 +290,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 0000000000000..1e48cbdd84d13 --- /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 73faf00898575..4348aaffd5032 100644 --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -1760,7 +1760,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 050addf43e789..a5760dbd91038 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 d822613b2cfb1..7abbbea3dc22b 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 d862a1a2e26cd3d32f948f0a6c8379d6b3790ba7 Mon Sep 17 00:00:00 2001 From: Matt Devereau Date: Fri, 15 Mar 2024 14:17:40 +0000 Subject: [PATCH 3/9] 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 4253e08ead198..fcc8ffbce8b95 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 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 36d2b449deb86..00431edf14c9f 100644 --- a/llvm/include/llvm/ADT/APInt.h +++ b/llvm/include/llvm/ADT/APInt.h @@ -1671,10 +1671,12 @@ class [[nodiscard]] APInt { /// any bit width. Exactly 64 bits will be translated. double bitsToDouble() const { return llvm::bit_cast(getWord(0)); } +#ifdef __FLOAT128__ float128 bitsToQuad() const { __uint128_t ul = ((__uint128_t)U.pVal[1] << 64) + U.pVal[0]; return llvm::bit_cast(ul); } +#endif /// Converts APInt bits to a float /// @@ -1701,6 +1703,7 @@ class [[nodiscard]] APInt { return APInt(sizeof(float) * CHAR_BIT, llvm::bit_cast(V)); } +#ifdef __FLOAT128__ static APInt longDoubleToBits(float128 V) { const uint64_t Words[2] = { static_cast(V), @@ -1708,6 +1711,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 ece9d02ac6927..f21153dd5c343 100644 --- a/llvm/include/llvm/IR/Constants.h +++ b/llvm/include/llvm/IR/Constants.h @@ -290,7 +290,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 1e48cbdd84d13..6ff844cd7b35a 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 4348aaffd5032..408e3a5031662 100644 --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -1674,8 +1674,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': @@ -1758,15 +1757,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(); @@ -2214,8 +2204,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? @@ -2345,11 +2338,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 a5760dbd91038..fc45d48c11215 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 7abbbea3dc22b..6c58a36408c8b 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 &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 fc1bcaa3d9264..7c2efcc6dbb96 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 { -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 From ca14318a410eb82d7ba04d8ac308b8676e269b48 Mon Sep 17 00:00:00 2001 From: Matt Devereau Date: Mon, 25 Mar 2024 13:39:09 +0000 Subject: [PATCH 4/9] Run Clang-format --- llvm/lib/Analysis/ConstantFolding.cpp | 6 +++--- llvm/unittests/Analysis/ConstantLogf128.cpp | 14 ++++++++------ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp index 408e3a5031662..fc792f67e859a 100644 --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -2204,11 +2204,11 @@ static Constant *ConstantFoldScalarCall1(StringRef Name, switch (IntrinsicID) { default: break; case Intrinsic::log: - #if defined(__FLOAT128__) && defined (HAS_LOGF128) - if (Ty->isFP128Ty()){ +#if defined(__FLOAT128__) && defined(HAS_LOGF128) + if (Ty->isFP128Ty()) { return ConstantFP::get(Ty, logf128(APF.convertToQuad())); } - #endif +#endif return ConstantFoldFP(log, APF, Ty); case Intrinsic::log2: // TODO: What about hosts that lack a C99 library? diff --git a/llvm/unittests/Analysis/ConstantLogf128.cpp b/llvm/unittests/Analysis/ConstantLogf128.cpp index 7c2efcc6dbb96..1be7e9b4ab9c4 100644 --- a/llvm/unittests/Analysis/ConstantLogf128.cpp +++ b/llvm/unittests/Analysis/ConstantLogf128.cpp @@ -35,13 +35,15 @@ TEST(ConstantFoldLogf128Fixture, ConstantFoldLogf128) { FunctionType *FP128FP128Prototype = FunctionType::get(FP128Ty, {FP128Ty}, false); Constant *Constant2L = ConstantFP::get128(FP128Ty, 2.0L); - Function *Logf128 = Function::Create( - FP128FP128Prototype, Function::ExternalLinkage, "llvm.log.f128", MainModule); + 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(Logf128Call, Logf128, Constant2L, &TLI); + Constant *FoldResult = + ConstantFoldCall(Logf128Call, Logf128, Constant2L, &TLI); #ifndef HAS_LOGF128 ASSERT_TRUE(FoldResult == nullptr); @@ -58,10 +60,10 @@ TEST(ConstantFoldLogf128Fixture, ConstantFoldLogf128) { ASSERT_STREQ(LongDoubleHexString, std::string("0X1.62E42FEFA39EF000000000000000000P-1").c_str()); -#endif //HAS_LOGF128 -#else // __FLOAT128__ +#endif // HAS_LOGF128 +#else // __FLOAT128__ ASSERT_TRUE(true); #endif } -} \ No newline at end of file +} // namespace \ No newline at end of file From 48e5f1b571720e2ab99ad6fbeec58b2cf944bbdf Mon Sep 17 00:00:00 2001 From: Matt Devereau Date: Thu, 28 Mar 2024 17:14:07 +0000 Subject: [PATCH 5/9] Add REQUIRES: logf128 lit guard and move tests to instsimplify --- llvm/CMakeLists.txt | 2 + llvm/cmake/config-ix.cmake | 11 +++ llvm/include/llvm/Config/llvm-config.h.cmake | 3 + llvm/include/llvm/IR/Constants.h | 4 - llvm/include/llvm/Support/float128.h | 3 + llvm/lib/Analysis/ConstantFolding.cpp | 19 +++-- llvm/lib/IR/Constants.cpp | 18 ----- llvm/test/CMakeLists.txt | 1 + .../InstSimplify/ConstProp/logf128.ll | 79 +++++++++++++++++++ llvm/test/lit.cfg.py | 3 + llvm/test/lit.site.cfg.py.in | 1 + llvm/unittests/Analysis/CMakeLists.txt | 1 - llvm/unittests/Analysis/ConstantLogf128.cpp | 69 ---------------- 13 files changed, 115 insertions(+), 99 deletions(-) create mode 100644 llvm/test/Transforms/InstSimplify/ConstProp/logf128.ll delete mode 100644 llvm/unittests/Analysis/ConstantLogf128.cpp diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt index d511376e18ba5..c48ab438ffe0b 100644 --- a/llvm/CMakeLists.txt +++ b/llvm/CMakeLists.txt @@ -562,6 +562,8 @@ set(LLVM_USE_STATIC_ZSTD FALSE CACHE BOOL "Use static version of zstd. Can be TR set(LLVM_ENABLE_CURL "OFF" CACHE STRING "Use libcurl for the HTTP client if available. Can be ON, OFF, or FORCE_ON") +set(LLVM_HAS_LOGF128 "OFF" CACHE STRING "Use logf128 to constant fold fp128 logarithm calls. Can be ON, OFF, or FORCE_ON") + set(LLVM_ENABLE_HTTPLIB "OFF" CACHE STRING "Use cpp-httplib HTTP server library if available. Can be ON, OFF, or FORCE_ON") set(LLVM_Z3_INSTALL_DIR "" CACHE STRING "Install directory of the Z3 solver.") diff --git a/llvm/cmake/config-ix.cmake b/llvm/cmake/config-ix.cmake index bf1b110245bb2..ce07cab7a56c6 100644 --- a/llvm/cmake/config-ix.cmake +++ b/llvm/cmake/config-ix.cmake @@ -257,6 +257,17 @@ else() set(LLVM_ENABLE_TERMINFO 0) endif() +if(LLVM_HAS_LOGF128) + include(CheckCXXSymbolExists) + check_cxx_symbol_exists(logf128 math.h HAS_LOGF128) + + if(LLVM_HAS_LOGF128 STREQUAL FORCE_ON AND NOT HAS_LOGF128) + message(FATAL_ERROR "Failed to configure logf128") + endif() + + set(LLVM_HAS_LOGF128 "${HAS_LOGF128}") +endif() + # function checks check_symbol_exists(arc4random "stdlib.h" HAVE_DECL_ARC4RANDOM) find_package(Backtrace) diff --git a/llvm/include/llvm/Config/llvm-config.h.cmake b/llvm/include/llvm/Config/llvm-config.h.cmake index 6605ea60df99e..629977cc11d68 100644 --- a/llvm/include/llvm/Config/llvm-config.h.cmake +++ b/llvm/include/llvm/Config/llvm-config.h.cmake @@ -198,4 +198,7 @@ /* Define if plugins enabled */ #cmakedefine LLVM_ENABLE_PLUGINS +/* Define if logf128 is available */ +#cmakedefine LLVM_HAS_LOGF128 + #endif diff --git a/llvm/include/llvm/IR/Constants.h b/llvm/include/llvm/IR/Constants.h index f21153dd5c343..4290ef4486c6f 100644 --- a/llvm/include/llvm/IR/Constants.h +++ b/llvm/include/llvm/IR/Constants.h @@ -290,10 +290,6 @@ 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. static Constant *get(Type *Ty, const APFloat &V); diff --git a/llvm/include/llvm/Support/float128.h b/llvm/include/llvm/Support/float128.h index 6ff844cd7b35a..f7a442fce8dd3 100644 --- a/llvm/include/llvm/Support/float128.h +++ b/llvm/include/llvm/Support/float128.h @@ -9,10 +9,13 @@ #ifndef LLVM_FLOAT128 #define LLVM_FLOAT128 +namespace llvm { + #if defined(__clang__) && defined(__FLOAT128__) typedef __float128 float128; #elif defined(__FLOAT128__) && (defined(__GNUC__) || defined(__GNUG__)) typedef _Float128 float128; #endif +} // namespace llvm #endif // LLVM_FLOAT128 diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp index fc792f67e859a..9c7664ab55b34 100644 --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -2088,8 +2088,18 @@ static Constant *ConstantFoldScalarCall1(StringRef Name, if (IntrinsicID == Intrinsic::canonicalize) return constantFoldCanonicalize(Ty, Call, U); - if (!Ty->isHalfTy() && !Ty->isFloatTy() && !Ty->isDoubleTy() && - !Ty->isFP128Ty()) +#if defined(__FLOAT128__) && defined(HAS_LOGF128) + if (Ty->isFP128Ty()) { + switch (IntrinsicID) { + default: + return nullptr; + case Intrinsic::log: + return ConstantFP::get(Ty, logf128(Op->getValueAPF().convertToQuad())); + } + } +#endif + + if (!Ty->isHalfTy() && !Ty->isFloatTy() && !Ty->isDoubleTy()) return nullptr; // Use internal versions of these intrinsics. @@ -2204,11 +2214,6 @@ static Constant *ConstantFoldScalarCall1(StringRef Name, switch (IntrinsicID) { default: break; case Intrinsic::log: -#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? diff --git a/llvm/lib/IR/Constants.cpp b/llvm/lib/IR/Constants.cpp index fc45d48c11215..a5fb497f54ed1 100644 --- a/llvm/lib/IR/Constants.cpp +++ b/llvm/lib/IR/Constants.cpp @@ -976,24 +976,6 @@ Constant *ConstantFP::get(Type *Ty, double V) { return C; } -#ifdef __FLOAT128__ -Constant *ConstantFP::get128(Type *Ty, float128 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(Ty)) - return ConstantVector::getSplat(VTy->getElementCount(), C); - - return C; -} -#endif - Constant *ConstantFP::get(Type *Ty, const APFloat &V) { ConstantFP *C = get(Ty->getContext(), V); assert(C->getType() == Ty->getScalarType() && diff --git a/llvm/test/CMakeLists.txt b/llvm/test/CMakeLists.txt index 6127b76db06b7..b419464aba3f5 100644 --- a/llvm/test/CMakeLists.txt +++ b/llvm/test/CMakeLists.txt @@ -25,6 +25,7 @@ llvm_canonicalize_cmake_booleans( LLVM_INCLUDE_DXIL_TESTS LLVM_TOOL_LLVM_DRIVER_BUILD LLVM_INCLUDE_SPIRV_TOOLS_TESTS + LLVM_HAS_LOGF128 ) configure_lit_site_cfg( diff --git a/llvm/test/Transforms/InstSimplify/ConstProp/logf128.ll b/llvm/test/Transforms/InstSimplify/ConstProp/logf128.ll new file mode 100644 index 0000000000000..387e8eda6173d --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/ConstProp/logf128.ll @@ -0,0 +1,79 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4 +; RUN: opt < %s -passes=instsimplify -S | FileCheck %s + +; REQUIRES: has_logf128 +; REQUIRES: aarch64-registered-target +declare fp128 @llvm.log.f128(fp128) + +define fp128 @log_e_64(){ +; CHECK-LABEL: define fp128 @log_e_64() { +; CHECK-NEXT: ret fp128 0xL300000000000000040010A2B23F3BAB7 +; + %A = call fp128 @llvm.log.f128(fp128 noundef 0xL00000000000000004005000000000000) + ret fp128 %A +} + +define fp128 @log_e_smallest_positive_subnormal_number(){ +; CHECK-LABEL: define fp128 @log_e_smallest_positive_subnormal_number() { +; CHECK-NEXT: ret fp128 0xL3000000000000000C00C654628220780 +; + %A = call fp128 @llvm.log.f128(fp128 noundef 0xL00000000000000010000000000000000) + ret fp128 %A +} + +define fp128 @log_e_largest_subnormal_number(){ +; CHECK-LABEL: define fp128 @log_e_largest_subnormal_number() { +; CHECK-NEXT: ret fp128 0xLD000000000000000C00C62D918CE2421 +; + %A = call fp128 @llvm.log.f128(fp128 noundef 0xLFFFFFFFFFFFFFFFF0000FFFFFFFFFFFF) + ret fp128 %A +} + +define fp128 @log_e_smallest_positive_normal_number(){ +; +; CHECK-LABEL: define fp128 @log_e_smallest_positive_normal_number() { +; CHECK-NEXT: ret fp128 0xLD000000000000000C00C62D918CE2421 +; + %A = call fp128 @llvm.log.f128(fp128 noundef 0xL00000000000000000001000000000000) + ret fp128 %A +} + +define fp128 @log_e_largest_normal_number(){ +; CHECK-LABEL: define fp128 @log_e_largest_normal_number() { +; CHECK-NEXT: ret fp128 0xLF000000000000000400C62E42FEFA39E +; + %A = call fp128 @llvm.log.f128(fp128 noundef 0xLFFFFFFFFFFFFFFFF7FFEFFFFFFFFFFFF) + ret fp128 %A +} + +define fp128 @log_e_largest_number_less_than_one(){ +; CHECK-LABEL: define fp128 @log_e_largest_number_less_than_one() { +; CHECK-NEXT: ret fp128 0xL0000000000000000BF8E000000000000 +; + %A = call fp128 @llvm.log.f128(fp128 noundef 0xLFFFFFFFFFFFFFFFF3FFEFFFFFFFFFFFF) + ret fp128 %A +} + +define fp128 @log_e_1(){ +; CHECK-LABEL: define fp128 @log_e_1() { +; CHECK-NEXT: ret fp128 0xL00000000000000000000000000000000 +; + %A = call fp128 @llvm.log.f128(fp128 noundef 0xL00000000000000003FFF000000000000) + ret fp128 %A +} + +define fp128 @log_e_smallest_number_larger_than_one(){ +; CHECK-LABEL: define fp128 @log_e_smallest_number_larger_than_one() { +; CHECK-NEXT: ret fp128 0xL00000000000000003F8F000000000000 +; + %A = call fp128 @llvm.log.f128(fp128 noundef 0xL00000000000000013FFF000000000000) + ret fp128 %A +} + +define fp128 @log_e_minus_2(){ +; CHECK-LABEL: define fp128 @log_e_minus_2() { +; CHECK-NEXT: ret fp128 0xL00000000000000007FFF800000000000 +; + %A = call fp128 @llvm.log.f128(fp128 noundef 0xL0000000000000000C000000000000000) + ret fp128 %A +} diff --git a/llvm/test/lit.cfg.py b/llvm/test/lit.cfg.py index 4c05317036d1a..356f006e5dcf3 100644 --- a/llvm/test/lit.cfg.py +++ b/llvm/test/lit.cfg.py @@ -614,3 +614,6 @@ def have_ld64_plugin_support(): # "OBJECT_MODE" to 'any' by default on AIX OS. if "system-aix" in config.available_features: config.environment["OBJECT_MODE"] = "any" + +if config.has_logf128: + config.available_features.add("has_logf128") \ No newline at end of file diff --git a/llvm/test/lit.site.cfg.py.in b/llvm/test/lit.site.cfg.py.in index b6f255d472d16..27cb1dd6477d9 100644 --- a/llvm/test/lit.site.cfg.py.in +++ b/llvm/test/lit.site.cfg.py.in @@ -61,6 +61,7 @@ config.reverse_iteration = @LLVM_ENABLE_REVERSE_ITERATION@ config.dxil_tests = @LLVM_INCLUDE_DXIL_TESTS@ config.have_llvm_driver = @LLVM_TOOL_LLVM_DRIVER_BUILD@ config.spirv_tools_tests = @LLVM_INCLUDE_SPIRV_TOOLS_TESTS@ +config.has_logf128 = @LLVM_HAS_LOGF128@ import lit.llvm lit.llvm.initialize(lit_config, config) diff --git a/llvm/unittests/Analysis/CMakeLists.txt b/llvm/unittests/Analysis/CMakeLists.txt index 796a31cc21681..9b3778f8a3f98 100644 --- a/llvm/unittests/Analysis/CMakeLists.txt +++ b/llvm/unittests/Analysis/CMakeLists.txt @@ -51,7 +51,6 @@ set(ANALYSIS_TEST_SOURCES ValueLatticeTest.cpp ValueTrackingTest.cpp VectorUtilsTest.cpp - ConstantLogf128.cpp ) set(MLGO_TESTS TFUtilsTest.cpp) diff --git a/llvm/unittests/Analysis/ConstantLogf128.cpp b/llvm/unittests/Analysis/ConstantLogf128.cpp deleted file mode 100644 index 1be7e9b4ab9c4..0000000000000 --- a/llvm/unittests/Analysis/ConstantLogf128.cpp +++ /dev/null @@ -1,69 +0,0 @@ -//===- 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 { - -TEST(ConstantFoldLogf128Fixture, ConstantFoldLogf128) { -#ifdef __FLOAT128__ - 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); - 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(Logf128Call, Logf128, Constant2L, &TLI); - -#ifndef HAS_LOGF128 - ASSERT_TRUE(FoldResult == nullptr); -#else - auto ConstantLog = dyn_cast(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.62E42FEFA39EF000000000000000000P-1").c_str()); -#endif // HAS_LOGF128 -#else // __FLOAT128__ - ASSERT_TRUE(true); -#endif -} - -} // namespace \ No newline at end of file From 24af5798f52f8aa6ff5a2915738a8815f42f6821 Mon Sep 17 00:00:00 2001 From: Matt Devereau Date: Tue, 2 Apr 2024 10:21:52 +0000 Subject: [PATCH 6/9] Add tests for 0/inf/NaN --- .../InstSimplify/ConstProp/logf128.ll | 44 ++++++++++++++++++- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/llvm/test/Transforms/InstSimplify/ConstProp/logf128.ll b/llvm/test/Transforms/InstSimplify/ConstProp/logf128.ll index 387e8eda6173d..dd155999bfb13 100644 --- a/llvm/test/Transforms/InstSimplify/ConstProp/logf128.ll +++ b/llvm/test/Transforms/InstSimplify/ConstProp/logf128.ll @@ -70,10 +70,50 @@ define fp128 @log_e_smallest_number_larger_than_one(){ ret fp128 %A } -define fp128 @log_e_minus_2(){ -; CHECK-LABEL: define fp128 @log_e_minus_2() { +define fp128 @log_e_negative_2(){ +; CHECK-LABEL: define fp128 @log_e_negative_2() { ; CHECK-NEXT: ret fp128 0xL00000000000000007FFF800000000000 ; %A = call fp128 @llvm.log.f128(fp128 noundef 0xL0000000000000000C000000000000000) ret fp128 %A } + +define fp128 @log_e_0(){ +; CHECK-LABEL: define fp128 @log_e_0() { +; CHECK-NEXT: ret fp128 0xL0000000000000000FFFF000000000000 +; + %A = call fp128 @llvm.log.f128(fp128 noundef 0xL00000000000000000000000000000000) + ret fp128 %A +} + +define fp128 @log_e_negative_0(){ +; CHECK-LABEL: define fp128 @log_e_negative_0() { +; CHECK-NEXT: ret fp128 0xL0000000000000000FFFF000000000000 +; + %A = call fp128 @llvm.log.f128(fp128 noundef 0xL00000000000000008000000000000000) + ret fp128 %A +} + +define fp128 @log_e_infinity(){ +; CHECK-LABEL: define fp128 @log_e_infinity() { +; CHECK-NEXT: ret fp128 0xL00000000000000007FFF000000000000 +; + %A = call fp128 @llvm.log.f128(fp128 noundef 0xL00000000000000007FFF000000000000) + ret fp128 %A +} + +define fp128 @log_e_negative_infinity(){ +; CHECK-LABEL: define fp128 @log_e_negative_infinity() { +; CHECK-NEXT: ret fp128 0xL00000000000000007FFF800000000000 +; + %A = call fp128 @llvm.log.f128(fp128 noundef 0xL0000000000000000FFFF000000000000) + ret fp128 %A +} + +define fp128 @log_e_nan(){ +; CHECK-LABEL: define fp128 @log_e_nan() { +; CHECK-NEXT: ret fp128 0xL00000000000000007FFF800000000001 +; + %A = call fp128 @llvm.log.f128(fp128 noundef 0xL00000000000000007FFF000000000001) + ret fp128 %A +} From 5f96eaec3a8619faf9372f39738b760436673fe4 Mon Sep 17 00:00:00 2001 From: Matt Devereau Date: Thu, 4 Apr 2024 06:25:57 +0000 Subject: [PATCH 7/9] Remove interal use of float128. Fix whitespace in tests --- llvm/include/llvm/ADT/APFloat.h | 6 ------ llvm/include/llvm/ADT/APInt.h | 10 ---------- llvm/lib/Analysis/ConstantFolding.cpp | 5 +++-- llvm/lib/Support/APFloat.cpp | 6 ------ .../InstSimplify/ConstProp/logf128.ll | 20 +++++++++---------- 5 files changed, 13 insertions(+), 34 deletions(-) diff --git a/llvm/include/llvm/ADT/APFloat.h b/llvm/include/llvm/ADT/APFloat.h index fcc8ffbce8b95..d5794b97bc267 100644 --- a/llvm/include/llvm/ADT/APFloat.h +++ b/llvm/include/llvm/ADT/APFloat.h @@ -300,9 +300,6 @@ 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 &); @@ -949,9 +946,6 @@ 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; diff --git a/llvm/include/llvm/ADT/APInt.h b/llvm/include/llvm/ADT/APInt.h index 00431edf14c9f..0f6e4c592af65 100644 --- a/llvm/include/llvm/ADT/APInt.h +++ b/llvm/include/llvm/ADT/APInt.h @@ -1703,16 +1703,6 @@ class [[nodiscard]] APInt { return APInt(sizeof(float) * CHAR_BIT, llvm::bit_cast(V)); } -#ifdef __FLOAT128__ - static APInt longDoubleToBits(float128 V) { - const uint64_t Words[2] = { - static_cast(V), - static_cast(llvm::bit_cast<__uint128_t>(V) >> 64), - }; - return APInt(sizeof(float128) * CHAR_BIT, 2, Words); - } -#endif - /// @} /// \name Mathematics Operations /// @{ diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp index 9c7664ab55b34..e292ff326a595 100644 --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -1673,8 +1673,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"; case 'n': return Name == "nearbyint" || Name == "nearbyintf"; case 'p': diff --git a/llvm/lib/Support/APFloat.cpp b/llvm/lib/Support/APFloat.cpp index 6c58a36408c8b..30c85f5b4214c 100644 --- a/llvm/lib/Support/APFloat.cpp +++ b/llvm/lib/Support/APFloat.cpp @@ -3967,12 +3967,6 @@ 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 &Buffer, StringRef Str) { Buffer.append(Str.begin(), Str.end()); diff --git a/llvm/test/Transforms/InstSimplify/ConstProp/logf128.ll b/llvm/test/Transforms/InstSimplify/ConstProp/logf128.ll index dd155999bfb13..02606bf148a57 100644 --- a/llvm/test/Transforms/InstSimplify/ConstProp/logf128.ll +++ b/llvm/test/Transforms/InstSimplify/ConstProp/logf128.ll @@ -38,7 +38,7 @@ define fp128 @log_e_smallest_positive_normal_number(){ ret fp128 %A } -define fp128 @log_e_largest_normal_number(){ +define fp128 @log_e_largest_normal_number(){ ; CHECK-LABEL: define fp128 @log_e_largest_normal_number() { ; CHECK-NEXT: ret fp128 0xLF000000000000000400C62E42FEFA39E ; @@ -46,7 +46,7 @@ define fp128 @log_e_largest_normal_number(){ ret fp128 %A } -define fp128 @log_e_largest_number_less_than_one(){ +define fp128 @log_e_largest_number_less_than_one(){ ; CHECK-LABEL: define fp128 @log_e_largest_number_less_than_one() { ; CHECK-NEXT: ret fp128 0xL0000000000000000BF8E000000000000 ; @@ -54,7 +54,7 @@ define fp128 @log_e_largest_number_less_than_one(){ ret fp128 %A } -define fp128 @log_e_1(){ +define fp128 @log_e_1(){ ; CHECK-LABEL: define fp128 @log_e_1() { ; CHECK-NEXT: ret fp128 0xL00000000000000000000000000000000 ; @@ -62,7 +62,7 @@ define fp128 @log_e_1(){ ret fp128 %A } -define fp128 @log_e_smallest_number_larger_than_one(){ +define fp128 @log_e_smallest_number_larger_than_one(){ ; CHECK-LABEL: define fp128 @log_e_smallest_number_larger_than_one() { ; CHECK-NEXT: ret fp128 0xL00000000000000003F8F000000000000 ; @@ -70,7 +70,7 @@ define fp128 @log_e_smallest_number_larger_than_one(){ ret fp128 %A } -define fp128 @log_e_negative_2(){ +define fp128 @log_e_negative_2(){ ; CHECK-LABEL: define fp128 @log_e_negative_2() { ; CHECK-NEXT: ret fp128 0xL00000000000000007FFF800000000000 ; @@ -78,7 +78,7 @@ define fp128 @log_e_negative_2(){ ret fp128 %A } -define fp128 @log_e_0(){ +define fp128 @log_e_0(){ ; CHECK-LABEL: define fp128 @log_e_0() { ; CHECK-NEXT: ret fp128 0xL0000000000000000FFFF000000000000 ; @@ -86,7 +86,7 @@ define fp128 @log_e_0(){ ret fp128 %A } -define fp128 @log_e_negative_0(){ +define fp128 @log_e_negative_0(){ ; CHECK-LABEL: define fp128 @log_e_negative_0() { ; CHECK-NEXT: ret fp128 0xL0000000000000000FFFF000000000000 ; @@ -94,7 +94,7 @@ define fp128 @log_e_negative_0(){ ret fp128 %A } -define fp128 @log_e_infinity(){ +define fp128 @log_e_infinity(){ ; CHECK-LABEL: define fp128 @log_e_infinity() { ; CHECK-NEXT: ret fp128 0xL00000000000000007FFF000000000000 ; @@ -102,7 +102,7 @@ define fp128 @log_e_infinity(){ ret fp128 %A } -define fp128 @log_e_negative_infinity(){ +define fp128 @log_e_negative_infinity(){ ; CHECK-LABEL: define fp128 @log_e_negative_infinity() { ; CHECK-NEXT: ret fp128 0xL00000000000000007FFF800000000000 ; @@ -110,7 +110,7 @@ define fp128 @log_e_negative_infinity(){ ret fp128 %A } -define fp128 @log_e_nan(){ +define fp128 @log_e_nan(){ ; CHECK-LABEL: define fp128 @log_e_nan() { ; CHECK-NEXT: ret fp128 0xL00000000000000007FFF800000000001 ; From 6a08ef5c6fdc22d0e0823ba90358b85abb179675 Mon Sep 17 00:00:00 2001 From: Matt Devereau Date: Tue, 9 Apr 2024 08:55:50 +0000 Subject: [PATCH 8/9] Add vector test and remove AArch64 target for IR tests --- llvm/test/Transforms/InstSimplify/ConstProp/logf128.ll | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/llvm/test/Transforms/InstSimplify/ConstProp/logf128.ll b/llvm/test/Transforms/InstSimplify/ConstProp/logf128.ll index 02606bf148a57..da56997f69382 100644 --- a/llvm/test/Transforms/InstSimplify/ConstProp/logf128.ll +++ b/llvm/test/Transforms/InstSimplify/ConstProp/logf128.ll @@ -2,7 +2,6 @@ ; RUN: opt < %s -passes=instsimplify -S | FileCheck %s ; REQUIRES: has_logf128 -; REQUIRES: aarch64-registered-target declare fp128 @llvm.log.f128(fp128) define fp128 @log_e_64(){ @@ -117,3 +116,11 @@ define fp128 @log_e_nan(){ %A = call fp128 @llvm.log.f128(fp128 noundef 0xL00000000000000007FFF000000000001) ret fp128 %A } + +define <2 x fp128> @log_e_negative_2_vector(){ +; CHECK-LABEL: define <2 x fp128> @log_e_negative_2_vector() { +; CHECK-NEXT: ret <2 x fp128> +; + %A = call <2 x fp128> @llvm.log.v2f128(<2 x fp128> ) + ret <2 x fp128> %A +} From 8427d6a2888e25318c47f7811f25ca628f8f2a84 Mon Sep 17 00:00:00 2001 From: Matt Devereau Date: Tue, 16 Apr 2024 17:05:58 +0000 Subject: [PATCH 9/9] Add newlines to end of file --- llvm/lib/Analysis/CMakeLists.txt | 2 +- llvm/test/lit.cfg.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Analysis/CMakeLists.txt b/llvm/lib/Analysis/CMakeLists.txt index 3d443cef2e65c..74476cb5440c6 100644 --- a/llvm/lib/Analysis/CMakeLists.txt +++ b/llvm/lib/Analysis/CMakeLists.txt @@ -164,4 +164,4 @@ 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 +endif() diff --git a/llvm/test/lit.cfg.py b/llvm/test/lit.cfg.py index 356f006e5dcf3..36bcc48307dd8 100644 --- a/llvm/test/lit.cfg.py +++ b/llvm/test/lit.cfg.py @@ -616,4 +616,4 @@ def have_ld64_plugin_support(): config.environment["OBJECT_MODE"] = "any" if config.has_logf128: - config.available_features.add("has_logf128") \ No newline at end of file + config.available_features.add("has_logf128")