diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt index d511376e18ba5e..c48ab438ffe0b3 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 bf1b110245bb2f..ce07cab7a56c6b 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/ADT/APFloat.h b/llvm/include/llvm/ADT/APFloat.h index deb74cb2fdeb1e..d5794b97bc2671 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) \ @@ -354,6 +355,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; /// @} @@ -1218,6 +1222,15 @@ 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. +#ifdef __FLOAT128__ + float128 convertToQuad() const; +#endif + /// 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 8d3c029b2e7e91..0f6e4c592af651 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,6 +1671,13 @@ 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 /// /// The conversion does not do a translation from integer to float, it just diff --git a/llvm/include/llvm/Config/llvm-config.h.cmake b/llvm/include/llvm/Config/llvm-config.h.cmake index 6605ea60df99e1..629977cc11d683 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/Support/float128.h b/llvm/include/llvm/Support/float128.h new file mode 100644 index 00000000000000..f7a442fce8dd32 --- /dev/null +++ b/llvm/include/llvm/Support/float128.h @@ -0,0 +1,21 @@ +//===-- 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 + +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/CMakeLists.txt b/llvm/lib/Analysis/CMakeLists.txt index 474b8d20fde16f..74476cb5440c61 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() diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp index 749374a3aa48af..e292ff326a5954 100644 --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -2089,6 +2089,17 @@ static Constant *ConstantFoldScalarCall1(StringRef Name, if (IntrinsicID == Intrinsic::canonicalize) return constantFoldCanonicalize(Ty, Call, U); +#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; diff --git a/llvm/lib/Support/APFloat.cpp b/llvm/lib/Support/APFloat.cpp index 0a4f5ac01553f1..30c85f5b4214ca 100644 --- a/llvm/lib/Support/APFloat.cpp +++ b/llvm/lib/Support/APFloat.cpp @@ -3670,6 +3670,15 @@ 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: /// exponent = all 1's, integer bit 0, significand 0 ("pseudoinfinity") @@ -5265,6 +5274,21 @@ double APFloat::convertToDouble() const { return Temp.getIEEE().convertToDouble(); } +#ifdef __FLOAT128__ +float128 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(); +} +#endif + float APFloat::convertToFloat() const { if (&getSemantics() == (const llvm::fltSemantics *)&semIEEEsingle) return getIEEE().convertToFloat(); diff --git a/llvm/test/CMakeLists.txt b/llvm/test/CMakeLists.txt index 6127b76db06b7f..b419464aba3f52 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 00000000000000..da56997f693822 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/ConstProp/logf128.ll @@ -0,0 +1,126 @@ +; 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 +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_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 +} + +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 +} diff --git a/llvm/test/lit.cfg.py b/llvm/test/lit.cfg.py index 4c05317036d1a3..36bcc48307dd82 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") diff --git a/llvm/test/lit.site.cfg.py.in b/llvm/test/lit.site.cfg.py.in index b6f255d472d16f..27cb1dd6477d93 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 b1aeaa6e71fd4c..9b3778f8a3f98f 100644 --- a/llvm/unittests/Analysis/CMakeLists.txt +++ b/llvm/unittests/Analysis/CMakeLists.txt @@ -80,5 +80,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)