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) {...@@ -1284,7 +1284,7 @@ pub const Attribute = union(Kind) {
1284 try w.print(" {t}(\"", .{attribute});1284 try w.print(" {t}(\"", .{attribute});
1285 var any = false;1285 var any = false;
1286 inline for (@typeInfo(AllocKind).@"struct".fields) |field| {1286 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;
1288 if (@field(allockind, field.name)) {1288 if (@field(allockind, field.name)) {
1289 if (!any) {1289 if (!any) {
1290 try w.writeByte(',');1290 try w.writeByte(',');
...@@ -1469,7 +1469,7 @@ pub const Attribute = union(Kind) {...@@ -1469,7 +1469,7 @@ pub const Attribute = union(Kind) {
1469 positive_subnormal: bool = false,1469 positive_subnormal: bool = false,
1470 positive_normal: bool = false,1470 positive_normal: bool = false,
1471 positive_infinity: bool = false,1471 positive_infinity: bool = false,
1472 _: u22 = 0,1472 unused: enum(u22) { unused = 0 } = .unused,
14731473
1474 pub const all = FpClass{1474 pub const all = FpClass{
1475 .signaling_nan = true,1475 .signaling_nan = true,
...@@ -1512,7 +1512,7 @@ pub const Attribute = union(Kind) {...@@ -1512,7 +1512,7 @@ pub const Attribute = union(Kind) {
1512 uninitialized: bool,1512 uninitialized: bool,
1513 zeroed: bool,1513 zeroed: bool,
1514 aligned: bool,1514 aligned: bool,
1515 _: u26 = 0,1515 unused: enum(u26) { unused = 0 } = .unused,
1516 };1516 };
15171517
1518 pub const AllocSize = packed struct(u32) {1518 pub const AllocSize = packed struct(u32) {
...@@ -1533,7 +1533,7 @@ pub const Attribute = union(Kind) {...@@ -1533,7 +1533,7 @@ pub const Attribute = union(Kind) {
1533 argmem: Effect = .none,1533 argmem: Effect = .none,
1534 inaccessiblemem: Effect = .none,1534 inaccessiblemem: Effect = .none,
1535 other: Effect = .none,1535 other: Effect = .none,
1536 _: u26 = 0,1536 unused: enum(u26) { unused = 0 } = .unused,
15371537
1538 pub const Effect = enum(u2) { none, read, write, readwrite };1538 pub const Effect = enum(u2) { none, read, write, readwrite };
15391539
...@@ -1553,7 +1553,7 @@ pub const Attribute = union(Kind) {...@@ -1553,7 +1553,7 @@ pub const Attribute = union(Kind) {
1553 pub const VScaleRange = packed struct(u32) {1553 pub const VScaleRange = packed struct(u32) {
1554 min: Alignment,1554 min: Alignment,
1555 max: Alignment,1555 max: Alignment,
1556 _: u20 = 0,1556 unused: enum(u20) { unused = 0 } = .unused,
15571557
1558 fn toLlvm(self: VScaleRange) packed struct(u64) { max: u32, min: u32 } {1558 fn toLlvm(self: VScaleRange) packed struct(u64) { max: u32, min: u32 } {
1559 return .{1559 return .{
...@@ -1870,7 +1870,7 @@ pub const ThreadLocal = enum(u3) {...@@ -1870,7 +1870,7 @@ pub const ThreadLocal = enum(u3) {
18701870
1871 pub fn format(p: Prefixed, w: *Writer) Writer.Error!void {1871 pub fn format(p: Prefixed, w: *Writer) Writer.Error!void {
1872 switch (p.thread_local) {1872 switch (p.thread_local) {
1873 .default => return,1873 .default => {},
1874 .generaldynamic => {1874 .generaldynamic => {
1875 var vecs: [2][]const u8 = .{ p.prefix, "thread_local" };1875 var vecs: [2][]const u8 = .{ p.prefix, "thread_local" };
1876 return w.writeVecAll(&vecs);1876 return w.writeVecAll(&vecs);
...@@ -4221,7 +4221,6 @@ pub const Function = struct {...@@ -4221,7 +4221,6 @@ pub const Function = struct {
4221 call,4221 call,
4222 @"call fast",4222 @"call fast",
4223 cmpxchg,4223 cmpxchg,
4224 @"cmpxchg weak",
4225 extractelement,4224 extractelement,
4226 extractvalue,4225 extractvalue,
4227 fadd,4226 fadd,
...@@ -4619,9 +4618,7 @@ pub const Function = struct {...@@ -4619,9 +4618,7 @@ pub const Function = struct {
4619 .@"tail call",4618 .@"tail call",
4620 .@"tail call fast",4619 .@"tail call fast",
4621 => wip.extraData(Call, instruction.data).ty.functionReturn(wip.builder),4620 => wip.extraData(Call, instruction.data).ty.functionReturn(wip.builder),
4622 .cmpxchg,4621 .cmpxchg => wip.builder.structTypeAssumeCapacity(.normal, &.{
4623 .@"cmpxchg weak",
4624 => wip.builder.structTypeAssumeCapacity(.normal, &.{
4625 wip.extraData(CmpXchg, instruction.data).cmp.typeOfWip(wip),4622 wip.extraData(CmpXchg, instruction.data).cmp.typeOfWip(wip),
4626 .i1,4623 .i1,
4627 }),4624 }),
...@@ -4806,9 +4803,7 @@ pub const Function = struct {...@@ -4806,9 +4803,7 @@ pub const Function = struct {
4806 .@"tail call",4803 .@"tail call",
4807 .@"tail call fast",4804 .@"tail call fast",
4808 => function.extraData(Call, instruction.data).ty.functionReturn(builder),4805 => function.extraData(Call, instruction.data).ty.functionReturn(builder),
4809 .cmpxchg,4806 .cmpxchg => builder.structTypeAssumeCapacity(.normal, &.{
4810 .@"cmpxchg weak",
4811 => builder.structTypeAssumeCapacity(.normal, &.{
4812 function.extraData(CmpXchg, instruction.data)4807 function.extraData(CmpXchg, instruction.data)
4813 .cmp.typeOf(function_index, builder),4808 .cmp.typeOf(function_index, builder),
4814 .i1,4809 .i1,
...@@ -5027,33 +5022,86 @@ pub const Function = struct {...@@ -5027,33 +5022,86 @@ pub const Function = struct {
5027 pub const Info = packed struct(u32) {5022 pub const Info = packed struct(u32) {
5028 alignment: Alignment,5023 alignment: Alignment,
5029 addr_space: AddrSpace,5024 addr_space: AddrSpace,
5030 _: u2 = undefined,5025 unused: enum(u2) { unused = 0 } = .unused,
5031 };5026 };
5032 };5027 };
50335028
5034 pub const Load = struct {5029 pub const Load = struct {
5035 info: MemoryAccessInfo,5030 info: Info,
5036 type: Type,5031 type: Type,
5037 ptr: Value,5032 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 };
5038 };5043 };
50395044
5040 pub const Store = struct {5045 pub const Store = struct {
5041 info: MemoryAccessInfo,5046 info: Info,
5042 val: Value,5047 val: Value,
5043 ptr: Value,5048 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 };
5044 };5057 };
50455058
5046 pub const CmpXchg = struct {5059 pub const CmpXchg = struct {
5047 info: MemoryAccessInfo,5060 info: Info,
5048 ptr: Value,5061 ptr: Value,
5049 cmp: Value,5062 cmp: Value,
5050 new: Value,5063 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 };
5053 };5101 };
50545102
5055 pub const AtomicRmw = struct {5103 pub const AtomicRmw = struct {
5056 info: MemoryAccessInfo,5104 info: Info,
5057 ptr: Value,5105 ptr: Value,
5058 val: Value,5106 val: Value,
50595107
...@@ -5073,8 +5121,21 @@ pub const Function = struct {...@@ -5073,8 +5121,21 @@ pub const Function = struct {
5073 fsub = 12,5121 fsub = 12,
5074 fmax = 13,5122 fmax = 13,
5075 fmin = 14,5123 fmin = 14,
5076 none = maxInt(u5),
5077 };5124 };
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,
5078 };5139 };
50795140
5080 pub const GetElementPtr = struct {5141 pub const GetElementPtr = struct {
...@@ -5112,6 +5173,7 @@ pub const Function = struct {...@@ -5112,6 +5173,7 @@ pub const Function = struct {
5112 callee: Value,5173 callee: Value,
5113 args_len: u32,5174 args_len: u32,
5114 //args: [args_len]Value,5175 //args: [args_len]Value,
5176 //callees: if (info.has_callees) Metadata else void,
51155177
5116 pub const Kind = enum {5178 pub const Kind = enum {
5117 normal,5179 normal,
...@@ -5125,8 +5187,9 @@ pub const Function = struct {...@@ -5125,8 +5187,9 @@ pub const Function = struct {
5125 };5187 };
5126 pub const Info = packed struct(u32) {5188 pub const Info = packed struct(u32) {
5127 call_conv: CallConv,5189 call_conv: CallConv,
5190 has_callees: bool,
5128 has_op_bundle_cold: bool,5191 has_op_bundle_cold: bool,
5129 _: u21 = undefined,5192 unused: enum(u20) { unused = 0 } = .unused,
5130 };5193 };
5131 };5194 };
51325195
...@@ -5195,8 +5258,11 @@ pub const Function = struct {...@@ -5195,8 +5258,11 @@ pub const Function = struct {
5195 Value,5258 Value,
5196 Instruction.BrCond.Weights,5259 Instruction.BrCond.Weights,
5197 => @enumFromInt(value),5260 => @enumFromInt(value),
5198 MemoryAccessInfo,
5199 Instruction.Alloca.Info,5261 Instruction.Alloca.Info,
5262 Instruction.Load.Info,
5263 Instruction.Store.Info,
5264 Instruction.CmpXchg.Info,
5265 Instruction.AtomicRmw.Info,
5200 Instruction.Call.Info,5266 Instruction.Call.Info,
5201 => @bitCast(value),5267 => @bitCast(value),
5202 else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)),5268 else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)),
...@@ -5706,6 +5772,10 @@ pub const WipFunction = struct {...@@ -5706,6 +5772,10 @@ pub const WipFunction = struct {
5706 return instruction.toValue();5772 return instruction.toValue();
5707 }5773 }
57085774
5775 pub const LoadMetadata = struct {
5776 range: Metadata.Optional = .none,
5777 };
5778
5709 pub fn load(5779 pub fn load(
5710 self: *WipFunction,5780 self: *WipFunction,
5711 access_kind: MemoryAccessKind,5781 access_kind: MemoryAccessKind,
...@@ -5714,7 +5784,19 @@ pub const WipFunction = struct {...@@ -5714,7 +5784,19 @@ pub const WipFunction = struct {
5714 alignment: Alignment,5784 alignment: Alignment,
5715 name: []const u8,5785 name: []const u8,
5716 ) Allocator.Error!Value {5786 ) 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);
5718 }5800 }
57195801
5720 pub fn loadAtomic(5802 pub fn loadAtomic(
...@@ -5726,6 +5808,20 @@ pub const WipFunction = struct {...@@ -5726,6 +5808,20 @@ pub const WipFunction = struct {
5726 ordering: AtomicOrdering,5808 ordering: AtomicOrdering,
5727 alignment: Alignment,5809 alignment: Alignment,
5728 name: []const u8,5810 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,
5729 ) Allocator.Error!Value {5825 ) Allocator.Error!Value {
5730 assert(ptr.typeOfWip(self).isPointer(self.builder));5826 assert(ptr.typeOfWip(self).isPointer(self.builder));
5731 try self.ensureUnusedExtraCapacity(1, Instruction.Load, 0);5827 try self.ensureUnusedExtraCapacity(1, Instruction.Load, 0);
...@@ -5741,13 +5837,15 @@ pub const WipFunction = struct {...@@ -5741,13 +5837,15 @@ pub const WipFunction = struct {
5741 .none => .system,5837 .none => .system,
5742 else => sync_scope,5838 else => sync_scope,
5743 },5839 },
5744 .success_ordering = ordering,5840 .ordering = ordering,
5745 .alignment = alignment,5841 .alignment = alignment,
5842 .has_range = !metadata.range.is_none,
5746 },5843 },
5747 .type = ty,5844 .type = ty,
5748 .ptr = ptr,5845 .ptr = ptr,
5749 }),5846 }),
5750 });5847 });
5848 if (metadata.range.unwrap()) |range| self.extra.appendAssumeCapacity(@bitCast(range));
5751 return instruction.toValue();5849 return instruction.toValue();
5752 }5850 }
57535851
...@@ -5784,7 +5882,7 @@ pub const WipFunction = struct {...@@ -5784,7 +5882,7 @@ pub const WipFunction = struct {
5784 .none => .system,5882 .none => .system,
5785 else => sync_scope,5883 else => sync_scope,
5786 },5884 },
5787 .success_ordering = ordering,5885 .ordering = ordering,
5788 .alignment = alignment,5886 .alignment = alignment,
5789 },5887 },
5790 .val = val,5888 .val = val,
...@@ -5803,7 +5901,7 @@ pub const WipFunction = struct {...@@ -5803,7 +5901,7 @@ pub const WipFunction = struct {
5803 try self.ensureUnusedExtraCapacity(1, NoExtra, 0);5901 try self.ensureUnusedExtraCapacity(1, NoExtra, 0);
5804 const instruction = try self.addInst(null, .{5902 const instruction = try self.addInst(null, .{
5805 .tag = .fence,5903 .tag = .fence,
5806 .data = @bitCast(MemoryAccessInfo{5904 .data = @bitCast(Instruction.Fence{
5807 .sync_scope = sync_scope,5905 .sync_scope = sync_scope,
5808 .success_ordering = ordering,5906 .success_ordering = ordering,
5809 }),5907 }),
...@@ -5833,12 +5931,10 @@ pub const WipFunction = struct {...@@ -5833,12 +5931,10 @@ pub const WipFunction = struct {
5833 _ = try self.builder.structType(.normal, &.{ ty, .i1 });5931 _ = try self.builder.structType(.normal, &.{ ty, .i1 });
5834 try self.ensureUnusedExtraCapacity(1, Instruction.CmpXchg, 0);5932 try self.ensureUnusedExtraCapacity(1, Instruction.CmpXchg, 0);
5835 const instruction = try self.addInst(name, .{5933 const instruction = try self.addInst(name, .{
5836 .tag = switch (kind) {5934 .tag = .cmpxchg,
5837 .strong => .cmpxchg,
5838 .weak => .@"cmpxchg weak",
5839 },
5840 .data = self.addExtraAssumeCapacity(Instruction.CmpXchg{5935 .data = self.addExtraAssumeCapacity(Instruction.CmpXchg{
5841 .info = .{5936 .info = .{
5937 .kind = kind,
5842 .access_kind = access_kind,5938 .access_kind = access_kind,
5843 .sync_scope = sync_scope,5939 .sync_scope = sync_scope,
5844 .success_ordering = success_ordering,5940 .success_ordering = success_ordering,
...@@ -5873,9 +5969,9 @@ pub const WipFunction = struct {...@@ -5873,9 +5969,9 @@ pub const WipFunction = struct {
5873 .data = self.addExtraAssumeCapacity(Instruction.AtomicRmw{5969 .data = self.addExtraAssumeCapacity(Instruction.AtomicRmw{
5874 .info = .{5970 .info = .{
5875 .access_kind = access_kind,5971 .access_kind = access_kind,
5876 .atomic_rmw_operation = operation,5972 .operation = operation,
5877 .sync_scope = sync_scope,5973 .sync_scope = sync_scope,
5878 .success_ordering = ordering,5974 .ordering = ordering,
5879 .alignment = alignment,5975 .alignment = alignment,
5880 },5976 },
5881 .ptr = ptr,5977 .ptr = ptr,
...@@ -6079,6 +6175,11 @@ pub const WipFunction = struct {...@@ -6079,6 +6175,11 @@ pub const WipFunction = struct {
6079 }, cond, lhs, rhs, name);6175 }, cond, lhs, rhs, name);
6080 }6176 }
60816177
6178 pub const CallMetadata = struct {
6179 callees: Metadata.Optional = .none,
6180 has_op_bundle_cold: bool = false,
6181 };
6182
6082 pub fn call(6183 pub fn call(
6083 self: *WipFunction,6184 self: *WipFunction,
6084 kind: Instruction.Call.Kind,6185 kind: Instruction.Call.Kind,
...@@ -6089,10 +6190,10 @@ pub const WipFunction = struct {...@@ -6089,10 +6190,10 @@ pub const WipFunction = struct {
6089 args: []const Value,6190 args: []const Value,
6090 name: []const u8,6191 name: []const u8,
6091 ) Allocator.Error!Value {6192 ) 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);
6093 }6194 }
60946195
6095 fn callInner(6196 pub fn callMetadata(
6096 self: *WipFunction,6197 self: *WipFunction,
6097 kind: Instruction.Call.Kind,6198 kind: Instruction.Call.Kind,
6098 call_conv: CallConv,6199 call_conv: CallConv,
...@@ -6100,8 +6201,8 @@ pub const WipFunction = struct {...@@ -6100,8 +6201,8 @@ pub const WipFunction = struct {
6100 ty: Type,6201 ty: Type,
6101 callee: Value,6202 callee: Value,
6102 args: []const Value,6203 args: []const Value,
6204 metadata: CallMetadata,
6103 name: []const u8,6205 name: []const u8,
6104 has_op_bundle_cold: bool,
6105 ) Allocator.Error!Value {6206 ) Allocator.Error!Value {
6106 const ret_ty = ty.functionReturn(self.builder);6207 const ret_ty = ty.functionReturn(self.builder);
6107 assert(ty.isFunction(self.builder));6208 assert(ty.isFunction(self.builder));
...@@ -6109,7 +6210,8 @@ pub const WipFunction = struct {...@@ -6109,7 +6210,8 @@ pub const WipFunction = struct {
6109 const params = ty.functionParameters(self.builder);6210 const params = ty.functionParameters(self.builder);
6110 for (params, args[0..params.len]) |param, arg_val| assert(param == arg_val.typeOfWip(self));6211 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));
6113 const instruction = try self.addInst(switch (ret_ty) {6215 const instruction = try self.addInst(switch (ret_ty) {
6114 .void => null,6216 .void => null,
6115 else => name,6217 else => name,
...@@ -6127,7 +6229,8 @@ pub const WipFunction = struct {...@@ -6127,7 +6229,8 @@ pub const WipFunction = struct {
6127 .data = self.addExtraAssumeCapacity(Instruction.Call{6229 .data = self.addExtraAssumeCapacity(Instruction.Call{
6128 .info = .{6230 .info = .{
6129 .call_conv = call_conv,6231 .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,
6131 },6234 },
6132 .attributes = function_attributes,6235 .attributes = function_attributes,
6133 .ty = ty,6236 .ty = ty,
...@@ -6136,6 +6239,7 @@ pub const WipFunction = struct {...@@ -6136,6 +6239,7 @@ pub const WipFunction = struct {
6136 }),6239 }),
6137 });6240 });
6138 self.extra.appendSliceAssumeCapacity(@ptrCast(args));6241 self.extra.appendSliceAssumeCapacity(@ptrCast(args));
6242 if (metadata.callees.unwrap()) |callees| self.extra.appendAssumeCapacity(@bitCast(callees));
6139 return instruction.toValue();6243 return instruction.toValue();
6140 }6244 }
61416245
...@@ -6176,15 +6280,15 @@ pub const WipFunction = struct {...@@ -6176,15 +6280,15 @@ pub const WipFunction = struct {
61766280
6177 pub fn callIntrinsicAssumeCold(self: *WipFunction) Allocator.Error!Value {6281 pub fn callIntrinsicAssumeCold(self: *WipFunction) Allocator.Error!Value {
6178 const intrinsic = try self.builder.getIntrinsic(.assume, &.{});6282 const intrinsic = try self.builder.getIntrinsic(.assume, &.{});
6179 return self.callInner(6283 return self.callMetadata(
6180 .normal,6284 .normal,
6181 CallConv.default,6285 CallConv.default,
6182 .none,6286 .none,
6183 intrinsic.typeOf(self.builder),6287 intrinsic.typeOf(self.builder),
6184 intrinsic.toValue(self.builder),6288 intrinsic.toValue(self.builder),
6185 &.{try self.builder.intValue(.i1, 1)},6289 &.{try self.builder.intValue(.i1, 1)},
6186 "",6290 .{ .has_op_bundle_cold = true },
6187 true,6291 undefined,
6188 );6292 );
6189 }6293 }
61906294
...@@ -6355,8 +6459,11 @@ pub const WipFunction = struct {...@@ -6355,8 +6459,11 @@ pub const WipFunction = struct {
6355 Value,6459 Value,
6356 Instruction.BrCond.Weights,6460 Instruction.BrCond.Weights,
6357 => @intFromEnum(value),6461 => @intFromEnum(value),
6358 MemoryAccessInfo,
6359 Instruction.Alloca.Info,6462 Instruction.Alloca.Info,
6463 Instruction.Load.Info,
6464 Instruction.Store.Info,
6465 Instruction.CmpXchg.Info,
6466 Instruction.AtomicRmw.Info,
6360 Instruction.Call.Info,6467 Instruction.Call.Info,
6361 => @bitCast(value),6468 => @bitCast(value),
6362 else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)),6469 else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)),
...@@ -6648,6 +6755,7 @@ pub const WipFunction = struct {...@@ -6648,6 +6755,7 @@ pub const WipFunction = struct {
6648 => {6755 => {
6649 var extra = self.extraDataTrail(Instruction.Call, instruction.data);6756 var extra = self.extraDataTrail(Instruction.Call, instruction.data);
6650 const args = extra.trail.next(extra.data.args_len, Value, self);6757 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);
6651 instruction.data = wip_extra.addExtra(Instruction.Call{6759 instruction.data = wip_extra.addExtra(Instruction.Call{
6652 .info = extra.data.info,6760 .info = extra.data.info,
6653 .attributes = extra.data.attributes,6761 .attributes = extra.data.attributes,
...@@ -6656,10 +6764,9 @@ pub const WipFunction = struct {...@@ -6656,10 +6764,9 @@ pub const WipFunction = struct {
6656 .args_len = extra.data.args_len,6764 .args_len = extra.data.args_len,
6657 });6765 });
6658 wip_extra.appendMappedValues(args, instructions);6766 wip_extra.appendMappedValues(args, instructions);
6767 wip_extra.appendSlice(callees);
6659 },6768 },
6660 .cmpxchg,6769 .cmpxchg => {
6661 .@"cmpxchg weak",
6662 => {
6663 const extra = self.extraData(Instruction.CmpXchg, instruction.data);6770 const extra = self.extraData(Instruction.CmpXchg, instruction.data);
6664 instruction.data = wip_extra.addExtra(Instruction.CmpXchg{6771 instruction.data = wip_extra.addExtra(Instruction.CmpXchg{
6665 .info = extra.info,6772 .info = extra.info,
...@@ -6730,12 +6837,14 @@ pub const WipFunction = struct {...@@ -6730,12 +6837,14 @@ pub const WipFunction = struct {
6730 .load,6837 .load,
6731 .@"load atomic",6838 .@"load atomic",
6732 => {6839 => {
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);
6734 instruction.data = wip_extra.addExtra(Instruction.Load{6842 instruction.data = wip_extra.addExtra(Instruction.Load{
6735 .type = extra.type,6843 .type = extra.data.type,
6736 .ptr = instructions.map(extra.ptr),6844 .ptr = instructions.map(extra.data.ptr),
6737 .info = extra.info,6845 .info = extra.data.info,
6738 });6846 });
6847 wip_extra.appendSlice(range);
6739 },6848 },
6740 .phi,6849 .phi,
6741 .@"phi fast",6850 .@"phi fast",
...@@ -7011,8 +7120,11 @@ pub const WipFunction = struct {...@@ -7011,8 +7120,11 @@ pub const WipFunction = struct {
7011 Value,7120 Value,
7012 Instruction.BrCond.Weights,7121 Instruction.BrCond.Weights,
7013 => @intFromEnum(value),7122 => @intFromEnum(value),
7014 MemoryAccessInfo,
7015 Instruction.Alloca.Info,7123 Instruction.Alloca.Info,
7124 Instruction.Load.Info,
7125 Instruction.Store.Info,
7126 Instruction.CmpXchg.Info,
7127 Instruction.AtomicRmw.Info,
7016 Instruction.Call.Info,7128 Instruction.Call.Info,
7017 => @bitCast(value),7129 => @bitCast(value),
7018 else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)),7130 else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)),
...@@ -7060,8 +7172,11 @@ pub const WipFunction = struct {...@@ -7060,8 +7172,11 @@ pub const WipFunction = struct {
7060 Value,7172 Value,
7061 Instruction.BrCond.Weights,7173 Instruction.BrCond.Weights,
7062 => @enumFromInt(value),7174 => @enumFromInt(value),
7063 MemoryAccessInfo,
7064 Instruction.Alloca.Info,7175 Instruction.Alloca.Info,
7176 Instruction.Load.Info,
7177 Instruction.Store.Info,
7178 Instruction.CmpXchg.Info,
7179 Instruction.AtomicRmw.Info,
7065 Instruction.Call.Info,7180 Instruction.Call.Info,
7066 => @bitCast(value),7181 => @bitCast(value),
7067 else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)),7182 else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)),
...@@ -7121,10 +7236,10 @@ pub const MemoryAccessKind = enum(u1) {...@@ -7121,10 +7236,10 @@ pub const MemoryAccessKind = enum(u1) {
71217236
7122 pub fn format(p: Prefixed, w: *Writer) Writer.Error!void {7237 pub fn format(p: Prefixed, w: *Writer) Writer.Error!void {
7123 switch (p.memory_access_kind) {7238 switch (p.memory_access_kind) {
7124 .normal => return,7239 .normal => {},
7125 .@"volatile" => {7240 .@"volatile" => {
7126 var vecs: [2][]const u8 = .{ p.prefix, "volatile" };7241 var vecs: [2][]const u8 = .{ p.prefix, "volatile" };
7127 return w.writeVecAll(&vecs);7242 try w.writeVecAll(&vecs);
7128 },7243 },
7129 }7244 }
7130 }7245 }
...@@ -7149,10 +7264,10 @@ pub const SyncScope = enum(u1) {...@@ -7149,10 +7264,10 @@ pub const SyncScope = enum(u1) {
71497264
7150 pub fn format(p: Prefixed, w: *Writer) Writer.Error!void {7265 pub fn format(p: Prefixed, w: *Writer) Writer.Error!void {
7151 switch (p.sync_scope) {7266 switch (p.sync_scope) {
7152 .system => return,7267 .system => {},
7153 .singlethread => {7268 .singlethread => {
7154 var vecs: [2][]const u8 = .{ p.prefix, "syncscope(\"singlethread\")" };7269 var vecs: [2][]const u8 = .{ p.prefix, "syncscope(\"singlethread\")" };
7155 return w.writeVecAll(&vecs);7270 try w.writeVecAll(&vecs);
7156 },7271 },
7157 }7272 }
7158 }7273 }
...@@ -7182,10 +7297,10 @@ pub const AtomicOrdering = enum(u3) {...@@ -7182,10 +7297,10 @@ pub const AtomicOrdering = enum(u3) {
71827297
7183 pub fn format(p: Prefixed, w: *Writer) Writer.Error!void {7298 pub fn format(p: Prefixed, w: *Writer) Writer.Error!void {
7184 switch (p.atomic_ordering) {7299 switch (p.atomic_ordering) {
7185 .none => return,7300 .none => {},
7186 else => {7301 else => {
7187 var vecs: [2][]const u8 = .{ p.prefix, @tagName(p.atomic_ordering) };7302 var vecs: [2][]const u8 = .{ p.prefix, @tagName(p.atomic_ordering) };
7188 return w.writeVecAll(&vecs);7303 try w.writeVecAll(&vecs);
7189 },7304 },
7190 }7305 }
7191 }7306 }
...@@ -7196,16 +7311,6 @@ pub const AtomicOrdering = enum(u3) {...@@ -7196,16 +7311,6 @@ pub const AtomicOrdering = enum(u3) {
7196 }7311 }
7197};7312};
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
7209pub const FastMath = packed struct(u8) {7314pub const FastMath = packed struct(u8) {
7210 unsafe_algebra: bool = false, // Legacy7315 unsafe_algebra: bool = false, // Legacy
7211 nnan: bool = false,7316 nnan: bool = false,
...@@ -7533,7 +7638,7 @@ pub const Constant = enum(u32) {...@@ -7533,7 +7638,7 @@ pub const Constant = enum(u32) {
7533 const item = builder.constant_items.get(constant);7638 const item = builder.constant_items.get(constant);
7534 return switch (item.tag) {7639 return switch (item.tag) {
7535 .positive_integer => {7640 .positive_integer => {
7536 const extra: *align(@alignOf(std.math.big.Limb)) Integer =7641 const extra: *align(@alignOf(std.math.big.Limb)) const Integer =
7537 @ptrCast(builder.constant_limbs.items[item.data..][0..Integer.limbs]);7642 @ptrCast(builder.constant_limbs.items[item.data..][0..Integer.limbs]);
7538 const limbs = builder.constant_limbs7643 const limbs = builder.constant_limbs
7539 .items[item.data + Integer.limbs ..][0..extra.limbs_len];7644 .items[item.data + Integer.limbs ..][0..extra.limbs_len];
...@@ -7568,6 +7673,21 @@ pub const Constant = enum(u32) {...@@ -7568,6 +7673,21 @@ pub const Constant = enum(u32) {
7568 }7673 }
7569 }7674 }
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
7571 pub fn getBase(self: Constant, builder: *const Builder) Global.Index {7691 pub fn getBase(self: Constant, builder: *const Builder) Global.Index {
7572 var cur = self;7692 var cur = self;
7573 while (true) switch (cur.unwrap()) {7693 while (true) switch (cur.unwrap()) {
...@@ -8183,7 +8303,7 @@ pub const Metadata = packed struct(u32) {...@@ -8183,7 +8303,7 @@ pub const Metadata = packed struct(u32) {
8183 };8303 };
81848304
8185 pub const DIFlags = packed struct(u32) {8305 pub const DIFlags = packed struct(u32) {
8186 Visibility: enum(u2) { Zero, Private, Protected, Public } = .Zero,8306 Visibility: enum(u2) { None, Private, Protected, Public } = .None,
8187 FwdDecl: bool = false,8307 FwdDecl: bool = false,
8188 AppleBlock: bool = false,8308 AppleBlock: bool = false,
8189 ReservedBit4: u1 = 0,8309 ReservedBit4: u1 = 0,
...@@ -8199,11 +8319,11 @@ pub const Metadata = packed struct(u32) {...@@ -8199,11 +8319,11 @@ pub const Metadata = packed struct(u32) {
8199 RValueReference: bool = false,8319 RValueReference: bool = false,
8200 ExportSymbols: bool = false,8320 ExportSymbols: bool = false,
8201 Inheritance: enum(u2) {8321 Inheritance: enum(u2) {
8202 Zero,8322 None,
8203 SingleInheritance,8323 SingleInheritance,
8204 MultipleInheritance,8324 MultipleInheritance,
8205 VirtualInheritance,8325 VirtualInheritance,
8206 } = .Zero,8326 } = .None,
8207 IntroducedVirtual: bool = false,8327 IntroducedVirtual: bool = false,
8208 BitField: bool = false,8328 BitField: bool = false,
8209 NoReturn: bool = false,8329 NoReturn: bool = false,
...@@ -8226,7 +8346,7 @@ pub const Metadata = packed struct(u32) {...@@ -8226,7 +8346,7 @@ pub const Metadata = packed struct(u32) {
8226 if (need_pipe) try w.writeAll(" | ") else need_pipe = true;8346 if (need_pipe) try w.writeAll(" | ") else need_pipe = true;
8227 try w.print("DIFlag{s}", .{field.name});8347 try w.print("DIFlag{s}", .{field.name});
8228 },8348 },
8229 .@"enum" => if (@field(self, field.name) != .Zero) {8349 .@"enum" => if (@field(self, field.name) != .None) {
8230 if (need_pipe) try w.writeAll(" | ") else need_pipe = true;8350 if (need_pipe) try w.writeAll(" | ") else need_pipe = true;
8231 try w.print("DIFlag{s}", .{@tagName(@field(self, field.name))});8351 try w.print("DIFlag{s}", .{@tagName(@field(self, field.name))});
8232 },8352 },
...@@ -8262,7 +8382,7 @@ pub const Metadata = packed struct(u32) {...@@ -8262,7 +8382,7 @@ pub const Metadata = packed struct(u32) {
8262 };8382 };
82638383
8264 pub const DISPFlags = packed struct(u32) {8384 pub const DISPFlags = packed struct(u32) {
8265 Virtuality: enum(u2) { Zero, Virtual, PureVirtual } = .Zero,8385 Virtuality: enum(u2) { None, Virtual, PureVirtual } = .None,
8266 LocalToUnit: bool = false,8386 LocalToUnit: bool = false,
8267 Definition: bool = false,8387 Definition: bool = false,
8268 Optimized: bool = false,8388 Optimized: bool = false,
...@@ -8283,7 +8403,7 @@ pub const Metadata = packed struct(u32) {...@@ -8283,7 +8403,7 @@ pub const Metadata = packed struct(u32) {
8283 if (need_pipe) try w.writeAll(" | ") else need_pipe = true;8403 if (need_pipe) try w.writeAll(" | ") else need_pipe = true;
8284 try w.print("DISPFlag{s}", .{field.name});8404 try w.print("DISPFlag{s}", .{field.name});
8285 },8405 },
8286 .@"enum" => if (@field(self, field.name) != .Zero) {8406 .@"enum" => if (@field(self, field.name) != .None) {
8287 if (need_pipe) try w.writeAll(" | ") else need_pipe = true;8407 if (need_pipe) try w.writeAll(" | ") else need_pipe = true;
8288 try w.print("DISPFlag{s}", .{@tagName(@field(self, field.name))});8408 try w.print("DISPFlag{s}", .{@tagName(@field(self, field.name))});
8289 },8409 },
...@@ -10007,11 +10127,11 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void...@@ -10007,11 +10127,11 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void
10007 instruction_index.name(&function).fmt(self),10127 instruction_index.name(&function).fmt(self),
10008 tag,10128 tag,
10009 extra.info.access_kind.fmt(" "),10129 extra.info.access_kind.fmt(" "),
10010 extra.info.atomic_rmw_operation,10130 extra.info.operation,
10011 extra.ptr.fmt(function_index, self, .{ .percent = true }),10131 extra.ptr.fmt(function_index, self, .{ .percent = true }),
10012 extra.val.fmt(function_index, self, .{ .percent = true }),10132 extra.val.fmt(function_index, self, .{ .percent = true }),
10013 extra.info.sync_scope.fmt(" "),10133 extra.info.sync_scope.fmt(" "),
10014 extra.info.success_ordering.fmt(" "),10134 extra.info.ordering.fmt(" "),
10015 extra.info.alignment.fmt(", "),10135 extra.info.alignment.fmt(", "),
10016 });10136 });
10017 },10137 },
...@@ -10055,9 +10175,10 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void...@@ -10055,9 +10175,10 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void
10055 .@"tail call",10175 .@"tail call",
10056 .@"tail call fast",10176 .@"tail call fast",
10057 => |tag| {10177 => |tag| {
10058 var extra =10178 var extra = function.extraDataTrail(Function.Instruction.Call, instruction.data);
10059 function.extraDataTrail(Function.Instruction.Call, instruction.data);
10060 const args = extra.trail.next(extra.data.args_len, Value, &function);10179 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);
10061 try w.writeAll(" ");10182 try w.writeAll(" ");
10062 const ret_ty = extra.data.ty.functionReturn(self);10183 const ret_ty = extra.data.ty.functionReturn(self);
10063 switch (ret_ty) {10184 switch (ret_ty) {
...@@ -10089,9 +10210,6 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void...@@ -10089,9 +10210,6 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void
10089 });10210 });
10090 }10211 }
10091 try w.writeByte(')');10212 try w.writeByte(')');
10092 if (extra.data.info.has_op_bundle_cold) {
10093 try w.writeAll(" [ \"cold\"() ]");
10094 }
10095 const call_function_attributes = extra.data.attributes.func(self);10213 const call_function_attributes = extra.data.attributes.func(self);
10096 if (call_function_attributes != .none) try w.print(" #{d}", .{10214 if (call_function_attributes != .none) try w.print(" #{d}", .{
10097 (try attribute_groups.getOrPutValue(10215 (try attribute_groups.getOrPutValue(
...@@ -10100,15 +10218,19 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void...@@ -10100,15 +10218,19 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void
10100 {},10218 {},
10101 )).index,10219 )).index,
10102 });10220 });
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 });
10103 },10227 },
10104 .cmpxchg,10228 .cmpxchg => |tag| {
10105 .@"cmpxchg weak",10229 const extra = function.extraData(Function.Instruction.CmpXchg, instruction.data);
10106 => |tag| {10230 try w.print(" %{f} = {t}{f}{f} {f}, {f}, {f}{f}{f}{f}{f}", .{
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}", .{
10110 instruction_index.name(&function).fmt(self),10231 instruction_index.name(&function).fmt(self),
10111 tag,10232 tag,
10233 extra.info.kind.fmt(" "),
10112 extra.info.access_kind.fmt(" "),10234 extra.info.access_kind.fmt(" "),
10113 extra.ptr.fmt(function_index, self, .{ .percent = true }),10235 extra.ptr.fmt(function_index, self, .{ .percent = true }),
10114 extra.cmp.fmt(function_index, self, .{ .percent = true }),10236 extra.cmp.fmt(function_index, self, .{ .percent = true }),
...@@ -10143,11 +10265,11 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void...@@ -10143,11 +10265,11 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void
10143 for (indices) |index| try w.print(", {d}", .{index});10265 for (indices) |index| try w.print(", {d}", .{index});
10144 },10266 },
10145 .fence => |tag| {10267 .fence => |tag| {
10146 const info: MemoryAccessInfo = @bitCast(instruction.data);10268 const fence: Function.Instruction.Fence = @bitCast(instruction.data);
10147 try w.print(" {t}{f}{f}", .{10269 try w.print(" {t}{f}{f}", .{
10148 tag,10270 tag,
10149 info.sync_scope.fmt(" "),10271 fence.sync_scope.fmt(" "),
10150 info.success_ordering.fmt(" "),10272 fence.success_ordering.fmt(" "),
10151 });10273 });
10152 },10274 },
10153 .fneg,10275 .fneg,
...@@ -10221,16 +10343,22 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void...@@ -10221,16 +10343,22 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void
10221 .load,10343 .load,
10222 .@"load atomic",10344 .@"load atomic",
10223 => |tag| {10345 => |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);
10225 try w.print(" %{f} = {t}{f} {f}, {f}{f}{f}{f}", .{10348 try w.print(" %{f} = {t}{f} {f}, {f}{f}{f}{f}", .{
10226 instruction_index.name(&function).fmt(self),10349 instruction_index.name(&function).fmt(self),
10227 tag,10350 tag,
10228 extra.info.access_kind.fmt(" "),10351 extra.data.info.access_kind.fmt(" "),
10229 extra.type.fmt(self, .percent),10352 extra.data.type.fmt(self, .percent),
10230 extra.ptr.fmt(function_index, self, .{ .percent = true }),10353 extra.data.ptr.fmt(function_index, self, .{ .percent = true }),
10231 extra.info.sync_scope.fmt(" "),10354 extra.data.info.sync_scope.fmt(" "),
10232 extra.info.success_ordering.fmt(" "),10355 extra.data.info.ordering.fmt(" "),
10233 extra.info.alignment.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),
10234 });10362 });
10235 },10363 },
10236 .phi,10364 .phi,
...@@ -10296,7 +10424,7 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void...@@ -10296,7 +10424,7 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void
10296 extra.val.fmt(function_index, self, .{ .percent = true }),10424 extra.val.fmt(function_index, self, .{ .percent = true }),
10297 extra.ptr.fmt(function_index, self, .{ .percent = true }),10425 extra.ptr.fmt(function_index, self, .{ .percent = true }),
10298 extra.info.sync_scope.fmt(" "),10426 extra.info.sync_scope.fmt(" "),
10299 extra.info.success_ordering.fmt(" "),10427 extra.info.ordering.fmt(" "),
10300 extra.info.alignment.fmt(", "),10428 extra.info.alignment.fmt(", "),
10301 });10429 });
10302 },10430 },
...@@ -12291,9 +12419,12 @@ pub fn debugFloatType(...@@ -12291,9 +12419,12 @@ pub fn debugFloatType(
12291 return self.debugFloatTypeAssumeCapacity(name, size_in_bits);12419 return self.debugFloatTypeAssumeCapacity(name, size_in_bits);
12292}12420}
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 {
12295 try self.metadata_forward_references.ensureUnusedCapacity(self.gpa, 1);12426 try self.metadata_forward_references.ensureUnusedCapacity(self.gpa, 1);
12296 return self.debugForwardReferenceAssumeCapacity();12427 return self.metadataForwardReferenceAssumeCapacity();
12297}12428}
1229812429
12299pub fn debugStructType(12430pub fn debugStructType(
...@@ -12521,15 +12652,8 @@ pub fn debugExpression(self: *Builder, elements: []const u32) Allocator.Error!Me...@@ -12521,15 +12652,8 @@ pub fn debugExpression(self: *Builder, elements: []const u32) Allocator.Error!Me
12521}12652}
1252212653
12523pub fn metadataTuple(self: *Builder, elements: []const Metadata) Allocator.Error!Metadata {12654pub 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 {
12531 try self.ensureUnusedMetadataCapacity(1, Metadata.Tuple, elements.len);12655 try self.ensureUnusedMetadataCapacity(1, Metadata.Tuple, elements.len);
12532 return self.metadataTupleOptionalsAssumeCapacity(elements);12656 return self.metadataTupleAssumeCapacity(elements);
12533}12657}
1253412658
12535pub fn debugLocalVar(12659pub fn debugLocalVar(
...@@ -12595,9 +12719,12 @@ pub fn metadataConstant(self: *Builder, value: Constant) Allocator.Error!Metadat...@@ -12595,9 +12719,12 @@ pub fn metadataConstant(self: *Builder, value: Constant) Allocator.Error!Metadat
12595 return self.metadataConstantAssumeCapacity(value);12719 return self.metadataConstantAssumeCapacity(value);
12596}12720}
1259712721
12722/// Deprecated, use `resolveMetadataForwardReference`.
12723pub const resolveDebugForwardReference = resolveMetadataForwardReference;
12724
12598/// Resolves the given forward reference to the given value (which is not itself a forward12725/// Resolves the given forward reference to the given value (which is not itself a forward
12599/// reference). If the forward reference is already resolved, its target is replaced.12726/// 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 {
12601 assert(fwd_ref.kind == .forward);12728 assert(fwd_ref.kind == .forward);
12602 assert(value.kind != .forward);12729 assert(value.kind != .forward);
12603 self.metadata_forward_references.items[fwd_ref.index] = value.toOptional();12730 self.metadata_forward_references.items[fwd_ref.index] = value.toOptional();
...@@ -12790,8 +12917,7 @@ fn debugFloatTypeAssumeCapacity(self: *Builder, name: ?Metadata.String, size_in_...@@ -12790,8 +12917,7 @@ fn debugFloatTypeAssumeCapacity(self: *Builder, name: ?Metadata.String, size_in_
12790 });12917 });
12791}12918}
1279212919
12793fn debugForwardReferenceAssumeCapacity(self: *Builder) Metadata {12920fn metadataForwardReferenceAssumeCapacity(self: *Builder) Metadata {
12794 assert(!self.strip);
12795 const index = self.metadata_forward_references.items.len;12921 const index = self.metadata_forward_references.items.len;
12796 self.metadata_forward_references.appendAssumeCapacity(.none);12922 self.metadata_forward_references.appendAssumeCapacity(.none);
12797 return .{ .index = @intCast(index), .kind = .forward };12923 return .{ .index = @intCast(index), .kind = .forward };
...@@ -13164,9 +13290,9 @@ fn debugExpressionAssumeCapacity(self: *Builder, elements: []const u32) Metadata...@@ -13164,9 +13290,9 @@ fn debugExpressionAssumeCapacity(self: *Builder, elements: []const u32) Metadata
13164 return .{ .index = @intCast(gop.index), .kind = .node };13290 return .{ .index = @intCast(gop.index), .kind = .node };
13165}13291}
1316613292
13167fn metadataTupleOptionalsAssumeCapacity(self: *Builder, elements: []const Metadata.Optional) Metadata {13293fn metadataTupleAssumeCapacity(self: *Builder, elements: []const Metadata) Metadata {
13168 const Key = struct {13294 const Key = struct {
13169 elements: []const Metadata.Optional,13295 elements: []const Metadata,
13170 };13296 };
13171 const Adapter = struct {13297 const Adapter = struct {
13172 builder: *const Builder,13298 builder: *const Builder,
...@@ -13181,9 +13307,9 @@ fn metadataTupleOptionalsAssumeCapacity(self: *Builder, elements: []const Metada...@@ -13181,9 +13307,9 @@ fn metadataTupleOptionalsAssumeCapacity(self: *Builder, elements: []const Metada
13181 const rhs_data = ctx.builder.metadata_items.items(.data)[rhs_index];13307 const rhs_data = ctx.builder.metadata_items.items(.data)[rhs_index];
13182 var rhs_extra = ctx.builder.metadataExtraDataTrail(Metadata.Tuple, rhs_data);13308 var rhs_extra = ctx.builder.metadataExtraDataTrail(Metadata.Tuple, rhs_data);
13183 return std.mem.eql(13309 return std.mem.eql(
13184 Metadata.Optional,13310 Metadata,
13185 lhs_key.elements,13311 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),
13187 );13313 );
13188 }13314 }
13189 };13315 };
...@@ -13949,7 +14075,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco...@@ -13949,7 +14075,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco
13949 .positive_integer,14075 .positive_integer,
13950 .negative_integer,14076 .negative_integer,
13951 => |tag| {14077 => |tag| {
13952 const extra: *align(@alignOf(std.math.big.Limb)) Constant.Integer =14078 const extra: *align(@alignOf(std.math.big.Limb)) const Constant.Integer =
13953 @ptrCast(self.constant_limbs.items[data..][0..Constant.Integer.limbs]);14079 @ptrCast(self.constant_limbs.items[data..][0..Constant.Integer.limbs]);
13954 const bigint: std.math.big.int.Const = .{14080 const bigint: std.math.big.int.Const = .{
13955 .limbs = self.constant_limbs14081 .limbs = self.constant_limbs
...@@ -15109,7 +15235,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco...@@ -15109,7 +15235,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco
15109 .ty = extra.type,15235 .ty = extra.type,
15110 .alignment = extra.info.alignment.toLlvm(),15236 .alignment = extra.info.alignment.toLlvm(),
15111 .is_volatile = extra.info.access_kind == .@"volatile",15237 .is_volatile = extra.info.access_kind == .@"volatile",
15112 .success_ordering = extra.info.success_ordering,15238 .ordering = extra.info.ordering,
15113 .sync_scope = extra.info.sync_scope,15239 .sync_scope = extra.info.sync_scope,
15114 });15240 });
15115 },15241 },
...@@ -15129,7 +15255,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco...@@ -15129,7 +15255,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco
15129 .val = adapter.getOffsetValueIndex(extra.val),15255 .val = adapter.getOffsetValueIndex(extra.val),
15130 .alignment = extra.info.alignment.toLlvm(),15256 .alignment = extra.info.alignment.toLlvm(),
15131 .is_volatile = extra.info.access_kind == .@"volatile",15257 .is_volatile = extra.info.access_kind == .@"volatile",
15132 .success_ordering = extra.info.success_ordering,15258 .ordering = extra.info.ordering,
15133 .sync_scope = extra.info.sync_scope,15259 .sync_scope = extra.info.sync_scope,
15134 });15260 });
15135 },15261 },
...@@ -15212,18 +15338,15 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco...@@ -15212,18 +15338,15 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco
15212 try function_block.writeAbbrev(FunctionBlock.AtomicRmw{15338 try function_block.writeAbbrev(FunctionBlock.AtomicRmw{
15213 .ptr = adapter.getOffsetValueIndex(extra.ptr),15339 .ptr = adapter.getOffsetValueIndex(extra.ptr),
15214 .val = adapter.getOffsetValueIndex(extra.val),15340 .val = adapter.getOffsetValueIndex(extra.val),
15215 .operation = extra.info.atomic_rmw_operation,15341 .operation = extra.info.operation,
15216 .is_volatile = extra.info.access_kind == .@"volatile",15342 .is_volatile = extra.info.access_kind == .@"volatile",
15217 .success_ordering = extra.info.success_ordering,15343 .ordering = extra.info.ordering,
15218 .sync_scope = extra.info.sync_scope,15344 .sync_scope = extra.info.sync_scope,
15219 .alignment = extra.info.alignment.toLlvm(),15345 .alignment = extra.info.alignment.toLlvm(),
15220 });15346 });
15221 },15347 },
15222 .cmpxchg,15348 .cmpxchg => {
15223 .@"cmpxchg weak",
15224 => |kind| {
15225 const extra = func.extraData(Function.Instruction.CmpXchg, data);15349 const extra = func.extraData(Function.Instruction.CmpXchg, data);
15226
15227 try function_block.writeAbbrev(FunctionBlock.CmpXchg{15350 try function_block.writeAbbrev(FunctionBlock.CmpXchg{
15228 .ptr = adapter.getOffsetValueIndex(extra.ptr),15351 .ptr = adapter.getOffsetValueIndex(extra.ptr),
15229 .cmp = adapter.getOffsetValueIndex(extra.cmp),15352 .cmp = adapter.getOffsetValueIndex(extra.cmp),
...@@ -15232,15 +15355,15 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco...@@ -15232,15 +15355,15 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco
15232 .success_ordering = extra.info.success_ordering,15355 .success_ordering = extra.info.success_ordering,
15233 .sync_scope = extra.info.sync_scope,15356 .sync_scope = extra.info.sync_scope,
15234 .failure_ordering = extra.info.failure_ordering,15357 .failure_ordering = extra.info.failure_ordering,
15235 .is_weak = kind == .@"cmpxchg weak",15358 .is_weak = extra.info.kind == .weak,
15236 .alignment = extra.info.alignment.toLlvm(),15359 .alignment = extra.info.alignment.toLlvm(),
15237 });15360 });
15238 },15361 },
15239 .fence => {15362 .fence => {
15240 const info: MemoryAccessInfo = @bitCast(data);15363 const fence: Function.Instruction.Fence = @bitCast(data);
15241 try function_block.writeAbbrev(FunctionBlock.Fence{15364 try function_block.writeAbbrev(FunctionBlock.Fence{
15242 .ordering = info.success_ordering,15365 .ordering = fence.success_ordering,
15243 .sync_scope = info.sync_scope,15366 .sync_scope = fence.sync_scope,
15244 });15367 });
15245 },15368 },
15246 }15369 }
...@@ -15313,17 +15436,58 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco...@@ -15313,17 +15436,58 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco
15313 };15436 };
15314 switch (weights) {15437 switch (weights) {
15315 .none => {},15438 .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{
15317 .inst = instr_index,15472 .inst = instr_index,
15318 .kind = .unpredictable,15473 .kind = .callees,
15319 .metadata = .empty_tuple,15474 .metadata = metadata,
15320 }, metadata_adapter),15475 },
15321 _ => try metadata_attach_block.writeAbbrevAdapted(MetadataAttachmentBlock.AttachmentInstructionSingle{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{
15322 .inst = instr_index,15485 .inst = instr_index,
15323 .kind = .prof,15486 .kind = .range,
15324 .metadata = weights.toMetadata(),15487 .metadata = metadata,
15325 }, metadata_adapter),15488 },
15326 }15489 metadata_adapter,
15490 );
15327 instr_index += 1;15491 instr_index += 1;
15328 },15492 },
15329 };15493 };
lib/std/zig/llvm/ir.zig+5-5
...@@ -79,7 +79,7 @@ pub const FixedMetadataKind = enum(u6) {...@@ -79,7 +79,7 @@ pub const FixedMetadataKind = enum(u6) {
79 //tbaa = 1,79 //tbaa = 1,
80 prof = 2,80 prof = 2,
81 //fpmath = 3,81 //fpmath = 3,
82 //range = 4,82 range = 4,
83 //@"tbaa.struct" = 5,83 //@"tbaa.struct" = 5,
84 //@"invariant.load" = 6,84 //@"invariant.load" = 6,
85 //@"alias.scope" = 7,85 //@"alias.scope" = 7,
...@@ -98,7 +98,7 @@ pub const FixedMetadataKind = enum(u6) {...@@ -98,7 +98,7 @@ pub const FixedMetadataKind = enum(u6) {
98 //section_prefix = 20,98 //section_prefix = 20,
99 //absolute_symbol = 21,99 //absolute_symbol = 21,
100 //associated = 22,100 //associated = 22,
101 //callees = 23,101 callees = 23,
102 //irr_loop = 24,102 //irr_loop = 24,
103 //@"llvm.access.group" = 25,103 //@"llvm.access.group" = 25,
104 //callback = 26,104 //callback = 26,
...@@ -1232,7 +1232,7 @@ pub const ModuleBlock = struct {...@@ -1232,7 +1232,7 @@ pub const ModuleBlock = struct {
1232 ty: Builder.Type,1232 ty: Builder.Type,
1233 alignment: std.meta.Int(.unsigned, @bitSizeOf(Builder.Alignment)),1233 alignment: std.meta.Int(.unsigned, @bitSizeOf(Builder.Alignment)),
1234 is_volatile: bool,1234 is_volatile: bool,
1235 success_ordering: Builder.AtomicOrdering,1235 ordering: Builder.AtomicOrdering,
1236 sync_scope: Builder.SyncScope,1236 sync_scope: Builder.SyncScope,
1237 };1237 };
12381238
...@@ -1264,7 +1264,7 @@ pub const ModuleBlock = struct {...@@ -1264,7 +1264,7 @@ pub const ModuleBlock = struct {
1264 val: u32,1264 val: u32,
1265 alignment: std.meta.Int(.unsigned, @bitSizeOf(Builder.Alignment)),1265 alignment: std.meta.Int(.unsigned, @bitSizeOf(Builder.Alignment)),
1266 is_volatile: bool,1266 is_volatile: bool,
1267 success_ordering: Builder.AtomicOrdering,1267 ordering: Builder.AtomicOrdering,
1268 sync_scope: Builder.SyncScope,1268 sync_scope: Builder.SyncScope,
1269 };1269 };
12701270
...@@ -1315,7 +1315,7 @@ pub const ModuleBlock = struct {...@@ -1315,7 +1315,7 @@ pub const ModuleBlock = struct {
1315 val: u32,1315 val: u32,
1316 operation: Builder.Function.Instruction.AtomicRmw.Operation,1316 operation: Builder.Function.Instruction.AtomicRmw.Operation,
1317 is_volatile: bool,1317 is_volatile: bool,
1318 success_ordering: Builder.AtomicOrdering,1318 ordering: Builder.AtomicOrdering,
1319 sync_scope: Builder.SyncScope,1319 sync_scope: Builder.SyncScope,
1320 alignment: std.meta.Int(.unsigned, @bitSizeOf(Builder.Alignment)),1320 alignment: std.meta.Int(.unsigned, @bitSizeOf(Builder.Alignment)),
1321 };1321 };
src/InternPool.zig+5-2
...@@ -7998,7 +7998,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:...@@ -7998,7 +7998,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
7998 });7998 });
7999 },7999 },
8000 .restricted_value => |restricted_value| {8000 .restricted_value => |restricted_value| {
8001 assert(restricted_value.ty.unwrap(ip).getTag(ip) == .type_restricted);8001 assert(ip.isRestrictedType(restricted_value.ty));
8002 assert(!ip.isUndef(restricted_value.unrestricted_value));8002 assert(!ip.isUndef(restricted_value.unrestricted_value));
8003 items.appendAssumeCapacity(.{8003 items.appendAssumeCapacity(.{
8004 .tag = .restricted_value,8004 .tag = .restricted_value,
...@@ -9019,7 +9019,10 @@ pub fn getUnion(...@@ -9019,7 +9019,10 @@ pub fn getUnion(
9019) Allocator.Error!Index {9019) Allocator.Error!Index {
9020 assert(un.ty != .none);9020 assert(un.ty != .none);
9021 assert(un.val != .none);9021 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
9024 var gop = try ip.getOrPutKey(gpa, io, tid, .{ .un = un });9027 var gop = try ip.getOrPutKey(gpa, io, tid, .{ .un = un });
9025 defer gop.deinit();9028 defer gop.deinit();
src/Sema.zig+41-18
...@@ -10053,6 +10053,7 @@ fn analyzeSwitchBlock(...@@ -10053,6 +10053,7 @@ fn analyzeSwitchBlock(
10053) CompileError!?Air.Inst.Ref {10053) CompileError!?Air.Inst.Ref {
10054 const pt = sema.pt;10054 const pt = sema.pt;
10055 const zcu = pt.zcu;10055 const zcu = pt.zcu;
10056 const ip = &zcu.intern_pool;
10056 const gpa = sema.gpa;10057 const gpa = sema.gpa;
1005710058
10058 const src_node_offset = zir_switch.switch_src_node_offset;10059 const src_node_offset = zir_switch.switch_src_node_offset;
...@@ -10076,7 +10077,13 @@ fn analyzeSwitchBlock(...@@ -10076,7 +10077,13 @@ fn analyzeSwitchBlock(
10076 operand_ty.containerLayout(zcu) != .@"packed")10077 operand_ty.containerLayout(zcu) != .@"packed")
10077 {10078 {
10078 const tag_val = try sema.unionToTag(block, val);10079 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 };
10080 }10087 }
10081 break :init .{10088 break :init .{
10082 if (maybe_operand_opv) |operand_opv| .fromValue(operand_opv) else val,10089 if (maybe_operand_opv) |operand_opv| .fromValue(operand_opv) else val,
...@@ -10269,7 +10276,7 @@ fn analyzeSwitchBlock(...@@ -10269,7 +10276,7 @@ fn analyzeSwitchBlock(
10269 break :item_val item_opv;10276 break :item_val item_opv;
10270 }10277 }
10271 if (maybe_operand_opv) |operand_opv| {10278 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);
10273 }10280 }
10274 assert(zir_switch.any_maybe_runtime_capture); // there's a payload capture10281 assert(zir_switch.any_maybe_runtime_capture); // there's a payload capture
10275 const operand_val, const operand_ref = switch (operand) {10282 const operand_val, const operand_ref = switch (operand) {
...@@ -11211,7 +11218,8 @@ fn validateSwitchBlock(...@@ -11211,7 +11218,8 @@ fn validateSwitchBlock(
11211 const union_obj = ip.loadUnionType(operand_ty.toIntern());11218 const union_obj = ip.loadUnionType(operand_ty.toIntern());
11212 switch (union_obj.tag_usage) {11219 switch (union_obj.tag_usage) {
11213 .tagged => {11220 .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;
11215 },11223 },
11216 .none => {11224 .none => {
11217 if (union_obj.layout == .@"packed") {11225 if (union_obj.layout == .@"packed") {
...@@ -16636,7 +16644,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -16636,7 +16644,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
16636 const union_field_ty = try sema.getBuiltinType(src, .@"Type.UnionField");16644 const union_field_ty = try sema.getBuiltinType(src, .@"Type.UnionField");
1663716645
16638 const union_obj = ip.loadUnionType(unrestricted_ty.toIntern());16646 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());
16640 const layout = union_obj.layout;16649 const layout = union_obj.layout;
1664116650
16642 const union_field_vals = try gpa.alloc(InternPool.Index, enum_obj.field_names.len);16651 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...@@ -18220,7 +18229,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
18220 break :blk ty;18229 break :blk ty;
18221 };18230 };
1822218231
18223 if (elem_ty.zigTypeTag(zcu) == .noreturn)18232 if (elem_ty.toIntern() == .noreturn_type)
18224 return sema.fail(block, elem_ty_src, "pointer to noreturn not allowed", .{});18233 return sema.fail(block, elem_ty_src, "pointer to noreturn not allowed", .{});
1822518234
18226 const target = zcu.getTarget();18235 const target = zcu.getTarget();
...@@ -18253,7 +18262,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -18253,7 +18262,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
18253 const ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_i]);18262 const ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_i]);
18254 extra_i += 1;18263 extra_i += 1;
18255 break :blk try sema.resolveAddressSpace(block, addrspace_src, ref, .pointer);18264 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
18258 const bit_offset: u16 = if (inst_data.flags.has_bit_range) blk: {18267 const bit_offset: u16 = if (inst_data.flags.has_bit_range) blk: {
18259 const ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_i]);18268 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...@@ -18284,7 +18293,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
18284 }18293 }
18285 }18294 }
1828618295
18287 if (elem_ty.zigTypeTag(zcu) == .@"fn") {18296 if (ip.isFunctionType(elem_ty.toIntern())) {
18288 if (inst_data.size != .one) {18297 if (inst_data.size != .one) {
18289 return sema.fail(block, elem_ty_src, "function pointers must be single pointers", .{});18298 return sema.fail(block, elem_ty_src, "function pointers must be single pointers", .{});
18290 }18299 }
...@@ -18594,7 +18603,8 @@ fn zirStructInit(...@@ -18594,7 +18603,8 @@ fn zirStructInit(
18594 );18603 );
18595 const field_index = try sema.unionFieldIndex(block, resolved_ty, field_name, field_src);18604 const field_index = try sema.unionFieldIndex(block, resolved_ty, field_name, field_src);
18596 const tag_ty = resolved_ty.unionTagTypeHypothetical(zcu);18605 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);
18598 const field_ty: Type = .fromInterned(zcu.typeToUnion(resolved_ty).?.field_types.get(ip)[field_index]);18608 const field_ty: Type = .fromInterned(zcu.typeToUnion(resolved_ty).?.field_types.get(ip)[field_index]);
1859918609
18600 if (field_ty.classify(zcu) == .no_possible_value) {18610 if (field_ty.classify(zcu) == .no_possible_value) {
...@@ -18626,7 +18636,10 @@ fn zirStructInit(...@@ -18626,7 +18636,10 @@ fn zirStructInit(
18626 if (sema.resolveValue(init_inst)) |val| {18636 if (sema.resolveValue(init_inst)) |val| {
18627 const struct_val = Value.fromInterned(try pt.internUnion(.{18637 const struct_val = Value.fromInterned(try pt.internUnion(.{
18628 .ty = resolved_ty.toIntern(),18638 .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(),
18630 .val = val.toIntern(),18643 .val = val.toIntern(),
18631 }));18644 }));
18632 const final_val_inst = try sema.coerce(block, result_ty, Air.internedToRef(struct_val.toIntern()), src);18645 const final_val_inst = try sema.coerce(block, result_ty, Air.internedToRef(struct_val.toIntern()), src);
...@@ -19358,7 +19371,8 @@ fn fieldType(...@@ -19358,7 +19371,8 @@ fn fieldType(
19358 },19371 },
19359 .@"union" => {19372 .@"union" => {
19360 const union_obj = zcu.typeToUnion(cur_ty).?;19373 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());
19362 const field_index = enum_obj.nameIndex(ip, field_name) orelse19376 const field_index = enum_obj.nameIndex(ip, field_name) orelse
19363 return sema.failWithBadUnionFieldAccess(block, cur_ty, union_obj, field_src, field_name);19377 return sema.failWithBadUnionFieldAccess(block, cur_ty, union_obj, field_src, field_name);
19364 const field_ty = union_obj.field_types.get(ip)[field_index];19378 const field_ty = union_obj.field_types.get(ip)[field_index];
...@@ -26604,6 +26618,7 @@ fn unionFieldPtr(...@@ -26604,6 +26618,7 @@ fn unionFieldPtr(
2660426618
26605 const union_obj = zcu.typeToUnion(union_ty).?;26619 const union_obj = zcu.typeToUnion(union_ty).?;
26606 const tag_ty: Type = .fromInterned(union_obj.enum_tag_type);26620 const tag_ty: Type = .fromInterned(union_obj.enum_tag_type);
26621 const unrestricted_tag_ty = tag_ty.unrestrictedType(zcu) orelse tag_ty;
2660726622
26608 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);26623 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
26609 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);26624 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);
...@@ -26630,17 +26645,17 @@ fn unionFieldPtr(...@@ -26630,17 +26645,17 @@ fn unionFieldPtr(
26630 break :ct;26645 break :ct;
26631 }26646 }
26632 // Store to the union to initialize the tag.26647 // 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);
26634 const payload_val = try field_ty.onePossibleValue(pt) orelse try pt.undefValue(field_ty);26649 const payload_val = try field_ty.onePossibleValue(pt) orelse try pt.undefValue(field_ty);
26635 const new_union_val = try pt.unionValue(union_ty, field_tag, payload_val);26650 const new_union_val = try pt.unionValue(union_ty, field_tag, payload_val);
26636 try sema.storePtrVal(block, src, union_ptr_val, new_union_val, union_ty);26651 try sema.storePtrVal(block, src, union_ptr_val, new_union_val, union_ty);
26637 } else {26652 } else {
26638 const union_val = try sema.pointerDeref(block, src, union_ptr_val, union_ptr_val.typeOf(zcu)) orelse break :ct;26653 const union_val = try sema.pointerDeref(block, src, union_ptr_val, union_ptr_val.typeOf(zcu)) orelse break :ct;
26639 if (union_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, src, null);26654 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).?;
26641 if (active_index != field_index) {26656 if (active_index != field_index) {
26642 const msg = msg: {26657 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);
26644 const msg = try sema.errMsg(src, "access of union field '{f}' while field '{f}' is active", .{26659 const msg = try sema.errMsg(src, "access of union field '{f}' while field '{f}' is active", .{
26645 field_name.fmt(ip),26660 field_name.fmt(ip),
26646 active_field_name.fmt(ip),26661 active_field_name.fmt(ip),
...@@ -26660,19 +26675,26 @@ fn unionFieldPtr(...@@ -26660,19 +26675,26 @@ fn unionFieldPtr(
26660 // If the union has a tag, we must either set or or safety check it depending on `initializing`.26675 // If the union has a tag, we must either set or or safety check it depending on `initializing`.
26661 tag: {26676 tag: {
26662 if (union_ty.containerLayout(zcu) != .auto) break :tag;26677 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;
26664 // There is a hypothetical non-trivial tag. We must set it even if not there at runtime, but26679 // There is a hypothetical non-trivial tag. We must set it even if not there at runtime, but
26665 // only emit a safety check if it's available at runtime (i.e. it's safety-tagged).26680 // 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);
26667 if (initializing) {26682 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));
26669 try sema.checkComptimeKnownStore(block, set_tag_inst, .unneeded); // `unneeded` since this isn't a "proper" store26687 try sema.checkComptimeKnownStore(block, set_tag_inst, .unneeded); // `unneeded` since this isn't a "proper" store
26670 } else if (block.wantSafety() and union_obj.has_runtime_tag) {26688 } else if (block.wantSafety() and union_obj.has_runtime_tag) {
26671 // The tag exists at runtime (actual or safety tag), so emit a safety check.26689 // The tag exists at runtime (actual or safety tag), so emit a safety check.
26672 // TODO would it be better if get_union_tag supported pointers to unions?26690 // TODO would it be better if get_union_tag supported pointers to unions?
26673 const union_val = try block.addTyOp(.load, union_ty, union_ptr);26691 const union_val = try block.addTyOp(.load, union_ty, union_ptr);
26674 const active_tag = try block.addTyOp(.get_union_tag, tag_ty, union_val);26692 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));
26676 }26698 }
26677 }26699 }
26678 if (field_ty.classify(zcu) == .no_possible_value) {26700 if (field_ty.classify(zcu) == .no_possible_value) {
...@@ -33539,7 +33561,8 @@ fn unionFieldIndex(...@@ -33539,7 +33561,8 @@ fn unionFieldIndex(
33539 const zcu = pt.zcu;33561 const zcu = pt.zcu;
33540 const ip = &zcu.intern_pool;33562 const ip = &zcu.intern_pool;
33541 const union_obj = zcu.typeToUnion(union_ty).?;33563 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());
33543 const field_index = enum_obj.nameIndex(ip, field_name) orelse33566 const field_index = enum_obj.nameIndex(ip, field_name) orelse
33544 return sema.failWithBadUnionFieldAccess(block, union_ty, union_obj, field_src, field_name);33567 return sema.failWithBadUnionFieldAccess(block, union_ty, union_obj, field_src, field_name);
33545 return @intCast(field_index);33568 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 {...@@ -694,8 +694,9 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
694 break :tag_ty try sema.analyzeAsType(&block, tag_type_src, .union_enum_tag_type, type_ref);694 break :tag_ty try sema.analyzeAsType(&block, tag_type_src, .union_enum_tag_type, type_ref);
695 },695 },
696 };696 };
697 const unrestricted_tag_ty = tag_ty.unrestrictedType(zcu) orelse tag_ty;
697 // Because the type is explicitly specified, we need to validate it.698 // 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(
699 &block,700 &block,
700 block.src(.container_arg),701 block.src(.container_arg),
701 "expected enum tag type, found '{f}'",702 "expected enum tag type, found '{f}'",
...@@ -738,9 +739,10 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {...@@ -738,9 +739,10 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
738 },739 },
739 },740 },
740 };741 };
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);744 try sema.ensureLayoutResolved(unrestricted_enum_tag_ty, block.src(.container_arg), .backing_enum);
743 const enum_obj = ip.loadEnumType(enum_tag_ty.toIntern());745 const enum_obj = ip.loadEnumType(unrestricted_enum_tag_ty.toIntern());
744746
745 if (union_obj.is_reified) {747 if (union_obj.is_reified) {
746 // We have field names in `union_obj.reified_field_names`, but we haven't748 // 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...@@ -3241,7 +3241,7 @@ pub fn validateExtern(ty: Type, position: ExternPosition, zcu: *const Zcu) bool
3241 .pointer => {3241 .pointer => {
3242 if (ty.isSlice(zcu)) return false;3242 if (ty.isSlice(zcu)) return false;
3243 const child_ty = ty.childType(zcu);3243 const child_ty = ty.childType(zcu);
3244 if (child_ty.zigTypeTag(zcu) == .@"fn") {3244 if (zcu.intern_pool.isFunctionType(child_ty.toIntern())) {
3245 return ty.isConstPtr(zcu) and validateExternCallconv(child_ty.fnCallingConvention(zcu));3245 return ty.isConstPtr(zcu) and validateExternCallconv(child_ty.fnCallingConvention(zcu));
3246 }3246 }
3247 return true;3247 return true;
src/Zcu.zig+8-3
...@@ -4165,9 +4165,14 @@ pub const UnionLayout = struct {...@@ -4165,9 +4165,14 @@ pub const UnionLayout = struct {
4165pub fn unionTagFieldIndex(zcu: *const Zcu, loaded_union: InternPool.LoadedUnionType, enum_tag: Value) ?u32 {4165pub fn unionTagFieldIndex(zcu: *const Zcu, loaded_union: InternPool.LoadedUnionType, enum_tag: Value) ?u32 {
4166 const ip = &zcu.intern_pool;4166 const ip = &zcu.intern_pool;
4167 if (enum_tag.toIntern() == .none) return null;4167 if (enum_tag.toIntern() == .none) return null;
4168 const enum_tag_key = ip.indexToKey(enum_tag.toIntern()).enum_tag;4168 const enum_tag_key = switch (ip.indexToKey(enum_tag.toIntern())) {
4169 assert(enum_tag_key.ty == loaded_union.enum_tag_type);4169 else => unreachable,
4170 const loaded_enum = ip.loadEnumType(loaded_union.enum_tag_type);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);
4171 return loaded_enum.tagValueIndex(ip, enum_tag_key.int);4176 return loaded_enum.tagValueIndex(ip, enum_tag_key.int);
4172}4177}
41734178
src/codegen/llvm.zig+114-31
...@@ -626,8 +626,8 @@ pub const Object = struct {...@@ -626,8 +626,8 @@ pub const Object = struct {
626 try builder.metadataString(compile_unit_dir),626 try builder.metadataString(compile_unit_dir),
627 );627 );
628628
629 const debug_enums_fwd_ref = try builder.debugForwardReference();629 const debug_enums_fwd_ref = try builder.metadataForwardReference();
630 const debug_globals_fwd_ref = try builder.debugForwardReference();630 const debug_globals_fwd_ref = try builder.metadataForwardReference();
631631
632 const debug_compile_unit = try builder.debugCompileUnit(632 const debug_compile_unit = try builder.debugCompileUnit(
633 debug_file,633 debug_file,
...@@ -701,9 +701,12 @@ pub const Object = struct {...@@ -701,9 +701,12 @@ pub const Object = struct {
701 const RestrictedDecls = struct {701 const RestrictedDecls = struct {
702 len: Builder.Variable.Index,702 len: Builder.Variable.Index,
703 array: Builder.Variable.Index,703 array: Builder.Variable.Index,
704 enum_seen: []const Builder.Variable.Index,
704 values: std.array_hash_map.Auto(InternPool.Index, Builder.Constant),705 values: std.array_hash_map.Auto(InternPool.Index, Builder.Constant),
706 metadata: Builder.Metadata.Optional,
705707
706 fn deinit(rd: *RestrictedDecls, gpa: Allocator) void {708 fn deinit(rd: *RestrictedDecls, gpa: Allocator) void {
709 gpa.free(rd.enum_seen);
707 rd.values.deinit(gpa);710 rd.values.deinit(gpa);
708 rd.* = undefined;711 rd.* = undefined;
709 }712 }
...@@ -716,7 +719,8 @@ pub const Object = struct {...@@ -716,7 +719,8 @@ pub const Object = struct {
716 const zcu = o.zcu;719 const zcu = o.zcu;
717 const target = zcu.getTarget();720 const target = zcu.getTarget();
718 const ip = &zcu.intern_pool;721 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
721 const ty_name = ip.loadRestrictedType(restricted_ty.toIntern()).name.toSlice(ip);725 const ty_name = ip.loadRestrictedType(restricted_ty.toIntern()).name.toSlice(ip);
722 gop.value_ptr.* = .{726 gop.value_ptr.* = .{
...@@ -730,7 +734,28 @@ pub const Object = struct {...@@ -730,7 +734,28 @@ pub const Object = struct {
730 .void,734 .void,
731 .default,735 .default,
732 ),736 ),
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 &.{},
733 .values = .empty,757 .values = .empty,
758 .metadata = .none,
734 };759 };
735 gop.value_ptr.len.setLinkage(.private, &o.builder);760 gop.value_ptr.len.setLinkage(.private, &o.builder);
736 gop.value_ptr.len.setMutability(.constant, &o.builder);761 gop.value_ptr.len.setMutability(.constant, &o.builder);
...@@ -738,23 +763,80 @@ pub const Object = struct {...@@ -738,23 +763,80 @@ pub const Object = struct {
738 gop.value_ptr.len.setUnnamedAddr(.unnamed_addr, &o.builder);763 gop.value_ptr.len.setUnnamedAddr(.unnamed_addr, &o.builder);
739 gop.value_ptr.array.setLinkage(.private, &o.builder);764 gop.value_ptr.array.setLinkage(.private, &o.builder);
740 gop.value_ptr.array.setMutability(.constant, &o.builder);765 gop.value_ptr.array.setMutability(.constant, &o.builder);
741 gop.value_ptr.array.setAlignment(unrestricted_ty.abiAlignment(zcu).toLlvm(), &o.builder);766 gop.value_ptr.array.setAlignment(Type.fromInterned(unrestricted_type).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 module767 gop.value_ptr.array.setUnnamedAddr(.unnamed_addr, &o.builder);
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);
745 return gop.value_ptr;768 return gop.value_ptr;
746 }769 }
747 fn genRestrictedDecls(o: *Object) Allocator.Error!void {770 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| {
749 const len = restricted_decls.values.count();774 const len = restricted_decls.values.count();
750 try restricted_decls.len.setInitializer(try o.builder.intConst(.i32, len), &o.builder);775 try restricted_decls.len.setInitializer(try o.builder.intConst(.i32, len), &o.builder);
751 try restricted_decls.array.setInitializer(switch (len) {776 try restricted_decls.array.setInitializer(switch (len) {
752 0 => try o.builder.zeroInitConst(.i8), // ensure unique address777 0 => try o.builder.structConst(try o.builder.structType(.normal, &.{}), &.{}),
753 else => try o.builder.arrayConst(778 else => try o.builder.arrayConst(
754 try o.builder.arrayType(len, restricted_decls.values.values()[0].typeOf(&o.builder)),779 try o.builder.arrayType(len, restricted_decls.values.values()[0].typeOf(&o.builder)),
755 restricted_decls.values.values(),780 restricted_decls.values.values(),
756 ),781 ),
757 }, &o.builder);782 }, &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 }
758 }840 }
759 }841 }
760842
...@@ -861,17 +943,17 @@ pub const Object = struct {...@@ -861,17 +943,17 @@ pub const Object = struct {
861 if (!o.builder.strip) {943 if (!o.builder.strip) {
862 if (o.debug_anyerror_fwd_ref.unwrap()) |fwd_ref| {944 if (o.debug_anyerror_fwd_ref.unwrap()) |fwd_ref| {
863 const debug_anyerror_type = try o.lowerDebugAnyerrorType();945 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);
865 }947 }
866948
867 try o.flushTypePool(pt);949 try o.flushTypePool(pt);
868950
869 o.builder.resolveDebugForwardReference(951 o.builder.resolveMetadataForwardReference(
870 o.debug_enums_fwd_ref.unwrap().?,952 o.debug_enums_fwd_ref.unwrap().?,
871 try o.builder.metadataTuple(o.debug_enums.items),953 try o.builder.metadataTuple(o.debug_enums.items),
872 );954 );
873955
874 o.builder.resolveDebugForwardReference(956 o.builder.resolveMetadataForwardReference(
875 o.debug_globals_fwd_ref.unwrap().?,957 o.debug_globals_fwd_ref.unwrap().?,
876 try o.builder.metadataTuple(o.debug_globals.items),958 try o.builder.metadataTuple(o.debug_globals.items),
877 );959 );
...@@ -1936,7 +2018,7 @@ pub const Object = struct {...@@ -1936,7 +2018,7 @@ pub const Object = struct {
1936 if (!o.builder.strip) {2018 if (!o.builder.strip) {
1937 assert(@intFromEnum(index) == o.debug_types.items.len);2019 assert(@intFromEnum(index) == o.debug_types.items.len);
1938 try o.debug_types.ensureUnusedCapacity(gpa, 1);2020 try o.debug_types.ensureUnusedCapacity(gpa, 1);
1939 const fwd_ref = try o.builder.debugForwardReference();2021 const fwd_ref = try o.builder.metadataForwardReference();
1940 o.debug_types.appendAssumeCapacity(fwd_ref);2022 o.debug_types.appendAssumeCapacity(fwd_ref);
1941 if (val == .anyerror_type) {2023 if (val == .anyerror_type) {
1942 assert(o.debug_anyerror_fwd_ref.is_none);2024 assert(o.debug_anyerror_fwd_ref.is_none);
...@@ -1968,7 +2050,7 @@ pub const Object = struct {...@@ -1968,7 +2050,7 @@ pub const Object = struct {
1968 .@"fn" => try o.builder.debugSubroutineType(null),2050 .@"fn" => try o.builder.debugSubroutineType(null),
1969 else => try o.builder.debugSignedType(name_str, 0),2051 else => try o.builder.debugSignedType(name_str, 0),
1970 };2052 };
1971 o.builder.resolveDebugForwardReference(fwd_ref, debug_incomplete_type);2053 o.builder.resolveMetadataForwardReference(fwd_ref, debug_incomplete_type);
1972 }2054 }
1973 }2055 }
1974 /// Should only be called by the `link.ConstPool` implementation.2056 /// Should only be called by the `link.ConstPool` implementation.
...@@ -1992,7 +2074,7 @@ pub const Object = struct {...@@ -1992,7 +2074,7 @@ pub const Object = struct {
1992 assert(o.debug_anyerror_fwd_ref == fwd_ref.toOptional());2074 assert(o.debug_anyerror_fwd_ref == fwd_ref.toOptional());
1993 } else {2075 } else {
1994 const debug_type = try o.lowerDebugType(pt, ty, fwd_ref);2076 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);
1996 }2078 }
1997 }2079 }
1998 }2080 }
...@@ -2527,7 +2609,7 @@ pub const Object = struct {...@@ -2527,7 +2609,7 @@ pub const Object = struct {
2527 const payload_fwd_ref = if (layout.tag_size == 0)2609 const payload_fwd_ref = if (layout.tag_size == 0)
2528 ty_fwd_ref2610 ty_fwd_ref
2529 else2611 else
2530 try o.builder.debugForwardReference();2612 try o.builder.metadataForwardReference();
25312613
2532 for (0..union_type.field_types.len) |field_index| {2614 for (0..union_type.field_types.len) |field_index| {
2533 const field_ty = union_type.field_types.get(ip)[field_index];2615 const field_ty = union_type.field_types.get(ip)[field_index];
...@@ -2566,7 +2648,7 @@ pub const Object = struct {...@@ -2566,7 +2648,7 @@ pub const Object = struct {
2566 return debug_payload_type;2648 return debug_payload_type;
2567 }2649 }
25682650
2569 o.builder.resolveDebugForwardReference(payload_fwd_ref, debug_payload_type);2651 o.builder.resolveMetadataForwardReference(payload_fwd_ref, debug_payload_type);
25702652
2571 const tag_offset: u64, const payload_offset: u64 = offsets: {2653 const tag_offset: u64, const payload_offset: u64 = offsets: {
2572 if (layout.tag_align.compare(.gte, layout.payload_align)) {2654 if (layout.tag_align.compare(.gte, layout.payload_align)) {
...@@ -3988,6 +4070,11 @@ pub const Object = struct {...@@ -3988,6 +4070,11 @@ pub const Object = struct {
3988 const restricted_decls = try o.getRestrictedDecls(ty);4070 const restricted_decls = try o.getRestrictedDecls(ty);
3989 const gop = try restricted_decls.values.getOrPut(o.gpa, arg_val);4071 const gop = try restricted_decls.values.getOrPut(o.gpa, arg_val);
3990 if (!gop.found_existing) gop.value_ptr.* = try o.lowerValue(restricted_value.unrestricted_value);4072 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 }
3991 return o.builder.intConst(.i32, gop.index);4078 return o.builder.intConst(.i32, gop.index);
3992 },4079 },
3993 .memoized_call => unreachable,4080 .memoized_call => unreachable,
...@@ -4002,37 +4089,29 @@ pub const Object = struct {...@@ -4002,37 +4089,29 @@ pub const Object = struct {
4002 const zcu = o.zcu;4089 const zcu = o.zcu;
4003 const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr;4090 const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr;
4004 const offset: u64 = prev_offset + ptr.byte_offset;4091 const offset: u64 = prev_offset + ptr.byte_offset;
4005 return switch (ptr.base_addr) {4092 const base_ptr = base_ptr: switch (ptr.base_addr) {
4006 .nav => |nav| {4093 .nav => |nav| try o.lowerNavRef(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 },
4012 .uav => |uav| {4094 .uav => |uav| {
4013 const orig_ptr_ty: Type = .fromInterned(uav.orig_ty);4095 const orig_ptr_ty: Type = .fromInterned(uav.orig_ty);
4014 const base_ptr = try o.lowerUavRef(4096 break :base_ptr try o.lowerUavRef(
4015 uav.val,4097 uav.val,
4016 orig_ptr_ty.ptrAlignment(zcu),4098 orig_ptr_ty.ptrAlignment(zcu),
4017 orig_ptr_ty.ptrAddressSpace(zcu),4099 orig_ptr_ty.ptrAddressSpace(zcu),
4018 );4100 );
4019 return o.builder.gepConst(.inbounds, .i8, base_ptr, null, &.{
4020 try o.builder.intConst(.i64, offset),
4021 });
4022 },4101 },
4023 .int => try o.builder.castConst(4102 .int => return o.builder.castConst(
4024 .inttoptr,4103 .inttoptr,
4025 try o.builder.intConst(try o.lowerType(.usize), offset),4104 try o.builder.intConst(try o.lowerType(.usize), offset),
4026 try o.lowerType(.fromInterned(ptr.ty)),4105 try o.lowerType(.fromInterned(ptr.ty)),
4027 ),4106 ),
4028 .eu_payload => |eu_ptr| try o.lowerPtr(4107 .eu_payload => |eu_ptr| return o.lowerPtr(
4029 eu_ptr,4108 eu_ptr,
4030 offset + codegen.errUnionPayloadOffset(4109 offset + codegen.errUnionPayloadOffset(
4031 Value.fromInterned(eu_ptr).typeOf(zcu).childType(zcu),4110 Value.fromInterned(eu_ptr).typeOf(zcu).childType(zcu),
4032 zcu,4111 zcu,
4033 ),4112 ),
4034 ),4113 ),
4035 .opt_payload => |opt_ptr| try o.lowerPtr(opt_ptr, offset),4114 .opt_payload => |opt_ptr| return o.lowerPtr(opt_ptr, offset),
4036 .field => |field| {4115 .field => |field| {
4037 const agg_ty = Value.fromInterned(field.base).typeOf(zcu).childType(zcu);4116 const agg_ty = Value.fromInterned(field.base).typeOf(zcu).childType(zcu);
4038 const field_off: u64 = switch (agg_ty.zigTypeTag(zcu)) {4117 const field_off: u64 = switch (agg_ty.zigTypeTag(zcu)) {
...@@ -4061,6 +4140,10 @@ pub const Object = struct {...@@ -4061,6 +4140,10 @@ pub const Object = struct {
4061 .comptime_field => unreachable,4140 .comptime_field => unreachable,
4062 .comptime_alloc => unreachable,4141 .comptime_alloc => unreachable,
4063 };4142 };
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 });
4064 }4147 }
40654148
4066 pub fn lowerPtrToVoid(4149 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...@@ -826,7 +826,7 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif
826 };826 };
827 }827 }
828828
829 const call = try self.wip.call(829 const call = try self.wip.callMetadata(
830 switch (modifier) {830 switch (modifier) {
831 .auto, .never_inline => .normal,831 .auto, .never_inline => .normal,
832 .never_tail => .notail,832 .never_tail => .notail,
...@@ -838,6 +838,17 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif...@@ -838,6 +838,17 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif
838 try o.lowerType(zig_fn_ty),838 try o.lowerType(zig_fn_ty),
839 llvm_fn,839 llvm_fn,
840 llvm_args.items,840 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 },
841 "",852 "",
842 );853 );
843854
...@@ -1667,6 +1678,7 @@ fn lowerTry(...@@ -1667,6 +1678,7 @@ fn lowerTry(
1667fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index, is_dispatch_loop: bool) TodoError!void {1678fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index, is_dispatch_loop: bool) TodoError!void {
1668 const o = self.object;1679 const o = self.object;
1669 const zcu = o.zcu;1680 const zcu = o.zcu;
1681 const ip = &zcu.intern_pool;
16701682
1671 const switch_br = self.air.unwrapSwitch(inst);1683 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...@@ -1694,6 +1706,7 @@ fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Tod
1694 // This asm is really, really, not what we want. As such, we will construct the jump table manually where1706 // This asm is really, really, not what we want. As such, we will construct the jump table manually where
1695 // appropriate (the values are dense and relatively few), and use it when lowering dispatches.1707 // appropriate (the values are dense and relatively few), and use it when lowering dispatches.
16961708
1709 const cond_ty = self.typeOf(switch_br.operand);
1697 const jmp_table: ?SwitchDispatchInfo.JmpTable = jmp_table: {1710 const jmp_table: ?SwitchDispatchInfo.JmpTable = jmp_table: {
1698 if (!is_dispatch_loop) break :jmp_table null;1711 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...@@ -1706,7 +1719,6 @@ fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Tod
1706 // about acceptable - it won't fill L1d cache on most CPUs.1719 // about acceptable - it won't fill L1d cache on most CPUs.
1707 const max_table_len = 1024;1720 const max_table_len = 1024;
17081721
1709 const cond_ty = self.typeOf(switch_br.operand);
1710 switch (cond_ty.zigTypeTag(zcu)) {1722 switch (cond_ty.zigTypeTag(zcu)) {
1711 .bool, .pointer => break :jmp_table null,1723 .bool, .pointer => break :jmp_table null,
1712 .@"enum", .int, .error_set, .@"struct", .@"union" => {},1724 .@"enum", .int, .error_set, .@"struct", .@"union" => {},
...@@ -1859,6 +1871,18 @@ fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Tod...@@ -1859,6 +1871,18 @@ fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Tod
1859 assert(self.switch_dispatch_info.remove(inst));1871 assert(self.switch_dispatch_info.remove(inst));
1860 };1872 };
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
1862 // Generate the initial dispatch.1886 // Generate the initial dispatch.
1863 // If this is a simple `switch_br`, this is the only dispatch.1887 // If this is a simple `switch_br`, this is the only dispatch.
1864 try self.lowerSwitchDispatch(inst, switch_br.operand, dispatch_info);1888 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...@@ -1869,6 +1893,16 @@ fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Tod
1869 const case_block = case_blocks[case.idx];1893 const case_block = case_blocks[case.idx];
1870 self.wip.cursor = .{ .block = case_block };1894 self.wip.cursor = .{ .block = case_block };
1871 if (switch_br.getHint(case.idx) == .cold) _ = try self.wip.callIntrinsicAssumeCold();1895 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 }
1872 try self.genBodyDebugScope(null, case.body, .none);1906 try self.genBodyDebugScope(null, case.body, .none);
1873 }1907 }
1874 self.wip.cursor = .{ .block = case_blocks[case_blocks.len - 1] };1908 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...@@ -2124,11 +2158,7 @@ fn airSliceElemVal(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder
2124 const elem_align = slice_ty.ptrAlignment(zcu).min(elem_ty.abiAlignment(zcu));2158 const elem_align = slice_ty.ptrAlignment(zcu).min(elem_ty.abiAlignment(zcu));
2125 const access_kind: Builder.MemoryAccessKind = if (slice_info.flags.is_volatile) .@"volatile" else .normal;2159 const access_kind: Builder.MemoryAccessKind = if (slice_info.flags.is_volatile) .@"volatile" else .normal;
2126 self.maybeMarkAllowZeroAccess(slice_info);2160 self.maybeMarkAllowZeroAccess(slice_info);
2127 if (isByRef(elem_ty, zcu)) {2161 return self.load(ptr, elem_ty, elem_align.toLlvm(), access_kind);
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 }
2132}2162}
21332163
2134fn airSliceElemPtr(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value {2164fn 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...@@ -2153,12 +2183,7 @@ fn airArrayElemVal(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder
2153 const elem_ty = array_ty.childType(zcu);2183 const elem_ty = array_ty.childType(zcu);
2154 if (isByRef(array_ty, zcu)) {2184 if (isByRef(array_ty, zcu)) {
2155 const elem_ptr = try self.ptraddScaled(array_llvm_val, rhs, elem_ty.abiSize(zcu));2185 const elem_ptr = try self.ptraddScaled(array_llvm_val, rhs, elem_ty.abiSize(zcu));
2156 if (isByRef(elem_ty, zcu)) {2186 return self.load(elem_ptr, elem_ty, elem_ty.abiAlignment(zcu).toLlvm(), .normal);
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 }
2162 }2187 }
21632188
2164 // This branch can be reached for vectors, which are always by-value.2189 // 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...@@ -2277,11 +2302,7 @@ fn airStructFieldVal(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Build
2277 else => struct_ptr_align.minStrict(.fromLog2Units(@ctz(offset))),2302 else => struct_ptr_align.minStrict(.fromLog2Units(@ctz(offset))),
2278 };2303 };
22792304
2280 if (isByRef(field_ty, zcu)) {2305 return self.load(field_ptr, field_ty, field_ptr_align.toLlvm(), .normal);
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 }
2285}2306}
22862307
2287fn airFieldParentPtr(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value {2308fn 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...@@ -3259,6 +3280,7 @@ fn airUnwrapRestricted(fg: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocat
3259 const target = zcu.getTarget();3280 const target = zcu.getTarget();
3260 const ty_op = fg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;3281 const ty_op = fg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3261 const unrestricted_ty = ty_op.ty.toType();3282 const unrestricted_ty = ty_op.ty.toType();
3283 const unrestricted_align = unrestricted_ty.abiAlignment(zcu);
3262 const restricted_ty = fg.typeOf(ty_op.operand);3284 const restricted_ty = fg.typeOf(ty_op.operand);
3263 const operand = try fg.resolveInst(ty_op.operand);3285 const operand = try fg.resolveInst(ty_op.operand);
3264 const restricted_decls = try o.getRestrictedDecls(restricted_ty);3286 const restricted_decls = try o.getRestrictedDecls(restricted_ty);
...@@ -3281,7 +3303,13 @@ fn airUnwrapRestricted(fg: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocat...@@ -3281,7 +3303,13 @@ fn airUnwrapRestricted(fg: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocat
3281 fg.wip.cursor = .{ .block = valid_block };3303 fg.wip.cursor = .{ .block = valid_block };
3282 }3304 }
3283 const ptr = try fg.ptraddScaled(restricted_decls.array.toValue(&o.builder), operand, unrestricted_ty.abiSize(zcu));3305 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 }, "");
3285}3313}
32863314
3287fn airWasmMemorySize(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value {3315fn 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...@@ -6042,8 +6070,27 @@ fn airUnionInit(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Va
6042 }6070 }
60436071
6044 if (layout.tag_size != 0) {6072 if (layout.tag_size != 0) {
6045 const loaded_enum = ip.loadEnumType(union_obj.enum_tag_type);6073 const tag_ty: Type = .fromInterned(union_obj.enum_tag_type);
6046 const llvm_tag_val = switch (loaded_enum.field_values.getOrNone(ip, extra.field_index)) {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)) {
6047 .none => try o.builder.intConst(6094 .none => try o.builder.intConst(
6048 try o.lowerType(.fromInterned(union_obj.enum_tag_type)),6095 try o.lowerType(.fromInterned(union_obj.enum_tag_type)),
6049 extra.field_index, // auto-numbered6096 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 {...@@ -172764,8 +172764,9 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
172764 var res = try cg.tempAllocMem(union_ty);172764 var res = try cg.tempAllocMem(union_ty);
172765 const union_layout = union_ty.unionGetLayout(zcu);172765 const union_layout = union_ty.unionGetLayout(zcu);
172766 if (union_layout.tag_size > 0) {172766 if (union_layout.tag_size > 0) {
172767 const tag_ty = union_ty.unionTagTypeRuntime(zcu).?;
172767 var tag_temp = try cg.tempFromValue(try pt.enumValueFieldIndex(172768 var tag_temp = try cg.tempFromValue(try pt.enumValueFieldIndex(
172768 union_ty.unionTagTypeRuntime(zcu).?,172769 tag_ty.unrestrictedType(zcu) orelse tag_ty,
172769 union_init.field_index,172770 union_init.field_index,
172770 ));172771 ));
172771 try res.write(&tag_temp, .{172772 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...@@ -4046,7 +4046,8 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
4046 const union_layout = Type.getUnionLayout(loaded_union, zcu);4046 const union_layout = Type.getUnionLayout(loaded_union, zcu);
4047 try diw.writeUleb128(union_layout.abi_size);4047 try diw.writeUleb128(union_layout.abi_size);
4048 try diw.writeUleb128(union_layout.abi_align.toByteUnits().?);4048 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());
4050 if (loaded_union.has_runtime_tag) {4051 if (loaded_union.has_runtime_tag) {
4051 try wip_nav.abbrevCode(.tagged_union);4052 try wip_nav.abbrevCode(.tagged_union);
4052 try wip_nav.infoSectionOffset(4053 try wip_nav.infoSectionOffset(
src/zig_llvm.cpp+10
...@@ -51,6 +51,7 @@...@@ -51,6 +51,7 @@
51#include <llvm/Target/CodeGenCWrappers.h>51#include <llvm/Target/CodeGenCWrappers.h>
52#include <llvm/Transforms/IPO.h>52#include <llvm/Transforms/IPO.h>
53#include <llvm/Transforms/IPO/AlwaysInliner.h>53#include <llvm/Transforms/IPO/AlwaysInliner.h>
54#include <llvm/Transforms/IPO/GlobalOpt.h>
54#include <llvm/Transforms/Instrumentation/ThreadSanitizer.h>55#include <llvm/Transforms/Instrumentation/ThreadSanitizer.h>
55#include <llvm/Transforms/Instrumentation/SanitizerCoverage.h>56#include <llvm/Transforms/Instrumentation/SanitizerCoverage.h>
56#include <llvm/Transforms/Scalar.h>57#include <llvm/Transforms/Scalar.h>
...@@ -348,6 +349,10 @@ ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machi...@@ -348,6 +349,10 @@ ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machi
348 });349 });
349350
350 pass_builder.registerOptimizerLastEPCallback([&](ModulePassManager &module_pm, OptimizationLevel level, ThinOrFullLTOPhase lto_phase) {351 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
351 if (!early_san) {356 if (!early_san) {
352 // Code coverage instrumentation.357 // Code coverage instrumentation.
353 if (options->sancov) {358 if (options->sancov) {
...@@ -404,6 +409,11 @@ ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machi...@@ -404,6 +409,11 @@ ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machi
404 }409 }
405 }410 }
406411
412 if (false) {
413 module_pm.printPipeline(outs(), [](StringRef S) { return S; });
414 outs() << '\n';
415 }
416
407 // Optimization phase417 // Optimization phase
408 module_pm.run(llvm_module, module_am);418 module_pm.run(llvm_module, module_am);
409419