Commit 7bab406c79
Changed files (13)
src/arch/wasm/CodeGen.zig
@@ -3139,16 +3139,25 @@ fn lowerParentPtrDecl(func: *CodeGen, ptr_val: Value, decl_index: Module.Decl.In
return func.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl_index, offset);
}
-fn lowerAnonDeclRef(func: *CodeGen, anon_decl: InternPool.Index, offset: u32) InnerError!WValue {
+fn lowerAnonDeclRef(
+ func: *CodeGen,
+ anon_decl: InternPool.Key.Ptr.Addr.AnonDecl,
+ offset: u32,
+) InnerError!WValue {
const mod = func.bin_file.base.options.module.?;
- const ty = mod.intern_pool.typeOf(anon_decl).toType();
+ const decl_val = anon_decl.val;
+ const ty = mod.intern_pool.typeOf(decl_val).toType();
const is_fn_body = ty.zigTypeTag(mod) == .Fn;
if (!is_fn_body and !ty.hasRuntimeBitsIgnoreComptime(mod)) {
return WValue{ .imm32 = 0xaaaaaaaa };
}
- const res = try func.bin_file.lowerAnonDecl(anon_decl, func.decl.srcLoc(mod));
+ const alignment = mod.intern_pool.indexToKey(anon_decl.orig_ty).ptr_type.flags.alignment;
+ if (alignment != .none) {
+ @panic("TODO how to make this anon decl be aligned?");
+ }
+ const res = try func.bin_file.lowerAnonDecl(decl_val, func.decl.srcLoc(mod));
switch (res) {
.ok => {},
.fail => |em| {
@@ -3156,7 +3165,7 @@ fn lowerAnonDeclRef(func: *CodeGen, anon_decl: InternPool.Index, offset: u32) In
return error.CodegenFail;
},
}
- const target_atom_index = func.bin_file.anon_decls.get(anon_decl).?;
+ const target_atom_index = func.bin_file.anon_decls.get(decl_val).?;
const target_sym_index = func.bin_file.getAtom(target_atom_index).getSymbolIndex().?;
if (is_fn_body) {
return WValue{ .function_index = target_sym_index };
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;
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);
}
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);
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(
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| {
src/link/C.zig
@@ -7,6 +7,7 @@ const fs = std.fs;
const C = @This();
const Module = @import("../Module.zig");
const InternPool = @import("../InternPool.zig");
+const Alignment = InternPool.Alignment;
const Compilation = @import("../Compilation.zig");
const codegen = @import("../codegen/c.zig");
const link = @import("../link.zig");
@@ -30,6 +31,10 @@ string_bytes: std.ArrayListUnmanaged(u8) = .{},
/// Tracks all the anonymous decls that are used by all the decls so they can
/// be rendered during flush().
anon_decls: std.AutoArrayHashMapUnmanaged(InternPool.Index, DeclBlock) = .{},
+/// Sparse set of anon decls that are overaligned. Underaligned anon decls are
+/// lowered the same as ABI-aligned anon decls. The keys here are a subset of
+/// the keys of `anon_decls`.
+aligned_anon_decls: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment) = .{},
/// Optimization, `updateDecl` reuses this buffer rather than creating a new
/// one with every call.
@@ -125,6 +130,7 @@ pub fn deinit(self: *C) void {
db.deinit(gpa);
}
self.anon_decls.deinit(gpa);
+ self.aligned_anon_decls.deinit(gpa);
self.string_bytes.deinit(gpa);
self.fwd_decl_buf.deinit(gpa);
@@ -179,6 +185,7 @@ pub fn updateFunc(
.fwd_decl = fwd_decl.toManaged(gpa),
.ctypes = ctypes.*,
.anon_decl_deps = self.anon_decls,
+ .aligned_anon_decls = self.aligned_anon_decls,
},
.code = code.toManaged(gpa),
.indent_writer = undefined, // set later so we can get a pointer to object.code
@@ -189,6 +196,7 @@ pub fn updateFunc(
function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() };
defer {
self.anon_decls = function.object.dg.anon_decl_deps;
+ self.aligned_anon_decls = function.object.dg.aligned_anon_decls;
fwd_decl.* = function.object.dg.fwd_decl.moveToUnmanaged();
code.* = function.object.code.moveToUnmanaged();
function.deinit();
@@ -232,6 +240,7 @@ fn updateAnonDecl(self: *C, module: *Module, i: usize) !void {
.fwd_decl = fwd_decl.toManaged(gpa),
.ctypes = .{},
.anon_decl_deps = self.anon_decls,
+ .aligned_anon_decls = self.aligned_anon_decls,
},
.code = code.toManaged(gpa),
.indent_writer = undefined, // set later so we can get a pointer to object.code
@@ -240,6 +249,7 @@ fn updateAnonDecl(self: *C, module: *Module, i: usize) !void {
defer {
self.anon_decls = object.dg.anon_decl_deps;
+ self.aligned_anon_decls = object.dg.aligned_anon_decls;
object.dg.ctypes.deinit(object.dg.gpa);
fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
code.* = object.code.moveToUnmanaged();
@@ -250,7 +260,8 @@ fn updateAnonDecl(self: *C, module: *Module, i: usize) !void {
.val = anon_decl.toValue(),
};
const c_value: codegen.CValue = .{ .constant = anon_decl };
- codegen.genDeclValue(&object, tv, false, c_value, .none, .none) catch |err| switch (err) {
+ const alignment: Alignment = self.aligned_anon_decls.get(anon_decl) orelse .none;
+ codegen.genDeclValue(&object, tv, false, c_value, alignment, .none) catch |err| switch (err) {
error.AnalysisFail => {
@panic("TODO: C backend AnalysisFail on anonymous decl");
//try module.failed_decls.put(gpa, decl_index, object.dg.error_msg.?);
@@ -296,6 +307,7 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !voi
.fwd_decl = fwd_decl.toManaged(gpa),
.ctypes = ctypes.*,
.anon_decl_deps = self.anon_decls,
+ .aligned_anon_decls = self.aligned_anon_decls,
},
.code = code.toManaged(gpa),
.indent_writer = undefined, // set later so we can get a pointer to object.code
@@ -303,6 +315,7 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !voi
object.indent_writer = .{ .underlying_writer = object.code.writer() };
defer {
self.anon_decls = object.dg.anon_decl_deps;
+ self.aligned_anon_decls = object.dg.aligned_anon_decls;
object.dg.ctypes.deinit(object.dg.gpa);
fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
code.* = object.code.moveToUnmanaged();
@@ -602,6 +615,7 @@ fn flushErrDecls(self: *C, ctypes: *codegen.CType.Store) FlushDeclError!void {
.fwd_decl = fwd_decl.toManaged(gpa),
.ctypes = ctypes.*,
.anon_decl_deps = self.anon_decls,
+ .aligned_anon_decls = self.aligned_anon_decls,
},
.code = code.toManaged(gpa),
.indent_writer = undefined, // set later so we can get a pointer to object.code
@@ -609,6 +623,7 @@ fn flushErrDecls(self: *C, ctypes: *codegen.CType.Store) FlushDeclError!void {
object.indent_writer = .{ .underlying_writer = object.code.writer() };
defer {
self.anon_decls = object.dg.anon_decl_deps;
+ self.aligned_anon_decls = object.dg.aligned_anon_decls;
object.dg.ctypes.deinit(gpa);
fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
code.* = object.code.moveToUnmanaged();
@@ -642,6 +657,7 @@ fn flushLazyFn(
.fwd_decl = fwd_decl.toManaged(gpa),
.ctypes = ctypes.*,
.anon_decl_deps = .{},
+ .aligned_anon_decls = .{},
},
.code = code.toManaged(gpa),
.indent_writer = undefined, // set later so we can get a pointer to object.code
@@ -651,6 +667,7 @@ fn flushLazyFn(
// If this assert trips just handle the anon_decl_deps the same as
// `updateFunc()` does.
assert(object.dg.anon_decl_deps.count() == 0);
+ assert(object.dg.aligned_anon_decls.count() == 0);
object.dg.ctypes.deinit(gpa);
fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
code.* = object.code.moveToUnmanaged();
src/codegen.zig
@@ -713,7 +713,7 @@ const RelocInfo = struct {
fn lowerAnonDeclRef(
bin_file: *link.File,
src_loc: Module.SrcLoc,
- decl_val: InternPool.Index,
+ anon_decl: InternPool.Key.Ptr.Addr.AnonDecl,
code: *std.ArrayList(u8),
debug_output: DebugInfoOutput,
reloc_info: RelocInfo,
@@ -723,6 +723,7 @@ fn lowerAnonDeclRef(
const mod = bin_file.options.module.?;
const ptr_width_bytes = @divExact(target.ptrBitWidth(), 8);
+ const decl_val = anon_decl.val;
const decl_ty = mod.intern_pool.typeOf(decl_val).toType();
const is_fn_body = decl_ty.zigTypeTag(mod) == .Fn;
if (!is_fn_body and !decl_ty.hasRuntimeBits(mod)) {
@@ -736,6 +737,10 @@ fn lowerAnonDeclRef(
.fail => |em| return .{ .fail = em },
}
+ const alignment = mod.intern_pool.indexToKey(anon_decl.orig_ty).ptr_type.flags.alignment;
+ if (alignment != .none) {
+ @panic("TODO how to make this anon decl be aligned?");
+ }
const vaddr = try bin_file.getAnonDeclVAddr(decl_val, .{
.parent_atom_index = reloc_info.parent_atom_index,
.offset = code.items.len,
src/Compilation.zig
@@ -3545,6 +3545,7 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v
.fwd_decl = fwd_decl.toManaged(gpa),
.ctypes = .{},
.anon_decl_deps = .{},
+ .aligned_anon_decls = .{},
};
defer {
dg.ctypes.deinit(gpa);
src/InternPool.zig
@@ -1074,7 +1074,7 @@ pub const Key = union(enum) {
decl: Module.Decl.Index,
mut_decl: MutDecl,
- anon_decl: Index,
+ anon_decl: AnonDecl,
comptime_field: Index,
int: Index,
eu_payload: Index,
@@ -1090,6 +1090,14 @@ pub const Key = union(enum) {
base: Index,
index: u64,
};
+ pub const AnonDecl = extern struct {
+ val: Index,
+ /// Contains the canonical pointer type of the anonymous
+ /// declaration. This may equal `ty` of the `Ptr` or it may be
+ /// different. Importantly, when lowering the anonymous decl,
+ /// the original pointer type alignment must be used.
+ orig_ty: Index,
+ };
};
};
@@ -1231,7 +1239,8 @@ pub const Key = union(enum) {
common ++ asBytes(&x.decl) ++ asBytes(&x.runtime_index),
),
- .anon_decl,
+ .anon_decl => |x| Hash.hash(seed2, common ++ asBytes(&x)),
+
.int,
.eu_payload,
.opt_payload,
@@ -1500,7 +1509,8 @@ pub const Key = union(enum) {
return switch (a_info.addr) {
.decl => |a_decl| a_decl == b_info.addr.decl,
.mut_decl => |a_mut_decl| std.meta.eql(a_mut_decl, b_info.addr.mut_decl),
- .anon_decl => |a_decl| a_decl == b_info.addr.anon_decl,
+ .anon_decl => |ad| ad.val == b_info.addr.anon_decl.val and
+ ad.orig_ty == b_info.addr.anon_decl.orig_ty,
.int => |a_int| a_int == b_info.addr.int,
.eu_payload => |a_eu_payload| a_eu_payload == b_info.addr.eu_payload,
.opt_payload => |a_opt_payload| a_opt_payload == b_info.addr.opt_payload,
@@ -2133,6 +2143,7 @@ pub const Index = enum(u32) {
ptr_decl: struct { data: *PtrDecl },
ptr_mut_decl: struct { data: *PtrMutDecl },
ptr_anon_decl: struct { data: *PtrAnonDecl },
+ ptr_anon_decl_aligned: struct { data: *PtrAnonDeclAligned },
ptr_comptime_field: struct { data: *PtrComptimeField },
ptr_int: struct { data: *PtrBase },
ptr_eu_payload: struct { data: *PtrBase },
@@ -2583,8 +2594,16 @@ pub const Tag = enum(u8) {
/// data is extra index of `PtrMutDecl`, which contains the type and address.
ptr_mut_decl,
/// A pointer to an anonymous decl.
- /// data is extra index of `PtrAnonDecl`, which contains the type and decl value.
+ /// data is extra index of `PtrAnonDecl`, which contains the pointer type and decl value.
+ /// The alignment of the anonymous decl is communicated via the pointer type.
ptr_anon_decl,
+ /// A pointer to an anonymous decl.
+ /// data is extra index of `PtrAnonDeclAligned`, which contains the pointer
+ /// type and decl value.
+ /// The original pointer type is also provided, which will be different than `ty`.
+ /// This encoding is only used when a pointer to an anonymous decl is
+ /// coerced to a different pointer type with a different alignment.
+ ptr_anon_decl_aligned,
/// data is extra index of `PtrComptimeField`, which contains the pointer type and field value.
ptr_comptime_field,
/// A pointer with an integer value.
@@ -2781,6 +2800,7 @@ pub const Tag = enum(u8) {
.ptr_decl => PtrDecl,
.ptr_mut_decl => PtrMutDecl,
.ptr_anon_decl => PtrAnonDecl,
+ .ptr_anon_decl_aligned => PtrAnonDeclAligned,
.ptr_comptime_field => PtrComptimeField,
.ptr_int => PtrBase,
.ptr_eu_payload => PtrBase,
@@ -3383,6 +3403,13 @@ pub const PtrAnonDecl = struct {
val: Index,
};
+pub const PtrAnonDeclAligned = struct {
+ ty: Index,
+ val: Index,
+ /// Must be nonequal to `ty`. Only the alignment from this value is important.
+ orig_ty: Index,
+};
+
pub const PtrMutDecl = struct {
ty: Index,
decl: Module.Decl.Index,
@@ -3736,7 +3763,20 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
const info = ip.extraData(PtrAnonDecl, data);
return .{ .ptr = .{
.ty = info.ty,
- .addr = .{ .anon_decl = info.val },
+ .addr = .{ .anon_decl = .{
+ .val = info.val,
+ .orig_ty = info.ty,
+ } },
+ } };
+ },
+ .ptr_anon_decl_aligned => {
+ const info = ip.extraData(PtrAnonDeclAligned, data);
+ return .{ .ptr = .{
+ .ty = info.ty,
+ .addr = .{ .anon_decl = .{
+ .val = info.val,
+ .orig_ty = info.orig_ty,
+ } },
} };
},
.ptr_comptime_field => {
@@ -3817,7 +3857,17 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
} };
},
.ptr_anon_decl => .{
- .anon_decl = ip.extraData(PtrAnonDecl, ptr_item.data).val,
+ .anon_decl = .{
+ .val = ip.extraData(PtrAnonDecl, ptr_item.data).val,
+ .orig_ty = info.ty,
+ },
+ },
+ .ptr_anon_decl_aligned => b: {
+ const sub_info = ip.extraData(PtrAnonDeclAligned, ptr_item.data);
+ break :b .{ .anon_decl = .{
+ .val = sub_info.val,
+ .orig_ty = sub_info.orig_ty,
+ } };
},
.ptr_comptime_field => .{
.comptime_field = ip.extraData(PtrComptimeField, ptr_item.data).field_val,
@@ -4571,13 +4621,22 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
.runtime_index = mut_decl.runtime_index,
}),
}),
- .anon_decl => |anon_decl| ip.items.appendAssumeCapacity(.{
- .tag = .ptr_anon_decl,
- .data = try ip.addExtra(gpa, PtrAnonDecl{
- .ty = ptr.ty,
- .val = anon_decl,
- }),
- }),
+ .anon_decl => |anon_decl| ip.items.appendAssumeCapacity(
+ if (ptrsHaveSameAlignment(ip, ptr.ty, ptr_type, anon_decl.orig_ty)) .{
+ .tag = .ptr_anon_decl,
+ .data = try ip.addExtra(gpa, PtrAnonDecl{
+ .ty = ptr.ty,
+ .val = anon_decl.val,
+ }),
+ } else .{
+ .tag = .ptr_anon_decl_aligned,
+ .data = try ip.addExtra(gpa, PtrAnonDeclAligned{
+ .ty = ptr.ty,
+ .val = anon_decl.val,
+ .orig_ty = anon_decl.orig_ty,
+ }),
+ },
+ ),
.comptime_field => |field_val| {
assert(field_val != .none);
ip.items.appendAssumeCapacity(.{
@@ -7184,6 +7243,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
.ptr_decl => @sizeOf(PtrDecl),
.ptr_mut_decl => @sizeOf(PtrMutDecl),
.ptr_anon_decl => @sizeOf(PtrAnonDecl),
+ .ptr_anon_decl_aligned => @sizeOf(PtrAnonDeclAligned),
.ptr_comptime_field => @sizeOf(PtrComptimeField),
.ptr_int => @sizeOf(PtrBase),
.ptr_eu_payload => @sizeOf(PtrBase),
@@ -7314,6 +7374,7 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {
.ptr_decl,
.ptr_mut_decl,
.ptr_anon_decl,
+ .ptr_anon_decl_aligned,
.ptr_comptime_field,
.ptr_int,
.ptr_eu_payload,
@@ -7695,6 +7756,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
inline .ptr_decl,
.ptr_mut_decl,
.ptr_anon_decl,
+ .ptr_anon_decl_aligned,
.ptr_comptime_field,
.ptr_int,
.ptr_eu_payload,
@@ -7855,7 +7917,7 @@ pub fn getBackingAddrTag(ip: *const InternPool, val: Index) ?Key.Ptr.Addr.Tag {
switch (ip.items.items(.tag)[base]) {
.ptr_decl => return .decl,
.ptr_mut_decl => return .mut_decl,
- .ptr_anon_decl => return .anon_decl,
+ .ptr_anon_decl, .ptr_anon_decl_aligned => return .anon_decl,
.ptr_comptime_field => return .comptime_field,
.ptr_int => return .int,
inline .ptr_eu_payload,
@@ -8032,6 +8094,7 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois
.ptr_decl,
.ptr_mut_decl,
.ptr_anon_decl,
+ .ptr_anon_decl_aligned,
.ptr_comptime_field,
.ptr_int,
.ptr_eu_payload,
@@ -8281,3 +8344,12 @@ pub fn addFieldName(
ip.extra.items[names_start + field_index] = @intFromEnum(name);
return null;
}
+
+/// Used only by `get` for pointer values, and mainly intended to use `Tag.ptr_anon_decl`
+/// encoding instead of `Tag.ptr_anon_decl_aligned` when possible.
+fn ptrsHaveSameAlignment(ip: *InternPool, a_ty: Index, a_info: Key.PtrType, b_ty: Index) bool {
+ if (a_ty == b_ty) return true;
+ const b_info = ip.indexToKey(b_ty).ptr_type;
+ return a_info.flags.alignment == b_info.flags.alignment and
+ (a_info.child == b_info.child or a_info.flags.alignment != .none);
+}
src/Sema.zig
@@ -3659,7 +3659,10 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
if (try sema.resolveComptimeKnownAllocValue(block, alloc, null)) |val| {
const new_mut_ptr = Air.internedToRef((try mod.intern(.{ .ptr = .{
.ty = alloc_ty.toIntern(),
- .addr = .{ .anon_decl = val },
+ .addr = .{ .anon_decl = .{
+ .val = val,
+ .orig_ty = alloc_ty.toIntern(),
+ } },
} })));
return sema.makePtrConst(block, new_mut_ptr);
}
@@ -5540,7 +5543,10 @@ fn addStrLitNoAlias(sema: *Sema, bytes: []const u8) CompileError!Air.Inst.Ref {
});
return Air.internedToRef((try mod.intern(.{ .ptr = .{
.ty = ptr_ty.toIntern(),
- .addr = .{ .anon_decl = val },
+ .addr = .{ .anon_decl = .{
+ .val = val,
+ .orig_ty = ptr_ty.toIntern(),
+ } },
} })));
}
@@ -30546,7 +30552,8 @@ fn beginComptimePtrLoad(
.ty_without_well_defined_layout = if (!layout_defined) decl.ty else null,
};
},
- .anon_decl => |decl_val| blk: {
+ .anon_decl => |anon_decl| blk: {
+ const decl_val = anon_decl.val;
if (decl_val.toValue().getVariable(mod) != null) return error.RuntimeLoad;
const decl_ty = ip.typeOf(decl_val).toType();
const decl_tv: TypedValue = .{ .ty = decl_ty, .val = decl_val.toValue() };
@@ -36650,6 +36657,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
.simple_value,
.ptr_decl,
.ptr_anon_decl,
+ .ptr_anon_decl_aligned,
.ptr_mut_decl,
.ptr_comptime_field,
.ptr_int,
src/TypedValue.zig
@@ -321,7 +321,8 @@ pub fn print(
.val = decl.val,
}, writer, level - 1, mod);
},
- .anon_decl => |decl_val| {
+ .anon_decl => |anon_decl| {
+ const decl_val = anon_decl.val;
if (level == 0) return writer.print("(anon decl '{d}')", .{
@intFromEnum(decl_val),
});
src/value.zig
@@ -1571,7 +1571,7 @@ pub const Value = struct {
.none => switch (ip.indexToKey(switch (ptr.addr) {
.decl => |decl| mod.declPtr(decl).ty.toIntern(),
.mut_decl => |mut_decl| mod.declPtr(mut_decl.decl).ty.toIntern(),
- .anon_decl => |anon_decl| ip.typeOf(anon_decl),
+ .anon_decl => |anon_decl| ip.typeOf(anon_decl.val),
.comptime_field => |comptime_field| ip.typeOf(comptime_field),
else => unreachable,
})) {
@@ -1604,7 +1604,7 @@ pub const Value = struct {
})).toValue(),
.ptr => |ptr| switch (ptr.addr) {
.decl => |decl| mod.declPtr(decl).val.maybeElemValue(mod, index),
- .anon_decl => |anon_decl| anon_decl.toValue().maybeElemValue(mod, index),
+ .anon_decl => |anon_decl| anon_decl.val.toValue().maybeElemValue(mod, index),
.mut_decl => |mut_decl| (try mod.declPtr(mut_decl.decl).internValue(mod))
.toValue().maybeElemValue(mod, index),
.int, .eu_payload => null,