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 Jul 21, 2024
1 parent ff04b07 commit 227931a
Show file tree
Hide file tree
Showing 19 changed files with 198 additions and 109 deletions.
57 changes: 48 additions & 9 deletions include/lauf/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,22 +36,61 @@ 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]]
#elif defined(__GNUC__) || defined(__GNUG__)
# 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_CONV_WARNING(...) \
_Pragma("GCC diagnostic push"); \
_Pragma("GCC diagnostic ignored \"-Wconversion\""); \
__VA_ARGS__; \
_Pragma("GCC diagnostic 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");
#else
# define LAUF_IGNORE_SIGN_WARNING(...) __VA_ARGS__
#endif

#endif // LAUF_CONFIG_H_INCLUDED
4 changes: 4 additions & 0 deletions include/lauf/runtime/builtin.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@

LAUF_HEADER_START

#if defined(__clang__)
#define LAUF_RUNTIME_BUILTIN_IMPL __attribute__((section("text.lauf_builtin"), aligned(8)))
#else
#define LAUF_RUNTIME_BUILTIN_IMPL
#endif

typedef union lauf_asm_inst lauf_asm_inst;
typedef struct lauf_asm_type lauf_asm_type;
Expand Down
12 changes: 6 additions & 6 deletions src/lauf/asm/builder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: BSL-1.0

#include <lauf/asm/builder.hpp>
#include <lauf/config.h>

#include <cstdio>
#include <cstdlib>
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
}
Expand Down Expand Up @@ -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
{
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
}

5 changes: 2 additions & 3 deletions src/lauf/asm/builder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ struct lauf_asm_builder : lauf::intrinsic_arena<lauf_asm_builder>
#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; \
Expand Down Expand Up @@ -315,7 +315,7 @@ 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; \
result.Name = {lauf::asm_op::Name, std::uint32_t(value)}; \
LAUF_IGNORE_BITFIELD_WARNING(result.Name = {lauf::asm_op::Name, std::uint32_t(value)}); \
if (value != result.Name.value) \
b->error(context, "invalid value"); \
return result; \
Expand All @@ -331,4 +331,3 @@ struct lauf_asm_builder : lauf::intrinsic_arena<lauf_asm_builder>
}(LAUF_BUILD_ASSERT_CONTEXT, Index)

#endif // SRC_LAUF_ASM_BUILDER_HPP_INCLUDED

39 changes: 25 additions & 14 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 = {", static_cast<unsigned>(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", static_cast<unsigned>(id), alignment);
_writer->format("data $data_%u = align %zu\n", to_underlying(id), alignment);
_writer->write("{\n");
}

Expand Down Expand Up @@ -157,8 +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(",
static_cast<unsigned>(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 @@ -175,7 +184,7 @@ class qbe_writer

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

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

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

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

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

void write_value(const qbe_value& value)
Expand All @@ -402,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", static_cast<unsigned>(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", static_cast<unsigned>(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 @@ -425,6 +433,8 @@ class qbe_writer
return "b";
case qbe_type::halfword:
return "h";
default:
LAUF_UNREACHABLE;
}
}

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

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

#endif // SRC_LAUF_BACKEND_QBE_HPP_INCLUDED

7 changes: 4 additions & 3 deletions src/lauf/frontend/text.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
});
};
Expand Down Expand Up @@ -846,4 +848,3 @@ lauf_asm_module* lauf_frontend_text(lauf_reader* reader, lauf_frontend_text_opti

return state.mod;
}

7 changes: 3 additions & 4 deletions src/lauf/lib/bits.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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");
Expand All @@ -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};

21 changes: 20 additions & 1 deletion src/lauf/lib/debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 __has_builtin(__builtin_debugtrap)
__builtin_debugtrap();
#elif __has_builtin(__debugbreak)
__debugbreak();
#elif defined(_MSC_VER)
__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;
}

Expand All @@ -157,4 +177,3 @@ LAUF_RUNTIME_BUILTIN(lauf_lib_debug_read, 0, 1,
}

const lauf_runtime_builtin_library lauf_lib_debug = {"lauf.debug", &lauf_lib_debug_read, nullptr};

Loading

0 comments on commit 227931a

Please sign in to comment.