Implement basic struct assignment

This commit is contained in:
David Gonzalez Martin 2025-03-24 20:35:51 +01:00
parent 37d45aa101
commit 27e8d13748
6 changed files with 104 additions and 12 deletions

View File

@ -955,6 +955,7 @@ pub const Builder = opaque {
pub const create_unreachable = api.LLVMBuildUnreachable;
pub const create_memcpy = api.LLVMBuildMemCpy;
pub const create_memset = api.LLVMBuildMemSet;
pub fn create_vaarg(builder: *Builder, va_list: *Value, arg_type: *Type) *Value {
return api.LLVMBuildVAArg(builder, va_list, arg_type, "");

View File

@ -140,13 +140,13 @@ arena_initialize = fn (initialization: ArenaInitialization) &Arena
zero,
});
//arena.& = {
// .reserved_size = initialization.reserved_size,
// .os_position = initialization.initial_size,
// .position = minimum_position,
// .granularity = initialization.granularity,
// zero,
//};
arena.& = {
.reserved_size = initialization.reserved_size,
.position = minimum_position,
.os_position = initialization.initial_size,
.granularity = initialization.granularity,
zero,
};
return arena;
}

View File

@ -2382,7 +2382,11 @@ const Converter = struct {
switch (store_type.get_evaluation_kind()) {
.aggregate => {
@trap();
if (left.type.bb.pointer.type != right.type) {
converter.report_error();
}
assert(right.lvalue);
_ = module.llvm.builder.create_memcpy(left.llvm, left.type.bb.pointer.alignment, right.llvm, right.type.get_byte_alignment(), module.integer_type(64, false).llvm.handle.to_integer().get_constant(right.type.get_byte_size(), @intFromBool(false)).to_value());
},
else => _ = module.create_store(.{ .source_value = right.llvm, .destination_value = left.llvm, .source_type = store_type, .destination_type = store_type, .alignment = store_alignment }),
}
@ -3258,6 +3262,7 @@ const Converter = struct {
@trap();
}
var zero_until_end = false;
if (zero) {
if (field_count == struct_type.fields.len) {
converter.report_error();
@ -3270,23 +3275,29 @@ const Converter = struct {
zero_field_value.* = module.get_zero_value(zero_field.type);
field_count += 1;
}
} else if (is_ordered) {
zero_until_end = true;
} else {
@trap();
}
}
if (field_count != struct_type.fields.len) {
// expect: 'zero' keyword
@trap();
if (!zero_until_end) {
@trap();
}
}
const field_values = field_value_buffer[0..field_count];
const field_indices = field_index_buffer[0..field_count];
const llvm_value = switch (is_constant and is_ordered) {
true => blk: {
var llvm_value_buffer: [64]*llvm.Constant = undefined;
var llvm_gc_value_buffer = [1]?*llvm.GlobalVariable{null} ** 64;
const llvm_values = llvm_value_buffer[0..field_count];
const llvm_gc_values = llvm_gc_value_buffer[0..field_count];
for (field_value_buffer[0..field_count], llvm_gc_values, llvm_values, struct_type.fields) |field_value, *llvm_gc_value, *llvm_field_value, *field| {
for (field_values, llvm_gc_values, llvm_values, struct_type.fields) |field_value, *llvm_gc_value, *llvm_field_value, *field| {
llvm_field_value.* = switch (field.type.llvm.handle == field_value.llvm.get_type()) {
true => field_value.llvm.to_constant(),
false => switch (field.type.bb) {
@ -3338,7 +3349,36 @@ const Converter = struct {
break :blk result;
},
false => @trap(),
false => blk: {
const alloca = module.create_alloca(.{ .type = ty, .name = "compound_literal" });
const llvm_struct = ty.llvm.handle.to_struct();
const fields = struct_type.fields[0..field_count];
for (fields, field_indices, field_values) |field, field_index, field_value| {
const gep = module.llvm.builder.create_struct_gep(llvm_struct, alloca, field_index);
assert(field_value.type == field.type);
// TODO: consider more store types
_ = module.create_store(.{
.destination_type = field.type,
.source_type = field_value.type,
.source_value = field_value.llvm,
.destination_value = gep,
});
}
if (zero_until_end) {
// const zero_field_values = field_value_buffer[field_count..][0..zero_fields.len];
const zero_gep = module.llvm.builder.create_struct_gep(llvm_struct, alloca, field_count);
const zero_value = module.integer_type(8, false).llvm.handle.to_integer().get_constant(0, @intFromBool(false)).to_value();
const raw_byte_count = ty.get_byte_size() - struct_type.fields[field_count].byte_offset;
const byte_count = module.integer_type(64, false).llvm.handle.to_integer().get_constant(raw_byte_count, @intFromBool(false)).to_value();
_ = module.llvm.builder.create_memset(zero_gep, zero_value, byte_count, 1);
} else {
assert(field_count == struct_type.fields.len);
}
break :blk alloca;
},
};
const value = module.values.add();

View File

@ -412,3 +412,7 @@ test "unreachable" {
test "pointer_cast" {
try invsrc(@src());
}
test "struct_assignment" {
try invsrc(@src());
}

View File

@ -90,6 +90,7 @@ pub extern fn LLVMBuildInsertValue(builder: *llvm.Builder, aggregate: *llvm.Valu
pub extern fn LLVMBuildExtractValue(builder: *llvm.Builder, aggregate: *llvm.Value, index: c_uint, name: [*:0]const u8) *llvm.Value;
pub extern fn LLVMBuildUnreachable(builder: *llvm.Builder) *llvm.Value;
pub extern fn LLVMBuildMemCpy(builder: *llvm.Builder, destination: *llvm.Value, destination_alignment: c_uint, source: *llvm.Value, source_alignment: c_uint, size: *llvm.Value) *llvm.Value;
pub extern fn LLVMBuildMemSet(builder: *llvm.Builder, pointer: *llvm.Value, value: *llvm.Value, value_count: *llvm.Value, alignment: c_uint) *llvm.Value;
pub extern fn LLVMBuildPhi(builder: *llvm.Builder, ty: *llvm.Type, name: [*:0]const u8) *llvm.Instruction.Phi;
pub extern fn LLVMAddIncoming(phi: *llvm.Instruction.Phi, incoming_value_pointer: [*]const *llvm.Value, incoming_basic_block_pointer: [*]const *llvm.BasicBlock, incoming_count: c_uint) void;
pub extern fn LLVMBuildSelect(builder: *llvm.Builder, condition: *llvm.Value, true_value: *llvm.Value, false_value: *llvm.Value, name: [*:0]const u8) *llvm.Value;

View File

@ -0,0 +1,46 @@
S1 = struct
{
a: u8,
b: u8,
c: u8,
}
S2 = struct
{
a: u8,
b: u8,
c: u8,
}
require = fn (ok: u1) void
{
if (!ok)
{
#trap();
}
}
[export] main = fn [cc(c)] () s32
{
>s1: S1 = {
.a = 255,
.b = 254,
.c = 253,
};
>s2 :S2 = {
.a = s1.a,
.b = s1.b,
.c = s1.c,
};
require(s1.a == 255);
require(s1.b == 254);
require(s1.c == 253);
require(s2.a == 255);
require(s2.b == 254);
require(s2.c == 253);
return 0;
}