[libc] Add osutils for Windows and make libc and its tests build on Windows target (#104676)

This PR first adds osutils for Windows, and changes some libc code to
make libc and its tests build on the Windows target. It then temporarily
disables some libc tests that are currently problematic on Windows.

Specifically, the changes besides the addition of osutils include:

- Macro `LIBC_TYPES_HAS_FLOAT16` is disabled on Windows. `clang-cl`
generates calls to functions in `compiler-rt` to handle float16
arithmetic and these functions are currently not linked in on Windows.
- Macro `LIBC_TYPES_HAS_INT128` is disabled on Windows.
- The invocation to `::aligned_malloc` is changed to an invocation to
`::_aligned_malloc`.
- The following unit tests are temporarily disabled because they
currently fail on Windows:
  - `test.src.__support.big_int_test`
  - `test.src.__support.arg_list_test`
  - `test.src.fenv.getenv_and_setenv_test`
- Tests involving `__m128i`, `__m256i`, and `__m512i` in
`test.src.string.memory_utils.op_tests.cpp`
- `test_range_errors` in `libc/test/src/math/smoke/AddTest.h` and
`libc/test/src/math/smoke/SubTest.h`
This commit is contained in:
Sirui Mu 2024-09-12 11:41:32 +08:00 committed by GitHub
parent 94698369e9
commit ded080152a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 163 additions and 13 deletions

View File

@ -206,6 +206,13 @@ if(explicit_target_triple AND
endif()
endif()
# Windows does not support full mode build.
if (LIBC_TARGET_OS_IS_WINDOWS AND LLVM_LIBC_FULL_BUILD)
message(FATAL_ERROR "Windows does not support full mode build.")
endif ()
message(STATUS
"Building libc for ${LIBC_TARGET_ARCHITECTURE} on ${LIBC_TARGET_OS} with
LIBC_COMPILE_OPTIONS_DEFAULT: ${LIBC_COMPILE_OPTIONS_DEFAULT}")

View File

@ -13,7 +13,8 @@
#if defined(__FLT16_MANT_DIG__) && \
(!defined(__GNUC__) || __GNUC__ >= 13 || defined(__clang__)) && \
!defined(__arm__) && !defined(_M_ARM) && !defined(__riscv)
!defined(__arm__) && !defined(_M_ARM) && !defined(__riscv) && \
!defined(_WIN32)
#define LIBC_TYPES_HAS_FLOAT16
// TODO: This would no longer be required if HdrGen let us guard function

View File

@ -10,8 +10,10 @@
#define LLVM_LIBC_MACROS_STDCKDINT_MACROS_H
// We need to use __builtin_*_overflow from GCC/Clang to implement the overflow
// macros. Check __GNUC__ for availability of such builtins.
#ifdef __GNUC__
// macros. Check __GNUC__ or __clang__ for availability of such builtins.
// Note that clang-cl defines __clang__ only and does not define __GNUC__ so we
// have to check for both.
#if defined(__GNUC__) || defined(__clang__)
// clang/gcc overlay may provides similar macros, we need to avoid redefining
// them.
#ifndef __STDC_VERSION_STDCKDINT_H__

View File

@ -199,4 +199,5 @@ add_object_library(
DEPENDS
libc.include.stdlib
libc.src.__support.common
libc.src.__support.macros.properties.os
)

View File

@ -16,15 +16,29 @@ void operator delete(void *mem, std::align_val_t) noexcept { ::free(mem); }
void operator delete(void *mem, size_t) noexcept { ::free(mem); }
void operator delete(void *mem, size_t, std::align_val_t) noexcept {
#ifdef LIBC_TARGET_OS_IS_WINDOWS
::_aligned_free(mem);
#else
::free(mem);
#endif
}
void operator delete[](void *mem) noexcept { ::free(mem); }
void operator delete[](void *mem, std::align_val_t) noexcept { ::free(mem); }
void operator delete[](void *mem, std::align_val_t) noexcept {
#ifdef LIBC_TARGET_OS_IS_WINDOWS
::_aligned_free(mem);
#else
::free(mem);
#endif
}
void operator delete[](void *mem, size_t) noexcept { ::free(mem); }
void operator delete[](void *mem, size_t, std::align_val_t) noexcept {
#ifdef LIBC_TARGET_OS_IS_WINDOWS
::_aligned_free(mem);
#else
::free(mem);
#endif
}

View File

@ -11,6 +11,7 @@
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/properties/os.h"
#include <stddef.h> // For size_t
#include <stdlib.h> // For malloc, free etc.
@ -47,7 +48,15 @@ public:
LIBC_INLINE static void *aligned_alloc(size_t s, std::align_val_t align,
AllocChecker &ac) {
#ifdef LIBC_TARGET_OS_IS_WINDOWS
// std::aligned_alloc is not available on Windows because std::free on
// Windows cannot deallocate any over-aligned memory. Microsoft provides an
// alternative for std::aligned_alloc named _aligned_malloc, but it must be
// paired with _aligned_free instead of std::free.
void *mem = ::_aligned_malloc(static_cast<size_t>(align), s);
#else
void *mem = ::aligned_alloc(static_cast<size_t>(align), s);
#endif
ac = (mem != nullptr);
return mem;
}

View File

@ -19,6 +19,8 @@
#include "linux/io.h"
#elif defined(__Fuchsia__)
#include "fuchsia/io.h"
#elif defined(_WIN32)
#include "windows/io.h"
#elif defined(__ELF__)
// TODO: Ideally we would have LIBC_TARGET_OS_IS_BAREMETAL.
#include "baremetal/io.h"

View File

@ -0,0 +1,10 @@
add_object_library(
windows_util
SRCS
exit.cpp
io.cpp
HDRS
io.h
DEPENDS
libc.src.__support.macros.config
)

View File

@ -0,0 +1,23 @@
//===-- Windows implementation of an exit function ------------------------===//
//
// 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/macros/config.h"
// On Windows we cannot make direct syscalls since Microsoft changes system call
// IDs periodically. We must rely on functions exported from ntdll.dll or
// kernel32.dll to invoke system service procedures.
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
namespace LIBC_NAMESPACE_DECL {
namespace internal {
[[noreturn]] void exit(int status) { ::ExitProcess(status); }
} // namespace internal
} // namespace LIBC_NAMESPACE_DECL

View File

@ -0,0 +1,25 @@
//===------------- Windows implementation of IO utils -----------*- 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
//
//===----------------------------------------------------------------------===//
#include "io.h"
#include "src/__support/macros/config.h"
// On Windows we cannot make direct syscalls since Microsoft changes system call
// IDs periodically. We must rely on functions exported from ntdll.dll or
// kernel32.dll to invoke system service procedures.
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
namespace LIBC_NAMESPACE_DECL {
void write_to_stderr(cpp::string_view msg) {
::HANDLE stream = ::GetStdHandle(STD_ERROR_HANDLE);
::WriteFile(stream, msg.data(), msg.size(), nullptr, nullptr);
}
} // namespace LIBC_NAMESPACE_DECL

View File

@ -0,0 +1,21 @@
//===------------- Windows implementation of IO utils -----------*- 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___SUPPORT_OSUTIL_WINDOWS_IO_H
#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_WINDOWS_IO_H
#include "src/__support/CPP/string_view.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
void write_to_stderr(cpp::string_view msg);
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_WINDOWS_IO_H

View File

@ -35,7 +35,7 @@
#endif // UINT64_MAX
// int128 / uint128 support
#if defined(__SIZEOF_INT128__)
#if defined(__SIZEOF_INT128__) && !defined(LIBC_TARGET_OS_IS_WINDOWS)
#define LIBC_TYPES_HAS_INT128
#endif // defined(__SIZEOF_INT128__)

View File

@ -140,9 +140,14 @@ add_libc_test(
arg_list_test.cpp
DEPENDS
libc.src.__support.arg_list
libc.src.__support.macros.properties.os
)
if(NOT LIBC_TARGET_ARCHITECTURE_IS_NVPTX)
# TODO: clang-cl generates calls into runtime library functions to
# handle 128-bit integer arithmetics and conversions which are not yet
# available on Windows. Re-enable 128-bit integer support on Windows once
# these functions are ready.
if(NOT LIBC_TARGET_ARCHITECTURE_IS_NVPTX AND NOT LIBC_TARGET_OS_IS_WINDOWS)
add_libc_test(
big_int_test
SUITE

View File

@ -25,6 +25,7 @@ add_libc_test(
libc.src.__support.FPUtil.fp_bits
libc.src.__support.FPUtil.fpbits_str
libc.src.__support.integer_literals
libc.src.__support.macros.properties.types
libc.src.__support.sign
)

View File

@ -9,6 +9,7 @@
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/fpbits_str.h"
#include "src/__support/integer_literals.h"
#include "src/__support/macros/properties/types.h"
#include "src/__support/sign.h" // Sign
#include "test/UnitTest/Test.h"
@ -425,13 +426,10 @@ TEST(LlvmLibcFPBitsTest, DoubleType) {
EXPECT_EQ(quiet_nan.is_quiet_nan(), true);
}
#ifdef LIBC_TARGET_ARCH_IS_X86
#ifdef LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80
TEST(LlvmLibcFPBitsTest, X86LongDoubleType) {
using LongDoubleBits = FPBits<long double>;
if constexpr (sizeof(long double) == sizeof(double))
return; // The tests for the "double" type cover for this case.
EXPECT_STREQ(LIBC_NAMESPACE::str(LongDoubleBits::inf(Sign::POS)).c_str(),
"(+Infinity)");
EXPECT_STREQ(LIBC_NAMESPACE::str(LongDoubleBits::inf(Sign::NEG)).c_str(),

View File

@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "src/__support/arg_list.h"
#include "src/__support/macros/properties/os.h"
#include "test/UnitTest/Test.h"
@ -120,7 +121,7 @@ TEST(LlvmLibcArgListTest, TestStructTypes) {
}
// Test vector extensions from clang.
#if __has_attribute(ext_vector_type)
#if !defined(LIBC_TARGET_OS_IS_WINDOWS) && __has_attribute(ext_vector_type)
using int1 = int __attribute__((ext_vector_type(1)));
using int2 = int __attribute__((ext_vector_type(2)));

View File

@ -41,6 +41,7 @@ add_libc_unittest(
libc.src.fenv.fesetenv
libc.src.fenv.fesetround
libc.src.__support.FPUtil.fenv_impl
libc.src.__support.macros.properties.os
LINK_LIBRARIES
LibcFPTestHelpers
)

View File

@ -13,6 +13,7 @@
#include "src/fenv/fesetround.h"
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/macros/properties/os.h"
#include "test/UnitTest/FEnvSafeTest.h"
#include "test/UnitTest/Test.h"
@ -20,6 +21,7 @@
using LlvmLibcFEnvTest = LIBC_NAMESPACE::testing::FEnvSafeTest;
#ifndef LIBC_TARGET_OS_IS_WINDOWS
TEST_F(LlvmLibcFEnvTest, GetEnvAndSetEnv) {
// We will disable all exceptions to prevent invocation of the exception
// handler.
@ -71,8 +73,9 @@ TEST_F(LlvmLibcFEnvTest, Set_FE_DFL_ENV) {
int rm = LIBC_NAMESPACE::fegetround();
EXPECT_EQ(rm, FE_TONEAREST);
}
#endif
#ifdef _WIN32
#ifdef LIBC_TARGET_OS_IS_WINDOWS
TEST_F(LlvmLibcFEnvTest, Windows_Set_Get_Test) {
// If a valid fenv_t is written, then reading it back out should be identical.
fenv_t setEnv = {0x7e00053e, 0x0f00000f};

View File

@ -12,6 +12,7 @@
#include "hdr/errno_macros.h"
#include "hdr/fenv_macros.h"
#include "src/__support/FPUtil/BasicOperations.h"
#include "src/__support/macros/properties/os.h"
#include "test/UnitTest/FEnvSafeTest.h"
#include "test/UnitTest/FPMatcher.h"
#include "test/UnitTest/Test.h"
@ -53,6 +54,7 @@ public:
}
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) {
@ -121,6 +123,7 @@ public:
FE_UNDERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
}
#endif
}
void test_inexact_results(AddFunc func) {

View File

@ -153,6 +153,7 @@ add_fp_unittest(
libc.hdr.errno_macros
libc.hdr.fenv_macros
libc.src.math.fadd
libc.src.__support.macros.properties.os
)
add_fp_unittest(
@ -168,6 +169,7 @@ add_fp_unittest(
libc.hdr.errno_macros
libc.hdr.fenv_macros
libc.src.math.faddl
libc.src.__support.macros.properties.os
)
add_fp_unittest(
@ -183,6 +185,7 @@ add_fp_unittest(
libc.hdr.errno_macros
libc.hdr.fenv_macros
libc.src.math.faddf128
libc.src.__support.macros.properties.os
)
add_fp_unittest(
@ -424,6 +427,7 @@ add_fp_unittest(
libc.src.errno.errno
libc.hdr.fenv_macros
libc.src.math.dsubl
libc.src.__support.macros.properties.os
)
add_fp_unittest(
@ -438,6 +442,7 @@ add_fp_unittest(
libc.hdr.errno_macros
libc.hdr.fenv_macros
libc.src.math.dsubf128
libc.src.__support.macros.properties.os
)
add_fp_unittest(
@ -4173,6 +4178,7 @@ add_fp_unittest(
libc.hdr.errno_macros
libc.hdr.fenv_macros
libc.src.math.f16add
libc.src.__support.macros.properties.os
)
add_fp_unittest(
@ -4187,6 +4193,7 @@ add_fp_unittest(
libc.hdr.errno_macros
libc.hdr.fenv_macros
libc.src.math.f16addf
libc.src.__support.macros.properties.os
)
add_fp_unittest(
@ -4201,6 +4208,7 @@ add_fp_unittest(
libc.hdr.errno_macros
libc.hdr.fenv_macros
libc.src.math.f16addl
libc.src.__support.macros.properties.os
)
add_fp_unittest(
@ -4215,6 +4223,7 @@ add_fp_unittest(
libc.hdr.errno_macros
libc.hdr.fenv_macros
libc.src.math.f16addf128
libc.src.__support.macros.properties.os
)
add_fp_unittest(
@ -4229,6 +4238,7 @@ add_fp_unittest(
libc.hdr.errno_macros
libc.hdr.fenv_macros
libc.src.math.f16sub
libc.src.__support.macros.properties.os
)
add_fp_unittest(
@ -4243,6 +4253,7 @@ add_fp_unittest(
libc.hdr.errno_macros
libc.hdr.fenv_macros
libc.src.math.f16subf
libc.src.__support.macros.properties.os
)
add_fp_unittest(
@ -4257,6 +4268,7 @@ add_fp_unittest(
libc.hdr.errno_macros
libc.hdr.fenv_macros
libc.src.math.f16subl
libc.src.__support.macros.properties.os
)
add_fp_unittest(
@ -4271,6 +4283,7 @@ add_fp_unittest(
libc.hdr.errno_macros
libc.hdr.fenv_macros
libc.src.math.f16subf128
libc.src.__support.macros.properties.os
)
add_fp_unittest(
@ -4552,6 +4565,7 @@ add_fp_unittest(
libc.hdr.errno_macros
libc.hdr.fenv_macros
libc.src.math.fsub
libc.src.__support.macros.properties.os
)
add_fp_unittest(
@ -4566,6 +4580,7 @@ add_fp_unittest(
libc.hdr.errno_macros
libc.hdr.fenv_macros
libc.src.math.fsubl
libc.src.__support.macros.properties.os
)
add_fp_unittest(
@ -4580,6 +4595,7 @@ add_fp_unittest(
libc.hdr.errno_macros
libc.hdr.fenv_macros
libc.src.math.fsubf128
libc.src.__support.macros.properties.os
)
add_fp_unittest(
@ -4753,6 +4769,7 @@ add_fp_unittest(
libc.hdr.errno_macros
libc.hdr.fenv_macros
libc.src.math.daddl
libc.src.__support.macros.properties.os
)
add_fp_unittest(
@ -4767,6 +4784,7 @@ add_fp_unittest(
libc.hdr.errno_macros
libc.hdr.fenv_macros
libc.src.math.daddf128
libc.src.__support.macros.properties.os
)
add_fp_unittest(

View File

@ -11,6 +11,7 @@
#include "hdr/errno_macros.h"
#include "hdr/fenv_macros.h"
#include "src/__support/macros/properties/os.h"
#include "test/UnitTest/FEnvSafeTest.h"
#include "test/UnitTest/FPMatcher.h"
#include "test/UnitTest/Test.h"
@ -52,6 +53,7 @@ public:
}
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) {
@ -123,6 +125,7 @@ public:
FE_UNDERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
}
#endif
}
void test_inexact_results(SubFunc func) {

View File

@ -12,6 +12,7 @@ add_libc_test(
libc.src.__support.CPP.array
libc.src.__support.CPP.cstddef
libc.src.__support.CPP.span
libc.src.__support.macros.properties.os
libc.src.__support.macros.properties.types
libc.src.__support.macros.sanitizer
libc.src.string.memory_utils.memory_utils

View File

@ -8,6 +8,7 @@
#include "memory_check_utils.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/properties/os.h"
#include "src/__support/macros/properties/types.h" // LIBC_TYPES_HAS_INT64
#include "src/string/memory_utils/op_aarch64.h"
#include "src/string/memory_utils/op_builtin.h"
@ -294,7 +295,7 @@ TYPED_TEST(LlvmLibcOpTest, Bcmp, BcmpImplementations) {
#endif // LIBC_TARGET_ARCH_IS_X86_64
using MemcmpImplementations = testing::TypeList<
#ifdef LIBC_TARGET_ARCH_IS_X86_64
#if defined(LIBC_TARGET_ARCH_IS_X86_64) && !defined(LIBC_TARGET_OS_IS_WINDOWS)
#ifdef __SSE2__
generic::Memcmp<__m128i>, //
#endif