authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-02 13:35:15-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-02 13:35:15-07:00
log220708e7c3f437958fbf8376975b70542b9ac199
tree46aba172a40fc29fc9d376bbc316855cc2438ead
parent446324a1d82514157f5a11a6ca775711bc48c419

LLVM: aggregate_init supports structs

in addition to tuples

3 files changed, 61 insertions(+), 13 deletions(-)

src/Sema.zig+2-2
...@@ -394,11 +394,11 @@ pub const Block = struct {...@@ -394,11 +394,11 @@ pub const Block = struct {
394394
395 fn addAggregateInit(395 fn addAggregateInit(
396 block: *Block,396 block: *Block,
397 vector_ty: Type,397 aggregate_ty: Type,
398 elements: []const Air.Inst.Ref,398 elements: []const Air.Inst.Ref,
399 ) !Air.Inst.Ref {399 ) !Air.Inst.Ref {
400 const sema = block.sema;400 const sema = block.sema;
401 const ty_ref = try sema.addType(vector_ty);401 const ty_ref = try sema.addType(aggregate_ty);
402 try sema.air_extra.ensureUnusedCapacity(sema.gpa, elements.len);402 try sema.air_extra.ensureUnusedCapacity(sema.gpa, elements.len);
403 const extra_index = @intCast(u32, sema.air_extra.items.len);403 const extra_index = @intCast(u32, sema.air_extra.items.len);
404 sema.appendRefsAssumeCapacity(elements);404 sema.appendRefsAssumeCapacity(elements);
src/codegen/llvm.zig+10-11
...@@ -2106,7 +2106,7 @@ pub const DeclGen = struct {...@@ -2106,7 +2106,7 @@ pub const DeclGen = struct {
2106 fn llvmFieldIndex(2106 fn llvmFieldIndex(
2107 dg: *DeclGen,2107 dg: *DeclGen,
2108 ty: Type,2108 ty: Type,
2109 field_index: u32,2109 field_index: usize,
2110 ptr_pl_buf: *Type.Payload.Pointer,2110 ptr_pl_buf: *Type.Payload.Pointer,
2111 ) ?c_uint {2111 ) ?c_uint {
2112 const target = dg.module.getTarget();2112 const target = dg.module.getTarget();
...@@ -4921,38 +4921,37 @@ pub const FuncGen = struct {...@@ -4921,38 +4921,37 @@ pub const FuncGen = struct {
4921 return vector;4921 return vector;
4922 },4922 },
4923 .Struct => {4923 .Struct => {
4924 const tuple = result_ty.castTag(.tuple).?.data;4924 var ptr_ty_buf: Type.Payload.Pointer = undefined;
49254925
4926 if (isByRef(result_ty)) {4926 if (isByRef(result_ty)) {
4927 const llvm_u32 = self.context.intType(32);4927 const llvm_u32 = self.context.intType(32);
4928 const alloca_inst = self.buildAlloca(llvm_result_ty);4928 const alloca_inst = self.buildAlloca(llvm_result_ty);
4929 // TODO in debug builds init to undef so that the padding will be 0xaa
4930 // even if we fully populate the fields.
4929 const target = self.dg.module.getTarget();4931 const target = self.dg.module.getTarget();
4930 alloca_inst.setAlignment(result_ty.abiAlignment(target));4932 alloca_inst.setAlignment(result_ty.abiAlignment(target));
49314933
4932 var indices: [2]*const llvm.Value = .{ llvm_u32.constNull(), undefined };4934 var indices: [2]*const llvm.Value = .{ llvm_u32.constNull(), undefined };
4933 var llvm_i: u32 = 0;
4934
4935 for (elements) |elem, i| {4935 for (elements) |elem, i| {
4936 if (tuple.values[i].tag() != .unreachable_value) continue;4936 if (result_ty.structFieldValueComptime(i) != null) continue;
4937 const field_ty = tuple.types[i];4937
4938 const llvm_elem = try self.resolveInst(elem);4938 const llvm_elem = try self.resolveInst(elem);
4939 const llvm_i = self.dg.llvmFieldIndex(result_ty, i, &ptr_ty_buf).?;
4939 indices[1] = llvm_u32.constInt(llvm_i, .False);4940 indices[1] = llvm_u32.constInt(llvm_i, .False);
4940 llvm_i += 1;
4941 const field_ptr = self.builder.buildInBoundsGEP(alloca_inst, &indices, indices.len, "");4941 const field_ptr = self.builder.buildInBoundsGEP(alloca_inst, &indices, indices.len, "");
4942 const store_inst = self.builder.buildStore(llvm_elem, field_ptr);4942 const store_inst = self.builder.buildStore(llvm_elem, field_ptr);
4943 store_inst.setAlignment(field_ty.abiAlignment(target));4943 store_inst.setAlignment(result_ty.structFieldAlign(i, target));
4944 }4944 }
49454945
4946 return alloca_inst;4946 return alloca_inst;
4947 } else {4947 } else {
4948 var result = llvm_result_ty.getUndef();4948 var result = llvm_result_ty.getUndef();
4949 var llvm_i: u32 = 0;
4950 for (elements) |elem, i| {4949 for (elements) |elem, i| {
4951 if (tuple.values[i].tag() != .unreachable_value) continue;4950 if (result_ty.structFieldValueComptime(i) != null) continue;
49524951
4953 const llvm_elem = try self.resolveInst(elem);4952 const llvm_elem = try self.resolveInst(elem);
4953 const llvm_i = self.dg.llvmFieldIndex(result_ty, i, &ptr_ty_buf).?;
4954 result = self.builder.buildInsertValue(result, llvm_elem, llvm_i, "");4954 result = self.builder.buildInsertValue(result, llvm_elem, llvm_i, "");
4955 llvm_i += 1;
4956 }4955 }
4957 return result;4956 return result;
4958 }4957 }
src/type.zig+49
...@@ -4479,6 +4479,55 @@ pub const Type = extern union {...@@ -4479,6 +4479,55 @@ pub const Type = extern union {
4479 }4479 }
4480 }4480 }
44814481
4482 pub fn structFieldAlign(ty: Type, index: usize, target: Target) u32 {
4483 switch (ty.tag()) {
4484 .@"struct" => {
4485 const struct_obj = ty.castTag(.@"struct").?.data;
4486 assert(struct_obj.layout != .Packed);
4487 return struct_obj.fields.values()[index].normalAlignment(target);
4488 },
4489 .@"union", .union_tagged => {
4490 const union_obj = ty.cast(Payload.Union).?.data;
4491 return union_obj.fields.values()[index].normalAlignment(target);
4492 },
4493 .tuple => return ty.castTag(.tuple).?.data.types[index].abiAlignment(target),
4494 .anon_struct => return ty.castTag(.anon_struct).?.data.types[index].abiAlignment(target),
4495 else => unreachable,
4496 }
4497 }
4498
4499 pub fn structFieldValueComptime(ty: Type, index: usize) ?Value {
4500 switch (ty.tag()) {
4501 .@"struct" => {
4502 const struct_obj = ty.castTag(.@"struct").?.data;
4503 assert(struct_obj.layout != .Packed);
4504 const field = struct_obj.fields.values()[index];
4505 if (field.is_comptime) {
4506 return field.default_val;
4507 } else {
4508 return null;
4509 }
4510 },
4511 .tuple => {
4512 const val = ty.castTag(.tuple).?.data.values[index];
4513 if (val.tag() == .unreachable_value) {
4514 return null;
4515 } else {
4516 return val;
4517 }
4518 },
4519 .anon_struct => {
4520 const val = ty.castTag(.anon_struct).?.data.values[index];
4521 if (val.tag() == .unreachable_value) {
4522 return null;
4523 } else {
4524 return val;
4525 }
4526 },
4527 else => unreachable,
4528 }
4529 }
4530
4482 pub const FieldOffset = struct {4531 pub const FieldOffset = struct {
4483 field: usize,4532 field: usize,
4484 offset: u64,4533 offset: u64,