authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-04-21 06:37:24-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-04-24 11:48:37-04:00
log221fb30b3c961f81e99bfe9b25db8460e6231824
tree5ac2c73284624453368d4e537b770b930b792b79
parent53373c4c719ff6244d7099ad1ceeda18d40e09e3

llvm: implement restricted type optimizations


12 files changed, 561 insertions(+), 222 deletions(-)

lib/std/zig/llvm/Builder.zig+300-136
......@@ -1284,7 +1284,7 @@ pub const Attribute = union(Kind) {
12841284 try w.print(" {t}(\"", .{attribute});
12851285 var any = false;
12861286 inline for (@typeInfo(AllocKind).@"struct".fields) |field| {
1287 if (comptime std.mem.eql(u8, field.name, "_")) continue;
1287 if (comptime std.mem.eql(u8, field.name, "unused")) continue;
12881288 if (@field(allockind, field.name)) {
12891289 if (!any) {
12901290 try w.writeByte(',');
......@@ -1469,7 +1469,7 @@ pub const Attribute = union(Kind) {
14691469 positive_subnormal: bool = false,
14701470 positive_normal: bool = false,
14711471 positive_infinity: bool = false,
1472 _: u22 = 0,
1472 unused: enum(u22) { unused = 0 } = .unused,
14731473
14741474 pub const all = FpClass{
14751475 .signaling_nan = true,
......@@ -1512,7 +1512,7 @@ pub const Attribute = union(Kind) {
15121512 uninitialized: bool,
15131513 zeroed: bool,
15141514 aligned: bool,
1515 _: u26 = 0,
1515 unused: enum(u26) { unused = 0 } = .unused,
15161516 };
15171517
15181518 pub const AllocSize = packed struct(u32) {
......@@ -1533,7 +1533,7 @@ pub const Attribute = union(Kind) {
15331533 argmem: Effect = .none,
15341534 inaccessiblemem: Effect = .none,
15351535 other: Effect = .none,
1536 _: u26 = 0,
1536 unused: enum(u26) { unused = 0 } = .unused,
15371537
15381538 pub const Effect = enum(u2) { none, read, write, readwrite };
15391539
......@@ -1553,7 +1553,7 @@ pub const Attribute = union(Kind) {
15531553 pub const VScaleRange = packed struct(u32) {
15541554 min: Alignment,
15551555 max: Alignment,
1556 _: u20 = 0,
1556 unused: enum(u20) { unused = 0 } = .unused,
15571557
15581558 fn toLlvm(self: VScaleRange) packed struct(u64) { max: u32, min: u32 } {
15591559 return .{
......@@ -1870,7 +1870,7 @@ pub const ThreadLocal = enum(u3) {
18701870
18711871 pub fn format(p: Prefixed, w: *Writer) Writer.Error!void {
18721872 switch (p.thread_local) {
1873 .default => return,
1873 .default => {},
18741874 .generaldynamic => {
18751875 var vecs: [2][]const u8 = .{ p.prefix, "thread_local" };
18761876 return w.writeVecAll(&vecs);
......@@ -4221,7 +4221,6 @@ pub const Function = struct {
42214221 call,
42224222 @"call fast",
42234223 cmpxchg,
4224 @"cmpxchg weak",
42254224 extractelement,
42264225 extractvalue,
42274226 fadd,
......@@ -4619,9 +4618,7 @@ pub const Function = struct {
46194618 .@"tail call",
46204619 .@"tail call fast",
46214620 => wip.extraData(Call, instruction.data).ty.functionReturn(wip.builder),
4622 .cmpxchg,
4623 .@"cmpxchg weak",
4624 => wip.builder.structTypeAssumeCapacity(.normal, &.{
4621 .cmpxchg => wip.builder.structTypeAssumeCapacity(.normal, &.{
46254622 wip.extraData(CmpXchg, instruction.data).cmp.typeOfWip(wip),
46264623 .i1,
46274624 }),
......@@ -4806,9 +4803,7 @@ pub const Function = struct {
48064803 .@"tail call",
48074804 .@"tail call fast",
48084805 => function.extraData(Call, instruction.data).ty.functionReturn(builder),
4809 .cmpxchg,
4810 .@"cmpxchg weak",
4811 => builder.structTypeAssumeCapacity(.normal, &.{
4806 .cmpxchg => builder.structTypeAssumeCapacity(.normal, &.{
48124807 function.extraData(CmpXchg, instruction.data)
48134808 .cmp.typeOf(function_index, builder),
48144809 .i1,
......@@ -5027,33 +5022,86 @@ pub const Function = struct {
50275022 pub const Info = packed struct(u32) {
50285023 alignment: Alignment,
50295024 addr_space: AddrSpace,
5030 _: u2 = undefined,
5025 unused: enum(u2) { unused = 0 } = .unused,
50315026 };
50325027 };
50335028
50345029 pub const Load = struct {
5035 info: MemoryAccessInfo,
5030 info: Info,
50365031 type: Type,
50375032 ptr: Value,
5033 //range: if (info.has_range) Metadata else void,
5034
5035 pub const Info = packed struct(u32) {
5036 access_kind: MemoryAccessKind,
5037 sync_scope: SyncScope,
5038 ordering: AtomicOrdering,
5039 alignment: Alignment,
5040 has_range: bool,
5041 unused: enum(u20) { unused = 0 } = .unused,
5042 };
50385043 };
50395044
50405045 pub const Store = struct {
5041 info: MemoryAccessInfo,
5046 info: Info,
50425047 val: Value,
50435048 ptr: Value,
5049
5050 pub const Info = packed struct(u32) {
5051 access_kind: MemoryAccessKind,
5052 sync_scope: SyncScope,
5053 ordering: AtomicOrdering,
5054 alignment: Alignment,
5055 unused: enum(u21) { unused = 0 } = .unused,
5056 };
50445057 };
50455058
50465059 pub const CmpXchg = struct {
5047 info: MemoryAccessInfo,
5060 info: Info,
50485061 ptr: Value,
50495062 cmp: Value,
50505063 new: Value,
50515064
5052 pub const Kind = enum { strong, weak };
5065 pub const Kind = enum(u1) {
5066 strong,
5067 weak,
5068
5069 pub fn format(kind: Kind, w: *Writer) Writer.Error!void {
5070 return Prefixed.format(.{ .kind = kind, .prefix = "" }, w);
5071 }
5072
5073 pub const Prefixed = struct {
5074 kind: Kind,
5075 prefix: []const u8,
5076
5077 pub fn format(p: Prefixed, w: *Writer) Writer.Error!void {
5078 switch (p.kind) {
5079 .strong => {},
5080 .weak => {
5081 var vecs: [2][]const u8 = .{ p.prefix, "weak" };
5082 try w.writeVecAll(&vecs);
5083 },
5084 }
5085 }
5086 };
5087
5088 pub fn fmt(kind: Kind, prefix: []const u8) Prefixed {
5089 return .{ .kind = kind, .prefix = prefix };
5090 }
5091 };
5092 pub const Info = packed struct(u32) {
5093 kind: Kind,
5094 access_kind: MemoryAccessKind,
5095 sync_scope: SyncScope,
5096 success_ordering: AtomicOrdering,
5097 failure_ordering: AtomicOrdering,
5098 alignment: Alignment,
5099 unused: enum(u17) { unused = 0 } = .unused,
5100 };
50535101 };
50545102
50555103 pub const AtomicRmw = struct {
5056 info: MemoryAccessInfo,
5104 info: Info,
50575105 ptr: Value,
50585106 val: Value,
50595107
......@@ -5073,8 +5121,21 @@ pub const Function = struct {
50735121 fsub = 12,
50745122 fmax = 13,
50755123 fmin = 14,
5076 none = maxInt(u5),
50775124 };
5125 pub const Info = packed struct(u32) {
5126 access_kind: MemoryAccessKind,
5127 operation: Operation,
5128 sync_scope: SyncScope,
5129 ordering: AtomicOrdering,
5130 alignment: Alignment,
5131 unused: enum(u16) { unused = 0 } = .unused,
5132 };
5133 };
5134
5135 pub const Fence = packed struct(u32) {
5136 sync_scope: SyncScope,
5137 success_ordering: AtomicOrdering,
5138 unused: enum(u28) { unused = 0 } = .unused,
50785139 };
50795140
50805141 pub const GetElementPtr = struct {
......@@ -5112,6 +5173,7 @@ pub const Function = struct {
51125173 callee: Value,
51135174 args_len: u32,
51145175 //args: [args_len]Value,
5176 //callees: if (info.has_callees) Metadata else void,
51155177
51165178 pub const Kind = enum {
51175179 normal,
......@@ -5125,8 +5187,9 @@ pub const Function = struct {
51255187 };
51265188 pub const Info = packed struct(u32) {
51275189 call_conv: CallConv,
5190 has_callees: bool,
51285191 has_op_bundle_cold: bool,
5129 _: u21 = undefined,
5192 unused: enum(u20) { unused = 0 } = .unused,
51305193 };
51315194 };
51325195
......@@ -5195,8 +5258,11 @@ pub const Function = struct {
51955258 Value,
51965259 Instruction.BrCond.Weights,
51975260 => @enumFromInt(value),
5198 MemoryAccessInfo,
51995261 Instruction.Alloca.Info,
5262 Instruction.Load.Info,
5263 Instruction.Store.Info,
5264 Instruction.CmpXchg.Info,
5265 Instruction.AtomicRmw.Info,
52005266 Instruction.Call.Info,
52015267 => @bitCast(value),
52025268 else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)),
......@@ -5706,6 +5772,10 @@ pub const WipFunction = struct {
57065772 return instruction.toValue();
57075773 }
57085774
5775 pub const LoadMetadata = struct {
5776 range: Metadata.Optional = .none,
5777 };
5778
57095779 pub fn load(
57105780 self: *WipFunction,
57115781 access_kind: MemoryAccessKind,
......@@ -5714,7 +5784,19 @@ pub const WipFunction = struct {
57145784 alignment: Alignment,
57155785 name: []const u8,
57165786 ) Allocator.Error!Value {
5717 return self.loadAtomic(access_kind, ty, ptr, .system, .none, alignment, name);
5787 return self.loadMetadata(access_kind, ty, ptr, alignment, .{}, name);
5788 }
5789
5790 pub fn loadMetadata(
5791 self: *WipFunction,
5792 access_kind: MemoryAccessKind,
5793 ty: Type,
5794 ptr: Value,
5795 alignment: Alignment,
5796 metadata: LoadMetadata,
5797 name: []const u8,
5798 ) Allocator.Error!Value {
5799 return self.loadAtomicMetadata(access_kind, ty, ptr, .system, .none, alignment, metadata, name);
57185800 }
57195801
57205802 pub fn loadAtomic(
......@@ -5726,6 +5808,20 @@ pub const WipFunction = struct {
57265808 ordering: AtomicOrdering,
57275809 alignment: Alignment,
57285810 name: []const u8,
5811 ) Allocator.Error!Value {
5812 return self.loadAtomicMetadata(access_kind, ty, ptr, sync_scope, ordering, alignment, .{}, name);
5813 }
5814
5815 pub fn loadAtomicMetadata(
5816 self: *WipFunction,
5817 access_kind: MemoryAccessKind,
5818 ty: Type,
5819 ptr: Value,
5820 sync_scope: SyncScope,
5821 ordering: AtomicOrdering,
5822 alignment: Alignment,
5823 metadata: LoadMetadata,
5824 name: []const u8,
57295825 ) Allocator.Error!Value {
57305826 assert(ptr.typeOfWip(self).isPointer(self.builder));
57315827 try self.ensureUnusedExtraCapacity(1, Instruction.Load, 0);
......@@ -5741,13 +5837,15 @@ pub const WipFunction = struct {
57415837 .none => .system,
57425838 else => sync_scope,
57435839 },
5744 .success_ordering = ordering,
5840 .ordering = ordering,
57455841 .alignment = alignment,
5842 .has_range = !metadata.range.is_none,
57465843 },
57475844 .type = ty,
57485845 .ptr = ptr,
57495846 }),
57505847 });
5848 if (metadata.range.unwrap()) |range| self.extra.appendAssumeCapacity(@bitCast(range));
57515849 return instruction.toValue();
57525850 }
57535851
......@@ -5784,7 +5882,7 @@ pub const WipFunction = struct {
57845882 .none => .system,
57855883 else => sync_scope,
57865884 },
5787 .success_ordering = ordering,
5885 .ordering = ordering,
57885886 .alignment = alignment,
57895887 },
57905888 .val = val,
......@@ -5803,7 +5901,7 @@ pub const WipFunction = struct {
58035901 try self.ensureUnusedExtraCapacity(1, NoExtra, 0);
58045902 const instruction = try self.addInst(null, .{
58055903 .tag = .fence,
5806 .data = @bitCast(MemoryAccessInfo{
5904 .data = @bitCast(Instruction.Fence{
58075905 .sync_scope = sync_scope,
58085906 .success_ordering = ordering,
58095907 }),
......@@ -5833,12 +5931,10 @@ pub const WipFunction = struct {
58335931 _ = try self.builder.structType(.normal, &.{ ty, .i1 });
58345932 try self.ensureUnusedExtraCapacity(1, Instruction.CmpXchg, 0);
58355933 const instruction = try self.addInst(name, .{
5836 .tag = switch (kind) {
5837 .strong => .cmpxchg,
5838 .weak => .@"cmpxchg weak",
5839 },
5934 .tag = .cmpxchg,
58405935 .data = self.addExtraAssumeCapacity(Instruction.CmpXchg{
58415936 .info = .{
5937 .kind = kind,
58425938 .access_kind = access_kind,
58435939 .sync_scope = sync_scope,
58445940 .success_ordering = success_ordering,
......@@ -5873,9 +5969,9 @@ pub const WipFunction = struct {
58735969 .data = self.addExtraAssumeCapacity(Instruction.AtomicRmw{
58745970 .info = .{
58755971 .access_kind = access_kind,
5876 .atomic_rmw_operation = operation,
5972 .operation = operation,
58775973 .sync_scope = sync_scope,
5878 .success_ordering = ordering,
5974 .ordering = ordering,
58795975 .alignment = alignment,
58805976 },
58815977 .ptr = ptr,
......@@ -6079,6 +6175,11 @@ pub const WipFunction = struct {
60796175 }, cond, lhs, rhs, name);
60806176 }
60816177
6178 pub const CallMetadata = struct {
6179 callees: Metadata.Optional = .none,
6180 has_op_bundle_cold: bool = false,
6181 };
6182
60826183 pub fn call(
60836184 self: *WipFunction,
60846185 kind: Instruction.Call.Kind,
......@@ -6089,10 +6190,10 @@ pub const WipFunction = struct {
60896190 args: []const Value,
60906191 name: []const u8,
60916192 ) Allocator.Error!Value {
6092 return self.callInner(kind, call_conv, function_attributes, ty, callee, args, name, false);
6193 return self.callMetadata(kind, call_conv, function_attributes, ty, callee, args, .{}, name);
60936194 }
60946195
6095 fn callInner(
6196 pub fn callMetadata(
60966197 self: *WipFunction,
60976198 kind: Instruction.Call.Kind,
60986199 call_conv: CallConv,
......@@ -6100,8 +6201,8 @@ pub const WipFunction = struct {
61006201 ty: Type,
61016202 callee: Value,
61026203 args: []const Value,
6204 metadata: CallMetadata,
61036205 name: []const u8,
6104 has_op_bundle_cold: bool,
61056206 ) Allocator.Error!Value {
61066207 const ret_ty = ty.functionReturn(self.builder);
61076208 assert(ty.isFunction(self.builder));
......@@ -6109,7 +6210,8 @@ pub const WipFunction = struct {
61096210 const params = ty.functionParameters(self.builder);
61106211 for (params, args[0..params.len]) |param, arg_val| assert(param == arg_val.typeOfWip(self));
61116212
6112 try self.ensureUnusedExtraCapacity(1, Instruction.Call, args.len);
6213 try self.ensureUnusedExtraCapacity(1, Instruction.Call, args.len +
6214 @intFromBool(!metadata.callees.is_none));
61136215 const instruction = try self.addInst(switch (ret_ty) {
61146216 .void => null,
61156217 else => name,
......@@ -6127,7 +6229,8 @@ pub const WipFunction = struct {
61276229 .data = self.addExtraAssumeCapacity(Instruction.Call{
61286230 .info = .{
61296231 .call_conv = call_conv,
6130 .has_op_bundle_cold = has_op_bundle_cold,
6232 .has_callees = !metadata.callees.is_none,
6233 .has_op_bundle_cold = metadata.has_op_bundle_cold,
61316234 },
61326235 .attributes = function_attributes,
61336236 .ty = ty,
......@@ -6136,6 +6239,7 @@ pub const WipFunction = struct {
61366239 }),
61376240 });
61386241 self.extra.appendSliceAssumeCapacity(@ptrCast(args));
6242 if (metadata.callees.unwrap()) |callees| self.extra.appendAssumeCapacity(@bitCast(callees));
61396243 return instruction.toValue();
61406244 }
61416245
......@@ -6176,15 +6280,15 @@ pub const WipFunction = struct {
61766280
61776281 pub fn callIntrinsicAssumeCold(self: *WipFunction) Allocator.Error!Value {
61786282 const intrinsic = try self.builder.getIntrinsic(.assume, &.{});
6179 return self.callInner(
6283 return self.callMetadata(
61806284 .normal,
61816285 CallConv.default,
61826286 .none,
61836287 intrinsic.typeOf(self.builder),
61846288 intrinsic.toValue(self.builder),
61856289 &.{try self.builder.intValue(.i1, 1)},
6186 "",
6187 true,
6290 .{ .has_op_bundle_cold = true },
6291 undefined,
61886292 );
61896293 }
61906294
......@@ -6355,8 +6459,11 @@ pub const WipFunction = struct {
63556459 Value,
63566460 Instruction.BrCond.Weights,
63576461 => @intFromEnum(value),
6358 MemoryAccessInfo,
63596462 Instruction.Alloca.Info,
6463 Instruction.Load.Info,
6464 Instruction.Store.Info,
6465 Instruction.CmpXchg.Info,
6466 Instruction.AtomicRmw.Info,
63606467 Instruction.Call.Info,
63616468 => @bitCast(value),
63626469 else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)),
......@@ -6648,6 +6755,7 @@ pub const WipFunction = struct {
66486755 => {
66496756 var extra = self.extraDataTrail(Instruction.Call, instruction.data);
66506757 const args = extra.trail.next(extra.data.args_len, Value, self);
6758 const callees = extra.trail.next(@intFromBool(extra.data.info.has_callees), Metadata, self);
66516759 instruction.data = wip_extra.addExtra(Instruction.Call{
66526760 .info = extra.data.info,
66536761 .attributes = extra.data.attributes,
......@@ -6656,10 +6764,9 @@ pub const WipFunction = struct {
66566764 .args_len = extra.data.args_len,
66576765 });
66586766 wip_extra.appendMappedValues(args, instructions);
6767 wip_extra.appendSlice(callees);
66596768 },
6660 .cmpxchg,
6661 .@"cmpxchg weak",
6662 => {
6769 .cmpxchg => {
66636770 const extra = self.extraData(Instruction.CmpXchg, instruction.data);
66646771 instruction.data = wip_extra.addExtra(Instruction.CmpXchg{
66656772 .info = extra.info,
......@@ -6730,12 +6837,14 @@ pub const WipFunction = struct {
67306837 .load,
67316838 .@"load atomic",
67326839 => {
6733 const extra = self.extraData(Instruction.Load, instruction.data);
6840 var extra = self.extraDataTrail(Instruction.Load, instruction.data);
6841 const range = extra.trail.next(@intFromBool(extra.data.info.has_range), Metadata, self);
67346842 instruction.data = wip_extra.addExtra(Instruction.Load{
6735 .type = extra.type,
6736 .ptr = instructions.map(extra.ptr),
6737 .info = extra.info,
6843 .type = extra.data.type,
6844 .ptr = instructions.map(extra.data.ptr),
6845 .info = extra.data.info,
67386846 });
6847 wip_extra.appendSlice(range);
67396848 },
67406849 .phi,
67416850 .@"phi fast",
......@@ -7011,8 +7120,11 @@ pub const WipFunction = struct {
70117120 Value,
70127121 Instruction.BrCond.Weights,
70137122 => @intFromEnum(value),
7014 MemoryAccessInfo,
70157123 Instruction.Alloca.Info,
7124 Instruction.Load.Info,
7125 Instruction.Store.Info,
7126 Instruction.CmpXchg.Info,
7127 Instruction.AtomicRmw.Info,
70167128 Instruction.Call.Info,
70177129 => @bitCast(value),
70187130 else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)),
......@@ -7060,8 +7172,11 @@ pub const WipFunction = struct {
70607172 Value,
70617173 Instruction.BrCond.Weights,
70627174 => @enumFromInt(value),
7063 MemoryAccessInfo,
70647175 Instruction.Alloca.Info,
7176 Instruction.Load.Info,
7177 Instruction.Store.Info,
7178 Instruction.CmpXchg.Info,
7179 Instruction.AtomicRmw.Info,
70657180 Instruction.Call.Info,
70667181 => @bitCast(value),
70677182 else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)),
......@@ -7121,10 +7236,10 @@ pub const MemoryAccessKind = enum(u1) {
71217236
71227237 pub fn format(p: Prefixed, w: *Writer) Writer.Error!void {
71237238 switch (p.memory_access_kind) {
7124 .normal => return,
7239 .normal => {},
71257240 .@"volatile" => {
71267241 var vecs: [2][]const u8 = .{ p.prefix, "volatile" };
7127 return w.writeVecAll(&vecs);
7242 try w.writeVecAll(&vecs);
71287243 },
71297244 }
71307245 }
......@@ -7149,10 +7264,10 @@ pub const SyncScope = enum(u1) {
71497264
71507265 pub fn format(p: Prefixed, w: *Writer) Writer.Error!void {
71517266 switch (p.sync_scope) {
7152 .system => return,
7267 .system => {},
71537268 .singlethread => {
71547269 var vecs: [2][]const u8 = .{ p.prefix, "syncscope(\"singlethread\")" };
7155 return w.writeVecAll(&vecs);
7270 try w.writeVecAll(&vecs);
71567271 },
71577272 }
71587273 }
......@@ -7182,10 +7297,10 @@ pub const AtomicOrdering = enum(u3) {
71827297
71837298 pub fn format(p: Prefixed, w: *Writer) Writer.Error!void {
71847299 switch (p.atomic_ordering) {
7185 .none => return,
7300 .none => {},
71867301 else => {
71877302 var vecs: [2][]const u8 = .{ p.prefix, @tagName(p.atomic_ordering) };
7188 return w.writeVecAll(&vecs);
7303 try w.writeVecAll(&vecs);
71897304 },
71907305 }
71917306 }
......@@ -7196,16 +7311,6 @@ pub const AtomicOrdering = enum(u3) {
71967311 }
71977312};
71987313
7199const MemoryAccessInfo = packed struct(u32) {
7200 access_kind: MemoryAccessKind = .normal,
7201 atomic_rmw_operation: Function.Instruction.AtomicRmw.Operation = .none,
7202 sync_scope: SyncScope,
7203 success_ordering: AtomicOrdering,
7204 failure_ordering: AtomicOrdering = .none,
7205 alignment: Alignment = .default,
7206 _: u13 = undefined,
7207};
7208
72097314pub const FastMath = packed struct(u8) {
72107315 unsafe_algebra: bool = false, // Legacy
72117316 nnan: bool = false,
......@@ -7533,7 +7638,7 @@ pub const Constant = enum(u32) {
75337638 const item = builder.constant_items.get(constant);
75347639 return switch (item.tag) {
75357640 .positive_integer => {
7536 const extra: *align(@alignOf(std.math.big.Limb)) Integer =
7641 const extra: *align(@alignOf(std.math.big.Limb)) const Integer =
75377642 @ptrCast(builder.constant_limbs.items[item.data..][0..Integer.limbs]);
75387643 const limbs = builder.constant_limbs
75397644 .items[item.data + Integer.limbs ..][0..extra.limbs_len];
......@@ -7568,6 +7673,21 @@ pub const Constant = enum(u32) {
75687673 }
75697674 }
75707675
7676 pub fn toInt(self: Constant, builder: *const Builder) ?std.math.big.int.Const {
7677 const item = builder.constant_items.get(self.unwrap().constant);
7678 switch (item.tag) {
7679 .positive_integer, .negative_integer => {
7680 const extra: *align(@alignOf(std.math.big.Limb)) const Integer =
7681 @ptrCast(builder.constant_limbs.items[item.data..][0..Integer.limbs]);
7682 return .{
7683 .positive = item.tag == .positive_integer,
7684 .limbs = builder.constant_limbs.items[item.data + Integer.limbs ..][0..extra.limbs_len],
7685 };
7686 },
7687 else => return null,
7688 }
7689 }
7690
75717691 pub fn getBase(self: Constant, builder: *const Builder) Global.Index {
75727692 var cur = self;
75737693 while (true) switch (cur.unwrap()) {
......@@ -8183,7 +8303,7 @@ pub const Metadata = packed struct(u32) {
81838303 };
81848304
81858305 pub const DIFlags = packed struct(u32) {
8186 Visibility: enum(u2) { Zero, Private, Protected, Public } = .Zero,
8306 Visibility: enum(u2) { None, Private, Protected, Public } = .None,
81878307 FwdDecl: bool = false,
81888308 AppleBlock: bool = false,
81898309 ReservedBit4: u1 = 0,
......@@ -8199,11 +8319,11 @@ pub const Metadata = packed struct(u32) {
81998319 RValueReference: bool = false,
82008320 ExportSymbols: bool = false,
82018321 Inheritance: enum(u2) {
8202 Zero,
8322 None,
82038323 SingleInheritance,
82048324 MultipleInheritance,
82058325 VirtualInheritance,
8206 } = .Zero,
8326 } = .None,
82078327 IntroducedVirtual: bool = false,
82088328 BitField: bool = false,
82098329 NoReturn: bool = false,
......@@ -8226,7 +8346,7 @@ pub const Metadata = packed struct(u32) {
82268346 if (need_pipe) try w.writeAll(" | ") else need_pipe = true;
82278347 try w.print("DIFlag{s}", .{field.name});
82288348 },
8229 .@"enum" => if (@field(self, field.name) != .Zero) {
8349 .@"enum" => if (@field(self, field.name) != .None) {
82308350 if (need_pipe) try w.writeAll(" | ") else need_pipe = true;
82318351 try w.print("DIFlag{s}", .{@tagName(@field(self, field.name))});
82328352 },
......@@ -8262,7 +8382,7 @@ pub const Metadata = packed struct(u32) {
82628382 };
82638383
82648384 pub const DISPFlags = packed struct(u32) {
8265 Virtuality: enum(u2) { Zero, Virtual, PureVirtual } = .Zero,
8385 Virtuality: enum(u2) { None, Virtual, PureVirtual } = .None,
82668386 LocalToUnit: bool = false,
82678387 Definition: bool = false,
82688388 Optimized: bool = false,
......@@ -8283,7 +8403,7 @@ pub const Metadata = packed struct(u32) {
82838403 if (need_pipe) try w.writeAll(" | ") else need_pipe = true;
82848404 try w.print("DISPFlag{s}", .{field.name});
82858405 },
8286 .@"enum" => if (@field(self, field.name) != .Zero) {
8406 .@"enum" => if (@field(self, field.name) != .None) {
82878407 if (need_pipe) try w.writeAll(" | ") else need_pipe = true;
82888408 try w.print("DISPFlag{s}", .{@tagName(@field(self, field.name))});
82898409 },
......@@ -10007,11 +10127,11 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void
1000710127 instruction_index.name(&function).fmt(self),
1000810128 tag,
1000910129 extra.info.access_kind.fmt(" "),
10010 extra.info.atomic_rmw_operation,
10130 extra.info.operation,
1001110131 extra.ptr.fmt(function_index, self, .{ .percent = true }),
1001210132 extra.val.fmt(function_index, self, .{ .percent = true }),
1001310133 extra.info.sync_scope.fmt(" "),
10014 extra.info.success_ordering.fmt(" "),
10134 extra.info.ordering.fmt(" "),
1001510135 extra.info.alignment.fmt(", "),
1001610136 });
1001710137 },
......@@ -10055,9 +10175,10 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void
1005510175 .@"tail call",
1005610176 .@"tail call fast",
1005710177 => |tag| {
10058 var extra =
10059 function.extraDataTrail(Function.Instruction.Call, instruction.data);
10178 var extra = function.extraDataTrail(Function.Instruction.Call, instruction.data);
1006010179 const args = extra.trail.next(extra.data.args_len, Value, &function);
10180 const callees =
10181 extra.trail.next(@intFromBool(extra.data.info.has_callees), Metadata, &function);
1006110182 try w.writeAll(" ");
1006210183 const ret_ty = extra.data.ty.functionReturn(self);
1006310184 switch (ret_ty) {
......@@ -10089,9 +10210,6 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void
1008910210 });
1009010211 }
1009110212 try w.writeByte(')');
10092 if (extra.data.info.has_op_bundle_cold) {
10093 try w.writeAll(" [ \"cold\"() ]");
10094 }
1009510213 const call_function_attributes = extra.data.attributes.func(self);
1009610214 if (call_function_attributes != .none) try w.print(" #{d}", .{
1009710215 (try attribute_groups.getOrPutValue(
......@@ -10100,15 +10218,19 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void
1010010218 {},
1010110219 )).index,
1010210220 });
10221 if (extra.data.info.has_op_bundle_cold) try w.writeAll(" [ \"cold\"() ]");
10222 metadata_formatter.need_comma = true;
10223 defer metadata_formatter.need_comma = undefined;
10224 for (callees) |metadata| try w.print("{f}", .{
10225 try metadata_formatter.fmt("!callees ", metadata, null),
10226 });
1010310227 },
10104 .cmpxchg,
10105 .@"cmpxchg weak",
10106 => |tag| {
10107 const extra =
10108 function.extraData(Function.Instruction.CmpXchg, instruction.data);
10109 try w.print(" %{f} = {t}{f} {f}, {f}, {f}{f}{f}{f}{f}", .{
10228 .cmpxchg => |tag| {
10229 const extra = function.extraData(Function.Instruction.CmpXchg, instruction.data);
10230 try w.print(" %{f} = {t}{f}{f} {f}, {f}, {f}{f}{f}{f}{f}", .{
1011010231 instruction_index.name(&function).fmt(self),
1011110232 tag,
10233 extra.info.kind.fmt(" "),
1011210234 extra.info.access_kind.fmt(" "),
1011310235 extra.ptr.fmt(function_index, self, .{ .percent = true }),
1011410236 extra.cmp.fmt(function_index, self, .{ .percent = true }),
......@@ -10143,11 +10265,11 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void
1014310265 for (indices) |index| try w.print(", {d}", .{index});
1014410266 },
1014510267 .fence => |tag| {
10146 const info: MemoryAccessInfo = @bitCast(instruction.data);
10268 const fence: Function.Instruction.Fence = @bitCast(instruction.data);
1014710269 try w.print(" {t}{f}{f}", .{
1014810270 tag,
10149 info.sync_scope.fmt(" "),
10150 info.success_ordering.fmt(" "),
10271 fence.sync_scope.fmt(" "),
10272 fence.success_ordering.fmt(" "),
1015110273 });
1015210274 },
1015310275 .fneg,
......@@ -10221,16 +10343,22 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void
1022110343 .load,
1022210344 .@"load atomic",
1022310345 => |tag| {
10224 const extra = function.extraData(Function.Instruction.Load, instruction.data);
10346 var extra = function.extraDataTrail(Function.Instruction.Load, instruction.data);
10347 const range = extra.trail.next(@intFromBool(extra.data.info.has_range), Metadata, &function);
1022510348 try w.print(" %{f} = {t}{f} {f}, {f}{f}{f}{f}", .{
1022610349 instruction_index.name(&function).fmt(self),
1022710350 tag,
10228 extra.info.access_kind.fmt(" "),
10229 extra.type.fmt(self, .percent),
10230 extra.ptr.fmt(function_index, self, .{ .percent = true }),
10231 extra.info.sync_scope.fmt(" "),
10232 extra.info.success_ordering.fmt(" "),
10233 extra.info.alignment.fmt(", "),
10351 extra.data.info.access_kind.fmt(" "),
10352 extra.data.type.fmt(self, .percent),
10353 extra.data.ptr.fmt(function_index, self, .{ .percent = true }),
10354 extra.data.info.sync_scope.fmt(" "),
10355 extra.data.info.ordering.fmt(" "),
10356 extra.data.info.alignment.fmt(", "),
10357 });
10358 metadata_formatter.need_comma = true;
10359 defer metadata_formatter.need_comma = undefined;
10360 for (range) |metadata| if (metadata.unwrap(self) != Metadata.empty_tuple) try w.print("{f}", .{
10361 try metadata_formatter.fmt("!range ", metadata, null),
1023410362 });
1023510363 },
1023610364 .phi,
......@@ -10296,7 +10424,7 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void
1029610424 extra.val.fmt(function_index, self, .{ .percent = true }),
1029710425 extra.ptr.fmt(function_index, self, .{ .percent = true }),
1029810426 extra.info.sync_scope.fmt(" "),
10299 extra.info.success_ordering.fmt(" "),
10427 extra.info.ordering.fmt(" "),
1030010428 extra.info.alignment.fmt(", "),
1030110429 });
1030210430 },
......@@ -12291,9 +12419,12 @@ pub fn debugFloatType(
1229112419 return self.debugFloatTypeAssumeCapacity(name, size_in_bits);
1229212420}
1229312421
12294pub fn debugForwardReference(self: *Builder) Allocator.Error!Metadata {
12422/// Deprecated, use `metadataForwardReference`.
12423pub const debugForwardReference = metadataForwardReference;
12424
12425pub fn metadataForwardReference(self: *Builder) Allocator.Error!Metadata {
1229512426 try self.metadata_forward_references.ensureUnusedCapacity(self.gpa, 1);
12296 return self.debugForwardReferenceAssumeCapacity();
12427 return self.metadataForwardReferenceAssumeCapacity();
1229712428}
1229812429
1229912430pub fn debugStructType(
......@@ -12521,15 +12652,8 @@ pub fn debugExpression(self: *Builder, elements: []const u32) Allocator.Error!Me
1252112652}
1252212653
1252312654pub fn metadataTuple(self: *Builder, elements: []const Metadata) Allocator.Error!Metadata {
12524 return self.metadataTupleOptionals(@ptrCast(elements));
12525}
12526
12527pub fn metadataTupleOptionals(
12528 self: *Builder,
12529 elements: []const Metadata.Optional,
12530) Allocator.Error!Metadata {
1253112655 try self.ensureUnusedMetadataCapacity(1, Metadata.Tuple, elements.len);
12532 return self.metadataTupleOptionalsAssumeCapacity(elements);
12656 return self.metadataTupleAssumeCapacity(elements);
1253312657}
1253412658
1253512659pub fn debugLocalVar(
......@@ -12595,9 +12719,12 @@ pub fn metadataConstant(self: *Builder, value: Constant) Allocator.Error!Metadat
1259512719 return self.metadataConstantAssumeCapacity(value);
1259612720}
1259712721
12722/// Deprecated, use `resolveMetadataForwardReference`.
12723pub const resolveDebugForwardReference = resolveMetadataForwardReference;
12724
1259812725/// Resolves the given forward reference to the given value (which is not itself a forward
1259912726/// reference). If the forward reference is already resolved, its target is replaced.
12600pub fn resolveDebugForwardReference(self: *Builder, fwd_ref: Metadata, value: Metadata) void {
12727pub fn resolveMetadataForwardReference(self: *Builder, fwd_ref: Metadata, value: Metadata) void {
1260112728 assert(fwd_ref.kind == .forward);
1260212729 assert(value.kind != .forward);
1260312730 self.metadata_forward_references.items[fwd_ref.index] = value.toOptional();
......@@ -12790,8 +12917,7 @@ fn debugFloatTypeAssumeCapacity(self: *Builder, name: ?Metadata.String, size_in_
1279012917 });
1279112918}
1279212919
12793fn debugForwardReferenceAssumeCapacity(self: *Builder) Metadata {
12794 assert(!self.strip);
12920fn metadataForwardReferenceAssumeCapacity(self: *Builder) Metadata {
1279512921 const index = self.metadata_forward_references.items.len;
1279612922 self.metadata_forward_references.appendAssumeCapacity(.none);
1279712923 return .{ .index = @intCast(index), .kind = .forward };
......@@ -13164,9 +13290,9 @@ fn debugExpressionAssumeCapacity(self: *Builder, elements: []const u32) Metadata
1316413290 return .{ .index = @intCast(gop.index), .kind = .node };
1316513291}
1316613292
13167fn metadataTupleOptionalsAssumeCapacity(self: *Builder, elements: []const Metadata.Optional) Metadata {
13293fn metadataTupleAssumeCapacity(self: *Builder, elements: []const Metadata) Metadata {
1316813294 const Key = struct {
13169 elements: []const Metadata.Optional,
13295 elements: []const Metadata,
1317013296 };
1317113297 const Adapter = struct {
1317213298 builder: *const Builder,
......@@ -13181,9 +13307,9 @@ fn metadataTupleOptionalsAssumeCapacity(self: *Builder, elements: []const Metada
1318113307 const rhs_data = ctx.builder.metadata_items.items(.data)[rhs_index];
1318213308 var rhs_extra = ctx.builder.metadataExtraDataTrail(Metadata.Tuple, rhs_data);
1318313309 return std.mem.eql(
13184 Metadata.Optional,
13310 Metadata,
1318513311 lhs_key.elements,
13186 rhs_extra.trail.next(rhs_extra.data.elements_len, Metadata.Optional, ctx.builder),
13312 rhs_extra.trail.next(rhs_extra.data.elements_len, Metadata, ctx.builder),
1318713313 );
1318813314 }
1318913315 };
......@@ -13949,7 +14075,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco
1394914075 .positive_integer,
1395014076 .negative_integer,
1395114077 => |tag| {
13952 const extra: *align(@alignOf(std.math.big.Limb)) Constant.Integer =
14078 const extra: *align(@alignOf(std.math.big.Limb)) const Constant.Integer =
1395314079 @ptrCast(self.constant_limbs.items[data..][0..Constant.Integer.limbs]);
1395414080 const bigint: std.math.big.int.Const = .{
1395514081 .limbs = self.constant_limbs
......@@ -15109,7 +15235,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco
1510915235 .ty = extra.type,
1511015236 .alignment = extra.info.alignment.toLlvm(),
1511115237 .is_volatile = extra.info.access_kind == .@"volatile",
15112 .success_ordering = extra.info.success_ordering,
15238 .ordering = extra.info.ordering,
1511315239 .sync_scope = extra.info.sync_scope,
1511415240 });
1511515241 },
......@@ -15129,7 +15255,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco
1512915255 .val = adapter.getOffsetValueIndex(extra.val),
1513015256 .alignment = extra.info.alignment.toLlvm(),
1513115257 .is_volatile = extra.info.access_kind == .@"volatile",
15132 .success_ordering = extra.info.success_ordering,
15258 .ordering = extra.info.ordering,
1513315259 .sync_scope = extra.info.sync_scope,
1513415260 });
1513515261 },
......@@ -15212,18 +15338,15 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco
1521215338 try function_block.writeAbbrev(FunctionBlock.AtomicRmw{
1521315339 .ptr = adapter.getOffsetValueIndex(extra.ptr),
1521415340 .val = adapter.getOffsetValueIndex(extra.val),
15215 .operation = extra.info.atomic_rmw_operation,
15341 .operation = extra.info.operation,
1521615342 .is_volatile = extra.info.access_kind == .@"volatile",
15217 .success_ordering = extra.info.success_ordering,
15343 .ordering = extra.info.ordering,
1521815344 .sync_scope = extra.info.sync_scope,
1521915345 .alignment = extra.info.alignment.toLlvm(),
1522015346 });
1522115347 },
15222 .cmpxchg,
15223 .@"cmpxchg weak",
15224 => |kind| {
15348 .cmpxchg => {
1522515349 const extra = func.extraData(Function.Instruction.CmpXchg, data);
15226
1522715350 try function_block.writeAbbrev(FunctionBlock.CmpXchg{
1522815351 .ptr = adapter.getOffsetValueIndex(extra.ptr),
1522915352 .cmp = adapter.getOffsetValueIndex(extra.cmp),
......@@ -15232,15 +15355,15 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco
1523215355 .success_ordering = extra.info.success_ordering,
1523315356 .sync_scope = extra.info.sync_scope,
1523415357 .failure_ordering = extra.info.failure_ordering,
15235 .is_weak = kind == .@"cmpxchg weak",
15358 .is_weak = extra.info.kind == .weak,
1523615359 .alignment = extra.info.alignment.toLlvm(),
1523715360 });
1523815361 },
1523915362 .fence => {
15240 const info: MemoryAccessInfo = @bitCast(data);
15363 const fence: Function.Instruction.Fence = @bitCast(data);
1524115364 try function_block.writeAbbrev(FunctionBlock.Fence{
15242 .ordering = info.success_ordering,
15243 .sync_scope = info.sync_scope,
15365 .ordering = fence.success_ordering,
15366 .sync_scope = fence.sync_scope,
1524415367 });
1524515368 },
1524615369 }
......@@ -15313,17 +15436,58 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco
1531315436 };
1531415437 switch (weights) {
1531515438 .none => {},
15316 .unpredictable => try metadata_attach_block.writeAbbrevAdapted(MetadataAttachmentBlock.AttachmentInstructionSingle{
15439 .unpredictable => try metadata_attach_block.writeAbbrevAdapted(
15440 MetadataAttachmentBlock.AttachmentInstructionSingle{
15441 .inst = instr_index,
15442 .kind = .unpredictable,
15443 .metadata = .empty_tuple,
15444 },
15445 metadata_adapter,
15446 ),
15447 _ => try metadata_attach_block.writeAbbrevAdapted(
15448 MetadataAttachmentBlock.AttachmentInstructionSingle{
15449 .inst = instr_index,
15450 .kind = .prof,
15451 .metadata = weights.toMetadata(),
15452 },
15453 metadata_adapter,
15454 ),
15455 }
15456 instr_index += 1;
15457 },
15458 .call,
15459 .@"call fast",
15460 .@"musttail call",
15461 .@"musttail call fast",
15462 .@"notail call",
15463 .@"notail call fast",
15464 .@"tail call",
15465 .@"tail call fast",
15466 => {
15467 var extra = func.extraDataTrail(Function.Instruction.Call, data);
15468 _ = extra.trail.next(extra.data.args_len, Value, &func);
15469 const callees = extra.trail.next(@intFromBool(extra.data.info.has_callees), Metadata, &func);
15470 for (callees) |metadata| try metadata_attach_block.writeAbbrevAdapted(
15471 MetadataAttachmentBlock.AttachmentInstructionSingle{
1531715472 .inst = instr_index,
15318 .kind = .unpredictable,
15319 .metadata = .empty_tuple,
15320 }, metadata_adapter),
15321 _ => try metadata_attach_block.writeAbbrevAdapted(MetadataAttachmentBlock.AttachmentInstructionSingle{
15473 .kind = .callees,
15474 .metadata = metadata,
15475 },
15476 metadata_adapter,
15477 );
15478 instr_index += 1;
15479 },
15480 .load, .@"load atomic" => {
15481 var extra = func.extraDataTrail(Function.Instruction.Load, data);
15482 const range = extra.trail.next(@intFromBool(extra.data.info.has_range), Metadata, &func);
15483 for (range) |metadata| if (metadata.unwrap(self) != Metadata.empty_tuple) try metadata_attach_block.writeAbbrevAdapted(
15484 MetadataAttachmentBlock.AttachmentInstructionSingle{
1532215485 .inst = instr_index,
15323 .kind = .prof,
15324 .metadata = weights.toMetadata(),
15325 }, metadata_adapter),
15326 }
15486 .kind = .range,
15487 .metadata = metadata,
15488 },
15489 metadata_adapter,
15490 );
1532715491 instr_index += 1;
1532815492 },
1532915493 };
lib/std/zig/llvm/ir.zig+5-5
......@@ -79,7 +79,7 @@ pub const FixedMetadataKind = enum(u6) {
7979 //tbaa = 1,
8080 prof = 2,
8181 //fpmath = 3,
82 //range = 4,
82 range = 4,
8383 //@"tbaa.struct" = 5,
8484 //@"invariant.load" = 6,
8585 //@"alias.scope" = 7,
......@@ -98,7 +98,7 @@ pub const FixedMetadataKind = enum(u6) {
9898 //section_prefix = 20,
9999 //absolute_symbol = 21,
100100 //associated = 22,
101 //callees = 23,
101 callees = 23,
102102 //irr_loop = 24,
103103 //@"llvm.access.group" = 25,
104104 //callback = 26,
......@@ -1232,7 +1232,7 @@ pub const ModuleBlock = struct {
12321232 ty: Builder.Type,
12331233 alignment: std.meta.Int(.unsigned, @bitSizeOf(Builder.Alignment)),
12341234 is_volatile: bool,
1235 success_ordering: Builder.AtomicOrdering,
1235 ordering: Builder.AtomicOrdering,
12361236 sync_scope: Builder.SyncScope,
12371237 };
12381238
......@@ -1264,7 +1264,7 @@ pub const ModuleBlock = struct {
12641264 val: u32,
12651265 alignment: std.meta.Int(.unsigned, @bitSizeOf(Builder.Alignment)),
12661266 is_volatile: bool,
1267 success_ordering: Builder.AtomicOrdering,
1267 ordering: Builder.AtomicOrdering,
12681268 sync_scope: Builder.SyncScope,
12691269 };
12701270
......@@ -1315,7 +1315,7 @@ pub const ModuleBlock = struct {
13151315 val: u32,
13161316 operation: Builder.Function.Instruction.AtomicRmw.Operation,
13171317 is_volatile: bool,
1318 success_ordering: Builder.AtomicOrdering,
1318 ordering: Builder.AtomicOrdering,
13191319 sync_scope: Builder.SyncScope,
13201320 alignment: std.meta.Int(.unsigned, @bitSizeOf(Builder.Alignment)),
13211321 };
src/InternPool.zig+5-2
......@@ -7998,7 +7998,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
79987998 });
79997999 },
80008000 .restricted_value => |restricted_value| {
8001 assert(restricted_value.ty.unwrap(ip).getTag(ip) == .type_restricted);
8001 assert(ip.isRestrictedType(restricted_value.ty));
80028002 assert(!ip.isUndef(restricted_value.unrestricted_value));
80038003 items.appendAssumeCapacity(.{
80048004 .tag = .restricted_value,
......@@ -9019,7 +9019,10 @@ pub fn getUnion(
90199019) Allocator.Error!Index {
90209020 assert(un.ty != .none);
90219021 assert(un.val != .none);
9022 assert(ip.loadUnionType(un.ty).layout != .@"packed");
9022
9023 const loaded_union = ip.loadUnionType(un.ty);
9024 assert(loaded_union.layout != .@"packed");
9025 assert(loaded_union.enum_tag_type == ip.typeOf(un.tag));
90239026
90249027 var gop = try ip.getOrPutKey(gpa, io, tid, .{ .un = un });
90259028 defer gop.deinit();
src/Sema.zig+41-18
......@@ -10053,6 +10053,7 @@ fn analyzeSwitchBlock(
1005310053) CompileError!?Air.Inst.Ref {
1005410054 const pt = sema.pt;
1005510055 const zcu = pt.zcu;
10056 const ip = &zcu.intern_pool;
1005610057 const gpa = sema.gpa;
1005710058
1005810059 const src_node_offset = zir_switch.switch_src_node_offset;
......@@ -10076,7 +10077,13 @@ fn analyzeSwitchBlock(
1007610077 operand_ty.containerLayout(zcu) != .@"packed")
1007710078 {
1007810079 const tag_val = try sema.unionToTag(block, val);
10079 break :init .{ tag_val, sema.typeOf(tag_val) };
10080 const tag_ty = sema.typeOf(tag_val);
10081 const unrestricted_tag_ty = tag_ty.unrestrictedType(zcu) orelse tag_ty;
10082 const unrestricted_tag_val = if (unrestricted_tag_ty.toIntern() != tag_ty.toIntern())
10083 try sema.unwrapRestricted(block, unrestricted_tag_ty, tag_val, src)
10084 else
10085 tag_val;
10086 break :init .{ unrestricted_tag_val, unrestricted_tag_ty };
1008010087 }
1008110088 break :init .{
1008210089 if (maybe_operand_opv) |operand_opv| .fromValue(operand_opv) else val,
......@@ -10269,7 +10276,7 @@ fn analyzeSwitchBlock(
1026910276 break :item_val item_opv;
1027010277 }
1027110278 if (maybe_operand_opv) |operand_opv| {
10272 break :item_val .fromInterned(zcu.intern_pool.indexToKey(operand_opv.toIntern()).un.val);
10279 break :item_val .fromInterned(ip.indexToKey(operand_opv.toIntern()).un.val);
1027310280 }
1027410281 assert(zir_switch.any_maybe_runtime_capture); // there's a payload capture
1027510282 const operand_val, const operand_ref = switch (operand) {
......@@ -11211,7 +11218,8 @@ fn validateSwitchBlock(
1121111218 const union_obj = ip.loadUnionType(operand_ty.toIntern());
1121211219 switch (union_obj.tag_usage) {
1121311220 .tagged => {
11214 break :item_ty .fromInterned(union_obj.enum_tag_type);
11221 const enum_tag_ty: Type = .fromInterned(union_obj.enum_tag_type);
11222 break :item_ty enum_tag_ty.unrestrictedType(zcu) orelse enum_tag_ty;
1121511223 },
1121611224 .none => {
1121711225 if (union_obj.layout == .@"packed") {
......@@ -16636,7 +16644,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1663616644 const union_field_ty = try sema.getBuiltinType(src, .@"Type.UnionField");
1663716645
1663816646 const union_obj = ip.loadUnionType(unrestricted_ty.toIntern());
16639 const enum_obj = ip.loadEnumType(union_obj.enum_tag_type);
16647 const enum_tag_ty: Type = .fromInterned(union_obj.enum_tag_type);
16648 const enum_obj = ip.loadEnumType((enum_tag_ty.unrestrictedType(zcu) orelse enum_tag_ty).toIntern());
1664016649 const layout = union_obj.layout;
1664116650
1664216651 const union_field_vals = try gpa.alloc(InternPool.Index, enum_obj.field_names.len);
......@@ -18220,7 +18229,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1822018229 break :blk ty;
1822118230 };
1822218231
18223 if (elem_ty.zigTypeTag(zcu) == .noreturn)
18232 if (elem_ty.toIntern() == .noreturn_type)
1822418233 return sema.fail(block, elem_ty_src, "pointer to noreturn not allowed", .{});
1822518234
1822618235 const target = zcu.getTarget();
......@@ -18253,7 +18262,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1825318262 const ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_i]);
1825418263 extra_i += 1;
1825518264 break :blk try sema.resolveAddressSpace(block, addrspace_src, ref, .pointer);
18256 } else if (elem_ty.zigTypeTag(zcu) == .@"fn" and target.cpu.arch == .avr) .flash else .generic;
18265 } else if (target.cpu.arch == .avr and ip.isFunctionType(elem_ty.toIntern())) .flash else .generic;
1825718266
1825818267 const bit_offset: u16 = if (inst_data.flags.has_bit_range) blk: {
1825918268 const ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_i]);
......@@ -18284,7 +18293,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1828418293 }
1828518294 }
1828618295
18287 if (elem_ty.zigTypeTag(zcu) == .@"fn") {
18296 if (ip.isFunctionType(elem_ty.toIntern())) {
1828818297 if (inst_data.size != .one) {
1828918298 return sema.fail(block, elem_ty_src, "function pointers must be single pointers", .{});
1829018299 }
......@@ -18594,7 +18603,8 @@ fn zirStructInit(
1859418603 );
1859518604 const field_index = try sema.unionFieldIndex(block, resolved_ty, field_name, field_src);
1859618605 const tag_ty = resolved_ty.unionTagTypeHypothetical(zcu);
18597 const tag_val = try pt.enumValueFieldIndex(tag_ty, field_index);
18606 const unrestricted_tag_ty = tag_ty.unrestrictedType(zcu) orelse tag_ty;
18607 const tag_val = try pt.enumValueFieldIndex(unrestricted_tag_ty, field_index);
1859818608 const field_ty: Type = .fromInterned(zcu.typeToUnion(resolved_ty).?.field_types.get(ip)[field_index]);
1859918609
1860018610 if (field_ty.classify(zcu) == .no_possible_value) {
......@@ -18626,7 +18636,10 @@ fn zirStructInit(
1862618636 if (sema.resolveValue(init_inst)) |val| {
1862718637 const struct_val = Value.fromInterned(try pt.internUnion(.{
1862818638 .ty = resolved_ty.toIntern(),
18629 .tag = tag_val.toIntern(),
18639 .tag = if (unrestricted_tag_ty.toIntern() != tag_ty.toIntern())
18640 try pt.intern(.{ .restricted_value = .{ .ty = tag_ty.toIntern(), .unrestricted_value = tag_val.toIntern() } })
18641 else
18642 tag_val.toIntern(),
1863018643 .val = val.toIntern(),
1863118644 }));
1863218645 const final_val_inst = try sema.coerce(block, result_ty, Air.internedToRef(struct_val.toIntern()), src);
......@@ -19358,7 +19371,8 @@ fn fieldType(
1935819371 },
1935919372 .@"union" => {
1936019373 const union_obj = zcu.typeToUnion(cur_ty).?;
19361 const enum_obj = ip.loadEnumType(union_obj.enum_tag_type);
19374 const enum_tag_ty: Type = .fromInterned(union_obj.enum_tag_type);
19375 const enum_obj = ip.loadEnumType((enum_tag_ty.unrestrictedType(zcu) orelse enum_tag_ty).toIntern());
1936219376 const field_index = enum_obj.nameIndex(ip, field_name) orelse
1936319377 return sema.failWithBadUnionFieldAccess(block, cur_ty, union_obj, field_src, field_name);
1936419378 const field_ty = union_obj.field_types.get(ip)[field_index];
......@@ -26604,6 +26618,7 @@ fn unionFieldPtr(
2660426618
2660526619 const union_obj = zcu.typeToUnion(union_ty).?;
2660626620 const tag_ty: Type = .fromInterned(union_obj.enum_tag_type);
26621 const unrestricted_tag_ty = tag_ty.unrestrictedType(zcu) orelse tag_ty;
2660726622
2660826623 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
2660926624 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);
......@@ -26630,17 +26645,17 @@ fn unionFieldPtr(
2663026645 break :ct;
2663126646 }
2663226647 // Store to the union to initialize the tag.
26633 const field_tag = try pt.enumValueFieldIndex(tag_ty, field_index);
26648 const field_tag = try pt.enumValueFieldIndex(unrestricted_tag_ty, field_index);
2663426649 const payload_val = try field_ty.onePossibleValue(pt) orelse try pt.undefValue(field_ty);
2663526650 const new_union_val = try pt.unionValue(union_ty, field_tag, payload_val);
2663626651 try sema.storePtrVal(block, src, union_ptr_val, new_union_val, union_ty);
2663726652 } else {
2663826653 const union_val = try sema.pointerDeref(block, src, union_ptr_val, union_ptr_val.typeOf(zcu)) orelse break :ct;
2663926654 if (union_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, src, null);
26640 const active_index = tag_ty.enumTagFieldIndex(union_val.unionTag(zcu).?, zcu).?;
26655 const active_index = unrestricted_tag_ty.enumTagFieldIndex(union_val.unionTag(zcu).?, zcu).?;
2664126656 if (active_index != field_index) {
2664226657 const msg = msg: {
26643 const active_field_name = tag_ty.enumFieldName(active_index, zcu);
26658 const active_field_name = unrestricted_tag_ty.enumFieldName(active_index, zcu);
2664426659 const msg = try sema.errMsg(src, "access of union field '{f}' while field '{f}' is active", .{
2664526660 field_name.fmt(ip),
2664626661 active_field_name.fmt(ip),
......@@ -26660,19 +26675,26 @@ fn unionFieldPtr(
2666026675 // If the union has a tag, we must either set or or safety check it depending on `initializing`.
2666126676 tag: {
2666226677 if (union_ty.containerLayout(zcu) != .auto) break :tag;
26663 if (tag_ty.classify(zcu) == .one_possible_value) break :tag;
26678 if (unrestricted_tag_ty.classify(zcu) == .one_possible_value) break :tag;
2666426679 // There is a hypothetical non-trivial tag. We must set it even if not there at runtime, but
2666526680 // only emit a safety check if it's available at runtime (i.e. it's safety-tagged).
26666 const want_tag = try pt.enumValueFieldIndex(tag_ty, field_index);
26681 const want_tag = try pt.enumValueFieldIndex(unrestricted_tag_ty, field_index);
2666726682 if (initializing) {
26668 const set_tag_inst = try block.addBinOp(.set_union_tag, union_ptr, .fromValue(want_tag));
26683 const set_tag_inst = try block.addBinOp(.set_union_tag, union_ptr, if (unrestricted_tag_ty.toIntern() != tag_ty.toIntern())
26684 .fromIntern(try pt.intern(.{ .restricted_value = .{ .ty = tag_ty.toIntern(), .unrestricted_value = want_tag.toIntern() } }))
26685 else
26686 .fromValue(want_tag));
2666926687 try sema.checkComptimeKnownStore(block, set_tag_inst, .unneeded); // `unneeded` since this isn't a "proper" store
2667026688 } else if (block.wantSafety() and union_obj.has_runtime_tag) {
2667126689 // The tag exists at runtime (actual or safety tag), so emit a safety check.
2667226690 // TODO would it be better if get_union_tag supported pointers to unions?
2667326691 const union_val = try block.addTyOp(.load, union_ty, union_ptr);
2667426692 const active_tag = try block.addTyOp(.get_union_tag, tag_ty, union_val);
26675 try sema.addSafetyCheckInactiveUnionField(block, src, active_tag, .fromValue(want_tag));
26693 const unrestricted_active_tag = if (unrestricted_tag_ty.toIntern() != tag_ty.toIntern())
26694 try sema.unwrapRestricted(block, unrestricted_tag_ty, active_tag, src)
26695 else
26696 active_tag;
26697 try sema.addSafetyCheckInactiveUnionField(block, src, unrestricted_active_tag, .fromValue(want_tag));
2667626698 }
2667726699 }
2667826700 if (field_ty.classify(zcu) == .no_possible_value) {
......@@ -33539,7 +33561,8 @@ fn unionFieldIndex(
3353933561 const zcu = pt.zcu;
3354033562 const ip = &zcu.intern_pool;
3354133563 const union_obj = zcu.typeToUnion(union_ty).?;
33542 const enum_obj = ip.loadEnumType(union_obj.enum_tag_type);
33564 const enum_tag_ty: Type = .fromInterned(union_obj.enum_tag_type);
33565 const enum_obj = ip.loadEnumType((enum_tag_ty.unrestrictedType(zcu) orelse enum_tag_ty).toIntern());
3354333566 const field_index = enum_obj.nameIndex(ip, field_name) orelse
3354433567 return sema.failWithBadUnionFieldAccess(block, union_ty, union_obj, field_src, field_name);
3354533568 return @intCast(field_index);
src/Sema/type_resolution.zig+5-3
......@@ -694,8 +694,9 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
694694 break :tag_ty try sema.analyzeAsType(&block, tag_type_src, .union_enum_tag_type, type_ref);
695695 },
696696 };
697 const unrestricted_tag_ty = tag_ty.unrestrictedType(zcu) orelse tag_ty;
697698 // Because the type is explicitly specified, we need to validate it.
698 if (tag_ty.zigTypeTag(zcu) != .@"enum") return sema.fail(
699 if (unrestricted_tag_ty.zigTypeTag(zcu) != .@"enum") return sema.fail(
699700 &block,
700701 block.src(.container_arg),
701702 "expected enum tag type, found '{f}'",
......@@ -738,9 +739,10 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
738739 },
739740 },
740741 };
742 const unrestricted_enum_tag_ty = enum_tag_ty.unrestrictedType(zcu) orelse enum_tag_ty;
741743
742 try sema.ensureLayoutResolved(enum_tag_ty, block.src(.container_arg), .backing_enum);
743 const enum_obj = ip.loadEnumType(enum_tag_ty.toIntern());
744 try sema.ensureLayoutResolved(unrestricted_enum_tag_ty, block.src(.container_arg), .backing_enum);
745 const enum_obj = ip.loadEnumType(unrestricted_enum_tag_ty.toIntern());
744746
745747 if (union_obj.is_reified) {
746748 // We have field names in `union_obj.reified_field_names`, but we haven't
src/Type.zig+1-1
......@@ -3241,7 +3241,7 @@ pub fn validateExtern(ty: Type, position: ExternPosition, zcu: *const Zcu) bool
32413241 .pointer => {
32423242 if (ty.isSlice(zcu)) return false;
32433243 const child_ty = ty.childType(zcu);
3244 if (child_ty.zigTypeTag(zcu) == .@"fn") {
3244 if (zcu.intern_pool.isFunctionType(child_ty.toIntern())) {
32453245 return ty.isConstPtr(zcu) and validateExternCallconv(child_ty.fnCallingConvention(zcu));
32463246 }
32473247 return true;
src/Zcu.zig+8-3
......@@ -4165,9 +4165,14 @@ pub const UnionLayout = struct {
41654165pub fn unionTagFieldIndex(zcu: *const Zcu, loaded_union: InternPool.LoadedUnionType, enum_tag: Value) ?u32 {
41664166 const ip = &zcu.intern_pool;
41674167 if (enum_tag.toIntern() == .none) return null;
4168 const enum_tag_key = ip.indexToKey(enum_tag.toIntern()).enum_tag;
4169 assert(enum_tag_key.ty == loaded_union.enum_tag_type);
4170 const loaded_enum = ip.loadEnumType(loaded_union.enum_tag_type);
4168 const enum_tag_key = switch (ip.indexToKey(enum_tag.toIntern())) {
4169 else => unreachable,
4170 .enum_tag => |enum_tag_key| enum_tag_key,
4171 .restricted_value => |restricted_value| ip.indexToKey(restricted_value.unrestricted_value).enum_tag,
4172 };
4173 const enum_tag_ty: Type = .fromInterned(loaded_union.enum_tag_type);
4174 assert(enum_tag_key.ty == (enum_tag_ty.unrestrictedType(zcu) orelse enum_tag_ty).toIntern());
4175 const loaded_enum = ip.loadEnumType(enum_tag_key.ty);
41714176 return loaded_enum.tagValueIndex(ip, enum_tag_key.int);
41724177}
41734178
src/codegen/llvm.zig+114-31
......@@ -626,8 +626,8 @@ pub const Object = struct {
626626 try builder.metadataString(compile_unit_dir),
627627 );
628628
629 const debug_enums_fwd_ref = try builder.debugForwardReference();
630 const debug_globals_fwd_ref = try builder.debugForwardReference();
629 const debug_enums_fwd_ref = try builder.metadataForwardReference();
630 const debug_globals_fwd_ref = try builder.metadataForwardReference();
631631
632632 const debug_compile_unit = try builder.debugCompileUnit(
633633 debug_file,
......@@ -701,9 +701,12 @@ pub const Object = struct {
701701 const RestrictedDecls = struct {
702702 len: Builder.Variable.Index,
703703 array: Builder.Variable.Index,
704 enum_seen: []const Builder.Variable.Index,
704705 values: std.array_hash_map.Auto(InternPool.Index, Builder.Constant),
706 metadata: Builder.Metadata.Optional,
705707
706708 fn deinit(rd: *RestrictedDecls, gpa: Allocator) void {
709 gpa.free(rd.enum_seen);
707710 rd.values.deinit(gpa);
708711 rd.* = undefined;
709712 }
......@@ -716,7 +719,8 @@ pub const Object = struct {
716719 const zcu = o.zcu;
717720 const target = zcu.getTarget();
718721 const ip = &zcu.intern_pool;
719 const unrestricted_ty = restricted_ty.unrestrictedType(zcu).?;
722 const restricted_type_key = ip.indexToKey(restricted_ty.toIntern()).restricted_type;
723 const unrestricted_type = restricted_type_key.unrestricted_type;
720724
721725 const ty_name = ip.loadRestrictedType(restricted_ty.toIntern()).name.toSlice(ip);
722726 gop.value_ptr.* = .{
......@@ -730,7 +734,28 @@ pub const Object = struct {
730734 .void,
731735 .default,
732736 ),
737 .enum_seen = if (ip.isEnumType(unrestricted_type)) enum_seen: {
738 const owner_mod = zcu.fileByIndex(restricted_type_key.zir_index.resolveFile(ip)).mod.?;
739 if (owner_mod.optimize_mode != .ReleaseSmall) break :enum_seen &.{};
740 const field_names = ip.loadEnumType(unrestricted_type).field_names;
741 const enum_seen = try o.gpa.alloc(Builder.Variable.Index, field_names.len);
742 errdefer o.gpa.free(enum_seen);
743 for (enum_seen, field_names.get(ip)) |*global, field_name| {
744 global.* = try o.builder.addVariable(
745 try o.builder.strtabStringFmt("{s}.{f}", .{ ty_name, field_name.fmt(ip) }),
746 .i1,
747 .default,
748 );
749 global.setLinkage(.private, &o.builder);
750 global.setMutability(.global, &o.builder);
751 global.setAlignment(InternPool.Alignment.@"1".toLlvm(), &o.builder);
752 global.setUnnamedAddr(.unnamed_addr, &o.builder);
753 try global.setInitializer(.false, &o.builder);
754 }
755 break :enum_seen enum_seen;
756 } else &.{},
733757 .values = .empty,
758 .metadata = .none,
734759 };
735760 gop.value_ptr.len.setLinkage(.private, &o.builder);
736761 gop.value_ptr.len.setMutability(.constant, &o.builder);
......@@ -738,23 +763,80 @@ pub const Object = struct {
738763 gop.value_ptr.len.setUnnamedAddr(.unnamed_addr, &o.builder);
739764 gop.value_ptr.array.setLinkage(.private, &o.builder);
740765 gop.value_ptr.array.setMutability(.constant, &o.builder);
741 gop.value_ptr.array.setAlignment(unrestricted_ty.abiAlignment(zcu).toLlvm(), &o.builder);
742 // Setting unnamed_addr here would reduce safety, and the module emitting the safety checks may not be the same module
743 // that defined the restricted type. In any case, llvm will add unnamed_addr itself if no safety checks end up being emitted.
744 gop.value_ptr.array.setUnnamedAddr(.default, &o.builder);
766 gop.value_ptr.array.setAlignment(Type.fromInterned(unrestricted_type).abiAlignment(zcu).toLlvm(), &o.builder);
767 gop.value_ptr.array.setUnnamedAddr(.unnamed_addr, &o.builder);
745768 return gop.value_ptr;
746769 }
747770 fn genRestrictedDecls(o: *Object) Allocator.Error!void {
748 for (o.restricted_map.values()) |restricted_decls| {
771 const zcu = o.zcu;
772 const ip = &zcu.intern_pool;
773 for (o.restricted_map.keys(), o.restricted_map.values()) |restricted_ty, restricted_decls| {
749774 const len = restricted_decls.values.count();
750775 try restricted_decls.len.setInitializer(try o.builder.intConst(.i32, len), &o.builder);
751776 try restricted_decls.array.setInitializer(switch (len) {
752 0 => try o.builder.zeroInitConst(.i8), // ensure unique address
777 0 => try o.builder.structConst(try o.builder.structType(.normal, &.{}), &.{}),
753778 else => try o.builder.arrayConst(
754779 try o.builder.arrayType(len, restricted_decls.values.values()[0].typeOf(&o.builder)),
755780 restricted_decls.values.values(),
756781 ),
757782 }, &o.builder);
783 if (restricted_decls.metadata.unwrap()) |metadata| {
784 const gpa = zcu.gpa;
785 const unrestricted_ty = ip.indexToKey(restricted_ty).restricted_type.unrestricted_type;
786 if (ip.isPointerType(unrestricted_ty)) {
787 assert(ip.isFunctionType(ip.indexToKey(unrestricted_ty).ptr_type.child));
788 const callees = try gpa.alloc(Builder.Metadata, len);
789 defer gpa.free(callees);
790 for (callees, restricted_decls.values.values()) |*callee, value|
791 callee.* = try o.builder.metadataConstant(value);
792 o.builder.resolveMetadataForwardReference(metadata, try o.builder.metadataTuple(callees));
793 } else {
794 assert(Type.fromInterned(unrestricted_ty).isAbiInt(zcu));
795 const ints = try gpa.alloc(std.math.big.int.Const, len);
796 defer gpa.free(ints);
797 var range: std.ArrayList(Builder.Metadata) = .empty;
798 defer range.deinit(gpa);
799 o.builder.resolveMetadataForwardReference(metadata, range: {
800 if (len == 0) break :range .empty_tuple;
801 const values = restricted_decls.values.values();
802 for (ints, values) |*int, value| int.* = value.toInt(&o.builder) orelse
803 break :range .empty_tuple;
804 std.mem.sortUnstable(std.math.big.int.Const, ints, {}, struct {
805 fn lessThan(_: void, lhs: std.math.big.int.Const, rhs: std.math.big.int.Const) bool {
806 return lhs.order(rhs).compare(.lt);
807 }
808 }.lessThan);
809 var int_ty = values[0].typeOf(&o.builder);
810 var start = ints[0];
811 var end: std.math.big.int.Mutable = .{
812 .limbs = try gpa.alloc(
813 std.math.big.Limb,
814 std.math.big.int.calcNonZeroTwosCompLimbCount(int_ty.scalarBits(&o.builder)),
815 ),
816 .len = undefined,
817 .positive = undefined,
818 };
819 defer gpa.free(end.limbs);
820 end.copy(start);
821 for (ints[1..]) |int| {
822 end.addScalar(end.toConst(), 1);
823 if (end.toConst().eql(int)) continue;
824 try range.appendSlice(gpa, &.{
825 try o.builder.metadataConstant(try o.builder.bigIntConst(int_ty, start)),
826 try o.builder.metadataConstant(try o.builder.bigIntConst(int_ty, end.toConst())),
827 });
828 start = int;
829 end.copy(int);
830 }
831 end.addScalar(end.toConst(), 1);
832 try range.appendSlice(gpa, &.{
833 try o.builder.metadataConstant(try o.builder.bigIntConst(int_ty, start)),
834 try o.builder.metadataConstant(try o.builder.bigIntConst(int_ty, end.toConst())),
835 });
836 break :range try o.builder.metadataTuple(range.items);
837 });
838 }
839 }
758840 }
759841 }
760842
......@@ -861,17 +943,17 @@ pub const Object = struct {
861943 if (!o.builder.strip) {
862944 if (o.debug_anyerror_fwd_ref.unwrap()) |fwd_ref| {
863945 const debug_anyerror_type = try o.lowerDebugAnyerrorType();
864 o.builder.resolveDebugForwardReference(fwd_ref, debug_anyerror_type);
946 o.builder.resolveMetadataForwardReference(fwd_ref, debug_anyerror_type);
865947 }
866948
867949 try o.flushTypePool(pt);
868950
869 o.builder.resolveDebugForwardReference(
951 o.builder.resolveMetadataForwardReference(
870952 o.debug_enums_fwd_ref.unwrap().?,
871953 try o.builder.metadataTuple(o.debug_enums.items),
872954 );
873955
874 o.builder.resolveDebugForwardReference(
956 o.builder.resolveMetadataForwardReference(
875957 o.debug_globals_fwd_ref.unwrap().?,
876958 try o.builder.metadataTuple(o.debug_globals.items),
877959 );
......@@ -1936,7 +2018,7 @@ pub const Object = struct {
19362018 if (!o.builder.strip) {
19372019 assert(@intFromEnum(index) == o.debug_types.items.len);
19382020 try o.debug_types.ensureUnusedCapacity(gpa, 1);
1939 const fwd_ref = try o.builder.debugForwardReference();
2021 const fwd_ref = try o.builder.metadataForwardReference();
19402022 o.debug_types.appendAssumeCapacity(fwd_ref);
19412023 if (val == .anyerror_type) {
19422024 assert(o.debug_anyerror_fwd_ref.is_none);
......@@ -1968,7 +2050,7 @@ pub const Object = struct {
19682050 .@"fn" => try o.builder.debugSubroutineType(null),
19692051 else => try o.builder.debugSignedType(name_str, 0),
19702052 };
1971 o.builder.resolveDebugForwardReference(fwd_ref, debug_incomplete_type);
2053 o.builder.resolveMetadataForwardReference(fwd_ref, debug_incomplete_type);
19722054 }
19732055 }
19742056 /// Should only be called by the `link.ConstPool` implementation.
......@@ -1992,7 +2074,7 @@ pub const Object = struct {
19922074 assert(o.debug_anyerror_fwd_ref == fwd_ref.toOptional());
19932075 } else {
19942076 const debug_type = try o.lowerDebugType(pt, ty, fwd_ref);
1995 o.builder.resolveDebugForwardReference(fwd_ref, debug_type);
2077 o.builder.resolveMetadataForwardReference(fwd_ref, debug_type);
19962078 }
19972079 }
19982080 }
......@@ -2527,7 +2609,7 @@ pub const Object = struct {
25272609 const payload_fwd_ref = if (layout.tag_size == 0)
25282610 ty_fwd_ref
25292611 else
2530 try o.builder.debugForwardReference();
2612 try o.builder.metadataForwardReference();
25312613
25322614 for (0..union_type.field_types.len) |field_index| {
25332615 const field_ty = union_type.field_types.get(ip)[field_index];
......@@ -2566,7 +2648,7 @@ pub const Object = struct {
25662648 return debug_payload_type;
25672649 }
25682650
2569 o.builder.resolveDebugForwardReference(payload_fwd_ref, debug_payload_type);
2651 o.builder.resolveMetadataForwardReference(payload_fwd_ref, debug_payload_type);
25702652
25712653 const tag_offset: u64, const payload_offset: u64 = offsets: {
25722654 if (layout.tag_align.compare(.gte, layout.payload_align)) {
......@@ -3988,6 +4070,11 @@ pub const Object = struct {
39884070 const restricted_decls = try o.getRestrictedDecls(ty);
39894071 const gop = try restricted_decls.values.getOrPut(o.gpa, arg_val);
39904072 if (!gop.found_existing) gop.value_ptr.* = try o.lowerValue(restricted_value.unrestricted_value);
4073 if (restricted_decls.enum_seen.len > 0) enum_seen: {
4074 const unrestricted_val: Value = .fromInterned(restricted_value.unrestricted_value);
4075 const tag_index = unrestricted_val.typeOf(zcu).enumTagFieldIndex(unrestricted_val, zcu) orelse break :enum_seen;
4076 try restricted_decls.enum_seen[tag_index].setInitializer(.true, &o.builder);
4077 }
39914078 return o.builder.intConst(.i32, gop.index);
39924079 },
39934080 .memoized_call => unreachable,
......@@ -4002,37 +4089,29 @@ pub const Object = struct {
40024089 const zcu = o.zcu;
40034090 const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr;
40044091 const offset: u64 = prev_offset + ptr.byte_offset;
4005 return switch (ptr.base_addr) {
4006 .nav => |nav| {
4007 const base_ptr = try o.lowerNavRef(nav);
4008 return o.builder.gepConst(.inbounds, .i8, base_ptr, null, &.{
4009 try o.builder.intConst(.i64, offset),
4010 });
4011 },
4092 const base_ptr = base_ptr: switch (ptr.base_addr) {
4093 .nav => |nav| try o.lowerNavRef(nav),
40124094 .uav => |uav| {
40134095 const orig_ptr_ty: Type = .fromInterned(uav.orig_ty);
4014 const base_ptr = try o.lowerUavRef(
4096 break :base_ptr try o.lowerUavRef(
40154097 uav.val,
40164098 orig_ptr_ty.ptrAlignment(zcu),
40174099 orig_ptr_ty.ptrAddressSpace(zcu),
40184100 );
4019 return o.builder.gepConst(.inbounds, .i8, base_ptr, null, &.{
4020 try o.builder.intConst(.i64, offset),
4021 });
40224101 },
4023 .int => try o.builder.castConst(
4102 .int => return o.builder.castConst(
40244103 .inttoptr,
40254104 try o.builder.intConst(try o.lowerType(.usize), offset),
40264105 try o.lowerType(.fromInterned(ptr.ty)),
40274106 ),
4028 .eu_payload => |eu_ptr| try o.lowerPtr(
4107 .eu_payload => |eu_ptr| return o.lowerPtr(
40294108 eu_ptr,
40304109 offset + codegen.errUnionPayloadOffset(
40314110 Value.fromInterned(eu_ptr).typeOf(zcu).childType(zcu),
40324111 zcu,
40334112 ),
40344113 ),
4035 .opt_payload => |opt_ptr| try o.lowerPtr(opt_ptr, offset),
4114 .opt_payload => |opt_ptr| return o.lowerPtr(opt_ptr, offset),
40364115 .field => |field| {
40374116 const agg_ty = Value.fromInterned(field.base).typeOf(zcu).childType(zcu);
40384117 const field_off: u64 = switch (agg_ty.zigTypeTag(zcu)) {
......@@ -4061,6 +4140,10 @@ pub const Object = struct {
40614140 .comptime_field => unreachable,
40624141 .comptime_alloc => unreachable,
40634142 };
4143 if (offset == 0) return base_ptr;
4144 return o.builder.gepConst(.inbounds, .i8, base_ptr, null, &.{
4145 try o.builder.intConst(.i64, offset),
4146 });
40644147 }
40654148
40664149 pub fn lowerPtrToVoid(
src/codegen/llvm/FuncGen.zig+68-21
......@@ -826,7 +826,7 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif
826826 };
827827 }
828828
829 const call = try self.wip.call(
829 const call = try self.wip.callMetadata(
830830 switch (modifier) {
831831 .auto, .never_inline => .normal,
832832 .never_tail => .notail,
......@@ -838,6 +838,17 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif
838838 try o.lowerType(zig_fn_ty),
839839 llvm_fn,
840840 llvm_args.items,
841 .{
842 .callees = if (air_call.callee.toIndex()) |callee_inst| switch (self.air.instructions.items(.tag)[@intFromEnum(callee_inst)]) {
843 else => .none,
844 .unwrap_restricted, .unwrap_restricted_safe => callees: {
845 const restricted_ty = self.typeOf(self.air.instructions.items(.data)[@intFromEnum(callee_inst)].ty_op.operand);
846 const restricted_decls = try o.getRestrictedDecls(restricted_ty);
847 if (restricted_decls.metadata.is_none) restricted_decls.metadata = .wrap(try o.builder.metadataForwardReference());
848 break :callees restricted_decls.metadata;
849 },
850 } else .none,
851 },
841852 "",
842853 );
843854
......@@ -1667,6 +1678,7 @@ fn lowerTry(
16671678fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index, is_dispatch_loop: bool) TodoError!void {
16681679 const o = self.object;
16691680 const zcu = o.zcu;
1681 const ip = &zcu.intern_pool;
16701682
16711683 const switch_br = self.air.unwrapSwitch(inst);
16721684
......@@ -1694,6 +1706,7 @@ fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Tod
16941706 // This asm is really, really, not what we want. As such, we will construct the jump table manually where
16951707 // appropriate (the values are dense and relatively few), and use it when lowering dispatches.
16961708
1709 const cond_ty = self.typeOf(switch_br.operand);
16971710 const jmp_table: ?SwitchDispatchInfo.JmpTable = jmp_table: {
16981711 if (!is_dispatch_loop) break :jmp_table null;
16991712
......@@ -1706,7 +1719,6 @@ fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Tod
17061719 // about acceptable - it won't fill L1d cache on most CPUs.
17071720 const max_table_len = 1024;
17081721
1709 const cond_ty = self.typeOf(switch_br.operand);
17101722 switch (cond_ty.zigTypeTag(zcu)) {
17111723 .bool, .pointer => break :jmp_table null,
17121724 .@"enum", .int, .error_set, .@"struct", .@"union" => {},
......@@ -1859,6 +1871,18 @@ fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Tod
18591871 assert(self.switch_dispatch_info.remove(inst));
18601872 };
18611873
1874 const restricted_enum_seen = if (ip.isEnumType(cond_ty.toIntern())) restricted_enum_seen: {
1875 const operand_inst = switch_br.operand.toIndex() orelse break :restricted_enum_seen &.{};
1876 switch (self.air.instructions.items(.tag)[@intFromEnum(operand_inst)]) {
1877 else => break :restricted_enum_seen &.{},
1878 .unwrap_restricted, .unwrap_restricted_safe => {
1879 const restricted_ty = self.typeOf(self.air.instructions.items(.data)[@intFromEnum(operand_inst)].ty_op.operand);
1880 const restricted_decls = try o.getRestrictedDecls(restricted_ty);
1881 break :restricted_enum_seen restricted_decls.enum_seen;
1882 },
1883 }
1884 } else &.{};
1885
18621886 // Generate the initial dispatch.
18631887 // If this is a simple `switch_br`, this is the only dispatch.
18641888 try self.lowerSwitchDispatch(inst, switch_br.operand, dispatch_info);
......@@ -1869,6 +1893,16 @@ fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Tod
18691893 const case_block = case_blocks[case.idx];
18701894 self.wip.cursor = .{ .block = case_block };
18711895 if (switch_br.getHint(case.idx) == .cold) _ = try self.wip.callIntrinsicAssumeCold();
1896 if (restricted_enum_seen.len > 0) restricted_enum_seen: {
1897 var maybe_any_seen: ?Builder.Value = null;
1898 for (case.items) |item| {
1899 const tag_index = cond_ty.enumTagFieldIndex(.fromInterned(item.toInterned().?), zcu) orelse break :restricted_enum_seen;
1900 const tag_seen = try self.wip.load(.normal, .i1, restricted_enum_seen[tag_index].toValue(&o.builder), InternPool.Alignment.@"1".toLlvm(), "");
1901 maybe_any_seen = if (maybe_any_seen) |any_seen| try self.wip.bin(.@"or", any_seen, tag_seen, "") else tag_seen;
1902 }
1903 assert(case.ranges.len == 0); // not supported by Sema yet
1904 _ = try self.wip.callIntrinsic(.normal, .none, .assume, &.{}, &.{maybe_any_seen.?}, "");
1905 }
18721906 try self.genBodyDebugScope(null, case.body, .none);
18731907 }
18741908 self.wip.cursor = .{ .block = case_blocks[case_blocks.len - 1] };
......@@ -2124,11 +2158,7 @@ fn airSliceElemVal(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder
21242158 const elem_align = slice_ty.ptrAlignment(zcu).min(elem_ty.abiAlignment(zcu));
21252159 const access_kind: Builder.MemoryAccessKind = if (slice_info.flags.is_volatile) .@"volatile" else .normal;
21262160 self.maybeMarkAllowZeroAccess(slice_info);
2127 if (isByRef(elem_ty, zcu)) {
2128 return self.loadByRef(ptr, elem_ty, elem_align.toLlvm(), access_kind);
2129 } else {
2130 return self.loadTruncate(access_kind, elem_ty, ptr, elem_align.toLlvm());
2131 }
2161 return self.load(ptr, elem_ty, elem_align.toLlvm(), access_kind);
21322162}
21332163
21342164fn airSliceElemPtr(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value {
......@@ -2153,12 +2183,7 @@ fn airArrayElemVal(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder
21532183 const elem_ty = array_ty.childType(zcu);
21542184 if (isByRef(array_ty, zcu)) {
21552185 const elem_ptr = try self.ptraddScaled(array_llvm_val, rhs, elem_ty.abiSize(zcu));
2156 if (isByRef(elem_ty, zcu)) {
2157 const elem_align = elem_ty.abiAlignment(zcu).toLlvm();
2158 return self.loadByRef(elem_ptr, elem_ty, elem_align, .normal);
2159 } else {
2160 return self.loadTruncate(.normal, elem_ty, elem_ptr, .default);
2161 }
2186 return self.load(elem_ptr, elem_ty, elem_ty.abiAlignment(zcu).toLlvm(), .normal);
21622187 }
21632188
21642189 // This branch can be reached for vectors, which are always by-value.
......@@ -2277,11 +2302,7 @@ fn airStructFieldVal(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Build
22772302 else => struct_ptr_align.minStrict(.fromLog2Units(@ctz(offset))),
22782303 };
22792304
2280 if (isByRef(field_ty, zcu)) {
2281 return self.loadByRef(field_ptr, field_ty, field_ptr_align.toLlvm(), .normal);
2282 } else {
2283 return self.loadTruncate(.normal, field_ty, field_ptr, field_ptr_align.toLlvm());
2284 }
2305 return self.load(field_ptr, field_ty, field_ptr_align.toLlvm(), .normal);
22852306}
22862307
22872308fn airFieldParentPtr(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value {
......@@ -3259,6 +3280,7 @@ fn airUnwrapRestricted(fg: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocat
32593280 const target = zcu.getTarget();
32603281 const ty_op = fg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
32613282 const unrestricted_ty = ty_op.ty.toType();
3283 const unrestricted_align = unrestricted_ty.abiAlignment(zcu);
32623284 const restricted_ty = fg.typeOf(ty_op.operand);
32633285 const operand = try fg.resolveInst(ty_op.operand);
32643286 const restricted_decls = try o.getRestrictedDecls(restricted_ty);
......@@ -3281,7 +3303,13 @@ fn airUnwrapRestricted(fg: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocat
32813303 fg.wip.cursor = .{ .block = valid_block };
32823304 }
32833305 const ptr = try fg.ptraddScaled(restricted_decls.array.toValue(&o.builder), operand, unrestricted_ty.abiSize(zcu));
3284 return fg.load(ptr, unrestricted_ty, unrestricted_ty.abiAlignment(zcu).toLlvm(), .normal);
3306 if (isByRef(unrestricted_ty, zcu)) return fg.loadByRef(ptr, unrestricted_ty, unrestricted_align.toLlvm(), .normal);
3307 return fg.wip.loadMetadata(.normal, try o.lowerType(unrestricted_ty), ptr, unrestricted_align.toLlvm(), .{
3308 .range = if (unrestricted_ty.isAbiInt(zcu)) range: {
3309 if (restricted_decls.metadata.is_none) restricted_decls.metadata = .wrap(try o.builder.metadataForwardReference());
3310 break :range restricted_decls.metadata;
3311 } else .none,
3312 }, "");
32853313}
32863314
32873315fn airWasmMemorySize(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value {
......@@ -6042,8 +6070,27 @@ fn airUnionInit(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Va
60426070 }
60436071
60446072 if (layout.tag_size != 0) {
6045 const loaded_enum = ip.loadEnumType(union_obj.enum_tag_type);
6046 const llvm_tag_val = switch (loaded_enum.field_values.getOrNone(ip, extra.field_index)) {
6073 const tag_ty: Type = .fromInterned(union_obj.enum_tag_type);
6074 const llvm_tag_val = if (tag_ty.unrestrictedType(zcu)) |unrestricted_tag_ty| llvm_tag_val: {
6075 const restricted_decls = try o.getRestrictedDecls(tag_ty);
6076 const unrestricted_tag_val = try self.pt.enumValueFieldIndex(unrestricted_tag_ty, extra.field_index);
6077 const tag_val = try self.pt.intern(.{ .restricted_value = .{
6078 .ty = union_obj.enum_tag_type,
6079 .unrestricted_value = unrestricted_tag_val.toIntern(),
6080 } });
6081 const gop = try restricted_decls.values.getOrPut(o.gpa, tag_val);
6082 if (!gop.found_existing) gop.value_ptr.* = try o.lowerValue(unrestricted_tag_val.toIntern());
6083 if (restricted_decls.enum_seen.len > 0) enum_seen: {
6084 const tag_index = unrestricted_tag_ty.enumTagFieldIndex(unrestricted_tag_val, zcu) orelse break :enum_seen;
6085 _ = try self.wip.store(
6086 .normal,
6087 .true,
6088 restricted_decls.enum_seen[tag_index].toValue(&o.builder),
6089 InternPool.Alignment.@"1".toLlvm(),
6090 );
6091 }
6092 break :llvm_tag_val try o.builder.intConst(.i32, gop.index);
6093 } else switch (ip.loadEnumType(union_obj.enum_tag_type).field_values.getOrNone(ip, extra.field_index)) {
60476094 .none => try o.builder.intConst(
60486095 try o.lowerType(.fromInterned(union_obj.enum_tag_type)),
60496096 extra.field_index, // auto-numbered
src/codegen/x86_64/CodeGen.zig+2-1
......@@ -172764,8 +172764,9 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
172764172764 var res = try cg.tempAllocMem(union_ty);
172765172765 const union_layout = union_ty.unionGetLayout(zcu);
172766172766 if (union_layout.tag_size > 0) {
172767 const tag_ty = union_ty.unionTagTypeRuntime(zcu).?;
172767172768 var tag_temp = try cg.tempFromValue(try pt.enumValueFieldIndex(
172768 union_ty.unionTagTypeRuntime(zcu).?,
172769 tag_ty.unrestrictedType(zcu) orelse tag_ty,
172769172770 union_init.field_index,
172770172771 ));
172771172772 try res.write(&tag_temp, .{
src/link/Dwarf.zig+2-1
......@@ -4046,7 +4046,8 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
40464046 const union_layout = Type.getUnionLayout(loaded_union, zcu);
40474047 try diw.writeUleb128(union_layout.abi_size);
40484048 try diw.writeUleb128(union_layout.abi_align.toByteUnits().?);
4049 const loaded_tag = ip.loadEnumType(loaded_union.enum_tag_type);
4049 const enum_tag_ty: Type = .fromInterned(loaded_union.enum_tag_type);
4050 const loaded_tag = ip.loadEnumType((enum_tag_ty.unrestrictedType(zcu) orelse enum_tag_ty).toIntern());
40504051 if (loaded_union.has_runtime_tag) {
40514052 try wip_nav.abbrevCode(.tagged_union);
40524053 try wip_nav.infoSectionOffset(
src/zig_llvm.cpp+10
......@@ -51,6 +51,7 @@
5151#include <llvm/Target/CodeGenCWrappers.h>
5252#include <llvm/Transforms/IPO.h>
5353#include <llvm/Transforms/IPO/AlwaysInliner.h>
54#include <llvm/Transforms/IPO/GlobalOpt.h>
5455#include <llvm/Transforms/Instrumentation/ThreadSanitizer.h>
5556#include <llvm/Transforms/Instrumentation/SanitizerCoverage.h>
5657#include <llvm/Transforms/Scalar.h>
......@@ -348,6 +349,10 @@ ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machi
348349 });
349350
350351 pass_builder.registerOptimizerLastEPCallback([&](ModulePassManager &module_pm, OptimizationLevel level, ThinOrFullLTOPhase lto_phase) {
352 // Restricted enums require an extra global optimization pass sometime after
353 // DropUnnecessaryAssumesPass to fully eliminate the helper global variables.
354 if (level.isOptimizingForSize()) module_pm.addPass(GlobalOptPass());
355
351356 if (!early_san) {
352357 // Code coverage instrumentation.
353358 if (options->sancov) {
......@@ -404,6 +409,11 @@ ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machi
404409 }
405410 }
406411
412 if (false) {
413 module_pm.printPipeline(outs(), [](StringRef S) { return S; });
414 outs() << '\n';
415 }
416
407417 // Optimization phase
408418 module_pm.run(llvm_module, module_am);
409419