aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2022-03-02 13:35:15 -0700
committerAndrew Kelley <andrew@ziglang.org>2022-03-02 13:35:15 -0700
commit220708e7c3f437958fbf8376975b70542b9ac199 (patch)
tree46aba172a40fc29fc9d376bbc316855cc2438ead /src
parent446324a1d82514157f5a11a6ca775711bc48c419 (diff)
downloadzig-220708e7c3f437958fbf8376975b70542b9ac199.tar.gz
zig-220708e7c3f437958fbf8376975b70542b9ac199.zip
LLVM: aggregate_init supports structs
in addition to tuples
Diffstat (limited to 'src')
-rw-r--r--src/Sema.zig4
-rw-r--r--src/codegen/llvm.zig21
-rw-r--r--src/type.zig49
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,