Implement basic struct assignment
This commit is contained in:
parent
37d45aa101
commit
27e8d13748
@ -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, "");
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -412,3 +412,7 @@ test "unreachable" {
|
||||
test "pointer_cast" {
|
||||
try invsrc(@src());
|
||||
}
|
||||
|
||||
test "struct_assignment" {
|
||||
try invsrc(@src());
|
||||
}
|
||||
|
@ -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;
|
||||
|
46
tests/struct_assignment.bbb
Normal file
46
tests/struct_assignment.bbb
Normal 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;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user