Implement pointer support in IR via load/store instructions

This commit is contained in:
Nikita Lisitsa 2026-03-23 15:35:28 +03:00
parent 0c11b09548
commit dd3eb5d14b
4 changed files with 87 additions and 15 deletions

View file

@ -7,7 +7,6 @@ foreign func free(ptr: unit*)
let array = alloc(400ul) as i32 mut*
*array = 10
*(array + 1) = 20
let q = array + 10
let n = q - array
array[5] = 50
let test = array[10]
array[15] = 1500
free(array as unit*)

View file

@ -25,6 +25,17 @@ namespace pslang::ir
node_ref source;
};
struct load
{
node_ref ptr;
};
struct store
{
node_ref ptr;
node_ref value;
};
struct unary_operation
{
ast::unary_operation_type type;
@ -49,7 +60,7 @@ namespace pslang::ir
std::size_t index;
};
struct address
struct instruction_address
{
node_ref target;
};
@ -100,11 +111,13 @@ namespace pslang::ir
nop,
literal,
copy,
load,
store,
unary_operation,
binary_operation,
cast_operation,
argument,
address,
instruction_address,
extern_symbol,
assignment,
jump,

View file

@ -75,7 +75,7 @@ namespace pslang::ir
}
else if (node.function_node)
{
mcontext.nodes.emplace_back(address{}, node.inferred_type);
mcontext.nodes.emplace_back(instruction_address{}, node.inferred_type);
lcontext.resolve_address.emplace_back(last(), node.function_node);
return last();
}
@ -91,6 +91,13 @@ namespace pslang::ir
node_ref apply(ast::unary_operation const & node)
{
auto arg1 = apply(*node.arg1);
if (node.type == ast::unary_operation_type::dereference)
{
mcontext.nodes.emplace_back(load{arg1}, node.inferred_type);
return last();
}
mcontext.nodes.emplace_back(unary_operation{node.type, arg1}, node.inferred_type);
return last();
}
@ -162,6 +169,20 @@ namespace pslang::ir
}
}
node_ref apply(ast::array_access const & node)
{
auto array = apply(*node.array);
auto index = apply(*node.index);
auto array_type = ast::get_type(*node.array);
if (std::get_if<types::pointer_type>(array_type.get()))
{
mcontext.nodes.emplace_back(binary_operation{ast::binary_operation_type::addition, array, index}, array_type);
mcontext.nodes.emplace_back(load{last()}, node.inferred_type);
return last();
}
throw std::runtime_error("Unknown array access left-hand side");
}
// TODO: array, array_access, field_access
// Statements
@ -174,9 +195,38 @@ namespace pslang::ir
node_ref apply(ast::assignment const & node)
{
auto rhs = apply(*node.rhs);
auto lhs = apply(*node.lhs);
mcontext.nodes.emplace_back(assignment{lhs, rhs}, ast::get_type(*node.rhs));
return last();
if (std::holds_alternative<ast::identifier>(*node.lhs))
{
auto lhs = apply(*node.lhs);
mcontext.nodes.emplace_back(assignment{lhs, rhs}, ast::get_type(*node.rhs));
return last();
}
if (auto array_access = std::get_if<ast::array_access>(node.lhs.get()))
{
auto array_type = get_type(*array_access->array);
if (std::get_if<types::pointer_type>(array_type.get()))
{
auto base_ptr = apply(*array_access->array);
auto index = apply(*array_access->index);
mcontext.nodes.emplace_back(binary_operation{ast::binary_operation_type::addition, base_ptr, index}, array_type);
mcontext.nodes.emplace_back(store{last(), rhs}, ast::get_type(*node.rhs));
return last();
}
}
if (auto unary_operation = std::get_if<ast::unary_operation>(node.lhs.get()))
{
if (unary_operation->type == ast::unary_operation_type::dereference)
{
auto lhs = apply(*unary_operation->arg1);
mcontext.nodes.emplace_back(store{lhs, rhs}, ast::get_type(*node.rhs));
return last();
}
}
throw std::runtime_error("Unknown assignment left-hand side");
}
node_ref apply(ast::variable_declaration const & node)
@ -380,7 +430,7 @@ namespace pslang::ir
mcontext.nodes.erase(extra_nop);
for (auto const & resolve : lcontext.resolve_address)
std::get<address>(resolve.address->instruction).target = lcontext.functions.at(resolve.target);
std::get<instruction_address>(resolve.address->instruction).target = lcontext.functions.at(resolve.target);
for (auto const & resolve : lcontext.resolve_call)
std::get<call>(resolve.call->instruction).target = lcontext.functions.at(resolve.target);

View file

@ -23,10 +23,10 @@ namespace pslang::ir
out << "not";
break;
case ast::unary_operation_type::address_of:
out << "address";
out << "addr";
break;
case ast::unary_operation_type::mutable_address_of:
out << "address";
out << "addr";
break;
case ast::unary_operation_type::dereference:
out << "deref";
@ -204,6 +204,16 @@ namespace pslang::ir
out << "copy $" << get_index(instruction.source);
}
void operator()(load const & instruction)
{
out << "load $" << get_index(instruction.ptr);
}
void operator()(store const & instruction)
{
out << "store $" << get_index(instruction.ptr) << " $" << get_index(instruction.value);
}
void operator()(unary_operation const & instruction)
{
print(out, instruction.type);
@ -226,9 +236,9 @@ namespace pslang::ir
out << "arg #" << instruction.index;
}
void operator()(address const & instruction)
void operator()(instruction_address const & instruction)
{
out << "addr $" << get_index(instruction.target);
out << "iaddr $" << get_index(instruction.target);
}
void operator()(extern_symbol const & instruction)