7 changes: 5 additions & 2 deletions libc/src/__support/FPUtil/generic/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ add_header_library(
libc.src.__support.common
libc.src.__support.CPP.bit
libc.src.__support.CPP.type_traits
libc.src.__support.FPUtil.cast
libc.src.__support.FPUtil.dyadic_float
libc.src.__support.FPUtil.fenv_impl
libc.src.__support.FPUtil.fp_bits
Expand All @@ -21,16 +22,17 @@ add_header_library(
FMA.h
DEPENDS
libc.hdr.fenv_macros
libc.src.__support.big_int
libc.src.__support.common
libc.src.__support.CPP.bit
libc.src.__support.CPP.limits
libc.src.__support.CPP.type_traits
libc.src.__support.FPUtil.basic_operations
libc.src.__support.FPUtil.cast
libc.src.__support.FPUtil.dyadic_float
libc.src.__support.FPUtil.fenv_impl
libc.src.__support.FPUtil.fp_bits
libc.src.__support.FPUtil.rounding_mode
libc.src.__support.big_int
libc.src.__support.macros.optimization
libc.src.__support.uint128
)
Expand Down Expand Up @@ -60,9 +62,10 @@ add_header_library(
libc.src.__support.CPP.bit
libc.src.__support.CPP.type_traits
libc.src.__support.FPUtil.basic_operations
libc.src.__support.FPUtil.cast
libc.src.__support.FPUtil.dyadic_float
libc.src.__support.FPUtil.fenv_impl
libc.src.__support.FPUtil.fp_bits
libc.src.__support.FPUtil.dyadic_float
libc.src.__support.FPUtil.rounding_mode
libc.src.__support.macros.attributes
libc.src.__support.macros.optimization
Expand Down
5 changes: 3 additions & 2 deletions libc/src/__support/FPUtil/generic/FMA.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "src/__support/CPP/type_traits.h"
#include "src/__support/FPUtil/BasicOperations.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/FPUtil/dyadic_float.h"
#include "src/__support/FPUtil/rounding_mode.h"
#include "src/__support/big_int.h"
Expand Down Expand Up @@ -157,7 +158,7 @@ fma(InType x, InType y, InType z) {
}

if (LIBC_UNLIKELY(x == 0 || y == 0 || z == 0))
return static_cast<OutType>(x * y + z);
return cast<OutType>(x * y + z);

int x_exp = 0;
int y_exp = 0;
Expand Down Expand Up @@ -198,7 +199,7 @@ fma(InType x, InType y, InType z) {
if (LIBC_UNLIKELY(x_exp == InFPBits::MAX_BIASED_EXPONENT ||
y_exp == InFPBits::MAX_BIASED_EXPONENT ||
z_exp == InFPBits::MAX_BIASED_EXPONENT))
return static_cast<OutType>(x * y + z);
return cast<OutType>(x * y + z);

// Extract mantissa and append hidden leading bits.
InStorageType x_mant = x_bits.get_explicit_mantissa();
Expand Down
5 changes: 3 additions & 2 deletions libc/src/__support/FPUtil/generic/add_sub.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "src/__support/FPUtil/BasicOperations.h"
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/FPUtil/dyadic_float.h"
#include "src/__support/FPUtil/rounding_mode.h"
#include "src/__support/macros/attributes.h"
Expand Down Expand Up @@ -106,14 +107,14 @@ add_or_sub(InType x, InType y) {
volatile InType tmp = y;
if constexpr (IsSub)
tmp = -tmp;
return static_cast<OutType>(tmp);
return cast<OutType>(tmp);
}

if (y_bits.is_zero()) {
volatile InType tmp = y;
if constexpr (IsSub)
tmp = -tmp;
return static_cast<OutType>(tmp);
return cast<OutType>(tmp);
}
}

Expand Down
3 changes: 2 additions & 1 deletion libc/src/__support/FPUtil/generic/sqrt.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "src/__support/CPP/type_traits.h"
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/FPUtil/dyadic_float.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
Expand Down Expand Up @@ -96,7 +97,7 @@ sqrt(InType x) {
// sqrt(-0) = -0
// sqrt(NaN) = NaN
// sqrt(-NaN) = -NaN
return static_cast<OutType>(x);
return cast<OutType>(x);
} else if (bits.is_neg()) {
// sqrt(-Inf) = NaN
// sqrt(-x) = NaN
Expand Down
24 changes: 18 additions & 6 deletions libc/src/math/generic/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,10 @@ add_entrypoint_object(
COMPILE_OPTIONS
-O3
DEPENDS
libc.src.__support.macros.properties.types
libc.src.__support.FPUtil.cast
libc.src.__support.FPUtil.nearest_integer_operations
libc.src.__support.macros.properties.cpu_features
libc.src.__support.macros.properties.types
FLAGS
ROUND_OPT
)
Expand Down Expand Up @@ -672,9 +673,10 @@ add_entrypoint_object(
COMPILE_OPTIONS
-O3
DEPENDS
libc.src.__support.macros.properties.types
libc.src.__support.FPUtil.cast
libc.src.__support.FPUtil.nearest_integer_operations
libc.src.__support.macros.properties.cpu_features
libc.src.__support.macros.properties.types
FLAGS
ROUND_OPT
)
Expand Down Expand Up @@ -741,9 +743,10 @@ add_entrypoint_object(
COMPILE_OPTIONS
-O3
DEPENDS
libc.src.__support.macros.properties.types
libc.src.__support.FPUtil.cast
libc.src.__support.FPUtil.nearest_integer_operations
libc.src.__support.macros.properties.cpu_features
libc.src.__support.macros.properties.types
FLAGS
ROUND_OPT
)
Expand Down Expand Up @@ -810,9 +813,10 @@ add_entrypoint_object(
COMPILE_OPTIONS
-O3
DEPENDS
libc.src.__support.macros.properties.types
libc.src.__support.FPUtil.cast
libc.src.__support.FPUtil.nearest_integer_operations
libc.src.__support.macros.properties.cpu_features
libc.src.__support.macros.properties.types
FLAGS
ROUND_OPT
)
Expand Down Expand Up @@ -881,6 +885,7 @@ add_entrypoint_object(
DEPENDS
libc.src.__support.macros.properties.types
libc.src.__support.FPUtil.nearest_integer_operations
libc.src.__support.FPUtil.cast
libc.src.__support.macros.properties.cpu_features
FLAGS
ROUND_OPT
Expand Down Expand Up @@ -1072,9 +1077,10 @@ add_entrypoint_object(
COMPILE_OPTIONS
-O3
DEPENDS
libc.src.__support.macros.properties.types
libc.src.__support.FPUtil.cast
libc.src.__support.FPUtil.nearest_integer_operations
libc.src.__support.macros.properties.cpu_features
libc.src.__support.macros.properties.types
FLAGS
ROUND_OPT
)
Expand Down Expand Up @@ -1362,12 +1368,15 @@ add_entrypoint_object(
.expxf16
libc.hdr.errno_macros
libc.hdr.fenv_macros
libc.src.__support.CPP.array
libc.src.__support.FPUtil.cast
libc.src.__support.FPUtil.except_value_utils
libc.src.__support.FPUtil.fenv_impl
libc.src.__support.FPUtil.fp_bits
libc.src.__support.FPUtil.multiply_add
libc.src.__support.FPUtil.nearest_integer
libc.src.__support.FPUtil.polyeval
libc.src.__support.FPUtil.rounding_mode
libc.src.__support.macros.attributes
libc.src.__support.macros.optimization
COMPILE_OPTIONS
-O3
Expand Down Expand Up @@ -1442,6 +1451,7 @@ add_entrypoint_object(
libc.hdr.errno_macros
libc.hdr.fenv_macros
libc.src.__support.CPP.array
libc.src.__support.FPUtil.cast
libc.src.__support.FPUtil.except_value_utils
libc.src.__support.FPUtil.fenv_impl
libc.src.__support.FPUtil.fp_bits
Expand Down Expand Up @@ -1545,6 +1555,7 @@ add_entrypoint_object(
libc.hdr.errno_macros
libc.hdr.fenv_macros
libc.src.__support.CPP.array
libc.src.__support.FPUtil.cast
libc.src.__support.FPUtil.except_value_utils
libc.src.__support.FPUtil.fenv_impl
libc.src.__support.FPUtil.fp_bits
Expand Down Expand Up @@ -1617,6 +1628,7 @@ add_entrypoint_object(
.expxf16
libc.hdr.errno_macros
libc.hdr.fenv_macros
libc.src.__support.FPUtil.cast
libc.src.__support.FPUtil.except_value_utils
libc.src.__support.FPUtil.fenv_impl
libc.src.__support.FPUtil.fp_bits
Expand Down
3 changes: 2 additions & 1 deletion libc/src/math/generic/ceilf16.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "src/math/ceilf16.h"
#include "src/__support/FPUtil/NearestIntegerOperations.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/properties/cpu_features.h"
Expand All @@ -17,7 +18,7 @@ namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(float16, ceilf16, (float16 x)) {
#if defined(__LIBC_USE_BUILTIN_CEIL_FLOOR_RINT_TRUNC) && \
defined(LIBC_TARGET_CPU_HAS_FAST_FLOAT16_OPS)
return static_cast<float16>(__builtin_ceilf(x));
return fputil::cast<float16>(__builtin_ceilf(x));
#else
return fputil::ceil(x);
#endif
Expand Down
11 changes: 6 additions & 5 deletions libc/src/math/generic/exp10f16.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/PolyEval.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/FPUtil/except_value_utils.h"
#include "src/__support/FPUtil/multiply_add.h"
#include "src/__support/FPUtil/nearest_integer.h"
Expand Down Expand Up @@ -118,13 +119,13 @@ LLVM_LIBC_FUNCTION(float16, exp10f16, (float16 x)) {
if (LIBC_UNLIKELY((x_u & ~(0x3c00U | 0x4000U | 0x4200U | 0x4400U)) == 0)) {
switch (x_u) {
case 0x3c00U: // x = 1.0f16
return static_cast<float16>(10.0);
return fputil::cast<float16>(10.0);
case 0x4000U: // x = 2.0f16
return static_cast<float16>(100.0);
return fputil::cast<float16>(100.0);
case 0x4200U: // x = 3.0f16
return static_cast<float16>(1'000.0);
return fputil::cast<float16>(1'000.0);
case 0x4400U: // x = 4.0f16
return static_cast<float16>(10'000.0);
return fputil::cast<float16>(10'000.0);
}
}

Expand Down Expand Up @@ -164,7 +165,7 @@ LLVM_LIBC_FUNCTION(float16, exp10f16, (float16 x)) {
// > 1 + x * P;
float exp10_lo = fputil::polyeval(lo, 0x1p+0f, 0x1.26bb14p+1f, 0x1.53526p+1f,
0x1.04b434p+1f, 0x1.2bcf9ep+0f);
return static_cast<float16>(exp2_hi_mid * exp10_lo);
return fputil::cast<float16>(exp2_hi_mid * exp10_lo);
}

} // namespace LIBC_NAMESPACE_DECL
3 changes: 2 additions & 1 deletion libc/src/math/generic/exp2f16.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/PolyEval.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/FPUtil/except_value_utils.h"
#include "src/__support/FPUtil/multiply_add.h"
#include "src/__support/FPUtil/nearest_integer.h"
Expand Down Expand Up @@ -121,7 +122,7 @@ LLVM_LIBC_FUNCTION(float16, exp2f16, (float16 x)) {
// > 1 + x * P;
float exp2_lo = fputil::polyeval(lo, 0x1p+0f, 0x1.62e43p-1f, 0x1.ec0aa6p-3f,
0x1.c6b4a6p-5f);
return static_cast<float16>(exp2_hi_mid * exp2_lo);
return fputil::cast<float16>(exp2_hi_mid * exp2_lo);
}

} // namespace LIBC_NAMESPACE_DECL
5 changes: 3 additions & 2 deletions libc/src/math/generic/expf16.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/PolyEval.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/FPUtil/except_value_utils.h"
#include "src/__support/FPUtil/rounding_mode.h"
#include "src/__support/common.h"
Expand Down Expand Up @@ -103,7 +104,7 @@ LLVM_LIBC_FUNCTION(float16, expf16, (float16 x)) {
// > display = hexadecimal;
// > P = fpminimax(expm1(x)/x, 2, [|SG...|], [-2^-5, 2^-5]);
// > 1 + x * P;
return static_cast<float16>(
return fputil::cast<float16>(
fputil::polyeval(xf, 0x1p+0f, 0x1p+0f, 0x1.0004p-1f, 0x1.555778p-3f));
}
}
Expand All @@ -113,7 +114,7 @@ LLVM_LIBC_FUNCTION(float16, expf16, (float16 x)) {

// exp(x) = exp(hi + mid) * exp(lo)
auto [exp_hi_mid, exp_lo] = exp_range_reduction(x);
return static_cast<float16>(exp_hi_mid * exp_lo);
return fputil::cast<float16>(exp_hi_mid * exp_lo);
}

} // namespace LIBC_NAMESPACE_DECL
7 changes: 4 additions & 3 deletions libc/src/math/generic/expm1f16.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/PolyEval.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/FPUtil/except_value_utils.h"
#include "src/__support/FPUtil/multiply_add.h"
#include "src/__support/FPUtil/rounding_mode.h"
Expand Down Expand Up @@ -99,7 +100,7 @@ LLVM_LIBC_FUNCTION(float16, expm1f16, (float16 x)) {
FPBits::one(Sign::NEG).get_val());
// When x <= -0x1.0ap+3, round(expm1(x), HP, RN) = -0x1.ffcp-1.
return fputil::round_result_slightly_down(
static_cast<float16>(-0x1.ffcp-1));
fputil::cast<float16>(-0x1.ffcp-1));
}

// When 0 < |x| <= 2^(-3).
Expand All @@ -114,7 +115,7 @@ LLVM_LIBC_FUNCTION(float16, expm1f16, (float16 x)) {
// > display = hexadecimal;
// > P = fpminimax(expm1(x)/x, 4, [|SG...|], [-2^-3, 2^-3]);
// > x * P;
return static_cast<float16>(
return fputil::cast<float16>(
xf * fputil::polyeval(xf, 0x1p+0f, 0x1.fffff8p-2f, 0x1.555556p-3f,
0x1.55905ep-5f, 0x1.1124c2p-7f));
}
Expand All @@ -126,7 +127,7 @@ LLVM_LIBC_FUNCTION(float16, expm1f16, (float16 x)) {
// exp(x) = exp(hi + mid) * exp(lo)
auto [exp_hi_mid, exp_lo] = exp_range_reduction(x);
// expm1(x) = exp(hi + mid) * exp(lo) - 1
return static_cast<float16>(fputil::multiply_add(exp_hi_mid, exp_lo, -1.0f));
return fputil::cast<float16>(fputil::multiply_add(exp_hi_mid, exp_lo, -1.0f));
}

} // namespace LIBC_NAMESPACE_DECL
3 changes: 2 additions & 1 deletion libc/src/math/generic/floorf16.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "src/math/floorf16.h"
#include "src/__support/FPUtil/NearestIntegerOperations.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/properties/cpu_features.h"
Expand All @@ -17,7 +18,7 @@ namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(float16, floorf16, (float16 x)) {
#if defined(__LIBC_USE_BUILTIN_CEIL_FLOOR_RINT_TRUNC) && \
defined(LIBC_TARGET_CPU_HAS_FAST_FLOAT16_OPS)
return static_cast<float16>(__builtin_floorf(x));
return fputil::cast<float16>(__builtin_floorf(x));
#else
return fputil::floor(x);
#endif
Expand Down
3 changes: 2 additions & 1 deletion libc/src/math/generic/rintf16.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "src/math/rintf16.h"
#include "src/__support/FPUtil/NearestIntegerOperations.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/properties/cpu_features.h"
Expand All @@ -17,7 +18,7 @@ namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(float16, rintf16, (float16 x)) {
#if defined(__LIBC_USE_BUILTIN_CEIL_FLOOR_RINT_TRUNC) && \
defined(LIBC_TARGET_CPU_HAS_FAST_FLOAT16_OPS)
return static_cast<float16>(__builtin_rintf(x));
return fputil::cast<float16>(__builtin_rintf(x));
#else
return fputil::round_using_current_rounding_mode(x);
#endif
Expand Down
3 changes: 2 additions & 1 deletion libc/src/math/generic/roundevenf16.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "src/math/roundevenf16.h"
#include "src/__support/FPUtil/NearestIntegerOperations.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/properties/cpu_features.h"
Expand All @@ -17,7 +18,7 @@ namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(float16, roundevenf16, (float16 x)) {
#if defined(__LIBC_USE_BUILTIN_ROUNDEVEN) && \
defined(LIBC_TARGET_CPU_HAS_FAST_FLOAT16_OPS)
return static_cast<float16>(__builtin_roundevenf(x));
return fputil::cast<float16>(__builtin_roundevenf(x));
#else
return fputil::round_using_specific_rounding_mode(x, FP_INT_TONEAREST);
#endif
Expand Down
3 changes: 2 additions & 1 deletion libc/src/math/generic/roundf16.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "src/math/roundf16.h"
#include "src/__support/FPUtil/NearestIntegerOperations.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/properties/cpu_features.h"
Expand All @@ -17,7 +18,7 @@ namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(float16, roundf16, (float16 x)) {
#if defined(__LIBC_USE_BUILTIN_ROUND) && \
defined(LIBC_TARGET_CPU_HAS_FAST_FLOAT16_OPS)
return static_cast<float16>(__builtin_roundf(x));
return fputil::cast<float16>(__builtin_roundf(x));
#else
return fputil::round(x);
#endif
Expand Down
3 changes: 2 additions & 1 deletion libc/src/math/generic/truncf16.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "src/math/truncf16.h"
#include "src/__support/FPUtil/NearestIntegerOperations.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/properties/cpu_features.h"
Expand All @@ -17,7 +18,7 @@ namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(float16, truncf16, (float16 x)) {
#if defined(__LIBC_USE_BUILTIN_CEIL_FLOOR_RINT_TRUNC) && \
defined(LIBC_TARGET_CPU_HAS_FAST_FLOAT16_OPS)
return static_cast<float16>(__builtin_truncf(x));
return fputil::cast<float16>(__builtin_truncf(x));
#else
return fputil::trunc(x);
#endif
Expand Down
7 changes: 7 additions & 0 deletions libc/src/stdlib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -621,3 +621,10 @@ add_entrypoint_object(
DEPENDS
.${LIBC_TARGET_OS}.abort
)

add_entrypoint_object(
system
ALIAS
DEPENDS
.${LIBC_TARGET_OS}.system
)
13 changes: 12 additions & 1 deletion libc/src/stdlib/gpu/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,16 @@ add_entrypoint_object(
../abort.h
DEPENDS
libc.include.stdlib
libc.src.__support.GPU.allocator
libc.src.__support.RPC.rpc_client
)

add_entrypoint_object(
system
SRCS
system.cpp
HDRS
../system.h
DEPENDS
libc.include.stdlib
libc.src.__support.RPC.rpc_client
)
29 changes: 29 additions & 0 deletions libc/src/stdlib/gpu/system.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//===-- GPU implementation of system --------------------------------------===//
//
// 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 "src/__support/RPC/rpc_client.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
#include "src/string/string_utils.h"

#include "src/stdlib/system.h"

namespace LIBC_NAMESPACE_DECL {

LLVM_LIBC_FUNCTION(int, system, (const char *command)) {
int ret;
rpc::Client::Port port = rpc::client.open<RPC_SYSTEM>();
port.send_n(command, internal::string_length(command) + 1);
port.recv(
[&](rpc::Buffer *buffer) { ret = static_cast<int>(buffer->data[0]); });
port.close();

return ret;
}

} // namespace LIBC_NAMESPACE_DECL
20 changes: 20 additions & 0 deletions libc/src/stdlib/system.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//===-- Implementation header for system ------------------------*- 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_LIBC_SRC_STDLIB_SYSTEM_H
#define LLVM_LIBC_SRC_STDLIB_SYSTEM_H

#include "src/__support/macros/config.h"

namespace LIBC_NAMESPACE_DECL {

int system(const char *command);

} // namespace LIBC_NAMESPACE_DECL

#endif // LLVM_LIBC_SRC_STDLIB_SYSTEM_H
45 changes: 45 additions & 0 deletions libc/test/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,36 @@ add_libc_test(
libc.include.llvm-libc-macros.stdckdint_macros
)

add_libc_test(
issubnormal_test
SUITE
libc_include_tests
SRCS
issubnormal_test.cpp
DEPENDS
libc.include.llvm-libc-macros.math_function_macros
)

add_libc_test(
issubnormalf_test
SUITE
libc_include_tests
SRCS
issubnormalf_test.cpp
DEPENDS
libc.include.llvm-libc-macros.math_function_macros
)

add_libc_test(
issubnormall_test
SUITE
libc_include_tests
SRCS
issubnormall_test.cpp
DEPENDS
libc.include.llvm-libc-macros.math_function_macros
)

add_libc_test(
isnormal_test
SUITE
Expand Down Expand Up @@ -366,6 +396,21 @@ add_libc_test(
libc.include.llvm-libc-macros.math_function_macros
)

add_libc_test(
issubnormal_c_test
C_TEST
UNIT_TEST_ONLY
SUITE
libc_include_tests
SRCS
issubnormal_test.c
COMPILE_OPTIONS
-Wall
-Werror
DEPENDS
libc.include.llvm-libc-macros.math_function_macros
)

add_libc_test(
fpclassify_c_test
C_TEST
Expand Down
49 changes: 49 additions & 0 deletions libc/test/include/IsSubnormalTest.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//===-- Utility class to test the issubnormal macro ------------*- 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_LIBC_TEST_INCLUDE_MATH_ISSUBNORMAL_H
#define LLVM_LIBC_TEST_INCLUDE_MATH_ISSUBNORMAL_H

#include "test/UnitTest/FPMatcher.h"
#include "test/UnitTest/Test.h"

#include "include/llvm-libc-macros/math-function-macros.h"

template <typename T>
class IsSubnormalTest : public LIBC_NAMESPACE::testing::Test {
DECLARE_SPECIAL_CONSTANTS(T)

public:
typedef bool (*IsSubnormalFunc)(T);

void testSpecialNumbers(IsSubnormalFunc func) {
EXPECT_FALSE(func(aNaN));
EXPECT_FALSE(func(neg_aNaN));
EXPECT_FALSE(func(sNaN));
EXPECT_FALSE(func(neg_sNaN));
EXPECT_FALSE(func(inf));
EXPECT_FALSE(func(neg_inf));
EXPECT_FALSE(func(min_normal));
EXPECT_FALSE(func(max_normal));
EXPECT_FALSE(func(neg_max_normal));
EXPECT_TRUE(func(min_denormal));
EXPECT_TRUE(func(neg_min_denormal));
EXPECT_TRUE(func(max_denormal));
EXPECT_FALSE(func(zero));
EXPECT_FALSE(func(neg_zero));
}
};

#define LIST_ISSUBNORMAL_TESTS(T, func) \
using LlvmLibcIsSubnormalTest = IsSubnormalTest<T>; \
TEST_F(LlvmLibcIsSubnormalTest, SpecialNumbers) { \
auto issubnormal_func = [](T x) { return func(x); }; \
testSpecialNumbers(issubnormal_func); \
}

#endif // LLVM_LIBC_TEST_INCLUDE_MATH_ISSUBNORMAL_H
24 changes: 24 additions & 0 deletions libc/test/include/issubnormal_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//===-- Unittests for issubnormal macro -----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDSList-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "include/llvm-libc-macros/math-function-macros.h"

#include <assert.h>

// check if macro is defined
#ifndef issubnormal
#error "issubnormal macro is not defined"
#else
int main(void) {
assert(issubnormal(1.819f) == 0);
assert(issubnormal(-1.726) == 0);
assert(issubnormal(1.426L) == 0);
assert(issubnormal(1e-308) == 1);
assert(issubnormal(-1e-308) == 1);
return 0;
}
#endif
12 changes: 12 additions & 0 deletions libc/test/include/issubnormal_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//===-- Unittest for issubnormal[d] macro ---------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDSList-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "IsSubnormalTest.h"
#include "include/llvm-libc-macros/math-function-macros.h"

LIST_ISSUBNORMAL_TESTS(double, issubnormal)
12 changes: 12 additions & 0 deletions libc/test/include/issubnormalf_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//===-- Unittest for issubnormal[f] macro ---------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDSList-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "IsSubnormalTest.h"
#include "include/llvm-libc-macros/math-function-macros.h"

LIST_ISSUBNORMAL_TESTS(float, issubnormal)
12 changes: 12 additions & 0 deletions libc/test/include/issubnormall_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//===-- Unittest for issubnormal[l] macro ---------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDSList-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "IsSubnormalTest.h"
#include "include/llvm-libc-macros/math-function-macros.h"

LIST_ISSUBNORMAL_TESTS(long double, issubnormal)
42 changes: 23 additions & 19 deletions libc/test/src/math/smoke/AddTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,33 +35,34 @@ class AddTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
using AddFunc = OutType (*)(InType, InType);

void test_special_numbers(AddFunc func) {
EXPECT_FP_IS_NAN(func(aNaN, aNaN));
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(sNaN, sNaN), FE_INVALID);
EXPECT_FP_IS_NAN(func(in.aNaN, in.aNaN));
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.sNaN, in.sNaN), FE_INVALID);

InType qnan_42 = InFPBits::quiet_nan(Sign::POS, 0x42).get_val();
EXPECT_FP_IS_NAN(func(qnan_42, zero));
EXPECT_FP_IS_NAN(func(zero, qnan_42));
EXPECT_FP_IS_NAN(func(qnan_42, in.zero));
EXPECT_FP_IS_NAN(func(in.zero, qnan_42));

EXPECT_FP_EQ(inf, func(inf, zero));
EXPECT_FP_EQ(neg_inf, func(neg_inf, zero));
EXPECT_FP_EQ(inf, func(inf, neg_zero));
EXPECT_FP_EQ(neg_inf, func(neg_inf, neg_zero));
EXPECT_FP_EQ(inf, func(in.inf, in.zero));
EXPECT_FP_EQ(neg_inf, func(in.neg_inf, in.zero));
EXPECT_FP_EQ(inf, func(in.inf, in.neg_zero));
EXPECT_FP_EQ(neg_inf, func(in.neg_inf, in.neg_zero));
}

void test_invalid_operations(AddFunc func) {
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(inf, neg_inf), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(neg_inf, inf), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.inf, in.neg_inf), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.neg_inf, in.inf), FE_INVALID);
}

void test_range_errors(AddFunc func) {
#ifndef LIBC_TARGET_OS_IS_WINDOWS
using namespace LIBC_NAMESPACE::fputil::testing;

if (ForceRoundingMode r(RoundingMode::Nearest); r.success) {
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(max_normal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(in.max_normal, in.max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
EXPECT_FP_EQ_WITH_EXCEPTION(-inf, func(neg_max_normal, neg_max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(-inf,
func(in.neg_max_normal, in.neg_max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);

Expand All @@ -75,10 +76,11 @@ class AddTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
}

if (ForceRoundingMode r(RoundingMode::TowardZero); r.success) {
EXPECT_FP_EQ_WITH_EXCEPTION(max_normal, func(max_normal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(max_normal,
func(in.max_normal, in.max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_max_normal,
func(neg_max_normal, neg_max_normal),
func(in.neg_max_normal, in.neg_max_normal),
FE_OVERFLOW | FE_INEXACT);

EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(in.min_denormal, in.min_denormal),
Expand All @@ -91,9 +93,11 @@ class AddTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
}

if (ForceRoundingMode r(RoundingMode::Downward); r.success) {
EXPECT_FP_EQ_WITH_EXCEPTION(max_normal, func(max_normal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(max_normal,
func(in.max_normal, in.max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_FP_EQ_WITH_EXCEPTION(-inf, func(neg_max_normal, neg_max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(-inf,
func(in.neg_max_normal, in.neg_max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);

Expand All @@ -107,11 +111,11 @@ class AddTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
}

if (ForceRoundingMode r(RoundingMode::Upward); r.success) {
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(max_normal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(in.max_normal, in.max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_max_normal,
func(neg_max_normal, neg_max_normal),
func(in.neg_max_normal, in.neg_max_normal),
FE_OVERFLOW | FE_INEXACT);

EXPECT_FP_EQ_WITH_EXCEPTION(min_denormal,
Expand All @@ -127,7 +131,7 @@ class AddTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
}

void test_inexact_results(AddFunc func) {
func(InType(1.0), min_denormal);
func(InType(1.0), in.min_denormal);
EXPECT_FP_EXCEPTION(FE_INEXACT);
}
};
Expand Down
15 changes: 15 additions & 0 deletions libc/test/src/math/smoke/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,7 @@ add_fp_unittest(
FmaTest.h
DEPENDS
libc.src.math.dfmal
libc.src.__support.macros.properties.types
)

add_fp_unittest(
Expand All @@ -413,6 +414,7 @@ add_fp_unittest(
FmaTest.h
DEPENDS
libc.src.math.dfmaf128
libc.src.__support.macros.properties.types
)

add_fp_unittest(
Expand Down Expand Up @@ -1062,6 +1064,7 @@ add_fp_unittest(
libc.hdr.fenv_macros
libc.src.errno.errno
libc.src.math.expf16
libc.src.__support.FPUtil.cast
)

add_fp_unittest(
Expand Down Expand Up @@ -1098,6 +1101,7 @@ add_fp_unittest(
libc.hdr.fenv_macros
libc.src.errno.errno
libc.src.math.exp2f16
libc.src.__support.FPUtil.cast
)

add_fp_unittest(
Expand Down Expand Up @@ -1145,6 +1149,7 @@ add_fp_unittest(
libc.hdr.fenv_macros
libc.src.errno.errno
libc.src.math.exp10f16
libc.src.__support.FPUtil.cast
)

add_fp_unittest(
Expand Down Expand Up @@ -3317,6 +3322,7 @@ add_fp_unittest(
FmaTest.h
DEPENDS
libc.src.math.fmaf
libc.src.__support.macros.properties.types
FLAGS
FMA_OPT__ONLY
)
Expand All @@ -3331,6 +3337,7 @@ add_fp_unittest(
FmaTest.h
DEPENDS
libc.src.math.fma
libc.src.__support.macros.properties.types
)

add_fp_unittest(
Expand Down Expand Up @@ -3368,6 +3375,7 @@ add_fp_unittest(
libc.hdr.fenv_macros
libc.src.errno.errno
libc.src.math.expm1f16
libc.src.__support.FPUtil.cast
)

add_fp_unittest(
Expand Down Expand Up @@ -4352,6 +4360,7 @@ add_fp_unittest(
FmaTest.h
DEPENDS
libc.src.math.f16fma
libc.src.__support.macros.properties.types
)

add_fp_unittest(
Expand All @@ -4364,6 +4373,7 @@ add_fp_unittest(
FmaTest.h
DEPENDS
libc.src.math.f16fmaf
libc.src.__support.macros.properties.types
)

add_fp_unittest(
Expand All @@ -4376,6 +4386,7 @@ add_fp_unittest(
FmaTest.h
DEPENDS
libc.src.math.f16fmal
libc.src.__support.macros.properties.types
)

add_fp_unittest(
Expand All @@ -4388,6 +4399,7 @@ add_fp_unittest(
FmaTest.h
DEPENDS
libc.src.math.f16fmaf128
libc.src.__support.macros.properties.types
)

add_fp_unittest(
Expand Down Expand Up @@ -4490,6 +4502,7 @@ add_fp_unittest(
FmaTest.h
DEPENDS
libc.src.math.ffma
libc.src.__support.macros.properties.types
)

add_fp_unittest(
Expand All @@ -4502,6 +4515,7 @@ add_fp_unittest(
FmaTest.h
DEPENDS
libc.src.math.ffmal
libc.src.__support.macros.properties.types
)

add_fp_unittest(
Expand All @@ -4514,6 +4528,7 @@ add_fp_unittest(
FmaTest.h
DEPENDS
libc.src.math.ffmaf128
libc.src.__support.macros.properties.types
)

add_fp_unittest(
Expand Down
82 changes: 46 additions & 36 deletions libc/test/src/math/smoke/DivTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,110 +28,120 @@ class DivTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
using InFPBits = typename InConstants::FPBits;
using InStorageType = typename InConstants::StorageType;

InConstants in;

public:
using DivFunc = OutType (*)(InType, InType);

void test_special_numbers(DivFunc func) {
EXPECT_FP_IS_NAN(func(aNaN, aNaN));
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(sNaN, sNaN), FE_INVALID);
EXPECT_FP_IS_NAN(func(in.aNaN, in.aNaN));
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.sNaN, in.sNaN), FE_INVALID);

InType qnan_42 = InFPBits::quiet_nan(Sign::POS, 0x42).get_val();
EXPECT_FP_IS_NAN(func(qnan_42, zero));
EXPECT_FP_IS_NAN(func(zero, qnan_42));
EXPECT_FP_IS_NAN(func(qnan_42, in.zero));
EXPECT_FP_IS_NAN(func(in.zero, qnan_42));

EXPECT_FP_EQ(inf, func(inf, zero));
EXPECT_FP_EQ(neg_inf, func(neg_inf, zero));
EXPECT_FP_EQ(neg_inf, func(inf, neg_zero));
EXPECT_FP_EQ(inf, func(neg_inf, neg_zero));
EXPECT_FP_EQ(inf, func(in.inf, in.zero));
EXPECT_FP_EQ(neg_inf, func(in.neg_inf, in.zero));
EXPECT_FP_EQ(neg_inf, func(in.inf, in.neg_zero));
EXPECT_FP_EQ(inf, func(in.neg_inf, in.neg_zero));
}

void test_division_by_zero(DivFunc func) {
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(InType(1.0), zero), FE_DIVBYZERO);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_inf, func(InType(-1.0), zero),
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(InType(1.0), in.zero), FE_DIVBYZERO);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_inf, func(InType(-1.0), in.zero),
FE_DIVBYZERO);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_inf, func(InType(1.0), neg_zero),
EXPECT_FP_EQ_WITH_EXCEPTION(neg_inf, func(InType(1.0), in.neg_zero),
FE_DIVBYZERO);
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(InType(1.0), zero), FE_DIVBYZERO);
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(InType(1.0), in.zero), FE_DIVBYZERO);
}

void test_invalid_operations(DivFunc func) {
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(zero, zero), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(neg_zero, zero), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(zero, neg_zero), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(neg_zero, neg_zero), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.zero, in.zero), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.neg_zero, in.zero), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.zero, in.neg_zero), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.neg_zero, in.neg_zero), FE_INVALID);

EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(inf, inf), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.inf, in.inf), FE_INVALID);
EXPECT_MATH_ERRNO(EDOM);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(neg_inf, inf), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.neg_inf, in.inf), FE_INVALID);
EXPECT_MATH_ERRNO(EDOM);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(inf, neg_inf), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.inf, in.neg_inf), FE_INVALID);
EXPECT_MATH_ERRNO(EDOM);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(neg_inf, neg_inf), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.neg_inf, in.neg_inf), FE_INVALID);
EXPECT_MATH_ERRNO(EDOM);
}

void test_range_errors(DivFunc func) {
using namespace LIBC_NAMESPACE::fputil::testing;

if (ForceRoundingMode r(RoundingMode::Nearest); r.success) {
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(max_normal, min_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(in.max_normal, in.min_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
EXPECT_FP_EQ_WITH_EXCEPTION(-inf, func(neg_max_normal, min_denormal),
EXPECT_FP_EQ_WITH_EXCEPTION(-inf,
func(in.neg_max_normal, in.min_denormal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);

EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(min_denormal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(in.min_denormal, in.max_normal),
FE_UNDERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_zero, func(neg_min_denormal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(neg_zero,
func(in.neg_min_denormal, in.max_normal),
FE_UNDERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
}

if (ForceRoundingMode r(RoundingMode::TowardZero); r.success) {
EXPECT_FP_EQ_WITH_EXCEPTION(max_normal, func(max_normal, min_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(max_normal,
func(in.max_normal, in.min_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_max_normal,
func(neg_max_normal, min_denormal),
func(in.neg_max_normal, in.min_denormal),
FE_OVERFLOW | FE_INEXACT);

EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(min_denormal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(in.min_denormal, in.max_normal),
FE_UNDERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_zero, func(neg_min_denormal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(neg_zero,
func(in.neg_min_denormal, in.max_normal),
FE_UNDERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
}

if (ForceRoundingMode r(RoundingMode::Downward); r.success) {
EXPECT_FP_EQ_WITH_EXCEPTION(max_normal, func(max_normal, min_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(max_normal,
func(in.max_normal, in.min_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_FP_EQ_WITH_EXCEPTION(-inf, func(neg_max_normal, min_denormal),
EXPECT_FP_EQ_WITH_EXCEPTION(-inf,
func(in.neg_max_normal, in.min_denormal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);

EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(min_denormal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(in.min_denormal, in.max_normal),
FE_UNDERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_min_denormal,
func(neg_min_denormal, max_normal),
func(in.neg_min_denormal, in.max_normal),
FE_UNDERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
}

if (ForceRoundingMode r(RoundingMode::Upward); r.success) {
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(max_normal, min_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(in.max_normal, in.min_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_max_normal,
func(neg_max_normal, min_denormal),
func(in.neg_max_normal, in.min_denormal),
FE_OVERFLOW | FE_INEXACT);

EXPECT_FP_EQ_WITH_EXCEPTION(min_denormal, func(min_denormal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(min_denormal,
func(in.min_denormal, in.max_normal),
FE_UNDERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_zero, func(neg_min_denormal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(neg_zero,
func(in.neg_min_denormal, in.max_normal),
FE_UNDERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
}
Expand Down
64 changes: 32 additions & 32 deletions libc/test/src/math/smoke/FModTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,61 +108,61 @@ class FmodTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
TEST_SPECIAL(T(3.0), neg_inf, T(3.0), false, 0);

TEST_SPECIAL(zero, aNaN, aNaN, false, 0);
TEST_SPECIAL(zero, -aNaN, aNaN, false, 0);
TEST_SPECIAL(zero, neg_aNaN, aNaN, false, 0);
TEST_SPECIAL(neg_zero, aNaN, aNaN, false, 0);
TEST_SPECIAL(neg_zero, -aNaN, aNaN, false, 0);
TEST_SPECIAL(neg_zero, neg_aNaN, aNaN, false, 0);
TEST_SPECIAL(T(1.0), aNaN, aNaN, false, 0);
TEST_SPECIAL(T(1.0), -aNaN, aNaN, false, 0);
TEST_SPECIAL(T(1.0), neg_aNaN, aNaN, false, 0);
TEST_SPECIAL(inf, aNaN, aNaN, false, 0);
TEST_SPECIAL(inf, -aNaN, aNaN, false, 0);
TEST_SPECIAL(inf, neg_aNaN, aNaN, false, 0);
TEST_SPECIAL(neg_inf, aNaN, aNaN, false, 0);
TEST_SPECIAL(neg_inf, -aNaN, aNaN, false, 0);
TEST_SPECIAL(neg_inf, neg_aNaN, aNaN, false, 0);
TEST_SPECIAL(zero, sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(zero, -sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(zero, neg_sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(neg_zero, sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(neg_zero, -sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(neg_zero, neg_sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(T(1.0), sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(T(1.0), -sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(T(1.0), neg_sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(inf, sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(inf, -sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(inf, neg_sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(neg_inf, sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(neg_inf, -sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(neg_inf, neg_sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(aNaN, zero, aNaN, false, 0);
TEST_SPECIAL(-aNaN, zero, aNaN, false, 0);
TEST_SPECIAL(neg_aNaN, zero, aNaN, false, 0);
TEST_SPECIAL(aNaN, neg_zero, aNaN, false, 0);
TEST_SPECIAL(-aNaN, neg_zero, aNaN, false, 0);
TEST_SPECIAL(neg_aNaN, neg_zero, aNaN, false, 0);
TEST_SPECIAL(aNaN, T(1.0), aNaN, false, 0);
TEST_SPECIAL(-aNaN, T(1.0), aNaN, false, 0);
TEST_SPECIAL(neg_aNaN, T(1.0), aNaN, false, 0);
TEST_SPECIAL(aNaN, inf, aNaN, false, 0);
TEST_SPECIAL(-aNaN, inf, aNaN, false, 0);
TEST_SPECIAL(neg_aNaN, inf, aNaN, false, 0);
TEST_SPECIAL(aNaN, neg_inf, aNaN, false, 0);
TEST_SPECIAL(-aNaN, neg_inf, aNaN, false, 0);
TEST_SPECIAL(neg_aNaN, neg_inf, aNaN, false, 0);
TEST_SPECIAL(sNaN, zero, aNaN, false, FE_INVALID);
TEST_SPECIAL(-sNaN, zero, aNaN, false, FE_INVALID);
TEST_SPECIAL(neg_sNaN, zero, aNaN, false, FE_INVALID);
TEST_SPECIAL(sNaN, neg_zero, aNaN, false, FE_INVALID);
TEST_SPECIAL(-sNaN, neg_zero, aNaN, false, FE_INVALID);
TEST_SPECIAL(neg_sNaN, neg_zero, aNaN, false, FE_INVALID);
TEST_SPECIAL(sNaN, T(1.0), aNaN, false, FE_INVALID);
TEST_SPECIAL(-sNaN, T(1.0), aNaN, false, FE_INVALID);
TEST_SPECIAL(neg_sNaN, T(1.0), aNaN, false, FE_INVALID);
TEST_SPECIAL(sNaN, inf, aNaN, false, FE_INVALID);
TEST_SPECIAL(-sNaN, inf, aNaN, false, FE_INVALID);
TEST_SPECIAL(neg_sNaN, inf, aNaN, false, FE_INVALID);
TEST_SPECIAL(sNaN, neg_inf, aNaN, false, FE_INVALID);
TEST_SPECIAL(-sNaN, neg_inf, aNaN, false, FE_INVALID);
TEST_SPECIAL(neg_sNaN, neg_inf, aNaN, false, FE_INVALID);
TEST_SPECIAL(aNaN, aNaN, aNaN, false, 0);
TEST_SPECIAL(aNaN, -aNaN, aNaN, false, 0);
TEST_SPECIAL(-aNaN, aNaN, aNaN, false, 0);
TEST_SPECIAL(-aNaN, -aNaN, aNaN, false, 0);
TEST_SPECIAL(aNaN, neg_aNaN, aNaN, false, 0);
TEST_SPECIAL(neg_aNaN, aNaN, aNaN, false, 0);
TEST_SPECIAL(neg_aNaN, neg_aNaN, aNaN, false, 0);
TEST_SPECIAL(aNaN, sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(aNaN, -sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(-aNaN, sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(-aNaN, -sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(aNaN, neg_sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(neg_aNaN, sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(neg_aNaN, neg_sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(sNaN, aNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(sNaN, -aNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(-sNaN, aNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(-sNaN, -aNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(sNaN, neg_aNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(neg_sNaN, aNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(neg_sNaN, neg_aNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(sNaN, sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(sNaN, -sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(-sNaN, sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(-sNaN, -sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(sNaN, neg_sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(neg_sNaN, sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(neg_sNaN, neg_sNaN, aNaN, false, FE_INVALID);

TEST_SPECIAL(T(6.5), T(2.25), T(2.0), false, 0);
TEST_SPECIAL(T(-6.5), T(2.25), T(-2.0), false, 0);
Expand Down
28 changes: 23 additions & 5 deletions libc/test/src/math/smoke/FmaTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
#ifndef LLVM_LIBC_TEST_SRC_MATH_FMATEST_H
#define LLVM_LIBC_TEST_SRC_MATH_FMATEST_H

#include "src/__support/CPP/type_traits.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/macros/properties/types.h"
#include "test/UnitTest/FEnvSafeTest.h"
#include "test/UnitTest/FPMatcher.h"
#include "test/UnitTest/Test.h"
Expand Down Expand Up @@ -37,6 +40,11 @@ class FmaTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
OutConstants out;
InConstants in;

const InType in_out_min_normal =
LIBC_NAMESPACE::fputil::cast<InType>(out.min_normal);
const InType in_out_min_denormal =
LIBC_NAMESPACE::fputil::cast<InType>(out.min_denormal);

public:
using FmaFunc = OutType (*)(InType, InType, InType);

Expand All @@ -52,7 +60,7 @@ class FmaTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {

// Test underflow rounding up.
EXPECT_FP_EQ(OutFPBits(OutStorageType(2)).get_val(),
func(OutType(0.5), out.min_denormal, out.min_denormal));
func(InType(0.5), in_out_min_denormal, in_out_min_denormal));

if constexpr (sizeof(OutType) < sizeof(InType)) {
EXPECT_FP_EQ(out.zero,
Expand All @@ -63,8 +71,9 @@ class FmaTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
OutType v = OutFPBits(static_cast<OutStorageType>(OUT_MIN_NORMAL_U +
OutStorageType(1)))
.get_val();
EXPECT_FP_EQ(v, func(OutType(1) / OutType(OUT_MIN_NORMAL_U << 1), v,
out.min_normal));
EXPECT_FP_EQ(v, func(InType(1) / InType(OUT_MIN_NORMAL_U << 1),
LIBC_NAMESPACE::fputil::cast<InType>(v),
in_out_min_normal));

if constexpr (sizeof(OutType) < sizeof(InType)) {
InFPBits tmp = InFPBits::one();
Expand All @@ -74,12 +83,21 @@ class FmaTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
InType v = InFPBits(static_cast<InStorageType>(IN_MIN_NORMAL_U +
InStorageType(1)))
.get_val();
EXPECT_FP_EQ(out.min_normal, func(reciprocal_value, v, out.min_normal));
EXPECT_FP_EQ(out.min_normal,
func(reciprocal_value, v, in_out_min_normal));
}

// Test overflow.
OutType z = out.max_normal;
EXPECT_FP_EQ_ALL_ROUNDING(OutType(0.75) * z, func(InType(1.75), z, -z));
InType in_z = LIBC_NAMESPACE::fputil::cast<InType>(out.max_normal);
#if defined(LIBC_TYPES_HAS_FLOAT16) && !defined(__LIBC_USE_FLOAT16_CONVERSION)
// Rounding modes other than the default might not be usable with float16.
if constexpr (LIBC_NAMESPACE::cpp::is_same_v<OutType, float16>)
EXPECT_FP_EQ(OutType(0.75) * z, func(InType(1.75), in_z, -in_z));
else
#endif
EXPECT_FP_EQ_ALL_ROUNDING(OutType(0.75) * z,
func(InType(1.75), in_z, -in_z));

// Exact cancellation.
EXPECT_FP_EQ_ROUNDING_NEAREST(
Expand Down
2 changes: 1 addition & 1 deletion libc/test/src/math/smoke/ModfTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ class ModfTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {

T integral;
T frac = func(x, &integral);
ASSERT_TRUE(LIBC_NAMESPACE::fputil::abs(frac) < 1.0l);
ASSERT_TRUE(LIBC_NAMESPACE::fputil::abs(frac) < T(1.0));
ASSERT_TRUE(LIBC_NAMESPACE::fputil::trunc(x) == integral);
ASSERT_TRUE(integral + frac == x);
}
Expand Down
52 changes: 28 additions & 24 deletions libc/test/src/math/smoke/MulTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,22 @@ class MulTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
using MulFunc = OutType (*)(InType, InType);

void test_special_numbers(MulFunc func) {
EXPECT_FP_IS_NAN(func(aNaN, aNaN));
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(sNaN, sNaN), FE_INVALID);
EXPECT_FP_IS_NAN(func(in.aNaN, in.aNaN));
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.sNaN, in.sNaN), FE_INVALID);

InType qnan_42 = InFPBits::quiet_nan(Sign::POS, 0x42).get_val();
EXPECT_FP_IS_NAN(func(qnan_42, zero));
EXPECT_FP_IS_NAN(func(zero, qnan_42));
EXPECT_FP_IS_NAN(func(qnan_42, in.zero));
EXPECT_FP_IS_NAN(func(in.zero, qnan_42));

EXPECT_FP_EQ(inf, func(inf, InType(1.0)));
EXPECT_FP_EQ(neg_inf, func(neg_inf, InType(1.0)));
EXPECT_FP_EQ(neg_inf, func(inf, InType(-1.0)));
EXPECT_FP_EQ(inf, func(neg_inf, InType(-1.0)));
EXPECT_FP_EQ(inf, func(in.inf, InType(1.0)));
EXPECT_FP_EQ(neg_inf, func(in.neg_inf, InType(1.0)));
EXPECT_FP_EQ(neg_inf, func(in.inf, InType(-1.0)));
EXPECT_FP_EQ(inf, func(in.neg_inf, InType(-1.0)));

EXPECT_FP_EQ_ALL_ROUNDING(zero, func(zero, zero));
EXPECT_FP_EQ_ALL_ROUNDING(zero, func(neg_zero, neg_zero));
EXPECT_FP_EQ_ALL_ROUNDING(neg_zero, func(zero, neg_zero));
EXPECT_FP_EQ_ALL_ROUNDING(neg_zero, func(neg_zero, zero));
EXPECT_FP_EQ_ALL_ROUNDING(zero, func(in.zero, in.zero));
EXPECT_FP_EQ_ALL_ROUNDING(zero, func(in.neg_zero, in.neg_zero));
EXPECT_FP_EQ_ALL_ROUNDING(neg_zero, func(in.zero, in.neg_zero));
EXPECT_FP_EQ_ALL_ROUNDING(neg_zero, func(in.neg_zero, in.zero));

EXPECT_FP_EQ_ALL_ROUNDING(OutType(1.0), func(1.0, 1.0));
EXPECT_FP_EQ_ALL_ROUNDING(OutType(15.0), func(3.0, 5.0));
Expand All @@ -58,20 +58,21 @@ class MulTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
}

void test_invalid_operations(MulFunc func) {
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(inf, zero), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(inf, neg_zero), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(neg_inf, zero), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(neg_inf, neg_zero), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.inf, in.zero), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.inf, in.neg_zero), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.neg_inf, in.zero), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.neg_inf, in.neg_zero), FE_INVALID);
}

void test_range_errors(MulFunc func) {
using namespace LIBC_NAMESPACE::fputil::testing;

if (ForceRoundingMode r(RoundingMode::Nearest); r.success) {
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(max_normal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(in.max_normal, in.max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_inf, func(neg_max_normal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(neg_inf,
func(in.neg_max_normal, in.max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);

Expand All @@ -85,10 +86,11 @@ class MulTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
}

if (ForceRoundingMode r(RoundingMode::TowardZero); r.success) {
EXPECT_FP_EQ_WITH_EXCEPTION(max_normal, func(max_normal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(max_normal,
func(in.max_normal, in.max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_max_normal,
func(neg_max_normal, max_normal),
func(in.neg_max_normal, in.max_normal),
FE_OVERFLOW | FE_INEXACT);

EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(in.min_denormal, in.min_denormal),
Expand All @@ -101,9 +103,11 @@ class MulTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
}

if (ForceRoundingMode r(RoundingMode::Downward); r.success) {
EXPECT_FP_EQ_WITH_EXCEPTION(max_normal, func(max_normal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(max_normal,
func(in.max_normal, in.max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_inf, func(neg_max_normal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(neg_inf,
func(in.neg_max_normal, in.max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);

Expand All @@ -117,11 +121,11 @@ class MulTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
}

if (ForceRoundingMode r(RoundingMode::Upward); r.success) {
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(max_normal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(in.max_normal, in.max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_max_normal,
func(neg_max_normal, max_normal),
func(in.neg_max_normal, in.max_normal),
FE_OVERFLOW | FE_INEXACT);

EXPECT_FP_EQ_WITH_EXCEPTION(min_denormal,
Expand Down
14 changes: 8 additions & 6 deletions libc/test/src/math/smoke/NextTowardTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ class NextTowardTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
const T neg_zero = FPBits::zero(Sign::NEG).get_val();
const T nan = FPBits::quiet_nan().get_val();

const long double to_inf = ToFPBits::inf(Sign::POS).get_val();
const long double to_neg_inf = ToFPBits::inf(Sign::NEG).get_val();
const long double to_zero = ToFPBits::zero().get_val();
const long double to_neg_zero = ToFPBits::zero(Sign::NEG).get_val();
const long double to_nan = ToFPBits::quiet_nan().get_val();
Expand Down Expand Up @@ -134,7 +136,7 @@ class NextTowardTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
ASSERT_FP_EQ_WITH_UNDERFLOW(result, expected);

result = func(x, inf);
result = func(x, to_inf);
expected_bits = min_normal + 1;
expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
ASSERT_FP_EQ(result, expected);
Expand All @@ -145,7 +147,7 @@ class NextTowardTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
ASSERT_FP_EQ_WITH_UNDERFLOW(result, expected);

result = func(x, -inf);
result = func(x, to_neg_inf);
expected_bits = FPBits::SIGN_MASK + min_normal + 1;
expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
ASSERT_FP_EQ(result, expected);
Expand All @@ -156,29 +158,29 @@ class NextTowardTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
expected_bits = max_normal - 1;
expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
ASSERT_FP_EQ(result, expected);
ASSERT_FP_EQ_WITH_OVERFLOW(func(x, inf), inf);
ASSERT_FP_EQ_WITH_OVERFLOW(func(x, to_inf), inf);

x = -x;
result = func(x, 0);
expected_bits = FPBits::SIGN_MASK + max_normal - 1;
expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
ASSERT_FP_EQ(result, expected);
ASSERT_FP_EQ_WITH_OVERFLOW(func(x, -inf), -inf);
ASSERT_FP_EQ_WITH_OVERFLOW(func(x, to_neg_inf), neg_inf);

// 'from' is infinity.
x = inf;
result = func(x, 0);
expected_bits = max_normal;
expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
ASSERT_FP_EQ(result, expected);
ASSERT_FP_EQ(func(x, inf), inf);
ASSERT_FP_EQ(func(x, to_inf), inf);

x = neg_inf;
result = func(x, 0);
expected_bits = FPBits::SIGN_MASK + max_normal;
expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
ASSERT_FP_EQ(result, expected);
ASSERT_FP_EQ(func(x, neg_inf), neg_inf);
ASSERT_FP_EQ(func(x, to_neg_inf), neg_inf);

// 'from' is a power of 2.
x = T(32.0);
Expand Down
16 changes: 11 additions & 5 deletions libc/test/src/math/smoke/SqrtTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,21 @@ class SqrtTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {

DECLARE_SPECIAL_CONSTANTS(OutType)

struct InConstants {
DECLARE_SPECIAL_CONSTANTS(InType)
};

InConstants in;

public:
typedef OutType (*SqrtFunc)(InType);

void test_special_numbers(SqrtFunc func) {
ASSERT_FP_EQ(aNaN, func(aNaN));
ASSERT_FP_EQ(inf, func(inf));
ASSERT_FP_EQ(aNaN, func(neg_inf));
ASSERT_FP_EQ(zero, func(zero));
ASSERT_FP_EQ(neg_zero, func(neg_zero));
ASSERT_FP_EQ(aNaN, func(in.aNaN));
ASSERT_FP_EQ(inf, func(in.inf));
ASSERT_FP_EQ(aNaN, func(in.neg_inf));
ASSERT_FP_EQ(zero, func(in.zero));
ASSERT_FP_EQ(neg_zero, func(in.neg_zero));
ASSERT_FP_EQ(aNaN, func(InType(-1.0)));
ASSERT_FP_EQ(OutType(1.0), func(InType(1.0)));
ASSERT_FP_EQ(OutType(2.0), func(InType(4.0)));
Expand Down
40 changes: 21 additions & 19 deletions libc/test/src/math/smoke/SubTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,33 +34,33 @@ class SubTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
using SubFunc = OutType (*)(InType, InType);

void test_special_numbers(SubFunc func) {
EXPECT_FP_IS_NAN(func(aNaN, aNaN));
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(sNaN, sNaN), FE_INVALID);
EXPECT_FP_IS_NAN(func(in.aNaN, in.aNaN));
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.sNaN, in.sNaN), FE_INVALID);

InType qnan_42 = InFPBits::quiet_nan(Sign::POS, 0x42).get_val();
EXPECT_FP_IS_NAN(func(qnan_42, zero));
EXPECT_FP_IS_NAN(func(zero, qnan_42));
EXPECT_FP_IS_NAN(func(qnan_42, in.zero));
EXPECT_FP_IS_NAN(func(in.zero, qnan_42));

EXPECT_FP_EQ(inf, func(inf, zero));
EXPECT_FP_EQ(neg_inf, func(neg_inf, zero));
EXPECT_FP_EQ(inf, func(inf, neg_zero));
EXPECT_FP_EQ(neg_inf, func(neg_inf, neg_zero));
EXPECT_FP_EQ(inf, func(in.inf, in.zero));
EXPECT_FP_EQ(neg_inf, func(in.neg_inf, in.zero));
EXPECT_FP_EQ(inf, func(in.inf, in.neg_zero));
EXPECT_FP_EQ(neg_inf, func(in.neg_inf, in.neg_zero));
}

void test_invalid_operations(SubFunc func) {
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(inf, inf), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(neg_inf, neg_inf), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.inf, in.inf), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.neg_inf, in.neg_inf), FE_INVALID);
}

void test_range_errors(SubFunc func) {
#ifndef LIBC_TARGET_OS_IS_WINDOWS
using namespace LIBC_NAMESPACE::fputil::testing;

if (ForceRoundingMode r(RoundingMode::Nearest); r.success) {
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(max_normal, neg_max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(in.max_normal, in.neg_max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
EXPECT_FP_EQ_WITH_EXCEPTION(-inf, func(neg_max_normal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(-inf, func(in.neg_max_normal, in.max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);

Expand All @@ -75,10 +75,11 @@ class SubTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
}

if (ForceRoundingMode r(RoundingMode::TowardZero); r.success) {
EXPECT_FP_EQ_WITH_EXCEPTION(max_normal, func(max_normal, neg_max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(max_normal,
func(in.max_normal, in.neg_max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_max_normal,
func(neg_max_normal, max_normal),
func(in.neg_max_normal, in.max_normal),
FE_OVERFLOW | FE_INEXACT);

EXPECT_FP_EQ_WITH_EXCEPTION(zero,
Expand All @@ -92,9 +93,10 @@ class SubTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
}

if (ForceRoundingMode r(RoundingMode::Downward); r.success) {
EXPECT_FP_EQ_WITH_EXCEPTION(max_normal, func(max_normal, neg_max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(max_normal,
func(in.max_normal, in.neg_max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_FP_EQ_WITH_EXCEPTION(-inf, func(neg_max_normal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(-inf, func(in.neg_max_normal, in.max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);

Expand All @@ -109,11 +111,11 @@ class SubTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
}

if (ForceRoundingMode r(RoundingMode::Upward); r.success) {
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(max_normal, neg_max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(in.max_normal, in.neg_max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_max_normal,
func(neg_max_normal, max_normal),
func(in.neg_max_normal, in.max_normal),
FE_OVERFLOW | FE_INEXACT);

EXPECT_FP_EQ_WITH_EXCEPTION(min_denormal,
Expand All @@ -129,7 +131,7 @@ class SubTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
}

void test_inexact_results(SubFunc func) {
func(InType(1.0), min_denormal);
func(InType(1.0), in.min_denormal);
EXPECT_FP_EXCEPTION(FE_INEXACT);
}
};
Expand Down
14 changes: 8 additions & 6 deletions libc/test/src/math/smoke/exp10f16_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//

#include "hdr/fenv_macros.h"
#include "src/__support/FPUtil/cast.h"
#include "src/errno/libc_errno.h"
#include "src/math/exp10f16.h"
#include "test/UnitTest/FPMatcher.h"
Expand All @@ -26,15 +27,14 @@ TEST_F(LlvmLibcExp10f16Test, SpecialNumbers) {
EXPECT_FP_EQ_ALL_ROUNDING(inf, LIBC_NAMESPACE::exp10f16(inf));
EXPECT_MATH_ERRNO(0);

EXPECT_FP_EQ_ALL_ROUNDING(static_cast<float16>(zero),
LIBC_NAMESPACE::exp10f16(neg_inf));
EXPECT_FP_EQ_ALL_ROUNDING(zero, LIBC_NAMESPACE::exp10f16(neg_inf));
EXPECT_MATH_ERRNO(0);

EXPECT_FP_EQ_ALL_ROUNDING(static_cast<float16>(1.0f),
EXPECT_FP_EQ_ALL_ROUNDING(LIBC_NAMESPACE::fputil::cast<float16>(1.0f),
LIBC_NAMESPACE::exp10f16(zero));
EXPECT_MATH_ERRNO(0);

EXPECT_FP_EQ_ALL_ROUNDING(static_cast<float16>(1.0f),
EXPECT_FP_EQ_ALL_ROUNDING(LIBC_NAMESPACE::fputil::cast<float16>(1.0f),
LIBC_NAMESPACE::exp10f16(neg_zero));
EXPECT_MATH_ERRNO(0);
}
Expand All @@ -47,7 +47,8 @@ TEST_F(LlvmLibcExp10f16Test, Overflow) {
EXPECT_MATH_ERRNO(ERANGE);

EXPECT_FP_EQ_WITH_EXCEPTION(
inf, LIBC_NAMESPACE::exp10f16(static_cast<float16>(5.0)), FE_OVERFLOW);
inf, LIBC_NAMESPACE::exp10f16(LIBC_NAMESPACE::fputil::cast<float16>(5.0)),
FE_OVERFLOW);
EXPECT_MATH_ERRNO(ERANGE);
}

Expand All @@ -59,7 +60,8 @@ TEST_F(LlvmLibcExp10f16Test, Underflow) {
EXPECT_MATH_ERRNO(ERANGE);

EXPECT_FP_EQ_WITH_EXCEPTION(
zero, LIBC_NAMESPACE::exp10f16(static_cast<float16>(-8.0)),
zero,
LIBC_NAMESPACE::exp10f16(LIBC_NAMESPACE::fputil::cast<float16>(-8.0)),
FE_UNDERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
}
14 changes: 8 additions & 6 deletions libc/test/src/math/smoke/exp2f16_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//

#include "hdr/fenv_macros.h"
#include "src/__support/FPUtil/cast.h"
#include "src/errno/libc_errno.h"
#include "src/math/exp2f16.h"
#include "test/UnitTest/FPMatcher.h"
Expand All @@ -26,15 +27,14 @@ TEST_F(LlvmLibcExp2f16Test, SpecialNumbers) {
EXPECT_FP_EQ_ALL_ROUNDING(inf, LIBC_NAMESPACE::exp2f16(inf));
EXPECT_MATH_ERRNO(0);

EXPECT_FP_EQ_ALL_ROUNDING(static_cast<float16>(zero),
LIBC_NAMESPACE::exp2f16(neg_inf));
EXPECT_FP_EQ_ALL_ROUNDING(zero, LIBC_NAMESPACE::exp2f16(neg_inf));
EXPECT_MATH_ERRNO(0);

EXPECT_FP_EQ_ALL_ROUNDING(static_cast<float16>(1.0f),
EXPECT_FP_EQ_ALL_ROUNDING(LIBC_NAMESPACE::fputil::cast<float16>(1.0f),
LIBC_NAMESPACE::exp2f16(zero));
EXPECT_MATH_ERRNO(0);

EXPECT_FP_EQ_ALL_ROUNDING(static_cast<float16>(1.0f),
EXPECT_FP_EQ_ALL_ROUNDING(LIBC_NAMESPACE::fputil::cast<float16>(1.0f),
LIBC_NAMESPACE::exp2f16(neg_zero));
EXPECT_MATH_ERRNO(0);
}
Expand All @@ -47,7 +47,8 @@ TEST_F(LlvmLibcExp2f16Test, Overflow) {
EXPECT_MATH_ERRNO(ERANGE);

EXPECT_FP_EQ_WITH_EXCEPTION(
inf, LIBC_NAMESPACE::exp2f16(static_cast<float16>(16.0)), FE_OVERFLOW);
inf, LIBC_NAMESPACE::exp2f16(LIBC_NAMESPACE::fputil::cast<float16>(16.0)),
FE_OVERFLOW);
EXPECT_MATH_ERRNO(ERANGE);
}

Expand All @@ -59,7 +60,8 @@ TEST_F(LlvmLibcExp2f16Test, Underflow) {
EXPECT_MATH_ERRNO(ERANGE);

EXPECT_FP_EQ_WITH_EXCEPTION(
zero, LIBC_NAMESPACE::exp2f16(static_cast<float16>(-25.0)),
zero,
LIBC_NAMESPACE::exp2f16(LIBC_NAMESPACE::fputil::cast<float16>(-25.0)),
FE_UNDERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
}
14 changes: 8 additions & 6 deletions libc/test/src/math/smoke/expf16_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "hdr/errno_macros.h"
#include "hdr/fenv_macros.h"
#include "src/__support/FPUtil/cast.h"
#include "src/errno/libc_errno.h"
#include "src/math/expf16.h"
#include "test/UnitTest/FPMatcher.h"
Expand All @@ -27,15 +28,14 @@ TEST_F(LlvmLibcExpf16Test, SpecialNumbers) {
EXPECT_FP_EQ_ALL_ROUNDING(inf, LIBC_NAMESPACE::expf16(inf));
EXPECT_MATH_ERRNO(0);

EXPECT_FP_EQ_ALL_ROUNDING(static_cast<float16>(zero),
LIBC_NAMESPACE::expf16(neg_inf));
EXPECT_FP_EQ_ALL_ROUNDING(zero, LIBC_NAMESPACE::expf16(neg_inf));
EXPECT_MATH_ERRNO(0);

EXPECT_FP_EQ_ALL_ROUNDING(static_cast<float16>(1.0f),
EXPECT_FP_EQ_ALL_ROUNDING(LIBC_NAMESPACE::fputil::cast<float16>(1.0f),
LIBC_NAMESPACE::expf16(zero));
EXPECT_MATH_ERRNO(0);

EXPECT_FP_EQ_ALL_ROUNDING(static_cast<float16>(1.0f),
EXPECT_FP_EQ_ALL_ROUNDING(LIBC_NAMESPACE::fputil::cast<float16>(1.0f),
LIBC_NAMESPACE::expf16(neg_zero));
EXPECT_MATH_ERRNO(0);
}
Expand All @@ -48,7 +48,8 @@ TEST_F(LlvmLibcExpf16Test, Overflow) {
EXPECT_MATH_ERRNO(ERANGE);

EXPECT_FP_EQ_WITH_EXCEPTION(
inf, LIBC_NAMESPACE::expf16(static_cast<float16>(12.0)), FE_OVERFLOW);
inf, LIBC_NAMESPACE::expf16(LIBC_NAMESPACE::fputil::cast<float16>(12.0)),
FE_OVERFLOW);
EXPECT_MATH_ERRNO(ERANGE);
}

Expand All @@ -60,7 +61,8 @@ TEST_F(LlvmLibcExpf16Test, Underflow) {
EXPECT_MATH_ERRNO(ERANGE);

EXPECT_FP_EQ_WITH_EXCEPTION(
zero, LIBC_NAMESPACE::expf16(static_cast<float16>(-18.0)),
zero,
LIBC_NAMESPACE::expf16(LIBC_NAMESPACE::fputil::cast<float16>(-18.0)),
FE_UNDERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
}
44 changes: 24 additions & 20 deletions libc/test/src/math/smoke/expm1f16_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "hdr/errno_macros.h"
#include "hdr/fenv_macros.h"
#include "src/__support/FPUtil/cast.h"
#include "src/errno/libc_errno.h"
#include "src/math/expm1f16.h"
#include "test/UnitTest/FPMatcher.h"
Expand All @@ -27,7 +28,7 @@ TEST_F(LlvmLibcExpm1f16Test, SpecialNumbers) {
EXPECT_FP_EQ_ALL_ROUNDING(inf, LIBC_NAMESPACE::expm1f16(inf));
EXPECT_MATH_ERRNO(0);

EXPECT_FP_EQ_ALL_ROUNDING(static_cast<float16>(-1.0),
EXPECT_FP_EQ_ALL_ROUNDING(LIBC_NAMESPACE::fputil::cast<float16>(-1.0),
LIBC_NAMESPACE::expm1f16(neg_inf));
EXPECT_MATH_ERRNO(0);

Expand All @@ -46,7 +47,7 @@ TEST_F(LlvmLibcExpm1f16Test, Overflow) {
EXPECT_MATH_ERRNO(ERANGE);

// round(16 * log(2), HP, RN);
float16 x = static_cast<float16>(0x1.63p+3);
float16 x = LIBC_NAMESPACE::fputil::cast<float16>(0x1.63p+3);

EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_NEAREST(inf, LIBC_NAMESPACE::expm1f16(x),
FE_OVERFLOW | FE_INEXACT);
Expand All @@ -68,41 +69,44 @@ TEST_F(LlvmLibcExpm1f16Test, Overflow) {
TEST_F(LlvmLibcExpm1f16Test, ResultNearNegOne) {
LIBC_NAMESPACE::libc_errno = 0;

EXPECT_FP_EQ_WITH_EXCEPTION(static_cast<float16>(-1.0),
EXPECT_FP_EQ_WITH_EXCEPTION(LIBC_NAMESPACE::fputil::cast<float16>(-1.0),
LIBC_NAMESPACE::expm1f16(neg_max_normal),
FE_INEXACT);

// round(-11 * log(2), HP, RN);
float16 x = static_cast<float16>(-0x1.e8p+2);
float16 x = LIBC_NAMESPACE::fputil::cast<float16>(-0x1.e8p+2);

EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_NEAREST(
static_cast<float16>(-0x1.ffcp-1), LIBC_NAMESPACE::expm1f16(x),
FE_INEXACT);
LIBC_NAMESPACE::fputil::cast<float16>(-0x1.ffcp-1),
LIBC_NAMESPACE::expm1f16(x), FE_INEXACT);

EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_UPWARD(static_cast<float16>(-0x1.ffcp-1),
LIBC_NAMESPACE::expm1f16(x),
FE_INEXACT);
EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_UPWARD(
LIBC_NAMESPACE::fputil::cast<float16>(-0x1.ffcp-1),
LIBC_NAMESPACE::expm1f16(x), FE_INEXACT);

EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_DOWNWARD(
static_cast<float16>(-1.0), LIBC_NAMESPACE::expm1f16(x), FE_INEXACT);
LIBC_NAMESPACE::fputil::cast<float16>(-1.0), LIBC_NAMESPACE::expm1f16(x),
FE_INEXACT);

EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_TOWARD_ZERO(
static_cast<float16>(-0x1.ffcp-1), LIBC_NAMESPACE::expm1f16(x),
FE_INEXACT);
LIBC_NAMESPACE::fputil::cast<float16>(-0x1.ffcp-1),
LIBC_NAMESPACE::expm1f16(x), FE_INEXACT);

x = static_cast<float16>(-0x1.0a4p+3);
x = LIBC_NAMESPACE::fputil::cast<float16>(-0x1.0a4p+3);

EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_NEAREST(
static_cast<float16>(-1.0), LIBC_NAMESPACE::expm1f16(x), FE_INEXACT);
LIBC_NAMESPACE::fputil::cast<float16>(-1.0), LIBC_NAMESPACE::expm1f16(x),
FE_INEXACT);

EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_UPWARD(static_cast<float16>(-0x1.ffcp-1),
LIBC_NAMESPACE::expm1f16(x),
FE_INEXACT);
EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_UPWARD(
LIBC_NAMESPACE::fputil::cast<float16>(-0x1.ffcp-1),
LIBC_NAMESPACE::expm1f16(x), FE_INEXACT);

EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_DOWNWARD(
static_cast<float16>(-1.0), LIBC_NAMESPACE::expm1f16(x), FE_INEXACT);
LIBC_NAMESPACE::fputil::cast<float16>(-1.0), LIBC_NAMESPACE::expm1f16(x),
FE_INEXACT);

EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_TOWARD_ZERO(
static_cast<float16>(-0x1.ffcp-1), LIBC_NAMESPACE::expm1f16(x),
FE_INEXACT);
LIBC_NAMESPACE::fputil::cast<float16>(-0x1.ffcp-1),
LIBC_NAMESPACE::expm1f16(x), FE_INEXACT);
}
1 change: 1 addition & 0 deletions libc/utils/MPFRWrapper/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ if(LIBC_TESTS_CAN_USE_MPFR)
libc.src.__support.CPP.stringstream
libc.src.__support.CPP.string_view
libc.src.__support.CPP.type_traits
libc.src.__support.FPUtil.cast
libc.src.__support.FPUtil.fp_bits
libc.src.__support.FPUtil.fpbits_str
LibcTest.unit
Expand Down
3 changes: 2 additions & 1 deletion libc/utils/MPFRWrapper/MPFRUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "src/__support/CPP/string_view.h"
#include "src/__support/CPP/stringstream.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/FPUtil/fpbits_str.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/properties/types.h"
Expand Down Expand Up @@ -683,7 +684,7 @@ template <> long double MPFRNumber::as<long double>() const {
template <> float16 MPFRNumber::as<float16>() const {
// TODO: Either prove that this cast won't cause double-rounding errors, or
// find a better way to get a float16.
return static_cast<float16>(mpfr_get_d(value, mpfr_rounding));
return fputil::cast<float16>(mpfr_get_d(value, mpfr_rounding));
}
#endif

Expand Down
11 changes: 11 additions & 0 deletions libc/utils/gpu/server/rpc_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,17 @@ rpc_status_t handle_server_impl(
});
break;
}
case RPC_SYSTEM: {
uint64_t sizes[lane_size] = {0};
void *args[lane_size] = {nullptr};
port->recv_n(args, sizes, [&](uint64_t size) { return new char[size]; });
port->send([&](rpc::Buffer *buffer, uint32_t id) {
buffer->data[0] = static_cast<uint64_t>(
system(reinterpret_cast<const char *>(args[id])));
delete[] reinterpret_cast<uint8_t *>(args[id]);
});
break;
}
case RPC_NOOP: {
port->recv([](rpc::Buffer *) {});
break;
Expand Down
2 changes: 1 addition & 1 deletion libcxx/docs/Status/Cxx23Issues.csv
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@
"`LWG3631 <https://wg21.link/LWG3631>`__","``basic_format_arg(T&&)`` should use ``remove_cvref_t<T>`` throughout","2023-02 (Issaquah)","|Complete|","17.0",""
"`LWG3645 <https://wg21.link/LWG3645>`__","``resize_and_overwrite`` is overspecified to call its callback with lvalues","2023-02 (Issaquah)","|Complete|","14.0",""
"`LWG3655 <https://wg21.link/LWG3655>`__","The ``INVOKE`` operation and union types","2023-02 (Issaquah)","|Complete|","18.0",""
"`LWG3723 <https://wg21.link/LWG3723>`__","``priority_queue::push_range`` needs to ``append_range``","2023-02 (Issaquah)","","",""
"`LWG3723 <https://wg21.link/LWG3723>`__","``priority_queue::push_range`` needs to ``append_range``","2023-02 (Issaquah)","|Complete|","17.0",""
"`LWG3734 <https://wg21.link/LWG3734>`__","Inconsistency in ``inout_ptr`` and ``out_ptr`` for empty case","2023-02 (Issaquah)","|Complete|","19.0",""
"`LWG3772 <https://wg21.link/LWG3772>`__","``repeat_view``'s ``piecewise`` constructor is missing Postconditions","2023-02 (Issaquah)","|Complete|","17.0",""
"`LWG3786 <https://wg21.link/LWG3786>`__","Flat maps' deduction guide needs to default ``Allocator`` to be useful","2023-02 (Issaquah)","","",""
Expand Down
1 change: 1 addition & 0 deletions libcxxabi/src/demangle/ItaniumDemangle.h
Original file line number Diff line number Diff line change
Expand Up @@ -4450,6 +4450,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseType() {
// parse them, take the second production.

if (TryToParseTemplateArgs && look() == 'I') {
Subs.push_back(Result);
Node *TA = getDerived().parseTemplateArgs();
if (TA == nullptr)
return nullptr;
Expand Down
3 changes: 3 additions & 0 deletions libcxxabi/test/test_demangle.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30024,6 +30024,9 @@ const char* cases[][2] =
// See https://github.com/itanium-cxx-abi/cxx-abi/issues/165.
{"_ZN1C1fIiEEvDTtlNS_UlT_TL0__E_EEE", "void C::f<int>(decltype(C::'lambda'(int, auto){}))"},

// See https://github.com/llvm/llvm-project/issues/108009.
{"_ZN3FooIiE6methodIb3BarEEvT0_IT_ES3_IiE", "void Foo<int>::method<bool, Bar>(Bar<bool>, Bar<int>)"},

// C++20 class type non-type template parameters:
{"_Z1fIXtl1BLPi0ELi1EEEEvv", "void f<B{(int*)0, 1}>()"},
{"_Z1fIXtl1BLPi32EEEEvv", "void f<B{(int*)32}>()"},
Expand Down
3 changes: 1 addition & 2 deletions lld/COFF/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,8 @@ static std::string getOutputPath(StringRef path, bool isDll, bool isDriver) {

// Returns true if S matches /crtend.?\.o$/.
static bool isCrtend(StringRef s) {
if (!s.ends_with(".o"))
if (!s.consume_back(".o"))
return false;
s = s.drop_back(2);
if (s.ends_with("crtend"))
return true;
return !s.empty() && s.drop_back().ends_with("crtend");
Expand Down
3 changes: 1 addition & 2 deletions lld/Common/DriverDispatcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,7 @@ parseFlavorWithoutMinGW(llvm::SmallVectorImpl<const char *> &argsV) {

// Deduct the flavor from argv[0].
StringRef arg0 = path::filename(argsV[0]);
if (arg0.ends_with_insensitive(".exe"))
arg0 = arg0.drop_back(4);
arg0.consume_back_insensitive(".exe");
Flavor f = parseProgname(arg0);
if (f == Invalid) {
err("lld is a generic driver.\n"
Expand Down
44 changes: 22 additions & 22 deletions lld/ELF/Arch/ARM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1215,7 +1215,7 @@ template <class ELFT> void ObjFile<ELFT>::importCmseSymbols() {
continue;
}

if (symtab.cmseImportLib.count(sym->getName())) {
if (ctx.symtab->cmseImportLib.count(sym->getName())) {
error("CMSE symbol '" + sym->getName() +
"' is multiply defined in import library '" + toString(this) + "'");
continue;
Expand All @@ -1227,7 +1227,7 @@ template <class ELFT> void ObjFile<ELFT>::importCmseSymbols() {
Twine(ACLESESYM_SIZE) + " bytes");
}

symtab.cmseImportLib[sym->getName()] = sym;
ctx.symtab->cmseImportLib[sym->getName()] = sym;
}
}

Expand Down Expand Up @@ -1263,9 +1263,9 @@ static std::string checkCmseSymAttributes(Symbol *acleSeSym, Symbol *sym) {
void elf::processArmCmseSymbols() {
if (!ctx.arg.cmseImplib)
return;
// Only symbols with external linkage end up in symtab, so no need to do
// Only symbols with external linkage end up in ctx.symtab, so no need to do
// linkage checks. Only check symbol type.
for (Symbol *acleSeSym : symtab.getSymbols()) {
for (Symbol *acleSeSym : ctx.symtab->getSymbols()) {
if (!acleSeSym->getName().starts_with(ACLESESYM_PREFIX))
continue;
// If input object build attributes do not support CMSE, error and disable
Expand All @@ -1279,7 +1279,7 @@ void elf::processArmCmseSymbols() {
// Try to find the associated symbol definition.
// Symbol must have external linkage.
StringRef name = acleSeSym->getName().substr(std::strlen(ACLESESYM_PREFIX));
Symbol *sym = symtab.find(name);
Symbol *sym = ctx.symtab->find(name);
if (!sym) {
error(toString(acleSeSym->file) + ": cmse special symbol '" +
acleSeSym->getName() +
Expand All @@ -1295,7 +1295,7 @@ void elf::processArmCmseSymbols() {
}

// <sym> may be redefined later in the link in .gnu.sgstubs
symtab.cmseSymMap[name] = {acleSeSym, sym};
ctx.symtab->cmseSymMap[name] = {acleSeSym, sym};
}

// If this is an Arm CMSE secure app, replace references to entry symbol <sym>
Expand All @@ -1304,8 +1304,8 @@ void elf::processArmCmseSymbols() {
MutableArrayRef<Symbol *> syms = file->getMutableSymbols();
for (size_t i = 0, e = syms.size(); i != e; ++i) {
StringRef symName = syms[i]->getName();
if (symtab.cmseSymMap.count(symName))
syms[i] = symtab.cmseSymMap[symName].acleSeSym;
if (ctx.symtab->cmseSymMap.count(symName))
syms[i] = ctx.symtab->cmseSymMap[symName].acleSeSym;
}
});
}
Expand All @@ -1332,26 +1332,26 @@ ArmCmseSGSection::ArmCmseSGSection()
/*alignment=*/32, ".gnu.sgstubs") {
entsize = ACLESESYM_SIZE;
// The range of addresses used in the CMSE import library should be fixed.
for (auto &[_, sym] : symtab.cmseImportLib) {
for (auto &[_, sym] : ctx.symtab->cmseImportLib) {
if (impLibMaxAddr <= sym->value)
impLibMaxAddr = sym->value + sym->size;
}
if (symtab.cmseSymMap.empty())
if (ctx.symtab->cmseSymMap.empty())
return;
addMappingSymbol();
for (auto &[_, entryFunc] : symtab.cmseSymMap)
for (auto &[_, entryFunc] : ctx.symtab->cmseSymMap)
addSGVeneer(cast<Defined>(entryFunc.acleSeSym),
cast<Defined>(entryFunc.sym));
for (auto &[_, sym] : symtab.cmseImportLib) {
if (!symtab.inCMSEOutImpLib.count(sym->getName()))
for (auto &[_, sym] : ctx.symtab->cmseImportLib) {
if (!ctx.symtab->inCMSEOutImpLib.count(sym->getName()))
warn("entry function '" + sym->getName() +
"' from CMSE import library is not present in secure application");
}

if (!symtab.cmseImportLib.empty() && ctx.arg.cmseOutputLib.empty()) {
for (auto &[_, entryFunc] : symtab.cmseSymMap) {
if (!ctx.symtab->cmseImportLib.empty() && ctx.arg.cmseOutputLib.empty()) {
for (auto &[_, entryFunc] : ctx.symtab->cmseSymMap) {
Symbol *sym = entryFunc.sym;
if (!symtab.inCMSEOutImpLib.count(sym->getName()))
if (!ctx.symtab->inCMSEOutImpLib.count(sym->getName()))
warn("new entry function '" + sym->getName() +
"' introduced but no output import library specified");
}
Expand All @@ -1360,17 +1360,17 @@ ArmCmseSGSection::ArmCmseSGSection()

void ArmCmseSGSection::addSGVeneer(Symbol *acleSeSym, Symbol *sym) {
entries.emplace_back(acleSeSym, sym);
if (symtab.cmseImportLib.count(sym->getName()))
symtab.inCMSEOutImpLib[sym->getName()] = true;
if (ctx.symtab->cmseImportLib.count(sym->getName()))
ctx.symtab->inCMSEOutImpLib[sym->getName()] = true;
// Symbol addresses different, nothing to do.
if (acleSeSym->file != sym->file ||
cast<Defined>(*acleSeSym).value != cast<Defined>(*sym).value)
return;
// Only secure symbols with values equal to that of it's non-secure
// counterpart needs to be in the .gnu.sgstubs section.
ArmCmseSGVeneer *ss = nullptr;
if (symtab.cmseImportLib.count(sym->getName())) {
Defined *impSym = symtab.cmseImportLib[sym->getName()];
if (ctx.symtab->cmseImportLib.count(sym->getName())) {
Defined *impSym = ctx.symtab->cmseImportLib[sym->getName()];
ss = make<ArmCmseSGVeneer>(sym, acleSeSym, impSym->value);
} else {
ss = make<ArmCmseSGVeneer>(sym, acleSeSym);
Expand Down Expand Up @@ -1451,12 +1451,12 @@ template <typename ELFT> void elf::writeARMCmseImportLib() {
osIsPairs.emplace_back(make<OutputSection>(impSymTab->name, 0, 0), impSymTab);
osIsPairs.emplace_back(make<OutputSection>(shstrtab->name, 0, 0), shstrtab);

std::sort(symtab.cmseSymMap.begin(), symtab.cmseSymMap.end(),
std::sort(ctx.symtab->cmseSymMap.begin(), ctx.symtab->cmseSymMap.end(),
[](const auto &a, const auto &b) -> bool {
return a.second.sym->getVA() < b.second.sym->getVA();
});
// Copy the secure gateway entry symbols to the import library symbol table.
for (auto &p : symtab.cmseSymMap) {
for (auto &p : ctx.symtab->cmseSymMap) {
Defined *d = cast<Defined>(p.second.sym);
impSymTab->addSymbol(makeDefined(
ctx.internalFile, d->getName(), d->computeBinding(),
Expand Down
2 changes: 1 addition & 1 deletion lld/ELF/Arch/PPC64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ void elf::writePrefixedInstruction(uint8_t *loc, uint64_t insn) {

static bool addOptional(StringRef name, uint64_t value,
std::vector<Defined *> &defined) {
Symbol *sym = symtab.find(name);
Symbol *sym = ctx.symtab->find(name);
if (!sym || sym->isDefined())
return false;
sym->resolve(Defined{ctx.internalFile, StringRef(), STB_GLOBAL, STV_HIDDEN,
Expand Down
2 changes: 2 additions & 0 deletions lld/ELF/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class InputSectionBase;
class EhInputSection;
class Defined;
class Symbol;
class SymbolTable;
class BitcodeCompiler;
class OutputSection;
class LinkerScript;
Expand Down Expand Up @@ -600,6 +601,7 @@ struct Ctx {
Defined *tlsModuleBase;
};
ElfSym sym;
std::unique_ptr<SymbolTable> symtab;

SmallVector<std::unique_ptr<MemoryBuffer>> memoryBuffers;
SmallVector<ELFFileBase *, 0> objectFiles;
Expand Down
46 changes: 23 additions & 23 deletions lld/ELF/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ void Ctx::reset() {

in.reset();
sym = ElfSym{};
symtab = std::make_unique<SymbolTable>();

memoryBuffers.clear();
objectFiles.clear();
Expand Down Expand Up @@ -155,7 +156,6 @@ bool link(ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
context->e.cleanupCallback = []() {
elf::ctx.reset();
elf::ctx.partitions.emplace_back();
symtab = SymbolTable();

SharedFile::vernauxNum = 0;
};
Expand All @@ -167,6 +167,7 @@ bool link(ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
LinkerScript script(ctx);
ctx.script = &script;
ctx.symAux.emplace_back();
ctx.symtab = std::make_unique<SymbolTable>();

ctx.partitions.clear();
ctx.partitions.emplace_back();
Expand Down Expand Up @@ -866,8 +867,7 @@ static StripPolicy getStrip(opt::InputArgList &args) {
static uint64_t parseSectionAddress(StringRef s, opt::InputArgList &args,
const opt::Arg &arg) {
uint64_t va = 0;
if (s.starts_with("0x"))
s = s.drop_front(2);
s.consume_front("0x");
if (!to_integer(s, va, 16))
error("invalid argument: " + arg.getAsString(args));
return va;
Expand Down Expand Up @@ -2195,7 +2195,7 @@ static void handleUndefinedGlob(Ctx &ctx, StringRef arg) {
// Calling sym->extract() in the loop is not safe because it may add new
// symbols to the symbol table, invalidating the current iterator.
SmallVector<Symbol *, 0> syms;
for (Symbol *sym : symtab.getSymbols())
for (Symbol *sym : ctx.symtab->getSymbols())
if (!sym->isPlaceholder() && pat->match(sym->getName()))
syms.push_back(sym);

Expand All @@ -2204,7 +2204,7 @@ static void handleUndefinedGlob(Ctx &ctx, StringRef arg) {
}

static void handleLibcall(Ctx &ctx, StringRef name) {
Symbol *sym = symtab.find(name);
Symbol *sym = ctx.symtab->find(name);
if (sym && sym->isLazy() && isa<BitcodeFile>(sym->file)) {
if (!ctx.arg.whyExtract.empty())
ctx.whyExtractRecords.emplace_back("<libcall>", sym->file, *sym);
Expand Down Expand Up @@ -2391,7 +2391,7 @@ template <class ELFT>
static void findKeepUniqueSections(Ctx &ctx, opt::InputArgList &args) {
for (auto *arg : args.filtered(OPT_keep_unique)) {
StringRef name = arg->getValue();
auto *d = dyn_cast_or_null<Defined>(symtab.find(name));
auto *d = dyn_cast_or_null<Defined>(ctx.symtab->find(name));
if (!d || !d->section) {
warn("could not find symbol " + name + " to keep unique");
continue;
Expand All @@ -2406,7 +2406,7 @@ static void findKeepUniqueSections(Ctx &ctx, opt::InputArgList &args) {

// Symbols in the dynsym could be address-significant in other executables
// or DSOs, so we conservatively mark them as address-significant.
for (Symbol *sym : symtab.getSymbols())
for (Symbol *sym : ctx.symtab->getSymbols())
if (sym->includeInDynsym())
markAddrsig(sym);

Expand Down Expand Up @@ -2575,24 +2575,24 @@ static std::vector<WrappedSymbol> addWrappedSymbols(opt::InputArgList &args) {
if (!seen.insert(name).second)
continue;

Symbol *sym = symtab.find(name);
Symbol *sym = ctx.symtab->find(name);
if (!sym)
continue;

Symbol *wrap =
symtab.addUnusedUndefined(saver().save("__wrap_" + name), sym->binding);
Symbol *wrap = ctx.symtab->addUnusedUndefined(
saver().save("__wrap_" + name), sym->binding);

// If __real_ is referenced, pull in the symbol if it is lazy. Do this after
// processing __wrap_ as that may have referenced __real_.
StringRef realName = saver().save("__real_" + name);
if (Symbol *real = symtab.find(realName)) {
symtab.addUnusedUndefined(name, sym->binding);
if (Symbol *real = ctx.symtab->find(realName)) {
ctx.symtab->addUnusedUndefined(name, sym->binding);
// Update sym's binding, which will replace real's later in
// SymbolTable::wrap.
sym->binding = real->binding;
}

Symbol *real = symtab.addUnusedUndefined(realName);
Symbol *real = ctx.symtab->addUnusedUndefined(realName);
v.push_back({sym, real, wrap});

// We want to tell LTO not to inline symbols to be overwritten
Expand Down Expand Up @@ -2627,7 +2627,7 @@ static void combineVersionedSymbol(Symbol &sym,
//
// * There is a definition of foo@v1 and foo@@v1.
// * There is a definition of foo@v1 and foo.
Defined *sym2 = dyn_cast_or_null<Defined>(symtab.find(sym.getName()));
Defined *sym2 = dyn_cast_or_null<Defined>(ctx.symtab->find(sym.getName()));
if (!sym2)
return;
const char *suffix2 = sym2->getVersionSuffix();
Expand Down Expand Up @@ -2682,7 +2682,7 @@ static void redirectSymbols(Ctx &ctx, ArrayRef<WrappedSymbol> wrapped) {
// symbols with a non-default version (foo@v1) and check whether it should be
// combined with foo or foo@@v1.
if (ctx.arg.versionDefinitions.size() > 2)
for (Symbol *sym : symtab.getSymbols())
for (Symbol *sym : ctx.symtab->getSymbols())
if (sym->hasVersionSuffix)
combineVersionedSymbol(*sym, map);

Expand All @@ -2698,7 +2698,7 @@ static void redirectSymbols(Ctx &ctx, ArrayRef<WrappedSymbol> wrapped) {

// Update pointers in the symbol table.
for (const WrappedSymbol &w : wrapped)
symtab.wrap(w.sym, w.real, w.wrap);
ctx.symtab->wrap(w.sym, w.real, w.wrap);
}

static void reportMissingFeature(StringRef config, const Twine &report) {
Expand Down Expand Up @@ -2862,22 +2862,22 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {

// Handle --trace-symbol.
for (auto *arg : args.filtered(OPT_trace_symbol))
symtab.insert(arg->getValue())->traced = true;
ctx.symtab->insert(arg->getValue())->traced = true;

ctx.internalFile = createInternalFile("<internal>");

// Handle -u/--undefined before input files. If both a.a and b.so define foo,
// -u foo a.a b.so will extract a.a.
for (StringRef name : ctx.arg.undefined)
symtab.addUnusedUndefined(name)->referenced = true;
ctx.symtab->addUnusedUndefined(name)->referenced = true;

parseFiles(files, armCmseImpLib);

// Create dynamic sections for dynamic linking and static PIE.
ctx.arg.hasDynSymTab = !ctx.sharedFiles.empty() || ctx.arg.isPic;

// If an entry symbol is in a static archive, pull out that file now.
if (Symbol *sym = symtab.find(ctx.arg.entry))
if (Symbol *sym = ctx.symtab->find(ctx.arg.entry))
handleUndefined(ctx, sym, "--entry");

// Handle the `--undefined-glob <pattern>` options.
Expand All @@ -2891,13 +2891,13 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {

// Prevent LTO from removing any definition referenced by -u.
for (StringRef name : ctx.arg.undefined)
if (Defined *sym = dyn_cast_or_null<Defined>(symtab.find(name)))
if (Defined *sym = dyn_cast_or_null<Defined>(ctx.symtab->find(name)))
sym->isUsedInRegularObj = true;

// Mark -init and -fini symbols so that the LTO doesn't eliminate them.
if (Symbol *sym = dyn_cast_or_null<Defined>(symtab.find(ctx.arg.init)))
if (Symbol *sym = dyn_cast_or_null<Defined>(ctx.symtab->find(ctx.arg.init)))
sym->isUsedInRegularObj = true;
if (Symbol *sym = dyn_cast_or_null<Defined>(symtab.find(ctx.arg.fini)))
if (Symbol *sym = dyn_cast_or_null<Defined>(ctx.symtab->find(ctx.arg.fini)))
sym->isUsedInRegularObj = true;

// If any of our inputs are bitcode files, the LTO code generator may create
Expand Down Expand Up @@ -2978,7 +2978,7 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
// name "foo@ver1") rather do harm, so we don't call this if -r is given.
if (!ctx.arg.relocatable) {
llvm::TimeTraceScope timeScope("Process symbol versions");
symtab.scanVersionScript();
ctx.symtab->scanVersionScript();
}

// Skip the normal linked output if some LTO options are specified.
Expand Down
4 changes: 2 additions & 2 deletions lld/ELF/ICF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ template <class ELFT> void ICF<ELFT>::run() {
// cannot be merged with the later computeIsPreemptible() pass which is used
// by scanRelocations().
if (ctx.arg.hasDynSymTab)
for (Symbol *sym : symtab.getSymbols())
for (Symbol *sym : ctx.symtab->getSymbols())
sym->isPreemptible = computeIsPreemptible(*sym);

// Two text sections may have identical content and relocations but different
Expand Down Expand Up @@ -568,7 +568,7 @@ template <class ELFT> void ICF<ELFT>::run() {
d->folded = true;
}
};
for (Symbol *sym : symtab.getSymbols())
for (Symbol *sym : ctx.symtab->getSymbols())
fold(sym);
parallelForEach(ctx.objectFiles, [&](ELFFileBase *file) {
for (Symbol *sym : file->getLocalSymbols())
Expand Down
49 changes: 25 additions & 24 deletions lld/ELF/InputFiles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -667,10 +667,10 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
if (flag && flag != GRP_COMDAT)
fatal(toString(this) + ": unsupported SHT_GROUP format");

bool keepGroup =
(flag & GRP_COMDAT) == 0 || ignoreComdats ||
symtab.comdatGroups.try_emplace(CachedHashStringRef(signature), this)
.second;
bool keepGroup = (flag & GRP_COMDAT) == 0 || ignoreComdats ||
ctx.symtab->comdatGroups
.try_emplace(CachedHashStringRef(signature), this)
.second;
if (keepGroup) {
if (!ctx.arg.resolveGroups)
this->sections[i] = createInputSection(
Expand Down Expand Up @@ -817,8 +817,8 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats,
ArrayRef<Elf_Word> entries =
cantFail(obj.template getSectionContentsAsArray<Elf_Word>(sec));
if ((entries[0] & GRP_COMDAT) == 0 || ignoreComdats ||
symtab.comdatGroups.find(CachedHashStringRef(signature))->second ==
this)
ctx.symtab->comdatGroups.find(CachedHashStringRef(signature))
->second == this)
selectedGroups.push_back(entries);
break;
}
Expand Down Expand Up @@ -1130,7 +1130,8 @@ void ObjFile<ELFT>::initializeSymbols(const object::ELFFile<ELFT> &obj) {
// Some entries have been filled by LazyObjFile.
for (size_t i = firstGlobal, end = eSyms.size(); i != end; ++i)
if (!symbols[i])
symbols[i] = symtab.insert(CHECK(eSyms[i].getName(stringTable), this));
symbols[i] =
ctx.symtab->insert(CHECK(eSyms[i].getName(stringTable), this));

// Perform symbol resolution on non-local symbols.
SmallVector<unsigned, 32> undefineds;
Expand Down Expand Up @@ -1508,7 +1509,7 @@ template <class ELFT> void SharedFile::parse() {
DenseMap<CachedHashStringRef, SharedFile *>::iterator it;
bool wasInserted;
std::tie(it, wasInserted) =
symtab.soNames.try_emplace(CachedHashStringRef(soName), this);
ctx.symtab->soNames.try_emplace(CachedHashStringRef(soName), this);

// If a DSO appears more than once on the command line with and without
// --as-needed, --no-as-needed takes precedence over --as-needed because a
Expand Down Expand Up @@ -1574,7 +1575,7 @@ template <class ELFT> void SharedFile::parse() {
name = saver().save(
(name + "@" + verName).toStringRef(versionedNameBuffer));
}
Symbol *s = symtab.addSymbol(
Symbol *s = ctx.symtab->addSymbol(
Undefined{this, name, sym.getBinding(), sym.st_other, sym.getType()});
s->exportDynamic = true;
if (sym.getBinding() != STB_WEAK &&
Expand All @@ -1598,7 +1599,7 @@ template <class ELFT> void SharedFile::parse() {

uint32_t alignment = getAlignment<ELFT>(sections, sym);
if (ver == idx) {
auto *s = symtab.addSymbol(
auto *s = ctx.symtab->addSymbol(
SharedSymbol{*this, name, sym.getBinding(), sym.st_other,
sym.getType(), sym.st_value, sym.st_size, alignment});
s->dsoDefined = true;
Expand All @@ -1616,7 +1617,7 @@ template <class ELFT> void SharedFile::parse() {
reinterpret_cast<const Elf_Verdef *>(verdefs[idx])->getAux()->vda_name;
versionedNameBuffer.clear();
name = (name + "@" + verName).toStringRef(versionedNameBuffer);
auto *s = symtab.addSymbol(
auto *s = ctx.symtab->addSymbol(
SharedSymbol{*this, saver().save(name), sym.getBinding(), sym.st_other,
sym.getType(), sym.st_value, sym.st_size, alignment});
s->dsoDefined = true;
Expand Down Expand Up @@ -1751,7 +1752,7 @@ createBitcodeSymbol(Symbol *&sym, const std::vector<bool> &keptComdats,
// this way LTO can reference the same string saver's copy rather than
// keeping copies of its own.
objSym.Name = uniqueSaver().save(objSym.getName());
sym = symtab.insert(objSym.getName());
sym = ctx.symtab->insert(objSym.getName());
}

int c = objSym.getComdatIndex();
Expand All @@ -1778,7 +1779,7 @@ void BitcodeFile::parse() {
for (std::pair<StringRef, Comdat::SelectionKind> s : obj->getComdatTable()) {
keptComdats.push_back(
s.second == Comdat::NoDeduplicate ||
symtab.comdatGroups.try_emplace(CachedHashStringRef(s.first), this)
ctx.symtab->comdatGroups.try_emplace(CachedHashStringRef(s.first), this)
.second);
}

Expand Down Expand Up @@ -1810,7 +1811,7 @@ void BitcodeFile::parseLazy() {
// keeping copies of its own.
irSym.Name = uniqueSaver().save(irSym.getName());
if (!irSym.isUndefined()) {
auto *sym = symtab.insert(irSym.getName());
auto *sym = ctx.symtab->insert(irSym.getName());
sym->resolve(LazySymbol{*this});
symbols[i] = sym;
}
Expand Down Expand Up @@ -1847,15 +1848,15 @@ void BinaryFile::parse() {

llvm::StringSaver &saver = lld::saver();

symtab.addAndCheckDuplicate(Defined{this, saver.save(s + "_start"),
STB_GLOBAL, STV_DEFAULT, STT_OBJECT, 0, 0,
section});
symtab.addAndCheckDuplicate(Defined{this, saver.save(s + "_end"), STB_GLOBAL,
STV_DEFAULT, STT_OBJECT, data.size(), 0,
section});
symtab.addAndCheckDuplicate(Defined{this, saver.save(s + "_size"), STB_GLOBAL,
STV_DEFAULT, STT_OBJECT, data.size(), 0,
nullptr});
ctx.symtab->addAndCheckDuplicate(Defined{this, saver.save(s + "_start"),
STB_GLOBAL, STV_DEFAULT, STT_OBJECT,
0, 0, section});
ctx.symtab->addAndCheckDuplicate(Defined{this, saver.save(s + "_end"),
STB_GLOBAL, STV_DEFAULT, STT_OBJECT,
data.size(), 0, section});
ctx.symtab->addAndCheckDuplicate(Defined{this, saver.save(s + "_size"),
STB_GLOBAL, STV_DEFAULT, STT_OBJECT,
data.size(), 0, nullptr});
}

InputFile *elf::createInternalFile(StringRef name) {
Expand Down Expand Up @@ -1902,7 +1903,7 @@ template <class ELFT> void ObjFile<ELFT>::parseLazy() {
for (size_t i = firstGlobal, end = eSyms.size(); i != end; ++i) {
if (eSyms[i].st_shndx == SHN_UNDEF)
continue;
symbols[i] = symtab.insert(CHECK(eSyms[i].getName(stringTable), this));
symbols[i] = ctx.symtab->insert(CHECK(eSyms[i].getName(stringTable), this));
symbols[i]->resolve(LazySymbol{*this});
if (!lazy)
break;
Expand Down
2 changes: 1 addition & 1 deletion lld/ELF/InputSection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1129,7 +1129,7 @@ static void switchMorestackCallsToMorestackNonSplit(
// If the target adjusted a function's prologue, all calls to
// __morestack inside that function should be switched to
// __morestack_non_split.
Symbol *moreStackNonSplit = symtab.find("__morestack_non_split");
Symbol *moreStackNonSplit = ctx.symtab->find("__morestack_non_split");
if (!moreStackNonSplit) {
error("mixing split-stack objects requires a definition of "
"__morestack_non_split");
Expand Down
2 changes: 1 addition & 1 deletion lld/ELF/LTO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ BitcodeCompiler::BitcodeCompiler(Ctx &ctx) : ctx(ctx) {
// Initialize usedStartStop.
if (ctx.bitcodeFiles.empty())
return;
for (Symbol *sym : symtab.getSymbols()) {
for (Symbol *sym : ctx.symtab->getSymbols()) {
if (sym->isPlaceholder())
continue;
StringRef s = sym->getName();
Expand Down
12 changes: 6 additions & 6 deletions lld/ELF/LinkerScript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ void LinkerScript::addSymbol(SymbolAssignment *cmd) {
Defined newSym(createInternalFile(cmd->location), cmd->name, STB_GLOBAL,
visibility, value.type, symValue, 0, sec);

Symbol *sym = symtab.insert(cmd->name);
Symbol *sym = ctx.symtab->insert(cmd->name);
sym->mergeProperties(newSym);
newSym.overwrite(*sym);
sym->isUsedInRegularObj = true;
Expand All @@ -249,7 +249,7 @@ static void declareSymbol(SymbolAssignment *cmd) {

// If the symbol is already defined, its order is 0 (with absence indicating
// 0); otherwise it's assigned the order of the SymbolAssignment.
Symbol *sym = symtab.insert(cmd->name);
Symbol *sym = ctx.symtab->insert(cmd->name);
if (!sym->isDefined())
ctx.scriptSymOrder.insert({sym, cmd->symOrder});

Expand Down Expand Up @@ -1682,7 +1682,7 @@ ExprValue LinkerScript::getSymbolValue(StringRef name, const Twine &loc) {
return 0;
}

if (Symbol *sym = symtab.find(name)) {
if (Symbol *sym = ctx.symtab->find(name)) {
if (auto *ds = dyn_cast<Defined>(sym)) {
ExprValue v{ds->section, false, ds->value, loc};
// Retain the original st_type, so that the alias will get the same
Expand Down Expand Up @@ -1781,8 +1781,8 @@ void LinkerScript::checkFinalScriptConditions() const {
void LinkerScript::addScriptReferencedSymbolsToSymTable() {
// Some symbols (such as __ehdr_start) are defined lazily only when there
// are undefined symbols for them, so we add these to trigger that logic.
auto reference = [](StringRef name) {
Symbol *sym = symtab.addUnusedUndefined(name);
auto reference = [&ctx = ctx](StringRef name) {
Symbol *sym = ctx.symtab->addUnusedUndefined(name);
sym->isUsedInRegularObj = true;
sym->referenced = true;
};
Expand Down Expand Up @@ -1811,6 +1811,6 @@ void LinkerScript::addScriptReferencedSymbolsToSymTable() {
}

bool LinkerScript::shouldAddProvideSym(StringRef symName) {
Symbol *sym = symtab.find(symName);
Symbol *sym = elf::ctx.symtab->find(symName);
return sym && !sym->isDefined() && !sym->isCommon();
}
24 changes: 12 additions & 12 deletions lld/ELF/MarkLive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ template <class ELFT> void MarkLive<ELFT>::run() {

// Preserve externally-visible symbols if the symbols defined by this
// file can interpose other ELF file's symbols at runtime.
for (Symbol *sym : symtab.getSymbols())
for (Symbol *sym : ctx.symtab->getSymbols())
if (sym->includeInDynsym() && sym->partition == partition)
markSymbol(sym);

Expand All @@ -229,16 +229,16 @@ template <class ELFT> void MarkLive<ELFT>::run() {
return;
}

markSymbol(symtab.find(ctx.arg.entry));
markSymbol(symtab.find(ctx.arg.init));
markSymbol(symtab.find(ctx.arg.fini));
markSymbol(ctx.symtab->find(ctx.arg.entry));
markSymbol(ctx.symtab->find(ctx.arg.init));
markSymbol(ctx.symtab->find(ctx.arg.fini));
for (StringRef s : ctx.arg.undefined)
markSymbol(symtab.find(s));
markSymbol(ctx.symtab->find(s));
for (StringRef s : ctx.script->referencedSymbols)
markSymbol(symtab.find(s));
for (auto [symName, _] : symtab.cmseSymMap) {
markSymbol(symtab.cmseSymMap[symName].sym);
markSymbol(symtab.cmseSymMap[symName].acleSeSym);
markSymbol(ctx.symtab->find(s));
for (auto [symName, _] : ctx.symtab->cmseSymMap) {
markSymbol(ctx.symtab->cmseSymMap[symName].sym);
markSymbol(ctx.symtab->cmseSymMap[symName].acleSeSym);
}

// Mark .eh_frame sections as live because there are usually no relocations
Expand Down Expand Up @@ -350,8 +350,8 @@ template <class ELFT> void MarkLive<ELFT>::moveToMain() {
for (InputSectionBase *sec : ctx.inputSections) {
if (!sec->isLive() || !isValidCIdentifier(sec->name))
continue;
if (symtab.find(("__start_" + sec->name).str()) ||
symtab.find(("__stop_" + sec->name).str()))
if (ctx.symtab->find(("__start_" + sec->name).str()) ||
ctx.symtab->find(("__stop_" + sec->name).str()))
enqueue(sec, 0);
}

Expand All @@ -366,7 +366,7 @@ template <class ELFT> void elf::markLive() {
// If --gc-sections is not given, retain all input sections.
if (!ctx.arg.gcSections) {
// If a DSO defines a symbol referenced in a regular object, it is needed.
for (Symbol *sym : symtab.getSymbols())
for (Symbol *sym : ctx.symtab->getSymbols())
if (auto *s = dyn_cast<SharedSymbol>(sym))
if (s->isUsedInRegularObj && !s->isWeak())
cast<SharedFile>(s->file)->isNeeded = true;
Expand Down
Loading