Skip to content

Commit

Permalink
Improve MSVC support
Browse files Browse the repository at this point in the history
  • Loading branch information
Spartan322 committed Jul 29, 2024
1 parent b770424 commit 9d1e0a8
Show file tree
Hide file tree
Showing 16 changed files with 318 additions and 67 deletions.
83 changes: 78 additions & 5 deletions include/lauf/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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 <bit>
template <typename T>
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 <typename T>
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 <typename T>
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
10 changes: 7 additions & 3 deletions include/lauf/runtime/builtin.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -96,4 +101,3 @@ typedef struct lauf_runtime_builtin_library
LAUF_HEADER_END

#endif // LAUF_RUNTIME_BUILTIN_H_INCLUDED

10 changes: 6 additions & 4 deletions src/lauf/asm/builder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<lauf_asm_block>);

struct lauf_asm_local
{
Expand Down Expand Up @@ -260,14 +261,14 @@ struct lauf_asm_builder : lauf::intrinsic_arena<lauf_asm_builder>
#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)

Expand Down Expand Up @@ -315,8 +316,9 @@ struct lauf_asm_builder : lauf::intrinsic_arena<lauf_asm_builder>
#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::int32_t>(std::uint32_t(value))}); \
if (value != static_cast<std::size_t>(result.Name.value)) \
b->error(context, "invalid value"); \
return result; \
}(LAUF_BUILD_ASSERT_CONTEXT, Value)
Expand Down
124 changes: 119 additions & 5 deletions src/lauf/asm/instruction.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,129 @@ struct asm_inst_none
asm_op op;
};

#ifdef _MSC_VER
} // namespace lauf
# include <bit>
# include <concepts>

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<decltype(converter)>(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<std::int32_t>(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<std::int32_t>(converter);
}

template <typename T>
LAUF_FORCE_INLINE constexpr explicit operator T() const
{
return static_cast<T>(static_cast<int32_t>(*this));
}

template <std::unsigned_integral T>
LAUF_FORCE_INLINE constexpr explicit operator T() const
{
return static_cast<T>(static_cast<uint32_t>(*this));
}

LAUF_FORCE_INLINE constexpr _24bitint operator+() const
{
return *this;
}

LAUF_FORCE_INLINE constexpr _24bitint operator-() const
{
return _24bitint{-static_cast<std::int32_t>(*this)};
}

LAUF_FORCE_INLINE constexpr _24bitint operator~() const
{
return _24bitint{~static_cast<std::int32_t>(*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 <typename CurType, typename DestType>
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;
}

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -127,4 +242,3 @@ union lauf_asm_inst
};

#endif // SRC_LAUF_ASM_INSTRUCTION_HPP_INCLUDED

Loading

0 comments on commit 9d1e0a8

Please sign in to comment.