aboutsummaryrefslogtreecommitdiff
path: root/src/codegen
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2023-10-19 15:10:35 -0700
committerAndrew Kelley <andrew@ziglang.org>2023-10-21 21:38:41 -0400
commit7bab406c790566781406a7968be22961ed7c305d (patch)
treee2f778d1c66dd62bf41da837bb76a882b792ec6e /src/codegen
parent5aa82ed477b85cf8681bc0dc65f97e813990a2ed (diff)
downloadzig-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.zig21
-rw-r--r--src/codegen/llvm.zig31
-rw-r--r--src/codegen/llvm/Builder.zig6
-rw-r--r--src/codegen/llvm/bindings.zig3
-rw-r--r--src/codegen/spirv.zig7
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| {