IR & Aarch64 compiler arrays support wip

This commit is contained in:
Nikita Lisitsa 2026-03-29 19:37:49 +03:00
parent 46c33b2acf
commit 1404437324
4 changed files with 196 additions and 78 deletions

View file

@ -63,21 +63,9 @@ struct ray:
func intersect_plane(ray: ray, normal: vec3, value: f32) -> f32: func intersect_plane(ray: ray, normal: vec3, value: f32) -> f32:
return (value - dot(ray.origin, normal)) / dot(ray.direction, normal) return (value - dot(ray.origin, normal)) / dot(ray.direction, normal)
mut v = vec3(1.0, 2.0, 3.0) mut a = [1, 2, 3]
mut u = vec3(1.0, 2.0, 3.0) a[0] = 10
let p = &mut u let p = a as i32*
p[4].x = 4.0 print_i32(p[1])
print_vec3(v)
print('\n')
print_i32(((p + 5) - p) as i32)
print('\n') print('\n')
// Assignment syntax:
// lhs = rhs
// lhs must be an lvalue
// An lvalue can be
// * An identifier
// * A pointer dereference
// * A field of another lvalue
// * Access by index to an lvalue array

View file

@ -507,9 +507,8 @@ namespace pslang::ast
if (types::equal(*source_type, *target_type)) if (types::equal(*source_type, *target_type))
return; return;
if (std::get_if<types::primitive_type>(target_type.get())) if (types::is_numeric_type(*source_type) && types::is_numeric_type(*target_type))
if (!types::is_bool_type(*source_type) && !types::is_bool_type(*target_type)) return;
return;
if (auto source_pointer_type = std::get_if<types::pointer_type>(source_type.get())) if (auto source_pointer_type = std::get_if<types::pointer_type>(source_type.get()))
{ {
@ -521,6 +520,30 @@ namespace pslang::ast
} }
} }
if (auto source_array_type = std::get_if<types::array_type>(source_type.get()))
{
if (auto target_pointer_type = std::get_if<types::pointer_type>(target_type.get()))
{
if (auto lvalue = classify_lvalue(node.expression))
{
if (target_pointer_type->is_mutable && *lvalue != ast::value_category::_mutable)
throw type_error("Cannot cast a non-mutable array to a mutable pointer", node.location);
if (!types::equal(*source_array_type->element_type, *target_pointer_type->referenced_type))
{
std::ostringstream os;
os << "Cannot cast an array of ";
ast::print(os, *source_array_type->element_type);
os << " to a pointer to a different type ";
ast::print(os, *target_pointer_type->referenced_type);
throw type_error(os.str(), node.location);
}
return;
}
else
throw type_error("Cannot cast a non-lvalue array to a pointer", node.location);
}
}
std::ostringstream os; std::ostringstream os;
os << "Cannot cast a value of type "; os << "Cannot cast a value of type ";
print(os, *source_type); print(os, *source_type);

View file

