From 220708e7c3f437958fbf8376975b70542b9ac199 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 2 Mar 2022 13:35:15 -0700 Subject: [PATCH] LLVM: aggregate_init supports structs in addition to tuples --- src/Sema.zig | 4 ++-- src/codegen/llvm.zig | 21 +++++++++---------- src/type.zig | 49 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 13 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index 0d107fb57a..2beeef0c6c 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -394,11 +394,11 @@ pub const Block = struct { fn addAggregateInit( block: *Block, - vector_ty: Type, + aggregate_ty: Type, elements: []const Air.Inst.Ref, ) !Air.Inst.Ref { const sema = block.sema; - const ty_ref = try sema.addType(vector_ty); + const ty_ref = try sema.addType(aggregate_ty); try sema.air_extra.ensureUnusedCapacity(sema.gpa, elements.len); const extra_index = @intCast(u32, sema.air_extra.items.len); sema.appendRefsAssumeCapacity(elements); diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 5ef62aadcb..7324df058a 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -2106,7 +2106,7 @@ pub const DeclGen = struct { fn llvmFieldIndex( dg: *DeclGen, ty: Type, - field_index: u32, + field_index: usize, ptr_pl_buf: *Type.Payload.Pointer, ) ?c_uint { const target = dg.module.getTarget(); @@ -4921,38 +4921,37 @@ pub const FuncGen = struct { return vector; }, .Struct => { - const tuple = result_ty.castTag(.tuple).?.data; + var ptr_ty_buf: Type.Payload.Pointer = undefined; if (isByRef(result_ty)) { const llvm_u32 = self.context.intType(32); const alloca_inst = self.buildAlloca(llvm_result_ty); + // TODO in debug builds init to undef so that the padding will be 0xaa + // even if we fully populate the fields. const target = self.dg.module.getTarget(); alloca_inst.setAlignment(result_ty.abiAlignment(target)); var indices: [2]*const llvm.Value = .{ llvm_u32.constNull(), undefined }; - var llvm_i: u32 = 0; - for (elements) |elem, i| { - if (tuple.values[i].tag() != .unreachable_value) continue; - const field_ty = tuple.types[i]; + if (result_ty.structFieldValueComptime(i) != null) continue; + const llvm_elem = try self.resolveInst(elem); + const llvm_i = self.dg.llvmFieldIndex(result_ty, i, &ptr_ty_buf).?; indices[1] = llvm_u32.constInt(llvm_i, .False); - llvm_i += 1; const field_ptr = self.builder.buildInBoundsGEP(alloca_inst, &indices, indices.len, ""); const store_inst = self.builder.buildStore(llvm_elem, field_ptr); - store_inst.setAlignment(field_ty.abiAlignment(target)); + store_inst.setAlignment(result_ty.structFieldAlign(i, target)); } return alloca_inst; } else { var result = llvm_result_ty.getUndef(); - var llvm_i: u32 = 0; for (elements) |elem, i| { - if (tuple.values[i].tag() != .unreachable_value) continue; + if (result_ty.structFieldValueComptime(i) != null) continue; const llvm_elem = try self.resolveInst(elem); + const llvm_i = self.dg.llvmFieldIndex(result_ty, i, &ptr_ty_buf).?; result = self.builder.buildInsertValue(result, llvm_elem, llvm_i, ""); - llvm_i += 1; } return result; } diff --git a/src/type.zig b/src/type.zig index 3c08ed5b63..e1e6a0ada2 100644 --- a/src/type.zig +++ b/src/type.zig @@ -4479,6 +4479,55 @@ pub const Type = extern union { } } + pub fn structFieldAlign(ty: Type, index: usize, target: Target) u32 { + switch (ty.tag()) { + .@"struct" => { + const struct_obj = ty.castTag(.@"struct").?.data; + assert(struct_obj.layout != .Packed); + return struct_obj.fields.values()[index].normalAlignment(target); + }, + .@"union", .union_tagged => { + const union_obj = ty.cast(Payload.Union).?.data; + return union_obj.fields.values()[index].normalAlignment(target); + }, + .tuple => return ty.castTag(.tuple).?.data.types[index].abiAlignment(target), + .anon_struct => return ty.castTag(.anon_struct).?.data.types[index].abiAlignment(target), + else => unreachable, + } + } + + pub fn structFieldValueComptime(ty: Type, index: usize) ?Value { + switch (ty.tag()) { + .@"struct" => { + const struct_obj = ty.castTag(.@"struct").?.data; + assert(struct_obj.layout != .Packed); + const field = struct_obj.fields.values()[index]; + if (field.is_comptime) { + return field.default_val; + } else { + return null; + } + }, + .tuple => { + const val = ty.castTag(.tuple).?.data.values[index]; + if (val.tag() == .unreachable_value) { + return null; + } else { + return val; + } + }, + .anon_struct => { + const val = ty.castTag(.anon_struct).?.data.values[index]; + if (val.tag() == .unreachable_value) { + return null; + } else { + return val; + } + }, + else => unreachable, + } + } + pub const FieldOffset = struct { field: usize, offset: u64,