Skip to content

Commit

Permalink
Add GCC support
Browse files Browse the repository at this point in the history
Add MSVC support
  • Loading branch information
Spartan322 committed Nov 3, 2023
1 parent fe4a48d commit f10b05e
Show file tree
Hide file tree
Showing 10 changed files with 135 additions and 77 deletions.
47 changes: 38 additions & 9 deletions include/lauf/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,22 +36,51 @@ 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(__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");
#else
# define LAUF_IGNORE_BITFIELD_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");
#else
# define LAUF_IGNORE_SIGN_WARNING(...) __VA_ARGS__
#endif

#endif // LAUF_CONFIG_H_INCLUDED
37 changes: 25 additions & 12 deletions src/lauf/backend/qbe.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@
#define SRC_LAUF_BACKEND_QBE_HPP_INCLUDED

#include <lauf/backend/qbe.h>
#include <lauf/config.h>

#include <cinttypes>
#include <lauf/writer.hpp>
#include <string>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <variant>

namespace lauf
Expand Down Expand Up @@ -80,6 +83,12 @@ enum class qbe_cc

class qbe_writer
{
template <class Enum>
constexpr std::underlying_type_t<Enum> to_underlying(Enum e) noexcept
{
return static_cast<std::underlying_type_t<Enum>>(e);
}

public:
qbe_writer() : _writer(lauf_create_string_writer()) {}

Expand All @@ -90,7 +99,7 @@ class qbe_writer
{
for (auto& [str, id] : _literals)
{
out->format("data $lit_%u = {", id);
out->format("data $lit_%u = {", to_underlying(id));
for (auto c : str)
out->format("b %d, ", c);
out->write("}\n");
Expand Down Expand Up @@ -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", id, alignment);
_writer->format("data $data_%u = align %zu\n", to_underlying(id), alignment);
_writer->write("{\n");
}

Expand Down Expand Up @@ -157,7 +166,8 @@ class qbe_writer
else if (std::holds_alternative<qbe_type>(ty))
_writer->format("function %s $%s(", type_name(std::get<qbe_type>(ty)), name);
else
_writer->format("function :tuple_%u $%s(", std::get<qbe_tuple>(ty), name);
_writer->format("function :tuple_%u $%s(", to_underlying(std::get<qbe_tuple>(ty)),
name);
}

void param(qbe_type ty, std::size_t idx)
Expand All @@ -174,7 +184,7 @@ class qbe_writer

void block(qbe_block id)
{
_writer->format("@block_%zu\n", id);
_writer->format("@block_%zu\n", to_underlying(id));
}

void end_function()
Expand All @@ -187,14 +197,14 @@ class qbe_writer
//=== instructions ===//
void jmp(qbe_block block)
{
_writer->format(" jmp @block_%zu\n", 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", block1, block2);
_writer->format(", @block_%zu, @block_%zu\n", to_underlying(block1), to_underlying(block2));
}

void ret()
Expand Down Expand Up @@ -346,7 +356,7 @@ class qbe_writer
else
{
write_reg(dest);
_writer->format(" =:tuple_%u call ", std::get<qbe_tuple>(ty));
_writer->format(" =:tuple_%u call ", to_underlying(std::get<qbe_tuple>(ty)));
}

write_value(fn);
Expand Down Expand Up @@ -378,7 +388,7 @@ class qbe_writer
if (a == qbe_alloc::return_)
_writer->write("%return");
else
_writer->format("%%a%u", a);
_writer->format("%%a%u", to_underlying(a));
}

void write_reg(qbe_reg reg)
Expand All @@ -388,7 +398,7 @@ class qbe_writer
else if (reg == qbe_reg::tmp2)
_writer->write("%tmp2");
else
_writer->format("%%r%u", reg);
_writer->format("%%r%u", to_underlying(reg));
}

void write_value(const qbe_value& value)
Expand All @@ -400,9 +410,9 @@ class qbe_writer
else if (std::holds_alternative<std::uintmax_t>(value))
_writer->format("%" PRIuMAX, std::get<std::uintmax_t>(value));
else if (std::holds_alternative<qbe_data>(value))
_writer->format("$data_%u", std::get<qbe_data>(value));
_writer->format("$data_%u", to_underlying(std::get<qbe_data>(value)));
else if (std::holds_alternative<qbe_literal>(value))
_writer->format("$lit_%u", std::get<qbe_literal>(value));
_writer->format("$lit_%u", to_underlying(std::get<qbe_literal>(value)));
else
_writer->format("$%s", std::get<const char*>(value));
}
Expand All @@ -423,6 +433,8 @@ class qbe_writer
return "b";
case qbe_type::halfword:
return "h";
default:
LAUF_UNREACHABLE;
}
}

Expand Down Expand Up @@ -450,6 +462,8 @@ class qbe_writer
return "uge";
case qbe_cc::ugt:
return "ugt";
default:
LAUF_UNREACHABLE;
}
}

Expand All @@ -460,4 +474,3 @@ class qbe_writer
} // namespace lauf

#endif // SRC_LAUF_BACKEND_QBE_HPP_INCLUDED

3 changes: 2 additions & 1 deletion src/lauf/lib/int.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
return Name##_sat; \
case LAUF_LIB_INT_OVERFLOW_PANIC: \
return Name##_panic; \
default: \
LAUF_UNREACHABLE; \
} \
}

Expand Down Expand Up @@ -670,4 +672,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};

6 changes: 5 additions & 1 deletion src/lauf/lib/memory.cpp
Original file line number Diff line number Diff line change
@@ -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 <lauf/lib/memory.h>

#include <cstring>
Expand Down Expand Up @@ -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;
}
}

Expand All @@ -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;
}
}

Expand Down Expand Up @@ -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};

7 changes: 4 additions & 3 deletions src/lauf/runtime/memory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -277,4 +279,3 @@ class memory
} // namespace lauf

#endif // LAUF_RUNTIME_MEMORY_HPP_INCLUDED

22 changes: 13 additions & 9 deletions src/lauf/runtime/process.cpp
Original file line number Diff line number Diff line change
@@ -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 <lauf/runtime/process.hpp>

#include <lauf/vm.hpp>
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -150,6 +152,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;
}
}

Expand Down Expand Up @@ -207,7 +211,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.
Expand All @@ -220,7 +224,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;
Expand All @@ -229,7 +233,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;
Expand All @@ -249,7 +253,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;
Expand All @@ -272,14 +276,15 @@ 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;

// Then we repeatedly resume the current fiber until it is done.
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;
Expand All @@ -297,7 +302,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
Expand All @@ -318,7 +323,7 @@ bool lauf_runtime_destroy_fiber(lauf_runtime_process* process, lauf_runtime_fibe
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;
Expand Down Expand Up @@ -381,4 +386,3 @@ bool lauf_runtime_increment_step(lauf_runtime_process* process)

return true;
}

Loading

0 comments on commit f10b05e

Please sign in to comment.