diff options
Diffstat (limited to 'rcc/include')
| -rw-r--r-- | rcc/include/rcc/ADT/STLFunctionalExtras.h | 112 | ||||
| -rw-r--r-- | rcc/include/rcc/Config/config.h.cmake | 291 | ||||
| -rw-r--r-- | rcc/include/rcc/Config/rcc-config.h.cmake | 158 | ||||
| -rw-r--r-- | rcc/include/rcc/DataTypes.h | 105 | ||||
| -rw-r--r-- | rcc/include/rcc/Support/Compiler.h | 853 | ||||
| -rw-r--r-- | rcc/include/rcc/Support/Errno.h | 64 | ||||
| -rw-r--r-- | rcc/include/rcc/Support/ErrorOr.h | 378 | ||||
| -rw-r--r-- | rcc/include/rcc/Support/MathExtras.h | 1050 |
8 files changed, 3011 insertions, 0 deletions
diff --git a/rcc/include/rcc/ADT/STLFunctionalExtras.h b/rcc/include/rcc/ADT/STLFunctionalExtras.h new file mode 100644 index 0000000..71a5b85 --- /dev/null +++ b/rcc/include/rcc/ADT/STLFunctionalExtras.h @@ -0,0 +1,112 @@ +/* + R *CC-Project + + Copyright (C) 2026 Richard Qin + + This file is part of RCC-Project. + + RCC-Project is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your option) any + later version. + + RCC-Project is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + RCC-Project; see the file COPYING. If not see + <http://www.gnu.org/licenses/>. + */ + +//===- llvm/ADT/STLFunctionalExtras.h - Extras for <functional> -*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file contains some extension to <functional>. +// +// No library is required when using these functions. +// +//===----------------------------------------------------------------------===// + +#ifndef RCC_ADT_STLFUNCTIONALEXTRAS_H +#define RCC_ADT_STLFUNCTIONALEXTRAS_H + +#include "rcc/Support/Compiler.h" + +#include <cstddef +#include <cstdint> +#include <type_traits> +#include <utility> + +namespace rcc +{ + +//===----------------------------------------------------------------------===// +// Extra additions to <functional> +//===----------------------------------------------------------------------===// + +/// An efficient, type-erasing, non-owning reference to a callable. This is +/// intended for use as the type of a function parameter that is not used +/// after the function in question returns. +/// +/// This class does not own the callable, so it is not in general safe to store +/// a function_ref. +template <typename Fn> class function_ref; + +template <typename Ret, typename... Params> +class RCC_GSL_POINTER function_ref<Ret (Params...)> +{ + Ret (*callback) (intptr_t callable, Params... params) = nullptr; + intptr_t callable = 0; + + template <typename Callable> + static Ret + callback_fn (intptr_t callable, Params... params) + { + return (*reinterpret_cast<Callable *> (callable)) ( + std::forward<Params> (params)...); + } + +public: + function_ref () = default; + function_ref (std::nullptr_t) + { + } + + template <typename Callable> + function_ref ( + Callable &&callable RCC_LIFETIME_BOUND, + // This is not the copy-constructor. + std::enable_if_t<!std::is_same<std::remove_cvref_t<Callable>, + function_ref>::value> * = nullptr, + // Functor must be callable and return a suitable type. + std::enable_if_t<std::is_void<Ret>::value || + std::is_convertible<decltype (std::declval<Callable> () ( + std::declval<Params> ()...)), + Ret>::value> * = nullptr) + : callback (callback_fn<std::remove_reference_t<Callable>>), + callable (reinterpret_cast<intptr_t> (&callable)) + { + } + + Ret + operator() (Params... params) const + { + return callback (callable, std::forward<Params> (params)...); + } + + explicit + operator bool () const + { + return callback; + } +}; + +} // end namespace rcc + +#endif // RCC_ADT_STLFUNCTIONALEXTRAS_H diff --git a/rcc/include/rcc/Config/config.h.cmake b/rcc/include/rcc/Config/config.h.cmake new file mode 100644 index 0000000..32761c1 --- /dev/null +++ b/rcc/include/rcc/Config/config.h.cmake @@ -0,0 +1,291 @@ +#ifndef CONFIG_H +#define CONFIG_H + +// Include this header only under the rcc source tree. +// This is a private header. + +/* Exported configuration */ +#include "rcc/Config/rcc-config.h" + +/* Bug report URL. */ +#define BUG_REPORT_URL "${BUG_REPORT_URL}" + +/* Define to 1 to enable backtraces, and to 0 otherwise. */ +#cmakedefine01 ENABLE_BACKTRACES + +/* Define to 1 to enable crash overrides, and to 0 otherwise. */ +#cmakedefine01 ENABLE_CRASH_OVERRIDES + +/* Define to 1 to enable crash memory dumps, and to 0 otherwise. */ +#cmakedefine01 RCC_ENABLE_CRASH_DUMPS + +/* Define to 1 to prefer forward slashes on Windows, and to 0 prefer + backslashes. */ +#cmakedefine01 RCC_WINDOWS_PREFER_FORWARD_SLASH + +/* Define to 1 if you have the `backtrace' function. */ +#cmakedefine HAVE_BACKTRACE ${HAVE_BACKTRACE} + +#define BACKTRACE_HEADER <${BACKTRACE_HEADER}> + +/* can use __crashreporter_info__ */ +#cmakedefine01 HAVE_CRASHREPORTER_INFO + +/* Define to 1 if you have the declaration of `arc4random', and to 0 if you + don't. */ +#cmakedefine01 HAVE_DECL_ARC4RANDOM + +/* Define to 1 if you have the declaration of `strerror_s', and to 0 if you + don't. */ +#cmakedefine01 HAVE_DECL_STRERROR_S + +/* Define if dlopen() is available on this platform. */ +#cmakedefine HAVE_DLOPEN ${HAVE_DLOPEN} + +/* Define to 1 if we can register EH frames on this platform. */ +#cmakedefine HAVE_REGISTER_FRAME ${HAVE_REGISTER_FRAME} + +/* Define to 1 if we can deregister EH frames on this platform. */ +#cmakedefine HAVE_DEREGISTER_FRAME ${HAVE_DEREGISTER_FRAME} + +/* Define if __unw_add_dynamic_fde() is available on this platform. */ +#cmakedefine HAVE_UNW_ADD_DYNAMIC_FDE ${HAVE_UNW_ADD_DYNAMIC_FDE} + +/* Define if libffi is available on this platform. */ +#cmakedefine HAVE_FFI_CALL ${HAVE_FFI_CALL} + +/* Define to 1 if you have the <ffi/ffi.h> header file. */ +#cmakedefine HAVE_FFI_FFI_H ${HAVE_FFI_FFI_H} + +/* Define to 1 if you have the <ffi.h> header file. */ +#cmakedefine HAVE_FFI_H ${HAVE_FFI_H} + +/* Define to 1 if you have the `futimens' function. */ +#cmakedefine HAVE_FUTIMENS ${HAVE_FUTIMENS} + +/* Define to 1 if you have the `futimes' function. */ +#cmakedefine HAVE_FUTIMES ${HAVE_FUTIMES} + +/* Define to 1 if you have the `getpagesize' function. */ +#cmakedefine HAVE_GETPAGESIZE ${HAVE_GETPAGESIZE} + +/* Define to 1 if you have the `getrusage' function. */ +#cmakedefine HAVE_GETRUSAGE ${HAVE_GETRUSAGE} + +/* Define to 1 if you have the `isatty' function. */ +#cmakedefine HAVE_ISATTY 1 + +/* Define to 1 if you have the `edit' library (-ledit). */ +#cmakedefine HAVE_LIBEDIT ${HAVE_LIBEDIT} + +/* Define to 1 if you have the `pfm' library (-lpfm). */ +#cmakedefine HAVE_LIBPFM ${HAVE_LIBPFM} + +/* Define to 1 if the `perf_branch_entry' struct has field cycles. */ +#cmakedefine LIBPFM_HAS_FIELD_CYCLES ${LIBPFM_HAS_FIELD_CYCLES} + +/* Define to 1 if you have the `psapi' library (-lpsapi). */ +#cmakedefine HAVE_LIBPSAPI ${HAVE_LIBPSAPI} + +/* Define to 1 if you have the `pthread' library (-lpthread). */ +#cmakedefine HAVE_LIBPTHREAD ${HAVE_LIBPTHREAD} + +/* Define to 1 if you have the `pthread_getname_np' function. */ +#cmakedefine HAVE_PTHREAD_GETNAME_NP ${HAVE_PTHREAD_GETNAME_NP} + +/* Define to 1 if you have the `pthread_setname_np' function. */ +#cmakedefine HAVE_PTHREAD_SETNAME_NP ${HAVE_PTHREAD_SETNAME_NP} + +/* Define to 1 if you have the `pthread_get_name_np' function. */ +#cmakedefine HAVE_PTHREAD_GET_NAME_NP ${HAVE_PTHREAD_GET_NAME_NP} + +/* Define to 1 if you have the `pthread_set_name_np' function. */ +#cmakedefine HAVE_PTHREAD_SET_NAME_NP ${HAVE_PTHREAD_SET_NAME_NP} + +/* Define to 1 if you have the <mach/mach.h> header file. */ +#cmakedefine HAVE_MACH_MACH_H ${HAVE_MACH_MACH_H} + +/* Define to 1 if you have the `mallctl' function. */ +#cmakedefine HAVE_MALLCTL ${HAVE_MALLCTL} + +/* Define to 1 if you have the `mallinfo' function. */ +#cmakedefine HAVE_MALLINFO ${HAVE_MALLINFO} + +/* Define to 1 if you have the `mallinfo2' function. */ +#cmakedefine HAVE_MALLINFO2 ${HAVE_MALLINFO2} + +/* Define to 1 if you have the <malloc/malloc.h> header file. */ +#cmakedefine HAVE_MALLOC_MALLOC_H ${HAVE_MALLOC_MALLOC_H} + +/* Define to 1 if you have the `malloc_zone_statistics' function. */ +#cmakedefine HAVE_MALLOC_ZONE_STATISTICS ${HAVE_MALLOC_ZONE_STATISTICS} + +/* Define to 1 if you have the `posix_spawn' function. */ +#cmakedefine HAVE_POSIX_SPAWN ${HAVE_POSIX_SPAWN} + +/* Define to 1 if you have the `pread' function. */ +#cmakedefine HAVE_PREAD ${HAVE_PREAD} + +/* Define to 1 if you have the <pthread.h> header file. */ +#cmakedefine HAVE_PTHREAD_H ${HAVE_PTHREAD_H} + +/* Have pthread_rwlock_init */ +#cmakedefine HAVE_PTHREAD_RWLOCK_INIT ${HAVE_PTHREAD_RWLOCK_INIT} + +/* Define to 1 if you have the `sbrk' function. */ +#cmakedefine HAVE_SBRK ${HAVE_SBRK} + +/* Define to 1 if you have the `setenv' function. */ +#cmakedefine HAVE_SETENV ${HAVE_SETENV} + +/* Define to 1 if you have the `sigaltstack' function. */ +#cmakedefine HAVE_SIGALTSTACK ${HAVE_SIGALTSTACK} + +/* Define to 1 if you have the `strerror_r' function. */ +#cmakedefine HAVE_STRERROR_R ${HAVE_STRERROR_R} + +/* Define to 1 if you have the `sysconf' function. */ +#cmakedefine HAVE_SYSCONF ${HAVE_SYSCONF} + +/* Define to 1 if you have the <sys/mman.h> header file. */ +#cmakedefine HAVE_SYS_MMAN_H ${HAVE_SYS_MMAN_H} + +/* Define to 1 if you have the <sys/ioctl.h> header file. */ +#cmakedefine HAVE_SYS_IOCTL_H ${HAVE_SYS_IOCTL_H} + +/* Define to 1 if stat struct has st_mtimespec member .*/ +#cmakedefine HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC ${HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC} + +/* Define to 1 if stat struct has st_mtim member. */ +#cmakedefine HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC ${HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC} + +/* Define to 1 if you have the <unistd.h> header file. */ +#cmakedefine HAVE_UNISTD_H ${HAVE_UNISTD_H} + +/* Have host's _alloca */ +#cmakedefine HAVE__ALLOCA ${HAVE__ALLOCA} + +/* Define to 1 if you have the `_chsize_s' function. */ +#cmakedefine HAVE__CHSIZE_S ${HAVE__CHSIZE_S} + +/* Define to 1 if you have the `_Unwind_Backtrace' function. */ +#cmakedefine HAVE__UNWIND_BACKTRACE ${HAVE__UNWIND_BACKTRACE} + +/* Have host's __alloca */ +#cmakedefine HAVE___ALLOCA ${HAVE___ALLOCA} + +/* Have host's __ashldi3 */ +#cmakedefine HAVE___ASHLDI3 ${HAVE___ASHLDI3} + +/* Have host's __ashrdi3 */ +#cmakedefine HAVE___ASHRDI3 ${HAVE___ASHRDI3} + +/* Have host's __chkstk */ +#cmakedefine HAVE___CHKSTK ${HAVE___CHKSTK} + +/* Have host's __chkstk_ms */ +#cmakedefine HAVE___CHKSTK_MS ${HAVE___CHKSTK_MS} + +/* Have host's __cmpdi2 */ +#cmakedefine HAVE___CMPDI2 ${HAVE___CMPDI2} + +/* Have host's __divdi3 */ +#cmakedefine HAVE___DIVDI3 ${HAVE___DIVDI3} + +/* Have host's __fixdfdi */ +#cmakedefine HAVE___FIXDFDI ${HAVE___FIXDFDI} + +/* Have host's __fixsfdi */ +#cmakedefine HAVE___FIXSFDI ${HAVE___FIXSFDI} + +/* Have host's __floatdidf */ +#cmakedefine HAVE___FLOATDIDF ${HAVE___FLOATDIDF} + +/* Have host's __lshrdi3 */ +#cmakedefine HAVE___LSHRDI3 ${HAVE___LSHRDI3} + +/* Have host's __main */ +#cmakedefine HAVE___MAIN ${HAVE___MAIN} + +/* Have host's __moddi3 */ +#cmakedefine HAVE___MODDI3 ${HAVE___MODDI3} + +/* Have host's __udivdi3 */ +#cmakedefine HAVE___UDIVDI3 ${HAVE___UDIVDI3} + +/* Have host's __umoddi3 */ +#cmakedefine HAVE___UMODDI3 ${HAVE___UMODDI3} + +/* Have host's ___chkstk */ +#cmakedefine HAVE____CHKSTK ${HAVE____CHKSTK} + +/* Have host's ___chkstk_ms */ +#cmakedefine HAVE____CHKSTK_MS ${HAVE____CHKSTK_MS} + +/* Define if ICU library is available */ +#cmakedefine01 HAVE_ICU + +/* Define if Windows vendored ICU is available */ +#cmakedefine01 HAVE_WINDOWS_ICU + +/* Define if iconv library is available */ +#cmakedefine01 HAVE_ICONV + +/* Linker version detected at compile time. */ +#cmakedefine HOST_LINK_VERSION "${HOST_LINK_VERSION}" + +/* Define if overriding target triple is enabled */ +#cmakedefine RCC_TARGET_TRIPLE_ENV "${RCC_TARGET_TRIPLE_ENV}" + +/* Whether tools show host and target info when invoked with --version */ +#cmakedefine01 RCC_VERSION_PRINTER_SHOW_HOST_TARGET_INFO + +/* Whether tools show optional build config flags when invoked with --version */ +#cmakedefine01 RCC_VERSION_PRINTER_SHOW_BUILD_CONFIG + +/* Define if libxml2 is supported on this platform. */ +#cmakedefine RCC_ENABLE_LIBXML2 ${RCC_ENABLE_LIBXML2} + +/* Define to the extension used for shared libraries, say, ".so". */ +#cmakedefine LTDL_SHLIB_EXT "${LTDL_SHLIB_EXT}" + +/* Define to the extension used for plugin libraries, say, ".so". */ +#cmakedefine RCC_PLUGIN_EXT "${RCC_PLUGIN_EXT}" + +/* Define to the address where bug reports for this package should be sent. */ +#cmakedefine PACKAGE_BUGREPORT "${PACKAGE_BUGREPORT}" + +/* Define to the full name of this package. */ +#cmakedefine PACKAGE_NAME "${PACKAGE_NAME}" + +/* Define to the full name and version of this package. */ +#cmakedefine PACKAGE_STRING "${PACKAGE_STRING}" + +/* Define to the version of this package. */ +#cmakedefine PACKAGE_VERSION "${PACKAGE_VERSION}" + +/* Define to the vendor of this package. */ +#cmakedefine PACKAGE_VENDOR "${PACKAGE_VENDOR}" + +/* Define to a function implementing stricmp */ +#cmakedefine stricmp ${stricmp} + +/* Define to a function implementing strdup */ +#cmakedefine strdup ${strdup} + +/* Whether GlobalISel rule coverage is being collected */ +#cmakedefine01 RCC_GISEL_COV_ENABLED + +/* Define to the default GlobalISel coverage file prefix */ +#cmakedefine RCC_GISEL_COV_PREFIX "${RCC_GISEL_COV_PREFIX}" + +/* Whether Timers signpost passes in Xcode Instruments */ +#cmakedefine01 RCC_SUPPORT_XCODE_SIGNPOSTS + +#cmakedefine HAVE_PROC_PID_RUSAGE 1 + +#cmakedefine HAVE_BUILTIN_THREAD_POINTER ${HAVE_BUILTIN_THREAD_POINTER} + +#cmakedefine HAVE_GETAUXVAL ${HAVE_GETAUXVAL} + +#endif diff --git a/rcc/include/rcc/Config/rcc-config.h.cmake b/rcc/include/rcc/Config/rcc-config.h.cmake new file mode 100644 index 0000000..9c0ba18 --- /dev/null +++ b/rcc/include/rcc/Config/rcc-config.h.cmake @@ -0,0 +1,158 @@ +/*===------- rcc/Config/rcc-config.h - RCC configuration -------*- 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 */ +/* */ +/*===----------------------------------------------------------------------===*/ + +/* This file enumerates variables from the RCC configuration so that they + can be in exported headers and won't override package specific directives. + This is a C header that can be included in the RCC C headers. */ + +#ifndef RCC_CONFIG_H +#define RCC_CONFIG_H + +/* Define if RCC_ENABLE_DUMP is enabled */ +#cmakedefine RCC_ENABLE_DUMP + +/* Target triple RCC will generate code for by default */ +/* Doesn't use `cmakedefine` because it is allowed to be empty. */ +#define RCC_DEFAULT_TARGET_TRIPLE "${RCC_DEFAULT_TARGET_TRIPLE}" + +/* Define if threads enabled */ +#cmakedefine01 RCC_ENABLE_THREADS + +/* Has gcc/MSVC atomic intrinsics */ +#cmakedefine01 RCC_HAS_ATOMICS + +/* Host triple RCC will be executed on */ +#cmakedefine RCC_HOST_TRIPLE "${RCC_HOST_TRIPLE}" + +/* RCC architecture name for the native architecture, if available */ +#cmakedefine RCC_NATIVE_ARCH ${RCC_NATIVE_ARCH} + +/* RCC name for the native AsmParser init function, if available */ +#cmakedefine RCC_NATIVE_ASMPARSER RCCInitialize${RCC_NATIVE_ARCH}AsmParser + +/* RCC name for the native AsmPrinter init function, if available */ +#cmakedefine RCC_NATIVE_ASMPRINTER RCCInitialize${RCC_NATIVE_ARCH}AsmPrinter + +/* RCC name for the native Disassembler init function, if available */ +#cmakedefine RCC_NATIVE_DISASSEMBLER RCCInitialize${RCC_NATIVE_ARCH}Disassembler + +/* RCC name for the native Target init function, if available */ +#cmakedefine RCC_NATIVE_TARGET RCCInitialize${RCC_NATIVE_ARCH}Target + +/* RCC name for the native TargetInfo init function, if available */ +#cmakedefine RCC_NATIVE_TARGETINFO RCCInitialize${RCC_NATIVE_ARCH}TargetInfo + +/* RCC name for the native target MC init function, if available */ +#cmakedefine RCC_NATIVE_TARGETMC RCCInitialize${RCC_NATIVE_ARCH}TargetMC + +/* RCC name for the native target MCA init function, if available */ +#cmakedefine RCC_NATIVE_TARGETMCA RCCInitialize${RCC_NATIVE_ARCH}TargetMCA + +/* Define if this is Unixish platform */ +#cmakedefine RCC_ON_UNIX ${RCC_ON_UNIX} + +/* Define if we have the Intel JIT API runtime support library */ +#cmakedefine01 RCC_USE_INTEL_JITEVENTS + +/* Define if we have the oprofile JIT-support library */ +#cmakedefine01 RCC_USE_OPROFILE + +/* Define if we have the perf JIT-support library */ +#cmakedefine01 RCC_USE_PERF + +/* Major version of the RCC API */ +#define RCC_VERSION_MAJOR ${RCC_VERSION_MAJOR} + +/* Minor version of the RCC API */ +#define RCC_VERSION_MINOR ${RCC_VERSION_MINOR} + +/* Patch version of the RCC API */ +#define RCC_VERSION_PATCH ${RCC_VERSION_PATCH} + +/* RCC version string */ +#define RCC_VERSION_STRING "${PACKAGE_VERSION}" + +/* Whether RCC records statistics for use with GetStatistics(), + * PrintStatistics() or PrintStatisticsJSON() + */ +#cmakedefine01 RCC_FORCE_ENABLE_STATS + +/* Define if we have z3 and want to build it */ +#cmakedefine RCC_WITH_Z3 ${RCC_WITH_Z3} + +/* Define if we have curl and want to use it */ +#cmakedefine RCC_ENABLE_CURL ${RCC_ENABLE_CURL} + +/* Define if we have cpp-httplib and want to use it */ +#cmakedefine RCC_ENABLE_HTTPLIB ${RCC_ENABLE_HTTPLIB} + +/* Define if zlib compression is available */ +#cmakedefine01 RCC_ENABLE_ZLIB + +/* Define if zstd compression is available */ +#cmakedefine01 RCC_ENABLE_ZSTD + +/* Define if xz (lzma) decompression is available */ +#cmakedefine01 RCC_ENABLE_LZMA + +/* Define if RCC is using tflite */ +#cmakedefine RCC_HAVE_TFLITE + +/* Define if we want to check profile consistency in lit tests */ +#cmakedefine RCC_ENABLE_PROFCHECK + +/* Define to 1 if you have the <sysexits.h> header file. */ +#cmakedefine HAVE_SYSEXITS_H ${HAVE_SYSEXITS_H} + +/* Define if building libRCC shared library */ +#cmakedefine RCC_BUILD_RCC_DYLIB + +/* Define if building RCC with BUILD_SHARED_LIBS */ +#cmakedefine RCC_BUILD_SHARED_LIBS + +/* Define if exporting RCC public interface for shared library */ +#cmakedefine RCC_ENABLE_RCC_EXPORT_ANNOTATIONS + +/* Define if exporting RCC-C public interface for shared library */ +#cmakedefine RCC_ENABLE_RCC_C_EXPORT_ANNOTATIONS + +/* Define if building RCC with RCC_FORCE_USE_OLD_TOOLCHAIN_LIBS */ +#cmakedefine RCC_FORCE_USE_OLD_TOOLCHAIN ${RCC_FORCE_USE_OLD_TOOLCHAIN} + +/* Define if rcc_unreachable should be optimized with undefined behavior + * in non assert builds */ +#cmakedefine01 RCC_UNREACHABLE_OPTIMIZE + +/* Define if building RCC with RCC_ENABLE_IO_SANDBOX */ +#cmakedefine01 RCC_ENABLE_IO_SANDBOX + +/* Define to 1 if you have the DIA SDK installed, and to 0 if you don't. */ +#cmakedefine01 RCC_ENABLE_DIA_SDK + +/* Define if plugins enabled */ +#cmakedefine RCC_ENABLE_PLUGINS + +/* Define if logf128 is available */ +#cmakedefine RCC_HAS_LOGF128 + +/* Define if building RCC with RCC_ENABLE_TELEMETRY */ +#cmakedefine01 RCC_ENABLE_TELEMETRY + +/* Define to 1 to enable expensive checks for debug location coverage checking, + and to 0 otherwise. */ +#cmakedefine01 RCC_ENABLE_DEBUGLOC_TRACKING_COVERAGE + +/* Define to 1 to enable expensive tracking of the origin of debug location + coverage bugs, and to 0 otherwise. */ +#cmakedefine01 RCC_ENABLE_DEBUGLOC_TRACKING_ORIGIN + +/* Define to 1 to enable RCC OnDisk Content Addressable Storage */ +#cmakedefine01 RCC_ENABLE_ONDISK_CAS + +#endif diff --git a/rcc/include/rcc/DataTypes.h b/rcc/include/rcc/DataTypes.h new file mode 100644 index 0000000..59e9b75 --- /dev/null +++ b/rcc/include/rcc/DataTypes.h @@ -0,0 +1,105 @@ +/* + RCC-Project + + Copyright (C) 2026 Richard Qin + + This file is part of RCC-Project. + + RCC-Project is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 3, or (at your option) any later + version. + + RCC-Project is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + +You should have received a copy of the GNU General Public License +along with RCC-Project; see the file COPYING. If not see +<http://www.gnu.org/licenses/>. +*/ + +// This implementation is based on include/llvm-c/DataTypes.h +/*===-- include/llvm-c/DataTypes.h - Define fixed size types ------*- 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 *| + |* *| + |*===----------------------------------------------------------------------===*| + |* *| + |* This file contains definitions to figure out the size of _HOST_ data + types.*| + |* This file is important because different host OS's define different + macros,*| + |* which makes portability tough. This file exports the following *| + |* definitions: *| + |* *| + |* [u]int(32|64)_t : typedefs for signed and unsigned 32/64 bit system + types*| + |* [U]INT(8|16|32|64)_(MIN|MAX) : Constants for the min and max values. *| + |* *| + |* No library is required when using these functions. *| + |* *| + |*===----------------------------------------------------------------------===*/ + +/* Please leave this file C-compatible. */ +#ifndef RCC_DATATYPES_H +#define RCC_DATATYPES_H + +#include <inttypes.h> +#include <stdint.h> + +#ifndef _MSC_VER + +#if !defined(UINT32_MAX) +#error "The standard header <cstdint> is not C++11 compliant. Must #define "\ + "__STDC_LIMIT_MACROS before #including llvm-c/DataTypes.h" +#endif + +#if !defined(UINT32_C) +#error "The standard header <cstdint> is not C++11 compliant. Must #define "\ + "__STDC_CONSTANT_MACROS before #including llvm-c/DataTypes.h" +#endif + +/* Note that <inttypes.h> includes <stdint.h>, if this is a C99 system. */ +#include <sys/types.h> + +#ifdef _AIX +// GCC is strict about defining large constants: they must have LL modifier. +#undef INT64_MAX +#undef INT64_MIN +#endif + +#else /* _MSC_VER */ +#ifdef __cplusplus +#include <cstddef> +#include <cstdlib> +#else +#include <stddef.h> +#include <stdlib.h> +#endif +#include <sys/types.h> + +#if defined(_WIN64) +typedef signed __int64 ssize_t; +#else +typedef signed int ssize_t; +#endif /* _WIN64 */ + +#endif /* _MSC_VER */ + +/* Set defaults for constants which we cannot find. */ +#if !defined(INT64_MAX) +#define INT64_MAX 9223372036854775807LL +#endif +#if !defined(INT64_MIN) +#define INT64_MIN ((-INT64_MAX) - 1) +#endif +#if !defined(UINT64_MAX) +#define UINT64_MAX 0xffffffffffffffffULL +#endif + +#endif diff --git a/rcc/include/rcc/Support/Compiler.h b/rcc/include/rcc/Support/Compiler.h new file mode 100644 index 0000000..511c4cd --- /dev/null +++ b/rcc/include/rcc/Support/Compiler.h @@ -0,0 +1,853 @@ +/* + RCC-Project + + Copyright (C) 2026 Richard Qin + + This file is part of RCC-Project. + + RCC-Project is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your option) any + later version. + + RCC-Project is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + RCC-Project; see the file COPYING. If not see + <http://www.gnu.org/licenses/>. +*/ + +//===-- llvm/Support/Compiler.h - Compiler abstraction support --*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines several macros, based on the current compiler. This allows +// use of compiler-specific features in a way that remains portable. This header +// can be included from either C or C++. +// +//===----------------------------------------------------------------------===// + +#ifndef RCC_SUPPORT_COMPILER_H +#define RCC_SUPPORT_COMPILER_H + +#include "rcc/Config/rcc-config.h" + +#include <stddef.h> + +#if defined(_MSC_VER) +#include <sal.h> +#endif + +#ifndef __has_feature +#define __has_feature(x) 0 +#endif + +#ifndef __has_extension +#define __has_extension(x) 0 +#endif + +#ifndef __has_attribute +#define __has_attribute(x) 0 +#endif + +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif + +#ifndef __has_warning +#define __has_warning(x) 0 +#endif + +// Only use __has_cpp_attribute in C++ mode. GCC defines __has_cpp_attribute in +// C mode, but the :: in __has_cpp_attribute(scoped::attribute) is invalid. +#ifndef RCC_HAS_CPP_ATTRIBUTE +#if defined(__cplusplus) && defined(__has_cpp_attribute) +#define RCC_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute (x) +#else +#define RCC_HAS_CPP_ATTRIBUTE(x) 0 +#endif +#endif + +/// \macro RCC_GNUC_PREREQ +/// Extend the default __GNUC_PREREQ even if glibc's features.h isn't +/// available. +#ifndef RCC_GNUC_PREREQ +#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) +#define RCC_GNUC_PREREQ(maj, min, patch) \ + ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) + __GNUC_PATCHLEVEL__ >= \ + ((maj) << 20) + ((min) << 10) + (patch)) +#elif defined(__GNUC__) && defined(__GNUC_MINOR__) +#define RCC_GNUC_PREREQ(maj, min, patch) \ + ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) >= ((maj) << 20) + ((min) << 10)) +#else +#define RCC_GNUC_PREREQ(maj, min, patch) 0 +#endif +#endif + +/// \macro RCC_MSC_PREREQ +/// Is the compiler MSVC of at least the specified version? +/// The common \param version values to check for are: +/// * 1910: VS2017, version 15.1 & 15.2 +/// * 1911: VS2017, version 15.3 & 15.4 +/// * 1912: VS2017, version 15.5 +/// * 1913: VS2017, version 15.6 +/// * 1914: VS2017, version 15.7 +/// * 1915: VS2017, version 15.8 +/// * 1916: VS2017, version 15.9 +/// * 1920: VS2019, version 16.0 +/// * 1921: VS2019, version 16.1 +/// * 1922: VS2019, version 16.2 +/// * 1923: VS2019, version 16.3 +/// * 1924: VS2019, version 16.4 +/// * 1925: VS2019, version 16.5 +/// * 1926: VS2019, version 16.6 +/// * 1927: VS2019, version 16.7 +/// * 1928: VS2019, version 16.8 + 16.9 +/// * 1929: VS2019, version 16.10 + 16.11 +/// * 1930: VS2022, version 17.0 +#ifdef _MSC_VER +#define RCC_MSC_PREREQ(version) (_MSC_VER >= (version)) + +// We require at least VS 2019. +#if !defined(RCC_FORCE_USE_OLD_TOOLCHAIN) +#if !RCC_MSC_PREREQ(1920) +#error RCC requires at least VS 2019. +#endif +#endif + +#else +#define RCC_MSC_PREREQ(version) 0 +#endif + +/// RCC_LIBRARY_VISIBILITY - If a class marked with this attribute is linked +/// into a shared library, then the class should be private to the library and +/// not accessible from outside it. Can also be used to mark variables and +/// functions, making them private to any shared library they are linked into. +/// On PE/COFF targets, library visibility is the default, so this isn't needed. +/// +/// RCC_EXTERNAL_VISIBILITY - classes, functions, and variables marked with +/// this attribute will be made public and visible outside of any shared library +/// they are linked in to. + +#if RCC_HAS_CPP_ATTRIBUTE(gnu::visibility) && defined(__GNUC__) && \ + !defined(__clang__) +#define RCC_ATTRIBUTE_VISIBILITY_HIDDEN [[gnu::visibility ("hidden")]] +#define RCC_ATTRIBUTE_VISIBILITY_DEFAULT [[gnu::visibility ("default")]] +#elif __has_attribute(visibility) +#define RCC_ATTRIBUTE_VISIBILITY_HIDDEN __attribute__ ((visibility ("hidden"))) +#define RCC_ATTRIBUTE_VISIBILITY_DEFAULT \ + __attribute__ ((visibility ("default"))) +#else +#define RCC_ATTRIBUTE_VISIBILITY_HIDDEN +#define RCC_ATTRIBUTE_VISIBILITY_DEFAULT +#endif + +#if defined(RCC_BUILD_RCC_DYLIB) || defined(RCC_BUILD_SHARED_LIBS) +#define RCC_EXTERNAL_VISIBILITY RCC_ATTRIBUTE_VISIBILITY_DEFAULT +#else +#define RCC_EXTERNAL_VISIBILITY +#endif + +#if (!(defined(_WIN32) || defined(__CYGWIN__)) || \ + ((defined(__MINGW32__) || defined(__CYGWIN__)) && defined(__clang__))) +#define RCC_LIBRARY_VISIBILITY RCC_ATTRIBUTE_VISIBILITY_HIDDEN +// Clang compilers older then 15 do not support gnu style attributes on +// namespaces. +#if defined(__clang__) && __clang_major__ < 15 +#define RCC_LIBRARY_VISIBILITY_NAMESPACE [[gnu::visibility ("hidden")]] +#else +#define RCC_LIBRARY_VISIBILITY_NAMESPACE RCC_ATTRIBUTE_VISIBILITY_HIDDEN +#endif +#define RCC_ALWAYS_EXPORT RCC_ATTRIBUTE_VISIBILITY_DEFAULT +#elif defined(_WIN32) +#define RCC_ALWAYS_EXPORT __declspec (dllexport) +#define RCC_LIBRARY_VISIBILITY +#define RCC_LIBRARY_VISIBILITY_NAMESPACE +#else +#define RCC_LIBRARY_VISIBILITY +#define RCC_ALWAYS_EXPORT +#define RCC_LIBRARY_VISIBILITY_NAMESPACE +#endif + +/// RCC_ABI is the main export/visibility macro to mark something as explicitly +/// exported when rcc is built as a shared library with everything else that is +/// unannotated will have internal visibility. +/// +/// RCC_ABI_EXPORT is for the special case for things like plugin symbol +/// declarations or definitions where we don't want the macro to be switching +/// between dllexport and dllimport on windows based on what codebase is being +/// built, it will only be dllexport. For non windows platforms this macro +/// behaves the same as RCC_ABI. +/// +/// RCC_EXPORT_TEMPLATE is used on explicit template instantiations in source +/// files that were declared extern in a header. This macro is only set as a +/// compiler export attribute on windows, on other platforms it does nothing. +/// +/// RCC_TEMPLATE_ABI is for annotating extern template declarations in headers +/// for both functions and classes. On windows its turned in to dllimport for +/// library consumers, for other platforms its a default visibility attribute. +/// +/// RCC_ABI_FOR_TEST is for annotating symbols that are exported from a +/// library-internal header solely so that unit tests can link against them. +/// Symbols in RCC's public headers are part of the RCC public interface and +/// should use RCC_ABI. RCC_ABI_FOR_TEST is reserved for internal headers, +/// whose symbols could be conditionally excluded when not building tests in the +/// future. +/// +#ifndef RCC_ABI_GENERATING_ANNOTATIONS +// Marker to add to classes or functions in public headers that should not have +// export macros added to them by the clang tool +#define RCC_ABI_NOT_EXPORTED +// TODO(https://github.com/rcc/rcc-project/issues/145406): eliminate need for +// two preprocessor definitions to gate RCC_ABI macro definitions. +#if defined(RCC_ENABLE_RCC_EXPORT_ANNOTATIONS) && !defined(RCC_BUILD_STATIC) +#if defined(_WIN32) && !defined(__MINGW32__) +#if defined(RCC_EXPORTS) +#define RCC_ABI __declspec (dllexport) +#define RCC_TEMPLATE_ABI +#define RCC_EXPORT_TEMPLATE __declspec (dllexport) +#else +#define RCC_ABI __declspec (dllimport) +#define RCC_TEMPLATE_ABI __declspec (dllimport) +#define RCC_EXPORT_TEMPLATE +#endif +#define RCC_ABI_EXPORT __declspec (dllexport) +#elif __has_attribute(visibility) +#if defined(__ELF__) || defined(__MINGW32__) || defined(_AIX) || \ + defined(__MVS__) || defined(__CYGWIN__) +#define RCC_ABI __attribute__ ((visibility ("default"))) +#define RCC_TEMPLATE_ABI RCC_ABI +#define RCC_EXPORT_TEMPLATE +#define RCC_ABI_EXPORT RCC_ABI +#elif defined(__MACH__) || defined(__wasm__) || defined(__EMSCRIPTEN__) +#define RCC_ABI __attribute__ ((visibility ("default"))) +#define RCC_TEMPLATE_ABI +#define RCC_EXPORT_TEMPLATE +#define RCC_ABI_EXPORT RCC_ABI +#endif +#endif +#endif +#if !defined(RCC_ABI) +#define RCC_ABI +#define RCC_TEMPLATE_ABI +#define RCC_EXPORT_TEMPLATE +#define RCC_ABI_EXPORT +#endif +#define RCC_ABI_FOR_TEST RCC_ABI +#endif + +#if defined(__GNUC__) +#define RCC_PREFETCH(addr, rw, locality) __builtin_prefetch (addr, rw, locality) +#else +#define RCC_PREFETCH(addr, rw, locality) +#endif + +#if __has_attribute(uninitialized) +#define RCC_ATTRIBUTE_UNINITIALIZED __attribute__ ((uninitialized)) +#else +#define RCC_ATTRIBUTE_UNINITIALIZED +#endif + +#if __has_attribute(used) +#define RCC_ATTRIBUTE_USED __attribute__ ((__used__)) +#else +#define RCC_ATTRIBUTE_USED +#endif + +#if __has_attribute(warn_unused) +#define RCC_ATTRIBUTE_WARN_UNUSED __attribute__ ((warn_unused)) +#else +#define RCC_ATTRIBUTE_WARN_UNUSED +#endif + +// Only enabled for clang: +// See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99587 +// GCC may produce "warning: 'retain' attribute ignored" (despite +// __has_attribute(retain) being 1). +#if defined(__clang__) && __has_attribute(retain) +#define RCC_ATTRIBUTE_RETAIN __attribute__ ((__retain__)) +#else +#define RCC_ATTRIBUTE_RETAIN +#endif + +// For deprecations that are not a simple rename, use [[deprecated(MSG)]] +// instead. +#if defined(__clang__) +#define RCC_DEPRECATED_WITH_FIXIT(MSG, FIX) \ + __attribute__ ((deprecated (MSG, FIX))) +#else +#define RCC_DEPRECATED_WITH_FIXIT(MSG, FIX) [[deprecated (MSG)]] +#endif + +// clang-format off +#if defined(__clang__) || defined(__GNUC__) +#define RCC_SUPPRESS_DEPRECATED_DECLARATIONS_PUSH \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#define RCC_SUPPRESS_DEPRECATED_DECLARATIONS_POP \ + _Pragma("GCC diagnostic pop") +#elif defined(_MSC_VER) +#define RCC_SUPPRESS_DEPRECATED_DECLARATIONS_PUSH \ + __pragma(warning(push)) \ + __pragma(warning(disable : 4996)) +#define RCC_SUPPRESS_DEPRECATED_DECLARATIONS_POP \ + __pragma(warning(pop)) +#else +#define RCC_SUPPRESS_DEPRECATED_DECLARATIONS_PUSH +#define RCC_SUPPRESS_DEPRECATED_DECLARATIONS_POP +#endif +// clang-format on + +// Indicate that a non-static, non-const C++ member function reinitializes +// the entire object to a known state, independent of the previous state of +// the object. +// +// The clang-tidy check bugprone-use-after-move recognizes this attribute as a +// marker that a moved-from object has left the indeterminate state and can be +// reused. +#if RCC_HAS_CPP_ATTRIBUTE(clang::reinitializes) +#define RCC_ATTRIBUTE_REINITIALIZES [[clang::reinitializes]] +#else +#define RCC_ATTRIBUTE_REINITIALIZES +#endif + +// Some compilers warn about unused functions. When a function is sometimes +// used or not depending on build settings (e.g. a function only called from +// within "assert"), this attribute can be used to suppress such warnings. +// +// However, it shouldn't be used for unused *variables*, as those have a much +// more portable solution: +// (void)unused_var_name; +// Prefer cast-to-void wherever it is sufficient. +#if __has_attribute(unused) +#define RCC_ATTRIBUTE_UNUSED __attribute__ ((__unused__)) +#else +#define RCC_ATTRIBUTE_UNUSED +#endif + +// FIXME: Provide this for PE/COFF targets. +#if __has_attribute(weak) && !defined(__MINGW32__) && !defined(__CYGWIN__) && \ + !defined(_WIN32) +#define RCC_HAS_ATTRIBUTE_WEAK 1 +#else +#define RCC_HAS_ATTRIBUTE_WEAK 0 +#endif +#if RCC_HAS_ATTRIBUTE_WEAK +#define RCC_ATTRIBUTE_WEAK __attribute__ ((__weak__)) +#else +#define RCC_ATTRIBUTE_WEAK +#endif + +// Prior to clang 3.2, clang did not accept any spelling of +// __has_attribute(const), so assume it is supported. +#if defined(__clang__) || defined(__GNUC__) +// aka 'CONST' but following RCC Conventions. +#define RCC_READNONE __attribute__ ((__const__)) +#else +#define RCC_READNONE +#endif + +#if __has_attribute(pure) || defined(__GNUC__) +// aka 'PURE' but following RCC Conventions. +#define RCC_READONLY __attribute__ ((__pure__)) +#else +#define RCC_READONLY +#endif + +#if __has_attribute(minsize) +#define RCC_ATTRIBUTE_MINSIZE __attribute__ ((minsize)) +#else +#define RCC_ATTRIBUTE_MINSIZE +#endif + +#if __has_builtin(__builtin_expect) || defined(__GNUC__) +#define RCC_LIKELY(EXPR) __builtin_expect ((bool)(EXPR), true) +#define RCC_UNLIKELY(EXPR) __builtin_expect ((bool)(EXPR), false) +#else +#define RCC_LIKELY(EXPR) (EXPR) +#define RCC_UNLIKELY(EXPR) (EXPR) +#endif + +/// RCC_ATTRIBUTE_NOINLINE - On compilers where we have a directive to do so, +/// mark a method "not for inlining". +#if __has_attribute(noinline) +#define RCC_ATTRIBUTE_NOINLINE __attribute__ ((noinline)) +#elif defined(_MSC_VER) +#define RCC_ATTRIBUTE_NOINLINE __declspec (noinline) +#else +#define RCC_ATTRIBUTE_NOINLINE +#endif + +/// RCC_ATTRIBUTE_ALWAYS_INLINE - On compilers where we have a directive to do +/// so, mark a method "always inline" because it is performance sensitive. +#if __has_attribute(always_inline) +#define RCC_ATTRIBUTE_ALWAYS_INLINE inline __attribute__ ((always_inline)) +#elif defined(_MSC_VER) +#define RCC_ATTRIBUTE_ALWAYS_INLINE __forceinline +#else +#define RCC_ATTRIBUTE_ALWAYS_INLINE inline +#endif + +/// RCC_ATTRIBUTE_ALWAYS_INLINE_UNLESS_DEBUG - Like +/// RCC_ATTRIBUTE_ALWAYS_INLINE but disabled in debug builds to avoid stack +/// overflow with deep recursion. +#if defined(NDEBUG) +#define RCC_ATTRIBUTE_ALWAYS_INLINE_UNLESS_DEBUG RCC_ATTRIBUTE_ALWAYS_INLINE +#else +#define RCC_ATTRIBUTE_ALWAYS_INLINE_UNLESS_DEBUG inline +#endif + +/// RCC_ATTRIBUTE_NO_DEBUG - On compilers where we have a directive to do +/// so, mark a method "no debug" because debug info makes the debugger +/// experience worse. +#if __has_attribute(nodebug) +#define RCC_ATTRIBUTE_NODEBUG __attribute__ ((nodebug)) +#else +#define RCC_ATTRIBUTE_NODEBUG +#endif + +#if __has_attribute(returns_nonnull) +#define RCC_ATTRIBUTE_RETURNS_NONNULL __attribute__ ((returns_nonnull)) +#elif defined(_MSC_VER) +#define RCC_ATTRIBUTE_RETURNS_NONNULL _Ret_notnull_ +#else +#define RCC_ATTRIBUTE_RETURNS_NONNULL +#endif + +/// RCC_ATTRIBUTE_RESTRICT - Annotates a pointer to tell the compiler that +/// it is not aliased in the current scope. +#if defined(__clang__) || defined(__GNUC__) || defined(_MSC_VER) +#define RCC_ATTRIBUTE_RESTRICT __restrict +#else +#define RCC_ATTRIBUTE_RESTRICT +#endif + +/// \macro RCC_ATTRIBUTE_RETURNS_NOALIAS Used to mark a function as returning a +/// pointer that does not alias any other valid pointer. +#ifdef __GNUC__ +#define RCC_ATTRIBUTE_RETURNS_NOALIAS __attribute__ ((__malloc__)) +#elif defined(_MSC_VER) +#define RCC_ATTRIBUTE_RETURNS_NOALIAS __declspec (restrict) +#else +#define RCC_ATTRIBUTE_RETURNS_NOALIAS +#endif + +/// RCC_FALLTHROUGH - Mark fallthrough cases in switch statements. +#if defined(__cplusplus) && __cplusplus > 201402L && \ + RCC_HAS_CPP_ATTRIBUTE(fallthrough) +#define RCC_FALLTHROUGH [[fallthrough]] +#elif RCC_HAS_CPP_ATTRIBUTE(gnu::fallthrough) +#define RCC_FALLTHROUGH [[gnu::fallthrough]] +#elif __has_attribute(fallthrough) +#define RCC_FALLTHROUGH __attribute__ ((fallthrough)) +#elif RCC_HAS_CPP_ATTRIBUTE(clang::fallthrough) +#define RCC_FALLTHROUGH [[clang::fallthrough]] +#else +#define RCC_FALLTHROUGH +#endif + +/// RCC_REQUIRE_CONSTANT_INITIALIZATION - Apply this to globals to ensure that +/// they are constant initialized. +#if RCC_HAS_CPP_ATTRIBUTE(clang::require_constant_initialization) +#define RCC_REQUIRE_CONSTANT_INITIALIZATION \ + [[clang::require_constant_initialization]] +#else +#define RCC_REQUIRE_CONSTANT_INITIALIZATION +#endif + +/// RCC_GSL_OWNER - Apply this to owning classes like SmallVector to enable +/// lifetime warnings. +#if RCC_HAS_CPP_ATTRIBUTE(gsl::Owner) +#define RCC_GSL_OWNER [[gsl::Owner]] +#else +#define RCC_GSL_OWNER +#endif + +/// RCC_GSL_POINTER - Apply this to non-owning classes like +/// StringRef to enable lifetime warnings. +#if RCC_HAS_CPP_ATTRIBUTE(gsl::Pointer) +#define RCC_GSL_POINTER [[gsl::Pointer]] +#else +#define RCC_GSL_POINTER +#endif + +#if RCC_HAS_CPP_ATTRIBUTE(clang::lifetimebound) +#define RCC_LIFETIME_BOUND [[clang::lifetimebound]] +#else +#define RCC_LIFETIME_BOUND +#endif + +#if RCC_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L +#define RCC_CTOR_NODISCARD [[nodiscard]] +#else +#define RCC_CTOR_NODISCARD +#endif + +// Macro to suppress the MSVC warning C4848: +// "support for attribute [[msvc::no_unique_address]] in C++17 and earlier +// is a vendor extension". +// This warning is removed in versions >= 19.43. +#if !defined(_MSC_VER) || _MSC_VER >= 1943 || defined(__clang__) +#define RCC_SUPPRESS_MSVC_ATTR_IS_VENDOR_EXT_PUSH +#define RCC_SUPPRESS_MSVC_ATTR_IS_VENDOR_EXT_POP +#else // MSVC < 19.43 +#define RCC_SUPPRESS_MSVC_ATTR_IS_VENDOR_EXT_PUSH \ + __pragma (warning (push)) __pragma (warning (disable : 4848)) +#define RCC_SUPPRESS_MSVC_ATTR_IS_VENDOR_EXT_POP __pragma (warning (pop)) +#endif + +#if RCC_HAS_CPP_ATTRIBUTE(no_unique_address) +#define RCC_NO_UNIQUE_ADDRESS [[no_unique_address]] +#elif RCC_HAS_CPP_ATTRIBUTE(msvc::no_unique_address) +#define RCC_NO_UNIQUE_ADDRESS \ + RCC_SUPPRESS_MSVC_ATTR_IS_VENDOR_EXT_PUSH \ + [[msvc::no_unique_address]] RCC_SUPPRESS_MSVC_ATTR_IS_VENDOR_EXT_POP +#else +#define RCC_NO_UNIQUE_ADDRESS +#endif + +/// RCC_EXTENSION - Support compilers where we have a keyword to suppress +/// pedantic diagnostics. +#ifdef __GNUC__ +#define RCC_EXTENSION __extension__ +#else +#define RCC_EXTENSION +#endif + +/// RCC_BUILTIN_UNREACHABLE - On compilers which support it, expands +/// to an expression which states that it is undefined behavior for the +/// compiler to reach this point. Otherwise is not defined. +/// +/// '#else' is intentionally left out so that other macro logic (e.g., +/// RCC_ASSUME_ALIGNED and rcc_unreachable()) can detect whether +/// RCC_BUILTIN_UNREACHABLE has a definition. +#if __has_builtin(__builtin_unreachable) || defined(__GNUC__) +#define RCC_BUILTIN_UNREACHABLE __builtin_unreachable () +#elif defined(_MSC_VER) +#define RCC_BUILTIN_UNREACHABLE __assume (false) +#endif + +/// RCC_BUILTIN_TRAP - On compilers which support it, expands to an expression +/// which causes the program to exit abnormally. +#if __has_builtin(__builtin_trap) || defined(__GNUC__) +#define RCC_BUILTIN_TRAP __builtin_trap () +#elif defined(_MSC_VER) +// The __debugbreak intrinsic is supported by MSVC, does not require forward +// declarations involving platform-specific typedefs (unlike RaiseException), +// results in a call to vectored exception handlers, and encodes to a short +// instruction that still causes the trapping behavior we want. +#define RCC_BUILTIN_TRAP __debugbreak () +#else +#define RCC_BUILTIN_TRAP *(volatile int *)0x11 = 0 +#endif + +/// RCC_BUILTIN_DEBUGTRAP - On compilers which support it, expands to +/// an expression which causes the program to break while running +/// under a debugger. +#if __has_builtin(__builtin_debugtrap) +#define RCC_BUILTIN_DEBUGTRAP __builtin_debugtrap () +#elif defined(_MSC_VER) +// The __debugbreak intrinsic is supported by MSVC and breaks while +// running under the debugger, and also supports invoking a debugger +// when the OS is configured appropriately. +#define RCC_BUILTIN_DEBUGTRAP __debugbreak () +#else +// Just continue execution when built with compilers that have no +// support. This is a debugging aid and not intended to force the +// program to abort if encountered. +#define RCC_BUILTIN_DEBUGTRAP +#endif + +/// \macro RCC_ASSUME_ALIGNED +/// Returns a pointer with an assumed alignment. +#if __has_builtin(__builtin_assume_aligned) || defined(__GNUC__) +#define RCC_ASSUME_ALIGNED(p, a) __builtin_assume_aligned (p, a) +#elif defined(RCC_BUILTIN_UNREACHABLE) +#define RCC_ASSUME_ALIGNED(p, a) \ + (((uintptr_t (p) % (a)) == 0) ? (p) : (RCC_BUILTIN_UNREACHABLE, (p))) +#else +#define RCC_ASSUME_ALIGNED(p, a) (p) +#endif + +/// \macro RCC_PACKED +/// Used to specify a packed structure. +/// RCC_PACKED( +/// struct A { +/// int i; +/// int j; +/// int k; +/// long long l; +/// }); +/// +/// RCC_PACKED_START +/// struct B { +/// int i; +/// int j; +/// int k; +/// long long l; +/// }; +/// RCC_PACKED_END +#ifdef _MSC_VER +#define RCC_PACKED(d) __pragma (pack (push, 1)) d __pragma (pack (pop)) +#define RCC_PACKED_START __pragma (pack (push, 1)) +#define RCC_PACKED_END __pragma (pack (pop)) +#else +#define RCC_PACKED(d) d __attribute__ ((packed)) +#define RCC_PACKED_START _Pragma ("pack(push, 1)") +#define RCC_PACKED_END _Pragma ("pack(pop)") +#endif + +/// \macro RCC_MEMORY_SANITIZER_BUILD +/// Whether RCC itself is built with MemorySanitizer instrumentation. +#if __has_feature(memory_sanitizer) +#define RCC_MEMORY_SANITIZER_BUILD 1 +#include <sanitizer/msan_interface.h> +#define RCC_NO_SANITIZE_MEMORY_ATTRIBUTE __attribute__ ((no_sanitize_memory)) +#else +#define RCC_MEMORY_SANITIZER_BUILD 0 +#define __msan_allocated_memory(p, size) +#define __msan_unpoison(p, size) +#define RCC_NO_SANITIZE_MEMORY_ATTRIBUTE +#endif + +/// \macro RCC_ADDRESS_SANITIZER_BUILD +/// Whether RCC itself is built with AddressSanitizer instrumentation. +#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) +#define RCC_ADDRESS_SANITIZER_BUILD 1 +#if __has_include(<sanitizer/asan_interface.h>) +#include <sanitizer/asan_interface.h> +#else +// These declarations exist to support ASan with MSVC. If MSVC eventually ships +// asan_interface.h in their headers, then we can remove this. +#ifdef __cplusplus +extern "C" +{ +#endif + void + __asan_poison_memory_region (void const volatile *addr, size_t size); + void + __asan_unpoison_memory_region (void const volatile *addr, size_t size); +#ifdef __cplusplus +} // extern "C" +#endif +#endif +#else +#define RCC_ADDRESS_SANITIZER_BUILD 0 +#define __asan_poison_memory_region(p, size) +#define __asan_unpoison_memory_region(p, size) +#endif + +/// \macro RCC_HWADDRESS_SANITIZER_BUILD +/// Whether RCC itself is built with HWAddressSanitizer instrumentation. +#if __has_feature(hwaddress_sanitizer) +#define RCC_HWADDRESS_SANITIZER_BUILD 1 +#else +#define RCC_HWADDRESS_SANITIZER_BUILD 0 +#endif + +/// \macro RCC_THREAD_SANITIZER_BUILD +/// Whether RCC itself is built with ThreadSanitizer instrumentation. +#if __has_feature(thread_sanitizer) || defined(__SANITIZE_THREAD__) +#define RCC_THREAD_SANITIZER_BUILD 1 +#else +#define RCC_THREAD_SANITIZER_BUILD 0 +#endif + +#if RCC_THREAD_SANITIZER_BUILD +// Thread Sanitizer is a tool that finds races in code. +// See http://code.google.com/p/data-race-test/wiki/DynamicAnnotations . +// tsan detects these exact functions by name. +#ifdef __cplusplus +extern "C" +{ +#endif + void + AnnotateHappensAfter (const char *file, int line, const volatile void *cv); + void + AnnotateHappensBefore (const char *file, int line, const volatile void *cv); + void + AnnotateIgnoreWritesBegin (const char *file, int line); + void + AnnotateIgnoreWritesEnd (const char *file, int line); +#ifdef __cplusplus +} +#endif + +// This marker is used to define a happens-before arc. The race detector will +// infer an arc from the begin to the end when they share the same pointer +// argument. +#define TsanHappensBefore(cv) AnnotateHappensBefore (__FILE__, __LINE__, cv) + +// This marker defines the destination of a happens-before arc. +#define TsanHappensAfter(cv) AnnotateHappensAfter (__FILE__, __LINE__, cv) + +// Ignore any races on writes between here and the next TsanIgnoreWritesEnd. +#define TsanIgnoreWritesBegin() AnnotateIgnoreWritesBegin (__FILE__, __LINE__) + +// Resume checking for racy writes. +#define TsanIgnoreWritesEnd() AnnotateIgnoreWritesEnd (__FILE__, __LINE__) +#else +#define TsanHappensBefore(cv) +#define TsanHappensAfter(cv) +#define TsanIgnoreWritesBegin() +#define TsanIgnoreWritesEnd() +#endif + +/// \macro RCC_NO_SANITIZE +/// Disable a particular sanitizer for a function. +#if __has_attribute(no_sanitize) +#define RCC_NO_SANITIZE(KIND) __attribute__ ((no_sanitize (KIND))) +#else +#define RCC_NO_SANITIZE(KIND) +#endif + +/// Mark debug helper function definitions like dump() that should not be +/// stripped from debug builds. +/// Note that you should also surround dump() functions with +/// `#if !defined(NDEBUG) || defined(RCC_ENABLE_DUMP)` so they do always +/// get stripped in release builds. +// FIXME: Move this to a private config.h as it's not usable in public headers. +#if !defined(NDEBUG) || defined(RCC_ENABLE_DUMP) +#define RCC_DUMP_METHOD \ + RCC_ATTRIBUTE_NOINLINE RCC_ATTRIBUTE_USED RCC_ATTRIBUTE_RETAIN +#else +#define RCC_DUMP_METHOD RCC_ATTRIBUTE_NOINLINE +#endif + +/// \macro RCC_PRETTY_FUNCTION +/// Gets a user-friendly looking function signature for the current scope +/// using the best available method on each platform. The exact format of the +/// resulting string is implementation specific and non-portable, so this should +/// only be used, for example, for logging or diagnostics. +#if defined(_MSC_VER) +#define RCC_PRETTY_FUNCTION __FUNCSIG__ +#elif defined(__GNUC__) || defined(__clang__) +#define RCC_PRETTY_FUNCTION __PRETTY_FUNCTION__ +#else +#define RCC_PRETTY_FUNCTION __func__ +#endif + +/// \macro RCC_THREAD_LOCAL +/// A thread-local storage specifier which can be used with globals, +/// extern globals, and static globals. +/// +/// This is essentially an extremely restricted analog to C++11's thread_local +/// support. It uses thread_local if available, falling back on gcc __thread +/// if not. __thread doesn't support many of the C++11 thread_local's +/// features. You should only use this for PODs that you can statically +/// initialize to some constant value. In almost all circumstances this is most +/// appropriate for use with a pointer, integer, or small aggregation of +/// pointers and integers. +#if RCC_ENABLE_THREADS +#if __has_feature(cxx_thread_local) || defined(_MSC_VER) +#define RCC_THREAD_LOCAL thread_local +#else +// Clang, GCC, and other compatible compilers used __thread prior to C++11 and +// we only need the restricted functionality that provides. +#define RCC_THREAD_LOCAL __thread +#endif +#else // !RCC_ENABLE_THREADS +// If threading is disabled entirely, this compiles to nothing and you get +// a normal global variable. +#define RCC_THREAD_LOCAL +#endif + +/// \macro RCC_ENABLE_EXCEPTIONS +/// Whether RCC is built with exception support. +#if __has_feature(cxx_exceptions) +#define RCC_ENABLE_EXCEPTIONS 1 +#elif defined(__GNUC__) && defined(__EXCEPTIONS) +#define RCC_ENABLE_EXCEPTIONS 1 +#elif defined(_MSC_VER) && defined(_CPPUNWIND) +#define RCC_ENABLE_EXCEPTIONS 1 +#endif + +/// \macro RCC_NO_PROFILE_INSTRUMENT_FUNCTION +/// Disable the profile instrument for a function. +#if __has_attribute(no_profile_instrument_function) +#define RCC_NO_PROFILE_INSTRUMENT_FUNCTION \ + __attribute__ ((no_profile_instrument_function)) +#else +#define RCC_NO_PROFILE_INSTRUMENT_FUNCTION +#endif + +/// \macro RCC_PREFERRED_TYPE +/// Adjust type of bit-field in debug info. +#if __has_attribute(preferred_type) +#define RCC_PREFERRED_TYPE(T) __attribute__ ((preferred_type (T))) +#else +#define RCC_PREFERRED_TYPE(T) +#endif + +#if RCC_HAS_CPP_ATTRIBUTE(clang::ptrauth_vtable_pointer) && \ + (defined(__PTRAUTH__) || __has_feature(ptrauth_calls)) +#define RCC_MOVABLE_POLYMORPHIC_TYPE \ + [[clang::ptrauth_vtable_pointer (default_key, no_address_discrimination, \ + default_extra_discrimination)]] +#else +#define RCC_MOVABLE_POLYMORPHIC_TYPE +#endif + +/// \macro RCC_VIRTUAL_ANCHOR_FUNCTION +/// This macro is used to adhere to RCC's policy that each class with a vtable +/// must have at least one out-of-line virtual function. This macro allows us +/// to declare such a function in `final` classes without triggering a warning. +// clang-format off +// Autoformatting makes this look awful. +#if defined(__clang__) + // Make sure this is only parsed if __clang__ is defined + #if __has_warning("-Wunnecessary-virtual-specifier") + #define RCC_DECLARE_VIRTUAL_ANCHOR_FUNCTION() \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wunnecessary-virtual-specifier\"") \ + virtual void anchor() \ + _Pragma("clang diagnostic pop") + #else // __has_warning + #define RCC_DECLARE_VIRTUAL_ANCHOR_FUNCTION() \ + virtual void anchor() + #endif +#else // defined(__clang__) + #define RCC_DECLARE_VIRTUAL_ANCHOR_FUNCTION() \ + virtual void anchor() +#endif +// clang-format on + +/// \macro RCC_IS_X86 +/// Whether the target architecture is x86 / x86-64. +#if defined(__x86_64__) || defined(__i386__) +#define RCC_IS_X86 1 +#else +#define RCC_IS_X86 0 +#endif + +/// \macro RCC_TARGET_SSE42 +/// Function attribute to compile a function with SSE4.2 enabled. +#if defined(__has_attribute) && __has_attribute(target) +#define RCC_TARGET_SSE42 __attribute__ ((target ("sse4.2"))) +#else +#define RCC_TARGET_SSE42 +#endif + +#if __has_builtin(__builtin_cpu_supports) && \ + (defined(__linux__) || defined(__APPLE__)) +#define RCC_CPU_SUPPORTS(feature) __builtin_cpu_supports (feature) +#else +#define RCC_CPU_SUPPORTS(feature) 0 +#endif + +/// \macro RCC_CPU_SUPPORTS_SSE42 +/// Expands to true if the runtime cpu supports SSE4.2, or if compiled with +/// SSE4.2 enabled. +#if defined(__SSE4_2__) +#define RCC_CPU_SUPPORTS_SSE42 1 +#else +#define RCC_CPU_SUPPORTS_SSE42 RCC_CPU_SUPPORTS ("sse4.2") +#endif + +#endif diff --git a/rcc/include/rcc/Support/Errno.h b/rcc/include/rcc/Support/Errno.h new file mode 100644 index 0000000..21d8d78 --- /dev/null +++ b/rcc/include/rcc/Support/Errno.h @@ -0,0 +1,64 @@ +/* + RCC-Project + + Copyright (C) 2026 Richard Qin + + This file is part of RCC-Project. + + RCC-Project is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your option) any + later version. + + RCC-Project is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + RCC-Project; see the file COPYING. If not see + <http://www.gnu.org/licenses/>. +*/ + +// This implementation is based on llvm/include/llvm/Support/Errno.h. + +#ifndef RCC_SUPPORT_ERRNO_H +#define RCC_SUPPORT_ERRNO_H + +#include "rcc/Support/Compiler.h" + +#include <cerrno> +#include <string> + +namespace rcc +{ +namespace sys +{ + +/// Returns a string representation of the errno value, using whatever +/// thread-safe variant of strerror() is available. Be sure to call this +/// immediately after the function that set errno, or errno may have been +/// overwritten by an intervening call. +RCC_ABI std::string +StrError (); + +/// Like the no-argument version above, but uses \p errnum instead of errno. +RCC_ABI std::string +StrError (int errnum); + +template <typename FailT, typename Fun, typename... Args> +inline decltype (auto) +RetryAfterSignal (const FailT &Fail, const Fun &F, const Args &...As) +{ + decltype (F (As...)) Res; + do + { + errno = 0; + Res = F (As...); + } while (Res == Fail && errno == EINTR); + return Res; +} + +} // namespace sys +} // namespace rcc + +#endif // RCC_SUPPORT_ERRNO_H diff --git a/rcc/include/rcc/Support/ErrorOr.h b/rcc/include/rcc/Support/ErrorOr.h new file mode 100644 index 0000000..0e17822 --- /dev/null +++ b/rcc/include/rcc/Support/ErrorOr.h @@ -0,0 +1,378 @@ +/* + RCC-Project + + Copyright (C) 2026 Richard Qin + + This file is part of RCC-Project. + + RCC-Project is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your option) any + later version. + + RCC-Project is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + RCC-Project; see the file COPYING. If not see + <http://www.gnu.org/licenses/>. +*/ + +//===- llvm/Support/ErrorOr.h - Error Smart Pointer -------------*- 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// Provides ErrorOr<T> smart pointer. +/// +//===----------------------------------------------------------------------===// + +#ifndef RCC_SUPPORT_ERROROR_H +#define RCC_SUPPORT_ERROROR_H + +#include <cassert> +#include <functional> // for std::reference_wrapper +#include <system_error> +#include <type_traits> +#include <utility> + +namespace rcc +{ + +/// Represents either an error or a value T. +/// +/// ErrorOr<T> is a pointer-like class that represents the result of an +/// operation. The result is either an error, or a value of type T. This is +/// designed to emulate the usage of returning a pointer where nullptr indicates +/// failure. However instead of just knowing that the operation failed, we also +/// have an error_code that describes why it failed. +/// +/// It is used like the following. +/// \code +/// ErrorOr<Buffer> getBuffer(); +/// +/// auto buffer = getBuffer(); +/// if (error_code ec = buffer.getError()) +/// return ec; +/// buffer->write("adena"); +/// \endcode +/// +/// +/// Implicit conversion to bool returns true if there is a usable value. The +/// unary * and -> operators provide pointer like access to the value. Accessing +/// the value when there is an error has undefined behavior. +/// +/// When T is a reference type the behavior is slightly different. The reference +/// is held in a std::reference_wrapper<std::remove_reference<T>::type>, and +/// there is special handling to make operator -> work as if T was not a +/// reference. +/// +/// T cannot be a rvalue reference. +template <class T> class ErrorOr +{ + template <class OtherT> friend class ErrorOr; + + static constexpr bool isRef = std::is_reference_v<T>; + + using wrap = std::reference_wrapper<std::remove_reference_t<T>>; + +public: + using storage_type = std::conditional_t<isRef, wrap, T>; + +private: + using reference = std::remove_reference_t<T> &; + using const_reference = const std::remove_reference_t<T> &; + using pointer = std::remove_reference_t<T> *; + using const_pointer = const std::remove_reference_t<T> *; + +public: + template <class E> + ErrorOr (E ErrorCode, + std::enable_if_t<std::is_error_code_enum<E>::value || + std::is_error_condition_enum<E>::value, + void *> = nullptr) + : HasError (true) + { + new (getErrorStorage ()) std::error_code (make_error_code (ErrorCode)); + } + + ErrorOr (std::error_code EC) : HasError (true) + { + new (getErrorStorage ()) std::error_code (EC); + } + + template <class OtherT> + ErrorOr (OtherT &&Val, + std::enable_if_t<std::is_convertible_v<OtherT, T>> * = nullptr) + : HasError (false) + { + new (getStorage ()) storage_type (std::forward<OtherT> (Val)); + } + + ErrorOr (const ErrorOr &Other) + { + copyConstruct (Other); + } + + template <class OtherT> + ErrorOr (const ErrorOr<OtherT> &Other, + std::enable_if_t<std::is_convertible_v<OtherT, T>> * = nullptr) + { + copyConstruct (Other); + } + + template <class OtherT> + explicit ErrorOr ( + const ErrorOr<OtherT> &Other, + std::enable_if_t<!std::is_convertible_v<OtherT, const T &>> * = nullptr) + { + copyConstruct (Other); + } + + ErrorOr (ErrorOr &&Other) + { + moveConstruct (std::move (Other)); + } + + template <class OtherT> + ErrorOr (ErrorOr<OtherT> &&Other, + std::enable_if_t<std::is_convertible_v<OtherT, T>> * = nullptr) + { + moveConstruct (std::move (Other)); + } + + // This might eventually need SFINAE but it's more complex than is_convertible + // & I'm too lazy to write it right now. + template <class OtherT> + explicit ErrorOr ( + ErrorOr<OtherT> &&Other, + std::enable_if_t<!std::is_convertible_v<OtherT, T>> * = nullptr) + { + moveConstruct (std::move (Other)); + } + + ErrorOr & + operator= (const ErrorOr &Other) + { + copyAssign (Other); + return *this; + } + + ErrorOr & + operator= (ErrorOr &&Other) + { + moveAssign (std::move (Other)); + return *this; + } + + ~ErrorOr () + { + if (!HasError) + { + getStorage ()->~storage_type (); + } + } + + /// Return false if there is an error. + explicit + operator bool () const + { + return !HasError; + } + + reference + get () + { + return *getStorage (); + } + const_reference + get () const + { + return const_cast<ErrorOr<T> *> (this)->get (); + } + + std::error_code + getError () const + { + return HasError ? *getErrorStorage () : std::error_code (); + } + + pointer + operator->() + { + return toPointer (getStorage ()); + } + + const_pointer + operator->() const + { + return toPointer (getStorage ()); + } + + reference + operator* () + { + return *getStorage (); + } + + const_reference + operator* () const + { + return *getStorage (); + } + +private: + template <class OtherT> + void + copyConstruct (const ErrorOr<OtherT> &Other) + { + if (!Other.HasError) + { + // Get the other value. + HasError = false; + new (getStorage ()) storage_type (*Other.getStorage ()); + } + else + { + // Get other's error. + HasError = true; + new (getErrorStorage ()) std::error_code (Other.getError ()); + } + } + + template <class T1> + static bool + compareThisIfSameType (const T1 &a, const T1 &b) + { + return &a == &b; + } + + template <class T1, class T2> + static bool + compareThisIfSameType (const T1 &, const T2 &) + { + return false; + } + + template <class OtherT> + void + copyAssign (const ErrorOr<OtherT> &Other) + { + if (compareThisIfSameType (*this, Other)) + { + return; + } + + this->~ErrorOr (); + new (this) ErrorOr (Other); + } + + template <class OtherT> + void + moveConstruct (ErrorOr<OtherT> &&Other) + { + if (!Other.HasError) + { + // Get the other value. + HasError = false; + new (getStorage ()) storage_type (std::move (*Other.getStorage ())); + } + else + { + // Get other's error. + HasError = true; + new (getErrorStorage ()) std::error_code (Other.getError ()); + } + } + + template <class OtherT> + void + moveAssign (ErrorOr<OtherT> &&Other) + { + if (compareThisIfSameType (*this, Other)) + { + return; + } + + this->~ErrorOr (); + new (this) ErrorOr (std::move (Other)); + } + + pointer + toPointer (pointer Val) + { + return Val; + } + + const_pointer + toPointer (const_pointer Val) const + { + return Val; + } + + pointer + toPointer (wrap *Val) + { + return &Val->get (); + } + + const_pointer + toPointer (const wrap *Val) const + { + return &Val->get (); + } + + storage_type * + getStorage () + { + assert (!HasError && "Cannot get value when an error exists!"); + return &TStorage; + } + + const storage_type * + getStorage () const + { + assert (!HasError && "Cannot get value when an error exists!"); + return &TStorage; + } + + std::error_code * + getErrorStorage () + { + assert (HasError && "Cannot get error when a value exists!"); + return &ErrorStorage; + } + + const std::error_code * + getErrorStorage () const + { + assert (HasError && "Cannot get error when a value exists!"); + return &ErrorStorage; + } + + union + { + storage_type TStorage; + std::error_code ErrorStorage; + }; + bool HasError : 1; +}; + +template <class T, class E> +std::enable_if_t<std::is_error_code_enum<E>::value || + std::is_error_condition_enum<E>::value, + bool> +operator== (const ErrorOr<T> &Err, E Code) +{ + return Err.getError () == Code; +} + +} // end namespace rcc + +#endif // RCC_SUPPORT_ERROROR_H diff --git a/rcc/include/rcc/Support/MathExtras.h b/rcc/include/rcc/Support/MathExtras.h new file mode 100644 index 0000000..6ea2a1f --- /dev/null +++ b/rcc/include/rcc/Support/MathExtras.h @@ -0,0 +1,1050 @@ +/* + RCC-Project + + Copyright (C) 2026 Richard Qin + + This file is part of RCC-Project. + + RCC-Project is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your option) any + later version. + + RCC-Project is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + RCC-Project; see the file COPYING. If not see + <http://www.gnu.org/licenses/>. +*/ + +//===-- llvm/Support/MathExtras.h - Useful math functions -------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file contains some functions that are useful for math stuff. +// +//===----------------------------------------------------------------------===// + +#ifndef RCC_SUPPORT_MATHEXTRAS_H +#define RCC_SUPPORT_MATHEXTRAS_H + +#include "rcc/Support/Compiler.h" +#include <bit> +#include <cassert> +#include <climits> +#include <cstdint> +#include <cstring> +#include <limits> +#include <numbers> +#include <type_traits> +#include <utility> + +namespace rcc +{ +/// Some template parameter helpers to optimize for bitwidth, for functions that +/// take multiple arguments. + +// We can't verify signedness, since callers rely on implicit coercions to +// signed/unsigned. +template <typename T, typename U> +using enableif_int = + std::enable_if_t<std::is_integral_v<T> && std::is_integral_v<U>>; + +// Use std::common_type_t to widen only up to the widest argument. +template <typename T, typename U, typename = enableif_int<T, U>> +using common_uint = + std::common_type_t<std::make_unsigned_t<T>, std::make_unsigned_t<U>>; +template <typename T, typename U, typename = enableif_int<T, U>> +using common_sint = + std::common_type_t<std::make_signed_t<T>, std::make_signed_t<U>>; + +/// Mathematical constants. +namespace numbers +{ +// clang-format off +inline constexpr float ef = std::numbers::e_v<float>; +inline constexpr float egammaf = std::numbers::egamma_v<float>; +inline constexpr float ln2f = std::numbers::ln2_v<float>; +inline constexpr float ln10f = std::numbers::ln10_v<float>; +inline constexpr float log2ef = std::numbers::log2e_v<float>; +inline constexpr float log10ef = std::numbers::log10e_v<float>; +inline constexpr float pif = std::numbers::pi_v<float>; +inline constexpr float inv_pif = std::numbers::inv_pi_v<float>; +inline constexpr float inv_sqrtpif = std::numbers::inv_sqrtpi_v<float>; +inline constexpr float sqrt2f = std::numbers::sqrt2_v<float>; +inline constexpr float inv_sqrt2f = 1.0f / std::numbers::sqrt2_v<float>; +inline constexpr float sqrt3f = std::numbers::sqrt3_v<float>; +inline constexpr float inv_sqrt3f = std::numbers::inv_sqrt3_v<float>; +inline constexpr float phif = std::numbers::phi_v<float>; + +// sqrtpi is not in C++20 std::numbers. +template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>> +inline constexpr T sqrtpi_v = T(0x1.c5bf891b4ef6bP+0); // (1.7724538509055160273) https://oeis.org/A002161 +inline constexpr double sqrtpi = sqrtpi_v<double>; +inline constexpr float sqrtpif = sqrtpi_v<float>; + +// These string literals are taken from below: +// https://github.com/bminor/glibc/blob/8543577b04ded6d979ffcc5a818930e4d74d0645/math/math.h#L1215-L1229 +constexpr const char *pis = "3.141592653589793238462643383279502884", + *inv_pis = "0.318309886183790671537767526745028724"; +// clang-format on +} // namespace numbers + +/// Create a bitmask with the N right-most bits set to 1, and all other +/// bits set to 0. Only unsigned types are allowed. +template <typename T> +constexpr T +maskTrailingOnes (unsigned N) +{ + static_assert (std::is_unsigned_v<T>, "Invalid type!"); + const unsigned Bits = CHAR_BIT * sizeof (T); + assert (N <= Bits && "Invalid bit index"); + if (N == 0) + { + return 0; + } + return T (-1) >> (Bits - N); +} + +/// Create a bitmask with the N left-most bits set to 1, and all other +/// bits set to 0. Only unsigned types are allowed. +template <typename T> +constexpr T +maskLeadingOnes (unsigned N) +{ + return ~maskTrailingOnes<T> (CHAR_BIT * sizeof (T) - N); +} + +/// Create a bitmask with the N right-most bits set to 0, and all other +/// bits set to 1. Only unsigned types are allowed. +template <typename T> +constexpr T +maskTrailingZeros (unsigned N) +{ + return maskLeadingOnes<T> (CHAR_BIT * sizeof (T) - N); +} + +/// Create a bitmask with the N left-most bits set to 0, and all other +/// bits set to 1. Only unsigned types are allowed. +template <typename T> +constexpr T +maskLeadingZeros (unsigned N) +{ + return maskTrailingOnes<T> (CHAR_BIT * sizeof (T) - N); +} + +/// Macro compressed bit reversal table for 256 bits. +/// +/// http://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable +static const unsigned char BitReverseTable256[256] = { +#define R2(n) n, n + 2 * 64, n + 1 * 64, n + 3 * 64 +#define R4(n) R2 (n), R2 (n + 2 * 16), R2 (n + 1 * 16), R2 (n + 3 * 16) +#define R6(n) R4 (n), R4 (n + 2 * 4), R4 (n + 1 * 4), R4 (n + 3 * 4) + R6 (0), R6 (2), R6 (1), R6 (3) +#undef R2 +#undef R4 +#undef R6 +}; + +/// Reverse the bits in \p Val. +template <typename T> +constexpr T +reverseBits (T Val) +{ +#if __has_builtin(__builtin_bitreverse8) + if constexpr (std::is_same_v<T, uint8_t>) + { + return __builtin_bitreverse8 (Val); + } +#endif +#if __has_builtin(__builtin_bitreverse16) + if constexpr (std::is_same_v<T, uint16_t>) + { + return __builtin_bitreverse16 (Val); + } +#endif +#if __has_builtin(__builtin_bitreverse32) + if constexpr (std::is_same_v<T, uint32_t>) + { + return __builtin_bitreverse32 (Val); + } +#endif +#if __has_builtin(__builtin_bitreverse64) + if constexpr (std::is_same_v<T, uint64_t>) + { + return __builtin_bitreverse64 (Val); + } +#endif + + unsigned char in[sizeof (Val)]; + unsigned char out[sizeof (Val)]; + std::memcpy (in, &Val, sizeof (Val)); + for (unsigned i = 0; i < sizeof (Val); ++i) + { + out[(sizeof (Val) - i) - 1] = BitReverseTable256[in[i]]; + } + std::memcpy (&Val, out, sizeof (Val)); + return Val; +} + +// NOTE: The following support functions use the _32/_64 extensions instead of +// type overloading so that signed and unsigned integers can be used without +// ambiguity. + +/// Return the high 32 bits of a 64 bit value. +constexpr uint32_t +Hi_32 (uint64_t Value) +{ + return static_cast<uint32_t> (Value >> 32); +} + +/// Return the low 32 bits of a 64 bit value. +constexpr uint32_t +Lo_32 (uint64_t Value) +{ + return static_cast<uint32_t> (Value); +} + +/// Make a 64-bit integer from a high / low pair of 32-bit integers. +constexpr uint64_t +Make_64 (uint32_t High, uint32_t Low) +{ + return ((uint64_t)High << 32) | (uint64_t)Low; +} + +/// Checks if an integer fits into the given bit width. +template <unsigned N> +constexpr bool +isInt (int64_t x) +{ + if constexpr (N == 0) + { + return 0 == x; + } + if constexpr (N == 8) + { + return static_cast<int8_t> (x) == x; + } + if constexpr (N == 16) + { + return static_cast<int16_t> (x) == x; + } + if constexpr (N == 32) + { + return static_cast<int32_t> (x) == x; + } + if constexpr (N < 64) + { + return -(INT64_C (1) << (N - 1)) <= x && x < (INT64_C (1) << (N - 1)); + } + (void)x; // MSVC v19.25 warns that x is unused. + return true; +} + +/// Checks if a signed integer is an N bit number shifted left by S. +template <unsigned N, unsigned S> +constexpr bool +isShiftedInt (int64_t x) +{ + static_assert (S < 64, "isShiftedInt<N, S> with S >= 64 is too much."); + static_assert (N + S <= 64, + "isShiftedInt<N, S> with N + S > 64 is too wide."); + return isInt<N + S> (x) && (x % (UINT64_C (1) << S) == 0); +} + +/// Checks if an unsigned integer fits into the given bit width. +template <unsigned N> +constexpr bool +isUInt (uint64_t x) +{ + if constexpr (N < 64) + { + return (x >> N) == 0; + } + (void)x; // MSVC v19.25 warns that x is unused. + return true; +} + +/// Checks if a unsigned integer is an N bit number shifted left by S. +template <unsigned N, unsigned S> +constexpr bool +isShiftedUInt (uint64_t x) +{ + static_assert (S < 64, "isShiftedUInt<N, S> with S >= 64 is too much."); + static_assert (N + S <= 64, + "isShiftedUInt<N, S> with N + S > 64 is too wide."); + // S must be strictly less than 64. So 1 << S is not undefined behavior. + return isUInt<N + S> (x) && (x % (UINT64_C (1) << S) == 0); +} + +/// Gets the maximum value for a N-bit unsigned integer. +inline constexpr uint64_t +maxUIntN (uint64_t N) +{ + assert (N <= 64 && "integer width out of range"); + + // uint64_t(1) << 64 is undefined behavior, so we can't do + // (uint64_t(1) << N) - 1 + // without checking first that N != 64. But this works and doesn't have a + // branch for N != 0. + // Unfortunately, shifting a uint64_t right by 64 bit is undefined + // behavior, so the condition on N == 0 is necessary. Fortunately, most + // optimizers do not emit branches for this check. + if (N == 0) + { + return 0; + } + return UINT64_MAX >> (64 - N); +} + +/// Gets the minimum value for a N-bit signed integer. +inline constexpr int64_t +minIntN (int64_t N) +{ + assert (N <= 64 && "integer width out of range"); + + if (N == 0) + { + return 0; + } + return UINT64_MAX << (N - 1); +} + +/// Gets the maximum value for a N-bit signed integer. +inline constexpr int64_t +maxIntN (int64_t N) +{ + assert (N <= 64 && "integer width out of range"); + + // This relies on two's complement wraparound when N == 64, so we convert to + // int64_t only at the very end to avoid UB. + if (N == 0) + { + return 0; + } + return (UINT64_C (1) << (N - 1)) - 1; +} + +/// Checks if an unsigned integer fits into the given (dynamic) bit width. +inline constexpr bool +isUIntN (unsigned N, uint64_t x) +{ + return N >= 64 || (x >> N) == 0; +} + +/// Checks if an signed integer fits into the given (dynamic) bit width. +inline constexpr bool +isIntN (unsigned N, int64_t x) +{ + return N >= 64 || (minIntN (N) <= x && x <= maxIntN (N)); +} + +/// Return true if the argument is a non-empty sequence of ones starting at the +/// least significant bit with the remainder zero (32 bit version). +/// Ex. isMask_32(0x0000FFFFU) == true. +constexpr bool +isMask_32 (uint32_t Value) +{ + return Value && ((Value + 1) & Value) == 0; +} + +/// Return true if the argument is a non-empty sequence of ones starting at the +/// least significant bit with the remainder zero (64 bit version). +constexpr bool +isMask_64 (uint64_t Value) +{ + return Value && ((Value + 1) & Value) == 0; +} + +/// Return true if the argument contains a non-empty sequence of ones with the +/// remainder zero (32 bit version.) Ex. isShiftedMask_32(0x0000FF00U) == true. +constexpr bool +isShiftedMask_32 (uint32_t Value) +{ + return Value && isMask_32 ((Value - 1) | Value); +} + +/// Return true if the argument contains a non-empty sequence of ones with the +/// remainder zero (64 bit version.) +constexpr bool +isShiftedMask_64 (uint64_t Value) +{ + return Value && isMask_64 ((Value - 1) | Value); +} + +/// Return true if the argument is a power of two > 0. +/// Ex. isPowerOf2_32(0x00100000U) == true (32 bit edition.) +constexpr bool +isPowerOf2_32 (uint32_t Value) +{ + return std::has_single_bit (Value); +} + +/// Return true if the argument is a power of two > 0 (64 bit edition.) +constexpr bool +isPowerOf2_64 (uint64_t Value) +{ + return std::has_single_bit (Value); +} + +/// Return true if the argument contains a non-empty sequence of ones with the +/// remainder zero (32 bit version.) Ex. isShiftedMask_32(0x0000FF00U) == true. +/// If true, \p MaskIdx will specify the index of the lowest set bit and \p +/// MaskLen is updated to specify the length of the mask, else neither are +/// updated. +inline bool +isShiftedMask_32 (uint32_t Value, unsigned &MaskIdx, unsigned &MaskLen) +{ + if (!isShiftedMask_32 (Value)) + { + return false; + } + MaskIdx = std::countr_zero (Value); + MaskLen = std::popcount (Value); + return true; +} + +/// Return true if the argument contains a non-empty sequence of ones with the +/// remainder zero (64 bit version.) If true, \p MaskIdx will specify the index +/// of the lowest set bit and \p MaskLen is updated to specify the length of the +/// mask, else neither are updated. +inline bool +isShiftedMask_64 (uint64_t Value, unsigned &MaskIdx, unsigned &MaskLen) +{ + if (!isShiftedMask_64 (Value)) + { + return false; + } + MaskIdx = std::countr_zero (Value); + MaskLen = std::popcount (Value); + return true; +} + +/// Compile time Log2. +/// Valid only for positive powers of two. +template <size_t kValue> +constexpr size_t +ConstantLog2 () +{ + static_assert (rcc::isPowerOf2_64 (kValue), + "Value is not a valid power of 2"); + return std::countr_zero (kValue); +} + +/// Return the floor log base 2 of the specified value, -1 if the value is zero. +/// (32 bit edition.) +/// Ex. Log2_32(32) == 5, Log2_32(1) == 0, Log2_32(0) == -1, Log2_32(6) == 2 +inline unsigned +Log2_32 (uint32_t Value) +{ + return 31 - std::countl_zero (Value); +} + +/// Return the floor log base 2 of the specified value, -1 if the value is zero. +/// (64 bit edition.) +inline unsigned +Log2_64 (uint64_t Value) +{ + return 63 - std::countl_zero (Value); +} + +/// Return the ceil log base 2 of the specified value, 32 if the value is zero. +/// (32 bit edition). +/// Ex. Log2_32_Ceil(32) == 5, Log2_32_Ceil(1) == 0, Log2_32_Ceil(6) == 3 +inline unsigned +Log2_32_Ceil (uint32_t Value) +{ + return 32 - std::countl_zero (Value - 1); +} + +/// Return the ceil log base 2 of the specified value, 64 if the value is zero. +/// (64 bit edition.) +inline unsigned +Log2_64_Ceil (uint64_t Value) +{ + return 64 - std::countl_zero (Value - 1); +} + +/// A and B are either alignments or offsets. Return the minimum alignment that +/// may be assumed after adding the two together. +template <typename U, typename V, typename T = common_uint<U, V>> +constexpr T +MinAlign (U A, V B) +{ + // The largest power of 2 that divides both A and B. + // + // Replace "-Value" by "1+~Value" in the following commented code to avoid + // MSVC warning C4146 + // return (A | B) & -(A | B); + return (A | B) & (1 + ~(A | B)); +} + +/// Fallback when arguments aren't integral. +constexpr uint64_t +MinAlign (uint64_t A, uint64_t B) +{ + return (A | B) & (1 + ~(A | B)); +} + +/// Returns the next power of two (in 64-bits) that is strictly greater than A. +/// Returns zero on overflow. +constexpr uint64_t +NextPowerOf2 (uint64_t A) +{ + A |= (A >> 1); + A |= (A >> 2); + A |= (A >> 4); + A |= (A >> 8); + A |= (A >> 16); + A |= (A >> 32); + return A + 1; +} + +/// Returns the power of two which is greater than or equal to the given value. +/// Essentially, it is a ceil operation across the domain of powers of two. +inline uint64_t +PowerOf2Ceil (uint64_t A) +{ + if (!A || A > UINT64_MAX / 2) + { + return 0; + } + return UINT64_C (1) << Log2_64_Ceil (A); +} + +/// Returns the integer ceil(Numerator / Denominator). Unsigned version. +/// Guaranteed to never overflow. +template <typename U, typename V, typename T = common_uint<U, V>> +constexpr T +divideCeil (U Numerator, V Denominator) +{ + assert (Denominator && "Division by zero"); + T Bias = (Numerator != 0); + return (Numerator - Bias) / Denominator + Bias; +} + +/// Fallback when arguments aren't integral. +constexpr uint64_t +divideCeil (uint64_t Numerator, uint64_t Denominator) +{ + assert (Denominator && "Division by zero"); + uint64_t Bias = (Numerator != 0); + return (Numerator - Bias) / Denominator + Bias; +} + +// Check whether divideCeilSigned or divideFloorSigned would overflow. This +// happens only when Numerator = INT_MIN and Denominator = -1. +template <typename U, typename V> +constexpr bool +divideSignedWouldOverflow (U Numerator, V Denominator) +{ + return Numerator == std::numeric_limits<U>::min () && Denominator == -1; +} + +/// Returns the integer ceil(Numerator / Denominator). Signed version. +/// Overflow is explicitly forbidden with an assert. +template <typename U, typename V, typename T = common_sint<U, V>> +constexpr T +divideCeilSigned (U Numerator, V Denominator) +{ + assert (Denominator && "Division by zero"); + assert (!divideSignedWouldOverflow (Numerator, Denominator) && + "Divide would overflow"); + if (!Numerator) + { + return 0; + } + // C's integer division rounds towards 0. + T Bias = Denominator >= 0 ? 1 : -1; + bool SameSign = (Numerator >= 0) == (Denominator >= 0); + return SameSign ? (Numerator - Bias) / Denominator + 1 + : Numerator / Denominator; +} + +/// Returns the integer floor(Numerator / Denominator). Signed version. +/// Overflow is explicitly forbidden with an assert. +template <typename U, typename V, typename T = common_sint<U, V>> +constexpr T +divideFloorSigned (U Numerator, V Denominator) +{ + assert (Denominator && "Division by zero"); + assert (!divideSignedWouldOverflow (Numerator, Denominator) && + "Divide would overflow"); + if (!Numerator) + { + return 0; + } + // C's integer division rounds towards 0. + T Bias = Denominator >= 0 ? -1 : 1; + bool SameSign = (Numerator >= 0) == (Denominator >= 0); + return SameSign ? Numerator / Denominator + : (Numerator - Bias) / Denominator - 1; +} + +/// Returns the remainder of the Euclidean division of LHS by RHS. Result is +/// always non-negative. +template <typename U, typename V, typename T = common_sint<U, V>> +constexpr T +mod (U Numerator, V Denominator) +{ + assert (Denominator >= 1 && "Mod by non-positive number"); + T Mod = Numerator % Denominator; + return Mod < 0 ? Mod + Denominator : Mod; +} + +/// Returns (Numerator / Denominator) rounded by round-half-up. Guaranteed to +/// never overflow. +template <typename U, typename V, typename T = common_uint<U, V>> +constexpr T +divideNearest (U Numerator, V Denominator) +{ + assert (Denominator && "Division by zero"); + T Mod = Numerator % Denominator; + return (Numerator / Denominator) + + (Mod > (static_cast<T> (Denominator) - 1) / 2); +} + +/// Returns the next integer (mod 2**nbits) that is greater than or equal to +/// \p Value and is a multiple of \p Align. \p Align must be non-zero. +/// +/// Examples: +/// \code +/// alignTo(5, 8) = 8 +/// alignTo(17, 8) = 24 +/// alignTo(~0LL, 8) = 0 +/// alignTo(321, 255) = 510 +/// \endcode +/// +/// Will overflow only if result is not representable in T. +template <typename U, typename V, typename T = common_uint<U, V>> +constexpr T +alignTo (U Value, V Align) +{ + assert (Align != 0u && "Align can't be 0."); + T CeilDiv = divideCeil (Value, Align); + return CeilDiv * Align; +} + +/// Fallback when arguments aren't integral. +constexpr uint64_t +alignTo (uint64_t Value, uint64_t Align) +{ + assert (Align != 0u && "Align can't be 0."); + uint64_t CeilDiv = divideCeil (Value, Align); + return CeilDiv * Align; +} + +/// Will overflow only if result is not representable in T. +template <typename U, typename V, typename T = common_uint<U, V>> +constexpr T +alignToPowerOf2 (U Value, V Align) +{ + assert (Align != 0 && (Align & (Align - 1)) == 0 && + "Align must be a power of 2"); + T NegAlign = static_cast<T> (0) - Align; + return (Value + (Align - 1)) & NegAlign; +} + +/// Fallback when arguments aren't integral. +constexpr uint64_t +alignToPowerOf2 (uint64_t Value, uint64_t Align) +{ + assert (Align != 0 && (Align & (Align - 1)) == 0 && + "Align must be a power of 2"); + uint64_t NegAlign = 0 - Align; + return (Value + (Align - 1)) & NegAlign; +} + +/// If non-zero \p Skew is specified, the return value will be a minimal integer +/// that is greater than or equal to \p Size and equal to \p A * N + \p Skew for +/// some integer N. If \p Skew is larger than \p A, its value is adjusted to '\p +/// Skew mod \p A'. \p Align must be non-zero. +/// +/// Examples: +/// \code +/// alignTo(5, 8, 7) = 7 +/// alignTo(17, 8, 1) = 17 +/// alignTo(~0LL, 8, 3) = 3 +/// alignTo(321, 255, 42) = 552 +/// \endcode +/// +/// May overflow. +template <typename U, typename V, typename W, + typename T = common_uint<common_uint<U, V>, W>> +constexpr T +alignTo (U Value, V Align, W Skew) +{ + assert (Align != 0u && "Align can't be 0."); + Skew %= Align; + return alignTo (Value - Skew, Align) + Skew; +} + +/// Returns the next integer (mod 2**nbits) that is greater than or equal to +/// \p Value and is a multiple of \c Align. \c Align must be non-zero. +/// +/// Will overflow only if result is not representable in T. +template <auto Align, typename V, typename T = common_uint<decltype (Align), V>> +constexpr T +alignTo (V Value) +{ + static_assert (Align != 0u, "Align must be non-zero"); + T CeilDiv = divideCeil (Value, Align); + return CeilDiv * Align; +} + +/// Returns the largest unsigned integer less than or equal to \p Value and is +/// \p Skew mod \p Align. \p Align must be non-zero. Guaranteed to never +/// overflow. +template <typename U, typename V, typename W = uint8_t, + typename T = common_uint<common_uint<U, V>, W>> +constexpr T +alignDown (U Value, V Align, W Skew = 0) +{ + assert (Align != 0u && "Align can't be 0."); + Skew %= Align; + return (Value - Skew) / Align * Align + Skew; +} + +/// Sign-extend the number in the bottom B bits of X to a 32-bit integer. +/// Requires B <= 32. +template <unsigned B> +constexpr int32_t +SignExtend32 (uint32_t X) +{ + static_assert (B <= 32, "Bit width out of range."); + if constexpr (B == 0) + { + return 0; + } + return int32_t (X << (32 - B)) >> (32 - B); +} + +/// Sign-extend the number in the bottom B bits of X to a 32-bit integer. +/// Requires B <= 32. +inline int32_t +SignExtend32 (uint32_t X, unsigned B) +{ + assert (B <= 32 && "Bit width out of range."); + if (B == 0) + { + return 0; + } + return int32_t (X << (32 - B)) >> (32 - B); +} + +/// Sign-extend the number in the bottom B bits of X to a 64-bit integer. +/// Requires B <= 64. +template <unsigned B> +constexpr int64_t +SignExtend64 (uint64_t x) +{ + static_assert (B <= 64, "Bit width out of range."); + if constexpr (B == 0) + { + return 0; + } + return int64_t (x << (64 - B)) >> (64 - B); +} + +/// Sign-extend the number in the bottom B bits of X to a 64-bit integer. +/// Requires B <= 64. +inline int64_t +SignExtend64 (uint64_t X, unsigned B) +{ + assert (B <= 64 && "Bit width out of range."); + if (B == 0) + { + return 0; + } + return int64_t (X << (64 - B)) >> (64 - B); +} + +/// Return the absolute value of a signed integer, converted to the +/// corresponding unsigned integer type. Avoids undefined behavior in std::abs +/// when you pass it INT_MIN or similar. +template <typename T, typename U = std::make_unsigned_t<T>> +constexpr U +AbsoluteValue (T X) +{ + // If X is negative, cast it to the unsigned type _before_ negating it. + return X < 0 ? -static_cast<U> (X) : X; +} + +/// Subtract two unsigned integers, X and Y, of type T and return the absolute +/// value of the result. +template <typename U, typename V, typename T = common_uint<U, V>> +constexpr T +AbsoluteDifference (U X, V Y) +{ + return X > Y ? (X - Y) : (Y - X); +} + +/// Add two unsigned integers, X and Y, of type T. Clamp the result to the +/// maximum representable value of T on overflow. ResultOverflowed indicates if +/// the result is larger than the maximum representable value of type T. +template <typename T> +std::enable_if_t<std::is_unsigned_v<T>, T> +SaturatingAdd (T X, T Y, bool *ResultOverflowed = nullptr) +{ + bool Dummy; + bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy; + // Hacker's Delight, p. 29 + T Z = X + Y; + Overflowed = (Z < X || Z < Y); + if (Overflowed) + { + return std::numeric_limits<T>::max (); + } + else + { + return Z; + } +} + +/// Add multiple unsigned integers of type T. Clamp the result to the +/// maximum representable value of T on overflow. +template <class T, class... Ts> +std::enable_if_t<std::is_unsigned_v<T>, T> +SaturatingAdd (T X, T Y, T Z, Ts... Args) +{ + bool Overflowed = false; + T XY = SaturatingAdd (X, Y, &Overflowed); + if (Overflowed) + { + return SaturatingAdd (std::numeric_limits<T>::max (), T (1), Args...); + } + return SaturatingAdd (XY, Z, Args...); +} + +/// Multiply two unsigned integers, X and Y, of type T. Clamp the result to the +/// maximum representable value of T on overflow. ResultOverflowed indicates if +/// the result is larger than the maximum representable value of type T. +template <typename T> +std::enable_if_t<std::is_unsigned_v<T>, T> +SaturatingMultiply (T X, T Y, bool *ResultOverflowed = nullptr) +{ + bool Dummy; + bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy; + + // Hacker's Delight, p. 30 has a different algorithm, but we don't use that + // because it fails for uint16_t (where multiplication can have undefined + // behavior due to promotion to int), and requires a division in addition + // to the multiplication. + + Overflowed = false; + + // Log2(Z) would be either Log2Z or Log2Z + 1. + // Special case: if X or Y is 0, Log2_64 gives -1, and Log2Z + // will necessarily be less than Log2Max as desired. + int Log2Z = Log2_64 (X) + Log2_64 (Y); + const T Max = std::numeric_limits<T>::max (); + int Log2Max = Log2_64 (Max); + if (Log2Z < Log2Max) + { + return X * Y; + } + if (Log2Z > Log2Max) + { + Overflowed = true; + return Max; + } + + // We're going to use the top bit, and maybe overflow one + // bit past it. Multiply all but the bottom bit then add + // that on at the end. + T Z = (X >> 1) * Y; + if (Z & ~(Max >> 1)) + { + Overflowed = true; + return Max; + } + Z <<= 1; + if (X & 1) + { + return SaturatingAdd (Z, Y, ResultOverflowed); + } + + return Z; +} + +/// Multiply two unsigned integers, X and Y, and add the unsigned integer, A to +/// the product. Clamp the result to the maximum representable value of T on +/// overflow. ResultOverflowed indicates if the result is larger than the +/// maximum representable value of type T. +template <typename T> +std::enable_if_t<std::is_unsigned_v<T>, T> +SaturatingMultiplyAdd (T X, T Y, T A, bool *ResultOverflowed = nullptr) +{ + bool Dummy; + bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy; + + T Product = SaturatingMultiply (X, Y, &Overflowed); + if (Overflowed) + { + return Product; + } + + return SaturatingAdd (A, Product, &Overflowed); +} + +/// Use this rather than HUGE_VALF; the latter causes warnings on MSVC. +RCC_ABI extern const float huge_valf; + +/// Add two signed integers, computing the two's complement truncated result, +/// returning a pair {result, overflow}, where "overflow" is a boolean value +/// indicating whether an overflow occurred. +template <typename T> +constexpr std::enable_if_t<std::is_signed_v<T>, std::pair<T, bool>> +AddOverflow (T X, T Y) +{ + // Perform the unsigned addition. + using U = std::make_unsigned_t<T>; + const U UX = static_cast<U> (X); + const U UY = static_cast<U> (Y); + const U UResult = UX + UY; + + // Convert to signed. + auto Result = static_cast<T> (UResult); + + // Adding two positive numbers should result in a positive number. + if (X > 0 && Y > 0) + { + return {Result, Result <= 0}; + } + // Adding two negatives should result in a negative number. + if (X < 0 && Y < 0) + { + return {Result, Result >= 0}; + } + return {Result, false}; +} + +/// Add two signed integers, computing the two's complement truncated result, +/// returning true if overflow occurred. +template <typename T> +std::enable_if_t<std::is_signed_v<T>, bool> +AddOverflow (T X, T Y, T &Result) +{ +#if __has_builtin(__builtin_add_overflow) + return __builtin_add_overflow (X, Y, &Result); +#else + auto [Res, Ovf] = AddOverflow (X, Y); + Result = Res; + return Ovf; +#endif +} + +/// Subtract two signed integers, computing the two's complement truncated +/// result, returning a pair {result, overflow}, where "overflow" is a +/// boolean value indicating whether an overflow occurred. +template <typename T> +constexpr std::enable_if_t<std::is_signed_v<T>, std::pair<T, bool>> +SubOverflow (T X, T Y) +{ + // Perform the unsigned addition. + using U = std::make_unsigned_t<T>; + const U UX = static_cast<U> (X); + const U UY = static_cast<U> (Y); + const U UResult = UX - UY; + + // Convert to signed. + auto Result = static_cast<T> (UResult); + + // Subtracting a positive number from a negative results in a negative number. + if (X <= 0 && Y > 0) + { + return {Result, Result >= 0}; + } + // Subtracting a negative number from a positive results in a positive number. + if (X >= 0 && Y < 0) + { + return {Result, Result <= 0}; + } + return {Result, false}; +} + +/// Subtract two signed integers, computing the two's complement truncated +/// result, returning true if an overflow occurred. +template <typename T> +std::enable_if_t<std::is_signed_v<T>, bool> +SubOverflow (T X, T Y, T &Result) +{ +#if __has_builtin(__builtin_sub_overflow) + return __builtin_sub_overflow (X, Y, &Result); +#else + auto [Res, Ovf] = SubOverflow (X, Y); + Result = Res; + return Ovf; +#endif +} + +/// Multiply two signed integers, computing the two's complement truncated +/// result, returning a pair {result, overflow}, where "overflow" is a +/// boolean value indicating whether an overflow occurred. +template <typename T> +constexpr std::enable_if_t<std::is_signed_v<T>, std::pair<T, bool>> +MulOverflow (T X, T Y) +{ + // Perform the unsigned multiplication on absolute values. + using U = std::make_unsigned_t<T>; + const U UX = X < 0 ? (0 - static_cast<U> (X)) : static_cast<U> (X); + const U UY = Y < 0 ? (0 - static_cast<U> (Y)) : static_cast<U> (Y); + const U UResult = UX * UY; + + // Convert to signed. + const bool IsNegative = (X < 0) ^ (Y < 0); + auto Result = IsNegative ? (0 - UResult) : UResult; + + // If any of the args was 0, result is 0 and no overflow occurs. + if (UX == 0 || UY == 0) + { + return {Result, false}; + } + + // UX and UY are in [1, 2^n], where n is the number of digits. + // Check how the max allowed absolute value (2^n for negative, 2^(n-1) for + // positive) divided by an argument compares to the other. + bool Overflow = + IsNegative + ? UX > (static_cast<U> (std::numeric_limits<T>::max ()) + U (1)) / UY + : UX > (static_cast<U> (std::numeric_limits<T>::max ())) / UY; + + return {Result, Overflow}; +} + +/// Multiply two signed integers, computing the two's complement truncated +/// result, returning true if an overflow occurred. +template <typename T> +std::enable_if_t<std::is_signed_v<T>, bool> +MulOverflow (T X, T Y, T &Result) +{ +#if __has_builtin(__builtin_mul_overflow) + return __builtin_mul_overflow (X, Y, &Result); +#else + auto [Res, Ovf] = MulOverflow (X, Y); + Result = Res; + return Ovf; +#endif +} + +/// Type to force float point values onto the stack, so that x86 doesn't add +/// hidden precision, avoiding rounding differences on various platforms. +#if defined(__i386__) || defined(_M_IX86) +using stack_float_t = volatile float; +#else +using stack_float_t = float; +#endif + +/// Returns the number of digits in the given integer. +RCC_ABI int +NumDigitsBase10 (uint64_t X); + +} // namespace rcc + +#endif |
