diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 6fe3d24..b6fb5a6 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -10,5 +10,5 @@ FetchContent_MakeAvailable(nanobench) add_executable(lauf_benchmark_chunk) target_sources(lauf_benchmark_chunk PRIVATE chunk.cpp) target_link_libraries(lauf_benchmark_chunk PRIVATE foonathan::lauf::core nanobench) -target_compile_features(lauf_benchmark_chunk PRIVATE cxx_std_17) +target_compile_features(lauf_benchmark_chunk PRIVATE cxx_std_20) diff --git a/include/lauf/config.h b/include/lauf/config.h index a978416..125f3f5 100644 --- a/include/lauf/config.h +++ b/include/lauf/config.h @@ -36,22 +36,134 @@ typedef uint64_t lauf_uint; # error "lauf assumes 8 bit bytes" #endif -#if !defined(__clang__) +/* #if !defined(__clang__) # error "lauf currently requires clang" -#endif +#endif */ //=== optimizations ===// -#define LAUF_LIKELY(Cond) __builtin_expect((Cond), 1) -#define LAUF_UNLIKELY(Cond) __builtin_expect((Cond), 0) -#define LAUF_TAIL_CALL [[clang::musttail]] -#define LAUF_NOINLINE [[gnu::noinline]] -#define LAUF_FORCE_INLINE [[gnu::always_inline]] -#define LAUF_UNREACHABLE __builtin_unreachable() +#define LAUF_LIKELY(Cond) Cond /*__builtin_expect((Cond), 1)*/ +#define LAUF_UNLIKELY(Cond) Cond /*__builtin_expect((Cond), 0)*/ +#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]] +#else +# define LAUF_TAIL_CALL +#endif +#if defined(_MSC_VER) +# define LAUF_NOINLINE __declspec(noinline) +# define LAUF_FORCE_INLINE __forceinline +# define LAUF_UNREACHABLE __assume(0) +#else +# define LAUF_NOINLINE [[gnu::noinline]] +# define LAUF_FORCE_INLINE [[gnu::always_inline]] inline +# define LAUF_UNREACHABLE __builtin_unreachable() +#endif //=== configurations ===// #ifndef LAUF_CONFIG_DISPATCH_JUMP_TABLE # define LAUF_CONFIG_DISPATCH_JUMP_TABLE 1 #endif -#endif // LAUF_CONFIG_H_INCLUDED +#if !defined(__clang__) && (defined(__GNUC__) || defined(__GNUG__)) +# define LAUF_IGNORE_BITFIELD_WARNING(...) \ + _Pragma("GCC diagnostic push"); \ + _Pragma("GCC diagnostic ignored \"-Wconversion\""); \ + __VA_ARGS__; \ + _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 + +#if !defined(__clang__) && (defined(__GNUC__) || defined(__GNUG__)) +# define LAUF_IGNORE_CONV_WARNING(...) \ + _Pragma("GCC diagnostic push"); \ + _Pragma("GCC diagnostic ignored \"-Wconversion\""); \ + __VA_ARGS__; \ + _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 +#if !defined(__clang__) && (defined(__GNUC__) || defined(__GNUG__)) +# define LAUF_IGNORE_SIGN_WARNING(...) \ + _Pragma("GCC diagnostic push"); \ + _Pragma("GCC diagnostic ignored \"-Wsign-conversion\""); \ + __VA_ARGS__; \ + _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 957c623..fbea30b 100644 --- a/include/lauf/runtime/builtin.h +++ b/include/lauf/runtime/builtin.h @@ -8,7 +8,15 @@ LAUF_HEADER_START -#define LAUF_RUNTIME_BUILTIN_IMPL __attribute__((section("text.lauf_builtin"), aligned(8))) +#if defined(__clang__) +# if defined(__APPLE__) && defined(__MACH__) +# define LAUF_RUNTIME_BUILTIN_IMPL __attribute__((section(".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 +#endif typedef union lauf_asm_inst lauf_asm_inst; typedef struct lauf_asm_type lauf_asm_type; @@ -92,4 +100,3 @@ typedef struct lauf_runtime_builtin_library LAUF_HEADER_END #endif // LAUF_RUNTIME_BUILTIN_H_INCLUDED - diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1545095..90a8281 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -29,7 +29,7 @@ endif() #=== Core library target ===# add_library(lauf_core) add_library(foonathan::lauf::core ALIAS lauf_core) -target_compile_features(lauf_core PRIVATE cxx_std_17) +target_compile_features(lauf_core PRIVATE cxx_std_20) target_include_directories(lauf_core SYSTEM INTERFACE ../include) target_include_directories(lauf_core PRIVATE ../include .) target_link_libraries(lauf_core PRIVATE lauf_warnings foonathan::lexy) @@ -133,7 +133,7 @@ target_sources(lauf_text PRIVATE ${src_dir}/frontend/text.cpp) add_library(lauf_qbe) add_library(foonathan::lauf::qbe ALIAS lauf_qbe) target_include_directories(lauf_qbe PRIVATE .) -target_compile_features(lauf_qbe PRIVATE cxx_std_17) +target_compile_features(lauf_qbe PRIVATE cxx_std_20) target_link_libraries(lauf_qbe PRIVATE lauf_warnings lauf_core) target_sources(lauf_qbe PUBLIC ${include_dir}/backend/qbe.h) diff --git a/src/lauf/asm/builder.cpp b/src/lauf/asm/builder.cpp index e244cdc..a403514 100644 --- a/src/lauf/asm/builder.cpp +++ b/src/lauf/asm/builder.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: BSL-1.0 #include +#include #include #include @@ -372,7 +373,7 @@ LAUF_NOINLINE lauf_asm_inst* emit_body(lauf_asm_inst* ip, lauf_asm_builder* b, assert(insts[dest->offset].op() == lauf::asm_op::block); auto dest_offset = dest->offset + 1; - jump->jump.offset = std::int32_t(dest_offset - cur_offset); + LAUF_IGNORE_BITFIELD_WARNING(jump->jump.offset = std::int32_t(dest_offset - cur_offset)); } return ip; @@ -437,7 +438,7 @@ void emit_debug_location(lauf_asm_builder* b) for (auto loc : block.debug_locations) { // We also have the initial block instruction that affects the inst_idx. - loc.inst_idx += block.offset + 1; + LAUF_IGNORE_CONV_WARNING(loc.inst_idx += block.offset + 1); cont.push_back(arena, loc); } } @@ -541,7 +542,7 @@ lauf_asm_local* lauf_asm_build_local(lauf_asm_builder* b, lauf_asm_layout layout // The offset is the current size, we don't need to worry about alignment. offset = std::uint16_t(b->local_allocation_size + sizeof(lauf_runtime_stack_frame)); - b->local_allocation_size += layout.size; + LAUF_IGNORE_CONV_WARNING(b->local_allocation_size += layout.size); } else { @@ -553,7 +554,7 @@ lauf_asm_local* lauf_asm_build_local(lauf_asm_builder* b, lauf_asm_layout layout // for a pointer. // Since `layout.alignment` is a multiple of it (as a power of two bigger than it), and // size a multiple of alignment, `layout.alignment + layout.size` is as well. - b->local_allocation_size += layout.alignment + layout.size; + LAUF_IGNORE_CONV_WARNING(b->local_allocation_size += layout.alignment + layout.size); // Since we don't know the exact alignment offset, we can't compute it statically. offset = UINT16_MAX; } @@ -1006,7 +1007,7 @@ void lauf_asm_inst_global_addr(lauf_asm_builder* b, const lauf_asm_global* globa b->cur->insts.push_back(*b, LAUF_BUILD_INST_VALUE(global_addr, global->allocation_idx)); b->cur->vstack.push_constant(*b, [&] { lauf_runtime_value result; - result.as_address.allocation = global->allocation_idx; + LAUF_IGNORE_BITFIELD_WARNING(result.as_address.allocation = global->allocation_idx); result.as_address.offset = 0; result.as_address.generation = 0; // Always true for globals. return result; @@ -1381,4 +1382,3 @@ void lauf_asm_inst_store_field(lauf_asm_builder* b, lauf_asm_type type, size_t f lauf_asm_inst_call_builtin(b, builtin); } } - diff --git a/src/lauf/asm/builder.hpp b/src/lauf/asm/builder.hpp index 946e739..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) @@ -282,7 +283,7 @@ struct lauf_asm_builder : lauf::intrinsic_arena #define LAUF_BUILD_INST_OFFSET(Name, Offset) \ [&](const char* context, std::ptrdiff_t offset) { \ lauf_asm_inst result; \ - result.Name = {lauf::asm_op::Name, std::int32_t(offset)}; \ + LAUF_IGNORE_BITFIELD_WARNING(result.Name = {lauf::asm_op::Name, std::int32_t(offset)}); \ if (result.Name.offset != offset) \ b->error(context, "offset too big"); \ return result; \ @@ -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; \ - 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) @@ -331,4 +333,3 @@ struct lauf_asm_builder : lauf::intrinsic_arena }(LAUF_BUILD_ASSERT_CONTEXT, Index) #endif // SRC_LAUF_ASM_BUILDER_HPP_INCLUDED - 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/backend/qbe.hpp b/src/lauf/backend/qbe.hpp index 0ea3f8b..31a06b4 100644 --- a/src/lauf/backend/qbe.hpp +++ b/src/lauf/backend/qbe.hpp @@ -5,12 +5,15 @@ #define SRC_LAUF_BACKEND_QBE_HPP_INCLUDED #include +#include #include #include #include +#include #include #include +#include #include namespace lauf @@ -80,6 +83,12 @@ enum class qbe_cc class qbe_writer { + template + constexpr std::underlying_type_t to_underlying(Enum e) noexcept + { + return static_cast>(e); + } + public: qbe_writer() : _writer(lauf_create_string_writer()) {} @@ -90,7 +99,7 @@ class qbe_writer { for (auto& [str, id] : _literals) { - out->format("data $lit_%u = {", static_cast(id)); + out->format("data $lit_%u = {", to_underlying(id)); for (auto c : str) out->format("b %d, ", c); out->write("}\n"); @@ -123,7 +132,7 @@ class qbe_writer //=== data ===// void begin_data(qbe_data id, std::size_t alignment) { - _writer->format("data $data_%u = align %zu\n", static_cast(id), alignment); + _writer->format("data $data_%u = align %zu\n", to_underlying(id), alignment); _writer->write("{\n"); } @@ -157,8 +166,8 @@ class qbe_writer else if (std::holds_alternative(ty)) _writer->format("function %s $%s(", type_name(std::get(ty)), name); else - _writer->format("function :tuple_%u $%s(", - static_cast(std::get(ty)), name); + _writer->format("function :tuple_%u $%s(", to_underlying(std::get(ty)), + name); } void param(qbe_type ty, std::size_t idx) @@ -175,7 +184,7 @@ class qbe_writer void block(qbe_block id) { - _writer->format("@block_%zu\n", static_cast(id)); + _writer->format("@block_%zu\n", to_underlying(id)); } void end_function() @@ -188,15 +197,14 @@ class qbe_writer //=== instructions ===// void jmp(qbe_block block) { - _writer->format(" jmp @block_%zu\n", static_cast(block)); + _writer->format(" jmp @block_%zu\n", to_underlying(block)); } void jnz(qbe_reg reg, qbe_block block1, qbe_block block2) { _writer->write(" jnz "); write_reg(reg); - _writer->format(", @block_%zu, @block_%zu\n", static_cast(block1), - static_cast(block2)); + _writer->format(", @block_%zu, @block_%zu\n", to_underlying(block1), to_underlying(block2)); } void ret() @@ -348,7 +356,7 @@ class qbe_writer else { write_reg(dest); - _writer->format(" =:tuple_%u call ", static_cast(std::get(ty))); + _writer->format(" =:tuple_%u call ", to_underlying(std::get(ty))); } write_value(fn); @@ -380,7 +388,7 @@ class qbe_writer if (a == qbe_alloc::return_) _writer->write("%return"); else - _writer->format("%%a%u", static_cast(a)); + _writer->format("%%a%u", to_underlying(a)); } void write_reg(qbe_reg reg) @@ -390,7 +398,7 @@ class qbe_writer else if (reg == qbe_reg::tmp2) _writer->write("%tmp2"); else - _writer->format("%%r%u", static_cast(reg)); + _writer->format("%%r%u", to_underlying(reg)); } void write_value(const qbe_value& value) @@ -402,9 +410,9 @@ class qbe_writer else if (std::holds_alternative(value)) _writer->format("%" PRIuMAX, std::get(value)); else if (std::holds_alternative(value)) - _writer->format("$data_%u", static_cast(std::get(value))); + _writer->format("$data_%u", to_underlying(std::get(value))); else if (std::holds_alternative(value)) - _writer->format("$lit_%u", static_cast(std::get(value))); + _writer->format("$lit_%u", to_underlying(std::get(value))); else _writer->format("$%s", std::get(value)); } @@ -425,6 +433,8 @@ class qbe_writer return "b"; case qbe_type::halfword: return "h"; + default: + LAUF_UNREACHABLE; } } @@ -452,6 +462,8 @@ class qbe_writer return "uge"; case qbe_cc::ugt: return "ugt"; + default: + LAUF_UNREACHABLE; } } @@ -462,4 +474,3 @@ class qbe_writer } // namespace lauf #endif // SRC_LAUF_BACKEND_QBE_HPP_INCLUDED - diff --git a/src/lauf/frontend/text.cpp b/src/lauf/frontend/text.cpp index c8c1f3c..02f9a2a 100644 --- a/src/lauf/frontend/text.cpp +++ b/src/lauf/frontend/text.cpp @@ -222,7 +222,7 @@ struct local_identifier struct signature { static constexpr auto rule = [] { - auto spec = dsl::integer >> LEXY_LIT("=>") + dsl::integer; + auto spec = dsl::integer >> (LEXY_LIT("=>") + dsl::integer); return dsl::parenthesized.opt(spec); }(); @@ -397,7 +397,7 @@ struct data_expr struct repetition { static constexpr auto rule = dsl::square_bracketed(dsl::recurse) - >> dsl::lit_c<'*'> + dsl::integer; + >> (dsl::lit_c<'*'> + dsl::integer); static constexpr auto value = lexy::callback([](const std::string& data, std::size_t n) { @@ -420,10 +420,10 @@ struct global_decl .map(LEXY_LIT("const"), LAUF_ASM_GLOBAL_READ_ONLY); static constexpr auto rule - = LAUF_KEYWORD("global") >> dsl::symbol + dsl::position(dsl::p) + = LAUF_KEYWORD("global") >> (dsl::symbol + dsl::position(dsl::p) + dsl::opt(dsl::colon >> dsl::p) + dsl::opt(dsl::equal_sign >> dsl::p) - + dsl::semicolon; + + dsl::semicolon); static constexpr auto value = callback( [](parse_state& state, lauf_asm_global_permissions perms, auto pos, const std::string& name, @@ -490,7 +490,7 @@ struct inst_jump }; struct inst_branch { - static constexpr auto rule = LAUF_KEYWORD("branch") >> dsl::p + dsl::p; + static constexpr auto rule = LAUF_KEYWORD("branch") >> (dsl::p + dsl::p); static constexpr auto value = inst(&lauf_asm_inst_branch); }; @@ -568,8 +568,8 @@ struct inst_cc struct inst_let { static constexpr auto rule - = LAUF_KEYWORD("let") >> dsl::position + dsl::p - + dsl::if_(dsl::equal_sign >> dsl::integer); + = LAUF_KEYWORD("let") >> (dsl::position + dsl::p + + dsl::if_(dsl::equal_sign >> dsl::integer)); static constexpr auto value = callback( [](parse_state& state, auto pos, const std::string& name, std::uint16_t idx = 0) { auto value = lauf_asm_inst_value(state.builder, idx); @@ -646,7 +646,7 @@ struct inst_aggregate_member }; static constexpr auto rule - = LAUF_KEYWORD("aggregate_member") >> dsl::p + dsl::integer; + = LAUF_KEYWORD("aggregate_member") >> (dsl::p + dsl::integer); static constexpr auto value = inst( [](lauf_asm_builder* b, const std::vector& members, std::size_t index) { lauf_asm_inst_aggregate_member(b, index, members.data(), members.size()); @@ -655,13 +655,13 @@ struct inst_aggregate_member struct inst_load_field { static constexpr auto rule - = LAUF_KEYWORD("load_field") >> dsl::p + dsl::integer; + = LAUF_KEYWORD("load_field") >> (dsl::p + dsl::integer); static constexpr auto value = inst(&lauf_asm_inst_load_field); }; struct inst_store_field { static constexpr auto rule - = LAUF_KEYWORD("store_field") >> dsl::p + dsl::integer; + = LAUF_KEYWORD("store_field") >> (dsl::p + dsl::integer); static constexpr auto value = inst(&lauf_asm_inst_store_field); }; @@ -670,8 +670,10 @@ struct location static constexpr auto rule = dsl::position; static constexpr auto value = callback([](parse_state& state, auto pos) { auto loc = lexy::get_input_location(state.input->buffer, pos, state.anchor); - lauf_asm_build_debug_location(state.builder, {0, std::uint16_t(loc.line_nr()), - std::uint16_t(loc.column_nr()), false, 0}); + LAUF_IGNORE_BITFIELD_WARNING( + lauf_asm_build_debug_location(state.builder, + {0, std::uint16_t(loc.line_nr()), + std::uint16_t(loc.column_nr()), false, 0})); state.anchor = loc.anchor(); }); }; @@ -694,7 +696,7 @@ struct instruction | dsl::p | dsl::p // | dsl::p | dsl::p; - return nested | dsl::else_ >> dsl::p + single + dsl::semicolon; + return nested | dsl::else_ >> (dsl::p + single + dsl::semicolon); }(); static constexpr auto value = lexy::forward; @@ -735,9 +737,9 @@ struct block struct local_decl { - static constexpr auto rule = LAUF_KEYWORD("local") >> dsl::position + dsl::p + static constexpr auto rule = LAUF_KEYWORD("local") >> (dsl::position + dsl::p + dsl::colon + dsl::p - + dsl::semicolon; + + dsl::semicolon); static constexpr auto value = callback( [](parse_state& state, auto pos, const std::string& name, lauf_asm_layout layout) { auto local = lauf_asm_build_local(state.builder, layout); @@ -790,7 +792,7 @@ struct function_decl auto locals = dsl::if_(dsl::list(dsl::p)); - return dsl::curly_bracketed.open() >> locals + (block_list | dsl::else_ >> inst_list); + return dsl::curly_bracketed.open() >> (locals + (block_list | dsl::else_ >> inst_list)); }(); static constexpr auto value = lexy::noop >> callback([](const parse_state& state) { @@ -798,9 +800,9 @@ struct function_decl }); }; - static constexpr auto rule = LAUF_KEYWORD("function") >> dsl::p
+ static constexpr auto rule = LAUF_KEYWORD("function") >> (dsl::p
+ dsl::if_(dsl::p) - + (dsl::semicolon | dsl::p); + + (dsl::semicolon | dsl::p)); static constexpr auto value = lexy::forward; }; @@ -846,4 +848,3 @@ lauf_asm_module* lauf_frontend_text(lauf_reader* reader, lauf_frontend_text_opti return state.mod; } - diff --git a/src/lauf/lib/bits.cpp b/src/lauf/lib/bits.cpp index 08e7f11..5198fd3 100644 --- a/src/lauf/lib/bits.cpp +++ b/src/lauf/lib/bits.cpp @@ -51,7 +51,7 @@ LAUF_RUNTIME_BUILTIN(lauf_lib_bits_shl, 2, 1, panic_flags, "shl", &lauf_lib_bits auto n = vstack_ptr[0].as_uint; ++vstack_ptr; - if (LAUF_UNLIKELY(n >= sizeof(lauf_uint) * CHAR_BIT)) + if (LAUF_UNLIKELY(n >= sizeof(lauf_uint) * CHAR_BIT)) [[unlikely]] return lauf_runtime_panic(process, "shift amount too big"); vstack_ptr[0].as_uint = x << n; @@ -64,7 +64,7 @@ LAUF_RUNTIME_BUILTIN(lauf_lib_bits_ushr, 2, 1, panic_flags, "ushr", &lauf_lib_bi auto n = vstack_ptr[0].as_uint; ++vstack_ptr; - if (LAUF_UNLIKELY(n >= sizeof(lauf_uint) * CHAR_BIT)) + if (LAUF_UNLIKELY(n >= sizeof(lauf_uint) * CHAR_BIT)) [[unlikely]] return lauf_runtime_panic(process, "shift amount too big"); vstack_ptr[0].as_uint = x >> n; @@ -77,7 +77,7 @@ LAUF_RUNTIME_BUILTIN(lauf_lib_bits_sshr, 2, 1, panic_flags, "sshr", &lauf_lib_bi auto n = vstack_ptr[0].as_uint; ++vstack_ptr; - if (LAUF_UNLIKELY(n >= sizeof(lauf_sint) * CHAR_BIT)) + if (LAUF_UNLIKELY(n >= sizeof(lauf_sint) * CHAR_BIT)) [[unlikely]] return lauf_runtime_panic(process, "shift amount too big"); static_assert(-1 >> 1 == -1, "compiler does not implement arithmetic right shift"); @@ -86,4 +86,3 @@ LAUF_RUNTIME_BUILTIN(lauf_lib_bits_sshr, 2, 1, panic_flags, "sshr", &lauf_lib_bi } const lauf_runtime_builtin_library lauf_lib_bits = {"lauf.bits", &lauf_lib_bits_sshr, nullptr}; - diff --git a/src/lauf/lib/debug.cpp b/src/lauf/lib/debug.cpp index 84148fa..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,7 +140,27 @@ 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 defined(_MSC_VER) + __debugbreak(); +#elif defined(__has_builtin) && __has_builtin(__builtin_debugtrap) __builtin_debugtrap(); +#elif defined(__has_builtin) && __has_builtin(__debugbreak) + __debugbreak(); +#elif defined(__ARMCC_VERSION) + __breakpoint(42) +#elif defined(__i386__) || defined(__x86_64__) + __asm__ __volatile__("int3"); +#elif defined(__thumb__) + __asm__ __volatile__(".inst 0xde01"); +#elif defined(__aarch64__) + __asm__ __volatile__(".inst 0xd4200000"); +#elif defined(__arm__) + __asm__ __volatile__(".inst 0xe7f001f0"); +#elif defined(__clang__) + __builtin_debugtrap(); +#elif defined(__STDC_HOSTED__) && (__STDC_HOSTED__ == 0) && defined(__GNUC__) + __builtin_trap(); +#endif LAUF_RUNTIME_BUILTIN_DISPATCH; } @@ -151,10 +171,11 @@ 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; } const lauf_runtime_builtin_library lauf_lib_debug = {"lauf.debug", &lauf_lib_debug_read, nullptr}; - diff --git a/src/lauf/lib/fiber.cpp b/src/lauf/lib/fiber.cpp index 5fed8bc..a87df06 100644 --- a/src/lauf/lib/fiber.cpp +++ b/src/lauf/lib/fiber.cpp @@ -13,7 +13,7 @@ LAUF_RUNTIME_BUILTIN(lauf_lib_fiber_create, 1, 1, LAUF_RUNTIME_BUILTIN_DEFAULT, auto address = vstack_ptr[0].as_function_address; auto fn = lauf_runtime_get_function_ptr_any(process, address); - if (LAUF_UNLIKELY(fn == nullptr)) + if (LAUF_UNLIKELY(fn == nullptr)) [[unlikely]] return lauf_runtime_panic(process, "invalid function address"); auto fiber = lauf_runtime_create_fiber(process, fn); @@ -29,10 +29,10 @@ LAUF_RUNTIME_BUILTIN(lauf_lib_fiber_destroy, 1, 0, LAUF_RUNTIME_BUILTIN_DEFAULT, ++vstack_ptr; auto fiber = lauf_runtime_get_fiber_ptr(process, handle); - if (LAUF_UNLIKELY(fiber == nullptr)) + if (LAUF_UNLIKELY(fiber == nullptr)) [[unlikely]] return lauf_runtime_panic(process, "invalid fiber handle"); - if (LAUF_UNLIKELY(!lauf_runtime_destroy_fiber(process, fiber))) + if (LAUF_UNLIKELY(!lauf_runtime_destroy_fiber(process, fiber))) [[unlikely]] return false; LAUF_RUNTIME_BUILTIN_DISPATCH; @@ -69,7 +69,7 @@ LAUF_RUNTIME_BUILTIN(lauf_lib_fiber_done, 1, 1, LAUF_RUNTIME_BUILTIN_DEFAULT, "d { auto handle = vstack_ptr[0].as_address; auto fiber = lauf_runtime_get_fiber_ptr(process, handle); - if (LAUF_UNLIKELY(fiber == nullptr)) + if (LAUF_UNLIKELY(fiber == nullptr)) [[unlikely]] return lauf_runtime_panic(process, "invalid fiber handle"); auto status = lauf_runtime_get_fiber_status(fiber); @@ -79,4 +79,3 @@ LAUF_RUNTIME_BUILTIN(lauf_lib_fiber_done, 1, 1, LAUF_RUNTIME_BUILTIN_DEFAULT, "d } const lauf_runtime_builtin_library lauf_lib_fiber = {"lauf.fiber", &lauf_lib_fiber_done, nullptr}; - diff --git a/src/lauf/lib/int.cpp b/src/lauf/lib/int.cpp index b3a18e0..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 @@ -22,6 +23,8 @@ return Name##_sat; \ case LAUF_LIB_INT_OVERFLOW_PANIC: \ return Name##_panic; \ + default: \ + LAUF_UNREACHABLE; \ } \ } @@ -538,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; @@ -670,4 +673,3 @@ LAUF_RUNTIME_BUILTIN(lauf_lib_int_u64_overflow, 1, 2, no_panic_flags, "u64_overf const lauf_runtime_builtin_library lauf_lib_int = {"lauf.int", &lauf_lib_int_u64_overflow, &lauf_lib_int_u64}; - diff --git a/src/lauf/lib/memory.cpp b/src/lauf/lib/memory.cpp index 0be9942..4ced865 100644 --- a/src/lauf/lib/memory.cpp +++ b/src/lauf/lib/memory.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2022-2023 Jonathan Müller and lauf contributors // SPDX-License-Identifier: BSL-1.0 +#include #include #include @@ -96,7 +97,7 @@ std::uint32_t addr_offset(lauf_runtime_address addr, lauf_sint offset) { lauf_sint result; auto overflow = __builtin_add_overflow(lauf_sint(addr.offset), offset, &result); - if (LAUF_UNLIKELY(overflow || result < 0 || result > UINT32_MAX)) + if (LAUF_UNLIKELY(overflow || result < 0 || result > UINT32_MAX)) [[unlikely]] result = UINT32_MAX; return std::uint32_t(result); @@ -209,6 +210,8 @@ lauf_runtime_builtin lauf_lib_memory_addr_add(lauf_lib_memory_addr_overflow over return addr_add_panic; case LAUF_LIB_MEMORY_ADDR_OVERFLOW_PANIC_STRICT: return addr_add_panic_strict; + default: + LAUF_UNREACHABLE; } } @@ -222,6 +225,8 @@ lauf_runtime_builtin lauf_lib_memory_addr_sub(lauf_lib_memory_addr_overflow over return addr_sub_panic; case LAUF_LIB_MEMORY_ADDR_OVERFLOW_PANIC_STRICT: return addr_sub_panic_strict; + default: + LAUF_UNREACHABLE; } } @@ -296,4 +301,3 @@ LAUF_RUNTIME_BUILTIN(lauf_lib_memory_cmp, 3, 1, LAUF_RUNTIME_BUILTIN_DEFAULT, "c } const lauf_runtime_builtin_library lauf_lib_memory = {"lauf.memory", &lauf_lib_memory_cmp, nullptr}; - diff --git a/src/lauf/runtime/memory.cpp b/src/lauf/runtime/memory.cpp index 25ff719..ae23a35 100644 --- a/src/lauf/runtime/memory.cpp +++ b/src/lauf/runtime/memory.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2022-2023 Jonathan Müller and lauf contributors // SPDX-License-Identifier: BSL-1.0 +#include #include #include @@ -126,7 +127,7 @@ bool lauf_runtime_get_address(lauf_runtime_process* p, lauf_runtime_address* all lauf_runtime_address lauf_runtime_get_global_address(lauf_runtime_process*, const lauf_asm_global* global) { - return {global->allocation_idx, 0, 0}; + LAUF_IGNORE_BITFIELD_WARNING(return {global->allocation_idx, 0, 0}); } const char* lauf_runtime_get_cstr(lauf_runtime_process* p, lauf_runtime_address addr) @@ -295,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) @@ -431,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 @@ -527,4 +528,3 @@ bool lauf_runtime_undeclare_weak(lauf_runtime_process* p, lauf_runtime_address a alloc->is_gc_weak = false; return true; } - diff --git a/src/lauf/runtime/memory.hpp b/src/lauf/runtime/memory.hpp index 9412d8c..e646917 100644 --- a/src/lauf/runtime/memory.hpp +++ b/src/lauf/runtime/memory.hpp @@ -40,6 +40,8 @@ constexpr bool is_const(allocation_source source) case allocation_source::local_memory: case allocation_source::heap_memory: return false; + default: + LAUF_UNREACHABLE; } } @@ -203,13 +205,13 @@ class memory { auto index = _allocations.size(); _allocations.push_back(allocator, alloc); - return {std::uint32_t(index), alloc.generation, 0}; + LAUF_IGNORE_BITFIELD_WARNING(return {std::uint32_t(index), alloc.generation, 0}); } lauf_runtime_address new_allocation_unchecked(allocation alloc) { auto index = _allocations.size(); _allocations.push_back_unchecked(alloc); - return {std::uint32_t(index), alloc.generation, 0}; + LAUF_IGNORE_BITFIELD_WARNING(return {std::uint32_t(index), alloc.generation, 0}); } allocation& operator[](std::size_t index) @@ -277,4 +279,3 @@ class memory } // namespace lauf #endif // LAUF_RUNTIME_MEMORY_HPP_INCLUDED - diff --git a/src/lauf/runtime/process.cpp b/src/lauf/runtime/process.cpp index 7002e43..2814b69 100644 --- a/src/lauf/runtime/process.cpp +++ b/src/lauf/runtime/process.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2022-2023 Jonathan Müller and lauf contributors // SPDX-License-Identifier: BSL-1.0 +#include #include #include @@ -90,7 +91,8 @@ LAUF_NOINLINE void lauf_runtime_process::do_cleanup(lauf_runtime_process* proces // We don't know the full size. vm->heap_allocator.free_alloc(vm->heap_allocator.user_data, alloc.ptr, 0); else - ; // We don't know the starting address of the allocation. + { // We don't know the starting address of the allocation. + } } else if (alloc.source == lauf::allocation_source::fiber_memory) { @@ -155,6 +157,8 @@ lauf_runtime_fiber_status lauf_runtime_get_fiber_status(const lauf_runtime_fiber return LAUF_RUNTIME_FIBER_SUSPENDED; case lauf_runtime_fiber::running: return LAUF_RUNTIME_FIBER_RUNNING; + default: + LAUF_UNREACHABLE; } } @@ -212,7 +216,7 @@ bool lauf_runtime_resume(lauf_runtime_process* process, lauf_runtime_fiber* fibe fiber->resume_by(nullptr); process->cur_fiber = fiber; - if (LAUF_UNLIKELY(fiber->expected_argument_count != input_count)) + if (LAUF_UNLIKELY(fiber->expected_argument_count != input_count)) [[unlikely]] return lauf_runtime_panic(process, "mismatched signature for fiber resume"); // We can't call fiber->transfer_arguments() as the order is different. @@ -225,7 +229,7 @@ bool lauf_runtime_resume(lauf_runtime_process* process, lauf_runtime_fiber* fibe auto success = lauf::execute(fiber->suspension_point.ip + 1, fiber->suspension_point.vstack_ptr, fiber->suspension_point.frame_ptr, process); - if (LAUF_LIKELY(success)) + if (LAUF_LIKELY(success)) [[likely]] { // fiber could have changed, so reset back to the current fiber. fiber = process->cur_fiber; @@ -234,7 +238,7 @@ bool lauf_runtime_resume(lauf_runtime_process* process, lauf_runtime_fiber* fibe { // Copy the final arguments. auto actual_output_count = fiber->root_function()->sig.output_count; - if (LAUF_UNLIKELY(actual_output_count != output_count)) + if (LAUF_UNLIKELY(actual_output_count != output_count)) [[unlikely]] return lauf_runtime_panic(process, "mismatched signature for fiber resume"); auto vstack_ptr = fiber->vstack.base() - actual_output_count; @@ -254,7 +258,7 @@ bool lauf_runtime_resume(lauf_runtime_process* process, lauf_runtime_fiber* fibe auto actual_output_count = fiber->suspension_point.ip->fiber_suspend.input_count; if (actual_output_count > 0) { - if (LAUF_UNLIKELY(actual_output_count != output_count)) + if (LAUF_UNLIKELY(actual_output_count != output_count)) [[unlikely]] return lauf_runtime_panic(process, "mismatched signature for fiber resume"); auto& vstack_ptr = fiber->suspension_point.vstack_ptr; @@ -277,6 +281,7 @@ bool lauf_runtime_resume_until_completion(lauf_runtime_process* process, lauf_ru // Resume the fiber at least once. if (LAUF_LIKELY(lauf_runtime_resume(process, fiber, input, input_count, output, output_count))) + [[likely]] { success = true; @@ -284,7 +289,7 @@ bool lauf_runtime_resume_until_completion(lauf_runtime_process* process, lauf_ru while (process->cur_fiber->status != lauf_runtime_fiber::done) { if (LAUF_UNLIKELY(!lauf_runtime_resume(process, process->cur_fiber, nullptr, 0, output, - output_count))) + output_count))) [[unlikely]] { success = false; break; @@ -302,7 +307,7 @@ bool lauf_runtime_resume_until_completion(lauf_runtime_process* process, lauf_ru bool lauf_runtime_destroy_fiber(lauf_runtime_process* process, lauf_runtime_fiber* fiber) { if (LAUF_UNLIKELY(fiber->status != lauf_runtime_fiber::done - && fiber->status != lauf_runtime_fiber::ready)) + && fiber->status != lauf_runtime_fiber::ready)) [[unlikely]] { assert(fiber->status == lauf_runtime_fiber::suspended); // The fiber is being canceled, which means we need to manually mark its local memory as @@ -313,17 +318,18 @@ 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; auto& alloc = process->memory[index]; assert(alloc.source == lauf::allocation_source::local_memory); assert(alloc.status != lauf::allocation_status::freed); - if (LAUF_UNLIKELY(alloc.split != lauf::allocation_split::unsplit)) + if (LAUF_UNLIKELY(alloc.split != lauf::allocation_split::unsplit)) [[unlikely]] return lauf_runtime_panic(process, "cannot free split allocation"); alloc.status = lauf::allocation_status::freed; @@ -386,4 +392,3 @@ bool lauf_runtime_increment_step(lauf_runtime_process* process) return true; } - diff --git a/src/lauf/runtime/stack.hpp b/src/lauf/runtime/stack.hpp index 93e165f..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 ===// @@ -117,7 +120,8 @@ class cstack { auto cur = _first; for (_first = nullptr; cur != nullptr; cur = chunk::deallocate(alloc, cur)) - {} + { + } } void* base() @@ -133,9 +137,9 @@ class cstack if (auto cur_chunk = chunk::chunk_of(frame_ptr); LAUF_UNLIKELY(frame_ptr->next_offset + callee->max_cstack_size - > cur_chunk->remaining_space(next_frame))) + > cur_chunk->remaining_space(next_frame))) [[unlikely]] { - if (LAUF_UNLIKELY(cur_chunk->next == nullptr)) + if (LAUF_UNLIKELY(cur_chunk->next == nullptr)) [[unlikely]] return nullptr; cur_chunk = cur_chunk->next; @@ -222,4 +226,3 @@ class vstack } // namespace lauf #endif // SRC_LAUF_RUNTIME_STACK_HPP_INCLUDED - diff --git a/src/lauf/runtime/stacktrace.cpp b/src/lauf/runtime/stacktrace.cpp index e15ca9f..4143b90 100644 --- a/src/lauf/runtime/stacktrace.cpp +++ b/src/lauf/runtime/stacktrace.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2022-2023 Jonathan Müller and lauf contributors // SPDX-License-Identifier: BSL-1.0 +#include #include #include @@ -28,6 +29,8 @@ lauf_runtime_stacktrace* lauf_runtime_get_stacktrace(lauf_runtime_process* p return new lauf_runtime_stacktrace{p->regs.frame_ptr, p->regs.ip}; case lauf_runtime_fiber::done: return nullptr; + default: + LAUF_UNREACHABLE; } } @@ -60,4 +63,3 @@ void lauf_runtime_destroy_stacktrace(lauf_runtime_stacktrace* st) { delete st; } - 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/arena.hpp b/src/lauf/support/arena.hpp index c1151fa..9a56ea9 100644 --- a/src/lauf/support/arena.hpp +++ b/src/lauf/support/arena.hpp @@ -67,7 +67,7 @@ class arena_base void* allocate(std::size_t size, std::size_t alignment) { - if (LAUF_UNLIKELY(size > block_size)) + if (LAUF_UNLIKELY(size > block_size)) [[unlikely]] { auto memory = ::operator new(size, std::align_val_t(alignment)); _extern_allocs @@ -77,9 +77,9 @@ class arena_base auto offset = align_offset(_cur_pos, alignment); auto remaining = std::size_t(_cur_block->end() - _cur_pos); - if (LAUF_UNLIKELY(offset + size > remaining)) + if (LAUF_UNLIKELY(offset + size > remaining)) [[unlikely]] { - if (LAUF_UNLIKELY(_cur_block->next == nullptr)) + if (LAUF_UNLIKELY(_cur_block->next == nullptr)) [[unlikely]] _cur_block->next = block::allocate(); _cur_block = _cur_block->next; @@ -241,4 +241,3 @@ struct arena : intrinsic_arena } // namespace lauf #endif // SRC_LAUF_SUPPORT_ARENA_HPP_INCLUDED - diff --git a/src/lauf/support/array.hpp b/src/lauf/support/array.hpp index 22db323..d9e9dc9 100644 --- a/src/lauf/support/array.hpp +++ b/src/lauf/support/array.hpp @@ -186,7 +186,7 @@ class array if (!_is_heap && arena.try_expand(_ptr, _capacity, new_capacity)) { - _capacity = new_capacity; + LAUF_IGNORE_BITFIELD_WARNING(_capacity = new_capacity); } else { @@ -195,9 +195,9 @@ class array if (_is_heap) ::operator delete(_ptr); - _ptr = static_cast(new_memory); - _capacity = new_capacity; - _is_heap = true; + _ptr = static_cast(new_memory); + LAUF_IGNORE_BITFIELD_WARNING(_capacity = new_capacity); + _is_heap = true; } } @@ -228,7 +228,7 @@ class array } else { - _capacity = extended_page_size / sizeof(T); + LAUF_IGNORE_BITFIELD_WARNING(_capacity = extended_page_size / sizeof(T)); } } } @@ -241,7 +241,7 @@ class array template void push_back(Allocator& alloc, const T& obj) { - if (LAUF_UNLIKELY(_size + 1 > _capacity)) + if (LAUF_UNLIKELY(_size + 1 > _capacity)) [[unlikely]] reserve(alloc, _size + 1); push_back_unchecked(obj); @@ -293,8 +293,8 @@ class array } void set_pages(page_block block) { - _ptr = static_cast(block.ptr); - _capacity = block.size / sizeof(T); + _ptr = static_cast(block.ptr); + LAUF_IGNORE_BITFIELD_WARNING(_capacity = block.size / sizeof(T)); } T* _ptr; @@ -305,4 +305,3 @@ class array } // namespace lauf #endif // SRC_LAUF_SUPPORT_ARRAY_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..1433a32 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); +#if defined(_WIN32) || (defined(__APPLE__) && defined(__MACH__)) + // Windows and Mac 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; @@ -135,4 +165,3 @@ std::size_t lauf::page_allocator::release() return _allocated_bytes; } - diff --git a/src/lauf/vm_execute.cpp b/src/lauf/vm_execute.cpp index 92b7e34..a19b125 100644 --- a/src/lauf/vm_execute.cpp +++ b/src/lauf/vm_execute.cpp @@ -1,6 +1,7 @@ // Copyright(C) 2022-2023 Jonathan Müller and lauf contributors // SPDX-License-Identifier: BSL-1.0 +#include #include #include @@ -73,6 +74,7 @@ LAUF_NOINLINE bool allocate_more_vstack_space(const lauf_asm_inst* ip, { process->cur_fiber->vstack.grow(process->vm->page_allocator, vstack_ptr); if (LAUF_UNLIKELY(process->cur_fiber->vstack.capacity() > process->vm->max_vstack_size)) + [[unlikely]] LAUF_DO_PANIC("vstack overflow"); LAUF_VM_DISPATCH; @@ -85,6 +87,7 @@ LAUF_NOINLINE bool allocate_more_cstack_space(const lauf_asm_inst* ip, { process->cur_fiber->cstack.grow(process->vm->page_allocator, frame_ptr); if (LAUF_UNLIKELY(process->cur_fiber->cstack.capacity() > process->vm->max_cstack_size)) + [[unlikely]] LAUF_DO_PANIC("cstack overflow"); LAUF_VM_DISPATCH; @@ -94,12 +97,12 @@ LAUF_NOINLINE bool allocate_more_cstack_space(const lauf_asm_inst* ip, { \ /* Check that we have enough space left on the vstack. */ \ if (auto remaining = vstack_ptr - process->cur_fiber->vstack.limit(); \ - LAUF_UNLIKELY(remaining < (Callee)->max_vstack_size)) \ + LAUF_UNLIKELY(remaining < (Callee)->max_vstack_size)) [[unlikely]] \ LAUF_TAIL_CALL return allocate_more_vstack_space(ip, vstack_ptr, frame_ptr, process); \ \ /* Create a new stack frame. */ \ auto new_frame = process->cur_fiber->cstack.new_call_frame(frame_ptr, (Callee), ip); \ - if (LAUF_UNLIKELY(new_frame == nullptr)) \ + if (LAUF_UNLIKELY(new_frame == nullptr)) [[unlikely]] \ LAUF_TAIL_CALL return allocate_more_cstack_space(ip, vstack_ptr, frame_ptr, process); \ \ /* And start executing the function. */ \ @@ -120,7 +123,7 @@ LAUF_NOINLINE bool call_undefined_function(const lauf_asm_inst* ip, lauf_runtime return extra == nullptr ? nullptr : extra->find_definition(callee); }(); - if (LAUF_UNLIKELY(definition == nullptr)) + if (LAUF_UNLIKELY(definition == nullptr)) [[unlikely]] { LAUF_DO_PANIC("calling undefined function"); } @@ -174,6 +177,7 @@ LAUF_FORCE_INLINE std::size_t get_global_allocation_idx(lauf_runtime_stack_frame std::size_t base_idx) { if (auto cur_mod = frame_ptr->function->module; LAUF_LIKELY(cur_mod == process->program._mod)) + [[likely]] { return base_idx; } @@ -210,12 +214,12 @@ 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]; - if (LAUF_UNLIKELY(alloc.split != lauf::allocation_split::unsplit)) + if (LAUF_UNLIKELY(alloc.split != lauf::allocation_split::unsplit)) [[unlikely]] LAUF_DO_PANIC("cannot free split allocation"); alloc.status = lauf::allocation_status::freed; @@ -263,7 +267,7 @@ LAUF_VM_EXECUTE(panic) LAUF_VM_EXECUTE(panic_if) { auto condition = vstack_ptr[1].as_uint; - if (LAUF_UNLIKELY(condition != 0)) + if (LAUF_UNLIKELY(condition != 0)) [[unlikely]] LAUF_TAIL_CALL return execute_panic(ip, vstack_ptr, frame_ptr, process); vstack_ptr += 2; @@ -273,7 +277,7 @@ LAUF_VM_EXECUTE(panic_if) LAUF_VM_EXECUTE(exit) { - if (LAUF_UNLIKELY(process == nullptr)) + if (LAUF_UNLIKELY(process == nullptr)) [[unlikely]] // During constant folding, we don't have a process, so check first. // We also don't have fibers, so just return. return true; @@ -294,7 +298,7 @@ LAUF_VM_EXECUTE(exit) { // Transfer values from our vstack. if (auto argument_count = std::uint8_t(cur_fiber->vstack.base() - vstack_ptr); - LAUF_UNLIKELY(!new_fiber->transfer_arguments(argument_count, vstack_ptr))) + LAUF_UNLIKELY(!new_fiber->transfer_arguments(argument_count, vstack_ptr))) [[unlikely]] LAUF_DO_PANIC("mismatched signature for fiber resume"); // Switch to parent fiber. @@ -340,7 +344,7 @@ LAUF_VM_EXECUTE(call) = lauf::uncompress_pointer_offset(frame_ptr->function, ip->call.offset); // Call an extern implementation if necessary. - if (LAUF_UNLIKELY(callee->insts == nullptr)) + if (LAUF_UNLIKELY(callee->insts == nullptr)) [[unlikely]] LAUF_TAIL_CALL return call_undefined_function(ip, vstack_ptr, frame_ptr, process); LAUF_DO_CALL(callee); @@ -353,7 +357,7 @@ LAUF_VM_EXECUTE(call_indirect) auto callee = lauf_runtime_get_function_ptr(process, ptr, {ip->call_indirect.input_count, ip->call_indirect.output_count}); - if (LAUF_UNLIKELY(callee == nullptr)) + if (LAUF_UNLIKELY(callee == nullptr)) [[unlikely]] LAUF_DO_PANIC("invalid function address"); LAUF_DO_CALL(callee); @@ -370,12 +374,12 @@ LAUF_VM_EXECUTE(fiber_resume) auto fiber = lauf::get_fiber(process, handle); if (LAUF_UNLIKELY(fiber == nullptr || (fiber->status != lauf_runtime_fiber::suspended - && fiber->status != lauf_runtime_fiber::ready))) + && fiber->status != lauf_runtime_fiber::ready))) [[unlikely]] LAUF_DO_PANIC("invalid fiber handle"); // Transfer values from our vstack. if (auto argument_count = ip->fiber_resume.input_count; - LAUF_UNLIKELY(!fiber->transfer_arguments(argument_count, vstack_ptr))) + LAUF_UNLIKELY(!fiber->transfer_arguments(argument_count, vstack_ptr))) [[unlikely]] LAUF_DO_PANIC("mismatched signature for fiber resume"); // Remove handle from stack. ++vstack_ptr; @@ -399,12 +403,12 @@ LAUF_VM_EXECUTE(fiber_transfer) auto fiber = lauf::get_fiber(process, handle); if (LAUF_UNLIKELY(fiber == nullptr || (fiber->status != lauf_runtime_fiber::suspended - && fiber->status != lauf_runtime_fiber::ready))) + && fiber->status != lauf_runtime_fiber::ready))) [[unlikely]] LAUF_DO_PANIC("invalid fiber handle"); // Transfer values from our vstack. if (auto argument_count = ip->fiber_resume.input_count; - LAUF_UNLIKELY(!fiber->transfer_arguments(argument_count, vstack_ptr))) + LAUF_UNLIKELY(!fiber->transfer_arguments(argument_count, vstack_ptr))) [[unlikely]] LAUF_DO_PANIC("mismatched signature for fiber resume"); // Remove handle from stack. ++vstack_ptr; @@ -427,7 +431,7 @@ LAUF_VM_EXECUTE(fiber_suspend) assert(process->cur_fiber->status == lauf_runtime_fiber::running); auto cur_fiber = process->cur_fiber; - if (LAUF_UNLIKELY(!cur_fiber->has_parent())) + if (LAUF_UNLIKELY(!cur_fiber->has_parent())) [[unlikely]] { // We're suspending the main fiber, so return instead. cur_fiber->suspend({ip, vstack_ptr, frame_ptr}, ip->fiber_suspend.output_count); @@ -437,12 +441,12 @@ LAUF_VM_EXECUTE(fiber_suspend) else { auto new_fiber = lauf::get_fiber(process, cur_fiber->parent); - if (LAUF_UNLIKELY(new_fiber == nullptr)) + if (LAUF_UNLIKELY(new_fiber == nullptr)) [[unlikely]] LAUF_DO_PANIC("cannot suspend to destroyed parent"); // Transfer values from our vstack. if (auto argument_count = ip->fiber_suspend.input_count; - LAUF_UNLIKELY(!new_fiber->transfer_arguments(argument_count, vstack_ptr))) + LAUF_UNLIKELY(!new_fiber->transfer_arguments(argument_count, vstack_ptr))) [[unlikely]] LAUF_DO_PANIC("mismatched signature for fiber resume"); // We resume the parent but without setting its parent (asymmetric). @@ -463,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; @@ -498,8 +502,10 @@ LAUF_VM_EXECUTE(global_addr) { --vstack_ptr; - vstack_ptr[0].as_address.allocation - = get_global_allocation_idx(frame_ptr, process, ip->global_addr.value); + LAUF_IGNORE_BITFIELD_WARNING( + vstack_ptr[0].as_address.allocation + = 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. @@ -526,7 +532,8 @@ LAUF_VM_EXECUTE(local_addr) auto allocation_idx = frame_ptr->first_local_alloc + ip->local_addr.index; --vstack_ptr; - vstack_ptr[0].as_address.allocation = std::uint32_t(allocation_idx); + LAUF_IGNORE_BITFIELD_WARNING(vstack_ptr[0].as_address.allocation + = std::uint32_t(allocation_idx)); vstack_ptr[0].as_address.offset = 0; vstack_ptr[0].as_address.generation = frame_ptr->local_generation; @@ -650,7 +657,7 @@ LAUF_VM_EXECUTE(select) auto idx = vstack_ptr[0].as_uint; ++vstack_ptr; - if (LAUF_UNLIKELY(idx > ip->select.idx)) + if (LAUF_UNLIKELY(idx > ip->select.idx)) [[unlikely]] LAUF_DO_PANIC("invalid select index"); auto value = vstack_ptr[idx]; @@ -665,12 +672,13 @@ 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))) + 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. - frame_ptr->first_local_alloc = process->memory.next_index(); - frame_ptr->local_generation = process->memory.cur_generation(); + LAUF_IGNORE_BITFIELD_WARNING(frame_ptr->first_local_alloc = process->memory.next_index()); + LAUF_IGNORE_BITFIELD_WARNING(frame_ptr->local_generation = process->memory.cur_generation()); ++ip; LAUF_VM_DISPATCH; @@ -697,7 +705,8 @@ LAUF_VM_EXECUTE(local_alloc_aligned) memory += lauf::align_offset(memory, ip->local_alloc_aligned.alignment()); // However, to increment the offset we need both alignment and size, as that was the offset // computation assumed in the builder. - frame_ptr->next_offset += ip->local_alloc_aligned.alignment() + ip->local_alloc.size; + LAUF_IGNORE_BITFIELD_WARNING(frame_ptr->next_offset + += ip->local_alloc_aligned.alignment() + ip->local_alloc.size); process->memory.new_allocation_unchecked( lauf::make_local_alloc(memory, ip->local_alloc.size, frame_ptr->local_generation)); @@ -707,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; @@ -718,13 +727,13 @@ LAUF_VM_EXECUTE(deref_const) auto address = vstack_ptr[0].as_address; auto alloc = process->memory.try_get(address); - if (LAUF_UNLIKELY(alloc == nullptr)) + if (LAUF_UNLIKELY(alloc == nullptr)) [[unlikely]] goto panic; { auto ptr = lauf::checked_offset(*alloc, address, {ip->deref_const.size, ip->deref_const.alignment()}); - if (LAUF_UNLIKELY(ptr == nullptr)) + if (LAUF_UNLIKELY(ptr == nullptr)) [[unlikely]] goto panic; vstack_ptr[0].as_native_ptr = const_cast(ptr); @@ -743,12 +752,13 @@ LAUF_VM_EXECUTE(deref_mut) auto alloc = process->memory.try_get(address); if (LAUF_UNLIKELY(alloc == nullptr) || LAUF_UNLIKELY(lauf::is_const(alloc->source))) + [[unlikely]] goto panic; { auto ptr = lauf::checked_offset(*alloc, address, {ip->deref_mut.size, ip->deref_mut.alignment()}); - if (LAUF_UNLIKELY(ptr == nullptr)) + if (LAUF_UNLIKELY(ptr == nullptr)) [[unlikely]] goto panic; vstack_ptr[0].as_native_ptr = const_cast(ptr); @@ -766,7 +776,8 @@ LAUF_VM_EXECUTE(array_element) auto address = vstack_ptr[1].as_address; auto index = vstack_ptr[0].as_sint; - address.offset += lauf_sint(ip->array_element.value) * index; + LAUF_IGNORE_BITFIELD_WARNING( + LAUF_IGNORE_SIGN_WARNING(address.offset += lauf_sint(ip->array_element.value) * index)); ++vstack_ptr; vstack_ptr[0].as_address = address; @@ -778,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; @@ -809,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); @@ -821,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; @@ -830,4 +845,3 @@ LAUF_VM_EXECUTE(store_global_value) ++ip; LAUF_VM_DISPATCH; } - 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 - diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index fe8d44d..6376517 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -10,7 +10,7 @@ FetchContent_MakeAvailable(doctest) add_library(lauf_test_base ${CMAKE_CURRENT_SOURCE_DIR}/doctest_main.cpp) target_link_libraries(lauf_test_base PUBLIC foonathan::lauf lauf_warnings doctest) target_include_directories(lauf_test_base PUBLIC ../src) -target_compile_features(lauf_test_base PUBLIC cxx_std_17) +target_compile_features(lauf_test_base PUBLIC cxx_std_20) #=== Interface compile check target. ===# add_library(lauf_interface_check OBJECT all.c) diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index c01b4db..f527d1e 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -3,11 +3,11 @@ add_executable(lauf_tool_interpreter interpreter.cpp) target_link_libraries(lauf_tool_interpreter PRIVATE foonathan::lauf::core foonathan::lauf::text lauf_warnings) -target_compile_features(lauf_tool_interpreter PRIVATE cxx_std_17) +target_compile_features(lauf_tool_interpreter PRIVATE cxx_std_20) set_target_properties(lauf_tool_interpreter PROPERTIES OUTPUT_NAME "lauf") add_executable(lauf_tool_qbe qbe.cpp) target_link_libraries(lauf_tool_qbe PRIVATE foonathan::lauf::core foonathan::lauf::text foonathan::lauf::qbe lauf_warnings) -target_compile_features(lauf_tool_qbe PRIVATE cxx_std_17) +target_compile_features(lauf_tool_qbe PRIVATE cxx_std_20) set_target_properties(lauf_tool_qbe PROPERTIES OUTPUT_NAME "lauf-qbe")