authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-05-25 19:23:01-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-06-10 20:47:55-07:00
log70cc68e9994f7dca53904075e15b2b6f87342539
treea02b75bcd056c2ce2d9a16a2ec51c4da06e03d9f
parent72e4ea38216aab7e7ed05978d04c5d32de44b5ce

Air: remove constant tag

Some uses have been moved to their own tag, the rest use interned. Also, finish porting comptime mutation to be more InternPool aware.

19 files changed, 863 insertions(+), 840 deletions(-)

src/Air.zig+12-6
...@@ -186,6 +186,14 @@ pub const Inst = struct {...@@ -186,6 +186,14 @@ pub const Inst = struct {
186 /// Allocates stack local memory.186 /// Allocates stack local memory.
187 /// Uses the `ty` field.187 /// Uses the `ty` field.
188 alloc,188 alloc,
189 /// This is a special value that tracks a set of types that have been stored
190 /// to an inferred allocation. It does not support any of the normal value queries.
191 /// Uses the `ty_pl` field, payload is an index of `values` array.
192 inferred_alloc,
193 /// Used to coordinate alloc_inferred, store_to_inferred_ptr, and resolve_inferred_alloc
194 /// instructions for comptime code.
195 /// Uses the `ty_pl` field, payload is an index of `values` array.
196 inferred_alloc_comptime,
189 /// If the function will pass the result by-ref, this instruction returns the197 /// If the function will pass the result by-ref, this instruction returns the
190 /// result pointer. Otherwise it is equivalent to `alloc`.198 /// result pointer. Otherwise it is equivalent to `alloc`.
191 /// Uses the `ty` field.199 /// Uses the `ty` field.
...@@ -397,9 +405,6 @@ pub const Inst = struct {...@@ -397,9 +405,6 @@ pub const Inst = struct {
397 /// was executed on the operand.405 /// was executed on the operand.
398 /// Uses the `ty_pl` field. Payload is `TryPtr`.406 /// Uses the `ty_pl` field. Payload is `TryPtr`.
399 try_ptr,407 try_ptr,
400 /// A comptime-known value. Uses the `ty_pl` field, payload is index of
401 /// `values` array.
402 constant,
403 /// A comptime-known value via an index into the InternPool.408 /// A comptime-known value via an index into the InternPool.
404 /// Uses the `interned` field.409 /// Uses the `interned` field.
405 interned,410 interned,
...@@ -1265,7 +1270,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index, ip: InternPool) Type {...@@ -1265,7 +1270,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index, ip: InternPool) Type {
12651270
1266 .assembly,1271 .assembly,
1267 .block,1272 .block,
1268 .constant,
1269 .struct_field_ptr,1273 .struct_field_ptr,
1270 .struct_field_val,1274 .struct_field_val,
1271 .slice_elem_ptr,1275 .slice_elem_ptr,
...@@ -1283,6 +1287,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index, ip: InternPool) Type {...@@ -1283,6 +1287,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index, ip: InternPool) Type {
1283 .sub_with_overflow,1287 .sub_with_overflow,
1284 .mul_with_overflow,1288 .mul_with_overflow,
1285 .shl_with_overflow,1289 .shl_with_overflow,
1290 .inferred_alloc,
1291 .inferred_alloc_comptime,
1286 .ptr_add,1292 .ptr_add,
1287 .ptr_sub,1293 .ptr_sub,
1288 .try_ptr,1294 .try_ptr,
...@@ -1495,7 +1501,6 @@ pub fn value(air: Air, inst: Inst.Ref, mod: *Module) !?Value {...@@ -1495,7 +1501,6 @@ pub fn value(air: Air, inst: Inst.Ref, mod: *Module) !?Value {
1495 const inst_index = @intCast(Air.Inst.Index, ref_int - ref_start_index);1501 const inst_index = @intCast(Air.Inst.Index, ref_int - ref_start_index);
1496 const air_datas = air.instructions.items(.data);1502 const air_datas = air.instructions.items(.data);
1497 switch (air.instructions.items(.tag)[inst_index]) {1503 switch (air.instructions.items(.tag)[inst_index]) {
1498 .constant => return air.values[air_datas[inst_index].ty_pl.payload],
1499 .interned => return air_datas[inst_index].interned.toValue(),1504 .interned => return air_datas[inst_index].interned.toValue(),
1500 else => return air.typeOfIndex(inst_index, mod.intern_pool).onePossibleValue(mod),1505 else => return air.typeOfIndex(inst_index, mod.intern_pool).onePossibleValue(mod),
1501 }1506 }
...@@ -1603,6 +1608,8 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: InternPool) bool {...@@ -1603,6 +1608,8 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: InternPool) bool {
1603 .mul_with_overflow,1608 .mul_with_overflow,
1604 .shl_with_overflow,1609 .shl_with_overflow,
1605 .alloc,1610 .alloc,
1611 .inferred_alloc,
1612 .inferred_alloc_comptime,
1606 .ret_ptr,1613 .ret_ptr,
1607 .bit_and,1614 .bit_and,
1608 .bit_or,1615 .bit_or,
...@@ -1651,7 +1658,6 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: InternPool) bool {...@@ -1651,7 +1658,6 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: InternPool) bool {
1651 .cmp_neq_optimized,1658 .cmp_neq_optimized,
1652 .cmp_vector,1659 .cmp_vector,
1653 .cmp_vector_optimized,1660 .cmp_vector_optimized,
1654 .constant,
1655 .interned,1661 .interned,
1656 .is_null,1662 .is_null,
1657 .is_non_null,1663 .is_non_null,
src/InternPool.zig+14-4
...@@ -515,10 +515,12 @@ pub const Key = union(enum) {...@@ -515,10 +515,12 @@ pub const Key = union(enum) {
515515
516 pub const ErrorUnion = struct {516 pub const ErrorUnion = struct {
517 ty: Index,517 ty: Index,
518 val: union(enum) {518 val: Value,
519
520 pub const Value = union(enum) {
519 err_name: NullTerminatedString,521 err_name: NullTerminatedString,
520 payload: Index,522 payload: Index,
521 },523 };
522 };524 };
523525
524 pub const EnumTag = struct {526 pub const EnumTag = struct {
...@@ -1068,7 +1070,7 @@ pub const Key = union(enum) {...@@ -1068,7 +1070,7 @@ pub const Key = union(enum) {
1068 .false, .true => .bool_type,1070 .false, .true => .bool_type,
1069 .empty_struct => .empty_struct_type,1071 .empty_struct => .empty_struct_type,
1070 .@"unreachable" => .noreturn_type,1072 .@"unreachable" => .noreturn_type,
1071 .generic_poison => unreachable,1073 .generic_poison => .generic_poison_type,
1072 },1074 },
1073 };1075 };
1074 }1076 }
...@@ -2671,6 +2673,10 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {...@@ -2671,6 +2673,10 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
2671 .only_possible_value => {2673 .only_possible_value => {
2672 const ty = @intToEnum(Index, data);2674 const ty = @intToEnum(Index, data);
2673 return switch (ip.indexToKey(ty)) {2675 return switch (ip.indexToKey(ty)) {
2676 .array_type, .vector_type => .{ .aggregate = .{
2677 .ty = ty,
2678 .storage = .{ .elems = &.{} },
2679 } },
2674 // TODO: migrate structs to properly use the InternPool rather2680 // TODO: migrate structs to properly use the InternPool rather
2675 // than using the SegmentedList trick, then the struct type will2681 // than using the SegmentedList trick, then the struct type will
2676 // have a slice of comptime values that can be used here for when2682 // have a slice of comptime values that can be used here for when
...@@ -3184,7 +3190,11 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {...@@ -3184,7 +3190,11 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
3184 assert(!(try ip.map.getOrPutAdapted(gpa, key, adapter)).found_existing);3190 assert(!(try ip.map.getOrPutAdapted(gpa, key, adapter)).found_existing);
3185 try ip.items.ensureUnusedCapacity(gpa, 1);3191 try ip.items.ensureUnusedCapacity(gpa, 1);
3186 ip.items.appendAssumeCapacity(.{3192 ip.items.appendAssumeCapacity(.{
3187 .tag = .ptr_elem,3193 .tag = switch (ptr.addr) {
3194 .elem => .ptr_elem,
3195 .field => .ptr_field,
3196 else => unreachable,
3197 },
3188 .data = try ip.addExtra(gpa, PtrBaseIndex{3198 .data = try ip.addExtra(gpa, PtrBaseIndex{
3189 .ty = ptr.ty,3199 .ty = ptr.ty,
3190 .base = base_index.base,3200 .base = base_index.base,
src/Liveness.zig+6-16
...@@ -321,8 +321,9 @@ pub fn categorizeOperand(...@@ -321,8 +321,9 @@ pub fn categorizeOperand(
321321
322 .arg,322 .arg,
323 .alloc,323 .alloc,
324 .inferred_alloc,
325 .inferred_alloc_comptime,
324 .ret_ptr,326 .ret_ptr,
325 .constant,
326 .interned,327 .interned,
327 .trap,328 .trap,
328 .breakpoint,329 .breakpoint,
...@@ -973,9 +974,7 @@ fn analyzeInst(...@@ -973,9 +974,7 @@ fn analyzeInst(
973 .work_group_id,974 .work_group_id,
974 => return analyzeOperands(a, pass, data, inst, .{ .none, .none, .none }),975 => return analyzeOperands(a, pass, data, inst, .{ .none, .none, .none }),
975976
976 .constant,977 .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable,
977 .interned,
978 => unreachable,
979978
980 .trap,979 .trap,
981 .unreach,980 .unreach,
...@@ -1269,10 +1268,7 @@ fn analyzeOperands(...@@ -1269,10 +1268,7 @@ fn analyzeOperands(
1269 const operand = Air.refToIndexAllowNone(op_ref) orelse continue;1268 const operand = Air.refToIndexAllowNone(op_ref) orelse continue;
12701269
1271 // Don't compute any liveness for constants1270 // Don't compute any liveness for constants
1272 switch (inst_tags[operand]) {1271 if (inst_tags[operand] == .interned) continue;
1273 .constant, .interned => continue,
1274 else => {},
1275 }
12761272
1277 _ = try data.live_set.put(gpa, operand, {});1273 _ = try data.live_set.put(gpa, operand, {});
1278 }1274 }
...@@ -1305,10 +1301,7 @@ fn analyzeOperands(...@@ -1305,10 +1301,7 @@ fn analyzeOperands(
1305 const operand = Air.refToIndexAllowNone(op_ref) orelse continue;1301 const operand = Air.refToIndexAllowNone(op_ref) orelse continue;
13061302
1307 // Don't compute any liveness for constants1303 // Don't compute any liveness for constants
1308 switch (inst_tags[operand]) {1304 if (inst_tags[operand] == .interned) continue;
1309 .constant, .interned => continue,
1310 else => {},
1311 }
13121305
1313 const mask = @as(Bpi, 1) << @intCast(OperandInt, i);1306 const mask = @as(Bpi, 1) << @intCast(OperandInt, i);
13141307
...@@ -1839,10 +1832,7 @@ fn AnalyzeBigOperands(comptime pass: LivenessPass) type {...@@ -1839,10 +1832,7 @@ fn AnalyzeBigOperands(comptime pass: LivenessPass) type {
18391832
1840 // Don't compute any liveness for constants1833 // Don't compute any liveness for constants
1841 const inst_tags = big.a.air.instructions.items(.tag);1834 const inst_tags = big.a.air.instructions.items(.tag);
1842 switch (inst_tags[operand]) {1835 if (inst_tags[operand] == .interned) return
1843 .constant, .interned => return,
1844 else => {},
1845 }
18461836
1847 // If our result is unused and the instruction doesn't need to be lowered, backends will1837 // If our result is unused and the instruction doesn't need to be lowered, backends will
1848 // skip the lowering of this instruction, so we don't want to record uses of operands.1838 // skip the lowering of this instruction, so we don't want to record uses of operands.
src/Liveness/Verify.zig+19-21
...@@ -41,8 +41,9 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {...@@ -41,8 +41,9 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
41 // no operands41 // no operands
42 .arg,42 .arg,
43 .alloc,43 .alloc,
44 .inferred_alloc,
45 .inferred_alloc_comptime,
44 .ret_ptr,46 .ret_ptr,
45 .constant,
46 .interned,47 .interned,
47 .breakpoint,48 .breakpoint,
48 .dbg_stmt,49 .dbg_stmt,
...@@ -554,16 +555,18 @@ fn verifyDeath(self: *Verify, inst: Air.Inst.Index, operand: Air.Inst.Index) Err...@@ -554,16 +555,18 @@ fn verifyDeath(self: *Verify, inst: Air.Inst.Index, operand: Air.Inst.Index) Err
554}555}
555556
556fn verifyOperand(self: *Verify, inst: Air.Inst.Index, op_ref: Air.Inst.Ref, dies: bool) Error!void {557fn verifyOperand(self: *Verify, inst: Air.Inst.Index, op_ref: Air.Inst.Ref, dies: bool) Error!void {
557 const operand = Air.refToIndexAllowNone(op_ref) orelse return;558 const operand = Air.refToIndexAllowNone(op_ref) orelse {
558 switch (self.air.instructions.items(.tag)[operand]) {559 assert(!dies);
559 .constant, .interned => {},560 return;
560 else => {561 };
561 if (dies) {562 if (self.air.instructions.items(.tag)[operand] == .interned) {
562 if (!self.live.remove(operand)) return invalid("%{}: dead operand %{} reused and killed again", .{ inst, operand });563 assert(!dies);
563 } else {564 return;
564 if (!self.live.contains(operand)) return invalid("%{}: dead operand %{} reused", .{ inst, operand });565 }
565 }566 if (dies) {
566 },567 if (!self.live.remove(operand)) return invalid("%{}: dead operand %{} reused and killed again", .{ inst, operand });
568 } else {
569 if (!self.live.contains(operand)) return invalid("%{}: dead operand %{} reused", .{ inst, operand });
567 }570 }
568}571}
569572
...@@ -576,16 +579,11 @@ fn verifyInst(...@@ -576,16 +579,11 @@ fn verifyInst(
576 const dies = self.liveness.operandDies(inst, @intCast(Liveness.OperandInt, operand_index));579 const dies = self.liveness.operandDies(inst, @intCast(Liveness.OperandInt, operand_index));
577 try self.verifyOperand(inst, operand, dies);580 try self.verifyOperand(inst, operand, dies);
578 }581 }
579 const tag = self.air.instructions.items(.tag);582 if (self.air.instructions.items(.tag)[inst] == .interned) return;
580 switch (tag[inst]) {583 if (self.liveness.isUnused(inst)) {
581 .constant, .interned => unreachable,584 assert(!self.live.contains(inst));
582 else => {585 } else {
583 if (self.liveness.isUnused(inst)) {586 try self.live.putNoClobber(self.gpa, inst, {});
584 assert(!self.live.contains(inst));
585 } else {
586 try self.live.putNoClobber(self.gpa, inst, {});
587 }
588 },
589 }587 }
590}588}
591589
src/Module.zig+1-8
...@@ -764,14 +764,7 @@ pub const Decl = struct {...@@ -764,14 +764,7 @@ pub const Decl = struct {
764764
765 pub fn typedValue(decl: Decl) error{AnalysisFail}!TypedValue {765 pub fn typedValue(decl: Decl) error{AnalysisFail}!TypedValue {
766 if (!decl.has_tv) return error.AnalysisFail;766 if (!decl.has_tv) return error.AnalysisFail;
767 return TypedValue{767 return TypedValue{ .ty = decl.ty, .val = decl.val };
768 .ty = decl.ty,
769 .val = decl.val,
770 };
771 }
772
773 pub fn value(decl: *Decl) error{AnalysisFail}!Value {
774 return (try decl.typedValue()).val;
775 }768 }
776769
777 pub fn isFunction(decl: Decl, mod: *const Module) !bool {770 pub fn isFunction(decl: Decl, mod: *const Module) !bool {
src/Sema.zig+585-660
...@@ -1991,23 +1991,21 @@ fn resolveMaybeUndefValAllowVariablesMaybeRuntime(...@@ -1991,23 +1991,21 @@ fn resolveMaybeUndefValAllowVariablesMaybeRuntime(
1991 const i = int - InternPool.static_len;1991 const i = int - InternPool.static_len;
1992 const air_tags = sema.air_instructions.items(.tag);1992 const air_tags = sema.air_instructions.items(.tag);
1993 if (try sema.typeHasOnePossibleValue(sema.typeOf(inst))) |opv| {1993 if (try sema.typeHasOnePossibleValue(sema.typeOf(inst))) |opv| {
1994 if (air_tags[i] == .constant) {1994 if (air_tags[i] == .interned) {
1995 const ty_pl = sema.air_instructions.items(.data)[i].ty_pl;1995 const interned = sema.air_instructions.items(.data)[i].interned;
1996 const val = sema.air_values.items[ty_pl.payload];1996 const val = interned.toValue();
1997 if (val.getVariable(sema.mod) != null) return val;1997 if (val.getVariable(sema.mod) != null) return val;
1998 }1998 }
1999 return opv;1999 return opv;
2000 }2000 }
2001 const air_datas = sema.air_instructions.items(.data);2001 const air_datas = sema.air_instructions.items(.data);
2002 switch (air_tags[i]) {2002 switch (air_tags[i]) {
2003 .constant => {2003 .interned => {
2004 const ty_pl = air_datas[i].ty_pl;2004 const val = air_datas[i].interned.toValue();
2005 const val = sema.air_values.items[ty_pl.payload];
2006 if (val.isRuntimeValue(sema.mod)) make_runtime.* = true;2005 if (val.isRuntimeValue(sema.mod)) make_runtime.* = true;
2007 if (val.isPtrToThreadLocal(sema.mod)) make_runtime.* = true;2006 if (val.isPtrToThreadLocal(sema.mod)) make_runtime.* = true;
2008 return val;2007 return val;
2009 },2008 },
2010 .interned => return air_datas[i].interned.toValue(),
2011 else => return null,2009 else => return null,
2012 }2010 }
2013}2011}
...@@ -2440,64 +2438,64 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE...@@ -2440,64 +2438,64 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
2440 const addr_space = target_util.defaultAddressSpace(target, .local);2438 const addr_space = target_util.defaultAddressSpace(target, .local);
24412439
2442 if (Air.refToIndex(ptr)) |ptr_inst| {2440 if (Air.refToIndex(ptr)) |ptr_inst| {
2443 if (sema.air_instructions.items(.tag)[ptr_inst] == .constant) {2441 switch (sema.air_instructions.items(.tag)[ptr_inst]) {
2444 const air_datas = sema.air_instructions.items(.data);2442 .inferred_alloc => {
2445 const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload];2443 const air_datas = sema.air_instructions.items(.data);
2446 switch (ptr_val.tag()) {2444 const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload];
2447 .inferred_alloc => {2445 const inferred_alloc = &ptr_val.castTag(.inferred_alloc).?.data;
2448 const inferred_alloc = &ptr_val.castTag(.inferred_alloc).?.data;2446 // Add the stored instruction to the set we will use to resolve peer types
2449 // Add the stored instruction to the set we will use to resolve peer types2447 // for the inferred allocation.
2450 // for the inferred allocation.2448 // This instruction will not make it to codegen; it is only to participate
2451 // This instruction will not make it to codegen; it is only to participate2449 // in the `stored_inst_list` of the `inferred_alloc`.
2452 // in the `stored_inst_list` of the `inferred_alloc`.2450 var trash_block = block.makeSubBlock();
2453 var trash_block = block.makeSubBlock();2451 defer trash_block.instructions.deinit(sema.gpa);
2454 defer trash_block.instructions.deinit(sema.gpa);2452 const operand = try trash_block.addBitCast(pointee_ty, .void_value);
2455 const operand = try trash_block.addBitCast(pointee_ty, .void_value);2453
24562454 const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
2457 const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{2455 .pointee_type = pointee_ty,
2458 .pointee_type = pointee_ty,2456 .@"align" = inferred_alloc.alignment,
2459 .@"align" = inferred_alloc.alignment,2457 .@"addrspace" = addr_space,
2460 .@"addrspace" = addr_space,2458 });
2461 });2459 const bitcasted_ptr = try block.addBitCast(ptr_ty, ptr);
2462 const bitcasted_ptr = try block.addBitCast(ptr_ty, ptr);
24632460
2464 try inferred_alloc.prongs.append(sema.arena, .{2461 try inferred_alloc.prongs.append(sema.arena, .{
2465 .stored_inst = operand,2462 .stored_inst = operand,
2466 .placeholder = Air.refToIndex(bitcasted_ptr).?,2463 .placeholder = Air.refToIndex(bitcasted_ptr).?,
2467 });2464 });
24682465
2469 return bitcasted_ptr;2466 return bitcasted_ptr;
2470 },2467 },
2471 .inferred_alloc_comptime => {2468 .inferred_alloc_comptime => {
2472 const iac = ptr_val.castTag(.inferred_alloc_comptime).?;2469 const air_datas = sema.air_instructions.items(.data);
2473 // There will be only one coerce_result_ptr because we are running at comptime.2470 const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload];
2474 // The alloc will turn into a Decl.2471 const iac = ptr_val.castTag(.inferred_alloc_comptime).?;
2475 var anon_decl = try block.startAnonDecl();2472 // There will be only one coerce_result_ptr because we are running at comptime.
2476 defer anon_decl.deinit();2473 // The alloc will turn into a Decl.
2477 iac.data.decl_index = try anon_decl.finish(2474 var anon_decl = try block.startAnonDecl();
2478 pointee_ty,2475 defer anon_decl.deinit();
2479 Value.undef,2476 iac.data.decl_index = try anon_decl.finish(
2480 iac.data.alignment,2477 pointee_ty,
2481 );2478 Value.undef,
2482 if (iac.data.alignment != 0) {2479 iac.data.alignment,
2483 try sema.resolveTypeLayout(pointee_ty);2480 );
2484 }2481 if (iac.data.alignment != 0) {
2485 const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{2482 try sema.resolveTypeLayout(pointee_ty);
2486 .pointee_type = pointee_ty,2483 }
2487 .@"align" = iac.data.alignment,2484 const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
2488 .@"addrspace" = addr_space,2485 .pointee_type = pointee_ty,
2489 });2486 .@"align" = iac.data.alignment,
2490 try sema.maybeQueueFuncBodyAnalysis(iac.data.decl_index);2487 .@"addrspace" = addr_space,
2491 return sema.addConstant(ptr_ty, (try sema.mod.intern(.{ .ptr = .{2488 });
2492 .ty = ptr_ty.toIntern(),2489 try sema.maybeQueueFuncBodyAnalysis(iac.data.decl_index);
2493 .addr = .{ .mut_decl = .{2490 return sema.addConstant(ptr_ty, (try sema.mod.intern(.{ .ptr = .{
2494 .decl = iac.data.decl_index,2491 .ty = ptr_ty.toIntern(),
2495 .runtime_index = block.runtime_index,2492 .addr = .{ .mut_decl = .{
2496 } },2493 .decl = iac.data.decl_index,
2497 } })).toValue());2494 .runtime_index = block.runtime_index,
2498 },2495 } },
2499 else => {},2496 } })).toValue());
2500 }2497 },
2498 else => {},
2501 }2499 }
2502 }2500 }
25032501
...@@ -3458,6 +3456,7 @@ fn zirAllocExtended(...@@ -3458,6 +3456,7 @@ fn zirAllocExtended(
3458 block: *Block,3456 block: *Block,
3459 extended: Zir.Inst.Extended.InstData,3457 extended: Zir.Inst.Extended.InstData,
3460) CompileError!Air.Inst.Ref {3458) CompileError!Air.Inst.Ref {
3459 const gpa = sema.gpa;
3461 const extra = sema.code.extraData(Zir.Inst.AllocExtended, extended.operand);3460 const extra = sema.code.extraData(Zir.Inst.AllocExtended, extended.operand);
3462 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = extra.data.src_node };3461 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = extra.data.src_node };
3463 const align_src: LazySrcLoc = .{ .node_offset_var_decl_align = extra.data.src_node };3462 const align_src: LazySrcLoc = .{ .node_offset_var_decl_align = extra.data.src_node };
...@@ -3487,13 +3486,19 @@ fn zirAllocExtended(...@@ -3487,13 +3486,19 @@ fn zirAllocExtended(
3487 if (small.has_type) {3486 if (small.has_type) {
3488 return sema.analyzeComptimeAlloc(block, var_ty, alignment);3487 return sema.analyzeComptimeAlloc(block, var_ty, alignment);
3489 } else {3488 } else {
3490 return sema.addConstant(3489 const ty_inst = try sema.addType(inferred_alloc_ty);
3491 inferred_alloc_ty,3490 try sema.air_values.append(gpa, try Value.Tag.inferred_alloc_comptime.create(sema.arena, .{
3492 try Value.Tag.inferred_alloc_comptime.create(sema.arena, .{3491 .decl_index = undefined,
3493 .decl_index = undefined,3492 .alignment = alignment,
3494 .alignment = alignment,3493 }));
3495 }),3494 try sema.air_instructions.append(gpa, .{
3496 );3495 .tag = .inferred_alloc_comptime,
3496 .data = .{ .ty_pl = .{
3497 .ty = ty_inst,
3498 .payload = @intCast(u32, sema.air_values.items.len - 1),
3499 } },
3500 });
3501 return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1));
3497 }3502 }
3498 }3503 }
34993504
...@@ -3511,17 +3516,19 @@ fn zirAllocExtended(...@@ -3511,17 +3516,19 @@ fn zirAllocExtended(
3511 return block.addTy(.alloc, ptr_type);3516 return block.addTy(.alloc, ptr_type);
3512 }3517 }
35133518
3514 // `Sema.addConstant` does not add the instruction to the block because it is3519 const ty_inst = try sema.addType(inferred_alloc_ty);
3515 // not needed in the case of constant values. However here, we plan to "downgrade"3520 try sema.air_values.append(gpa, try Value.Tag.inferred_alloc.create(sema.arena, .{
3516 // to a normal instruction when we hit `resolve_inferred_alloc`. So we append3521 .alignment = alignment,
3517 // to the block even though it is currently a `.constant`.3522 }));
3518 const result = try sema.addConstant(3523 const result_index = try block.addInstAsIndex(.{
3519 inferred_alloc_ty,3524 .tag = .inferred_alloc,
3520 try Value.Tag.inferred_alloc.create(sema.arena, .{ .alignment = alignment }),3525 .data = .{ .ty_pl = .{
3521 );3526 .ty = ty_inst,
3522 try block.instructions.append(sema.gpa, Air.refToIndex(result).?);3527 .payload = @intCast(u32, sema.air_values.items.len - 1),
3523 try sema.unresolved_inferred_allocs.putNoClobber(sema.gpa, Air.refToIndex(result).?, {});3528 } },
3524 return result;3529 });
3530 try sema.unresolved_inferred_allocs.putNoClobber(gpa, result_index, {});
3531 return Air.indexToRef(result_index);
3525}3532}
35263533
3527fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {3534fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -3616,16 +3623,24 @@ fn zirAllocInferredComptime(...@@ -3616,16 +3623,24 @@ fn zirAllocInferredComptime(
3616 inst: Zir.Inst.Index,3623 inst: Zir.Inst.Index,
3617 inferred_alloc_ty: Type,3624 inferred_alloc_ty: Type,
3618) CompileError!Air.Inst.Ref {3625) CompileError!Air.Inst.Ref {
3626 const gpa = sema.gpa;
3619 const src_node = sema.code.instructions.items(.data)[inst].node;3627 const src_node = sema.code.instructions.items(.data)[inst].node;
3620 const src = LazySrcLoc.nodeOffset(src_node);3628 const src = LazySrcLoc.nodeOffset(src_node);
3621 sema.src = src;3629 sema.src = src;
3622 return sema.addConstant(3630
3623 inferred_alloc_ty,3631 const ty_inst = try sema.addType(inferred_alloc_ty);
3624 try Value.Tag.inferred_alloc_comptime.create(sema.arena, .{3632 try sema.air_values.append(gpa, try Value.Tag.inferred_alloc_comptime.create(sema.arena, .{
3625 .decl_index = undefined,3633 .decl_index = undefined,
3626 .alignment = 0,3634 .alignment = 0,
3627 }),3635 }));
3628 );3636 try sema.air_instructions.append(gpa, .{
3637 .tag = .inferred_alloc_comptime,
3638 .data = .{ .ty_pl = .{
3639 .ty = ty_inst,
3640 .payload = @intCast(u32, sema.air_values.items.len - 1),
3641 } },
3642 });
3643 return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1));
3629}3644}
36303645
3631fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {3646fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -3676,31 +3691,39 @@ fn zirAllocInferred(...@@ -3676,31 +3691,39 @@ fn zirAllocInferred(
3676 const tracy = trace(@src());3691 const tracy = trace(@src());
3677 defer tracy.end();3692 defer tracy.end();
36783693
3694 const gpa = sema.gpa;
3679 const src_node = sema.code.instructions.items(.data)[inst].node;3695 const src_node = sema.code.instructions.items(.data)[inst].node;
3680 const src = LazySrcLoc.nodeOffset(src_node);3696 const src = LazySrcLoc.nodeOffset(src_node);
3681 sema.src = src;3697 sema.src = src;
36823698
3699 const ty_inst = try sema.addType(inferred_alloc_ty);
3683 if (block.is_comptime) {3700 if (block.is_comptime) {
3684 return sema.addConstant(3701 try sema.air_values.append(gpa, try Value.Tag.inferred_alloc_comptime.create(sema.arena, .{
3685 inferred_alloc_ty,3702 .decl_index = undefined,
3686 try Value.Tag.inferred_alloc_comptime.create(sema.arena, .{3703 .alignment = 0,
3687 .decl_index = undefined,3704 }));
3688 .alignment = 0,3705 try sema.air_instructions.append(gpa, .{
3689 }),3706 .tag = .inferred_alloc_comptime,
3690 );3707 .data = .{ .ty_pl = .{
3708 .ty = ty_inst,
3709 .payload = @intCast(u32, sema.air_values.items.len - 1),
3710 } },
3711 });
3712 return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1));
3691 }3713 }
36923714
3693 // `Sema.addConstant` does not add the instruction to the block because it is3715 try sema.air_values.append(gpa, try Value.Tag.inferred_alloc.create(sema.arena, .{
3694 // not needed in the case of constant values. However here, we plan to "downgrade"3716 .alignment = 0,
3695 // to a normal instruction when we hit `resolve_inferred_alloc`. So we append3717 }));
3696 // to the block even though it is currently a `.constant`.3718 const result_index = try block.addInstAsIndex(.{
3697 const result = try sema.addConstant(3719 .tag = .inferred_alloc,
3698 inferred_alloc_ty,3720 .data = .{ .ty_pl = .{
3699 try Value.Tag.inferred_alloc.create(sema.arena, .{ .alignment = 0 }),3721 .ty = ty_inst,
3700 );3722 .payload = @intCast(u32, sema.air_values.items.len - 1),
3701 try block.instructions.append(sema.gpa, Air.refToIndex(result).?);3723 } },
3702 try sema.unresolved_inferred_allocs.putNoClobber(sema.gpa, Air.refToIndex(result).?, {});3724 });
3703 return result;3725 try sema.unresolved_inferred_allocs.putNoClobber(gpa, result_index, {});
3726 return Air.indexToRef(result_index);
3704}3727}
37053728
3706fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {3729fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
...@@ -3712,7 +3735,6 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -3712,7 +3735,6 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
3712 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };3735 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
3713 const ptr = try sema.resolveInst(inst_data.operand);3736 const ptr = try sema.resolveInst(inst_data.operand);
3714 const ptr_inst = Air.refToIndex(ptr).?;3737 const ptr_inst = Air.refToIndex(ptr).?;
3715 assert(sema.air_instructions.items(.tag)[ptr_inst] == .constant);
3716 const value_index = sema.air_instructions.items(.data)[ptr_inst].ty_pl.payload;3738 const value_index = sema.air_instructions.items(.data)[ptr_inst].ty_pl.payload;
3717 const ptr_val = sema.air_values.items[value_index];3739 const ptr_val = sema.air_values.items[value_index];
3718 const var_is_mut = switch (sema.typeOf(ptr).toIntern()) {3740 const var_is_mut = switch (sema.typeOf(ptr).toIntern()) {
...@@ -3722,7 +3744,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -3722,7 +3744,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
3722 };3744 };
3723 const target = sema.mod.getTarget();3745 const target = sema.mod.getTarget();
37243746
3725 switch (ptr_val.tag()) {3747 switch (sema.air_instructions.items(.tag)[ptr_inst]) {
3726 .inferred_alloc_comptime => {3748 .inferred_alloc_comptime => {
3727 const iac = ptr_val.castTag(.inferred_alloc_comptime).?;3749 const iac = ptr_val.castTag(.inferred_alloc_comptime).?;
3728 const decl_index = iac.data.decl_index;3750 const decl_index = iac.data.decl_index;
...@@ -3767,7 +3789,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -3767,7 +3789,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
3767 // Detect if the value is comptime-known. In such case, the3789 // Detect if the value is comptime-known. In such case, the
3768 // last 3 AIR instructions of the block will look like this:3790 // last 3 AIR instructions of the block will look like this:
3769 //3791 //
3770 // %a = constant3792 // %a = interned
3771 // %b = bitcast(%a)3793 // %b = bitcast(%a)
3772 // %c = store(%b, %d)3794 // %c = store(%b, %d)
3773 //3795 //
...@@ -3814,7 +3836,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -3814,7 +3836,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
3814 const candidate = block.instructions.items[search_index];3836 const candidate = block.instructions.items[search_index];
3815 switch (air_tags[candidate]) {3837 switch (air_tags[candidate]) {
3816 .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue,3838 .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue,
3817 .constant => break candidate,3839 .interned => break candidate,
3818 else => break :ct,3840 else => break :ct,
3819 }3841 }
3820 };3842 };
...@@ -4981,15 +5003,15 @@ fn zirStoreToBlockPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE...@@ -4981,15 +5003,15 @@ fn zirStoreToBlockPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
4981 const src: LazySrcLoc = sema.src;5003 const src: LazySrcLoc = sema.src;
4982 blk: {5004 blk: {
4983 const ptr_inst = Air.refToIndex(ptr) orelse break :blk;5005 const ptr_inst = Air.refToIndex(ptr) orelse break :blk;
4984 if (sema.air_instructions.items(.tag)[ptr_inst] != .constant) break :blk;5006 const air_data = sema.air_instructions.items(.data)[ptr_inst];
4985 const air_datas = sema.air_instructions.items(.data);5007 switch (sema.air_instructions.items(.tag)[ptr_inst]) {
4986 const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload];
4987 switch (ptr_val.tag()) {
4988 .inferred_alloc_comptime => {5008 .inferred_alloc_comptime => {
5009 const ptr_val = sema.air_values.items[air_data.ty_pl.payload];
4989 const iac = ptr_val.castTag(.inferred_alloc_comptime).?;5010 const iac = ptr_val.castTag(.inferred_alloc_comptime).?;
4990 return sema.storeToInferredAllocComptime(block, src, operand, iac);5011 return sema.storeToInferredAllocComptime(block, src, operand, iac);
4991 },5012 },
4992 .inferred_alloc => {5013 .inferred_alloc => {
5014 const ptr_val = sema.air_values.items[air_data.ty_pl.payload];
4993 const inferred_alloc = ptr_val.castTag(.inferred_alloc).?;5015 const inferred_alloc = ptr_val.castTag(.inferred_alloc).?;
4994 return sema.storeToInferredAlloc(block, ptr, operand, inferred_alloc);5016 return sema.storeToInferredAlloc(block, ptr, operand, inferred_alloc);
4995 },5017 },
...@@ -5009,11 +5031,10 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi...@@ -5009,11 +5031,10 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi
5009 const ptr = try sema.resolveInst(bin_inst.lhs);5031 const ptr = try sema.resolveInst(bin_inst.lhs);
5010 const operand = try sema.resolveInst(bin_inst.rhs);5032 const operand = try sema.resolveInst(bin_inst.rhs);
5011 const ptr_inst = Air.refToIndex(ptr).?;5033 const ptr_inst = Air.refToIndex(ptr).?;
5012 assert(sema.air_instructions.items(.tag)[ptr_inst] == .constant);
5013 const air_datas = sema.air_instructions.items(.data);5034 const air_datas = sema.air_instructions.items(.data);
5014 const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload];5035 const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload];
50155036
5016 switch (ptr_val.tag()) {5037 switch (sema.air_instructions.items(.tag)[ptr_inst]) {
5017 .inferred_alloc_comptime => {5038 .inferred_alloc_comptime => {
5018 const iac = ptr_val.castTag(.inferred_alloc_comptime).?;5039 const iac = ptr_val.castTag(.inferred_alloc_comptime).?;
5019 return sema.storeToInferredAllocComptime(block, src, operand, iac);5040 return sema.storeToInferredAllocComptime(block, src, operand, iac);
...@@ -6988,16 +7009,7 @@ fn analyzeCall(...@@ -6988,16 +7009,7 @@ fn analyzeCall(
6988 const res2: Air.Inst.Ref = res2: {7009 const res2: Air.Inst.Ref = res2: {
6989 if (should_memoize and is_comptime_call) {7010 if (should_memoize and is_comptime_call) {
6990 if (mod.memoized_calls.getContext(memoized_call_key, .{ .module = mod })) |result| {7011 if (mod.memoized_calls.getContext(memoized_call_key, .{ .module = mod })) |result| {
6991 const ty_inst = try sema.addType(fn_ret_ty);7012 break :res2 try sema.addConstant(fn_ret_ty, result.val);
6992 try sema.air_values.append(gpa, result.val);
6993 sema.air_instructions.set(block_inst, .{
6994 .tag = .constant,
6995 .data = .{ .ty_pl = .{
6996 .ty = ty_inst,
6997 .payload = @intCast(u32, sema.air_values.items.len - 1),
6998 } },
6999 });
7000 break :res2 Air.indexToRef(block_inst);
7001 }7013 }
7002 }7014 }
70037015
...@@ -9407,7 +9419,7 @@ fn zirParam(...@@ -9407,7 +9419,7 @@ fn zirParam(
9407 if (is_comptime) {9419 if (is_comptime) {
9408 // If this is a comptime parameter we can add a constant generic_poison9420 // If this is a comptime parameter we can add a constant generic_poison
9409 // since this is also a generic parameter.9421 // since this is also a generic parameter.
9410 const result = try sema.addConstant(param_ty, Value.generic_poison);9422 const result = try sema.addConstant(Type.generic_poison, Value.generic_poison);
9411 sema.inst_map.putAssumeCapacityNoClobber(inst, result);9423 sema.inst_map.putAssumeCapacityNoClobber(inst, result);
9412 } else {9424 } else {
9413 // Otherwise we need a dummy runtime instruction.9425 // Otherwise we need a dummy runtime instruction.
...@@ -15104,7 +15116,7 @@ fn analyzePtrArithmetic(...@@ -15104,7 +15116,7 @@ fn analyzePtrArithmetic(
15104 if (air_tag == .ptr_sub) {15116 if (air_tag == .ptr_sub) {
15105 return sema.fail(block, op_src, "TODO implement Sema comptime pointer subtraction", .{});15117 return sema.fail(block, op_src, "TODO implement Sema comptime pointer subtraction", .{});
15106 }15118 }
15107 const new_ptr_val = try ptr_val.elemPtr(ptr_ty, offset_int, sema.mod);15119 const new_ptr_val = try ptr_val.elemPtr(new_ptr_ty, offset_int, sema.mod);
15108 return sema.addConstant(new_ptr_ty, new_ptr_val);15120 return sema.addConstant(new_ptr_ty, new_ptr_val);
15109 } else break :rs offset_src;15121 } else break :rs offset_src;
15110 } else break :rs ptr_src;15122 } else break :rs ptr_src;
...@@ -25378,8 +25390,8 @@ fn elemPtrOneLayerOnly(...@@ -25378,8 +25390,8 @@ fn elemPtrOneLayerOnly(
25378 const ptr_val = maybe_ptr_val orelse break :rs indexable_src;25390 const ptr_val = maybe_ptr_val orelse break :rs indexable_src;
25379 const index_val = maybe_index_val orelse break :rs elem_index_src;25391 const index_val = maybe_index_val orelse break :rs elem_index_src;
25380 const index = @intCast(usize, index_val.toUnsignedInt(mod));25392 const index = @intCast(usize, index_val.toUnsignedInt(mod));
25381 const elem_ptr = try ptr_val.elemPtr(indexable_ty, index, mod);
25382 const result_ty = try sema.elemPtrType(indexable_ty, index);25393 const result_ty = try sema.elemPtrType(indexable_ty, index);
25394 const elem_ptr = try ptr_val.elemPtr(result_ty, index, mod);
25383 return sema.addConstant(result_ty, elem_ptr);25395 return sema.addConstant(result_ty, elem_ptr);
25384 };25396 };
25385 const result_ty = try sema.elemPtrType(indexable_ty, null);25397 const result_ty = try sema.elemPtrType(indexable_ty, null);
...@@ -25424,8 +25436,9 @@ fn elemVal(...@@ -25424,8 +25436,9 @@ fn elemVal(
25424 const indexable_val = maybe_indexable_val orelse break :rs indexable_src;25436 const indexable_val = maybe_indexable_val orelse break :rs indexable_src;
25425 const index_val = maybe_index_val orelse break :rs elem_index_src;25437 const index_val = maybe_index_val orelse break :rs elem_index_src;
25426 const index = @intCast(usize, index_val.toUnsignedInt(mod));25438 const index = @intCast(usize, index_val.toUnsignedInt(mod));
25427 const elem_ptr_val = try indexable_val.elemPtr(indexable_ty, index, mod);25439 const elem_ptr_ty = try sema.elemPtrType(indexable_ty, index);
25428 if (try sema.pointerDeref(block, indexable_src, elem_ptr_val, indexable_ty)) |elem_val| {25440 const elem_ptr_val = try indexable_val.elemPtr(elem_ptr_ty, index, mod);
25441 if (try sema.pointerDeref(block, indexable_src, elem_ptr_val, elem_ptr_ty)) |elem_val| {
25429 return sema.addConstant(indexable_ty.elemType2(mod), elem_val);25442 return sema.addConstant(indexable_ty.elemType2(mod), elem_val);
25430 }25443 }
25431 break :rs indexable_src;25444 break :rs indexable_src;
...@@ -25684,7 +25697,7 @@ fn elemPtrArray(...@@ -25684,7 +25697,7 @@ fn elemPtrArray(
25684 return sema.addConstUndef(elem_ptr_ty);25697 return sema.addConstUndef(elem_ptr_ty);
25685 }25698 }
25686 if (offset) |index| {25699 if (offset) |index| {
25687 const elem_ptr = try array_ptr_val.elemPtr(array_ptr_ty, index, mod);25700 const elem_ptr = try array_ptr_val.elemPtr(elem_ptr_ty, index, mod);
25688 return sema.addConstant(elem_ptr_ty, elem_ptr);25701 return sema.addConstant(elem_ptr_ty, elem_ptr);
25689 }25702 }
25690 }25703 }
...@@ -25740,8 +25753,9 @@ fn elemValSlice(...@@ -25740,8 +25753,9 @@ fn elemValSlice(
25740 const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else "";25753 const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else "";
25741 return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label });25754 return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label });
25742 }25755 }
25743 const elem_ptr_val = try slice_val.elemPtr(slice_ty, index, mod);25756 const elem_ptr_ty = try sema.elemPtrType(slice_ty, index);
25744 if (try sema.pointerDeref(block, slice_src, elem_ptr_val, slice_ty)) |elem_val| {25757 const elem_ptr_val = try slice_val.elemPtr(elem_ptr_ty, index, mod);
25758 if (try sema.pointerDeref(block, slice_src, elem_ptr_val, elem_ptr_ty)) |elem_val| {
25745 return sema.addConstant(elem_ty, elem_val);25759 return sema.addConstant(elem_ty, elem_val);
25746 }25760 }
25747 runtime_src = slice_src;25761 runtime_src = slice_src;
...@@ -25800,7 +25814,7 @@ fn elemPtrSlice(...@@ -25800,7 +25814,7 @@ fn elemPtrSlice(
25800 const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else "";25814 const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else "";
25801 return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label });25815 return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label });
25802 }25816 }
25803 const elem_ptr_val = try slice_val.elemPtr(slice_ty, index, mod);25817 const elem_ptr_val = try slice_val.elemPtr(elem_ptr_ty, index, mod);
25804 return sema.addConstant(elem_ptr_ty, elem_ptr_val);25818 return sema.addConstant(elem_ptr_ty, elem_ptr_val);
25805 }25819 }
25806 }25820 }
...@@ -25916,7 +25930,10 @@ fn coerceExtra(...@@ -25916,7 +25930,10 @@ fn coerceExtra(
2591625930
25917 // null to ?T25931 // null to ?T
25918 if (inst_ty.zigTypeTag(mod) == .Null) {25932 if (inst_ty.zigTypeTag(mod) == .Null) {
25919 return sema.addConstant(dest_ty, Value.null);25933 return sema.addConstant(dest_ty, (try mod.intern(.{ .opt = .{
25934 .ty = dest_ty.toIntern(),
25935 .val = .none,
25936 } })).toValue());
25920 }25937 }
2592125938
25922 // cast from ?*T and ?[*]T to ?*anyopaque25939 // cast from ?*T and ?[*]T to ?*anyopaque
...@@ -27665,43 +27682,40 @@ fn storePtrVal(...@@ -27665,43 +27682,40 @@ fn storePtrVal(
27665 switch (mut_kit.pointee) {27682 switch (mut_kit.pointee) {
27666 .direct => |val_ptr| {27683 .direct => |val_ptr| {
27667 if (mut_kit.mut_decl.runtime_index == .comptime_field_ptr) {27684 if (mut_kit.mut_decl.runtime_index == .comptime_field_ptr) {
27668 if (!operand_val.eql(val_ptr.*, operand_ty, sema.mod)) {27685 if (!operand_val.eql(val_ptr.*, operand_ty, mod)) {
27669 // TODO use failWithInvalidComptimeFieldStore27686 // TODO use failWithInvalidComptimeFieldStore
27670 return sema.fail(block, src, "value stored in comptime field does not match the default value of the field", .{});27687 return sema.fail(block, src, "value stored in comptime field does not match the default value of the field", .{});
27671 }27688 }
27672 return;27689 return;
27673 }27690 }
27674 const arena = mut_kit.beginArena(sema.mod);27691 val_ptr.* = (try operand_val.intern(operand_ty, mod)).toValue();
27675 defer mut_kit.finishArena(sema.mod);
27676
27677 val_ptr.* = try operand_val.copy(arena);
27678 },27692 },
27679 .reinterpret => |reinterpret| {27693 .reinterpret => |reinterpret| {
27680 const abi_size = try sema.usizeCast(block, src, mut_kit.ty.abiSize(mod));27694 const abi_size = try sema.usizeCast(block, src, mut_kit.ty.abiSize(mod));
27681 const buffer = try sema.gpa.alloc(u8, abi_size);27695 const buffer = try sema.gpa.alloc(u8, abi_size);
27682 defer sema.gpa.free(buffer);27696 defer sema.gpa.free(buffer);
27683 reinterpret.val_ptr.*.writeToMemory(mut_kit.ty, sema.mod, buffer) catch |err| switch (err) {27697 reinterpret.val_ptr.*.writeToMemory(mut_kit.ty, mod, buffer) catch |err| switch (err) {
27684 error.OutOfMemory => return error.OutOfMemory,27698 error.OutOfMemory => return error.OutOfMemory,
27685 error.ReinterpretDeclRef => unreachable,27699 error.ReinterpretDeclRef => unreachable,
27686 error.IllDefinedMemoryLayout => unreachable, // Sema was supposed to emit a compile error already27700 error.IllDefinedMemoryLayout => unreachable, // Sema was supposed to emit a compile error already
27687 error.Unimplemented => return sema.fail(block, src, "TODO: implement writeToMemory for type '{}'", .{mut_kit.ty.fmt(sema.mod)}),27701 error.Unimplemented => return sema.fail(block, src, "TODO: implement writeToMemory for type '{}'", .{mut_kit.ty.fmt(mod)}),
27688 };27702 };
27689 operand_val.writeToMemory(operand_ty, sema.mod, buffer[reinterpret.byte_offset..]) catch |err| switch (err) {27703 operand_val.writeToMemory(operand_ty, mod, buffer[reinterpret.byte_offset..]) catch |err| switch (err) {
27690 error.OutOfMemory => return error.OutOfMemory,27704 error.OutOfMemory => return error.OutOfMemory,
27691 error.ReinterpretDeclRef => unreachable,27705 error.ReinterpretDeclRef => unreachable,
27692 error.IllDefinedMemoryLayout => unreachable, // Sema was supposed to emit a compile error already27706 error.IllDefinedMemoryLayout => unreachable, // Sema was supposed to emit a compile error already
27693 error.Unimplemented => return sema.fail(block, src, "TODO: implement writeToMemory for type '{}'", .{mut_kit.ty.fmt(sema.mod)}),27707 error.Unimplemented => return sema.fail(block, src, "TODO: implement writeToMemory for type '{}'", .{mut_kit.ty.fmt(mod)}),
27694 };27708 };
2769527709
27696 const arena = mut_kit.beginArena(sema.mod);27710 const arena = mut_kit.beginArena(mod);
27697 defer mut_kit.finishArena(sema.mod);27711 defer mut_kit.finishArena(mod);
2769827712
27699 reinterpret.val_ptr.* = try Value.readFromMemory(mut_kit.ty, sema.mod, buffer, arena);27713 reinterpret.val_ptr.* = (try (try Value.readFromMemory(mut_kit.ty, mod, buffer, arena)).intern(mut_kit.ty, mod)).toValue();
27700 },27714 },
27701 .bad_decl_ty, .bad_ptr_ty => {27715 .bad_decl_ty, .bad_ptr_ty => {
27702 // TODO show the decl declaration site in a note and explain whether the decl27716 // TODO show the decl declaration site in a note and explain whether the decl
27703 // or the pointer is the problematic type27717 // or the pointer is the problematic type
27704 return sema.fail(block, src, "comptime mutation of a reinterpreted pointer requires type '{}' to have a well-defined memory layout", .{mut_kit.ty.fmt(sema.mod)});27718 return sema.fail(block, src, "comptime mutation of a reinterpreted pointer requires type '{}' to have a well-defined memory layout", .{mut_kit.ty.fmt(mod)});
27705 },27719 },
27706 }27720 }
27707}27721}
...@@ -27754,7 +27768,7 @@ fn beginComptimePtrMutation(...@@ -27754,7 +27768,7 @@ fn beginComptimePtrMutation(
27754 const mod = sema.mod;27768 const mod = sema.mod;
27755 const ptr = mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr;27769 const ptr = mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr;
27756 switch (ptr.addr) {27770 switch (ptr.addr) {
27757 .decl => unreachable, // isComptimeMutablePtr has been checked already27771 .decl, .int => unreachable, // isComptimeMutablePtr has been checked already
27758 .mut_decl => |mut_decl| {27772 .mut_decl => |mut_decl| {
27759 const decl = mod.declPtr(mut_decl.decl);27773 const decl = mod.declPtr(mut_decl.decl);
27760 return sema.beginComptimePtrMutationInner(block, src, decl.ty, &decl.val, ptr_elem_ty, mut_decl);27774 return sema.beginComptimePtrMutationInner(block, src, decl.ty, &decl.val, ptr_elem_ty, mut_decl);
...@@ -27767,546 +27781,472 @@ fn beginComptimePtrMutation(...@@ -27767,546 +27781,472 @@ fn beginComptimePtrMutation(
27767 .runtime_index = .comptime_field_ptr,27781 .runtime_index = .comptime_field_ptr,
27768 });27782 });
27769 },27783 },
27770 else => unreachable,27784 .eu_payload => |eu_ptr| {
27771 }27785 const eu_ty = mod.intern_pool.typeOf(eu_ptr).toType().childType(mod);
27772 if (true) unreachable;27786 var parent = try sema.beginComptimePtrMutation(block, src, eu_ptr.toValue(), eu_ty);
27773 switch (ptr_val.toIntern()) {27787 switch (parent.pointee) {
27774 .none => switch (ptr_val.tag()) {27788 .direct => |val_ptr| {
27775 .decl_ref_mut => {27789 const payload_ty = parent.ty.errorUnionPayload(mod);
27776 const decl_ref_mut = ptr_val.castTag(.decl_ref_mut).?.data;27790 if (val_ptr.ip_index == .none and val_ptr.tag() == .eu_payload) {
27777 const decl = sema.mod.declPtr(decl_ref_mut.decl_index);27791 return ComptimePtrMutationKit{
27778 return sema.beginComptimePtrMutationInner(block, src, decl.ty, &decl.val, ptr_elem_ty, decl_ref_mut);27792 .mut_decl = parent.mut_decl,
27779 },27793 .pointee = .{ .direct = &val_ptr.castTag(.eu_payload).?.data },
27780 .comptime_field_ptr => {27794 .ty = payload_ty,
27781 const payload = ptr_val.castTag(.comptime_field_ptr).?.data;27795 };
27782 const duped = try sema.arena.create(Value);27796 } else {
27783 duped.* = payload.field_val;27797 // An error union has been initialized to undefined at comptime and now we
27784 return sema.beginComptimePtrMutationInner(block, src, payload.field_ty, duped, ptr_elem_ty, .{27798 // are for the first time setting the payload. We must change the
27785 .decl_index = @intToEnum(Module.Decl.Index, 0),27799 // representation of the error union from `undef` to `opt_payload`.
27786 .runtime_index = .comptime_field_ptr,27800 const arena = parent.beginArena(sema.mod);
27787 });27801 defer parent.finishArena(sema.mod);
27788 },27802
27789 .elem_ptr => {27803 const payload = try arena.create(Value.Payload.SubValue);
27790 const elem_ptr = ptr_val.castTag(.elem_ptr).?.data;27804 payload.* = .{
27791 var parent = try sema.beginComptimePtrMutation(block, src, elem_ptr.array_ptr, elem_ptr.elem_ty);27805 .base = .{ .tag = .eu_payload },
2779227806 .data = Value.undef,
27793 switch (parent.pointee) {27807 };
27794 .direct => |val_ptr| switch (parent.ty.zigTypeTag(mod)) {
27795 .Array, .Vector => {
27796 const check_len = parent.ty.arrayLenIncludingSentinel(mod);
27797 if (elem_ptr.index >= check_len) {
27798 // TODO have the parent include the decl so we can say "declared here"
27799 return sema.fail(block, src, "comptime store of index {d} out of bounds of array length {d}", .{
27800 elem_ptr.index, check_len,
27801 });
27802 }
27803 const elem_ty = parent.ty.childType(mod);
27804
27805 // We might have a pointer to multiple elements of the array (e.g. a pointer
27806 // to a sub-array). In this case, we just have to reinterpret the relevant
27807 // bytes of the whole array rather than any single element.
27808 const elem_abi_size_u64 = try sema.typeAbiSize(elem_ptr.elem_ty);
27809 if (elem_abi_size_u64 < try sema.typeAbiSize(ptr_elem_ty)) {
27810 const elem_abi_size = try sema.usizeCast(block, src, elem_abi_size_u64);
27811 return .{
27812 .decl_ref_mut = parent.decl_ref_mut,
27813 .pointee = .{ .reinterpret = .{
27814 .val_ptr = val_ptr,
27815 .byte_offset = elem_abi_size * elem_ptr.index,
27816 } },
27817 .ty = parent.ty,
27818 };
27819 }
2782027808
27821 switch (val_ptr.toIntern()) {27809 val_ptr.* = Value.initPayload(&payload.base);
27822 .undef => {
27823 // An array has been initialized to undefined at comptime and now we
27824 // are for the first time setting an element. We must change the representation
27825 // of the array from `undef` to `array`.
27826 const arena = parent.beginArena(sema.mod);
27827 defer parent.finishArena(sema.mod);
2782827810
27829 const array_len_including_sentinel =27811 return ComptimePtrMutationKit{
27830 try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel(mod));27812 .mut_decl = parent.mut_decl,
27831 const elems = try arena.alloc(Value, array_len_including_sentinel);27813 .pointee = .{ .direct = &payload.data },
27832 @memset(elems, Value.undef);27814 .ty = payload_ty,
27815 };
27816 }
27817 },
27818 .bad_decl_ty, .bad_ptr_ty => return parent,
27819 // Even though the parent value type has well-defined memory layout, our
27820 // pointer type does not.
27821 .reinterpret => return ComptimePtrMutationKit{
27822 .mut_decl = parent.mut_decl,
27823 .pointee = .bad_ptr_ty,
27824 .ty = eu_ty,
27825 },
27826 }
27827 },
27828 .opt_payload => |opt_ptr| {
27829 const opt_ty = mod.intern_pool.typeOf(opt_ptr).toType().childType(mod);
27830 var parent = try sema.beginComptimePtrMutation(block, src, opt_ptr.toValue(), opt_ty);
27831 switch (parent.pointee) {
27832 .direct => |val_ptr| {
27833 const payload_ty = parent.ty.optionalChild(mod);
27834 switch (val_ptr.ip_index) {
27835 .undef, .null_value => {
27836 // An optional has been initialized to undefined at comptime and now we
27837 // are for the first time setting the payload. We must change the
27838 // representation of the optional from `undef` to `opt_payload`.
27839 const arena = parent.beginArena(sema.mod);
27840 defer parent.finishArena(sema.mod);
2783327841
27834 val_ptr.* = try Value.Tag.aggregate.create(arena, elems);27842 const payload = try arena.create(Value.Payload.SubValue);
27843 payload.* = .{
27844 .base = .{ .tag = .opt_payload },
27845 .data = Value.undef,
27846 };
2783527847
27836 return beginComptimePtrMutationInner(27848 val_ptr.* = Value.initPayload(&payload.base);
27837 sema,
27838 block,
27839 src,
27840 elem_ty,
27841 &elems[elem_ptr.index],
27842 ptr_elem_ty,
27843 parent.decl_ref_mut,
27844 );
27845 },
27846 .none => switch (val_ptr.tag()) {
27847 .bytes => {
27848 // An array is memory-optimized to store a slice of bytes, but we are about
27849 // to modify an individual field and the representation has to change.
27850 // If we wanted to avoid this, there would need to be special detection
27851 // elsewhere to identify when writing a value to an array element that is stored
27852 // using the `bytes` tag, and handle it without making a call to this function.
27853 const arena = parent.beginArena(sema.mod);
27854 defer parent.finishArena(sema.mod);
27855
27856 const bytes = val_ptr.castTag(.bytes).?.data;
27857 const dest_len = parent.ty.arrayLenIncludingSentinel(mod);
27858 // bytes.len may be one greater than dest_len because of the case when
27859 // assigning `[N:S]T` to `[N]T`. This is allowed; the sentinel is omitted.
27860 assert(bytes.len >= dest_len);
27861 const elems = try arena.alloc(Value, @intCast(usize, dest_len));
27862 for (elems, 0..) |*elem, i| {
27863 elem.* = try mod.intValue(elem_ty, bytes[i]);
27864 }
27865
27866 val_ptr.* = try Value.Tag.aggregate.create(arena, elems);
27867
27868 return beginComptimePtrMutationInner(
27869 sema,
27870 block,
27871 src,
27872 elem_ty,
27873 &elems[elem_ptr.index],
27874 ptr_elem_ty,
27875 parent.decl_ref_mut,
27876 );
27877 },
27878 .str_lit => {
27879 // An array is memory-optimized to store a slice of bytes, but we are about
27880 // to modify an individual field and the representation has to change.
27881 // If we wanted to avoid this, there would need to be special detection
27882 // elsewhere to identify when writing a value to an array element that is stored
27883 // using the `str_lit` tag, and handle it without making a call to this function.
27884 const arena = parent.beginArena(sema.mod);
27885 defer parent.finishArena(sema.mod);
27886
27887 const str_lit = val_ptr.castTag(.str_lit).?.data;
27888 const dest_len = parent.ty.arrayLenIncludingSentinel(mod);
27889 const bytes = sema.mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len];
27890 const elems = try arena.alloc(Value, @intCast(usize, dest_len));
27891 for (bytes, 0..) |byte, i| {
27892 elems[i] = try mod.intValue(elem_ty, byte);
27893 }
27894 if (parent.ty.sentinel(mod)) |sent_val| {
27895 assert(elems.len == bytes.len + 1);
27896 elems[bytes.len] = sent_val;
27897 }
27898
27899 val_ptr.* = try Value.Tag.aggregate.create(arena, elems);
27900
27901 return beginComptimePtrMutationInner(
27902 sema,
27903 block,
27904 src,
27905 elem_ty,
27906 &elems[elem_ptr.index],
27907 ptr_elem_ty,
27908 parent.decl_ref_mut,
27909 );
27910 },
27911 .repeated => {
27912 // An array is memory-optimized to store only a single element value, and
27913 // that value is understood to be the same for the entire length of the array.
27914 // However, now we want to modify an individual field and so the
27915 // representation has to change. If we wanted to avoid this, there would
27916 // need to be special detection elsewhere to identify when writing a value to an
27917 // array element that is stored using the `repeated` tag, and handle it
27918 // without making a call to this function.
27919 const arena = parent.beginArena(sema.mod);
27920 defer parent.finishArena(sema.mod);
27921
27922 const repeated_val = try val_ptr.castTag(.repeated).?.data.copy(arena);
27923 const array_len_including_sentinel =
27924 try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel(mod));
27925 const elems = try arena.alloc(Value, array_len_including_sentinel);
27926 if (elems.len > 0) elems[0] = repeated_val;
27927 for (elems[1..]) |*elem| {
27928 elem.* = try repeated_val.copy(arena);
27929 }
27930
27931 val_ptr.* = try Value.Tag.aggregate.create(arena, elems);
27932
27933 return beginComptimePtrMutationInner(
27934 sema,
27935 block,
27936 src,
27937 elem_ty,
27938 &elems[elem_ptr.index],
27939 ptr_elem_ty,
27940 parent.decl_ref_mut,
27941 );
27942 },
27943
27944 .aggregate => return beginComptimePtrMutationInner(
27945 sema,
27946 block,
27947 src,
27948 elem_ty,
27949 &val_ptr.castTag(.aggregate).?.data[elem_ptr.index],
27950 ptr_elem_ty,
27951 parent.decl_ref_mut,
27952 ),
2795327849
27954 .the_only_possible_value => {27850 return ComptimePtrMutationKit{
27955 const duped = try sema.arena.create(Value);27851 .mut_decl = parent.mut_decl,
27956 duped.* = Value.initTag(.the_only_possible_value);27852 .pointee = .{ .direct = &payload.data },
27957 return beginComptimePtrMutationInner(27853 .ty = payload_ty,
27958 sema,27854 };
27959 block,27855 },
27960 src,27856 .none => switch (val_ptr.tag()) {
27961 elem_ty,27857 .opt_payload => return ComptimePtrMutationKit{
27962 duped,27858 .mut_decl = parent.mut_decl,
27963 ptr_elem_ty,27859 .pointee = .{ .direct = &val_ptr.castTag(.opt_payload).?.data },
27964 parent.decl_ref_mut,27860 .ty = payload_ty,
27965 );27861 },
27966 },
2796727862
27968 else => unreachable,27863 else => return ComptimePtrMutationKit{
27969 },27864 .mut_decl = parent.mut_decl,
27970 else => unreachable,27865 .pointee = .{ .direct = val_ptr },
27971 }27866 .ty = payload_ty,
27867 },
27972 },27868 },
27973 else => {27869 else => return ComptimePtrMutationKit{
27974 if (elem_ptr.index != 0) {27870 .mut_decl = parent.mut_decl,
27975 // TODO include a "declared here" note for the decl27871 .pointee = .{ .direct = val_ptr },
27976 return sema.fail(block, src, "out of bounds comptime store of index {d}", .{27872 .ty = payload_ty,
27977 elem_ptr.index,
27978 });
27979 }
27980 return beginComptimePtrMutationInner(
27981 sema,
27982 block,
27983 src,
27984 parent.ty,
27985 val_ptr,
27986 ptr_elem_ty,
27987 parent.decl_ref_mut,
27988 );
27989 },27873 },
27990 },27874 }
27991 .reinterpret => |reinterpret| {27875 },
27992 if (!elem_ptr.elem_ty.hasWellDefinedLayout(mod)) {27876 .bad_decl_ty, .bad_ptr_ty => return parent,
27993 // Even though the parent value type has well-defined memory layout, our27877 // Even though the parent value type has well-defined memory layout, our
27994 // pointer type does not.27878 // pointer type does not.
27995 return ComptimePtrMutationKit{27879 .reinterpret => return ComptimePtrMutationKit{
27996 .decl_ref_mut = parent.decl_ref_mut,27880 .mut_decl = parent.mut_decl,
27997 .pointee = .bad_ptr_ty,27881 .pointee = .bad_ptr_ty,
27998 .ty = elem_ptr.elem_ty,27882 .ty = opt_ty,
27883 },
27884 }
27885 },
27886 .elem => |elem_ptr| {
27887 const base_elem_ty = mod.intern_pool.typeOf(elem_ptr.base).toType().elemType2(mod);
27888 var parent = try sema.beginComptimePtrMutation(block, src, elem_ptr.base.toValue(), base_elem_ty);
27889
27890 switch (parent.pointee) {
27891 .direct => |val_ptr| switch (parent.ty.zigTypeTag(mod)) {
27892 .Array, .Vector => {
27893 const check_len = parent.ty.arrayLenIncludingSentinel(mod);
27894 if (elem_ptr.index >= check_len) {
27895 // TODO have the parent include the decl so we can say "declared here"
27896 return sema.fail(block, src, "comptime store of index {d} out of bounds of array length {d}", .{
27897 elem_ptr.index, check_len,
27898 });
27899 }
27900 const elem_ty = parent.ty.childType(mod);
27901
27902 // We might have a pointer to multiple elements of the array (e.g. a pointer
27903 // to a sub-array). In this case, we just have to reinterpret the relevant
27904 // bytes of the whole array rather than any single element.
27905 const elem_abi_size_u64 = try sema.typeAbiSize(base_elem_ty);
27906 if (elem_abi_size_u64 < try sema.typeAbiSize(ptr_elem_ty)) {
27907 const elem_abi_size = try sema.usizeCast(block, src, elem_abi_size_u64);
27908 return .{
27909 .mut_decl = parent.mut_decl,
27910 .pointee = .{ .reinterpret = .{
27911 .val_ptr = val_ptr,
27912 .byte_offset = elem_abi_size * elem_ptr.index,
27913 } },
27914 .ty = parent.ty,
27999 };27915 };
28000 }27916 }
2800127917
28002 const elem_abi_size_u64 = try sema.typeAbiSize(elem_ptr.elem_ty);27918 switch (val_ptr.ip_index) {
28003 const elem_abi_size = try sema.usizeCast(block, src, elem_abi_size_u64);27919 .undef => {
28004 return ComptimePtrMutationKit{27920 // An array has been initialized to undefined at comptime and now we
28005 .decl_ref_mut = parent.decl_ref_mut,27921 // are for the first time setting an element. We must change the representation
28006 .pointee = .{ .reinterpret = .{27922 // of the array from `undef` to `array`.
28007 .val_ptr = reinterpret.val_ptr,27923 const arena = parent.beginArena(sema.mod);
28008 .byte_offset = reinterpret.byte_offset + elem_abi_size * elem_ptr.index,27924 defer parent.finishArena(sema.mod);
28009 } },
28010 .ty = parent.ty,
28011 };
28012 },
28013 .bad_decl_ty, .bad_ptr_ty => return parent,
28014 }
28015 },
28016 .field_ptr => {
28017 const field_ptr = ptr_val.castTag(.field_ptr).?.data;
28018 const field_index = @intCast(u32, field_ptr.field_index);
2801927925
28020 var parent = try sema.beginComptimePtrMutation(block, src, field_ptr.container_ptr, field_ptr.container_ty);27926 const array_len_including_sentinel =
28021 switch (parent.pointee) {27927 try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel(mod));
28022 .direct => |val_ptr| switch (val_ptr.toIntern()) {27928 const elems = try arena.alloc(Value, array_len_including_sentinel);
28023 .undef => {27929 @memset(elems, Value.undef);
28024 // A struct or union has been initialized to undefined at comptime and now we
28025 // are for the first time setting a field. We must change the representation
28026 // of the struct/union from `undef` to `struct`/`union`.
28027 const arena = parent.beginArena(sema.mod);
28028 defer parent.finishArena(sema.mod);
2802927930
28030 switch (parent.ty.zigTypeTag(mod)) {27931 val_ptr.* = try Value.Tag.aggregate.create(arena, elems);
28031 .Struct => {
28032 const fields = try arena.alloc(Value, parent.ty.structFieldCount(mod));
28033 @memset(fields, Value.undef);
2803427932
28035 val_ptr.* = try Value.Tag.aggregate.create(arena, fields);27933 return beginComptimePtrMutationInner(
27934 sema,
27935 block,
27936 src,
27937 elem_ty,
27938 &elems[elem_ptr.index],
27939 ptr_elem_ty,
27940 parent.mut_decl,
27941 );
27942 },
27943 .none => switch (val_ptr.tag()) {
27944 .bytes => {
27945 // An array is memory-optimized to store a slice of bytes, but we are about
27946 // to modify an individual field and the representation has to change.
27947 // If we wanted to avoid this, there would need to be special detection
27948 // elsewhere to identify when writing a value to an array element that is stored
27949 // using the `bytes` tag, and handle it without making a call to this function.
27950 const arena = parent.beginArena(sema.mod);
27951 defer parent.finishArena(sema.mod);
27952
27953 const bytes = val_ptr.castTag(.bytes).?.data;
27954 const dest_len = parent.ty.arrayLenIncludingSentinel(mod);
27955 // bytes.len may be one greater than dest_len because of the case when
27956 // assigning `[N:S]T` to `[N]T`. This is allowed; the sentinel is omitted.
27957 assert(bytes.len >= dest_len);
27958 const elems = try arena.alloc(Value, @intCast(usize, dest_len));
27959 for (elems, 0..) |*elem, i| {
27960 elem.* = try mod.intValue(elem_ty, bytes[i]);
27961 }
27962
27963 val_ptr.* = try Value.Tag.aggregate.create(arena, elems);
2803627964
28037 return beginComptimePtrMutationInner(27965 return beginComptimePtrMutationInner(
28038 sema,27966 sema,
28039 block,27967 block,
28040 src,27968 src,
28041 parent.ty.structFieldType(field_index, mod),27969 elem_ty,
28042 &fields[field_index],27970 &elems[elem_ptr.index],
28043 ptr_elem_ty,27971 ptr_elem_ty,
28044 parent.decl_ref_mut,27972 parent.mut_decl,
28045 );27973 );
28046 },27974 },
28047 .Union => {27975 .repeated => {
28048 const payload = try arena.create(Value.Payload.Union);27976 // An array is memory-optimized to store only a single element value, and
28049 const tag_ty = parent.ty.unionTagTypeHypothetical(mod);27977 // that value is understood to be the same for the entire length of the array.
28050 payload.* = .{ .data = .{27978 // However, now we want to modify an individual field and so the
28051 .tag = try mod.enumValueFieldIndex(tag_ty, field_index),27979 // representation has to change. If we wanted to avoid this, there would
28052 .val = Value.undef,27980 // need to be special detection elsewhere to identify when writing a value to an
28053 } };27981 // array element that is stored using the `repeated` tag, and handle it
27982 // without making a call to this function.
27983 const arena = parent.beginArena(sema.mod);
27984 defer parent.finishArena(sema.mod);
27985
27986 const repeated_val = try val_ptr.castTag(.repeated).?.data.copy(arena);
27987 const array_len_including_sentinel =
27988 try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel(mod));
27989 const elems = try arena.alloc(Value, array_len_including_sentinel);
27990 if (elems.len > 0) elems[0] = repeated_val;
27991 for (elems[1..]) |*elem| {
27992 elem.* = try repeated_val.copy(arena);
27993 }
2805427994
28055 val_ptr.* = Value.initPayload(&payload.base);27995 val_ptr.* = try Value.Tag.aggregate.create(arena, elems);
2805627996
28057 return beginComptimePtrMutationInner(27997 return beginComptimePtrMutationInner(
28058 sema,27998 sema,
28059 block,27999 block,
28060 src,28000 src,
28061 parent.ty.structFieldType(field_index, mod),28001 elem_ty,
28062 &payload.data.val,28002 &elems[elem_ptr.index],
28063 ptr_elem_ty,28003 ptr_elem_ty,
28064 parent.decl_ref_mut,28004 parent.mut_decl,
28065 );28005 );
28066 },28006 },
28067 .Pointer => {28007
28068 assert(parent.ty.isSlice(mod));28008 .aggregate => return beginComptimePtrMutationInner(
28069 val_ptr.* = try Value.Tag.slice.create(arena, .{28009 sema,
28070 .ptr = Value.undef,28010 block,
28071 .len = Value.undef,28011 src,
28072 });28012 elem_ty,
2807328013 &val_ptr.castTag(.aggregate).?.data[elem_ptr.index],
28074 switch (field_index) {28014 ptr_elem_ty,
28075 Value.Payload.Slice.ptr_index => return beginComptimePtrMutationInner(28015 parent.mut_decl,
28076 sema,28016 ),
28077 block,28017
28078 src,
28079 parent.ty.slicePtrFieldType(mod),
28080 &val_ptr.castTag(.slice).?.data.ptr,
28081 ptr_elem_ty,
28082 parent.decl_ref_mut,
28083 ),
28084 Value.Payload.Slice.len_index => return beginComptimePtrMutationInner(
28085 sema,
28086 block,
28087 src,
28088 Type.usize,
28089 &val_ptr.castTag(.slice).?.data.len,
28090 ptr_elem_ty,
28091 parent.decl_ref_mut,
28092 ),
28093
28094 else => unreachable,
28095 }
28096 },
28097 else => unreachable,28018 else => unreachable,
28098 }28019 },
28099 },28020 else => unreachable,
28100 .empty_struct => {28021 }
28101 const duped = try sema.arena.create(Value);28022 },
28102 duped.* = Value.initTag(.the_only_possible_value);28023 else => {
28103 return beginComptimePtrMutationInner(28024 if (elem_ptr.index != 0) {
28104 sema,28025 // TODO include a "declared here" note for the decl
28105 block,28026 return sema.fail(block, src, "out of bounds comptime store of index {d}", .{
28106 src,28027 elem_ptr.index,
28107 parent.ty.structFieldType(field_index, mod),28028 });
28108 duped,28029 }
28109 ptr_elem_ty,28030 return beginComptimePtrMutationInner(
28110 parent.decl_ref_mut,28031 sema,
28111 );28032 block,
28112 },28033 src,
28113 .none => switch (val_ptr.tag()) {28034 parent.ty,
28114 .aggregate => return beginComptimePtrMutationInner(28035 val_ptr,
28115 sema,28036 ptr_elem_ty,
28116 block,28037 parent.mut_decl,
28117 src,28038 );
28118 parent.ty.structFieldType(field_index, mod),28039 },
28119 &val_ptr.castTag(.aggregate).?.data[field_index],28040 },
28120 ptr_elem_ty,28041 .reinterpret => |reinterpret| {
28121 parent.decl_ref_mut,28042 if (!base_elem_ty.hasWellDefinedLayout(mod)) {
28122 ),28043 // Even though the parent value type has well-defined memory layout, our
28123 .repeated => {28044 // pointer type does not.
28124 const arena = parent.beginArena(sema.mod);28045 return ComptimePtrMutationKit{
28125 defer parent.finishArena(sema.mod);28046 .mut_decl = parent.mut_decl,
28047 .pointee = .bad_ptr_ty,
28048 .ty = base_elem_ty,
28049 };
28050 }
2812628051
28127 const elems = try arena.alloc(Value, parent.ty.structFieldCount(mod));28052 const elem_abi_size_u64 = try sema.typeAbiSize(base_elem_ty);
28128 @memset(elems, val_ptr.castTag(.repeated).?.data);28053 const elem_abi_size = try sema.usizeCast(block, src, elem_abi_size_u64);
28129 val_ptr.* = try Value.Tag.aggregate.create(arena, elems);28054 return ComptimePtrMutationKit{
28055 .mut_decl = parent.mut_decl,
28056 .pointee = .{ .reinterpret = .{
28057 .val_ptr = reinterpret.val_ptr,
28058 .byte_offset = reinterpret.byte_offset + elem_abi_size * elem_ptr.index,
28059 } },
28060 .ty = parent.ty,
28061 };
28062 },
28063 .bad_decl_ty, .bad_ptr_ty => return parent,
28064 }
28065 },
28066 .field => |field_ptr| {
28067 const base_child_ty = mod.intern_pool.typeOf(field_ptr.base).toType().childType(mod);
28068 const field_index = @intCast(u32, field_ptr.index);
28069
28070 var parent = try sema.beginComptimePtrMutation(block, src, field_ptr.base.toValue(), base_child_ty);
28071 switch (parent.pointee) {
28072 .direct => |val_ptr| switch (val_ptr.ip_index) {
28073 .undef => {
28074 // A struct or union has been initialized to undefined at comptime and now we
28075 // are for the first time setting a field. We must change the representation
28076 // of the struct/union from `undef` to `struct`/`union`.
28077 const arena = parent.beginArena(sema.mod);
28078 defer parent.finishArena(sema.mod);
28079
28080 switch (parent.ty.zigTypeTag(mod)) {
28081 .Struct => {
28082 const fields = try arena.alloc(Value, parent.ty.structFieldCount(mod));
28083 @memset(fields, Value.undef);
28084
28085 val_ptr.* = try Value.Tag.aggregate.create(arena, fields);
2813028086
28131 return beginComptimePtrMutationInner(28087 return beginComptimePtrMutationInner(
28132 sema,28088 sema,
28133 block,28089 block,
28134 src,28090 src,
28135 parent.ty.structFieldType(field_index, mod),28091 parent.ty.structFieldType(field_index, mod),
28136 &elems[field_index],28092 &fields[field_index],
28137 ptr_elem_ty,28093 ptr_elem_ty,
28138 parent.decl_ref_mut,28094 parent.mut_decl,
28139 );28095 );
28140 },28096 },
28141 .@"union" => {28097 .Union => {
28142 // We need to set the active field of the union.28098 const payload = try arena.create(Value.Payload.Union);
28143 const union_tag_ty = field_ptr.container_ty.unionTagTypeHypothetical(mod);28099 const tag_ty = parent.ty.unionTagTypeHypothetical(mod);
28100 payload.* = .{ .data = .{
28101 .tag = try mod.enumValueFieldIndex(tag_ty, field_index),
28102 .val = Value.undef,
28103 } };
2814428104
28145 const payload = &val_ptr.castTag(.@"union").?.data;28105 val_ptr.* = Value.initPayload(&payload.base);
28146 payload.tag = try mod.enumValueFieldIndex(union_tag_ty, field_index);
2814728106
28148 return beginComptimePtrMutationInner(28107 return beginComptimePtrMutationInner(
28149 sema,28108 sema,
28150 block,28109 block,
28151 src,28110 src,
28152 parent.ty.structFieldType(field_index, mod),28111 parent.ty.structFieldType(field_index, mod),
28153 &payload.val,28112 &payload.data.val,
28154 ptr_elem_ty,28113 ptr_elem_ty,
28155 parent.decl_ref_mut,28114 parent.mut_decl,
28156 );28115 );
28157 },28116 },
28158 .slice => switch (field_index) {28117 .Pointer => {
28159 Value.Payload.Slice.ptr_index => return beginComptimePtrMutationInner(28118 assert(parent.ty.isSlice(mod));
28160 sema,28119 val_ptr.* = try Value.Tag.slice.create(arena, .{
28161 block,28120 .ptr = Value.undef,
28162 src,28121 .len = Value.undef,
28163 parent.ty.slicePtrFieldType(mod),28122 });
28164 &val_ptr.castTag(.slice).?.data.ptr,
28165 ptr_elem_ty,
28166 parent.decl_ref_mut,
28167 ),
2816828123
28169 Value.Payload.Slice.len_index => return beginComptimePtrMutationInner(28124 switch (field_index) {
28170 sema,28125 Value.slice_ptr_index => return beginComptimePtrMutationInner(
28171 block,28126 sema,
28172 src,28127 block,
28173 Type.usize,28128 src,
28174 &val_ptr.castTag(.slice).?.data.len,28129 parent.ty.slicePtrFieldType(mod),
28175 ptr_elem_ty,28130 &val_ptr.castTag(.slice).?.data.ptr,
28176 parent.decl_ref_mut,28131 ptr_elem_ty,
28177 ),28132 parent.mut_decl,
28133 ),
28134 Value.slice_len_index => return beginComptimePtrMutationInner(
28135 sema,
28136 block,
28137 src,
28138 Type.usize,
28139 &val_ptr.castTag(.slice).?.data.len,
28140 ptr_elem_ty,
28141 parent.mut_decl,
28142 ),
2817828143
28179 else => unreachable,28144 else => unreachable,
28145 }
28180 },28146 },
28181
28182 else => unreachable,28147 else => unreachable,
28183 },28148 }
28184 else => unreachable,
28185 },28149 },
28186 .reinterpret => |reinterpret| {28150 .empty_struct => {
28187 const field_offset_u64 = field_ptr.container_ty.structFieldOffset(field_index, mod);28151 const duped = try sema.arena.create(Value);
28188 const field_offset = try sema.usizeCast(block, src, field_offset_u64);28152 duped.* = val_ptr.*;
28189 return ComptimePtrMutationKit{28153 return beginComptimePtrMutationInner(
28190 .decl_ref_mut = parent.decl_ref_mut,28154 sema,
28191 .pointee = .{ .reinterpret = .{28155 block,
28192 .val_ptr = reinterpret.val_ptr,28156 src,
28193 .byte_offset = reinterpret.byte_offset + field_offset,28157 parent.ty.structFieldType(field_index, mod),
28194 } },28158 duped,
28195 .ty = parent.ty,28159 ptr_elem_ty,
28196 };28160 parent.mut_decl,
28161 );
28197 },28162 },
28198 .bad_decl_ty, .bad_ptr_ty => return parent,28163 .none => switch (val_ptr.tag()) {
28199 }28164 .aggregate => return beginComptimePtrMutationInner(
28200 },28165 sema,
28201 .eu_payload_ptr => {28166 block,
28202 const eu_ptr = ptr_val.castTag(.eu_payload_ptr).?.data;28167 src,
28203 var parent = try sema.beginComptimePtrMutation(block, src, eu_ptr.container_ptr, eu_ptr.container_ty);28168 parent.ty.structFieldType(field_index, mod),
28204 switch (parent.pointee) {28169 &val_ptr.castTag(.aggregate).?.data[field_index],
28205 .direct => |val_ptr| {28170 ptr_elem_ty,
28206 const payload_ty = parent.ty.errorUnionPayload(mod);28171 parent.mut_decl,
28207 if (val_ptr.ip_index == .none and val_ptr.tag() == .eu_payload) {28172 ),
28208 return ComptimePtrMutationKit{28173 .repeated => {
28209 .decl_ref_mut = parent.decl_ref_mut,
28210 .pointee = .{ .direct = &val_ptr.castTag(.eu_payload).?.data },
28211 .ty = payload_ty,
28212 };
28213 } else {
28214 // An error union has been initialized to undefined at comptime and now we
28215 // are for the first time setting the payload. We must change the
28216 // representation of the error union from `undef` to `opt_payload`.
28217 const arena = parent.beginArena(sema.mod);28174 const arena = parent.beginArena(sema.mod);
28218 defer parent.finishArena(sema.mod);28175 defer parent.finishArena(sema.mod);
2821928176
28220 const payload = try arena.create(Value.Payload.SubValue);28177 const elems = try arena.alloc(Value, parent.ty.structFieldCount(mod));
28221 payload.* = .{28178 @memset(elems, val_ptr.castTag(.repeated).?.data);
28222 .base = .{ .tag = .eu_payload },28179 val_ptr.* = try Value.Tag.aggregate.create(arena, elems);
28223 .data = Value.undef,
28224 };
2822528180
28226 val_ptr.* = Value.initPayload(&payload.base);28181 return beginComptimePtrMutationInner(
28182 sema,
28183 block,
28184 src,
28185 parent.ty.structFieldType(field_index, mod),
28186 &elems[field_index],
28187 ptr_elem_ty,
28188 parent.mut_decl,
28189 );
28190 },
28191 .@"union" => {
28192 // We need to set the active field of the union.
28193 const union_tag_ty = base_child_ty.unionTagTypeHypothetical(mod);
2822728194
28228 return ComptimePtrMutationKit{28195 const payload = &val_ptr.castTag(.@"union").?.data;
28229 .decl_ref_mut = parent.decl_ref_mut,28196 payload.tag = try mod.enumValueFieldIndex(union_tag_ty, field_index);
28230 .pointee = .{ .direct = &payload.data },
28231 .ty = payload_ty,
28232 };
28233 }
28234 },
28235 .bad_decl_ty, .bad_ptr_ty => return parent,
28236 // Even though the parent value type has well-defined memory layout, our
28237 // pointer type does not.
28238 .reinterpret => return ComptimePtrMutationKit{
28239 .decl_ref_mut = parent.decl_ref_mut,
28240 .pointee = .bad_ptr_ty,
28241 .ty = eu_ptr.container_ty,
28242 },
28243 }
28244 },
28245 .opt_payload_ptr => {
28246 const opt_ptr = if (ptr_val.castTag(.opt_payload_ptr)) |some| some.data else {
28247 return sema.beginComptimePtrMutation(block, src, ptr_val, ptr_elem_ty.optionalChild(mod));
28248 };
28249 var parent = try sema.beginComptimePtrMutation(block, src, opt_ptr.container_ptr, opt_ptr.container_ty);
28250 switch (parent.pointee) {
28251 .direct => |val_ptr| {
28252 const payload_ty = parent.ty.optionalChild(mod);
28253 switch (val_ptr.toIntern()) {
28254 .undef, .null_value => {
28255 // An optional has been initialized to undefined at comptime and now we
28256 // are for the first time setting the payload. We must change the
28257 // representation of the optional from `undef` to `opt_payload`.
28258 const arena = parent.beginArena(sema.mod);
28259 defer parent.finishArena(sema.mod);
2826028197
28261 const payload = try arena.create(Value.Payload.SubValue);28198 return beginComptimePtrMutationInner(
28262 payload.* = .{28199 sema,
28263 .base = .{ .tag = .opt_payload },28200 block,
28264 .data = Value.undef,28201 src,
28265 };28202 parent.ty.structFieldType(field_index, mod),
28203 &payload.val,
28204 ptr_elem_ty,
28205 parent.mut_decl,
28206 );
28207 },
28208 .slice => switch (field_index) {
28209 Value.slice_ptr_index => return beginComptimePtrMutationInner(
28210 sema,
28211 block,
28212 src,
28213 parent.ty.slicePtrFieldType(mod),
28214 &val_ptr.castTag(.slice).?.data.ptr,
28215 ptr_elem_ty,
28216 parent.mut_decl,
28217 ),
2826628218
28267 val_ptr.* = Value.initPayload(&payload.base);28219 Value.slice_len_index => return beginComptimePtrMutationInner(
28220 sema,
28221 block,
28222 src,
28223 Type.usize,
28224 &val_ptr.castTag(.slice).?.data.len,
28225 ptr_elem_ty,
28226 parent.mut_decl,
28227 ),
2826828228
28269 return ComptimePtrMutationKit{28229 else => unreachable,
28270 .decl_ref_mut = parent.decl_ref_mut,28230 },
28271 .pointee = .{ .direct = &payload.data },
28272 .ty = payload_ty,
28273 };
28274 },
28275 .none => switch (val_ptr.tag()) {
28276 .opt_payload => return ComptimePtrMutationKit{
28277 .decl_ref_mut = parent.decl_ref_mut,
28278 .pointee = .{ .direct = &val_ptr.castTag(.opt_payload).?.data },
28279 .ty = payload_ty,
28280 },
2828128231
28282 else => return ComptimePtrMutationKit{28232 else => unreachable,
28283 .decl_ref_mut = parent.decl_ref_mut,
28284 .pointee = .{ .direct = val_ptr },
28285 .ty = payload_ty,
28286 },
28287 },
28288 else => return ComptimePtrMutationKit{
28289 .decl_ref_mut = parent.decl_ref_mut,
28290 .pointee = .{ .direct = val_ptr },
28291 .ty = payload_ty,
28292 },
28293 }
28294 },
28295 .bad_decl_ty, .bad_ptr_ty => return parent,
28296 // Even though the parent value type has well-defined memory layout, our
28297 // pointer type does not.
28298 .reinterpret => return ComptimePtrMutationKit{
28299 .decl_ref_mut = parent.decl_ref_mut,
28300 .pointee = .bad_ptr_ty,
28301 .ty = opt_ptr.container_ty,
28302 },28233 },
28303 }28234 else => unreachable,
28304 },28235 },
28305 .decl_ref => unreachable, // isComptimeMutablePtr has been checked already28236 .reinterpret => |reinterpret| {
28306 else => unreachable,28237 const field_offset_u64 = base_child_ty.structFieldOffset(field_index, mod);
28307 },28238 const field_offset = try sema.usizeCast(block, src, field_offset_u64);
28308 else => switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr) {28239 return ComptimePtrMutationKit{
28309 else => unreachable,28240 .mut_decl = parent.mut_decl,
28241 .pointee = .{ .reinterpret = .{
28242 .val_ptr = reinterpret.val_ptr,
28243 .byte_offset = reinterpret.byte_offset + field_offset,
28244 } },
28245 .ty = parent.ty,
28246 };
28247 },
28248 .bad_decl_ty, .bad_ptr_ty => return parent,
28249 }
28310 },28250 },
28311 }28251 }
28312}28252}
...@@ -28418,6 +28358,7 @@ fn beginComptimePtrLoad(...@@ -28418,6 +28358,7 @@ fn beginComptimePtrLoad(
28418 .mut_decl => |mut_decl| mut_decl.decl,28358 .mut_decl => |mut_decl| mut_decl.decl,
28419 else => unreachable,28359 else => unreachable,
28420 };28360 };
28361 const is_mutable = ptr.addr == .mut_decl;
28421 const decl = mod.declPtr(decl_index);28362 const decl = mod.declPtr(decl_index);
28422 const decl_tv = try decl.typedValue();28363 const decl_tv = try decl.typedValue();
28423 if (decl.getVariable(mod) != null) return error.RuntimeLoad;28364 if (decl.getVariable(mod) != null) return error.RuntimeLoad;
...@@ -28426,7 +28367,7 @@ fn beginComptimePtrLoad(...@@ -28426,7 +28367,7 @@ fn beginComptimePtrLoad(
28426 break :blk ComptimePtrLoadKit{28367 break :blk ComptimePtrLoadKit{
28427 .parent = if (layout_defined) .{ .tv = decl_tv, .byte_offset = 0 } else null,28368 .parent = if (layout_defined) .{ .tv = decl_tv, .byte_offset = 0 } else null,
28428 .pointee = decl_tv,28369 .pointee = decl_tv,
28429 .is_mutable = false,28370 .is_mutable = is_mutable,
28430 .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null,28371 .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null,
28431 };28372 };
28432 },28373 },
...@@ -29411,7 +29352,7 @@ fn analyzeDeclVal(...@@ -29411,7 +29352,7 @@ fn analyzeDeclVal(
29411 const decl_ref = try sema.analyzeDeclRefInner(decl_index, false);29352 const decl_ref = try sema.analyzeDeclRefInner(decl_index, false);
29412 const result = try sema.analyzeLoad(block, src, decl_ref, src);29353 const result = try sema.analyzeLoad(block, src, decl_ref, src);
29413 if (Air.refToIndex(result)) |index| {29354 if (Air.refToIndex(result)) |index| {
29414 if (sema.air_instructions.items(.tag)[index] == .constant and !block.is_typeof) {29355 if (sema.air_instructions.items(.tag)[index] == .interned and !block.is_typeof) {
29415 try sema.decl_val_table.put(sema.gpa, decl_index, result);29356 try sema.decl_val_table.put(sema.gpa, decl_index, result);
29416 }29357 }
29417 }29358 }
...@@ -30049,8 +29990,8 @@ fn analyzeSlice(...@@ -30049,8 +29990,8 @@ fn analyzeSlice(
30049 const end_int = end_val.getUnsignedInt(mod).?;29990 const end_int = end_val.getUnsignedInt(mod).?;
30050 const sentinel_index = try sema.usizeCast(block, end_src, end_int - start_int);29991 const sentinel_index = try sema.usizeCast(block, end_src, end_int - start_int);
3005129992
30052 const elem_ptr = try ptr_val.elemPtr(new_ptr_ty, sentinel_index, sema.mod);29993 const elem_ptr = try ptr_val.elemPtr(try sema.elemPtrType(new_ptr_ty, sentinel_index), sentinel_index, sema.mod);
30053 const res = try sema.pointerDerefExtra(block, src, elem_ptr, elem_ty, false);29994 const res = try sema.pointerDerefExtra(block, src, elem_ptr, elem_ty);
30054 const actual_sentinel = switch (res) {29995 const actual_sentinel = switch (res) {
30055 .runtime_load => break :sentinel_check,29996 .runtime_load => break :sentinel_check,
30056 .val => |v| v,29997 .val => |v| v,
...@@ -33421,35 +33362,24 @@ fn addConstUndef(sema: *Sema, ty: Type) CompileError!Air.Inst.Ref {...@@ -33421,35 +33362,24 @@ fn addConstUndef(sema: *Sema, ty: Type) CompileError!Air.Inst.Ref {
33421}33362}
3342233363
33423pub fn addConstant(sema: *Sema, ty: Type, val: Value) SemaError!Air.Inst.Ref {33364pub fn addConstant(sema: *Sema, ty: Type, val: Value) SemaError!Air.Inst.Ref {
33365 const mod = sema.mod;
33424 const gpa = sema.gpa;33366 const gpa = sema.gpa;
33425 if (val.ip_index != .none) {33367
33426 if (@enumToInt(val.toIntern()) < Air.ref_start_index)33368 // This assertion can be removed when the `ty` parameter is removed from
33427 return @intToEnum(Air.Inst.Ref, @enumToInt(val.toIntern()));33369 // this function thanks to the InternPool transition being complete.
33428 try sema.air_instructions.append(gpa, .{33370 if (std.debug.runtime_safety) {
33429 .tag = .interned,33371 const val_ty = mod.intern_pool.typeOf(val.toIntern());
33430 .data = .{ .interned = val.toIntern() },33372 if (ty.toIntern() != val_ty) {
33431 });33373 std.debug.panic("addConstant type mismatch: '{}' vs '{}'\n", .{
33432 const result = Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1));33374 ty.fmt(mod), val_ty.toType().fmt(mod),
33433 // This assertion can be removed when the `ty` parameter is removed from33375 });
33434 // this function thanks to the InternPool transition being complete.
33435 if (std.debug.runtime_safety) {
33436 const val_ty = sema.typeOf(result);
33437 if (!Type.eql(val_ty, ty, sema.mod)) {
33438 std.debug.panic("addConstant type mismatch: '{}' vs '{}'\n", .{
33439 ty.fmt(sema.mod), val_ty.fmt(sema.mod),
33440 });
33441 }
33442 }33376 }
33443 return result;
33444 }33377 }
33445 const ty_inst = try sema.addType(ty);33378 if (@enumToInt(val.toIntern()) < Air.ref_start_index)
33446 try sema.air_values.append(gpa, val);33379 return @intToEnum(Air.Inst.Ref, @enumToInt(val.toIntern()));
33447 try sema.air_instructions.append(gpa, .{33380 try sema.air_instructions.append(gpa, .{
33448 .tag = .constant,33381 .tag = .interned,
33449 .data = .{ .ty_pl = .{33382 .data = .{ .interned = val.toIntern() },
33450 .ty = ty_inst,
33451 .payload = @intCast(u32, sema.air_values.items.len - 1),
33452 } },
33453 });33383 });
33454 return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1));33384 return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1));
33455}33385}
...@@ -33606,7 +33536,7 @@ pub fn analyzeAddressSpace(...@@ -33606,7 +33536,7 @@ pub fn analyzeAddressSpace(
33606fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr_ty: Type) CompileError!?Value {33536fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr_ty: Type) CompileError!?Value {
33607 const mod = sema.mod;33537 const mod = sema.mod;
33608 const load_ty = ptr_ty.childType(mod);33538 const load_ty = ptr_ty.childType(mod);
33609 const res = try sema.pointerDerefExtra(block, src, ptr_val, load_ty, true);33539 const res = try sema.pointerDerefExtra(block, src, ptr_val, load_ty);
33610 switch (res) {33540 switch (res) {
33611 .runtime_load => return null,33541 .runtime_load => return null,
33612 .val => |v| return v,33542 .val => |v| return v,
...@@ -33632,7 +33562,7 @@ const DerefResult = union(enum) {...@@ -33632,7 +33562,7 @@ const DerefResult = union(enum) {
33632 out_of_bounds: Type,33562 out_of_bounds: Type,
33633};33563};
3363433564
33635fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, load_ty: Type, want_mutable: bool) CompileError!DerefResult {33565fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, load_ty: Type) CompileError!DerefResult {
33636 const mod = sema.mod;33566 const mod = sema.mod;
33637 const target = mod.getTarget();33567 const target = mod.getTarget();
33638 const deref = sema.beginComptimePtrLoad(block, src, ptr_val, load_ty) catch |err| switch (err) {33568 const deref = sema.beginComptimePtrLoad(block, src, ptr_val, load_ty) catch |err| switch (err) {
...@@ -33647,13 +33577,8 @@ fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value...@@ -33647,13 +33577,8 @@ fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value
33647 if (coerce_in_mem_ok) {33577 if (coerce_in_mem_ok) {
33648 // We have a Value that lines up in virtual memory exactly with what we want to load,33578 // We have a Value that lines up in virtual memory exactly with what we want to load,
33649 // and it is in-memory coercible to load_ty. It may be returned without modifications.33579 // and it is in-memory coercible to load_ty. It may be returned without modifications.
33650 if (deref.is_mutable and want_mutable) {33580 // Move mutable decl values to the InternPool and assert other decls are already in the InternPool.
33651 // The decl whose value we are obtaining here may be overwritten with33581 return .{ .val = (if (deref.is_mutable) try tv.val.intern(tv.ty, mod) else tv.val.toIntern()).toValue() };
33652 // a different value upon further semantic analysis, which would
33653 // invalidate this memory. So we must copy here.
33654 return DerefResult{ .val = try tv.val.copy(sema.arena) };
33655 }
33656 return DerefResult{ .val = tv.val };
33657 }33582 }
33658 }33583 }
3365933584
src/TypedValue.zig+54
...@@ -124,6 +124,60 @@ pub fn print(...@@ -124,6 +124,60 @@ pub fn print(
124 }124 }
125 return writer.writeAll(" }");125 return writer.writeAll(" }");
126 },126 },
127 .slice => {
128 if (level == 0) {
129 return writer.writeAll(".{ ... }");
130 }
131 const payload = val.castTag(.slice).?.data;
132 const elem_ty = ty.elemType2(mod);
133 const len = payload.len.toUnsignedInt(mod);
134
135 if (elem_ty.eql(Type.u8, mod)) str: {
136 const max_len = @intCast(usize, std.math.min(len, max_string_len));
137 var buf: [max_string_len]u8 = undefined;
138
139 var i: u32 = 0;
140 while (i < max_len) : (i += 1) {
141 const elem_val = payload.ptr.elemValue(mod, i) catch |err| switch (err) {
142 error.OutOfMemory => @panic("OOM"), // TODO: eliminate this panic
143 };
144 if (elem_val.isUndef(mod)) break :str;
145 buf[i] = std.math.cast(u8, elem_val.toUnsignedInt(mod)) orelse break :str;
146 }
147
148 // TODO would be nice if this had a bit of unicode awareness.
149 const truncated = if (len > max_string_len) " (truncated)" else "";
150 return writer.print("\"{}{s}\"", .{ std.zig.fmtEscapes(buf[0..max_len]), truncated });
151 }
152
153 try writer.writeAll(".{ ");
154
155 const max_len = std.math.min(len, max_aggregate_items);
156 var i: u32 = 0;
157 while (i < max_len) : (i += 1) {
158 if (i != 0) try writer.writeAll(", ");
159 const elem_val = payload.ptr.elemValue(mod, i) catch |err| switch (err) {
160 error.OutOfMemory => @panic("OOM"), // TODO: eliminate this panic
161 };
162 try print(.{
163 .ty = elem_ty,
164 .val = elem_val,
165 }, writer, level - 1, mod);
166 }
167 if (len > max_aggregate_items) {
168 try writer.writeAll(", ...");
169 }
170 return writer.writeAll(" }");
171 },
172 .eu_payload => {
173 val = val.castTag(.eu_payload).?.data;
174 ty = ty.errorUnionPayload(mod);
175 },
176 .opt_payload => {
177 val = val.castTag(.opt_payload).?.data;
178 ty = ty.optionalChild(mod);
179 return print(.{ .ty = ty, .val = val }, writer, level, mod);
180 },
127 // TODO these should not appear in this function181 // TODO these should not appear in this function
128 .inferred_alloc => return writer.writeAll("(inferred allocation value)"),182 .inferred_alloc => return writer.writeAll("(inferred allocation value)"),
129 .inferred_alloc_comptime => return writer.writeAll("(inferred comptime allocation value)"),183 .inferred_alloc_comptime => return writer.writeAll("(inferred comptime allocation value)"),
src/arch/aarch64/CodeGen.zig+5-7
...@@ -845,8 +845,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -845,8 +845,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
845 .ptr_elem_val => try self.airPtrElemVal(inst),845 .ptr_elem_val => try self.airPtrElemVal(inst),
846 .ptr_elem_ptr => try self.airPtrElemPtr(inst),846 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
847847
848 .constant => unreachable, // excluded from function bodies848 .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable,
849 .interned => unreachable, // excluded from function bodies
850 .unreach => self.finishAirBookkeeping(),849 .unreach => self.finishAirBookkeeping(),
851850
852 .optional_payload => try self.airOptionalPayload(inst),851 .optional_payload => try self.airOptionalPayload(inst),
...@@ -919,8 +918,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -919,8 +918,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
919918
920/// Asserts there is already capacity to insert into top branch inst_table.919/// Asserts there is already capacity to insert into top branch inst_table.
921fn processDeath(self: *Self, inst: Air.Inst.Index) void {920fn processDeath(self: *Self, inst: Air.Inst.Index) void {
922 const air_tags = self.air.instructions.items(.tag);921 assert(self.air.instructions.items(.tag)[inst] != .interned);
923 if (air_tags[inst] == .constant) return; // Constants are immortal.
924 // When editing this function, note that the logic must synchronize with `reuseOperand`.922 // When editing this function, note that the logic must synchronize with `reuseOperand`.
925 const prev_value = self.getResolvedInstValue(inst);923 const prev_value = self.getResolvedInstValue(inst);
926 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];924 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
...@@ -6155,15 +6153,15 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {...@@ -6155,15 +6153,15 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
6155 });6153 });
61566154
6157 switch (self.air.instructions.items(.tag)[inst_index]) {6155 switch (self.air.instructions.items(.tag)[inst_index]) {
6158 .constant => {6156 .interned => {
6159 // Constants have static lifetimes, so they are always memoized in the outer most table.6157 // Constants have static lifetimes, so they are always memoized in the outer most table.
6160 const branch = &self.branch_stack.items[0];6158 const branch = &self.branch_stack.items[0];
6161 const gop = try branch.inst_table.getOrPut(self.gpa, inst_index);6159 const gop = try branch.inst_table.getOrPut(self.gpa, inst_index);
6162 if (!gop.found_existing) {6160 if (!gop.found_existing) {
6163 const ty_pl = self.air.instructions.items(.data)[inst_index].ty_pl;6161 const interned = self.air.instructions.items(.data)[inst_index].interned;
6164 gop.value_ptr.* = try self.genTypedValue(.{6162 gop.value_ptr.* = try self.genTypedValue(.{
6165 .ty = inst_ty,6163 .ty = inst_ty,
6166 .val = self.air.values[ty_pl.payload],6164 .val = interned.toValue(),
6167 });6165 });
6168 }6166 }
6169 return gop.value_ptr.*;6167 return gop.value_ptr.*;
src/arch/arm/CodeGen.zig+5-7
...@@ -829,8 +829,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -829,8 +829,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
829 .ptr_elem_val => try self.airPtrElemVal(inst),829 .ptr_elem_val => try self.airPtrElemVal(inst),
830 .ptr_elem_ptr => try self.airPtrElemPtr(inst),830 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
831831
832 .constant => unreachable, // excluded from function bodies832 .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable,
833 .interned => unreachable, // excluded from function bodies
834 .unreach => self.finishAirBookkeeping(),833 .unreach => self.finishAirBookkeeping(),
835834
836 .optional_payload => try self.airOptionalPayload(inst),835 .optional_payload => try self.airOptionalPayload(inst),
...@@ -903,8 +902,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -903,8 +902,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
903902
904/// Asserts there is already capacity to insert into top branch inst_table.903/// Asserts there is already capacity to insert into top branch inst_table.
905fn processDeath(self: *Self, inst: Air.Inst.Index) void {904fn processDeath(self: *Self, inst: Air.Inst.Index) void {
906 const air_tags = self.air.instructions.items(.tag);905 assert(self.air.instructions.items(.tag)[inst] != .interned);
907 if (air_tags[inst] == .constant) return; // Constants are immortal.
908 // When editing this function, note that the logic must synchronize with `reuseOperand`.906 // When editing this function, note that the logic must synchronize with `reuseOperand`.
909 const prev_value = self.getResolvedInstValue(inst);907 const prev_value = self.getResolvedInstValue(inst);
910 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];908 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
...@@ -6103,15 +6101,15 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {...@@ -6103,15 +6101,15 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
6103 });6101 });
61046102
6105 switch (self.air.instructions.items(.tag)[inst_index]) {6103 switch (self.air.instructions.items(.tag)[inst_index]) {
6106 .constant => {6104 .interned => {
6107 // Constants have static lifetimes, so they are always memoized in the outer most table.6105 // Constants have static lifetimes, so they are always memoized in the outer most table.
6108 const branch = &self.branch_stack.items[0];6106 const branch = &self.branch_stack.items[0];
6109 const gop = try branch.inst_table.getOrPut(self.gpa, inst_index);6107 const gop = try branch.inst_table.getOrPut(self.gpa, inst_index);
6110 if (!gop.found_existing) {6108 if (!gop.found_existing) {
6111 const ty_pl = self.air.instructions.items(.data)[inst_index].ty_pl;6109 const interned = self.air.instructions.items(.data)[inst_index].interned;
6112 gop.value_ptr.* = try self.genTypedValue(.{6110 gop.value_ptr.* = try self.genTypedValue(.{
6113 .ty = inst_ty,6111 .ty = inst_ty,
6114 .val = self.air.values[ty_pl.payload],6112 .val = interned.toValue(),
6115 });6113 });
6116 }6114 }
6117 return gop.value_ptr.*;6115 return gop.value_ptr.*;
src/arch/riscv64/CodeGen.zig+5-7
...@@ -659,8 +659,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -659,8 +659,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
659 .ptr_elem_val => try self.airPtrElemVal(inst),659 .ptr_elem_val => try self.airPtrElemVal(inst),
660 .ptr_elem_ptr => try self.airPtrElemPtr(inst),660 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
661661
662 .constant => unreachable, // excluded from function bodies662 .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable,
663 .interned => unreachable, // excluded from function bodies
664 .unreach => self.finishAirBookkeeping(),663 .unreach => self.finishAirBookkeeping(),
665664
666 .optional_payload => try self.airOptionalPayload(inst),665 .optional_payload => try self.airOptionalPayload(inst),
...@@ -730,8 +729,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -730,8 +729,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
730729
731/// Asserts there is already capacity to insert into top branch inst_table.730/// Asserts there is already capacity to insert into top branch inst_table.
732fn processDeath(self: *Self, inst: Air.Inst.Index) void {731fn processDeath(self: *Self, inst: Air.Inst.Index) void {
733 const air_tags = self.air.instructions.items(.tag);732 assert(self.air.instructions.items(.tag)[inst] != .interned);
734 if (air_tags[inst] == .constant) return; // Constants are immortal.
735 // When editing this function, note that the logic must synchronize with `reuseOperand`.733 // When editing this function, note that the logic must synchronize with `reuseOperand`.
736 const prev_value = self.getResolvedInstValue(inst);734 const prev_value = self.getResolvedInstValue(inst);
737 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];735 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
...@@ -2557,15 +2555,15 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {...@@ -2557,15 +2555,15 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
2557 });2555 });
25582556
2559 switch (self.air.instructions.items(.tag)[inst_index]) {2557 switch (self.air.instructions.items(.tag)[inst_index]) {
2560 .constant => {2558 .interned => {
2561 // Constants have static lifetimes, so they are always memoized in the outer most table.2559 // Constants have static lifetimes, so they are always memoized in the outer most table.
2562 const branch = &self.branch_stack.items[0];2560 const branch = &self.branch_stack.items[0];
2563 const gop = try branch.inst_table.getOrPut(self.gpa, inst_index);2561 const gop = try branch.inst_table.getOrPut(self.gpa, inst_index);
2564 if (!gop.found_existing) {2562 if (!gop.found_existing) {
2565 const ty_pl = self.air.instructions.items(.data)[inst_index].ty_pl;2563 const interned = self.air.instructions.items(.data)[inst_index].interned;
2566 gop.value_ptr.* = try self.genTypedValue(.{2564 gop.value_ptr.* = try self.genTypedValue(.{
2567 .ty = inst_ty,2565 .ty = inst_ty,
2568 .val = self.air.values[ty_pl.payload],2566 .val = interned.toValue(),
2569 });2567 });
2570 }2568 }
2571 return gop.value_ptr.*;2569 return gop.value_ptr.*;
src/arch/sparc64/CodeGen.zig+5-7
...@@ -679,8 +679,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -679,8 +679,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
679 .ptr_elem_val => try self.airPtrElemVal(inst),679 .ptr_elem_val => try self.airPtrElemVal(inst),
680 .ptr_elem_ptr => try self.airPtrElemPtr(inst),680 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
681681
682 .constant => unreachable, // excluded from function bodies682 .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable,
683 .interned => unreachable, // excluded from function bodies
684 .unreach => self.finishAirBookkeeping(),683 .unreach => self.finishAirBookkeeping(),
685684
686 .optional_payload => try self.airOptionalPayload(inst),685 .optional_payload => try self.airOptionalPayload(inst),
...@@ -4423,8 +4422,7 @@ fn performReloc(self: *Self, inst: Mir.Inst.Index) !void {...@@ -4423,8 +4422,7 @@ fn performReloc(self: *Self, inst: Mir.Inst.Index) !void {
44234422
4424/// Asserts there is already capacity to insert into top branch inst_table.4423/// Asserts there is already capacity to insert into top branch inst_table.
4425fn processDeath(self: *Self, inst: Air.Inst.Index) void {4424fn processDeath(self: *Self, inst: Air.Inst.Index) void {
4426 const air_tags = self.air.instructions.items(.tag);4425 assert(self.air.instructions.items(.tag)[inst] != .interned);
4427 if (air_tags[inst] == .constant) return; // Constants are immortal.
4428 // When editing this function, note that the logic must synchronize with `reuseOperand`.4426 // When editing this function, note that the logic must synchronize with `reuseOperand`.
4429 const prev_value = self.getResolvedInstValue(inst);4427 const prev_value = self.getResolvedInstValue(inst);
4430 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];4428 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
...@@ -4553,15 +4551,15 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue {...@@ -4553,15 +4551,15 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue {
45534551
4554 if (Air.refToIndex(ref)) |inst| {4552 if (Air.refToIndex(ref)) |inst| {
4555 switch (self.air.instructions.items(.tag)[inst]) {4553 switch (self.air.instructions.items(.tag)[inst]) {
4556 .constant => {4554 .interned => {
4557 // Constants have static lifetimes, so they are always memoized in the outer most table.4555 // Constants have static lifetimes, so they are always memoized in the outer most table.
4558 const branch = &self.branch_stack.items[0];4556 const branch = &self.branch_stack.items[0];
4559 const gop = try branch.inst_table.getOrPut(self.gpa, inst);4557 const gop = try branch.inst_table.getOrPut(self.gpa, inst);
4560 if (!gop.found_existing) {4558 if (!gop.found_existing) {
4561 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;4559 const interned = self.air.instructions.items(.data)[inst].interned;
4562 gop.value_ptr.* = try self.genTypedValue(.{4560 gop.value_ptr.* = try self.genTypedValue(.{
4563 .ty = ty,4561 .ty = ty,
4564 .val = self.air.values[ty_pl.payload],4562 .val = interned.toValue(),
4565 });4563 });
4566 }4564 }
4567 return gop.value_ptr.*;4565 return gop.value_ptr.*;
src/arch/wasm/CodeGen.zig+2-3
...@@ -883,7 +883,7 @@ fn iterateBigTomb(func: *CodeGen, inst: Air.Inst.Index, operand_count: usize) !B...@@ -883,7 +883,7 @@ fn iterateBigTomb(func: *CodeGen, inst: Air.Inst.Index, operand_count: usize) !B
883883
884fn processDeath(func: *CodeGen, ref: Air.Inst.Ref) void {884fn processDeath(func: *CodeGen, ref: Air.Inst.Ref) void {
885 const inst = Air.refToIndex(ref) orelse return;885 const inst = Air.refToIndex(ref) orelse return;
886 if (func.air.instructions.items(.tag)[inst] == .constant) return;886 assert(func.air.instructions.items(.tag)[inst] != .interned);
887 // Branches are currently only allowed to free locals allocated887 // Branches are currently only allowed to free locals allocated
888 // within their own branch.888 // within their own branch.
889 // TODO: Upon branch consolidation free any locals if needed.889 // TODO: Upon branch consolidation free any locals if needed.
...@@ -1832,8 +1832,7 @@ fn buildPointerOffset(func: *CodeGen, ptr_value: WValue, offset: u64, action: en...@@ -1832,8 +1832,7 @@ fn buildPointerOffset(func: *CodeGen, ptr_value: WValue, offset: u64, action: en
1832fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {1832fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
1833 const air_tags = func.air.instructions.items(.tag);1833 const air_tags = func.air.instructions.items(.tag);
1834 return switch (air_tags[inst]) {1834 return switch (air_tags[inst]) {
1835 .constant => unreachable,1835 .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable,
1836 .interned => unreachable,
18371836
1838 .add => func.airBinOp(inst, .add),1837 .add => func.airBinOp(inst, .add),
1839 .add_sat => func.airSatBinOp(inst, .add),1838 .add_sat => func.airSatBinOp(inst, .add),
src/arch/x86_64/CodeGen.zig+8-11
...@@ -1922,8 +1922,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -1922,8 +1922,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
1922 .ptr_elem_val => try self.airPtrElemVal(inst),1922 .ptr_elem_val => try self.airPtrElemVal(inst),
1923 .ptr_elem_ptr => try self.airPtrElemPtr(inst),1923 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
19241924
1925 .constant => unreachable, // excluded from function bodies1925 .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable,
1926 .interned => unreachable, // excluded from function bodies
1927 .unreach => if (self.wantSafety()) try self.airTrap() else self.finishAirBookkeeping(),1926 .unreach => if (self.wantSafety()) try self.airTrap() else self.finishAirBookkeeping(),
19281927
1929 .optional_payload => try self.airOptionalPayload(inst),1928 .optional_payload => try self.airOptionalPayload(inst),
...@@ -2097,10 +2096,8 @@ fn feed(self: *Self, bt: *Liveness.BigTomb, operand: Air.Inst.Ref) void {...@@ -2097,10 +2096,8 @@ fn feed(self: *Self, bt: *Liveness.BigTomb, operand: Air.Inst.Ref) void {
20972096
2098/// Asserts there is already capacity to insert into top branch inst_table.2097/// Asserts there is already capacity to insert into top branch inst_table.
2099fn processDeath(self: *Self, inst: Air.Inst.Index) void {2098fn processDeath(self: *Self, inst: Air.Inst.Index) void {
2100 switch (self.air.instructions.items(.tag)[inst]) {2099 assert(self.air.instructions.items(.tag)[inst] != .interned);
2101 .constant => unreachable,2100 self.inst_tracking.getPtr(inst).?.die(self, inst);
2102 else => self.inst_tracking.getPtr(inst).?.die(self, inst),
2103 }
2104}2101}
21052102
2106/// Called when there are no operands, and the instruction is always unreferenced.2103/// Called when there are no operands, and the instruction is always unreferenced.
...@@ -2876,8 +2873,8 @@ fn activeIntBits(self: *Self, dst_air: Air.Inst.Ref) u16 {...@@ -2876,8 +2873,8 @@ fn activeIntBits(self: *Self, dst_air: Air.Inst.Ref) u16 {
2876 const dst_info = dst_ty.intInfo(mod);2873 const dst_info = dst_ty.intInfo(mod);
2877 if (Air.refToIndex(dst_air)) |inst| {2874 if (Air.refToIndex(dst_air)) |inst| {
2878 switch (air_tag[inst]) {2875 switch (air_tag[inst]) {
2879 .constant => {2876 .interned => {
2880 const src_val = self.air.values[air_data[inst].ty_pl.payload];2877 const src_val = air_data[inst].interned.toValue();
2881 var space: Value.BigIntSpace = undefined;2878 var space: Value.BigIntSpace = undefined;
2882 const src_int = src_val.toBigInt(&space, mod);2879 const src_int = src_val.toBigInt(&space, mod);
2883 return @intCast(u16, src_int.bitCountTwosComp()) +2880 return @intCast(u16, src_int.bitCountTwosComp()) +
...@@ -11584,11 +11581,11 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue {...@@ -11584,11 +11581,11 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue {
1158411581
11585 if (Air.refToIndex(ref)) |inst| {11582 if (Air.refToIndex(ref)) |inst| {
11586 const mcv = switch (self.air.instructions.items(.tag)[inst]) {11583 const mcv = switch (self.air.instructions.items(.tag)[inst]) {
11587 .constant => tracking: {11584 .interned => tracking: {
11588 const gop = try self.const_tracking.getOrPut(self.gpa, inst);11585 const gop = try self.const_tracking.getOrPut(self.gpa, inst);
11589 if (!gop.found_existing) gop.value_ptr.* = InstTracking.init(try self.genTypedValue(.{11586 if (!gop.found_existing) gop.value_ptr.* = InstTracking.init(try self.genTypedValue(.{
11590 .ty = ty,11587 .ty = ty,
11591 .val = (try self.air.value(ref, mod)).?,11588 .val = self.air.instructions.items(.data)[inst].interned.toValue(),
11592 }));11589 }));
11593 break :tracking gop.value_ptr;11590 break :tracking gop.value_ptr;
11594 },11591 },
...@@ -11605,7 +11602,7 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue {...@@ -11605,7 +11602,7 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue {
1160511602
11606fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) *InstTracking {11603fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) *InstTracking {
11607 const tracking = switch (self.air.instructions.items(.tag)[inst]) {11604 const tracking = switch (self.air.instructions.items(.tag)[inst]) {
11608 .constant => &self.const_tracking,11605 .interned => &self.const_tracking,
11609 else => &self.inst_tracking,11606 else => &self.inst_tracking,
11610 }.getPtr(inst).?;11607 }.getPtr(inst).?;
11611 return switch (tracking.short) {11608 return switch (tracking.short) {
src/codegen/c.zig+2-3
...@@ -2890,8 +2890,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,...@@ -2890,8 +2890,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
28902890
2891 const result_value = switch (air_tags[inst]) {2891 const result_value = switch (air_tags[inst]) {
2892 // zig fmt: off2892 // zig fmt: off
2893 .constant => unreachable, // excluded from function bodies2893 .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable,
2894 .interned => unreachable, // excluded from function bodies
28952894
2896 .arg => try airArg(f, inst),2895 .arg => try airArg(f, inst),
28972896
...@@ -7783,8 +7782,8 @@ fn reap(f: *Function, inst: Air.Inst.Index, operands: []const Air.Inst.Ref) !voi...@@ -7783,8 +7782,8 @@ fn reap(f: *Function, inst: Air.Inst.Index, operands: []const Air.Inst.Ref) !voi
77837782
7784fn die(f: *Function, inst: Air.Inst.Index, ref: Air.Inst.Ref) !void {7783fn die(f: *Function, inst: Air.Inst.Index, ref: Air.Inst.Ref) !void {
7785 const ref_inst = Air.refToIndex(ref) orelse return;7784 const ref_inst = Air.refToIndex(ref) orelse return;
7785 assert(f.air.instructions.items(.tag)[ref_inst] != .interned);
7786 const c_value = (f.value_map.fetchRemove(ref_inst) orelse return).value;7786 const c_value = (f.value_map.fetchRemove(ref_inst) orelse return).value;
7787 if (f.air.instructions.items(.tag)[ref_inst] == .constant) return;
7788 const local_index = switch (c_value) {7787 const local_index = switch (c_value) {
7789 .local, .new_local => |l| l,7788 .local, .new_local => |l| l,
7790 else => return,7789 else => return,
src/codegen/llvm.zig+1-2
...@@ -4530,8 +4530,7 @@ pub const FuncGen = struct {...@@ -4530,8 +4530,7 @@ pub const FuncGen = struct {
45304530
4531 .vector_store_elem => try self.airVectorStoreElem(inst),4531 .vector_store_elem => try self.airVectorStoreElem(inst),
45324532
4533 .constant => unreachable,4533 .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable,
4534 .interned => unreachable,
45354534
4536 .unreach => self.airUnreach(inst),4535 .unreach => self.airUnreach(inst),
4537 .dbg_stmt => self.airDbgStmt(inst),4536 .dbg_stmt => self.airDbgStmt(inst),
src/codegen/spirv.zig-1
...@@ -1807,7 +1807,6 @@ pub const DeclGen = struct {...@@ -1807,7 +1807,6 @@ pub const DeclGen = struct {
1807 .br => return self.airBr(inst),1807 .br => return self.airBr(inst),
1808 .breakpoint => return,1808 .breakpoint => return,
1809 .cond_br => return self.airCondBr(inst),1809 .cond_br => return self.airCondBr(inst),
1810 .constant => unreachable,
1811 .dbg_stmt => return self.airDbgStmt(inst),1810 .dbg_stmt => return self.airDbgStmt(inst),
1812 .loop => return self.airLoop(inst),1811 .loop => return self.airLoop(inst),
1813 .ret => return self.airRet(inst),1812 .ret => return self.airRet(inst),
src/print_air.zig+4-8
...@@ -93,14 +93,10 @@ const Writer = struct {...@@ -93,14 +93,10 @@ const Writer = struct {
9393
94 fn writeAllConstants(w: *Writer, s: anytype) @TypeOf(s).Error!void {94 fn writeAllConstants(w: *Writer, s: anytype) @TypeOf(s).Error!void {
95 for (w.air.instructions.items(.tag), 0..) |tag, i| {95 for (w.air.instructions.items(.tag), 0..) |tag, i| {
96 if (tag != .interned) continue;
96 const inst = @intCast(Air.Inst.Index, i);97 const inst = @intCast(Air.Inst.Index, i);
97 switch (tag) {98 try w.writeInst(s, inst);
98 .constant, .interned => {99 try s.writeByte('\n');
99 try w.writeInst(s, inst);
100 try s.writeByte('\n');
101 },
102 else => continue,
103 }
104 }100 }
105 }101 }
106102
...@@ -304,7 +300,7 @@ const Writer = struct {...@@ -304,7 +300,7 @@ const Writer = struct {
304300
305 .struct_field_ptr => try w.writeStructField(s, inst),301 .struct_field_ptr => try w.writeStructField(s, inst),
306 .struct_field_val => try w.writeStructField(s, inst),302 .struct_field_val => try w.writeStructField(s, inst),
307 .constant => try w.writeConstant(s, inst),303 .inferred_alloc, .inferred_alloc_comptime => try w.writeConstant(s, inst),
308 .interned => try w.writeInterned(s, inst),304 .interned => try w.writeInterned(s, inst),
309 .assembly => try w.writeAssembly(s, inst),305 .assembly => try w.writeAssembly(s, inst),
310 .dbg_stmt => try w.writeDbgStmt(s, inst),306 .dbg_stmt => try w.writeDbgStmt(s, inst),
src/value.zig+129-69
...@@ -35,6 +35,22 @@ pub const Value = struct {...@@ -35,6 +35,22 @@ pub const Value = struct {
35 // The first section of this enum are tags that require no payload.35 // The first section of this enum are tags that require no payload.
36 // After this, the tag requires a payload.36 // After this, the tag requires a payload.
3737
38 /// When the type is error union:
39 /// * If the tag is `.@"error"`, the error union is an error.
40 /// * If the tag is `.eu_payload`, the error union is a payload.
41 /// * A nested error such as `anyerror!(anyerror!T)` in which the the outer error union
42 /// is non-error, but the inner error union is an error, is represented as
43 /// a tag of `.eu_payload`, with a sub-tag of `.@"error"`.
44 eu_payload,
45 /// When the type is optional:
46 /// * If the tag is `.null_value`, the optional is null.
47 /// * If the tag is `.opt_payload`, the optional is a payload.
48 /// * A nested optional such as `??T` in which the the outer optional
49 /// is non-null, but the inner optional is null, is represented as
50 /// a tag of `.opt_payload`, with a sub-tag of `.null_value`.
51 opt_payload,
52 /// Pointer and length as sub `Value` objects.
53 slice,
38 /// A slice of u8 whose memory is managed externally.54 /// A slice of u8 whose memory is managed externally.
39 bytes,55 bytes,
40 /// This value is repeated some number of times. The amount of times to repeat56 /// This value is repeated some number of times. The amount of times to repeat
...@@ -58,14 +74,16 @@ pub const Value = struct {...@@ -58,14 +74,16 @@ pub const Value = struct {
5874
59 pub fn Type(comptime t: Tag) type {75 pub fn Type(comptime t: Tag) type {
60 return switch (t) {76 return switch (t) {
61 .repeated => Payload.SubValue,77 .eu_payload,
6278 .opt_payload,
79 .repeated,
80 => Payload.SubValue,
81 .slice => Payload.Slice,
63 .bytes => Payload.Bytes,82 .bytes => Payload.Bytes,
64
65 .inferred_alloc => Payload.InferredAlloc,
66 .inferred_alloc_comptime => Payload.InferredAllocComptime,
67 .aggregate => Payload.Aggregate,83 .aggregate => Payload.Aggregate,
68 .@"union" => Payload.Union,84 .@"union" => Payload.Union,
85 .inferred_alloc => Payload.InferredAlloc,
86 .inferred_alloc_comptime => Payload.InferredAllocComptime,
69 };87 };
70 }88 }
7189
...@@ -172,7 +190,10 @@ pub const Value = struct {...@@ -172,7 +190,10 @@ pub const Value = struct {
172 .legacy = .{ .ptr_otherwise = &new_payload.base },190 .legacy = .{ .ptr_otherwise = &new_payload.base },
173 };191 };
174 },192 },
175 .repeated => {193 .eu_payload,
194 .opt_payload,
195 .repeated,
196 => {
176 const payload = self.cast(Payload.SubValue).?;197 const payload = self.cast(Payload.SubValue).?;
177 const new_payload = try arena.create(Payload.SubValue);198 const new_payload = try arena.create(Payload.SubValue);
178 new_payload.* = .{199 new_payload.* = .{
...@@ -184,6 +205,21 @@ pub const Value = struct {...@@ -184,6 +205,21 @@ pub const Value = struct {
184 .legacy = .{ .ptr_otherwise = &new_payload.base },205 .legacy = .{ .ptr_otherwise = &new_payload.base },
185 };206 };
186 },207 },
208 .slice => {
209 const payload = self.castTag(.slice).?;
210 const new_payload = try arena.create(Payload.Slice);
211 new_payload.* = .{
212 .base = payload.base,
213 .data = .{
214 .ptr = try payload.data.ptr.copy(arena),
215 .len = try payload.data.len.copy(arena),
216 },
217 };
218 return Value{
219 .ip_index = .none,
220 .legacy = .{ .ptr_otherwise = &new_payload.base },
221 };
222 },
187 .aggregate => {223 .aggregate => {
188 const payload = self.castTag(.aggregate).?;224 const payload = self.castTag(.aggregate).?;
189 const new_payload = try arena.create(Payload.Aggregate);225 const new_payload = try arena.create(Payload.Aggregate);
...@@ -263,6 +299,15 @@ pub const Value = struct {...@@ -263,6 +299,15 @@ pub const Value = struct {
263 try out_stream.writeAll("(repeated) ");299 try out_stream.writeAll("(repeated) ");
264 val = val.castTag(.repeated).?.data;300 val = val.castTag(.repeated).?.data;
265 },301 },
302 .eu_payload => {
303 try out_stream.writeAll("(eu_payload) ");
304 val = val.castTag(.repeated).?.data;
305 },
306 .opt_payload => {
307 try out_stream.writeAll("(opt_payload) ");
308 val = val.castTag(.repeated).?.data;
309 },
310 .slice => return out_stream.writeAll("(slice)"),
266 .inferred_alloc => return out_stream.writeAll("(inferred allocation value)"),311 .inferred_alloc => return out_stream.writeAll("(inferred allocation value)"),
267 .inferred_alloc_comptime => return out_stream.writeAll("(inferred comptime allocation value)"),312 .inferred_alloc_comptime => return out_stream.writeAll("(inferred comptime allocation value)"),
268 };313 };
...@@ -1653,13 +1698,18 @@ pub const Value = struct {...@@ -1653,13 +1698,18 @@ pub const Value = struct {
1653 .Null,1698 .Null,
1654 .Struct, // It sure would be nice to do something clever with structs.1699 .Struct, // It sure would be nice to do something clever with structs.
1655 => |zig_type_tag| std.hash.autoHash(hasher, zig_type_tag),1700 => |zig_type_tag| std.hash.autoHash(hasher, zig_type_tag),
1701 .Pointer => {
1702 assert(ty.isSlice(mod));
1703 const slice = val.castTag(.slice).?.data;
1704 const ptr_ty = ty.slicePtrFieldType(mod);
1705 slice.ptr.hashUncoerced(ptr_ty, hasher, mod);
1706 },
1656 .Type,1707 .Type,
1657 .Float,1708 .Float,
1658 .ComptimeFloat,1709 .ComptimeFloat,
1659 .Bool,1710 .Bool,
1660 .Int,1711 .Int,
1661 .ComptimeInt,1712 .ComptimeInt,
1662 .Pointer,
1663 .Fn,1713 .Fn,
1664 .Optional,1714 .Optional,
1665 .ErrorSet,1715 .ErrorSet,
...@@ -1799,9 +1849,15 @@ pub const Value = struct {...@@ -1799,9 +1849,15 @@ pub const Value = struct {
1799 /// Asserts the value is a single-item pointer to an array, or an array,1849 /// Asserts the value is a single-item pointer to an array, or an array,
1800 /// or an unknown-length pointer, and returns the element value at the index.1850 /// or an unknown-length pointer, and returns the element value at the index.
1801 pub fn elemValue(val: Value, mod: *Module, index: usize) Allocator.Error!Value {1851 pub fn elemValue(val: Value, mod: *Module, index: usize) Allocator.Error!Value {
1802 switch (val.toIntern()) {1852 return switch (val.ip_index) {
1803 .undef => return Value.undef,1853 .undef => Value.undef,
1804 else => return switch (mod.intern_pool.indexToKey(val.toIntern())) {1854 .none => switch (val.tag()) {
1855 .repeated => val.castTag(.repeated).?.data,
1856 .aggregate => val.castTag(.aggregate).?.data[index],
1857 .slice => val.castTag(.slice).?.data.ptr.elemValue(mod, index),
1858 else => unreachable,
1859 },
1860 else => switch (mod.intern_pool.indexToKey(val.toIntern())) {
1805 .ptr => |ptr| switch (ptr.addr) {1861 .ptr => |ptr| switch (ptr.addr) {
1806 .decl => |decl| mod.declPtr(decl).val.elemValue(mod, index),1862 .decl => |decl| mod.declPtr(decl).val.elemValue(mod, index),
1807 .mut_decl => |mut_decl| mod.declPtr(mut_decl.decl).val.elemValue(mod, index),1863 .mut_decl => |mut_decl| mod.declPtr(mut_decl.decl).val.elemValue(mod, index),
...@@ -1829,7 +1885,7 @@ pub const Value = struct {...@@ -1829,7 +1885,7 @@ pub const Value = struct {
1829 },1885 },
1830 else => unreachable,1886 else => unreachable,
1831 },1887 },
1832 }1888 };
1833 }1889 }
18341890
1835 pub fn isLazyAlign(val: Value, mod: *Module) bool {1891 pub fn isLazyAlign(val: Value, mod: *Module) bool {
...@@ -1875,25 +1931,28 @@ pub const Value = struct {...@@ -1875,25 +1931,28 @@ pub const Value = struct {
1875 }1931 }
18761932
1877 pub fn isPtrToThreadLocal(val: Value, mod: *Module) bool {1933 pub fn isPtrToThreadLocal(val: Value, mod: *Module) bool {
1878 return switch (mod.intern_pool.indexToKey(val.toIntern())) {1934 return switch (val.ip_index) {
1879 .variable => |variable| variable.is_threadlocal,1935 .none => false,
1880 .ptr => |ptr| switch (ptr.addr) {1936 else => switch (mod.intern_pool.indexToKey(val.toIntern())) {
1881 .decl => |decl_index| {1937 .variable => |variable| variable.is_threadlocal,
1882 const decl = mod.declPtr(decl_index);1938 .ptr => |ptr| switch (ptr.addr) {
1883 assert(decl.has_tv);1939 .decl => |decl_index| {
1884 return decl.val.isPtrToThreadLocal(mod);1940 const decl = mod.declPtr(decl_index);
1885 },1941 assert(decl.has_tv);
1886 .mut_decl => |mut_decl| {1942 return decl.val.isPtrToThreadLocal(mod);
1887 const decl = mod.declPtr(mut_decl.decl);1943 },
1888 assert(decl.has_tv);1944 .mut_decl => |mut_decl| {
1889 return decl.val.isPtrToThreadLocal(mod);1945 const decl = mod.declPtr(mut_decl.decl);
1946 assert(decl.has_tv);
1947 return decl.val.isPtrToThreadLocal(mod);
1948 },
1949 .int => false,
1950 .eu_payload, .opt_payload => |base_ptr| base_ptr.toValue().isPtrToThreadLocal(mod),
1951 .comptime_field => |comptime_field| comptime_field.toValue().isPtrToThreadLocal(mod),
1952 .elem, .field => |base_index| base_index.base.toValue().isPtrToThreadLocal(mod),
1890 },1953 },
1891 .int => false,1954 else => false,
1892 .eu_payload, .opt_payload => |base_ptr| base_ptr.toValue().isPtrToThreadLocal(mod),
1893 .comptime_field => |comptime_field| comptime_field.toValue().isPtrToThreadLocal(mod),
1894 .elem, .field => |base_index| base_index.base.toValue().isPtrToThreadLocal(mod),
1895 },1955 },
1896 else => false,
1897 };1956 };
1898 }1957 }
18991958
...@@ -1926,9 +1985,21 @@ pub const Value = struct {...@@ -1926,9 +1985,21 @@ pub const Value = struct {
1926 }1985 }
19271986
1928 pub fn fieldValue(val: Value, mod: *Module, index: usize) !Value {1987 pub fn fieldValue(val: Value, mod: *Module, index: usize) !Value {
1929 switch (val.toIntern()) {1988 return switch (val.ip_index) {
1930 .undef => return Value.undef,1989 .undef => Value.undef,
1931 else => return switch (mod.intern_pool.indexToKey(val.toIntern())) {1990 .none => switch (val.tag()) {
1991 .aggregate => {
1992 const field_values = val.castTag(.aggregate).?.data;
1993 return field_values[index];
1994 },
1995 .@"union" => {
1996 const payload = val.castTag(.@"union").?.data;
1997 // TODO assert the tag is correct
1998 return payload.val;
1999 },
2000 else => unreachable,
2001 },
2002 else => switch (mod.intern_pool.indexToKey(val.toIntern())) {
1932 .aggregate => |aggregate| switch (aggregate.storage) {2003 .aggregate => |aggregate| switch (aggregate.storage) {
1933 .bytes => |bytes| try mod.intern(.{ .int = .{2004 .bytes => |bytes| try mod.intern(.{ .int = .{
1934 .ty = .u8_type,2005 .ty = .u8_type,
...@@ -1941,7 +2012,7 @@ pub const Value = struct {...@@ -1941,7 +2012,7 @@ pub const Value = struct {
1941 .un => |un| un.val.toValue(),2012 .un => |un| un.val.toValue(),
1942 else => unreachable,2013 else => unreachable,
1943 },2014 },
1944 }2015 };
1945 }2016 }
19462017
1947 pub fn unionTag(val: Value, mod: *Module) Value {2018 pub fn unionTag(val: Value, mod: *Module) Value {
...@@ -1956,36 +2027,17 @@ pub const Value = struct {...@@ -1956,36 +2027,17 @@ pub const Value = struct {
1956 /// Returns a pointer to the element value at the index.2027 /// Returns a pointer to the element value at the index.
1957 pub fn elemPtr(2028 pub fn elemPtr(
1958 val: Value,2029 val: Value,
1959 ty: Type,2030 elem_ptr_ty: Type,
1960 index: usize,2031 index: usize,
1961 mod: *Module,2032 mod: *Module,
1962 ) Allocator.Error!Value {2033 ) Allocator.Error!Value {
1963 const elem_ty = ty.elemType2(mod);2034 const elem_ty = elem_ptr_ty.childType(mod);
1964 const ptr_ty_key = mod.intern_pool.indexToKey(ty.toIntern()).ptr_type;
1965 assert(ptr_ty_key.host_size == 0);
1966 assert(ptr_ty_key.bit_offset == 0);
1967 assert(ptr_ty_key.vector_index == .none);
1968 const elem_alignment = InternPool.Alignment.fromByteUnits(elem_ty.abiAlignment(mod));
1969 const alignment = switch (ptr_ty_key.alignment) {
1970 .none => .none,
1971 else => ptr_ty_key.alignment.min(
1972 @intToEnum(InternPool.Alignment, @ctz(index * elem_ty.abiSize(mod))),
1973 ),
1974 };
1975 const ptr_ty = try mod.ptrType(.{
1976 .elem_type = elem_ty.toIntern(),
1977 .alignment = if (alignment == elem_alignment) .none else alignment,
1978 .is_const = ptr_ty_key.is_const,
1979 .is_volatile = ptr_ty_key.is_volatile,
1980 .is_allowzero = ptr_ty_key.is_allowzero,
1981 .address_space = ptr_ty_key.address_space,
1982 });
1983 const ptr_val = switch (mod.intern_pool.indexToKey(val.toIntern())) {2035 const ptr_val = switch (mod.intern_pool.indexToKey(val.toIntern())) {
1984 .ptr => |ptr| ptr: {2036 .ptr => |ptr| ptr: {
1985 switch (ptr.addr) {2037 switch (ptr.addr) {
1986 .elem => |elem| if (mod.intern_pool.typeOf(elem.base).toType().elemType2(mod).eql(elem_ty, mod))2038 .elem => |elem| if (mod.intern_pool.typeOf(elem.base).toType().elemType2(mod).eql(elem_ty, mod))
1987 return (try mod.intern(.{ .ptr = .{2039 return (try mod.intern(.{ .ptr = .{
1988 .ty = ptr_ty.toIntern(),2040 .ty = elem_ptr_ty.toIntern(),
1989 .addr = .{ .elem = .{2041 .addr = .{ .elem = .{
1990 .base = elem.base,2042 .base = elem.base,
1991 .index = elem.index + index,2043 .index = elem.index + index,
...@@ -2001,7 +2053,7 @@ pub const Value = struct {...@@ -2001,7 +2053,7 @@ pub const Value = struct {
2001 else => val,2053 else => val,
2002 };2054 };
2003 return (try mod.intern(.{ .ptr = .{2055 return (try mod.intern(.{ .ptr = .{
2004 .ty = ptr_ty.toIntern(),2056 .ty = elem_ptr_ty.toIntern(),
2005 .addr = .{ .elem = .{2057 .addr = .{ .elem = .{
2006 .base = ptr_val.toIntern(),2058 .base = ptr_val.toIntern(),
2007 .index = index,2059 .index = index,
...@@ -4058,9 +4110,12 @@ pub const Value = struct {...@@ -4058,9 +4110,12 @@ pub const Value = struct {
4058 pub const Payload = struct {4110 pub const Payload = struct {
4059 tag: Tag,4111 tag: Tag,
40604112
4061 pub const SubValue = struct {4113 pub const Slice = struct {
4062 base: Payload,4114 base: Payload,
4063 data: Value,4115 data: struct {
4116 ptr: Value,
4117 len: Value,
4118 },
4064 };4119 };
40654120
4066 pub const Bytes = struct {4121 pub const Bytes = struct {
...@@ -4069,6 +4124,11 @@ pub const Value = struct {...@@ -4069,6 +4124,11 @@ pub const Value = struct {
4069 data: []const u8,4124 data: []const u8,
4070 };4125 };
40714126
4127 pub const SubValue = struct {
4128 base: Payload,
4129 data: Value,
4130 };
4131
4072 pub const Aggregate = struct {4132 pub const Aggregate = struct {
4073 base: Payload,4133 base: Payload,
4074 /// Field values. The types are according to the struct or array type.4134 /// Field values. The types are according to the struct or array type.
...@@ -4076,6 +4136,18 @@ pub const Value = struct {...@@ -4076,6 +4136,18 @@ pub const Value = struct {
4076 data: []Value,4136 data: []Value,
4077 };4137 };
40784138
4139 pub const Union = struct {
4140 pub const base_tag = Tag.@"union";
4141
4142 base: Payload = .{ .tag = base_tag },
4143 data: Data,
4144
4145 pub const Data = struct {
4146 tag: Value,
4147 val: Value,
4148 };
4149 };
4150
4079 pub const InferredAlloc = struct {4151 pub const InferredAlloc = struct {
4080 pub const base_tag = Tag.inferred_alloc;4152 pub const base_tag = Tag.inferred_alloc;
40814153
...@@ -4110,18 +4182,6 @@ pub const Value = struct {...@@ -4110,18 +4182,6 @@ pub const Value = struct {
4110 alignment: u32,4182 alignment: u32,
4111 },4183 },
4112 };4184 };
4113
4114 pub const Union = struct {
4115 pub const base_tag = Tag.@"union";
4116
4117 base: Payload = .{ .tag = base_tag },
4118 data: Data,
4119
4120 pub const Data = struct {
4121 tag: Value,
4122 val: Value,
4123 };
4124 };
4125 };4185 };
41264186
4127 pub const BigIntSpace = InternPool.Key.Int.Storage.BigIntSpace;4187 pub const BigIntSpace = InternPool.Key.Int.Storage.BigIntSpace;
tools/lldb_pretty_printers.py+6
...@@ -682,4 +682,10 @@ def __lldb_init_module(debugger, _=None):...@@ -682,4 +682,10 @@ def __lldb_init_module(debugger, _=None):
682 add(debugger, category='zig.stage2', regex=True, type='^Air\\.Inst\\.Data\\.Data__struct_[1-9][0-9]*$', inline_children=True, summary=True)682 add(debugger, category='zig.stage2', regex=True, type='^Air\\.Inst\\.Data\\.Data__struct_[1-9][0-9]*$', inline_children=True, summary=True)
683 add(debugger, category='zig.stage2', type='Module.Decl::Module.Decl.Index', synth=True)683 add(debugger, category='zig.stage2', type='Module.Decl::Module.Decl.Index', synth=True)
684 add(debugger, category='zig.stage2', type='InternPool.Index', synth=True)684 add(debugger, category='zig.stage2', type='InternPool.Index', synth=True)
685 add(debugger, category='zig.stage2', type='InternPool.Key', identifier='zig_TaggedUnion', synth=True)
686 add(debugger, category='zig.stage2', type='InternPool.Key.Int.Storage', identifier='zig_TaggedUnion', synth=True)
687 add(debugger, category='zig.stage2', type='InternPool.Key.ErrorUnion.Value', identifier='zig_TaggedUnion', synth=True)
688 add(debugger, category='zig.stage2', type='InternPool.Key.Float.Storage', identifier='zig_TaggedUnion', synth=True)
689 add(debugger, category='zig.stage2', type='InternPool.Key.Ptr.Addr', identifier='zig_TaggedUnion', synth=True)
690 add(debugger, category='zig.stage2', type='InternPool.Key.Aggregate.Storage', identifier='zig_TaggedUnion', synth=True)
685 add(debugger, category='zig.stage2', type='arch.x86_64.CodeGen.MCValue', identifier='zig_TaggedUnion', synth=True, inline_children=True, summary=True)691 add(debugger, category='zig.stage2', type='arch.x86_64.CodeGen.MCValue', identifier='zig_TaggedUnion', synth=True, inline_children=True, summary=True)