diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2023-10-19 15:10:35 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2023-10-21 21:38:41 -0400 |
| commit | 7bab406c790566781406a7968be22961ed7c305d (patch) | |
| tree | e2f778d1c66dd62bf41da837bb76a882b792ec6e /src/codegen | |
| parent | 5aa82ed477b85cf8681bc0dc65f97e813990a2ed (diff) | |
| download | zig-7bab406c790566781406a7968be22961ed7c305d.tar.gz zig-7bab406c790566781406a7968be22961ed7c305d.zip | |
InternPool: store alignment of anon decls
Commit 5393e56500d499753dbc39704c0161b47d1e4d5c has a flaw pointed out
by @mlugg: the `ty` field of pointer values changes when comptime values
are pointer-casted. This commit introduces a new encoding which
additionally stores the "original pointer type" which is used to store
the alignment of the anonymous decl, and potentially other information
in the future such as section and pointer address space. However, this
new encoding is only used when the original pointer type differs from
the casted pointer type in a meaningful way.
I was able to make the LLVM backend and the C backend lower anonymous
decls with the appropriate alignment, however I will need some help
figuring out how to do this for the backends that lower anonymous decls
via src/codegen.zig and the wasm backend.
Diffstat (limited to 'src/codegen')
| -rw-r--r-- | src/codegen/c.zig | 21 | ||||
| -rw-r--r-- | src/codegen/llvm.zig | 31 | ||||
| -rw-r--r-- | src/codegen/llvm/Builder.zig | 6 | ||||
| -rw-r--r-- | src/codegen/llvm/bindings.zig | 3 | ||||
| -rw-r--r-- | src/codegen/spirv.zig | 7 |
5 files changed, 50 insertions, 18 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 94598985c0..897d0ea047 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -531,6 +531,7 @@ pub const DeclGen = struct { /// Keeps track of anonymous decls that need to be rendered before this /// (named) Decl in the output C code. anon_decl_deps: std.AutoArrayHashMapUnmanaged(InternPool.Index, C.DeclBlock), + aligned_anon_decls: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment), fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } { @setCold(true); @@ -548,11 +549,12 @@ pub const DeclGen = struct { writer: anytype, ty: Type, ptr_val: Value, - decl_val: InternPool.Index, + anon_decl: InternPool.Key.Ptr.Addr.AnonDecl, location: ValueRenderLocation, ) error{ OutOfMemory, AnalysisFail }!void { const mod = dg.module; const ip = &mod.intern_pool; + const decl_val = anon_decl.val; const decl_ty = ip.typeOf(decl_val).toType(); // Render an undefined pointer if we have a pointer to a zero-bit or comptime type. @@ -592,8 +594,23 @@ pub const DeclGen = struct { // Indicate that the anon decl should be rendered to the output so that // our reference above is not undefined. + const ptr_type = ip.indexToKey(anon_decl.orig_ty).ptr_type; const gop = try dg.anon_decl_deps.getOrPut(dg.gpa, decl_val); if (!gop.found_existing) gop.value_ptr.* = .{}; + + // Only insert an alignment entry if the alignment is greater than ABI + // alignment. If there is already an entry, keep the greater alignment. + const explicit_alignment = ptr_type.flags.alignment; + if (explicit_alignment != .none) { + const abi_alignment = ptr_type.child.toType().abiAlignment(mod); + if (explicit_alignment.compareStrict(.gt, abi_alignment)) { + const aligned_gop = try dg.aligned_anon_decls.getOrPut(dg.gpa, decl_val); + aligned_gop.value_ptr.* = if (aligned_gop.found_existing) + aligned_gop.value_ptr.maxStrict(explicit_alignment) + else + explicit_alignment; + } + } } fn renderDeclValue( @@ -651,7 +668,7 @@ pub const DeclGen = struct { switch (ptr.addr) { .decl => |d| try dg.renderDeclValue(writer, ptr_ty, ptr_val.toValue(), d, location), .mut_decl => |md| try dg.renderDeclValue(writer, ptr_ty, ptr_val.toValue(), md.decl, location), - .anon_decl => |decl_val| try dg.renderAnonDeclValue(writer, ptr_ty, ptr_val.toValue(), decl_val, location), + .anon_decl => |anon_decl| try dg.renderAnonDeclValue(writer, ptr_ty, ptr_val.toValue(), anon_decl, location), .int => |int| { try writer.writeByte('('); try dg.renderCType(writer, ptr_cty); diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 9bb012deb1..ed4f1bdf6c 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -3051,9 +3051,17 @@ pub const Object = struct { llvm_addr_space: Builder.AddrSpace, alignment: InternPool.Alignment, ) Error!Builder.Variable.Index { + assert(alignment != .none); // TODO: Add address space to the anon_decl_map const gop = try o.anon_decl_map.getOrPut(o.gpa, decl_val); - if (gop.found_existing) return gop.value_ptr.ptr(&o.builder).kind.variable; + if (gop.found_existing) { + // Keep the greater of the two alignments. + const variable_index = gop.value_ptr.ptr(&o.builder).kind.variable; + const old_alignment = InternPool.Alignment.fromLlvm(variable_index.getAlignment(&o.builder)); + const max_alignment = old_alignment.maxStrict(alignment); + variable_index.setAlignment(max_alignment.toLlvm(), &o.builder); + return variable_index; + } errdefer assert(o.anon_decl_map.remove(decl_val)); const mod = o.module; @@ -3069,8 +3077,7 @@ pub const Object = struct { try variable_index.setInitializer(try o.lowerValue(decl_val), &o.builder); variable_index.setLinkage(.internal, &o.builder); variable_index.setUnnamedAddr(.unnamed_addr, &o.builder); - if (alignment != .none) - variable_index.setAlignment(alignment.toLlvm(), &o.builder); + variable_index.setAlignment(alignment.toLlvm(), &o.builder); return variable_index; } @@ -4253,13 +4260,6 @@ pub const Object = struct { return o.builder.bigIntConst(try o.builder.intType(ty.intInfo(mod).bits), bigint); } - fn lowerParentPtrAnonDecl(o: *Object, decl_val: InternPool.Index) Error!Builder.Constant { - const mod = o.module; - const decl_ty = mod.intern_pool.typeOf(decl_val).toType(); - const ptr_ty = try mod.singleMutPtrType(decl_ty); - return o.lowerAnonDeclRef(ptr_ty, decl_val); - } - fn lowerParentPtrDecl(o: *Object, decl_index: Module.Decl.Index) Allocator.Error!Builder.Constant { const mod = o.module; const decl = mod.declPtr(decl_index); @@ -4275,7 +4275,7 @@ pub const Object = struct { return switch (ptr.addr) { .decl => |decl| try o.lowerParentPtrDecl(decl), .mut_decl => |mut_decl| try o.lowerParentPtrDecl(mut_decl.decl), - .anon_decl => |anon_decl| try o.lowerParentPtrAnonDecl(anon_decl), + .anon_decl => |ad| try o.lowerAnonDeclRef(ad.orig_ty.toType(), ad), .int => |int| try o.lowerIntAsPtr(int), .eu_payload => |eu_ptr| { const parent_ptr = try o.lowerParentPtr(eu_ptr.toValue()); @@ -4394,10 +4394,11 @@ pub const Object = struct { fn lowerAnonDeclRef( o: *Object, ptr_ty: Type, - decl_val: InternPool.Index, + anon_decl: InternPool.Key.Ptr.Addr.AnonDecl, ) Error!Builder.Constant { const mod = o.module; const ip = &mod.intern_pool; + const decl_val = anon_decl.val; const decl_ty = ip.typeOf(decl_val).toType(); const target = mod.getTarget(); @@ -4416,9 +4417,9 @@ pub const Object = struct { if (is_fn_body) @panic("TODO"); - const addr_space = target_util.defaultAddressSpace(target, .global_constant); - const llvm_addr_space = toLlvmAddressSpace(addr_space, target); - const alignment = ptr_ty.ptrAlignment(mod); + const orig_ty = anon_decl.orig_ty.toType(); + const llvm_addr_space = toLlvmAddressSpace(orig_ty.ptrAddressSpace(mod), target); + const alignment = orig_ty.ptrAlignment(mod); const llvm_global = (try o.resolveGlobalAnonDecl(decl_val, llvm_addr_space, alignment)).ptrConst(&o.builder).global; const llvm_val = try o.builder.convConst( diff --git a/src/codegen/llvm/Builder.zig b/src/codegen/llvm/Builder.zig index 5a9703af3d..4f971db1de 100644 --- a/src/codegen/llvm/Builder.zig +++ b/src/codegen/llvm/Builder.zig @@ -2477,6 +2477,12 @@ pub const Variable = struct { self.ptr(builder).alignment = alignment; } + pub fn getAlignment(self: Index, builder: *Builder) Alignment { + if (builder.useLibLlvm()) + return Alignment.fromByteUnits(self.toLlvm(builder).getAlignment()); + return self.ptr(builder).alignment; + } + pub fn toLlvm(self: Index, builder: *const Builder) *llvm.Value { return self.ptrConst(builder).global.toLlvm(builder); } diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig index bb68e28bf2..d7144b36ce 100644 --- a/src/codegen/llvm/bindings.zig +++ b/src/codegen/llvm/bindings.zig @@ -273,6 +273,9 @@ pub const Value = opaque { pub const setAlignment = LLVMSetAlignment; extern fn LLVMSetAlignment(V: *Value, Bytes: c_uint) void; + pub const getAlignment = LLVMGetAlignment; + extern fn LLVMGetAlignment(V: *Value) c_uint; + pub const setFunctionCallConv = LLVMSetFunctionCallConv; extern fn LLVMSetFunctionCallConv(Fn: *Value, CC: CallConv) void; diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index ded73d6afd..e7e6ebdef3 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -959,12 +959,17 @@ const DeclGen = struct { } } - fn constantAnonDeclRef(self: *DeclGen, ty: Type, decl_val: InternPool.Index) !IdRef { + fn constantAnonDeclRef( + self: *DeclGen, + ty: Type, + anon_decl: InternPool.Key.Ptr.Addr.AnonDecl, + ) !IdRef { // TODO: Merge this function with constantDeclRef. const mod = self.module; const ip = &mod.intern_pool; const ty_ref = try self.resolveType(ty, .direct); + const decl_val = anon_decl.val; const decl_ty = ip.typeOf(decl_val).toType(); if (decl_val.toValue().getFunction(mod)) |func| { |
