diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt index 3b69d027e006313d61855af478c319f4e0553ff7..687a9a6892118e6e7bba0b501a7c18b48fcbacb6 100644 --- a/llvm/CMakeLists.txt +++ b/llvm/CMakeLists.txt @@ -522,6 +522,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 5d430f974bbf88627797bfcd6869fa5887025000..8b377a5d5942c33384a892b9970fa91ddaf5e13d 100644 --- a/llvm/cmake/config-ix.cmake +++ b/llvm/cmake/config-ix.cmake @@ -263,6 +263,17 @@ if(LLVM_HAVE_LIBXAR) endif() 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 64caa5a76545673d36154bab03531bfdbf7c2795..ebbb67b9e0913b19feed3d7bdbd45bc2efb869a2 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 @@ public: Expected convertFromString(StringRef, roundingMode); APInt bitcastToAPInt() const; double convertToDouble() const; +#ifdef HAS_IEE754_FLOAT128 + float128 convertToQuad() const; +#endif float convertToFloat() const; /// @} @@ -1199,6 +1203,15 @@ public: /// 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 HAS_IEE754_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 6f2f25548cc84ba7cb2ba4a3892e3ed061aeebb7..330cfc8c709f1cc28b13f5cbefa3cdbc62700663 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 @@ -1663,6 +1664,13 @@ public: /// any bit width. Exactly 64 bits will be translated. double bitsToDouble() const { return llvm::bit_cast(getWord(0)); } +#ifdef HAS_IEE754_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 012ae2174cc2a10223485f7b421bc83d28f46ed8..2f1dc9ec0f980739e4e9ca3709bba5226b510787 100644 --- a/llvm/include/llvm/Config/llvm-config.h.cmake +++ b/llvm/include/llvm/Config/llvm-config.h.cmake @@ -126,4 +126,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 0000000000000000000000000000000000000000..8887cd2bad7a02cd96bc82885fe0609210b9e5fd --- /dev/null +++ b/llvm/include/llvm/Support/float128.h @@ -0,0 +1,30 @@ +//===-- 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__) && \ + defined(__SIZEOF_INT128__) && !defined(__LONG_DOUBLE_IBM128__) +#define HAS_IEE754_FLOAT128 +typedef __float128 float128; +#elif defined(__FLOAT128__) && defined(__SIZEOF_INT128__) && \ + !defined(__LONG_DOUBLE_IBM128__) && \ + (defined(__GNUC__) || defined(__GNUG__)) +#define HAS_IEE754_FLOAT128 +typedef _Float128 float128; +#elif defined(__aarch64__) && defined(__linux__) && \ + !defined(__LONG_DOUBLE_IBM128__) +#define HAS_IEE754_FLOAT128 +typedef long double float128; +#endif + +} // namespace llvm +#endif // LLVM_FLOAT128 diff --git a/llvm/lib/Analysis/CMakeLists.txt b/llvm/lib/Analysis/CMakeLists.txt index a694eee1ade03afebd48eb7186222d65ed8d9d0b..b35764c7fb4b4858b588b23aa897feaa32b743c4 100644 --- a/llvm/lib/Analysis/CMakeLists.txt +++ b/llvm/lib/Analysis/CMakeLists.txt @@ -195,3 +195,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 38cccb3ea3c2594debeb5596299116cd109ada95..449de7ce314daf84d74f9769526db98479c6a23a 100644 --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -62,6 +62,11 @@ using namespace llvm; +static cl::opt +EnableLoglConstantFold("enable-logl-constant-fold", + cl::desc("Enable logl constant fold."), + cl::init(false), cl::Hidden); + namespace { //===----------------------------------------------------------------------===// @@ -1684,9 +1689,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': @@ -1749,6 +1754,14 @@ Constant *GetConstantFoldFPValue(double V, Type *Ty) { llvm_unreachable("Can only constant fold half/float/double"); } +#if defined(HAS_IEE754_FLOAT128) +Constant *GetConstantFoldFPValue128(float128 V, Type *Ty) { + if (Ty->isFP128Ty()) + return ConstantFP::get(Ty, V); + llvm_unreachable("Can only constant fold fp128"); +} +#endif + /// Clear the floating-point exception state. inline void llvm_fenv_clearexcept() { #if defined(HAVE_FENV_H) && HAVE_DECL_FE_ALL_EXCEPT @@ -1781,6 +1794,20 @@ Constant *ConstantFoldFP(double (*NativeFP)(double), const APFloat &V, return GetConstantFoldFPValue(Result, Ty); } +#if defined(HAS_IEE754_FLOAT128) +Constant *ConstantFoldFP128(float128 (*NativeFP)(float128), + const APFloat &V, Type *Ty) { + llvm_fenv_clearexcept(); + float128 Result = NativeFP(V.convertToQuad()); + if (llvm_fenv_testexcept()) { + llvm_fenv_clearexcept(); + return nullptr; + } + + return GetConstantFoldFPValue128(Result, Ty); +} +#endif + Constant *ConstantFoldBinaryFP(double (*NativeFP)(double, double), const APFloat &V, const APFloat &W, Type *Ty) { llvm_fenv_clearexcept(); @@ -2100,6 +2127,22 @@ static Constant *ConstantFoldScalarCall1(StringRef Name, if (IntrinsicID == Intrinsic::canonicalize) return constantFoldCanonicalize(Ty, Call, U); +#if defined(HAS_IEE754_FLOAT128) && defined(HAS_LOGF128) + if (Ty->isFP128Ty()) { + if (IntrinsicID == Intrinsic::log) { + float128 Result = logf128(Op->getValueAPF().convertToQuad()); + if (EnableLoglConstantFold) + return GetConstantFoldFPValue128(Result, Ty); + } + + LibFunc Fp128Func = NotLibFunc; + if (TLI->getLibFunc(Name, Fp128Func) && TLI->has(Fp128Func) && + Fp128Func == LibFunc_logl) + if (EnableLoglConstantFold) + return ConstantFoldFP128(logf128, Op->getValueAPF(), Ty); + } +#endif + if (!Ty->isHalfTy() && !Ty->isFloatTy() && !Ty->isDoubleTy()) return nullptr; @@ -2357,6 +2400,8 @@ static Constant *ConstantFoldScalarCall1(StringRef Name, // TODO: What about hosts that lack a C99 library? return ConstantFoldFP(log10, APF, Ty); break; + case LibFunc_logl: + return nullptr; case LibFunc_nearbyint: case LibFunc_nearbyintf: case LibFunc_rint: diff --git a/llvm/lib/Support/APFloat.cpp b/llvm/lib/Support/APFloat.cpp index 4a73739b5282a82ef4398b04574250ef97e4132e..815e9faccbbe3ae93ecf7f5df961d8e8e5a6e3ef 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 HAS_IEE754_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") @@ -5226,6 +5235,21 @@ double APFloat::convertToDouble() const { return Temp.getIEEE().convertToDouble(); } +#ifdef HAS_IEE754_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 8cd77b72c987349f3a2e4eae01a6e2663a4a1ed3..6a7f3ff9a8be1d823846c4cc0f116fe03b3b2fb7 100644 --- a/llvm/test/CMakeLists.txt +++ b/llvm/test/CMakeLists.txt @@ -25,6 +25,9 @@ llvm_canonicalize_cmake_booleans( LLVM_ENABLE_REVERSE_ITERATION LLVM_INCLUDE_DXIL_TESTS LLVM_TOOL_LLVM_DRIVER_BUILD + LLVM_INCLUDE_SPIRV_TOOLS_TESTS + LLVM_APPEND_VC_REV + 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 0000000000000000000000000000000000000000..1f8e1d377f93b383b10443b09bd4185bb46e165e --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/ConstProp/logf128.ll @@ -0,0 +1,173 @@ +; 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) +declare fp128 @logl(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 +} + +define fp128 @logl_e_64(){ +; CHECK-LABEL: define fp128 @logl_e_64() { +; CHECK-NEXT: [[A:%.*]] = call fp128 @logl(fp128 noundef 0xL00000000000000004005000000000000) +; CHECK-NEXT: ret fp128 0xL300000000000000040010A2B23F3BAB7 +; + %A = call fp128 @logl(fp128 noundef 0xL00000000000000004005000000000000) + ret fp128 %A +} + +define fp128 @logl_e_0(){ +; CHECK-LABEL: define fp128 @logl_e_0() { +; CHECK-NEXT: [[A:%.*]] = call fp128 @logl(fp128 noundef 0xL00000000000000000000000000000000) +; CHECK-NEXT: ret fp128 [[A]] +; + %A = call fp128 @logl(fp128 noundef 0xL00000000000000000000000000000000) + ret fp128 %A +} + +define fp128 @logl_e_infinity(){ +; CHECK-LABEL: define fp128 @logl_e_infinity() { +; CHECK-NEXT: [[A:%.*]] = call fp128 @logl(fp128 noundef 0xL00000000000000007FFF000000000000) +; CHECK-NEXT: ret fp128 0xL00000000000000007FFF000000000000 +; + %A = call fp128 @logl(fp128 noundef 0xL00000000000000007FFF000000000000) + ret fp128 %A +} + +define fp128 @logl_e_nan(){ +; CHECK-LABEL: define fp128 @logl_e_nan() { +; CHECK-NEXT: [[A:%.*]] = call fp128 @logl(fp128 noundef 0xL00000000000000007FFF000000000001) +; CHECK-NEXT: ret fp128 [[A]] +; + %A = call fp128 @logl(fp128 noundef 0xL00000000000000007FFF000000000001) + ret fp128 %A +} + + +define fp128 @logl_e_negative_2(){ +; CHECK-LABEL: define fp128 @logl_e_negative_2() { +; CHECK-NEXT: [[A:%.*]] = call fp128 @logl(fp128 noundef 0xL0000000000000000C000000000000000) +; CHECK-NEXT: ret fp128 [[A]] +; + %A = call fp128 @logl(fp128 noundef 0xL0000000000000000C000000000000000) + ret fp128 %A +} diff --git a/llvm/test/lit.cfg.py b/llvm/test/lit.cfg.py index 9cc8520960c23a6cfe8d1fc2adf9e12b5251ed22..36555fa40963947196fe6333c2a1e1e6909aee53 100644 --- a/llvm/test/lit.cfg.py +++ b/llvm/test/lit.cfg.py @@ -648,3 +648,6 @@ if "system-aix" in config.available_features: if config.use_classic_flang: config.available_features.add("classic_flang") + +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 20c1ecca1d43002a436cb5b11929b136b12ba81d..cecf7d8c7b350b38c90765ab1b19106f7e28286b 100644 --- a/llvm/test/lit.site.cfg.py.in +++ b/llvm/test/lit.site.cfg.py.in @@ -64,6 +64,10 @@ config.have_llvm_driver = @LLVM_TOOL_LLVM_DRIVER_BUILD@ config.use_classic_flang = @LLVM_ENABLE_CLASSIC_FLANG@ config.enable_enable_autotuner = @LLVM_ENABLE_AUTOTUNER@ config.enable_build_for_common = @LLVM_BUILD_FOR_COMMON@ +config.spirv_tools_tests = @LLVM_INCLUDE_SPIRV_TOOLS_TESTS@ +config.have_vc_rev = @LLVM_APPEND_VC_REV@ +config.force_vc_rev = "@LLVM_FORCE_VC_REVISION@" +config.has_logf128 = @LLVM_HAS_LOGF128@ import lit.llvm lit.llvm.initialize(lit_config, config)