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 {
186186 /// Allocates stack local memory.
187187 /// Uses the `ty` field.
188188 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,
189197 /// If the function will pass the result by-ref, this instruction returns the
190198 /// result pointer. Otherwise it is equivalent to `alloc`.
191199 /// Uses the `ty` field.
......@@ -397,9 +405,6 @@ pub const Inst = struct {
397405 /// was executed on the operand.
398406 /// Uses the `ty_pl` field. Payload is `TryPtr`.
399407 try_ptr,
400 /// A comptime-known value. Uses the `ty_pl` field, payload is index of
401 /// `values` array.
402 constant,
403408 /// A comptime-known value via an index into the InternPool.
404409 /// Uses the `interned` field.
405410 interned,
......@@ -1265,7 +1270,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index, ip: InternPool) Type {
12651270
12661271 .assembly,
12671272 .block,
1268 .constant,
12691273 .struct_field_ptr,
12701274 .struct_field_val,
12711275 .slice_elem_ptr,
......@@ -1283,6 +1287,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index, ip: InternPool) Type {
12831287 .sub_with_overflow,
12841288 .mul_with_overflow,
12851289 .shl_with_overflow,
1290 .inferred_alloc,
1291 .inferred_alloc_comptime,
12861292 .ptr_add,
12871293 .ptr_sub,
12881294 .try_ptr,
......@@ -1495,7 +1501,6 @@ pub fn value(air: Air, inst: Inst.Ref, mod: *Module) !?Value {
14951501 const inst_index = @intCast(Air.Inst.Index, ref_int - ref_start_index);
14961502 const air_datas = air.instructions.items(.data);
14971503 switch (air.instructions.items(.tag)[inst_index]) {
1498 .constant => return air.values[air_datas[inst_index].ty_pl.payload],
14991504 .interned => return air_datas[inst_index].interned.toValue(),
15001505 else => return air.typeOfIndex(inst_index, mod.intern_pool).onePossibleValue(mod),
15011506 }
......@@ -1603,6 +1608,8 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: InternPool) bool {
16031608 .mul_with_overflow,
16041609 .shl_with_overflow,
16051610 .alloc,
1611 .inferred_alloc,
1612 .inferred_alloc_comptime,
16061613 .ret_ptr,
16071614 .bit_and,
16081615 .bit_or,
......@@ -1651,7 +1658,6 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: InternPool) bool {
16511658 .cmp_neq_optimized,
16521659 .cmp_vector,
16531660 .cmp_vector_optimized,
1654 .constant,
16551661 .interned,
16561662 .is_null,
16571663 .is_non_null,
src/InternPool.zig+14-4
......@@ -515,10 +515,12 @@ pub const Key = union(enum) {
515515
516516 pub const ErrorUnion = struct {
517517 ty: Index,
518 val: union(enum) {
518 val: Value,
519
520 pub const Value = union(enum) {
519521 err_name: NullTerminatedString,
520522 payload: Index,
521 },
523 };
522524 };
523525
524526 pub const EnumTag = struct {
......@@ -1068,7 +1070,7 @@ pub const Key = union(enum) {
10681070 .false, .true => .bool_type,
10691071 .empty_struct => .empty_struct_type,
10701072 .@"unreachable" => .noreturn_type,
1071 .generic_poison => unreachable,
1073 .generic_poison => .generic_poison_type,
10721074 },
10731075 };
10741076 }
......@@ -2671,6 +2673,10 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
26712673 .only_possible_value => {
26722674 const ty = @intToEnum(Index, data);
26732675 return switch (ip.indexToKey(ty)) {
2676 .array_type, .vector_type => .{ .aggregate = .{
2677 .ty = ty,
2678 .storage = .{ .elems = &.{} },
2679 } },
26742680 // TODO: migrate structs to properly use the InternPool rather
26752681 // than using the SegmentedList trick, then the struct type will
26762682 // 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 {
31843190 assert(!(try ip.map.getOrPutAdapted(gpa, key, adapter)).found_existing);
31853191 try ip.items.ensureUnusedCapacity(gpa, 1);
31863192 ip.items.appendAssumeCapacity(.{
3187 .tag = .ptr_elem,
3193 .tag = switch (ptr.addr) {
3194 .elem => .ptr_elem,
3195 .field => .ptr_field,
3196 else => unreachable,
3197 },
31883198 .data = try ip.addExtra(gpa, PtrBaseIndex{
31893199 .ty = ptr.ty,
31903200 .base = base_index.base,
src/Liveness.zig+6-16
......@@ -321,8 +321,9 @@ pub fn categorizeOperand(
321321
322322 .arg,
323323 .alloc,
324 .inferred_alloc,
325 .inferred_alloc_comptime,
324326 .ret_ptr,
325 .constant,
326327 .interned,
327328 .trap,
328329 .breakpoint,
......@@ -973,9 +974,7 @@ fn analyzeInst(
973974 .work_group_id,
974975 => return analyzeOperands(a, pass, data, inst, .{ .none, .none, .none }),
975976
976 .constant,
977 .interned,
978 => unreachable,
977 .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable,
979978
980979 .trap,
981980 .unreach,
......@@ -1269,10 +1268,7 @@ fn analyzeOperands(
12691268 const operand = Air.refToIndexAllowNone(op_ref) orelse continue;
12701269
12711270 // Don't compute any liveness for constants
1272 switch (inst_tags[operand]) {
1273 .constant, .interned => continue,
1274 else => {},
1275 }
1271 if (inst_tags[operand] == .interned) continue;
12761272
12771273 _ = try data.live_set.put(gpa, operand, {});
12781274 }
......@@ -1305,10 +1301,7 @@ fn analyzeOperands(
13051301 const operand = Air.refToIndexAllowNone(op_ref) orelse continue;
13061302
13071303 // Don't compute any liveness for constants
1308 switch (inst_tags[operand]) {
1309 .constant, .interned => continue,
1310 else => {},
1311 }
1304 if (inst_tags[operand] == .interned) continue;
13121305
13131306 const mask = @as(Bpi, 1) << @intCast(OperandInt, i);
13141307
......@@ -1839,10 +1832,7 @@ fn AnalyzeBigOperands(comptime pass: LivenessPass) type {
18391832
18401833 // Don't compute any liveness for constants
18411834 const inst_tags = big.a.air.instructions.items(.tag);
1842 switch (inst_tags[operand]) {
1843 .constant, .interned => return,
1844 else => {},
1845 }
1835 if (inst_tags[operand] == .interned) return
18461836
18471837 // If our result is unused and the instruction doesn't need to be lowered, backends will
18481838 // 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 {
4141 // no operands
4242 .arg,
4343 .alloc,
44 .inferred_alloc,
45 .inferred_alloc_comptime,
4446 .ret_ptr,
45 .constant,
4647 .interned,
4748 .breakpoint,
4849 .dbg_stmt,
......@@ -554,16 +555,18 @@ fn verifyDeath(self: *Verify, inst: Air.Inst.Index, operand: Air.Inst.Index) Err
554555}
555556
556557fn 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 switch (self.air.instructions.items(.tag)[operand]) {
559 .constant, .interned => {},
560 else => {
561 if (dies) {
562 if (!self.live.remove(operand)) return invalid("%{}: dead operand %{} reused and killed again", .{ inst, operand });
563 } else {
564 if (!self.live.contains(operand)) return invalid("%{}: dead operand %{} reused", .{ inst, operand });
565 }
566 },
558 const operand = Air.refToIndexAllowNone(op_ref) orelse {
559 assert(!dies);
560 return;
561 };
562 if (self.air.instructions.items(.tag)[operand] == .interned) {
563 assert(!dies);
564 return;
565 }
566 if (dies) {
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 });
567570 }
568571}
569572
......@@ -576,16 +579,11 @@ fn verifyInst(
576579 const dies = self.liveness.operandDies(inst, @intCast(Liveness.OperandInt, operand_index));
577580 try self.verifyOperand(inst, operand, dies);
578581 }
579 const tag = self.air.instructions.items(.tag);
580 switch (tag[inst]) {
581 .constant, .interned => unreachable,
582 else => {
583 if (self.liveness.isUnused(inst)) {
584 assert(!self.live.contains(inst));
585 } else {
586 try self.live.putNoClobber(self.gpa, inst, {});
587 }
588 },
582 if (self.air.instructions.items(.tag)[inst] == .interned) return;
583 if (self.liveness.isUnused(inst)) {
584 assert(!self.live.contains(inst));
585 } else {
586 try self.live.putNoClobber(self.gpa, inst, {});
589587 }
590588}
591589
src/Module.zig+1-8
......@@ -764,14 +764,7 @@ pub const Decl = struct {
764764
765765 pub fn typedValue(decl: Decl) error{AnalysisFail}!TypedValue {
766766 if (!decl.has_tv) return error.AnalysisFail;
767 return TypedValue{
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;
767 return TypedValue{ .ty = decl.ty, .val = decl.val };
775768 }
776769
777770 pub fn isFunction(decl: Decl, mod: *const Module) !bool {
src/Sema.zig+585-660
......@@ -1991,23 +1991,21 @@ fn resolveMaybeUndefValAllowVariablesMaybeRuntime(
19911991 const i = int - InternPool.static_len;
19921992 const air_tags = sema.air_instructions.items(.tag);
19931993 if (try sema.typeHasOnePossibleValue(sema.typeOf(inst))) |opv| {
1994 if (air_tags[i] == .constant) {
1995 const ty_pl = sema.air_instructions.items(.data)[i].ty_pl;
1996 const val = sema.air_values.items[ty_pl.payload];
1994 if (air_tags[i] == .interned) {
1995 const interned = sema.air_instructions.items(.data)[i].interned;
1996 const val = interned.toValue();
19971997 if (val.getVariable(sema.mod) != null) return val;
19981998 }
19991999 return opv;
20002000 }
20012001 const air_datas = sema.air_instructions.items(.data);
20022002 switch (air_tags[i]) {
2003 .constant => {
2004 const ty_pl = air_datas[i].ty_pl;
2005 const val = sema.air_values.items[ty_pl.payload];
2003 .interned => {
2004 const val = air_datas[i].interned.toValue();
20062005 if (val.isRuntimeValue(sema.mod)) make_runtime.* = true;
20072006 if (val.isPtrToThreadLocal(sema.mod)) make_runtime.* = true;
20082007 return val;
20092008 },
2010 .interned => return air_datas[i].interned.toValue(),
20112009 else => return null,
20122010 }
20132011}
......@@ -2440,64 +2438,64 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
24402438 const addr_space = target_util.defaultAddressSpace(target, .local);
24412439
24422440 if (Air.refToIndex(ptr)) |ptr_inst| {
2443 if (sema.air_instructions.items(.tag)[ptr_inst] == .constant) {
2444 const air_datas = sema.air_instructions.items(.data);
2445 const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload];
2446 switch (ptr_val.tag()) {
2447 .inferred_alloc => {
2448 const inferred_alloc = &ptr_val.castTag(.inferred_alloc).?.data;
2449 // Add the stored instruction to the set we will use to resolve peer types
2450 // for the inferred allocation.
2451 // This instruction will not make it to codegen; it is only to participate
2452 // in the `stored_inst_list` of the `inferred_alloc`.
2453 var trash_block = block.makeSubBlock();
2454 defer trash_block.instructions.deinit(sema.gpa);
2455 const operand = try trash_block.addBitCast(pointee_ty, .void_value);
2456
2457 const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
2458 .pointee_type = pointee_ty,
2459 .@"align" = inferred_alloc.alignment,
2460 .@"addrspace" = addr_space,
2461 });
2462 const bitcasted_ptr = try block.addBitCast(ptr_ty, ptr);
2441 switch (sema.air_instructions.items(.tag)[ptr_inst]) {
2442 .inferred_alloc => {
2443 const air_datas = sema.air_instructions.items(.data);
2444 const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload];
2445 const inferred_alloc = &ptr_val.castTag(.inferred_alloc).?.data;
2446 // Add the stored instruction to the set we will use to resolve peer types
2447 // for the inferred allocation.
2448 // This instruction will not make it to codegen; it is only to participate
2449 // in the `stored_inst_list` of the `inferred_alloc`.
2450 var trash_block = block.makeSubBlock();
2451 defer trash_block.instructions.deinit(sema.gpa);
2452 const operand = try trash_block.addBitCast(pointee_ty, .void_value);
2453
2454 const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
2455 .pointee_type = pointee_ty,
2456 .@"align" = inferred_alloc.alignment,
2457 .@"addrspace" = addr_space,
2458 });
2459 const bitcasted_ptr = try block.addBitCast(ptr_ty, ptr);
24632460
2464 try inferred_alloc.prongs.append(sema.arena, .{
2465 .stored_inst = operand,
2466 .placeholder = Air.refToIndex(bitcasted_ptr).?,
2467 });
2461 try inferred_alloc.prongs.append(sema.arena, .{
2462 .stored_inst = operand,
2463 .placeholder = Air.refToIndex(bitcasted_ptr).?,
2464 });
24682465
2469 return bitcasted_ptr;
2470 },
2471 .inferred_alloc_comptime => {
2472 const iac = ptr_val.castTag(.inferred_alloc_comptime).?;
2473 // There will be only one coerce_result_ptr because we are running at comptime.
2474 // The alloc will turn into a Decl.
2475 var anon_decl = try block.startAnonDecl();
2476 defer anon_decl.deinit();
2477 iac.data.decl_index = try anon_decl.finish(
2478 pointee_ty,
2479 Value.undef,
2480 iac.data.alignment,
2481 );
2482 if (iac.data.alignment != 0) {
2483 try sema.resolveTypeLayout(pointee_ty);
2484 }
2485 const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
2486 .pointee_type = pointee_ty,
2487 .@"align" = iac.data.alignment,
2488 .@"addrspace" = addr_space,
2489 });
2490 try sema.maybeQueueFuncBodyAnalysis(iac.data.decl_index);
2491 return sema.addConstant(ptr_ty, (try sema.mod.intern(.{ .ptr = .{
2492 .ty = ptr_ty.toIntern(),
2493 .addr = .{ .mut_decl = .{
2494 .decl = iac.data.decl_index,
2495 .runtime_index = block.runtime_index,
2496 } },
2497 } })).toValue());
2498 },
2499 else => {},
2500 }
2466 return bitcasted_ptr;
2467 },
2468 .inferred_alloc_comptime => {
2469 const air_datas = sema.air_instructions.items(.data);
2470 const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload];
2471 const iac = ptr_val.castTag(.inferred_alloc_comptime).?;
2472 // There will be only one coerce_result_ptr because we are running at comptime.
2473 // The alloc will turn into a Decl.
2474 var anon_decl = try block.startAnonDecl();
2475 defer anon_decl.deinit();
2476 iac.data.decl_index = try anon_decl.finish(
2477 pointee_ty,
2478 Value.undef,
2479 iac.data.alignment,
2480 );
2481 if (iac.data.alignment != 0) {
2482 try sema.resolveTypeLayout(pointee_ty);
2483 }
2484 const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
2485 .pointee_type = pointee_ty,
2486 .@"align" = iac.data.alignment,
2487 .@"addrspace" = addr_space,
2488 });
2489 try sema.maybeQueueFuncBodyAnalysis(iac.data.decl_index);
2490 return sema.addConstant(ptr_ty, (try sema.mod.intern(.{ .ptr = .{
2491 .ty = ptr_ty.toIntern(),
2492 .addr = .{ .mut_decl = .{
2493 .decl = iac.data.decl_index,
2494 .runtime_index = block.runtime_index,
2495 } },
2496 } })).toValue());
2497 },
2498 else => {},
25012499 }
25022500 }
25032501
......@@ -3458,6 +3456,7 @@ fn zirAllocExtended(
34583456 block: *Block,
34593457 extended: Zir.Inst.Extended.InstData,
34603458) CompileError!Air.Inst.Ref {
3459 const gpa = sema.gpa;
34613460 const extra = sema.code.extraData(Zir.Inst.AllocExtended, extended.operand);
34623461 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = extra.data.src_node };
34633462 const align_src: LazySrcLoc = .{ .node_offset_var_decl_align = extra.data.src_node };
......@@ -3487,13 +3486,19 @@ fn zirAllocExtended(
34873486 if (small.has_type) {
34883487 return sema.analyzeComptimeAlloc(block, var_ty, alignment);
34893488 } else {
3490 return sema.addConstant(
3491 inferred_alloc_ty,
3492 try Value.Tag.inferred_alloc_comptime.create(sema.arena, .{
3493 .decl_index = undefined,
3494 .alignment = alignment,
3495 }),
3496 );
3489 const ty_inst = try sema.addType(inferred_alloc_ty);
3490 try sema.air_values.append(gpa, try Value.Tag.inferred_alloc_comptime.create(sema.arena, .{
3491 .decl_index = undefined,
3492 .alignment = alignment,
3493 }));
3494 try sema.air_instructions.append(gpa, .{
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));
34973502 }
34983503 }
34993504
......@@ -3511,17 +3516,19 @@ fn zirAllocExtended(
35113516 return block.addTy(.alloc, ptr_type);
35123517 }
35133518
3514 // `Sema.addConstant` does not add the instruction to the block because it is
3515 // not needed in the case of constant values. However here, we plan to "downgrade"
3516 // to a normal instruction when we hit `resolve_inferred_alloc`. So we append
3517 // to the block even though it is currently a `.constant`.
3518 const result = try sema.addConstant(
3519 inferred_alloc_ty,
3520 try Value.Tag.inferred_alloc.create(sema.arena, .{ .alignment = alignment }),
3521 );
3522 try block.instructions.append(sema.gpa, Air.refToIndex(result).?);
3523 try sema.unresolved_inferred_allocs.putNoClobber(sema.gpa, Air.refToIndex(result).?, {});
3524 return result;
3519 const ty_inst = try sema.addType(inferred_alloc_ty);
3520 try sema.air_values.append(gpa, try Value.Tag.inferred_alloc.create(sema.arena, .{
3521 .alignment = alignment,
3522 }));
3523 const result_index = try block.addInstAsIndex(.{
3524 .tag = .inferred_alloc,
3525 .data = .{ .ty_pl = .{
3526 .ty = ty_inst,
3527 .payload = @intCast(u32, sema.air_values.items.len - 1),
3528 } },
3529 });
3530 try sema.unresolved_inferred_allocs.putNoClobber(gpa, result_index, {});
3531 return Air.indexToRef(result_index);
35253532}
35263533
35273534fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -3616,16 +3623,24 @@ fn zirAllocInferredComptime(
36163623 inst: Zir.Inst.Index,
36173624 inferred_alloc_ty: Type,
36183625) CompileError!Air.Inst.Ref {
3626 const gpa = sema.gpa;
36193627 const src_node = sema.code.instructions.items(.data)[inst].node;
36203628 const src = LazySrcLoc.nodeOffset(src_node);
36213629 sema.src = src;
3622 return sema.addConstant(
3623 inferred_alloc_ty,
3624 try Value.Tag.inferred_alloc_comptime.create(sema.arena, .{
3625 .decl_index = undefined,
3626 .alignment = 0,
3627 }),
3628 );
3630
3631 const ty_inst = try sema.addType(inferred_alloc_ty);
3632 try sema.air_values.append(gpa, try Value.Tag.inferred_alloc_comptime.create(sema.arena, .{
3633 .decl_index = undefined,
3634 .alignment = 0,
3635 }));
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));
36293644}
36303645
36313646fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -3676,31 +3691,39 @@ fn zirAllocInferred(
36763691 const tracy = trace(@src());
36773692 defer tracy.end();
36783693
3694 const gpa = sema.gpa;
36793695 const src_node = sema.code.instructions.items(.data)[inst].node;
36803696 const src = LazySrcLoc.nodeOffset(src_node);
36813697 sema.src = src;
36823698
3699 const ty_inst = try sema.addType(inferred_alloc_ty);
36833700 if (block.is_comptime) {
3684 return sema.addConstant(
3685 inferred_alloc_ty,
3686 try Value.Tag.inferred_alloc_comptime.create(sema.arena, .{
3687 .decl_index = undefined,
3688 .alignment = 0,
3689 }),
3690 );
3701 try sema.air_values.append(gpa, try Value.Tag.inferred_alloc_comptime.create(sema.arena, .{
3702 .decl_index = undefined,
3703 .alignment = 0,
3704 }));
3705 try sema.air_instructions.append(gpa, .{
3706 .tag = .inferred_alloc_comptime,
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));
36913713 }
36923714
3693 // `Sema.addConstant` does not add the instruction to the block because it is
3694 // not needed in the case of constant values. However here, we plan to "downgrade"
3695 // to a normal instruction when we hit `resolve_inferred_alloc`. So we append
3696 // to the block even though it is currently a `.constant`.
3697 const result = try sema.addConstant(
3698 inferred_alloc_ty,
3699 try Value.Tag.inferred_alloc.create(sema.arena, .{ .alignment = 0 }),
3700 );
3701 try block.instructions.append(sema.gpa, Air.refToIndex(result).?);
3702 try sema.unresolved_inferred_allocs.putNoClobber(sema.gpa, Air.refToIndex(result).?, {});
3703 return result;
3715 try sema.air_values.append(gpa, try Value.Tag.inferred_alloc.create(sema.arena, .{
3716 .alignment = 0,
3717 }));
3718 const result_index = try block.addInstAsIndex(.{
3719 .tag = .inferred_alloc,
3720 .data = .{ .ty_pl = .{
3721 .ty = ty_inst,
3722 .payload = @intCast(u32, sema.air_values.items.len - 1),
3723 } },
3724 });
3725 try sema.unresolved_inferred_allocs.putNoClobber(gpa, result_index, {});
3726 return Air.indexToRef(result_index);
37043727}
37053728
37063729fn 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
37123735 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
37133736 const ptr = try sema.resolveInst(inst_data.operand);
37143737 const ptr_inst = Air.refToIndex(ptr).?;
3715 assert(sema.air_instructions.items(.tag)[ptr_inst] == .constant);
37163738 const value_index = sema.air_instructions.items(.data)[ptr_inst].ty_pl.payload;
37173739 const ptr_val = sema.air_values.items[value_index];
37183740 const var_is_mut = switch (sema.typeOf(ptr).toIntern()) {
......@@ -3722,7 +3744,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
37223744 };
37233745 const target = sema.mod.getTarget();
37243746
3725 switch (ptr_val.tag()) {
3747 switch (sema.air_instructions.items(.tag)[ptr_inst]) {
37263748 .inferred_alloc_comptime => {
37273749 const iac = ptr_val.castTag(.inferred_alloc_comptime).?;
37283750 const decl_index = iac.data.decl_index;
......@@ -3767,7 +3789,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
37673789 // Detect if the value is comptime-known. In such case, the
37683790 // last 3 AIR instructions of the block will look like this:
37693791 //
3770 // %a = constant
3792 // %a = interned
37713793 // %b = bitcast(%a)
37723794 // %c = store(%b, %d)
37733795 //
......@@ -3814,7 +3836,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
38143836 const candidate = block.instructions.items[search_index];
38153837 switch (air_tags[candidate]) {
38163838 .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue,
3817 .constant => break candidate,
3839 .interned => break candidate,
38183840 else => break :ct,
38193841 }
38203842 };
......@@ -4981,15 +5003,15 @@ fn zirStoreToBlockPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
49815003 const src: LazySrcLoc = sema.src;
49825004 blk: {
49835005 const ptr_inst = Air.refToIndex(ptr) orelse break :blk;
4984 if (sema.air_instructions.items(.tag)[ptr_inst] != .constant) break :blk;
4985 const air_datas = sema.air_instructions.items(.data);
4986 const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload];
4987 switch (ptr_val.tag()) {
5006 const air_data = sema.air_instructions.items(.data)[ptr_inst];
5007 switch (sema.air_instructions.items(.tag)[ptr_inst]) {
49885008 .inferred_alloc_comptime => {
5009 const ptr_val = sema.air_values.items[air_data.ty_pl.payload];
49895010 const iac = ptr_val.castTag(.inferred_alloc_comptime).?;
49905011 return sema.storeToInferredAllocComptime(block, src, operand, iac);
49915012 },
49925013 .inferred_alloc => {
5014 const ptr_val = sema.air_values.items[air_data.ty_pl.payload];
49935015 const inferred_alloc = ptr_val.castTag(.inferred_alloc).?;
49945016 return sema.storeToInferredAlloc(block, ptr, operand, inferred_alloc);
49955017 },
......@@ -5009,11 +5031,10 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi
50095031 const ptr = try sema.resolveInst(bin_inst.lhs);
50105032 const operand = try sema.resolveInst(bin_inst.rhs);
50115033 const ptr_inst = Air.refToIndex(ptr).?;
5012 assert(sema.air_instructions.items(.tag)[ptr_inst] == .constant);
50135034 const air_datas = sema.air_instructions.items(.data);
50145035 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]) {
50175038 .inferred_alloc_comptime => {
50185039 const iac = ptr_val.castTag(.inferred_alloc_comptime).?;
50195040 return sema.storeToInferredAllocComptime(block, src, operand, iac);
......@@ -6988,16 +7009,7 @@ fn analyzeCall(
69887009 const res2: Air.Inst.Ref = res2: {
69897010 if (should_memoize and is_comptime_call) {
69907011 if (mod.memoized_calls.getContext(memoized_call_key, .{ .module = mod })) |result| {
6991 const ty_inst = try sema.addType(fn_ret_ty);
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);
7012 break :res2 try sema.addConstant(fn_ret_ty, result.val);
70017013 }
70027014 }
70037015
......@@ -9407,7 +9419,7 @@ fn zirParam(
94079419 if (is_comptime) {
94089420 // If this is a comptime parameter we can add a constant generic_poison
94099421 // 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);
94119423 sema.inst_map.putAssumeCapacityNoClobber(inst, result);
94129424 } else {
94139425 // Otherwise we need a dummy runtime instruction.
......@@ -15104,7 +15116,7 @@ fn analyzePtrArithmetic(
1510415116 if (air_tag == .ptr_sub) {
1510515117 return sema.fail(block, op_src, "TODO implement Sema comptime pointer subtraction", .{});
1510615118 }
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);
1510815120 return sema.addConstant(new_ptr_ty, new_ptr_val);
1510915121 } else break :rs offset_src;
1511015122 } else break :rs ptr_src;
......@@ -25378,8 +25390,8 @@ fn elemPtrOneLayerOnly(
2537825390 const ptr_val = maybe_ptr_val orelse break :rs indexable_src;
2537925391 const index_val = maybe_index_val orelse break :rs elem_index_src;
2538025392 const index = @intCast(usize, index_val.toUnsignedInt(mod));
25381 const elem_ptr = try ptr_val.elemPtr(indexable_ty, index, mod);
2538225393 const result_ty = try sema.elemPtrType(indexable_ty, index);
25394 const elem_ptr = try ptr_val.elemPtr(result_ty, index, mod);
2538325395 return sema.addConstant(result_ty, elem_ptr);
2538425396 };
2538525397 const result_ty = try sema.elemPtrType(indexable_ty, null);
......@@ -25424,8 +25436,9 @@ fn elemVal(
2542425436 const indexable_val = maybe_indexable_val orelse break :rs indexable_src;
2542525437 const index_val = maybe_index_val orelse break :rs elem_index_src;
2542625438 const index = @intCast(usize, index_val.toUnsignedInt(mod));
25427 const elem_ptr_val = try indexable_val.elemPtr(indexable_ty, index, mod);
25428 if (try sema.pointerDeref(block, indexable_src, elem_ptr_val, indexable_ty)) |elem_val| {
25439 const elem_ptr_ty = try sema.elemPtrType(indexable_ty, index);
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| {
2542925442 return sema.addConstant(indexable_ty.elemType2(mod), elem_val);
2543025443 }
2543125444 break :rs indexable_src;
......@@ -25684,7 +25697,7 @@ fn elemPtrArray(
2568425697 return sema.addConstUndef(elem_ptr_ty);
2568525698 }
2568625699 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);
2568825701 return sema.addConstant(elem_ptr_ty, elem_ptr);
2568925702 }
2569025703 }
......@@ -25740,8 +25753,9 @@ fn elemValSlice(
2574025753 const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else "";
2574125754 return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label });
2574225755 }
25743 const elem_ptr_val = try slice_val.elemPtr(slice_ty, index, mod);
25744 if (try sema.pointerDeref(block, slice_src, elem_ptr_val, slice_ty)) |elem_val| {
25756 const elem_ptr_ty = try sema.elemPtrType(slice_ty, index);
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| {
2574525759 return sema.addConstant(elem_ty, elem_val);
2574625760 }
2574725761 runtime_src = slice_src;
......@@ -25800,7 +25814,7 @@ fn elemPtrSlice(
2580025814 const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else "";
2580125815 return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label });
2580225816 }
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);
2580425818 return sema.addConstant(elem_ptr_ty, elem_ptr_val);
2580525819 }
2580625820 }
......@@ -25916,7 +25930,10 @@ fn coerceExtra(
2591625930
2591725931 // null to ?T
2591825932 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());
2592025937 }
2592125938
2592225939 // cast from ?*T and ?[*]T to ?*anyopaque
......@@ -27665,43 +27682,40 @@ fn storePtrVal(
2766527682 switch (mut_kit.pointee) {
2766627683 .direct => |val_ptr| {
2766727684 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)) {
2766927686 // TODO use failWithInvalidComptimeFieldStore
2767027687 return sema.fail(block, src, "value stored in comptime field does not match the default value of the field", .{});
2767127688 }
2767227689 return;
2767327690 }
27674 const arena = mut_kit.beginArena(sema.mod);
27675 defer mut_kit.finishArena(sema.mod);
27676
27677 val_ptr.* = try operand_val.copy(arena);
27691 val_ptr.* = (try operand_val.intern(operand_ty, mod)).toValue();
2767827692 },
2767927693 .reinterpret => |reinterpret| {
2768027694 const abi_size = try sema.usizeCast(block, src, mut_kit.ty.abiSize(mod));
2768127695 const buffer = try sema.gpa.alloc(u8, abi_size);
2768227696 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) {
2768427698 error.OutOfMemory => return error.OutOfMemory,
2768527699 error.ReinterpretDeclRef => unreachable,
2768627700 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)}),
2768827702 };
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) {
2769027704 error.OutOfMemory => return error.OutOfMemory,
2769127705 error.ReinterpretDeclRef => unreachable,
2769227706 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)}),
2769427708 };
2769527709
27696 const arena = mut_kit.beginArena(sema.mod);
27697 defer mut_kit.finishArena(sema.mod);
27710 const arena = mut_kit.beginArena(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();
2770027714 },
2770127715 .bad_decl_ty, .bad_ptr_ty => {
2770227716 // TODO show the decl declaration site in a note and explain whether the decl
2770327717 // 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)});
2770527719 },
2770627720 }
2770727721}
......@@ -27754,7 +27768,7 @@ fn beginComptimePtrMutation(
2775427768 const mod = sema.mod;
2775527769 const ptr = mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr;
2775627770 switch (ptr.addr) {
27757 .decl => unreachable, // isComptimeMutablePtr has been checked already
27771 .decl, .int => unreachable, // isComptimeMutablePtr has been checked already
2775827772 .mut_decl => |mut_decl| {
2775927773 const decl = mod.declPtr(mut_decl.decl);
2776027774 return sema.beginComptimePtrMutationInner(block, src, decl.ty, &decl.val, ptr_elem_ty, mut_decl);
......@@ -27767,546 +27781,472 @@ fn beginComptimePtrMutation(
2776727781 .runtime_index = .comptime_field_ptr,
2776827782 });
2776927783 },
27770 else => unreachable,
27771 }
27772 if (true) unreachable;
27773 switch (ptr_val.toIntern()) {
27774 .none => switch (ptr_val.tag()) {
27775 .decl_ref_mut => {
27776 const decl_ref_mut = ptr_val.castTag(.decl_ref_mut).?.data;
27777 const decl = sema.mod.declPtr(decl_ref_mut.decl_index);
27778 return sema.beginComptimePtrMutationInner(block, src, decl.ty, &decl.val, ptr_elem_ty, decl_ref_mut);
27779 },
27780 .comptime_field_ptr => {
27781 const payload = ptr_val.castTag(.comptime_field_ptr).?.data;
27782 const duped = try sema.arena.create(Value);
27783 duped.* = payload.field_val;
27784 return sema.beginComptimePtrMutationInner(block, src, payload.field_ty, duped, ptr_elem_ty, .{
27785 .decl_index = @intToEnum(Module.Decl.Index, 0),
27786 .runtime_index = .comptime_field_ptr,
27787 });
27788 },
27789 .elem_ptr => {
27790 const elem_ptr = ptr_val.castTag(.elem_ptr).?.data;
27791 var parent = try sema.beginComptimePtrMutation(block, src, elem_ptr.array_ptr, elem_ptr.elem_ty);
27792
27793 switch (parent.pointee) {
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 }
27784 .eu_payload => |eu_ptr| {
27785 const eu_ty = mod.intern_pool.typeOf(eu_ptr).toType().childType(mod);
27786 var parent = try sema.beginComptimePtrMutation(block, src, eu_ptr.toValue(), eu_ty);
27787 switch (parent.pointee) {
27788 .direct => |val_ptr| {
27789 const payload_ty = parent.ty.errorUnionPayload(mod);
27790 if (val_ptr.ip_index == .none and val_ptr.tag() == .eu_payload) {
27791 return ComptimePtrMutationKit{
27792 .mut_decl = parent.mut_decl,
27793 .pointee = .{ .direct = &val_ptr.castTag(.eu_payload).?.data },
27794 .ty = payload_ty,
27795 };
27796 } else {
27797 // An error union has been initialized to undefined at comptime and now we
27798 // are for the first time setting the payload. We must change the
27799 // representation of the error union from `undef` to `opt_payload`.
27800 const arena = parent.beginArena(sema.mod);
27801 defer parent.finishArena(sema.mod);
27802
27803 const payload = try arena.create(Value.Payload.SubValue);
27804 payload.* = .{
27805 .base = .{ .tag = .eu_payload },
27806 .data = Value.undef,
27807 };
2782027808
27821 switch (val_ptr.toIntern()) {
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);
27809 val_ptr.* = Value.initPayload(&payload.base);
2782827810
27829 const array_len_including_sentinel =
27830 try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel(mod));
27831 const elems = try arena.alloc(Value, array_len_including_sentinel);
27832 @memset(elems, Value.undef);
27811 return ComptimePtrMutationKit{
27812 .mut_decl = parent.mut_decl,
27813 .pointee = .{ .direct = &payload.data },
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(
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 ),
27848 val_ptr.* = Value.initPayload(&payload.base);
2795327849
27954 .the_only_possible_value => {
27955 const duped = try sema.arena.create(Value);
27956 duped.* = Value.initTag(.the_only_possible_value);
27957 return beginComptimePtrMutationInner(
27958 sema,
27959 block,
27960 src,
27961 elem_ty,
27962 duped,
27963 ptr_elem_ty,
27964 parent.decl_ref_mut,
27965 );
27966 },
27850 return ComptimePtrMutationKit{
27851 .mut_decl = parent.mut_decl,
27852 .pointee = .{ .direct = &payload.data },
27853 .ty = payload_ty,
27854 };
27855 },
27856 .none => switch (val_ptr.tag()) {
27857 .opt_payload => return ComptimePtrMutationKit{
27858 .mut_decl = parent.mut_decl,
27859 .pointee = .{ .direct = &val_ptr.castTag(.opt_payload).?.data },
27860 .ty = payload_ty,
27861 },
2796727862
27968 else => unreachable,
27969 },
27970 else => unreachable,
27971 }
27863 else => return ComptimePtrMutationKit{
27864 .mut_decl = parent.mut_decl,
27865 .pointee = .{ .direct = val_ptr },
27866 .ty = payload_ty,
27867 },
2797227868 },
27973 else => {
27974 if (elem_ptr.index != 0) {
27975 // TODO include a "declared here" note for the decl
27976 return sema.fail(block, src, "out of bounds comptime store of index {d}", .{
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 );
27869 else => return ComptimePtrMutationKit{
27870 .mut_decl = parent.mut_decl,
27871 .pointee = .{ .direct = val_ptr },
27872 .ty = payload_ty,
2798927873 },
27990 },
27991 .reinterpret => |reinterpret| {
27992 if (!elem_ptr.elem_ty.hasWellDefinedLayout(mod)) {
27993 // Even though the parent value type has well-defined memory layout, our
27994 // pointer type does not.
27995 return ComptimePtrMutationKit{
27996 .decl_ref_mut = parent.decl_ref_mut,
27997 .pointee = .bad_ptr_ty,
27998 .ty = elem_ptr.elem_ty,
27874 }
27875 },
27876 .bad_decl_ty, .bad_ptr_ty => return parent,
27877 // Even though the parent value type has well-defined memory layout, our
27878 // pointer type does not.
27879 .reinterpret => return ComptimePtrMutationKit{
27880 .mut_decl = parent.mut_decl,
27881 .pointee = .bad_ptr_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,
2799927915 };
2800027916 }
2800127917
28002 const elem_abi_size_u64 = try sema.typeAbiSize(elem_ptr.elem_ty);
28003 const elem_abi_size = try sema.usizeCast(block, src, elem_abi_size_u64);
28004 return ComptimePtrMutationKit{
28005 .decl_ref_mut = parent.decl_ref_mut,
28006 .pointee = .{ .reinterpret = .{
28007 .val_ptr = reinterpret.val_ptr,
28008 .byte_offset = reinterpret.byte_offset + elem_abi_size * elem_ptr.index,
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);
27918 switch (val_ptr.ip_index) {
27919 .undef => {
27920 // An array has been initialized to undefined at comptime and now we
27921 // are for the first time setting an element. We must change the representation
27922 // of the array from `undef` to `array`.
27923 const arena = parent.beginArena(sema.mod);
27924 defer parent.finishArena(sema.mod);
2801927925
28020 var parent = try sema.beginComptimePtrMutation(block, src, field_ptr.container_ptr, field_ptr.container_ty);
28021 switch (parent.pointee) {
28022 .direct => |val_ptr| switch (val_ptr.toIntern()) {
28023 .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);
27926 const array_len_including_sentinel =
27927 try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel(mod));
27928 const elems = try arena.alloc(Value, array_len_including_sentinel);
27929 @memset(elems, Value.undef);
2802927930
28030 switch (parent.ty.zigTypeTag(mod)) {
28031 .Struct => {
28032 const fields = try arena.alloc(Value, parent.ty.structFieldCount(mod));
28033 @memset(fields, Value.undef);
27931 val_ptr.* = try Value.Tag.aggregate.create(arena, elems);
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
2803727965 return beginComptimePtrMutationInner(
2803827966 sema,
2803927967 block,
2804027968 src,
28041 parent.ty.structFieldType(field_index, mod),
28042 &fields[field_index],
27969 elem_ty,
27970 &elems[elem_ptr.index],
2804327971 ptr_elem_ty,
28044 parent.decl_ref_mut,
27972 parent.mut_decl,
2804527973 );
2804627974 },
28047 .Union => {
28048 const payload = try arena.create(Value.Payload.Union);
28049 const tag_ty = parent.ty.unionTagTypeHypothetical(mod);
28050 payload.* = .{ .data = .{
28051 .tag = try mod.enumValueFieldIndex(tag_ty, field_index),
28052 .val = Value.undef,
28053 } };
27975 .repeated => {
27976 // An array is memory-optimized to store only a single element value, and
27977 // that value is understood to be the same for the entire length of the array.
27978 // However, now we want to modify an individual field and so the
27979 // representation has to change. If we wanted to avoid this, there would
27980 // need to be special detection elsewhere to identify when writing a value to an
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
2805727997 return beginComptimePtrMutationInner(
2805827998 sema,
2805927999 block,
2806028000 src,
28061 parent.ty.structFieldType(field_index, mod),
28062 &payload.data.val,
28001 elem_ty,
28002 &elems[elem_ptr.index],
2806328003 ptr_elem_ty,
28064 parent.decl_ref_mut,
28004 parent.mut_decl,
2806528005 );
2806628006 },
28067 .Pointer => {
28068 assert(parent.ty.isSlice(mod));
28069 val_ptr.* = try Value.Tag.slice.create(arena, .{
28070 .ptr = Value.undef,
28071 .len = Value.undef,
28072 });
28073
28074 switch (field_index) {
28075 Value.Payload.Slice.ptr_index => return beginComptimePtrMutationInner(
28076 sema,
28077 block,
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 },
28007
28008 .aggregate => return beginComptimePtrMutationInner(
28009 sema,
28010 block,
28011 src,
28012 elem_ty,
28013 &val_ptr.castTag(.aggregate).?.data[elem_ptr.index],
28014 ptr_elem_ty,
28015 parent.mut_decl,
28016 ),
28017
2809728018 else => unreachable,
28098 }
28099 },
28100 .empty_struct => {
28101 const duped = try sema.arena.create(Value);
28102 duped.* = Value.initTag(.the_only_possible_value);
28103 return beginComptimePtrMutationInner(
28104 sema,
28105 block,
28106 src,
28107 parent.ty.structFieldType(field_index, mod),
28108 duped,
28109 ptr_elem_ty,
28110 parent.decl_ref_mut,
28111 );
28112 },
28113 .none => switch (val_ptr.tag()) {
28114 .aggregate => return beginComptimePtrMutationInner(
28115 sema,
28116 block,
28117 src,
28118 parent.ty.structFieldType(field_index, mod),
28119 &val_ptr.castTag(.aggregate).?.data[field_index],
28120 ptr_elem_ty,
28121 parent.decl_ref_mut,
28122 ),
28123 .repeated => {
28124 const arena = parent.beginArena(sema.mod);
28125 defer parent.finishArena(sema.mod);
28019 },
28020 else => unreachable,
28021 }
28022 },
28023 else => {
28024 if (elem_ptr.index != 0) {
28025 // TODO include a "declared here" note for the decl
28026 return sema.fail(block, src, "out of bounds comptime store of index {d}", .{
28027 elem_ptr.index,
28028 });
28029 }
28030 return beginComptimePtrMutationInner(
28031 sema,
28032 block,
28033 src,
28034 parent.ty,
28035 val_ptr,
28036 ptr_elem_ty,
28037 parent.mut_decl,
28038 );
28039 },
28040 },
28041 .reinterpret => |reinterpret| {
28042 if (!base_elem_ty.hasWellDefinedLayout(mod)) {
28043 // Even though the parent value type has well-defined memory layout, our
28044 // pointer type does not.
28045 return ComptimePtrMutationKit{
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));
28128 @memset(elems, val_ptr.castTag(.repeated).?.data);
28129 val_ptr.* = try Value.Tag.aggregate.create(arena, elems);
28052 const elem_abi_size_u64 = try sema.typeAbiSize(base_elem_ty);
28053 const elem_abi_size = try sema.usizeCast(block, src, elem_abi_size_u64);
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
2813128087 return beginComptimePtrMutationInner(
2813228088 sema,
2813328089 block,
2813428090 src,
2813528091 parent.ty.structFieldType(field_index, mod),
28136 &elems[field_index],
28092 &fields[field_index],
2813728093 ptr_elem_ty,
28138 parent.decl_ref_mut,
28094 parent.mut_decl,
2813928095 );
2814028096 },
28141 .@"union" => {
28142 // We need to set the active field of the union.
28143 const union_tag_ty = field_ptr.container_ty.unionTagTypeHypothetical(mod);
28097 .Union => {
28098 const payload = try arena.create(Value.Payload.Union);
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;
28146 payload.tag = try mod.enumValueFieldIndex(union_tag_ty, field_index);
28105 val_ptr.* = Value.initPayload(&payload.base);
2814728106
2814828107 return beginComptimePtrMutationInner(
2814928108 sema,
2815028109 block,
2815128110 src,
2815228111 parent.ty.structFieldType(field_index, mod),
28153 &payload.val,
28112 &payload.data.val,
2815428113 ptr_elem_ty,
28155 parent.decl_ref_mut,
28114 parent.mut_decl,
2815628115 );
2815728116 },
28158 .slice => switch (field_index) {
28159 Value.Payload.Slice.ptr_index => return beginComptimePtrMutationInner(
28160 sema,
28161 block,
28162 src,
28163 parent.ty.slicePtrFieldType(mod),
28164 &val_ptr.castTag(.slice).?.data.ptr,
28165 ptr_elem_ty,
28166 parent.decl_ref_mut,
28167 ),
28117 .Pointer => {
28118 assert(parent.ty.isSlice(mod));
28119 val_ptr.* = try Value.Tag.slice.create(arena, .{
28120 .ptr = Value.undef,
28121 .len = Value.undef,
28122 });
2816828123
28169 Value.Payload.Slice.len_index => return beginComptimePtrMutationInner(
28170 sema,
28171 block,
28172 src,
28173 Type.usize,
28174 &val_ptr.castTag(.slice).?.data.len,
28175 ptr_elem_ty,
28176 parent.decl_ref_mut,
28177 ),
28124 switch (field_index) {
28125 Value.slice_ptr_index => return beginComptimePtrMutationInner(
28126 sema,
28127 block,
28128 src,
28129 parent.ty.slicePtrFieldType(mod),
28130 &val_ptr.castTag(.slice).?.data.ptr,
28131 ptr_elem_ty,
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 }
2818028146 },
28181
2818228147 else => unreachable,
28183 },
28184 else => unreachable,
28148 }
2818528149 },
28186 .reinterpret => |reinterpret| {
28187 const field_offset_u64 = field_ptr.container_ty.structFieldOffset(field_index, mod);
28188 const field_offset = try sema.usizeCast(block, src, field_offset_u64);
28189 return ComptimePtrMutationKit{
28190 .decl_ref_mut = parent.decl_ref_mut,
28191 .pointee = .{ .reinterpret = .{
28192 .val_ptr = reinterpret.val_ptr,
28193 .byte_offset = reinterpret.byte_offset + field_offset,
28194 } },
28195 .ty = parent.ty,
28196 };
28150 .empty_struct => {
28151 const duped = try sema.arena.create(Value);
28152 duped.* = val_ptr.*;
28153 return beginComptimePtrMutationInner(
28154 sema,
28155 block,
28156 src,
28157 parent.ty.structFieldType(field_index, mod),
28158 duped,
28159 ptr_elem_ty,
28160 parent.mut_decl,
28161 );
2819728162 },
28198 .bad_decl_ty, .bad_ptr_ty => return parent,
28199 }
28200 },
28201 .eu_payload_ptr => {
28202 const eu_ptr = ptr_val.castTag(.eu_payload_ptr).?.data;
28203 var parent = try sema.beginComptimePtrMutation(block, src, eu_ptr.container_ptr, eu_ptr.container_ty);
28204 switch (parent.pointee) {
28205 .direct => |val_ptr| {
28206 const payload_ty = parent.ty.errorUnionPayload(mod);
28207 if (val_ptr.ip_index == .none and val_ptr.tag() == .eu_payload) {
28208 return ComptimePtrMutationKit{
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`.
28163 .none => switch (val_ptr.tag()) {
28164 .aggregate => return beginComptimePtrMutationInner(
28165 sema,
28166 block,
28167 src,
28168 parent.ty.structFieldType(field_index, mod),
28169 &val_ptr.castTag(.aggregate).?.data[field_index],
28170 ptr_elem_ty,
28171 parent.mut_decl,
28172 ),
28173 .repeated => {
2821728174 const arena = parent.beginArena(sema.mod);
2821828175 defer parent.finishArena(sema.mod);
2821928176
28220 const payload = try arena.create(Value.Payload.SubValue);
28221 payload.* = .{
28222 .base = .{ .tag = .eu_payload },
28223 .data = Value.undef,
28224 };
28177 const elems = try arena.alloc(Value, parent.ty.structFieldCount(mod));
28178 @memset(elems, val_ptr.castTag(.repeated).?.data);
28179 val_ptr.* = try Value.Tag.aggregate.create(arena, elems);
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{
28229 .decl_ref_mut = parent.decl_ref_mut,
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);
28195 const payload = &val_ptr.castTag(.@"union").?.data;
28196 payload.tag = try mod.enumValueFieldIndex(union_tag_ty, field_index);
2826028197
28261 const payload = try arena.create(Value.Payload.SubValue);
28262 payload.* = .{
28263 .base = .{ .tag = .opt_payload },
28264 .data = Value.undef,
28265 };
28198 return beginComptimePtrMutationInner(
28199 sema,
28200 block,
28201 src,
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{
28270 .decl_ref_mut = parent.decl_ref_mut,
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 },
28229 else => unreachable,
28230 },
2828128231
28282 else => return ComptimePtrMutationKit{
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,
28232 else => unreachable,
2830228233 },
28303 }
28304 },
28305 .decl_ref => unreachable, // isComptimeMutablePtr has been checked already
28306 else => unreachable,
28307 },
28308 else => switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr) {
28309 else => unreachable,
28234 else => unreachable,
28235 },
28236 .reinterpret => |reinterpret| {
28237 const field_offset_u64 = base_child_ty.structFieldOffset(field_index, mod);
28238 const field_offset = try sema.usizeCast(block, src, field_offset_u64);
28239 return ComptimePtrMutationKit{
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 }
2831028250 },
2831128251 }
2831228252}
......@@ -28418,6 +28358,7 @@ fn beginComptimePtrLoad(
2841828358 .mut_decl => |mut_decl| mut_decl.decl,
2841928359 else => unreachable,
2842028360 };
28361 const is_mutable = ptr.addr == .mut_decl;
2842128362 const decl = mod.declPtr(decl_index);
2842228363 const decl_tv = try decl.typedValue();
2842328364 if (decl.getVariable(mod) != null) return error.RuntimeLoad;
......@@ -28426,7 +28367,7 @@ fn beginComptimePtrLoad(
2842628367 break :blk ComptimePtrLoadKit{
2842728368 .parent = if (layout_defined) .{ .tv = decl_tv, .byte_offset = 0 } else null,
2842828369 .pointee = decl_tv,
28429 .is_mutable = false,
28370 .is_mutable = is_mutable,
2843028371 .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null,
2843128372 };
2843228373 },
......@@ -29411,7 +29352,7 @@ fn analyzeDeclVal(
2941129352 const decl_ref = try sema.analyzeDeclRefInner(decl_index, false);
2941229353 const result = try sema.analyzeLoad(block, src, decl_ref, src);
2941329354 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) {
2941529356 try sema.decl_val_table.put(sema.gpa, decl_index, result);
2941629357 }
2941729358 }
......@@ -30049,8 +29990,8 @@ fn analyzeSlice(
3004929990 const end_int = end_val.getUnsignedInt(mod).?;
3005029991 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);
30053 const res = try sema.pointerDerefExtra(block, src, elem_ptr, elem_ty, false);
29993 const elem_ptr = try ptr_val.elemPtr(try sema.elemPtrType(new_ptr_ty, sentinel_index), sentinel_index, sema.mod);
29994 const res = try sema.pointerDerefExtra(block, src, elem_ptr, elem_ty);
3005429995 const actual_sentinel = switch (res) {
3005529996 .runtime_load => break :sentinel_check,
3005629997 .val => |v| v,
......@@ -33421,35 +33362,24 @@ fn addConstUndef(sema: *Sema, ty: Type) CompileError!Air.Inst.Ref {
3342133362}
3342233363
3342333364pub fn addConstant(sema: *Sema, ty: Type, val: Value) SemaError!Air.Inst.Ref {
33365 const mod = sema.mod;
3342433366 const gpa = sema.gpa;
33425 if (val.ip_index != .none) {
33426 if (@enumToInt(val.toIntern()) < Air.ref_start_index)
33427 return @intToEnum(Air.Inst.Ref, @enumToInt(val.toIntern()));
33428 try sema.air_instructions.append(gpa, .{
33429 .tag = .interned,
33430 .data = .{ .interned = val.toIntern() },
33431 });
33432 const result = Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1));
33433 // This assertion can be removed when the `ty` parameter is removed from
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 }
33367
33368 // This assertion can be removed when the `ty` parameter is removed from
33369 // this function thanks to the InternPool transition being complete.
33370 if (std.debug.runtime_safety) {
33371 const val_ty = mod.intern_pool.typeOf(val.toIntern());
33372 if (ty.toIntern() != val_ty) {
33373 std.debug.panic("addConstant type mismatch: '{}' vs '{}'\n", .{
33374 ty.fmt(mod), val_ty.toType().fmt(mod),
33375 });
3344233376 }
33443 return result;
3344433377 }
33445 const ty_inst = try sema.addType(ty);
33446 try sema.air_values.append(gpa, val);
33378 if (@enumToInt(val.toIntern()) < Air.ref_start_index)
33379 return @intToEnum(Air.Inst.Ref, @enumToInt(val.toIntern()));
3344733380 try sema.air_instructions.append(gpa, .{
33448 .tag = .constant,
33449 .data = .{ .ty_pl = .{
33450 .ty = ty_inst,
33451 .payload = @intCast(u32, sema.air_values.items.len - 1),
33452 } },
33381 .tag = .interned,
33382 .data = .{ .interned = val.toIntern() },
3345333383 });
3345433384 return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1));
3345533385}
......@@ -33606,7 +33536,7 @@ pub fn analyzeAddressSpace(
3360633536fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr_ty: Type) CompileError!?Value {
3360733537 const mod = sema.mod;
3360833538 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);
3361033540 switch (res) {
3361133541 .runtime_load => return null,
3361233542 .val => |v| return v,
......@@ -33632,7 +33562,7 @@ const DerefResult = union(enum) {
3363233562 out_of_bounds: Type,
3363333563};
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 {
3363633566 const mod = sema.mod;
3363733567 const target = mod.getTarget();
3363833568 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
3364733577 if (coerce_in_mem_ok) {
3364833578 // We have a Value that lines up in virtual memory exactly with what we want to load,
3364933579 // and it is in-memory coercible to load_ty. It may be returned without modifications.
33650 if (deref.is_mutable and want_mutable) {
33651 // The decl whose value we are obtaining here may be overwritten with
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 };
33580 // Move mutable decl values to the InternPool and assert other decls are already in the InternPool.
33581 return .{ .val = (if (deref.is_mutable) try tv.val.intern(tv.ty, mod) else tv.val.toIntern()).toValue() };
3365733582 }
3365833583 }
3365933584
src/TypedValue.zig+54
......@@ -124,6 +124,60 @@ pub fn print(
124124 }
125125 return writer.writeAll(" }");
126126 },
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 },
127181 // TODO these should not appear in this function
128182 .inferred_alloc => return writer.writeAll("(inferred allocation value)"),
129183 .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 {
845845 .ptr_elem_val => try self.airPtrElemVal(inst),
846846 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
847847
848 .constant => unreachable, // excluded from function bodies
849 .interned => unreachable, // excluded from function bodies
848 .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable,
850849 .unreach => self.finishAirBookkeeping(),
851850
852851 .optional_payload => try self.airOptionalPayload(inst),
......@@ -919,8 +918,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
919918
920919/// Asserts there is already capacity to insert into top branch inst_table.
921920fn processDeath(self: *Self, inst: Air.Inst.Index) void {
922 const air_tags = self.air.instructions.items(.tag);
923 if (air_tags[inst] == .constant) return; // Constants are immortal.
921 assert(self.air.instructions.items(.tag)[inst] != .interned);
924922 // When editing this function, note that the logic must synchronize with `reuseOperand`.
925923 const prev_value = self.getResolvedInstValue(inst);
926924 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 {
61556153 });
61566154
61576155 switch (self.air.instructions.items(.tag)[inst_index]) {
6158 .constant => {
6156 .interned => {
61596157 // Constants have static lifetimes, so they are always memoized in the outer most table.
61606158 const branch = &self.branch_stack.items[0];
61616159 const gop = try branch.inst_table.getOrPut(self.gpa, inst_index);
61626160 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;
61646162 gop.value_ptr.* = try self.genTypedValue(.{
61656163 .ty = inst_ty,
6166 .val = self.air.values[ty_pl.payload],
6164 .val = interned.toValue(),
61676165 });
61686166 }
61696167 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 {
829829 .ptr_elem_val => try self.airPtrElemVal(inst),
830830 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
831831
832 .constant => unreachable, // excluded from function bodies
833 .interned => unreachable, // excluded from function bodies
832 .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable,
834833 .unreach => self.finishAirBookkeeping(),
835834
836835 .optional_payload => try self.airOptionalPayload(inst),
......@@ -903,8 +902,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
903902
904903/// Asserts there is already capacity to insert into top branch inst_table.
905904fn processDeath(self: *Self, inst: Air.Inst.Index) void {
906 const air_tags = self.air.instructions.items(.tag);
907 if (air_tags[inst] == .constant) return; // Constants are immortal.
905 assert(self.air.instructions.items(.tag)[inst] != .interned);
908906 // When editing this function, note that the logic must synchronize with `reuseOperand`.
909907 const prev_value = self.getResolvedInstValue(inst);
910908 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 {
61036101 });
61046102
61056103 switch (self.air.instructions.items(.tag)[inst_index]) {
6106 .constant => {
6104 .interned => {
61076105 // Constants have static lifetimes, so they are always memoized in the outer most table.
61086106 const branch = &self.branch_stack.items[0];
61096107 const gop = try branch.inst_table.getOrPut(self.gpa, inst_index);
61106108 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;
61126110 gop.value_ptr.* = try self.genTypedValue(.{
61136111 .ty = inst_ty,
6114 .val = self.air.values[ty_pl.payload],
6112 .val = interned.toValue(),
61156113 });
61166114 }
61176115 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 {
659659 .ptr_elem_val => try self.airPtrElemVal(inst),
660660 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
661661
662 .constant => unreachable, // excluded from function bodies
663 .interned => unreachable, // excluded from function bodies
662 .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable,
664663 .unreach => self.finishAirBookkeeping(),
665664
666665 .optional_payload => try self.airOptionalPayload(inst),
......@@ -730,8 +729,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
730729
731730/// Asserts there is already capacity to insert into top branch inst_table.
732731fn processDeath(self: *Self, inst: Air.Inst.Index) void {
733 const air_tags = self.air.instructions.items(.tag);
734 if (air_tags[inst] == .constant) return; // Constants are immortal.
732 assert(self.air.instructions.items(.tag)[inst] != .interned);
735733 // When editing this function, note that the logic must synchronize with `reuseOperand`.
736734 const prev_value = self.getResolvedInstValue(inst);
737735 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 {
25572555 });
25582556
25592557 switch (self.air.instructions.items(.tag)[inst_index]) {
2560 .constant => {
2558 .interned => {
25612559 // Constants have static lifetimes, so they are always memoized in the outer most table.
25622560 const branch = &self.branch_stack.items[0];
25632561 const gop = try branch.inst_table.getOrPut(self.gpa, inst_index);
25642562 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;
25662564 gop.value_ptr.* = try self.genTypedValue(.{
25672565 .ty = inst_ty,
2568 .val = self.air.values[ty_pl.payload],
2566 .val = interned.toValue(),
25692567 });
25702568 }
25712569 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 {
679679 .ptr_elem_val => try self.airPtrElemVal(inst),
680680 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
681681
682 .constant => unreachable, // excluded from function bodies
683 .interned => unreachable, // excluded from function bodies
682 .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable,
684683 .unreach => self.finishAirBookkeeping(),
685684
686685 .optional_payload => try self.airOptionalPayload(inst),
......@@ -4423,8 +4422,7 @@ fn performReloc(self: *Self, inst: Mir.Inst.Index) !void {
44234422
44244423/// Asserts there is already capacity to insert into top branch inst_table.
44254424fn processDeath(self: *Self, inst: Air.Inst.Index) void {
4426 const air_tags = self.air.instructions.items(.tag);
4427 if (air_tags[inst] == .constant) return; // Constants are immortal.
4425 assert(self.air.instructions.items(.tag)[inst] != .interned);
44284426 // When editing this function, note that the logic must synchronize with `reuseOperand`.
44294427 const prev_value = self.getResolvedInstValue(inst);
44304428 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 {
45534551
45544552 if (Air.refToIndex(ref)) |inst| {
45554553 switch (self.air.instructions.items(.tag)[inst]) {
4556 .constant => {
4554 .interned => {
45574555 // Constants have static lifetimes, so they are always memoized in the outer most table.
45584556 const branch = &self.branch_stack.items[0];
45594557 const gop = try branch.inst_table.getOrPut(self.gpa, inst);
45604558 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;
45624560 gop.value_ptr.* = try self.genTypedValue(.{
45634561 .ty = ty,
4564 .val = self.air.values[ty_pl.payload],
4562 .val = interned.toValue(),
45654563 });
45664564 }
45674565 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
883883
884884fn processDeath(func: *CodeGen, ref: Air.Inst.Ref) void {
885885 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);
887887 // Branches are currently only allowed to free locals allocated
888888 // within their own branch.
889889 // TODO: Upon branch consolidation free any locals if needed.
......@@ -1832,8 +1832,7 @@ fn buildPointerOffset(func: *CodeGen, ptr_value: WValue, offset: u64, action: en
18321832fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
18331833 const air_tags = func.air.instructions.items(.tag);
18341834 return switch (air_tags[inst]) {
1835 .constant => unreachable,
1836 .interned => unreachable,
1835 .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable,
18371836
18381837 .add => func.airBinOp(inst, .add),
18391838 .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 {
19221922 .ptr_elem_val => try self.airPtrElemVal(inst),
19231923 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
19241924
1925 .constant => unreachable, // excluded from function bodies
1926 .interned => unreachable, // excluded from function bodies
1925 .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable,
19271926 .unreach => if (self.wantSafety()) try self.airTrap() else self.finishAirBookkeeping(),
19281927
19291928 .optional_payload => try self.airOptionalPayload(inst),
......@@ -2097,10 +2096,8 @@ fn feed(self: *Self, bt: *Liveness.BigTomb, operand: Air.Inst.Ref) void {
20972096
20982097/// Asserts there is already capacity to insert into top branch inst_table.
20992098fn processDeath(self: *Self, inst: Air.Inst.Index) void {
2100 switch (self.air.instructions.items(.tag)[inst]) {
2101 .constant => unreachable,
2102 else => self.inst_tracking.getPtr(inst).?.die(self, inst),
2103 }
2099 assert(self.air.instructions.items(.tag)[inst] != .interned);
2100 self.inst_tracking.getPtr(inst).?.die(self, inst);
21042101}
21052102
21062103/// 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 {
28762873 const dst_info = dst_ty.intInfo(mod);
28772874 if (Air.refToIndex(dst_air)) |inst| {
28782875 switch (air_tag[inst]) {
2879 .constant => {
2880 const src_val = self.air.values[air_data[inst].ty_pl.payload];
2876 .interned => {
2877 const src_val = air_data[inst].interned.toValue();
28812878 var space: Value.BigIntSpace = undefined;
28822879 const src_int = src_val.toBigInt(&space, mod);
28832880 return @intCast(u16, src_int.bitCountTwosComp()) +
......@@ -11584,11 +11581,11 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue {
1158411581
1158511582 if (Air.refToIndex(ref)) |inst| {
1158611583 const mcv = switch (self.air.instructions.items(.tag)[inst]) {
11587 .constant => tracking: {
11584 .interned => tracking: {
1158811585 const gop = try self.const_tracking.getOrPut(self.gpa, inst);
1158911586 if (!gop.found_existing) gop.value_ptr.* = InstTracking.init(try self.genTypedValue(.{
1159011587 .ty = ty,
11591 .val = (try self.air.value(ref, mod)).?,
11588 .val = self.air.instructions.items(.data)[inst].interned.toValue(),
1159211589 }));
1159311590 break :tracking gop.value_ptr;
1159411591 },
......@@ -11605,7 +11602,7 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue {
1160511602
1160611603fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) *InstTracking {
1160711604 const tracking = switch (self.air.instructions.items(.tag)[inst]) {
11608 .constant => &self.const_tracking,
11605 .interned => &self.const_tracking,
1160911606 else => &self.inst_tracking,
1161011607 }.getPtr(inst).?;
1161111608 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,
28902890
28912891 const result_value = switch (air_tags[inst]) {
28922892 // zig fmt: off
2893 .constant => unreachable, // excluded from function bodies
2894 .interned => unreachable, // excluded from function bodies
2893 .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable,
28952894
28962895 .arg => try airArg(f, inst),
28972896
......@@ -7783,8 +7782,8 @@ fn reap(f: *Function, inst: Air.Inst.Index, operands: []const Air.Inst.Ref) !voi
77837782
77847783fn die(f: *Function, inst: Air.Inst.Index, ref: Air.Inst.Ref) !void {
77857784 const ref_inst = Air.refToIndex(ref) orelse return;
7785 assert(f.air.instructions.items(.tag)[ref_inst] != .interned);
77867786 const c_value = (f.value_map.fetchRemove(ref_inst) orelse return).value;
7787 if (f.air.instructions.items(.tag)[ref_inst] == .constant) return;
77887787 const local_index = switch (c_value) {
77897788 .local, .new_local => |l| l,
77907789 else => return,
src/codegen/llvm.zig+1-2
......@@ -4530,8 +4530,7 @@ pub const FuncGen = struct {
45304530
45314531 .vector_store_elem => try self.airVectorStoreElem(inst),
45324532
4533 .constant => unreachable,
4534 .interned => unreachable,
4533 .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable,
45354534
45364535 .unreach => self.airUnreach(inst),
45374536 .dbg_stmt => self.airDbgStmt(inst),
src/codegen/spirv.zig-1
......@@ -1807,7 +1807,6 @@ pub const DeclGen = struct {
18071807 .br => return self.airBr(inst),
18081808 .breakpoint => return,
18091809 .cond_br => return self.airCondBr(inst),
1810 .constant => unreachable,
18111810 .dbg_stmt => return self.airDbgStmt(inst),
18121811 .loop => return self.airLoop(inst),
18131812 .ret => return self.airRet(inst),
src/print_air.zig+4-8
......@@ -93,14 +93,10 @@ const Writer = struct {
9393
9494 fn writeAllConstants(w: *Writer, s: anytype) @TypeOf(s).Error!void {
9595 for (w.air.instructions.items(.tag), 0..) |tag, i| {
96 if (tag != .interned) continue;
9697 const inst = @intCast(Air.Inst.Index, i);
97 switch (tag) {
98 .constant, .interned => {
99 try w.writeInst(s, inst);
100 try s.writeByte('\n');
101 },
102 else => continue,
103 }
98 try w.writeInst(s, inst);
99 try s.writeByte('\n');
104100 }
105101 }
106102
......@@ -304,7 +300,7 @@ const Writer = struct {
304300
305301 .struct_field_ptr => try w.writeStructField(s, inst),
306302 .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),
308304 .interned => try w.writeInterned(s, inst),
309305 .assembly => try w.writeAssembly(s, inst),
310306 .dbg_stmt => try w.writeDbgStmt(s, inst),
src/value.zig+129-69
......@@ -35,6 +35,22 @@ pub const Value = struct {
3535 // The first section of this enum are tags that require no payload.
3636 // 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,
3854 /// A slice of u8 whose memory is managed externally.
3955 bytes,
4056 /// This value is repeated some number of times. The amount of times to repeat
......@@ -58,14 +74,16 @@ pub const Value = struct {
5874
5975 pub fn Type(comptime t: Tag) type {
6076 return switch (t) {
61 .repeated => Payload.SubValue,
62
77 .eu_payload,
78 .opt_payload,
79 .repeated,
80 => Payload.SubValue,
81 .slice => Payload.Slice,
6382 .bytes => Payload.Bytes,
64
65 .inferred_alloc => Payload.InferredAlloc,
66 .inferred_alloc_comptime => Payload.InferredAllocComptime,
6783 .aggregate => Payload.Aggregate,
6884 .@"union" => Payload.Union,
85 .inferred_alloc => Payload.InferredAlloc,
86 .inferred_alloc_comptime => Payload.InferredAllocComptime,
6987 };
7088 }
7189
......@@ -172,7 +190,10 @@ pub const Value = struct {
172190 .legacy = .{ .ptr_otherwise = &new_payload.base },
173191 };
174192 },
175 .repeated => {
193 .eu_payload,
194 .opt_payload,
195 .repeated,
196 => {
176197 const payload = self.cast(Payload.SubValue).?;
177198 const new_payload = try arena.create(Payload.SubValue);
178199 new_payload.* = .{
......@@ -184,6 +205,21 @@ pub const Value = struct {
184205 .legacy = .{ .ptr_otherwise = &new_payload.base },
185206 };
186207 },
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 },
187223 .aggregate => {
188224 const payload = self.castTag(.aggregate).?;
189225 const new_payload = try arena.create(Payload.Aggregate);
......@@ -263,6 +299,15 @@ pub const Value = struct {
263299 try out_stream.writeAll("(repeated) ");
264300 val = val.castTag(.repeated).?.data;
265301 },
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)"),
266311 .inferred_alloc => return out_stream.writeAll("(inferred allocation value)"),
267312 .inferred_alloc_comptime => return out_stream.writeAll("(inferred comptime allocation value)"),
268313 };
......@@ -1653,13 +1698,18 @@ pub const Value = struct {
16531698 .Null,
16541699 .Struct, // It sure would be nice to do something clever with structs.
16551700 => |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 },
16561707 .Type,
16571708 .Float,
16581709 .ComptimeFloat,
16591710 .Bool,
16601711 .Int,
16611712 .ComptimeInt,
1662 .Pointer,
16631713 .Fn,
16641714 .Optional,
16651715 .ErrorSet,
......@@ -1799,9 +1849,15 @@ pub const Value = struct {
17991849 /// Asserts the value is a single-item pointer to an array, or an array,
18001850 /// or an unknown-length pointer, and returns the element value at the index.
18011851 pub fn elemValue(val: Value, mod: *Module, index: usize) Allocator.Error!Value {
1802 switch (val.toIntern()) {
1803 .undef => return Value.undef,
1804 else => return switch (mod.intern_pool.indexToKey(val.toIntern())) {
1852 return switch (val.ip_index) {
1853 .undef => Value.undef,
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())) {
18051861 .ptr => |ptr| switch (ptr.addr) {
18061862 .decl => |decl| mod.declPtr(decl).val.elemValue(mod, index),
18071863 .mut_decl => |mut_decl| mod.declPtr(mut_decl.decl).val.elemValue(mod, index),
......@@ -1829,7 +1885,7 @@ pub const Value = struct {
18291885 },
18301886 else => unreachable,
18311887 },
1832 }
1888 };
18331889 }
18341890
18351891 pub fn isLazyAlign(val: Value, mod: *Module) bool {
......@@ -1875,25 +1931,28 @@ pub const Value = struct {
18751931 }
18761932
18771933 pub fn isPtrToThreadLocal(val: Value, mod: *Module) bool {
1878 return switch (mod.intern_pool.indexToKey(val.toIntern())) {
1879 .variable => |variable| variable.is_threadlocal,
1880 .ptr => |ptr| switch (ptr.addr) {
1881 .decl => |decl_index| {
1882 const decl = mod.declPtr(decl_index);
1883 assert(decl.has_tv);
1884 return decl.val.isPtrToThreadLocal(mod);
1885 },
1886 .mut_decl => |mut_decl| {
1887 const decl = mod.declPtr(mut_decl.decl);
1888 assert(decl.has_tv);
1889 return decl.val.isPtrToThreadLocal(mod);
1934 return switch (val.ip_index) {
1935 .none => false,
1936 else => switch (mod.intern_pool.indexToKey(val.toIntern())) {
1937 .variable => |variable| variable.is_threadlocal,
1938 .ptr => |ptr| switch (ptr.addr) {
1939 .decl => |decl_index| {
1940 const decl = mod.declPtr(decl_index);
1941 assert(decl.has_tv);
1942 return decl.val.isPtrToThreadLocal(mod);
1943 },
1944 .mut_decl => |mut_decl| {
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),
18901953 },
1891 .int => 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),
1954 else => false,
18951955 },
1896 else => false,
18971956 };
18981957 }
18991958
......@@ -1926,9 +1985,21 @@ pub const Value = struct {
19261985 }
19271986
19281987 pub fn fieldValue(val: Value, mod: *Module, index: usize) !Value {
1929 switch (val.toIntern()) {
1930 .undef => return Value.undef,
1931 else => return switch (mod.intern_pool.indexToKey(val.toIntern())) {
1988 return switch (val.ip_index) {
1989 .undef => Value.undef,
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())) {
19322003 .aggregate => |aggregate| switch (aggregate.storage) {
19332004 .bytes => |bytes| try mod.intern(.{ .int = .{
19342005 .ty = .u8_type,
......@@ -1941,7 +2012,7 @@ pub const Value = struct {
19412012 .un => |un| un.val.toValue(),
19422013 else => unreachable,
19432014 },
1944 }
2015 };
19452016 }
19462017
19472018 pub fn unionTag(val: Value, mod: *Module) Value {
......@@ -1956,36 +2027,17 @@ pub const Value = struct {
19562027 /// Returns a pointer to the element value at the index.
19572028 pub fn elemPtr(
19582029 val: Value,
1959 ty: Type,
2030 elem_ptr_ty: Type,
19602031 index: usize,
19612032 mod: *Module,
19622033 ) Allocator.Error!Value {
1963 const elem_ty = ty.elemType2(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 });
2034 const elem_ty = elem_ptr_ty.childType(mod);
19832035 const ptr_val = switch (mod.intern_pool.indexToKey(val.toIntern())) {
19842036 .ptr => |ptr| ptr: {
19852037 switch (ptr.addr) {
19862038 .elem => |elem| if (mod.intern_pool.typeOf(elem.base).toType().elemType2(mod).eql(elem_ty, mod))
19872039 return (try mod.intern(.{ .ptr = .{
1988 .ty = ptr_ty.toIntern(),
2040 .ty = elem_ptr_ty.toIntern(),
19892041 .addr = .{ .elem = .{
19902042 .base = elem.base,
19912043 .index = elem.index + index,
......@@ -2001,7 +2053,7 @@ pub const Value = struct {
20012053 else => val,
20022054 };
20032055 return (try mod.intern(.{ .ptr = .{
2004 .ty = ptr_ty.toIntern(),
2056 .ty = elem_ptr_ty.toIntern(),
20052057 .addr = .{ .elem = .{
20062058 .base = ptr_val.toIntern(),
20072059 .index = index,
......@@ -4058,9 +4110,12 @@ pub const Value = struct {
40584110 pub const Payload = struct {
40594111 tag: Tag,
40604112
4061 pub const SubValue = struct {
4113 pub const Slice = struct {
40624114 base: Payload,
4063 data: Value,
4115 data: struct {
4116 ptr: Value,
4117 len: Value,
4118 },
40644119 };
40654120
40664121 pub const Bytes = struct {
......@@ -4069,6 +4124,11 @@ pub const Value = struct {
40694124 data: []const u8,
40704125 };
40714126
4127 pub const SubValue = struct {
4128 base: Payload,
4129 data: Value,
4130 };
4131
40724132 pub const Aggregate = struct {
40734133 base: Payload,
40744134 /// Field values. The types are according to the struct or array type.
......@@ -4076,6 +4136,18 @@ pub const Value = struct {
40764136 data: []Value,
40774137 };
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
40794151 pub const InferredAlloc = struct {
40804152 pub const base_tag = Tag.inferred_alloc;
40814153
......@@ -4110,18 +4182,6 @@ pub const Value = struct {
41104182 alignment: u32,
41114183 },
41124184 };
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 };
41254185 };
41264186
41274187 pub const BigIntSpace = InternPool.Key.Int.Storage.BigIntSpace;
tools/lldb_pretty_printers.py+6
......@@ -682,4 +682,10 @@ def __lldb_init_module(debugger, _=None):
682682 add(debugger, category='zig.stage2', regex=True, type='^Air\\.Inst\\.Data\\.Data__struct_[1-9][0-9]*$', inline_children=True, summary=True)
683683 add(debugger, category='zig.stage2', type='Module.Decl::Module.Decl.Index', synth=True)
684684 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)
685691 add(debugger, category='zig.stage2', type='arch.x86_64.CodeGen.MCValue', identifier='zig_TaggedUnion', synth=True, inline_children=True, summary=True)