Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[libc] Provide an implementation of the 'stdint.h' header #83353

Merged
merged 1 commit into from
Mar 4, 2024

Conversation

jhuber6
Copy link
Contributor

@jhuber6 jhuber6 commented Feb 28, 2024

Summary:
I've noticed one problem is that the user includes stdint.h the
compiler will do #include_next <stdint.h> potentially into a
conflicting implementation on systems with multiple headers installed.
The clang header is standards compliant and works with clang and
gcc which are both of our targets, so I simply copied it here. This
has the effect of including stdint.h on clang / LLVM libc behaving the
same as -ffreestanding.

@llvmbot
Copy link
Collaborator

llvmbot commented Feb 28, 2024

@llvm/pr-subscribers-backend-amdgpu

@llvm/pr-subscribers-libc

Author: Joseph Huber (jhuber6)

Changes

Summary:
I've noticed one problem is that the user includes stdint.h the
compiler will do #include_next &lt;stdint.h&gt; potentially into a
conflicting implementation on systems with multiple headers installed.
The clang header is standards compliant and works with clang and
gcc which are both of our targets, so I simply copied it here. This
has the effect of including stdint.h on clang / LLVM libc behaving the
same as -ffreestanding.


Patch is 29.51 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/83353.diff

3 Files Affected:

  • (modified) libc/include/CMakeLists.txt (+8)
  • (added) libc/include/llvm-libc-macros/stdint-macros.h (+878)
  • (added) libc/include/stdint.h.def (+14)
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 9090b3bca01e0d..34d6839fd789a9 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -84,6 +84,14 @@ add_gen_header(
     .llvm-libc-macros.float_macros
 )
 
