Disclaimer: Forgive me if my format sucks, I've never submitted a PR before! Fixes: #517 I added a few things to allow zig to link with the CRT properly both statically and dynamically. In Visual Studio 2017, Microsoft changed how the c-runtime is factored again. With this change, they also added a COM interface to allow you to query the respective Visual Studio instance for two of them. This does that and also falls back on a registry query for 2015 support. If you're using a Visual Studio instance older than 2015, you'll have to use the existing options available with the zig compiler. Changes are listed below along with a general description of the changes. all_types.cpp: The separate variables for msvc/kern32 have been removed and all win32 libc directory paths have been combined into a ZigList since we're querying more than two directories and differentiating one from another doesn't matter to lld. analyze.cpp: The existing functions were extended to support querying libc libs & libc headers at runtime. codegen.cpp/hpp: Microsoft uses the new 'Universal C Runtime' name now. Doesn't matter from a functionality standpoint. I left the compiler switches as is to not introduce any breaking changes. link.cpp: We're linking 4 libs and generating another in order to support the UCRT. Dynamic: msvcrt/d, vcruntime/d, ucrt/d, legacy_stdio_definitions.lib Static: libcmt/d, libvcruntime/d libucrt/d, legacy_stdio_definitions.lib main.cpp: Update function call names. os.cpp/hpp: COM/Registry interface for querying Windows UCRT/SDK. Sources: [Windows CRT](https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-library-features) [VS 2015 Breaking Changes](https://msdn.microsoft.com/en-us/library/bb531344.aspx)
155 lines
3.6 KiB
C++
155 lines
3.6 KiB
C++
/*
|
|
* Copyright (c) 2015 Andrew Kelley
|
|
*
|
|
* This file is part of zig, which is MIT licensed.
|
|
* See http://opensource.org/licenses/MIT
|
|
*/
|
|
|
|
#ifndef ZIG_UTIL_HPP
|
|
#define ZIG_UTIL_HPP
|
|
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
|
|
#include <new>
|
|
|
|
#if defined(_MSC_VER)
|
|
|
|
#include <intrin.h>
|
|
|
|
#define ATTRIBUTE_COLD __declspec(noinline)
|
|
#define ATTRIBUTE_PRINTF(a, b)
|
|
#define ATTRIBUTE_RETURNS_NOALIAS __declspec(restrict)
|
|
#define ATTRIBUTE_NORETURN __declspec(noreturn)
|
|
|
|
#else
|
|
|
|
#define ATTRIBUTE_COLD __attribute__((cold))
|
|
#define ATTRIBUTE_PRINTF(a, b) __attribute__((format(printf, a, b)))
|
|
#define ATTRIBUTE_RETURNS_NOALIAS __attribute__((__malloc__))
|
|
#define ATTRIBUTE_NORETURN __attribute__((noreturn))
|
|
|
|
#endif
|
|
|
|
#define BREAKPOINT __asm("int $0x03")
|
|
|
|
ATTRIBUTE_COLD
|
|
ATTRIBUTE_NORETURN
|
|
ATTRIBUTE_PRINTF(1, 2)
|
|
void zig_panic(const char *format, ...);
|
|
|
|
ATTRIBUTE_COLD
|
|
ATTRIBUTE_NORETURN
|
|
static inline void zig_unreachable(void) {
|
|
zig_panic("unreachable");
|
|
}
|
|
|
|
#if defined(_MSC_VER)
|
|
static inline int clzll(unsigned long long mask) {
|
|
unsigned long lz;
|
|
#if defined(_WIN64)
|
|
if (_BitScanReverse64(&lz, mask))
|
|
return static_cast<int>(63 - lz);
|
|
zig_unreachable();
|
|
#else
|
|
if (_BitScanReverse(&lz, mask >> 32))
|
|
lz += 32;
|
|
else
|
|
_BitScanReverse(&lz, mask & 0xffffffff);
|
|
return 63 - lz;
|
|
#endif
|
|
}
|
|
#else
|
|
#define clzll(x) __builtin_clzll(x)
|
|
#endif
|
|
|
|
template<typename T>
|
|
ATTRIBUTE_RETURNS_NOALIAS static inline T *allocate_nonzero(size_t count) {
|
|
T *ptr = reinterpret_cast<T*>(malloc(count * sizeof(T)));
|
|
if (!ptr)
|
|
zig_panic("allocation failed");
|
|
return ptr;
|
|
}
|
|
|
|
template<typename T>
|
|
ATTRIBUTE_RETURNS_NOALIAS static inline T *allocate(size_t count) {
|
|
T *ptr = reinterpret_cast<T*>(calloc(count, sizeof(T)));
|
|
if (!ptr)
|
|
zig_panic("allocation failed");
|
|
return ptr;
|
|
}
|
|
|
|
template<typename T>
|
|
static inline void safe_memcpy(T *dest, const T *src, size_t count) {
|
|
#ifdef NDEBUG
|
|
memcpy(dest, src, count * sizeof(T));
|
|
#else
|
|
// manually assign every elment to trigger compile error for non-copyable structs
|
|
for (size_t i = 0; i < count; i += 1) {
|
|
dest[i] = src[i];
|
|
}
|
|
#endif
|
|
}
|
|
|
|
template<typename T>
|
|
static inline T *reallocate_nonzero(T *old, size_t old_count, size_t new_count) {
|
|
#ifdef NDEBUG
|
|
T *ptr = reinterpret_cast<T*>(realloc(old, new_count * sizeof(T)));
|
|
if (!ptr)
|
|
zig_panic("allocation failed");
|
|
return ptr;
|
|
#else
|
|
// manually assign every element to trigger compile error for non-copyable structs
|
|
T *ptr = allocate_nonzero<T>(new_count);
|
|
safe_memcpy(ptr, old, old_count);
|
|
free(old);
|
|
return ptr;
|
|
#endif
|
|
}
|
|
|
|
template <typename T, size_t n>
|
|
constexpr size_t array_length(const T (&)[n]) {
|
|
return n;
|
|
}
|
|
|
|
template <typename T>
|
|
static inline T max(T a, T b) {
|
|
return (a >= b) ? a : b;
|
|
}
|
|
|
|
template <typename T>
|
|
static inline T min(T a, T b) {
|
|
return (a <= b) ? a : b;
|
|
}
|
|
|
|
template<typename T>
|
|
static inline T clamp(T min_value, T value, T max_value) {
|
|
return max(min(value, max_value), min_value);
|
|
}
|
|
|
|
static inline bool mem_eql_str(const char *mem, size_t mem_len, const char *str) {
|
|
size_t str_len = strlen(str);
|
|
if (str_len != mem_len)
|
|
return false;
|
|
return memcmp(mem, str, mem_len) == 0;
|
|
}
|
|
|
|
static inline bool is_power_of_2(uint64_t x) {
|
|
return x != 0 && ((x & (~x + 1)) == x);
|
|
}
|
|
|
|
uint32_t int_hash(int i);
|
|
bool int_eq(int a, int b);
|
|
uint32_t uint64_hash(uint64_t i);
|
|
bool uint64_eq(uint64_t a, uint64_t b);
|
|
uint32_t ptr_hash(const void *ptr);
|
|
bool ptr_eq(const void *a, const void *b);
|
|
|
|
static inline uint8_t log2_u64(uint64_t x) {
|
|
return (63 - clzll(x));
|
|
}
|
|
|
|
#endif
|