diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2022-02-10 00:24:52 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2022-02-10 00:27:02 -0700 |
| commit | c10fdde5a64a46bc514500e97b8c87d19f86e431 (patch) | |
| tree | 0512ae6e4bd7082d6df656f53ee174b99fe7f49e /src/codegen/llvm.zig | |
| parent | 57357c43e3b56fd636cd08af591c50a08223b654 (diff) | |
| download | zig-c10fdde5a64a46bc514500e97b8c87d19f86e431.tar.gz zig-c10fdde5a64a46bc514500e97b8c87d19f86e431.zip | |
stage2: LLVM backend: make unnamed struct globals
LLVM union globals have to be lowered as unnamed structs if the
non-most-aligned field is the active tag. In this case it bubbles up so
that structs containing unions have the same restriction.
This fix needs to be applied to optionals and other callsites of
createNamedStruct.
The bug fixed in this commit was revealed in searching for
the cause of #10837.
Diffstat (limited to 'src/codegen/llvm.zig')
| -rw-r--r-- | src/codegen/llvm.zig | 45 |
1 files changed, 34 insertions, 11 deletions
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 9c9bf0d0f2..d85a16d16f 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -809,7 +809,16 @@ pub const DeclGen = struct { }; } - fn llvmType(dg: *DeclGen, t: Type) Error!*const llvm.Type { + fn isUnnamedType(dg: *DeclGen, ty: Type, val: *const llvm.Value) bool { + // Once `llvmType` succeeds, successive calls to it with the same Zig type + // are guaranteed to succeed. So if a call to `llvmType` fails here it means + // it is the first time lowering the type, which means the value can't possible + // have that type. + const llvm_ty = dg.llvmType(ty) catch return true; + return val.typeOf() != llvm_ty; + } + + fn llvmType(dg: *DeclGen, t: Type) Allocator.Error!*const llvm.Type { const gpa = dg.gpa; switch (t.zigTypeTag()) { .Void, .NoReturn => return dg.context.voidType(), @@ -1168,9 +1177,8 @@ pub const DeclGen = struct { .BoundFn => @panic("TODO remove BoundFn from the language"), - .Frame, - .AnyFrame, - => return dg.todo("implement llvmType for type '{}'", .{t}), + .Frame => @panic("TODO implement llvmType for Frame types"), + .AnyFrame => @panic("TODO implement llvmType for AnyFrame types"), } } @@ -1299,7 +1307,8 @@ pub const DeclGen = struct { llvm_u32.constInt(0, .False), llvm_u32.constInt(field_ptr.field_index, .False), }; - return parent_ptr.constInBoundsGEP(&indices, indices.len); + const uncasted = parent_ptr.constInBoundsGEP(&indices, indices.len); + return uncasted.constBitCast(try dg.llvmType(tv.ty)); }, .elem_ptr => { const elem_ptr = tv.val.castTag(.elem_ptr).?.data; @@ -1463,6 +1472,7 @@ pub const DeclGen = struct { var llvm_fields = try std.ArrayListUnmanaged(*const llvm.Value).initCapacity(gpa, llvm_field_count); defer llvm_fields.deinit(gpa); + var make_unnamed_struct = false; const struct_obj = tv.ty.castTag(.@"struct").?.data; if (struct_obj.layout == .Packed) { const target = dg.module.getTarget(); @@ -1558,17 +1568,30 @@ pub const DeclGen = struct { const field_ty = tv.ty.structFieldType(i); if (!field_ty.hasRuntimeBits()) continue; - llvm_fields.appendAssumeCapacity(try dg.genTypedValue(.{ + const field_llvm_val = try dg.genTypedValue(.{ .ty = field_ty, .val = field_val, - })); + }); + + make_unnamed_struct = make_unnamed_struct or + dg.isUnnamedType(field_ty, field_llvm_val); + + llvm_fields.appendAssumeCapacity(field_llvm_val); } } - return llvm_struct_ty.constNamedStruct( - llvm_fields.items.ptr, - @intCast(c_uint, llvm_fields.items.len), - ); + if (make_unnamed_struct) { + return dg.context.constStruct( + llvm_fields.items.ptr, + @intCast(c_uint, llvm_fields.items.len), + .False, + ); + } else { + return llvm_struct_ty.constNamedStruct( + llvm_fields.items.ptr, + @intCast(c_uint, llvm_fields.items.len), + ); + } }, .Union => { const llvm_union_ty = try dg.llvmType(tv.ty); |