@ -369,16 +369,60 @@ namespace pslang::ir
} }
} }
node_ref apply(ast::array const & node)
{
mcontext.nodes->emplace_back(alloc{}, node.inferred_type);
auto array = last();
for (std::size_t i = 0; i < node.elements.size(); ++i)
{
auto element = apply(node.elements[i]);
mcontext.nodes->emplace_back(assignment{array, element, {i}});
}
return array;
}
node_ref apply(ast::array_access const & node) node_ref apply(ast::array_access const & node)
{ {
auto array_type = ast::get_type(*node.array); auto object_type = ast::get_type(*node.array);
if (types::is_pointer_type(*array_type)) auto array_type = std::get_if<types::array_type>(object_type.get());
auto pointer_type = std::get_if<types::pointer_type>(object_type.get());
if (array_type || pointer_type)
{ {
auto new_ptr = apply(ast::binary_operation{ast::binary_operation_type::addition, node.array, node.index, {}, array_type}); types::type_ptr element_type;
mcontext.nodes->emplace_back(load{new_ptr}, node.inferred_type); if (array_type)
element_type = array_type->element_type;
else // if (pointer_type)
element_type = pointer_type->referenced_type;
auto target_pointer_type = std::make_shared<types::type>(types::pointer_type{element_type, true});
node_ref base_ptr;
if (array_type)
{
auto array = apply(*node.array);
mcontext.nodes->emplace_back(cast_operation{array, target_pointer_type}, target_pointer_type);
base_ptr = last();
}
else // if (pointer_type)
{
base_ptr = apply(*node.array);
}
auto i64_type = std::make_shared<types::type>(types::primitive_type{types::i64_type{}});
std::int64_t element_size = ast::type_size(*element_type);
auto index = apply(*node.index);
mcontext.nodes->emplace_back(cast_operation{index, i64_type}, i64_type);
auto index_cast = last();
mcontext.nodes->emplace_back(literal{ast::i64_literal{element_size}}, i64_type);
mcontext.nodes->emplace_back(binary_operation{ast::binary_operation_type::multiplication, index_cast, last()}, i64_type);
mcontext.nodes->emplace_back(binary_operation{ast::binary_operation_type::addition, base_ptr, last()}, target_pointer_type);
mcontext.nodes->emplace_back(load{last()}, node.inferred_type);
return last(); return last();
} }
throw std::runtime_error("Unknown array access left-hand side"); else
throw std::runtime_error("Unknown array access left-hand side");
} }
node_ref apply(ast::field_access const & node) node_ref apply(ast::field_access const & node)
@ -452,10 +496,42 @@ namespace pslang::ir
if (auto array_access = std::get_if<ast::array_access>(node.get())) if (auto array_access = std::get_if<ast::array_access>(node.get()))
{ {
auto array_type = get_type(*array_access->array); auto object_type = get_type(*array_access->array);
if (types::is_pointer_type(*array_type)) auto array_type = std::get_if<types::array_type>(object_type.get());
auto pointer_type = std::get_if<types::pointer_type>(object_type.get());
if (array_type || pointer_type)
{ {
return apply(ast::binary_operation{ast::binary_operation_type::addition, array_access->array, array_access->index, {}, array_type}); types::type_ptr element_type;
if (array_type)
element_type = array_type->element_type;
else // if (pointer_type)
element_type = pointer_type->referenced_type;
auto target_pointer_type = std::make_shared<types::type>(types::pointer_type{element_type, true});
node_ref base_ptr;
if (array_type)
{
auto array = apply(*array_access->array);
mcontext.nodes->emplace_back(cast_operation{array, target_pointer_type}, target_pointer_type);
base_ptr = last();
}
else // if (pointer_type)
{
base_ptr = apply(*array_access->array);
}
auto i64_type = std::make_shared<types::type>(types::primitive_type{types::i64_type{}});
std::int64_t element_size = ast::type_size(*element_type);
auto index = apply(*array_access->index);
mcontext.nodes->emplace_back(cast_operation{index, i64_type}, i64_type);
auto index_cast = last();
mcontext.nodes->emplace_back(literal{ast::i64_literal{element_size}}, i64_type);
mcontext.nodes->emplace_back(binary_operation{ast::binary_operation_type::multiplication, index_cast, last()}, i64_type);
mcontext.nodes->emplace_back(binary_operation{ast::binary_operation_type::addition, base_ptr, last()}, target_pointer_type);
return last();
} }
} }

View file

