x86_64 backend: support returning structs & arrays

This commit is contained in:
Nikita Lisitsa 2026-07-31 13:55:02 +03:00
parent 8d4bc9aa62
commit 16d6ed4174

View file

@ -34,6 +34,11 @@ namespace pslang::jit::linux_x86_64
reg::r9,
};
static std::array<reg, 2> integer_ret_reg = {
reg::rax,
reg::rdx,
};
struct small_struct_data
{
struct octet
@ -760,7 +765,27 @@ namespace pslang::jit::linux_x86_64
{}
else if (struct_type || array_type)
{
throw std::runtime_error("Not implemented");
if (auto small_struct = classify_small_struct(lcontext, type))
{
auto address = node_address(*node.value);
std::uint8_t reg_index = 0;
std::uint8_t fp_reg = 0;
for (int o : {0, 1})
{
auto & octet = small_struct->octets[o];
if (!octet) break;
if (octet->has_integer)
load(*node.value, integer_ret_reg[reg_index++], 8 * o);
else if (octet->has_floating_point)
load_xmm(*node.value, (reg)(fp_reg++), 8, 8 * o);
}
}
else
{
copy_memory(node_address(*node.value), {reg::rdi, 0}, size);
}
}
else if (types::is_integer_like_type(*type))
load(*node.value, reg::rax);
@ -851,7 +876,7 @@ namespace pslang::jit::linux_x86_64
for (std::size_t o : {0, 1})
{
auto & octet = small_struct->octets[o];
if (!octet) continue;
if (!octet) break;
if (octet->has_integer)
builder.mov_write(integer_arg_reg[reg_index++], reg::rsp, stack_size - argument_position[i] + 8 * o);
else if (octet->has_floating_point)
@ -933,25 +958,25 @@ namespace pslang::jit::linux_x86_64
return {.base = reg::rsp, .offset = stack_size - stack_position.at(it)};
}
void load(ir::node_ref it, reg reg_dst)
void load(ir::node_ref it, reg reg_dst, std::int32_t offset = 0)
{
auto const address = node_address(it);
if (address.base)
builder.mov_read(*address.base, address.offset, reg_dst);
builder.mov_read(*address.base, address.offset + offset, reg_dst);
else
builder.mov_read_rip_prev(address.offset, reg_dst);
builder.mov_read_rip_prev(address.offset + offset, reg_dst);
}
void store(ir::node_ref it, reg reg_src)
void store(ir::node_ref it, reg reg_src, std::int32_t offset = 0)
{
auto const address = node_address(it);
if (address.base)
builder.mov_write(reg_src, *address.base, address.offset);
builder.mov_write(reg_src, *address.base, address.offset + offset);
else
builder.mov_write_rip_prev(reg_src, address.offset);
builder.mov_write_rip_prev(reg_src, address.offset + offset);
}
void load_xmm(ir::node_ref it, reg reg_dst, std::uint8_t size)
void load_xmm(ir::node_ref it, reg reg_dst, std::uint8_t size, std::int32_t offset = 0)
{
if (size != 4 && size != 8)
throw std::runtime_error("Bad type size for load_xmm");
@ -960,15 +985,15 @@ namespace pslang::jit::linux_x86_64
if (address.base)
{
if (size == 4)
builder.mov_read_xmm_32(*address.base, address.offset, reg_dst);
builder.mov_read_xmm_32(*address.base, address.offset + offset, reg_dst);
else
builder.mov_read_xmm(*address.base, address.offset, reg_dst);
builder.mov_read_xmm(*address.base, address.offset + offset, reg_dst);
}
else
throw std::runtime_error("RIP-relative XMM read is not supported");
}
void store_xmm(ir::node_ref it, reg reg_src, std::uint8_t size)
void store_xmm(ir::node_ref it, reg reg_src, std::uint8_t size, std::int32_t offset = 0)
{
if (size != 4 && size != 8)
throw std::runtime_error("Bad type size for store_xmm");
@ -977,9 +1002,9 @@ namespace pslang::jit::linux_x86_64
if (address.base)
{
if (size == 4)
builder.mov_write_xmm_32(reg_src, *address.base, address.offset);
builder.mov_write_xmm_32(reg_src, *address.base, address.offset + offset);
else
builder.mov_write_xmm(reg_src, *address.base, address.offset);
builder.mov_write_xmm(reg_src, *address.base, address.offset + offset);
}
else
throw std::runtime_error("RIP-relative XMM write is not supported");