+add_gen_header(
+  stdint
+  DEF_FILE stdint.h.def
+  GEN_HDR stdint.h
+  DEPENDS
+    .llvm-libc-macros.stdint_macros
+)
+
 add_gen_header(
   limits
   DEF_FILE limits.h.def
diff --git a/libc/include/llvm-libc-macros/stdint-macros.h b/libc/include/llvm-libc-macros/stdint-macros.h
new file mode 100644
index 00000000000000..472c33e5df58dd
--- /dev/null
+++ b/libc/include/llvm-libc-macros/stdint-macros.h
@@ -0,0 +1,878 @@
+//===-- Definition of macros from stdint.h --------------------------------===//
+//
+// 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_MACROS_STDINT_MACROS_H
+#define LLVM_LIBC_MACROS_STDINT_MACROS_H
+
+// These definitions are copied directly from the clang implementation located
+// at 'clang/lib/Headers/stdint.h'. We provide it here againt for compatibility.
+
+/* C99 7.18.1.1 Exact-width integer types.
+ * C99 7.18.1.2 Minimum-width integer types.
+ * C99 7.18.1.3 Fastest minimum-width integer types.
+ *
+ * The standard requires that exact-width type be defined for 8-, 16-, 32-, and
+ * 64-bit types if they are implemented. Other exact width types are optional.
+ * This implementation defines an exact-width types for every integer width
+ * that is represented in the standard integer types.
+ *
+ * The standard also requires minimum-width types be defined for 8-, 16-, 32-,
+ * and 64-bit widths regardless of whether there are corresponding exact-width
+ * types.
+ *
+ * To accommodate targets that are missing types that are exactly 8, 16, 32, or
+ * 64 bits wide, this implementation takes an approach of cascading
+ * redefinitions, redefining __int_leastN_t to successively smaller exact-width
+ * types. It is therefore important that the types are defined in order of
+ * descending widths.
+ *
+ * We currently assume that the minimum-width types and the fastest
+ * minimum-width types are the same. This is allowed by the standard, but is
+ * suboptimal.
+ *
+ * In violation of the standard, some targets do not implement a type that is
+ * wide enough to represent all of the required widths (8-, 16-, 32-, 64-bit).
+ * To accommodate these targets, a required minimum-width type is only
+ * defined if there exists an exact-width type of equal or greater width.
+ */
+
+#ifdef __INT64_TYPE__
+#ifndef __int8_t_defined /* glibc sys/types.h also defines int64_t*/
+typedef __INT64_TYPE__ int64_t;
+#endif /* __int8_t_defined */
+typedef __UINT64_TYPE__ uint64_t;
+#undef __int_least64_t
+#define __int_least64_t int64_t
+#undef __uint_least64_t
+#define __uint_least64_t uint64_t
+#undef __int_least32_t
+#define __int_least32_t int64_t
+#undef __uint_least32_t
+#define __uint_least32_t uint64_t
+#undef __int_least16_t
+#define __int_least16_t int64_t
+#undef __uint_least16_t
+#define __uint_least16_t uint64_t
+#undef __int_least8_t
+#define __int_least8_t int64_t
+#undef __uint_least8_t
+#define __uint_least8_t uint64_t
+#endif /* __INT64_TYPE__ */
+
+#ifdef __int_least64_t
+typedef __int_least64_t int_least64_t;
+typedef __uint_least64_t uint_least64_t;
+typedef __int_least64_t int_fast64_t;
+typedef __uint_least64_t uint_fast64_t;
+#endif /* __int_least64_t */
+
+#ifdef __INT56_TYPE__
+typedef __INT56_TYPE__ int56_t;
+typedef __UINT56_TYPE__ uint56_t;
+typedef int56_t int_least56_t;
+typedef uint56_t uint_least56_t;
+typedef int56_t int_fast56_t;
+typedef uint56_t uint_fast56_t;
+#undef __int_least32_t
+#define __int_least32_t int56_t
+#undef __uint_least32_t
+#define __uint_least32_t uint56_t
+#undef __int_least16_t
+#define __int_least16_t int56_t
+#undef __uint_least16_t
+#define __uint_least16_t uint56_t
+#undef __int_least8_t
+#define __int_least8_t int56_t
+#undef __uint_least8_t
+#define __uint_least8_t uint56_t
+#endif /* __INT56_TYPE__ */
+
+#ifdef __INT48_TYPE__
+typedef __INT48_TYPE__ int48_t;
+typedef __UINT48_TYPE__ uint48_t;
+typedef int48_t int_least48_t;
+typedef uint48_t uint_least48_t;
+typedef int48_t int_fast48_t;
+typedef uint48_t uint_fast48_t;
+#undef __int_least32_t
+#define __int_least32_t int48_t
+#undef __uint_least32_t
+#define __uint_least32_t uint48_t
+#undef __int_least16_t
+#define __int_least16_t int48_t
+#undef __uint_least16_t
+#define __uint_least16_t uint48_t
+#undef __int_least8_t
+#define __int_least8_t int48_t
+#undef __uint_least8_t
+#define __uint_least8_t uint48_t
+#endif /* __INT48_TYPE__ */
+
+#ifdef __INT40_TYPE__
+typedef __INT40_TYPE__ int40_t;
+typedef __UINT40_TYPE__ uint40_t;
+typedef int40_t int_least40_t;
+typedef uint40_t uint_least40_t;
+typedef int40_t int_fast40_t;
+typedef uint40_t uint_fast40_t;
+#undef __int_least32_t
+#define __int_least32_t int40_t
+#undef __uint_least32_t
+#define __uint_least32_t uint40_t
+#undef __int_least16_t
+#define __int_least16_t int40_t
+#undef __uint_least16_t
+#define __uint_least16_t uint40_t
+#undef __int_least8_t
+#define __int_least8_t int40_t
+#undef __uint_least8_t
+#define __uint_least8_t uint40_t
+#endif /* __INT40_TYPE__ */
+
+#ifdef __INT32_TYPE__
+
+#ifndef __int8_t_defined /* glibc sys/types.h also defines int32_t*/
+typedef __INT32_TYPE__ int32_t;
+#endif /* __int8_t_defined */
+
+#ifndef __uint32_t_defined /* more glibc compatibility */
+#define __uint32_t_defined
+typedef __UINT32_TYPE__ uint32_t;
+#endif /* __uint32_t_defined */
+
+#undef __int_least32_t
+#define __int_least32_t int32_t
+#undef __uint_least32_t
+#define __uint_least32_t uint32_t
+#undef __int_least16_t
+#define __int_least16_t int32_t
+#undef __uint_least16_t
+#define __uint_least16_t uint32_t
+#undef __int_least8_t
+#define __int_least8_t int32_t
+#undef __uint_least8_t
+#define __uint_least8_t uint32_t
+#endif /* __INT32_TYPE__ */
+
+#ifdef __int_least32_t
+typedef __int_least32_t int_least32_t;
+typedef __uint_least32_t uint_least32_t;
+typedef __int_least32_t int_fast32_t;
+typedef __uint_least32_t uint_fast32_t;
+#endif /* __int_least32_t */
+
+#ifdef __INT24_TYPE__
+typedef __INT24_TYPE__ int24_t;
+typedef __UINT24_TYPE__ uint24_t;
+typedef int24_t int_least24_t;
+typedef uint24_t uint_least24_t;
+typedef int24_t int_fast24_t;
+typedef uint24_t uint_fast24_t;
+#undef __int_least16_t
+#define __int_least16_t int24_t
+#undef __uint_least16_t
+#define __uint_least16_t uint24_t
+#undef __int_least8_t
+#define __int_least8_t int24_t
+#undef __uint_least8_t
+#define __uint_least8_t uint24_t
+#endif /* __INT24_TYPE__ */
+
+#ifdef __INT16_TYPE__
+#ifndef __int8_t_defined /* glibc sys/types.h also defines int16_t*/
+typedef __INT16_TYPE__ int16_t;
+#endif /* __int8_t_defined */
+typedef __UINT16_TYPE__ uint16_t;
+#undef __int_least16_t
+#define __int_least16_t int16_t
+#undef __uint_least16_t
+#define __uint_least16_t uint16_t
+#undef __int_least8_t
+#define __int_least8_t int16_t
+#undef __uint_least8_t
+#define __uint_least8_t uint16_t
+#endif /* __INT16_TYPE__ */
+
+#ifdef __int_least16_t
+typedef __int_least16_t int_least16_t;
+typedef __uint_least16_t uint_least16_t;
+typedef __int_least16_t int_fast16_t;
+typedef __uint_least16_t uint_fast16_t;
+#endif /* __int_least16_t */
+
+#ifdef __INT8_TYPE__
+#ifndef __int8_t_defined /* glibc sys/types.h also defines int8_t*/
+typedef __INT8_TYPE__ int8_t;
+#endif /* __int8_t_defined */
+typedef __UINT8_TYPE__ uint8_t;
+#undef __int_least8_t
+#define __int_least8_t int8_t
+#undef __uint_least8_t
+#define __uint_least8_t uint8_t
+#endif /* __INT8_TYPE__ */
+
+#ifdef __int_least8_t
+typedef __int_least8_t int_least8_t;
+typedef __uint_least8_t uint_least8_t;
+typedef __int_least8_t int_fast8_t;
+typedef __uint_least8_t uint_fast8_t;
+#endif /* __int_least8_t */
+
+/* prevent glibc sys/types.h from defining conflicting types */
+#ifndef __int8_t_defined
+#define __int8_t_defined
+#endif /* __int8_t_defined */
+
+/* C99 7.18.1.4 Integer types capable of holding object pointers.
+ */
+#define __stdint_join3(a, b, c) a##b##c
+
+#ifndef _INTPTR_T
+#ifndef __intptr_t_defined
+typedef __INTPTR_TYPE__ intptr_t;
+#define __intptr_t_defined
+#define _INTPTR_T
+#endif
+#endif
+
+#ifndef _UINTPTR_T
+typedef __UINTPTR_TYPE__ uintptr_t;
+#define _UINTPTR_T
+#endif
+
+/* C99 7.18.1.5 Greatest-width integer types.
+ */
+typedef __INTMAX_TYPE__ intmax_t;
+typedef __UINTMAX_TYPE__ uintmax_t;
+
+/* C99 7.18.4 Macros for minimum-width integer constants.
+ *
+ * The standard requires that integer constant macros be defined for all the
+ * minimum-width types defined above. As 8-, 16-, 32-, and 64-bit minimum-width
+ * types are required, the corresponding integer constant macros are defined
+ * here. This implementation also defines minimum-width types for every other
+ * integer width that the target implements, so corresponding macros are
+ * defined below, too.
+ *
+ * These macros are defined using the same successive-shrinking approach as
+ * the type definitions above. It is likewise important that macros are defined
+ * in order of decending width.
+ *
+ * Note that C++ should not check __STDC_CONSTANT_MACROS here, contrary to the
+ * claims of the C standard (see C++ 18.3.1p2, [cstdint.syn]).
+ */
+
+#define __int_c_join(a, b) a##b
+#define __int_c(v, suffix) __int_c_join(v, suffix)
+#define __uint_c(v, suffix) __int_c_join(v##U, suffix)
+
+#ifdef __INT64_TYPE__
+#undef __int64_c_suffix
+#undef __int32_c_suffix
+#undef __int16_c_suffix
+#undef __int8_c_suffix
+#ifdef __INT64_C_SUFFIX__
+#define __int64_c_suffix __INT64_C_SUFFIX__
+#define __int32_c_suffix __INT64_C_SUFFIX__
+#define __int16_c_suffix __INT64_C_SUFFIX__
+#define __int8_c_suffix __INT64_C_SUFFIX__
+#endif /* __INT64_C_SUFFIX__ */
+#endif /* __INT64_TYPE__ */
+
+#ifdef __int_least64_t
+#ifdef __int64_c_suffix
+#define INT64_C(v) __int_c(v, __int64_c_suffix)
+#define UINT64_C(v) __uint_c(v, __int64_c_suffix)
+#else
+#define INT64_C(v) v
+#define UINT64_C(v) v##U
+#endif /* __int64_c_suffix */
+#endif /* __int_least64_t */
+
+#ifdef __INT56_TYPE__
+#undef __int32_c_suffix
+#undef __int16_c_suffix
+#undef __int8_c_suffix
+#ifdef __INT56_C_SUFFIX__
+#define INT56_C(v) __int_c(v, __INT56_C_SUFFIX__)
+#define UINT56_C(v) __uint_c(v, __INT56_C_SUFFIX__)
+#define __int32_c_suffix __INT56_C_SUFFIX__
+#define __int16_c_suffix __INT56_C_SUFFIX__
+#define __int8_c_suffix __INT56_C_SUFFIX__
+#else
+#define INT56_C(v) v
+#define UINT56_C(v) v##U
+#endif /* __INT56_C_SUFFIX__ */
+#endif /* __INT56_TYPE__ */
+
+#ifdef __INT48_TYPE__
+#undef __int32_c_suffix
+#undef __int16_c_suffix
+#undef __int8_c_suffix
+#ifdef __INT48_C_SUFFIX__
+#define INT48_C(v) __int_c(v, __INT48_C_SUFFIX__)
+#define UINT48_C(v) __uint_c(v, __INT48_C_SUFFIX__)
+#define __int32_c_suffix __INT48_C_SUFFIX__
+#define __int16_c_suffix __INT48_C_SUFFIX__
+#define __int8_c_suffix __INT48_C_SUFFIX__
+#else
+#define INT48_C(v) v
+#define UINT48_C(v) v##U
+#endif /* __INT48_C_SUFFIX__ */
+#endif /* __INT48_TYPE__ */
+
+#ifdef __INT40_TYPE__
+#undef __int32_c_suffix
+#undef __int16_c_suffix
+#undef __int8_c_suffix
+#ifdef __INT40_C_SUFFIX__
+#define INT40_C(v) __int_c(v, __INT40_C_SUFFIX__)
+#define UINT40_C(v) __uint_c(v, __INT40_C_SUFFIX__)
+#define __int32_c_suffix __INT40_C_SUFFIX__
+#define __int16_c_suffix __INT40_C_SUFFIX__
+#define __int8_c_suffix __INT40_C_SUFFIX__
+#else
+#define INT40_C(v) v
+#define UINT40_C(v) v##U
+#endif /* __INT40_C_SUFFIX__ */
+#endif /* __INT40_TYPE__ */
+
+#ifdef __INT32_TYPE__
+#undef __int32_c_suffix
+#undef __int16_c_suffix
+#undef __int8_c_suffix
+#ifdef __INT32_C_SUFFIX__
+#define __int32_c_suffix __INT32_C_SUFFIX__
+#define __int16_c_suffix __INT32_C_SUFFIX__
+#define __int8_c_suffix __INT32_C_SUFFIX__
+#endif /* __INT32_C_SUFFIX__ */
+#endif /* __INT32_TYPE__ */
+
+#ifdef __int_least32_t
+#ifdef __int32_c_suffix
+#define INT32_C(v) __int_c(v, __int32_c_suffix)
+#define UINT32_C(v) __uint_c(v, __int32_c_suffix)
+#else
+#define INT32_C(v) v
+#define UINT32_C(v) v##U
+#endif /* __int32_c_suffix */
+#endif /* __int_least32_t */
+
+#ifdef __INT24_TYPE__
+#undef __int16_c_suffix
+#undef __int8_c_suffix
+#ifdef __INT24_C_SUFFIX__
+#define INT24_C(v) __int_c(v, __INT24_C_SUFFIX__)
+#define UINT24_C(v) __uint_c(v, __INT24_C_SUFFIX__)
+#define __int16_c_suffix __INT24_C_SUFFIX__
+#define __int8_c_suffix __INT24_C_SUFFIX__
+#else
+#define INT24_C(v) v
+#define UINT24_C(v) v##U
+#endif /* __INT24_C_SUFFIX__ */
+#endif /* __INT24_TYPE__ */
+
+#ifdef __INT16_TYPE__
+#undef __int16_c_suffix
+#undef __int8_c_suffix
+#ifdef __INT16_C_SUFFIX__
+#define __int16_c_suffix __INT16_C_SUFFIX__
+#define __int8_c_suffix __INT16_C_SUFFIX__
+#endif /* __INT16_C_SUFFIX__ */
+#endif /* __INT16_TYPE__ */
+
+#ifdef __int_least16_t
+#ifdef __int16_c_suffix
+#define INT16_C(v) __int_c(v, __int16_c_suffix)
+#define UINT16_C(v) __uint_c(v, __int16_c_suffix)
+#else
+#define INT16_C(v) v
+#define UINT16_C(v) v##U
+#endif /* __int16_c_suffix */
+#endif /* __int_least16_t */
+
+#ifdef __INT8_TYPE__
+#undef __int8_c_suffix
+#ifdef __INT8_C_SUFFIX__
+#define __int8_c_suffix __INT8_C_SUFFIX__
+#endif /* __INT8_C_SUFFIX__ */
+#endif /* __INT8_TYPE__ */
+
+#ifdef __int_least8_t
+#ifdef __int8_c_suffix
+#define INT8_C(v) __int_c(v, __int8_c_suffix)
+#define UINT8_C(v) __uint_c(v, __int8_c_suffix)
+#else
+#define INT8_C(v) v
+#define UINT8_C(v) v##U
+#endif /* __int8_c_suffix */
+#endif /* __int_least8_t */
+
+/* C99 7.18.2.1 Limits of exact-width integer types.
+ * C99 7.18.2.2 Limits of minimum-width integer types.
+ * C99 7.18.2.3 Limits of fastest minimum-width integer types.
+ *
+ * The presence of limit macros are completely optional in C99.  This
+ * implementation defines limits for all of the types (exact- and
+ * minimum-width) that it defines above, using the limits of the minimum-width
+ * type for any types that do not have exact-width representations.
+ *
+ * As in the type definitions, this section takes an approach of
+ * successive-shrinking to determine which limits to use for the standard (8,
+ * 16, 32, 64) bit widths when they don't have exact representations. It is
+ * therefore important that the definitions be kept in order of decending
+ * widths.
+ *
+ * Note that C++ should not check __STDC_LIMIT_MACROS here, contrary to the
+ * claims of the C standard (see C++ 18.3.1p2, [cstdint.syn]).
+ */
+
+#ifdef __INT64_TYPE__
+#define INT64_MAX INT64_C(9223372036854775807)
+#define INT64_MIN (-INT64_C(9223372036854775807) - 1)
+#define UINT64_MAX UINT64_C(18446744073709551615)
+
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
+#define UINT64_WIDTH 64
+#define INT64_WIDTH UINT64_WIDTH
+
+#define __UINT_LEAST64_WIDTH UINT64_WIDTH
+#undef __UINT_LEAST32_WIDTH
+#define __UINT_LEAST32_WIDTH UINT64_WIDTH
+#undef __UINT_LEAST16_WIDTH
+#define __UINT_LEAST16_WIDTH UINT64_WIDTH
+#undef __UINT_LEAST8_MAX
+#define __UINT_LEAST8_MAX UINT64_MAX
+#endif /* __STDC_VERSION__ */
+
+#define __INT_LEAST64_MIN INT64_MIN
+#define __INT_LEAST64_MAX INT64_MAX
+#define __UINT_LEAST64_MAX UINT64_MAX
+#undef __INT_LEAST32_MIN
+#define __INT_LEAST32_MIN INT64_MIN
+#undef __INT_LEAST32_MAX
+#define __INT_LEAST32_MAX INT64_MAX
+#undef __UINT_LEAST32_MAX
+#define __UINT_LEAST32_MAX UINT64_MAX
+#undef __INT_LEAST16_MIN
+#define __INT_LEAST16_MIN INT64_MIN
+#undef __INT_LEAST16_MAX
+#define __INT_LEAST16_MAX INT64_MAX
+#undef __UINT_LEAST16_MAX
+#define __UINT_LEAST16_MAX UINT64_MAX
+#undef __INT_LEAST8_MIN
+#define __INT_LEAST8_MIN INT64_MIN
+#undef __INT_LEAST8_MAX
+#define __INT_LEAST8_MAX INT64_MAX
+#undef __UINT_LEAST8_MAX
+#define __UINT_LEAST8_MAX UINT64_MAX
+#endif /* __INT64_TYPE__ */
+
+#ifdef __INT_LEAST64_MIN
+#define INT_LEAST64_MIN __INT_LEAST64_MIN
+#define INT_LEAST64_MAX __INT_LEAST64_MAX
+#define UINT_LEAST64_MAX __UINT_LEAST64_MAX
+#define INT_FAST64_MIN __INT_LEAST64_MIN
+#define INT_FAST64_MAX __INT_LEAST64_MAX
+#define UINT_FAST64_MAX __UINT_LEAST64_MAX
+
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
+#define UINT_LEAST64_WIDTH __UINT_LEAST64_WIDTH
+#define INT_LEAST64_WIDTH UINT_LEAST64_WIDTH
+#define UINT_FAST64_WIDTH __UINT_LEAST64_WIDTH
+#define INT_FAST64_WIDTH UINT_FAST64_WIDTH
+#endif /* __STDC_VERSION__ */
+#endif /* __INT_LEAST64_MIN */
+
+#ifdef __INT56_TYPE__
+#define INT56_MAX INT56_C(36028797018963967)
+#define INT56_MIN (-INT56_C(36028797018963967) - 1)
+#define UINT56_MAX UINT56_C(72057594037927935)
+#define INT_LEAST56_MIN INT56_MIN
+#define INT_LEAST56_MAX INT56_MAX
+#define UINT_LEAST56_MAX UINT56_MAX
+#define INT_FAST56_MIN INT56_MIN
+#define INT_FAST56_MAX INT56_MAX
+#define UINT_FAST56_MAX UINT56_MAX
+
+#undef __INT_LEAST32_MIN
+#define __INT_LEAST32_MIN INT56_MIN
+#undef __INT_LEAST32_MAX
+#define __INT_LEAST32_MAX INT56_MAX
+#undef __UINT_LEAST32_MAX
+#define __UINT_LEAST32_MAX UINT56_MAX
+#undef __INT_LEAST16_MIN
+#define __INT_LEAST16_MIN INT56_MIN
+#undef __INT_LEAST16_MAX
+#define __INT_LEAST16_MAX INT56_MAX
+#undef __UINT_LEAST16_MAX
+#define __UINT_LEAST16_MAX UINT56_MAX
+#undef __INT_LEAST8_MIN
+#define __INT_LEAST8_MIN INT56_MIN
+#undef __INT_LEAST8_MAX
+#define __INT_LEAST8_MAX INT56_MAX
+#undef __UINT_LEAST8_MAX
+#define __UINT_LEAST8_MAX UINT56_MAX
+
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
+#define UINT56_WIDTH 56
+#define INT56_WIDTH UINT56_WIDTH
+#define UINT_LEAST56_WIDTH UINT56_WIDTH
+#define INT_LEAST56_WIDTH UINT_LEAST56_WIDTH
+#define UINT_FAST56_WIDTH UINT56_WIDTH
+#define INT_FAST56_WIDTH UINT_FAST56_WIDTH
+#undef __UINT_LEAST32_WIDTH
+#define __UINT_LEAST32_WIDTH UINT56_WIDTH
+#undef __UINT_LEAST16_WIDTH
+#define __UINT_LEAST16_WIDTH UINT56_WIDTH
+#undef __UINT_LEAST8_WIDTH
+#define __UINT_LEAST8_WIDTH UINT56_WIDTH
+#endif /* __STDC_VERSION__ */
+#endif /* __INT56_TYPE__ */
+
+#ifdef __INT48_TYPE__
+#define INT48_MAX INT48_C(140737488355327)
+#define INT48_MIN (-INT48_C(140737488355327) - 1)
+#define UINT48_MAX UINT48_C(281474976710655)
+#define INT_LEAST48_MIN INT48_MIN
+#define INT_LEAST48_MAX INT48_MAX
+#define UINT_LEAST48_MAX UINT48_MAX
+#define INT_FAST48_MIN INT48_MIN
+#define INT_FAST48_MAX INT48_MAX
+#define UINT_FAST48_MAX UINT48_MAX
+
+#undef __INT_LEAST32_MIN
+#define __INT_LEAST32_MIN INT48_MIN
+#undef __INT_LEAST32_MAX
+#define __INT_LEAST32_MAX INT48_MAX
+#undef __UINT_LEAST32_MAX
+#define __UINT_LEAST32_MAX UINT48_MAX
+#undef __INT_LEAST16_MIN
+#define __INT_LEAST16_MIN INT48_MIN
+#undef __INT_LEAST16_MAX
+#define __INT_LEAST16_MAX INT48_MAX
+#undef __UINT_LEAST16_MAX
+#define __UINT_LEAST16_MAX UINT48_MAX
+#undef __INT_LEAST8_MIN
+#define __INT_LEAST8_MIN INT48_MIN
+#undef __INT_LEAST8_MAX
+#define __INT_LEAST8_MAX INT48_MAX
+#undef __UINT_LEAST8_MAX
+#define __UINT_LEAST8_MAX UINT48_MAX
+
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
+#define UINT48_WIDTH 48
+#define INT48_WIDTH UINT48_WIDTH
+#define UINT_LEAST48_WIDTH UINT48_WIDTH
+#define INT_LEAST48_WIDTH UINT_LEAST48_WIDTH
+#define UINT_FAST48_WIDTH UINT48_WIDTH
+#define INT_FAST48_WIDTH UINT_FAST48_WIDTH
+#undef __UINT_LEAST32_WIDTH
+#define __UINT_LEAST32_WIDTH UINT48_WIDTH
+#undef __UINT_LEAST16_WIDTH
+#define __UINT_LEAST16_WIDTH UINT48_WIDTH
+#undef __UINT_LEAST8_WIDTH
+#define __UINT_LEAST8_WIDTH UINT48_WIDTH
+#endif /* __STDC_VERSION__ */
+#endif /* __INT48_TYPE__ */
+
+#ifdef __INT40_TYPE__
+#define INT40_MAX INT40_C(549755813887)
+#define INT40_MIN (-INT40_C(549755813887) - 1)
+#define UINT40_MAX UINT40_C(1099511627775)
+#define INT_LEAST40_MIN INT40_MIN
+#define INT_LEAST40_MAX INT40_MAX
+#define UINT_LEAST40_MAX UINT40_MAX
+#define INT_FAST40_MIN INT40_MIN
+#define INT_FAST40_MAX INT40_MAX
+#define UINT_FAST40_MAX UINT40_MAX
+
+#undef __INT_LEAST32_MIN
+#define __INT_LEAST32_MIN INT40_MIN
+#undef __INT_LEAST32_MAX
+#define __INT_LEAST32_MAX INT40_MAX
+#undef __UINT_LEAST32_MAX
+#define __UINT_LEAST32_MAX UINT40_MAX
+#undef __INT_LEAST16_MIN
+#define __INT_LEAST16_MIN INT40_MIN
+#undef __INT_LEAST16_MAX
+#define __INT_LEAST16_MAX INT40_MAX
+#undef __UINT_LEAST16_MAX
+#define __UINT_LEAST16_MAX UINT40_MAX
+#undef __INT_LEAST8_MIN
+#define __INT_LEAST8_MIN INT40_MIN
+#undef __INT_LEAST8_MAX
+#define __INT_LEAST8_MAX INT40_MAX
+#undef __UINT_LEAST8_MAX
+#defin...
[truncated]

@nickdesaulniers
Copy link
Member

We probably need to be careful with this change. I'm nervous if stdint.h from clang is 100% the same for different architectures?

I do worry about #include_next as I highly suspect it's behavior is non-deterministic in the face of -I (or perhaps -isystem) flags.

If we did do this change, I think we could+should replace our #include <stdint.h> with including our stdint.h.

$ grep -rn '<stdint' libc | wc -l
208

@jhuber6
Copy link
Contributor Author

jhuber6 commented Feb 28, 2024

We probably need to be careful with this change. I'm nervous if stdint.h from clang is 100% the same for different architectures?

This is the same handling clang uses for all its targets, if you do -ffreestanding on your target you'll get this implementation so it's expected to work for all architectures clang supports I'd say.

I do worry about #include_next as I highly suspect it's behavior is non-deterministic in the face of -I (or perhaps -isystem) flags.

This does not use the include_next part, that's handled in clang.

If we did do this change, I think we could+should replace our #include <stdint.h> with including our stdint.h.

$ grep -rn '<stdint' libc | wc -l
208

If we replaced this it would have equivalent behavior to compiling with clang -ffreestanding.

@jhuber6
Copy link
Contributor Author

jhuber6 commented Feb 28, 2024

Also it would probably pick this up by default because we -I/libc/install in the output directory.

@lntue
Copy link
Contributor

lntue commented Feb 28, 2024

We probably need to be careful with this change. I'm nervous if stdint.h from clang is 100% the same for different architectures?

This is the same handling clang uses for all its targets, if you do -ffreestanding on your target you'll get this implementation so it's expected to work for all architectures clang supports I'd say.

I do worry about #include_next as I highly suspect it's behavior is non-deterministic in the face of -I (or perhaps -isystem) flags.

This does not use the include_next part, that's handled in clang.

If we did do this change, I think we could+should replace our #include <stdint.h> with including our stdint.h.

$ grep -rn '<stdint' libc | wc -l
208

If we replaced this it would have equivalent behavior to compiling with clang -ffreestanding.

For those completely independent headers like this, it would be actually easier to provide our own complete freestanding headers. It might actually be easier to add support for other platforms when we can control these ourselves.

On the other hands, now we also have uint24_t, uint48_t, uint56_t, but still not uint128_t [[sad face]].

@lntue
Copy link
Contributor

lntue commented Feb 28, 2024

We probably need to be careful with this change. I'm nervous if stdint.h from clang is 100% the same for different architectures?

I do worry about #include_next as I highly suspect it's behavior is non-deterministic in the face of -I (or perhaps -isystem) flags.

If we did do this change, I think we could+should replace our #include <stdint.h> with including our stdint.h.

$ grep -rn '<stdint' libc | wc -l
208

+1 on use our own copy. If there are mismatches on some platform, it's better to fail on that platform, then we are informed and update our headers to match it.

@jhuber6
Copy link
Contributor Author

jhuber6 commented Feb 29, 2024

+1 on use our own copy. If there are mismatches on some platform, it's better to fail on that platform, then we are informed and update our headers to match it.

Yeah, I think this is straightforward enough since we already use the clang -ffreestanding version, so this functionally has no change if we go with this.

@gchatelet
Copy link
Contributor

Can you update utils/bazel/llvm-project-overlay/libc/BUILD.bazel as well?

Like it was done for: float-macros.h

libc_support_library(
name = "llvm_libc_macros_float_macros",
hdrs = ["include/llvm-libc-macros/float-macros.h"],
)

@jhuber6
Copy link
Contributor Author

jhuber6 commented Feb 29, 2024

Can you update utils/bazel/llvm-project-overlay/libc/BUILD.bazel as well?

Like it was done for: float-macros.h

libc_support_library(
name = "llvm_libc_macros_float_macros",
hdrs = ["include/llvm-libc-macros/float-macros.h"],
)

done.

Copy link
Contributor

@gchatelet gchatelet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM on my side but wait for other reviewers before landing.

@nickdesaulniers
Copy link
Member

To be clear, I am in favor of this. I just have a sinking fear of "what could go wrong?" that is perhaps just being overly cautious. I don't have anything specific in mind as an answer.

If we did do this change, I think we could+should replace our #include <stdint.h> with including our stdint.h.

$ grep -rn '<stdint' libc | wc -l
208

If we replaced this it would have equivalent behavior to compiling with clang -ffreestanding.

-ffreestanding is more than just <stdint.h>; llvm will elide libcall optimizations.

My point was more so that I think we should match

72ce629

where we had too many issues from using <limits.h> and instead now provide our own and use that everywhere. I think we should do exactly that, but for <stdint.h>, for the same reasons.

I'm also trying to fix all of the lint warnings (#65694) where we do warn about including system headers (such as <stdint.h>). I'd prefer to try to curtail these kind of inclusions to one place (when necessary) (or omit entirely when we have our own impl) so that we can throw NOLINT on the single includes then consistently use our wrappers.

Also, looking at 72ce629, I wonder if this PR should be updating libc/spec/stdc.td in a similar manner?

I do worry about #include_next as I highly suspect it's behavior is non-deterministic in the face of -I (or perhaps -isystem) flags.
This does not use the include_next part, that's handled in clang.

Right, which is why I'm in favor of providing our own. I was implying that I don't like the alternative.

Also it would probably pick this up by default because we -I/libc/install in the output directory.

What we do with our build flags won't affect what happens when users consume our headers. They won't be adding -I /libc/install for instance.

@jhuber6
Copy link
Contributor Author

jhuber6 commented Feb 29, 2024

-ffreestanding is more than just <stdint.h>; llvm will elide libcall optimizations.

I mostly meant this quite literally, if you include clang/lib/Headers/stdint.h without __STDC_HOSTED__ set, you will literally get the header I have copied here. This is the behavior when compiling with -ffreestanding for this header, which means that there is no behavioral change at least for clang.

Also, looking at 72ce629, I wonder if this PR should be updating libc/spec/stdc.td in a similar manner?

Yeah, likely should be added. My original intention was to provide this in the install without using it internally. I personally don't think there is a large benefit to using it internally because stdint.h is pretty well defined with -ffreestanding enabled like we use now.

Summary:
I've noticed one problem is that the user includes `stdint.h` the
compiler will do `#include_next <stdint.h>` potentially into a
conflicting implementation on systems with multiple headers installed.
The `clang` header is standards compliant and works with `clang` and
`gcc` which are both of our targets, so I simply copied it here. This
has the effect of including `stdint.h` on clang / LLVM libc behaving the
same as `-ffreestanding`.
@jhuber6
Copy link
Contributor Author

jhuber6 commented Mar 4, 2024

For clarification, this patch implements a stdint.h that will be installed. This is useful because stdint.h is expected to be able to be usable from the C library but we previously didn't provide one. I used the clang implementation as it's correct to the standard and GCC compatible. I think in a separate patch we could move #include <stdint.h> to include this header instead. Though personally I don't think it will change much because it's stdint.h is defined by the standard to be freestanding.

Copy link
Member

@nickdesaulniers nickdesaulniers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixing #65694 requires that we do something about including system headers (such as <stdint.h>).

@jhuber6 jhuber6 merged commit c996023 into llvm:main Mar 4, 2024
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants