From 9d1e0a877ad201bac13eefc317f7ae2b5ec85f41 Mon Sep 17 00:00:00 2001 From: Spartan322 Date: Wed, 24 Jul 2024 18:04:07 -0400 Subject: [PATCH] Improve MSVC support --- include/lauf/config.h | 83 +++++++++++++++++-- include/lauf/runtime/builtin.h | 10 ++- src/lauf/asm/builder.hpp | 10 ++- src/lauf/asm/instruction.hpp | 124 ++++++++++++++++++++++++++-- src/lauf/backend/dump.cpp | 40 +++++---- src/lauf/lib/debug.cpp | 14 ++-- src/lauf/lib/int.cpp | 3 +- src/lauf/runtime/memory.cpp | 4 +- src/lauf/runtime/process.cpp | 9 +- src/lauf/runtime/stack.hpp | 3 + src/lauf/support/align.hpp | 4 +- src/lauf/support/array_list.hpp | 5 +- src/lauf/support/page_allocator.cpp | 38 ++++++++- src/lauf/vm_execute.cpp | 26 +++--- src/lauf/writer.cpp | 6 +- src/lauf/writer.hpp | 6 +- 16 files changed, 318 insertions(+), 67 deletions(-) diff --git a/include/lauf/config.h b/include/lauf/config.h index c1bc0e7..125f3f5 100644 --- a/include/lauf/config.h +++ b/include/lauf/config.h @@ -43,9 +43,17 @@ typedef uint64_t lauf_uint; //=== optimizations ===// #define LAUF_LIKELY(Cond) Cond /*__builtin_expect((Cond), 1)*/ #define LAUF_UNLIKELY(Cond) Cond /*__builtin_expect((Cond), 0)*/ -#if defined(__clang__) +#if defined(__has_cpp_attribute) +# if __has_cpp_attribute(gnu::musttail) +# define LAUF_TAIL_CALL [[gnu::musttail]] +# elif __has_cpp_attribute(clang::musttail) +# define LAUF_TAIL_CALL [[clang::musttail]] +# else +# define LAUF_TAIL_CALL +# endif +#elif defined(__clang__) # define LAUF_TAIL_CALL [[clang::musttail]] -#elif defined(__GNUC__) || defined(__GNUG__) +#else # define LAUF_TAIL_CALL #endif #if defined(_MSC_VER) @@ -68,7 +76,13 @@ typedef uint64_t lauf_uint; _Pragma("GCC diagnostic push"); \ _Pragma("GCC diagnostic ignored \"-Wconversion\""); \ __VA_ARGS__; \ - _Pragma("GCC diagnostic pop"); + _Pragma("GCC diagnostic pop") +#elif defined(_MSC_VER) +# define LAUF_IGNORE_BITFIELD_WARNING(...) \ + _Pragma("warning(push)"); \ + _Pragma("warning(disable : 4267)"); \ + __VA_ARGS__; \ + _Pragma("warning(pop)") #else # define LAUF_IGNORE_BITFIELD_WARNING(...) __VA_ARGS__ #endif @@ -78,7 +92,13 @@ typedef uint64_t lauf_uint; _Pragma("GCC diagnostic push"); \ _Pragma("GCC diagnostic ignored \"-Wconversion\""); \ __VA_ARGS__; \ - _Pragma("GCC diagnostic pop"); + _Pragma("GCC diagnostic pop") +#elif defined(_MSC_VER) +# define LAUF_IGNORE_CONV_WARNING(...) \ + _Pragma("warning(push)"); \ + _Pragma("warning(disable : 4267)"); \ + __VA_ARGS__; \ + _Pragma("warning(pop)") #else # define LAUF_IGNORE_CONV_WARNING(...) __VA_ARGS__ #endif @@ -88,9 +108,62 @@ typedef uint64_t lauf_uint; _Pragma("GCC diagnostic push"); \ _Pragma("GCC diagnostic ignored \"-Wsign-conversion\""); \ __VA_ARGS__; \ - _Pragma("GCC diagnostic pop"); + _Pragma("GCC diagnostic pop") +#elif defined(_MSC_VER) +# define LAUF_IGNORE_SIGN_WARNING(...) \ + _Pragma("warning(push)"); \ + _Pragma("warning(disable : 4267)"); \ + __VA_ARGS__; \ + _Pragma("warning(pop)") #else # define LAUF_IGNORE_SIGN_WARNING(...) __VA_ARGS__ #endif +#if defined(__GNUC__) && (__GNUC__ == 12 && __GNUC_MINOR__ < 3) +# define LAUF_WORKAROUND_GCC_BOGUS_MEMCPY 1 +#else +# define LAUF_WORKAROUND_GCC_BOGUS_MEMCPY 0 +#endif + +#if defined(_MSC_VER) && !defined(__clang__) +# include +template +static LAUF_FORCE_INLINE bool __builtin_add_overflow(uint64_t a, uint64_t b, T* out) +{ + unsigned long long tmp; +# if defined(_M_IX86) || defined(_M_X64) + auto carry = _addcarry_u64(0, a, b, &tmp); +# else + tmp = a + b; + unsigned long long vector = (a & b) ^ ((a ^ b) & ~tmp); + auto carry = vector >> 63; +# endif + *out = tmp; + return carry; +} + +template +static LAUF_FORCE_INLINE bool __builtin_sub_overflow(uint64_t a, uint64_t b, T* out) +{ + unsigned long long tmp; +# if defined(_M_IX86) || defined(_M_X64) + auto borrow = _subborrow_u64(0, a, b, &tmp); +# else + tmp = a - b; + unsigned long long vector = ((a ^ b) & a); + auto borrow = vector >> 63; +# endif + *out = tmp; + return borrow; +} + +template +static LAUF_FORCE_INLINE bool __builtin_mul_overflow(uint64_t a, uint64_t b, T* out) +{ + *out = a * b; + // This test isnt exact, but avoids doing integer division + return ((std::countl_zero(a) + std::countl_zero(b)) < 64); +} +#endif + #endif // LAUF_CONFIG_H_INCLUDED diff --git a/include/lauf/runtime/builtin.h b/include/lauf/runtime/builtin.h index 510a318..ac8adc2 100644 --- a/include/lauf/runtime/builtin.h +++ b/include/lauf/runtime/builtin.h @@ -9,9 +9,14 @@ LAUF_HEADER_START #if defined(__clang__) -#define LAUF_RUNTIME_BUILTIN_IMPL __attribute__((section("text.lauf_builtin"), aligned(8))) +# if defined(__APPLE__) && defined(__MACH__) +# define LAUF_RUNTIME_BUILTIN_IMPL \ + __attribute__((section("__TEXT,text.lauf_builtin"), aligned(8))) +# else +# define LAUF_RUNTIME_BUILTIN_IMPL __attribute__((section("text.lauf_builtin"), aligned(8))) +# endif #else -#define LAUF_RUNTIME_BUILTIN_IMPL +# define LAUF_RUNTIME_BUILTIN_IMPL #endif typedef union lauf_asm_inst lauf_asm_inst; @@ -96,4 +101,3 @@ typedef struct lauf_runtime_builtin_library LAUF_HEADER_END #endif // LAUF_RUNTIME_BUILTIN_H_INCLUDED - diff --git a/src/lauf/asm/builder.hpp b/src/lauf/asm/builder.hpp index 46f547e..478add0 100644 --- a/src/lauf/asm/builder.hpp +++ b/src/lauf/asm/builder.hpp @@ -193,6 +193,7 @@ struct lauf_asm_block : sig{input_count, 0}, vstack(arena, input_count), terminator(unterminated), next{} {} }; +static_assert(std::is_trivially_copyable_v); struct lauf_asm_local { @@ -260,14 +261,14 @@ struct lauf_asm_builder : lauf::intrinsic_arena #define LAUF_BUILD_ASSERT(Cond, Msg) \ do \ { \ - if (LAUF_UNLIKELY(!(Cond))) \ + if (LAUF_UNLIKELY(!(Cond))) [[unlikely]] \ b->error(LAUF_BUILD_ASSERT_CONTEXT, Msg); \ } while (0) #define LAUF_BUILD_CHECK_CUR \ do \ { \ - if (LAUF_UNLIKELY(b->cur == nullptr)) \ + if (LAUF_UNLIKELY(b->cur == nullptr)) [[unlikely]] \ return; \ } while (0) @@ -315,8 +316,9 @@ struct lauf_asm_builder : lauf::intrinsic_arena #define LAUF_BUILD_INST_VALUE(Name, Value) \ [&](const char* context, std::size_t value) { \ lauf_asm_inst result; \ - LAUF_IGNORE_BITFIELD_WARNING(result.Name = {lauf::asm_op::Name, std::uint32_t(value)}); \ - if (value != result.Name.value) \ + LAUF_IGNORE_BITFIELD_WARNING( \ + result.Name = {lauf::asm_op::Name, static_cast(std::uint32_t(value))}); \ + if (value != static_cast(result.Name.value)) \ b->error(context, "invalid value"); \ return result; \ }(LAUF_BUILD_ASSERT_CONTEXT, Value) diff --git a/src/lauf/asm/instruction.hpp b/src/lauf/asm/instruction.hpp index 2fbe3b9..132223f 100644 --- a/src/lauf/asm/instruction.hpp +++ b/src/lauf/asm/instruction.hpp @@ -48,10 +48,120 @@ struct asm_inst_none asm_op op; }; +#ifdef _MSC_VER +} // namespace lauf +# include +# include + +namespace lauf { +// MSVC tends not to respect bit-fields for packing +# pragma pack(push, 1) +struct _24bitint +{ + std::int8_t value_b1 : 8 {}; + std::int16_t value_b2 : 16 {}; + + LAUF_FORCE_INLINE constexpr _24bitint() = default; + LAUF_FORCE_INLINE constexpr _24bitint(std::int32_t value) + { + *this = value; + } + + struct int_converter + { + std::int8_t value_b1 {}; + std::int16_t value_b2 {}; + std::int8_t value_b3 {}; + }; + + LAUF_FORCE_INLINE constexpr _24bitint& operator=(std::int32_t lhs) + { + int_converter converter = std::bit_cast(lhs); + value_b1 = converter.value_b1; + value_b2 = converter.value_b2; + return *this; + } + + LAUF_FORCE_INLINE constexpr operator std::int32_t() const + { + int_converter converter {}; + converter.value_b1 = value_b1; + converter.value_b2 = value_b2; + converter.value_b3 = value_b2 >> 15; + return std::bit_cast(converter); + } + + LAUF_FORCE_INLINE constexpr explicit operator std::uint32_t() const + { + int_converter converter {}; + converter.value_b1 = value_b1; + converter.value_b2 = value_b2; + return std::bit_cast(converter); + } + + template + LAUF_FORCE_INLINE constexpr explicit operator T() const + { + return static_cast(static_cast(*this)); + } + + template + LAUF_FORCE_INLINE constexpr explicit operator T() const + { + return static_cast(static_cast(*this)); + } + + LAUF_FORCE_INLINE constexpr _24bitint operator+() const + { + return *this; + } + + LAUF_FORCE_INLINE constexpr _24bitint operator-() const + { + return _24bitint{-static_cast(*this)}; + } + + LAUF_FORCE_INLINE constexpr _24bitint operator~() const + { + return _24bitint{~static_cast(*this)}; + } + + LAUF_FORCE_INLINE _24bitint& operator++() + { + return *this = *this + 1; + } + + LAUF_FORCE_INLINE _24bitint operator++(int) + { + _24bitint result{*this}; + ++(*this); + return result; + } + + LAUF_FORCE_INLINE _24bitint& operator--() + { + return *this = *this - 1; + } + + LAUF_FORCE_INLINE _24bitint operator--(int) + { + _24bitint result(*this); + --(*this); + return result; + } +}; +# pragma pack(pop) +#endif + struct asm_inst_offset { - asm_op op : 8; + asm_op op : 8; + +#ifdef _MSC_VER + _24bitint offset; +#else std::int32_t offset : 24; +#endif }; template @@ -59,7 +169,8 @@ std::ptrdiff_t compress_pointer_offset(CurType* _cur, DestType* _dest) { auto cur = (void*)(_cur); auto dest = (void*)(_dest); - assert(is_aligned(cur, alignof(void*)) && is_aligned(dest, alignof(void*))); + assert(is_aligned(dest, alignof(void*))); + assert(is_aligned(cur, alignof(void*))); return (void**)dest - (void**)cur; } @@ -91,8 +202,12 @@ struct asm_inst_layout struct asm_inst_value { - asm_op op : 8; - std::uint32_t value : 24; + asm_op op : 8; +#ifdef _MSC_VER + _24bitint value; +#else + std::int32_t value : 24; +#endif }; struct asm_inst_stack_idx @@ -127,4 +242,3 @@ union lauf_asm_inst }; #endif // SRC_LAUF_ASM_INSTRUCTION_HPP_INCLUDED - diff --git a/src/lauf/backend/dump.cpp b/src/lauf/backend/dump.cpp index f98b5bc..f52156b 100644 --- a/src/lauf/backend/dump.cpp +++ b/src/lauf/backend/dump.cpp @@ -92,7 +92,10 @@ std::string find_global_name(const lauf_asm_module* mod, unsigned idx) { auto name = lauf_asm_global_debug_name(global); if (name != nullptr) - return "'" + std::string(name) + "'"; + { + using namespace std::string_literals; + return "'"s + name + "'"s; + } return "global_" + std::to_string(idx); } @@ -141,7 +144,7 @@ void dump_function(lauf_writer* writer, lauf_backend_dump_options opts, const la writer->write("return"); break; case lauf::asm_op::return_free: - writer->format("return_free %d", ip->return_free.value); + writer->format("return_free %d", static_cast(ip->return_free.value)); break; case lauf::asm_op::jump: writer->format("jump <%04zx>", ip + ip->jump.offset - fn->insts); @@ -213,19 +216,21 @@ void dump_function(lauf_writer* writer, lauf_backend_dump_options opts, const la break; case lauf::asm_op::push: - writer->format("push 0x%X", ip->push.value); + writer->format("push 0x%X", static_cast(ip->push.value)); break; case lauf::asm_op::push2: - writer->format("push2 0x%X", ip->push2.value); + writer->format("push2 0x%X", static_cast(ip->push2.value)); break; case lauf::asm_op::push3: - writer->format("push3 0x%X", ip->push3.value); + writer->format("push3 0x%X", static_cast(ip->push3.value)); break; case lauf::asm_op::pushn: - writer->format("pushn 0x%X", ip->pushn.value); + writer->format("pushn 0x%X", static_cast(ip->pushn.value)); break; case lauf::asm_op::global_addr: { - writer->format("global_addr @%s", find_global_name(mod, ip->global_addr.value).c_str()); + writer->format("global_addr @%s", + find_global_name(mod, static_cast(ip->global_addr.value)) + .c_str()); break; } case lauf::asm_op::function_addr: { @@ -280,7 +285,8 @@ void dump_function(lauf_writer* writer, lauf_backend_dump_options opts, const la break; case lauf::asm_op::setup_local_alloc: - writer->format("setup_local_alloc %u", ip->setup_local_alloc.value); + writer->format("setup_local_alloc %u", + static_cast(ip->setup_local_alloc.value)); break; case lauf::asm_op::local_alloc: writer->format("local_alloc (%u, %zu)", ip->local_alloc.size, @@ -291,7 +297,8 @@ void dump_function(lauf_writer* writer, lauf_backend_dump_options opts, const la ip->local_alloc_aligned.alignment()); break; case lauf::asm_op::local_storage: - writer->format("local_storage (%u, 8)", ip->local_storage.value); + writer->format("local_storage (%u, 8)", + static_cast(ip->local_storage.value)); break; case lauf::asm_op::deref_const: writer->format("deref_const (%u, %zu)", ip->deref_const.size, @@ -301,10 +308,12 @@ void dump_function(lauf_writer* writer, lauf_backend_dump_options opts, const la writer->format("deref_mut (%u, %zu)", ip->deref_mut.size, ip->deref_mut.alignment()); break; case lauf::asm_op::array_element: - writer->format("array_element [%u]", ip->array_element.value); + writer->format("array_element [%u]", + static_cast(ip->array_element.value)); break; case lauf::asm_op::aggregate_member: - writer->format("aggregate_member %u", ip->aggregate_member.value); + writer->format("aggregate_member %u", + static_cast(ip->aggregate_member.value)); break; case lauf::asm_op::load_local_value: writer->format("load_local_value %u <%zx>", ip->load_local_value.index, @@ -316,11 +325,15 @@ void dump_function(lauf_writer* writer, lauf_backend_dump_options opts, const la break; case lauf::asm_op::load_global_value: writer->format("load_global_value @%s", - find_global_name(mod, ip->load_global_value.value).c_str()); + find_global_name(mod, + static_cast(ip->load_global_value.value)) + .c_str()); break; case lauf::asm_op::store_global_value: writer->format("store_global_value @%s", - find_global_name(mod, ip->store_global_value.value).c_str()); + find_global_name(mod, static_cast( + ip->store_global_value.value)) + .c_str()); break; case lauf::asm_op::count: @@ -369,4 +382,3 @@ void lauf_backend_dump_chunk(lauf_writer* writer, lauf_backend_dump_options opti dump_module_header(writer, mod); dump_function(writer, options, mod, chunk->fn); } - diff --git a/src/lauf/lib/debug.cpp b/src/lauf/lib/debug.cpp index 6b9bb8e..8fe78e2 100644 --- a/src/lauf/lib/debug.cpp +++ b/src/lauf/lib/debug.cpp @@ -53,7 +53,7 @@ void lauf::debug_print_cstack(lauf_runtime_process* process, const lauf_runtime_ else { auto addr = lauf_asm_get_instruction_index(fn, ip); - std::fprintf(stderr, " at <%04lx>\n", addr); + std::fprintf(stderr, " at <%04zx>\n", addr); } ++index; @@ -140,11 +140,11 @@ LAUF_RUNTIME_BUILTIN(lauf_lib_debug_break, 0, 0, LAUF_RUNTIME_BUILTIN_NO_PROCESS | LAUF_RUNTIME_BUILTIN_NO_PANIC, "break", &lauf_lib_debug_print_all_cstacks) { -#if __has_builtin(__builtin_debugtrap) - __builtin_debugtrap(); -#elif __has_builtin(__debugbreak) +#if defined(_MSC_VER) __debugbreak(); -#elif defined(_MSC_VER) +#elif defined(__has_builtin) && __has_builtin(__builtin_debugtrap) + __builtin_debugtrap(); +#elif defined(__has_builtin) && __has_builtin(__debugbreak) __debugbreak(); #elif defined(__ARMCC_VERSION) __breakpoint(42) @@ -171,7 +171,9 @@ LAUF_RUNTIME_BUILTIN(lauf_lib_debug_read, 0, 1, std::printf("[lauf] debug read: 0x"); --vstack_ptr; - std::scanf("%" SCNx64, &vstack_ptr->as_uint); + [[maybe_unused]] + int _ + = std::scanf("%" SCNx64, &vstack_ptr->as_uint); LAUF_RUNTIME_BUILTIN_DISPATCH; } diff --git a/src/lauf/lib/int.cpp b/src/lauf/lib/int.cpp index 5854963..b9d7341 100644 --- a/src/lauf/lib/int.cpp +++ b/src/lauf/lib/int.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2022-2023 Jonathan Müller and lauf contributors // SPDX-License-Identifier: BSL-1.0 +#include "lauf/config.h" #include #include @@ -540,7 +541,7 @@ LAUF_RUNTIME_BUILTIN_IMPL bool load_int(const lauf_asm_inst* ip, lauf_runtime_va if constexpr (std::is_unsigned_v) vstack_ptr[1].as_uint = value; else - vstack_ptr[1].as_sint = value; + vstack_ptr[1].as_sint = static_cast(value); ++vstack_ptr; diff --git a/src/lauf/runtime/memory.cpp b/src/lauf/runtime/memory.cpp index 279cb24..ae23a35 100644 --- a/src/lauf/runtime/memory.cpp +++ b/src/lauf/runtime/memory.cpp @@ -296,7 +296,7 @@ size_t lauf_runtime_gc(lauf_runtime_process* p) // (We've done a size check already, so the initial offset is fine) auto offset = lauf::align_offset(alloc->ptr, alignof(lauf_runtime_value)); auto ptr = reinterpret_cast(static_cast(alloc->ptr) - + offset); + + offset); for (auto end = ptr + (alloc->size - offset) / sizeof(lauf_runtime_value); ptr != end; ++ptr) @@ -432,7 +432,7 @@ bool lauf_runtime_split_allocation(lauf_runtime_process* p, lauf_runtime_address // the allocation. Otherwise, it is somewhere in the middle. auto new_alloc = *alloc; new_alloc.ptr = static_cast(new_alloc.ptr) + addr.offset; - new_alloc.size -= addr.offset; + new_alloc.size -= static_cast(addr.offset); new_alloc.split = alloc->split == lauf::allocation_split::unsplit || alloc->split == lauf::allocation_split::split_last ? lauf::allocation_split::split_last diff --git a/src/lauf/runtime/process.cpp b/src/lauf/runtime/process.cpp index 7e0a3d3..2814b69 100644 --- a/src/lauf/runtime/process.cpp +++ b/src/lauf/runtime/process.cpp @@ -318,10 +318,11 @@ bool lauf_runtime_destroy_fiber(lauf_runtime_process* process, lauf_runtime_fibe for (auto frame_ptr = fiber->suspension_point.frame_ptr; frame_ptr != &fiber->trampoline_frame; frame_ptr = frame_ptr->prev) { - auto first_inst = frame_ptr->function->insts; - auto local_alloc_count = first_inst->op() == lauf::asm_op::setup_local_alloc - ? first_inst->setup_local_alloc.value - : 0u; + auto first_inst = frame_ptr->function->insts; + auto local_alloc_count + = first_inst->op() == lauf::asm_op::setup_local_alloc + ? static_cast(first_inst->setup_local_alloc.value) + : 0u; for (auto i = 0u; i != local_alloc_count; ++i) { auto index = frame_ptr->first_local_alloc + i; diff --git a/src/lauf/runtime/stack.hpp b/src/lauf/runtime/stack.hpp index e808ae9..6fcbcbf 100644 --- a/src/lauf/runtime/stack.hpp +++ b/src/lauf/runtime/stack.hpp @@ -12,6 +12,8 @@ #include //=== stack frame ===// +; // Resolves clangd bug: https://github.com/clangd/clangd/issues/1167 +#pragma pack(push, 8) struct lauf_runtime_stack_frame { // The current function. @@ -42,6 +44,7 @@ struct lauf_runtime_stack_frame return reinterpret_cast(this) + next_offset; } }; +#pragma pack(pop) static_assert(alignof(lauf_runtime_stack_frame) == alignof(void*)); //=== cstack ===// diff --git a/src/lauf/support/align.hpp b/src/lauf/support/align.hpp index 99b84ac..fc7ea89 100644 --- a/src/lauf/support/align.hpp +++ b/src/lauf/support/align.hpp @@ -4,6 +4,7 @@ #ifndef SRC_LAUF_SUPPORT_ALIGN_HPP_INCLUDED #define SRC_LAUF_SUPPORT_ALIGN_HPP_INCLUDED +#include #include #include @@ -17,7 +18,7 @@ constexpr bool is_valid_alignment(std::size_t alignment) noexcept constexpr std::uint8_t align_log2(std::size_t alignment) noexcept { assert(is_valid_alignment(alignment)); - return std::uint8_t(__builtin_ctzll(alignment)); + return std::uint8_t(std::countr_zero(alignment)); } constexpr std::size_t align_offset(std::uintptr_t address, std::size_t alignment) noexcept @@ -49,4 +50,3 @@ constexpr std::size_t round_to_multiple_of_alignment(std::size_t size, } // namespace lauf #endif // SRC_LAUF_SUPPORT_ALIGN_HPP_INCLUDED - diff --git a/src/lauf/support/array_list.hpp b/src/lauf/support/array_list.hpp index 7d6b54d..b30ac5a 100644 --- a/src/lauf/support/array_list.hpp +++ b/src/lauf/support/array_list.hpp @@ -31,8 +31,8 @@ class array_list array_list() : _first_block(nullptr), _cur_block(nullptr), _next_idx(0), _block_count(0) {} // For simplicity for now. - array_list(const array_list&) = delete; - array_list& operator=(const array_list&) = delete; + array_list(const array_list&) = default; + array_list& operator=(const array_list&) = default; // Arena takes care of deallaction. ~array_list() = default; @@ -306,4 +306,3 @@ class array_list } // namespace lauf #endif // SRC_LAUF_SUPPORT_ARRAY_LIST_HPP_INCLUDED - diff --git a/src/lauf/support/page_allocator.cpp b/src/lauf/support/page_allocator.cpp index 8fb4b73..a61b0cd 100644 --- a/src/lauf/support/page_allocator.cpp +++ b/src/lauf/support/page_allocator.cpp @@ -4,8 +4,19 @@ #include #include -#include -#include +#ifdef _WIN32 +# ifndef NOMINMAX +# define NOMINMAX +# endif +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# define MAP_FAILED ((void*)-1) +#else +# include +# include +#endif // #define LAUF_PAGE_ALLOCATOR_LOG #ifdef LAUF_PAGE_ALLOCATOR_LOG @@ -39,12 +50,18 @@ struct lauf::page_allocator::free_list_node namespace { const auto real_page_size = [] { +#ifdef _WIN32 + auto info = SYSTEM_INFO{}; + ::GetSystemInfo(&info); + auto result = static_cast(info.dwPageSize); +#else auto result = static_cast(::sysconf(_SC_PAGE_SIZE)); +#endif assert(lauf::page_allocator::page_size <= result); assert(result % lauf::page_allocator::page_size == 0); return result; }(); -} +} // namespace lauf::page_block lauf::page_allocator::allocate(std::size_t size) { @@ -67,8 +84,12 @@ lauf::page_block lauf::page_allocator::allocate(std::size_t size) return {cur, cur->size}; } - // Allocate new set of pages. +// Allocate new set of pages. +#ifdef _WIN32 + auto pages = VirtualAlloc(nullptr, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); +#else auto pages = ::mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); +#endif assert(pages != MAP_FAILED); // NOLINT: macro _allocated_bytes += size; @@ -85,7 +106,12 @@ std::size_t lauf::page_allocator::try_extend(page_block block, std::size_t new_s new_size = round_to_multiple_of_alignment(new_size, real_page_size); +#ifdef _WIN32 + // Windows does not support the functionality of mremap + auto ptr = MAP_FAILED; +#else auto ptr = ::mremap(block.ptr, block.size, new_size, 0); +#endif if (ptr == MAP_FAILED) // NOLINT: macro { LAUF_PAGE_ALLOCATOR_DO_LOG("try_extend({%p, %zu}, %zu): failed", block.ptr, block.size, @@ -127,7 +153,11 @@ std::size_t lauf::page_allocator::release() auto size = cur->size; auto next = cur->next; +#ifdef _WIN32 + VirtualFree(cur, 0, MEM_RELEASE); +#else ::munmap(cur, size); +#endif _allocated_bytes -= size; cur = next; diff --git a/src/lauf/vm_execute.cpp b/src/lauf/vm_execute.cpp index 3741b96..a19b125 100644 --- a/src/lauf/vm_execute.cpp +++ b/src/lauf/vm_execute.cpp @@ -214,7 +214,7 @@ LAUF_VM_EXECUTE(return_) } LAUF_VM_EXECUTE(return_free) { - for (auto i = 0u; i != ip->return_free.value; ++i) + for (auto i = 0u; i != static_cast(ip->return_free.value); ++i) { auto index = frame_ptr->first_local_alloc + i; auto& alloc = process->memory[index]; @@ -467,7 +467,7 @@ LAUF_VM_EXECUTE(fiber_suspend) LAUF_VM_EXECUTE(push) { --vstack_ptr; - vstack_ptr[0].as_uint = ip->push.value; + vstack_ptr[0].as_uint = static_cast(ip->push.value); ++ip; LAUF_VM_DISPATCH; @@ -504,7 +504,8 @@ LAUF_VM_EXECUTE(global_addr) LAUF_IGNORE_BITFIELD_WARNING( vstack_ptr[0].as_address.allocation - = get_global_allocation_idx(frame_ptr, process, ip->global_addr.value)); + = get_global_allocation_idx(frame_ptr, process, + static_cast(ip->global_addr.value))); vstack_ptr[0].as_address.offset = 0; vstack_ptr[0].as_address.generation = 0; // Always true for globals. @@ -671,7 +672,8 @@ LAUF_VM_EXECUTE(select) LAUF_VM_EXECUTE(setup_local_alloc) { // If necessary, grow the allocation array - this will then tail call back here. - if (LAUF_UNLIKELY(process->memory.needs_to_grow(ip->setup_local_alloc.value))) [[unlikely]] + if (LAUF_UNLIKELY(process->memory.needs_to_grow( + static_cast(ip->setup_local_alloc.value)))) [[unlikely]] LAUF_TAIL_CALL return grow_allocation_array(ip, vstack_ptr, frame_ptr, process); // Setup the necessary metadata. @@ -714,7 +716,7 @@ LAUF_VM_EXECUTE(local_alloc_aligned) } LAUF_VM_EXECUTE(local_storage) { - frame_ptr->next_offset += ip->local_storage.value; + frame_ptr->next_offset += static_cast(ip->local_storage.value); ++ip; LAUF_VM_DISPATCH; @@ -787,7 +789,7 @@ LAUF_VM_EXECUTE(array_element) LAUF_VM_EXECUTE(aggregate_member) { auto address = vstack_ptr[0].as_address; - address.offset += ip->aggregate_member.value; + address.offset += static_cast(ip->aggregate_member.value); vstack_ptr[0].as_address = address; ++ip; @@ -818,8 +820,10 @@ LAUF_VM_EXECUTE(store_local_value) LAUF_VM_EXECUTE(load_global_value) { - auto allocation = get_global_allocation_idx(frame_ptr, process, ip->load_global_value.value); - auto memory = process->memory[allocation].ptr; + auto allocation + = get_global_allocation_idx(frame_ptr, process, + static_cast(ip->load_global_value.value)); + auto memory = process->memory[allocation].ptr; --vstack_ptr; vstack_ptr[0] = *reinterpret_cast(memory); @@ -830,8 +834,10 @@ LAUF_VM_EXECUTE(load_global_value) LAUF_VM_EXECUTE(store_global_value) { - auto allocation = get_global_allocation_idx(frame_ptr, process, ip->store_global_value.value); - auto memory = process->memory[allocation].ptr; + auto allocation + = get_global_allocation_idx(frame_ptr, process, + static_cast(ip->store_global_value.value)); + auto memory = process->memory[allocation].ptr; *reinterpret_cast(memory) = vstack_ptr[0]; ++vstack_ptr; diff --git a/src/lauf/writer.cpp b/src/lauf/writer.cpp index eb0846c..1509f16 100644 --- a/src/lauf/writer.cpp +++ b/src/lauf/writer.cpp @@ -13,7 +13,10 @@ void lauf_writer::write(const char* str) write(str, std::strlen(str)); } -[[gnu::format(printf, 2, 3)]] void lauf_writer::format(const char* fmt, ...) +#if __has_cpp_attribute(gnu::format) +[[gnu::format(printf, 2, 3)]] +#endif +void lauf_writer::format(const char* fmt, ...) { constexpr auto small_buffer = 1024; char buffer[small_buffer + 1]; @@ -108,4 +111,3 @@ lauf_writer* lauf_create_stdout_writer(void) { return new file_writer(stdout); } - diff --git a/src/lauf/writer.hpp b/src/lauf/writer.hpp index 44a01dd..fa6573d 100644 --- a/src/lauf/writer.hpp +++ b/src/lauf/writer.hpp @@ -17,8 +17,10 @@ struct lauf_writer void write(const char* str); - [[gnu::format(printf, 2, 3)]] void format(const char* fmt, ...); +#if __has_cpp_attribute(gnu::format) + [[gnu::format(printf, 2, 3)]] +#endif + void format(const char* fmt, ...); }; #endif // SRC_LAUF_WRITER_HPP_INCLUDED -