Skip to content

Commit

Permalink
Add lauf_asm_value to have a stable reference to a stack value
Browse files Browse the repository at this point in the history
  • Loading branch information
foonathan committed Apr 13, 2024
1 parent 21f96a6 commit ff04b07
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 32 deletions.
14 changes: 14 additions & 0 deletions include/lauf/asm/builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ typedef struct lauf_asm_type lauf_asm_type;
typedef struct lauf_asm_layout lauf_asm_layout;
typedef struct lauf_runtime_builtin lauf_runtime_builtin_function;

typedef struct lauf_asm_value
{
uint32_t _id;
} lauf_asm_value;

typedef enum lauf_asm_inst_condition_code
{
LAUF_ASM_INST_CC_EQ,
Expand Down Expand Up @@ -249,6 +254,15 @@ void lauf_asm_inst_layout(lauf_asm_builder* b, lauf_asm_layout layout);
void lauf_asm_inst_cc(lauf_asm_builder* b, lauf_asm_inst_condition_code cc);

//=== stack manipulation instructions ===//
/// Returns a stable id for the value at the given stack idx.
/// As long as the corresponding value remains on the stack, it can be referenced using that id,
/// even if it is shifted around on the stack due to other stack manipulation instructions.
lauf_asm_value lauf_asm_inst_value(lauf_asm_builder* b, uint16_t stack_index);

/// Returns the stack index of the value with the given id.
/// The value must still be on the stack.
uint16_t lauf_asm_inst_value_stack_index(lauf_asm_builder* b, lauf_asm_value value);

/// Pops the Nth value of the stack.
///
/// Signature: x_N+1 x_N x_N-1 ... x_0 => x_N+1 x_N-1 ... x_0
Expand Down
62 changes: 42 additions & 20 deletions src/lauf/asm/builder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -740,7 +740,7 @@ void lauf_asm_inst_call(lauf_asm_builder* b, const lauf_asm_function* callee)
auto offset = lauf::compress_pointer_offset(b->fn, callee);
b->cur->insts.push_back(*b, LAUF_BUILD_INST_OFFSET(call, offset));

b->cur->vstack.push(*b, callee->sig.output_count);
b->cur->vstack.push_output(*b, callee->sig.output_count);
}

namespace
Expand Down Expand Up @@ -784,7 +784,7 @@ void lauf_asm_inst_call_indirect(lauf_asm_builder* b, lauf_asm_signature sig)
sig.output_count, 0));
}

b->cur->vstack.push(*b, sig.output_count);
b->cur->vstack.push_output(*b, sig.output_count);
}

namespace
Expand All @@ -801,7 +801,7 @@ void add_call_builtin(lauf_asm_builder* b, lauf_runtime_builtin_function callee)
b->cur->insts.push_back(*b, LAUF_BUILD_INST_SIGNATURE(call_builtin_sig, callee.input_count,
callee.output_count, callee.flags));

b->cur->vstack.push(*b, callee.output_count);
b->cur->vstack.push_output(*b, callee.output_count);
}
} // namespace

Expand Down Expand Up @@ -910,7 +910,7 @@ void lauf_asm_inst_fiber_resume(lauf_asm_builder* b, lauf_asm_signature sig)
LAUF_BUILD_ASSERT(b->cur->vstack.pop(), "missing handle");
b->cur->insts.push_back(*b, LAUF_BUILD_INST_SIGNATURE(fiber_resume, sig.input_count,
sig.output_count, 0));
b->cur->vstack.push(*b, sig.output_count);
b->cur->vstack.push_output(*b, sig.output_count);
}

void lauf_asm_inst_fiber_transfer(lauf_asm_builder* b, lauf_asm_signature sig)
Expand All @@ -921,7 +921,7 @@ void lauf_asm_inst_fiber_transfer(lauf_asm_builder* b, lauf_asm_signature sig)
LAUF_BUILD_ASSERT(b->cur->vstack.pop(), "missing handle");
b->cur->insts.push_back(*b, LAUF_BUILD_INST_SIGNATURE(fiber_transfer, sig.input_count,
sig.output_count, 0));
b->cur->vstack.push(*b, sig.output_count);
b->cur->vstack.push_output(*b, sig.output_count);
}

void lauf_asm_inst_fiber_suspend(lauf_asm_builder* b, lauf_asm_signature sig)
Expand All @@ -931,7 +931,7 @@ void lauf_asm_inst_fiber_suspend(lauf_asm_builder* b, lauf_asm_signature sig)
LAUF_BUILD_ASSERT(b->cur->vstack.pop(sig.input_count), "missing inputs");
b->cur->insts.push_back(*b, LAUF_BUILD_INST_SIGNATURE(fiber_suspend, sig.input_count,
sig.output_count, 0));
b->cur->vstack.push(*b, sig.output_count);
b->cur->vstack.push_output(*b, sig.output_count);
}

