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_unreachable = api.LLVMBuildUnreachable;
|
||||||
|
|
||||||
pub const create_memcpy = api.LLVMBuildMemCpy;
|
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 {
|
pub fn create_vaarg(builder: *Builder, va_list: *Value, arg_type: *Type) *Value {
|
||||||
return api.LLVMBuildVAArg(builder, va_list, arg_type, "");
|
return api.LLVMBuildVAArg(builder, va_list, arg_type, "");
|
||||||
|
@ -140,13 +140,13 @@ arena_initialize = fn (initialization: ArenaInitialization) &Arena
|
|||||||
zero,
|
zero,
|
||||||
});
|
});
|
||||||
|
|
||||||
//arena.& = {
|
arena.& = {
|
||||||
// .reserved_size = initialization.reserved_size,
|
.reserved_size = initialization.reserved_size,
|
||||||
// .os_position = initialization.initial_size,
|
.position = minimum_position,
|
||||||
// .position = minimum_position,
|
.os_position = initialization.initial_size,
|
||||||
// .granularity = initialization.granularity,
|
.granularity = initialization.granularity,
|
||||||
// zero,
|
zero,
|
||||||
//};
|
};
|
||||||
|
|
||||||
return arena;
|
return arena;
|
||||||
}
|
}
|
||||||
|
@ -2382,7 +2382,11 @@ const Converter = struct {
|
|||||||
|
|
||||||
switch (store_type.get_evaluation_kind()) {
|
switch (store_type.get_evaluation_kind()) {
|
||||||
.aggregate => {
|
.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 }),
|
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();
|
@trap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var zero_until_end = false;
|
||||||
if (zero) {
|
if (zero) {
|
||||||
if (field_count == struct_type.fields.len) {
|
if (field_count == struct_type.fields.len) {
|
||||||
converter.report_error();
|
converter.report_error();
|
||||||
@ -3270,23 +3275,29 @@ const Converter = struct {
|
|||||||
zero_field_value.* = module.get_zero_value(zero_field.type);
|
zero_field_value.* = module.get_zero_value(zero_field.type);
|
||||||
field_count += 1;
|
field_count += 1;
|
||||||
}
|
}
|
||||||
|
} else if (is_ordered) {
|
||||||
|
zero_until_end = true;
|
||||||
} else {
|
} else {
|
||||||
@trap();
|
@trap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (field_count != struct_type.fields.len) {
|
if (field_count != struct_type.fields.len) {
|
||||||
// expect: 'zero' keyword
|
if (!zero_until_end) {
|
||||||
@trap();
|
@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) {
|
const llvm_value = switch (is_constant and is_ordered) {
|
||||||
true => blk: {
|
true => blk: {
|
||||||
var llvm_value_buffer: [64]*llvm.Constant = undefined;
|
var llvm_value_buffer: [64]*llvm.Constant = undefined;
|
||||||
var llvm_gc_value_buffer = [1]?*llvm.GlobalVariable{null} ** 64;
|
var llvm_gc_value_buffer = [1]?*llvm.GlobalVariable{null} ** 64;
|
||||||
const llvm_values = llvm_value_buffer[0..field_count];
|
const llvm_values = llvm_value_buffer[0..field_count];
|
||||||
const llvm_gc_values = llvm_gc_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()) {
|
llvm_field_value.* = switch (field.type.llvm.handle == field_value.llvm.get_type()) {
|
||||||
true => field_value.llvm.to_constant(),
|
true => field_value.llvm.to_constant(),
|
||||||
false => switch (field.type.bb) {
|
false => switch (field.type.bb) {
|
||||||
@ -3338,7 +3349,36 @@ const Converter = struct {
|
|||||||
|
|
||||||
break :blk result;
|
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();
|
const value = module.values.add();
|
||||||
|
@ -412,3 +412,7 @@ test "unreachable" {
|
|||||||
test "pointer_cast" {
|
test "pointer_cast" {
|
||||||
try invsrc(@src());
|
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 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 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 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 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 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;
|
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