@ -589,63 +589,84 @@ namespace pslang::jit::aarch64
return; return;
} }
if (types::is_integer_type(*src_type)) if (auto array_type = std::get_if<types::array_type>(src_type.get()))
{ {
load(node.arg1, 0); if (auto pointer_type = std::get_if<types::pointer_type>(dst_type.get()))
if (types::is_integer_type(*dst_type))
{ {
extend(0, dst_type); if (types::equal(*array_type->element_type, *pointer_type->referenced_type))
}
else if (types::is_floating_point_type(*dst_type))
{
auto dst_mode = fp_mode_for(*dst_type);
if (types::is_signed_integer_type(*src_type))
{ {
builder.fmov(0, 0, 3, 1); std::int32_t offset = stack_size - stack_position.at(node.arg1);
builder.scvtf(0, 0, 3); builder.add_imm(31, 0, offset);
if (dst_mode != 3) store(it, 0);
builder.fcvt(0, 3, 0, dst_mode); return;
} }
else if (types::is_unsigned_integer_type(*src_type))
{
builder.fmov(0, 0, 3, 1);
builder.ucvtf(0, 0, 3);
if (dst_mode != 3)
builder.fcvt(0, 3, 0, dst_mode);
}
}
}
else if (types::is_floating_point_type(*src_type))
{
auto src_mode = fp_mode_for(*src_type);
if (types::is_integer_type(*dst_type))
{
if (types::is_signed_integer_type(*dst_type))
{
builder.fcvtns(0, 0, src_mode);
extend(0, dst_type);
}
else if (types::is_unsigned_integer_type(*dst_type))
{
builder.fcvtnu(0, 0, src_mode);
extend(0, dst_type);
}
}
else if (types::is_floating_point_type(*dst_type))
{
auto dst_mode = fp_mode_for(*dst_type);
builder.fcvt(0, src_mode, 0, dst_mode);
} }
} }
if (types::is_integer_type(*dst_type)) if (types::is_numeric_type(*src_type) && types::is_numeric_type(*dst_type))
{ {
store(it, 0); if (types::is_integer_type(*src_type))
} {
else if (types::is_floating_point_type(*dst_type)) load(node.arg1, 0);
{ if (types::is_integer_type(*dst_type))
store_fp(it, 0, fp_mode_for(*dst_type)); {
extend(0, dst_type);
}
else if (types::is_floating_point_type(*dst_type))
{
auto dst_mode = fp_mode_for(*dst_type);
if (types::is_signed_integer_type(*src_type))
{
builder.fmov(0, 0, 3, 1);
builder.scvtf(0, 0, 3);
if (dst_mode != 3)
builder.fcvt(0, 3, 0, dst_mode);
}
else if (types::is_unsigned_integer_type(*src_type))
{
builder.fmov(0, 0, 3, 1);
builder.ucvtf(0, 0, 3);
if (dst_mode != 3)
builder.fcvt(0, 3, 0, dst_mode);
}
}
}
else if (types::is_floating_point_type(*src_type))
{
auto src_mode = fp_mode_for(*src_type);
if (types::is_integer_type(*dst_type))
{
if (types::is_signed_integer_type(*dst_type))
{
builder.fcvtns(0, 0, src_mode);
extend(0, dst_type);
}
else if (types::is_unsigned_integer_type(*dst_type))
{
builder.fcvtnu(0, 0, src_mode);
extend(0, dst_type);
}
}
else if (types::is_floating_point_type(*dst_type))
{
auto dst_mode = fp_mode_for(*dst_type);
builder.fcvt(0, src_mode, 0, dst_mode);
}
}
if (types::is_integer_type(*dst_type))
{
store(it, 0);
}
else if (types::is_floating_point_type(*dst_type))
{
store_fp(it, 0, fp_mode_for(*dst_type));
}
return;
} }
throw std::runtime_error("Unknown types for cast instruction");
} }
void apply(ir::node_ref it, ir::argument const & node, types::type_ptr const & type) void apply(ir::node_ref it, ir::argument const & node, types::type_ptr const & type)
@ -675,9 +696,19 @@ namespace pslang::jit::aarch64
std::size_t dst_offset = stack_size - stack_position.at(node.lhs); std::size_t dst_offset = stack_size - stack_position.at(node.lhs);
for (auto field_id : node.path) for (auto field_id : node.path)
{ {
auto struct_node = std::get<types::struct_type>(*dst_type).node; if (auto struct_type = std::get_if<types::struct_type>(dst_type.get()))
dst_type = struct_node->fields[field_id].inferred_type; {
dst_offset = dst_offset + struct_node->fields[field_id].layout.offset; auto struct_node = struct_type->node;
dst_type = struct_node->fields[field_id].inferred_type;
dst_offset += struct_node->fields[field_id].layout.offset;
}
else if (auto array_type = std::get_if<types::array_type>(dst_type.get()))
{
dst_type = array_type->element_type;
dst_offset += field_id * ast::type_size(*array_type->element_type);
}
else
throw std::runtime_error("Unknown object type for field assignment");
} }
copy_memory(31, src_offset, 31, dst_offset, ast::type_size(*dst_type), 0); copy_memory(31, src_offset, 31, dst_offset, ast::type_size(*dst_type), 0);