diff --git a/src/LLVM.zig b/src/LLVM.zig index f9dc77c..8833994 100644 --- a/src/LLVM.zig +++ b/src/LLVM.zig @@ -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, ""); diff --git a/src/compiler.bbb b/src/compiler.bbb index 13dc3be..feb9263 100644 --- a/src/compiler.bbb +++ b/src/compiler.bbb @@ -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; } diff --git a/src/converter.zig b/src/converter.zig index b2feb13..14a0bc6 100644 --- a/src/converter.zig +++ b/src/converter.zig @@ -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(); diff --git a/src/converter_test.zig b/src/converter_test.zig index 8ad6fca..1417bd3 100644 --- a/src/converter_test.zig +++ b/src/converter_test.zig @@ -412,3 +412,7 @@ test "unreachable" { test "pointer_cast" { try invsrc(@src()); } + +test "struct_assignment" { + try invsrc(@src()); +} diff --git a/src/llvm_api.zig b/src/llvm_api.zig index 01f2e69..375ceda 100644 --- a/src/llvm_api.zig +++ b/src/llvm_api.zig @@ -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; diff --git a/tests/struct_assignment.bbb b/tests/struct_assignment.bbb new file mode 100644 index 0000000..7d168ef --- /dev/null +++ b/tests/struct_assignment.bbb @@ -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; +}