void lauf_asm_inst_uint(lauf_asm_builder* b, lauf_uint value)
Expand Down Expand Up @@ -966,7 +966,7 @@ void lauf_asm_inst_uint(lauf_asm_builder* b, lauf_uint value)
b->cur->insts.push_back(*b, LAUF_BUILD_INST_VALUE(push3, value >> 48));
}

b->cur->vstack.push(*b, [&] {
b->cur->vstack.push_constant(*b, [&] {
lauf_runtime_value result;
result.as_uint = value;
return result;
Expand Down Expand Up @@ -996,15 +996,15 @@ void lauf_asm_inst_null(lauf_asm_builder* b)

// NULL has all bits set.
b->cur->insts.push_back(*b, LAUF_BUILD_INST_VALUE(pushn, 0));
b->cur->vstack.push(*b, lauf_runtime_value{});
b->cur->vstack.push_constant(*b, lauf_runtime_value{});
}

void lauf_asm_inst_global_addr(lauf_asm_builder* b, const lauf_asm_global* global)
{
LAUF_BUILD_CHECK_CUR;

b->cur->insts.push_back(*b, LAUF_BUILD_INST_VALUE(global_addr, global->allocation_idx));
b->cur->vstack.push(*b, [&] {
b->cur->vstack.push_constant(*b, [&] {
lauf_runtime_value result;
result.as_address.allocation = global->allocation_idx;
result.as_address.offset = 0;
Expand Down Expand Up @@ -1034,7 +1034,7 @@ void lauf_asm_inst_function_addr(lauf_asm_builder* b, const lauf_asm_function* f

auto offset = lauf::compress_pointer_offset(b->fn, function);
b->cur->insts.push_back(*b, LAUF_BUILD_INST_OFFSET(function_addr, offset));
b->cur->vstack.push(*b, [&] {
b->cur->vstack.push_constant(*b, [&] {
lauf_runtime_value result;
result.as_function_address.index = function->function_idx;
result.as_function_address.input_count = function->sig.input_count;
Expand Down Expand Up @@ -1101,15 +1101,37 @@ void lauf_asm_inst_cc(lauf_asm_builder* b, lauf_asm_inst_condition_code cc)

add_pop_top_n(b, 1);
b->cur->insts.push_back(*b, LAUF_BUILD_INST_VALUE(push, value.as_uint));
b->cur->vstack.push(*b, value);
b->cur->vstack.push_constant(*b, value);
}
else
{
b->cur->insts.push_back(*b, LAUF_BUILD_INST_VALUE(cc, unsigned(cc)));
b->cur->vstack.push(*b, 1);
b->cur->vstack.push_output(*b, 1);
}
}

lauf_asm_value lauf_asm_inst_value(lauf_asm_builder* b, uint16_t stack_index)
{
if (LAUF_UNLIKELY(b->cur == nullptr))
return lauf::invalid_asm_value;
LAUF_BUILD_ASSERT(stack_index < b->cur->vstack.size(), "invalid stack index");

auto& id = b->cur->vstack.id(stack_index);
if (id == lauf::invalid_asm_value)
id = b->allocate_value_id();
return id;
}

uint16_t lauf_asm_inst_value_stack_index(lauf_asm_builder* b, lauf_asm_value value)
{
if (LAUF_UNLIKELY(b->cur == nullptr))
return UINT16_MAX;

auto idx = b->cur->vstack.find_stack_idx_of(value);
LAUF_BUILD_ASSERT(idx, "value is already popped from the stack");
return *idx;
}

void lauf_asm_inst_pop(lauf_asm_builder* b, uint16_t stack_index)
{
LAUF_BUILD_CHECK_CUR;
Expand Down Expand Up @@ -1167,7 +1189,7 @@ void lauf_asm_inst_select(lauf_asm_builder* b, uint16_t count)
LAUF_BUILD_ASSERT(b->cur->vstack.pop(count), "missing alternative values");

b->cur->insts.push_back(*b, LAUF_BUILD_INST_STACK_IDX(select, uint16_t(count - 1)));
b->cur->vstack.push(*b, 1);
b->cur->vstack.push_output(*b, 1);
}

void lauf_asm_inst_array_element(lauf_asm_builder* b, lauf_asm_layout element_layout)
Expand All @@ -1187,12 +1209,12 @@ void lauf_asm_inst_array_element(lauf_asm_builder* b, lauf_asm_layout element_la
auto offset = index->as_constant.as_sint * lauf_sint(multiple);
if (offset > 0)
b->cur->insts.push_back(*b, LAUF_BUILD_INST_VALUE(aggregate_member, lauf_uint(offset)));
b->cur->vstack.push(*b, 1);
b->cur->vstack.push_output(*b, 1);
}
else
{
b->cur->insts.push_back(*b, LAUF_BUILD_INST_VALUE(array_element, multiple));
b->cur->vstack.push(*b, 1);
b->cur->vstack.push_output(*b, 1);
}
}

Expand All @@ -1212,7 +1234,7 @@ void lauf_asm_inst_aggregate_member(lauf_asm_builder* b, size_t member_index,
{
LAUF_BUILD_ASSERT(b->cur->vstack.pop(1), "missing address");
b->cur->insts.push_back(*b, LAUF_BUILD_INST_VALUE(aggregate_member, offset));
b->cur->vstack.push(*b, 1);
b->cur->vstack.push_output(*b, 1);
}
}

Expand Down Expand Up @@ -1287,14 +1309,14 @@ void lauf_asm_inst_load_field(lauf_asm_builder* b, lauf_asm_type type, size_t fi
b->cur->insts.push_back(*b,
LAUF_BUILD_INST_LOCAL_ADDR(load_local_value, addr->as_local->index,
addr->as_local->offset));
b->cur->vstack.push(*b, 1);
b->cur->vstack.push_output(*b, 1);
}
else if (constant_folding == load_store_global)
{
add_pop_top_n(b, 1);
b->cur->insts.push_back(*b, LAUF_BUILD_INST_VALUE(load_global_value,
addr->as_constant.as_address.allocation));
b->cur->vstack.push(*b, 1);
b->cur->vstack.push_output(*b, 1);
}
else if (type.layout.size == 0 && type.load_fn == nullptr)
{
Expand All @@ -1304,7 +1326,7 @@ void lauf_asm_inst_load_field(lauf_asm_builder* b, lauf_asm_type type, size_t fi
else
{
b->cur->insts.push_back(*b, LAUF_BUILD_INST_LAYOUT(deref_const, type.layout));
b->cur->vstack.push(*b, 1);
b->cur->vstack.push_output(*b, 1);

lauf_asm_inst_uint(b, field_index);

Expand Down Expand Up @@ -1348,7 +1370,7 @@ void lauf_asm_inst_store_field(lauf_asm_builder* b, lauf_asm_type type, size_t f
else
{
b->cur->insts.push_back(*b, LAUF_BUILD_INST_LAYOUT(deref_mut, type.layout));
b->cur->vstack.push(*b, 1);
b->cur->vstack.push_output(*b, 1);

lauf_asm_inst_uint(b, field_index);

Expand Down
54 changes: 48 additions & 6 deletions src/lauf/asm/builder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,36 @@
#include <lauf/asm/type.h>
#include <lauf/runtime/value.h>
#include <lauf/support/arena.hpp>
#include <lauf/support/array.hpp>
#include <lauf/support/array_list.hpp>
#include <optional>

//=== vstack ===//
namespace
{
constexpr bool operator==(lauf_asm_value lhs, lauf_asm_value rhs) noexcept
{
return lhs._id == rhs._id;
}
} // namespace

namespace lauf
{
constexpr lauf_asm_value invalid_asm_value = {._id = uint32_t(-1)};

class builder_vstack
{
public:
struct value
{
enum
enum type_t
{
unknown,
constant,
local_addr,
} type;
};
type_t type = unknown;
lauf_asm_value id = invalid_asm_value;
union
{
char as_unknown;
Expand All @@ -38,7 +51,7 @@ class builder_vstack
explicit builder_vstack(arena_base& arena, std::size_t input_count) : _max(input_count)
{
for (auto i = 0u; i != input_count; ++i)
_stack.push_back(arena, {value::unknown, {}});
_stack.push_back(arena, {});
}

std::size_t size() const
Expand All @@ -56,12 +69,12 @@ class builder_vstack
if (size() > _max)
_max = size();
}
void push(arena_base& arena, std::size_t n)
void push_output(arena_base& arena, std::size_t n)
{
for (auto i = 0u; i != n; ++i)
push(arena, {value::unknown, {}});
push(arena, {});
}
void push(arena_base& arena, lauf_runtime_value constant)
void push_constant(arena_base& arena, lauf_runtime_value constant)
{
value v;
v.type = value::constant;
Expand Down Expand Up @@ -117,6 +130,26 @@ class builder_vstack
*cur = save;
}

lauf_asm_value& id(std::size_t stack_idx)
{
return _stack.back(stack_idx).id;
}

std::optional<std::uint16_t> find_stack_idx_of(lauf_asm_value id) const
{
auto cur = _stack.end();
--cur;
for (std::uint16_t i = 0u; i != _stack.size(); ++i)
{
if (cur->id == id)
return i;

--cur;
}

return std::nullopt;
}

bool finish(uint8_t& output_count)
{
if (size() > UCHAR_MAX)
Expand Down Expand Up @@ -184,6 +217,8 @@ struct lauf_asm_builder : lauf::intrinsic_arena<lauf_asm_builder>
// Number of local_addr instructions.
std::uint16_t local_addr_count = 0;

lauf_asm_value next_value = {0};

bool errored = false;

explicit lauf_asm_builder(lauf::arena_key key, lauf_asm_build_options options)
Expand All @@ -207,8 +242,15 @@ struct lauf_asm_builder : lauf::intrinsic_arena<lauf_asm_builder>
local_allocation_size = 0;
local_addr_count = 0;

next_value._id = 0;

errored = false;
}

lauf_asm_value allocate_value_id() noexcept
{
return {next_value._id++};
}
};

//=== assertions ===//
Expand Down
Loading

0 comments on commit ff04b07

Please sign in to comment.