mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
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.
This commit is contained in:
parent
72e4ea3821
commit
70cc68e999
19 changed files with 879 additions and 856 deletions
18
src/Air.zig
18
src/Air.zig
|
|
@ -186,6 +186,14 @@ pub const Inst = struct {
|
|||
/// Allocates stack local memory.
|
||||
/// Uses the `ty` field.
|
||||
alloc,
|
||||
/// This is a special value that tracks a set of types that have been stored
|
||||
/// to an inferred allocation. It does not support any of the normal value queries.
|
||||
/// Uses the `ty_pl` field, payload is an index of `values` array.
|
||||
inferred_alloc,
|
||||
/// Used to coordinate alloc_inferred, store_to_inferred_ptr, and resolve_inferred_alloc
|
||||
/// instructions for comptime code.
|
||||
/// Uses the `ty_pl` field, payload is an index of `values` array.
|
||||
inferred_alloc_comptime,
|
||||
/// If the function will pass the result by-ref, this instruction returns the
|
||||
/// result pointer. Otherwise it is equivalent to `alloc`.
|
||||
/// Uses the `ty` field.
|
||||
|
|
@ -397,9 +405,6 @@ pub const Inst = struct {
|
|||
/// was executed on the operand.
|
||||
/// Uses the `ty_pl` field. Payload is `TryPtr`.
|
||||
try_ptr,
|
||||
/// A comptime-known value. Uses the `ty_pl` field, payload is index of
|
||||
/// `values` array.
|
||||
constant,
|
||||
/// A comptime-known value via an index into the InternPool.
|
||||
/// Uses the `interned` field.
|
||||
interned,
|
||||
|
|
@ -1265,7 +1270,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index, ip: InternPool) Type {
|
|||
|
||||
.assembly,
|
||||
.block,
|
||||
.constant,
|
||||
.struct_field_ptr,
|
||||
.struct_field_val,
|
||||
.slice_elem_ptr,
|
||||
|
|
@ -1283,6 +1287,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index, ip: InternPool) Type {
|
|||
.sub_with_overflow,
|
||||
.mul_with_overflow,
|
||||
.shl_with_overflow,
|
||||
.inferred_alloc,
|
||||
.inferred_alloc_comptime,
|
||||
.ptr_add,
|
||||
.ptr_sub,
|
||||
.try_ptr,
|
||||
|
|
@ -1495,7 +1501,6 @@ pub fn value(air: Air, inst: Inst.Ref, mod: *Module) !?Value {
|
|||
const inst_index = @intCast(Air.Inst.Index, ref_int - ref_start_index);
|
||||
const air_datas = air.instructions.items(.data);
|
||||
switch (air.instructions.items(.tag)[inst_index]) {
|
||||
.constant => return air.values[air_datas[inst_index].ty_pl.payload],
|
||||
.interned => return air_datas[inst_index].interned.toValue(),
|
||||
else => return air.typeOfIndex(inst_index, mod.intern_pool).onePossibleValue(mod),
|
||||
}
|
||||
|
|
@ -1603,6 +1608,8 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: InternPool) bool {
|
|||
.mul_with_overflow,
|
||||
.shl_with_overflow,
|
||||
.alloc,
|
||||
.inferred_alloc,
|
||||
.inferred_alloc_comptime,
|
||||
.ret_ptr,
|
||||
.bit_and,
|
||||
.bit_or,
|
||||
|
|
@ -1651,7 +1658,6 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: InternPool) bool {
|
|||
.cmp_neq_optimized,
|
||||
.cmp_vector,
|
||||
.cmp_vector_optimized,
|
||||
.constant,
|
||||
.interned,
|
||||
.is_null,
|
||||
.is_non_null,
|
||||
|
|
|
|||
|
|
@ -515,10 +515,12 @@ pub const Key = union(enum) {
|
|||
|
||||
pub const ErrorUnion = struct {
|
||||
ty: Index,
|
||||
val: union(enum) {
|
||||
val: Value,
|
||||
|
||||
pub const Value = union(enum) {
|
||||
err_name: NullTerminatedString,
|
||||
payload: Index,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
pub const EnumTag = struct {
|
||||
|
|
@ -1068,7 +1070,7 @@ pub const Key = union(enum) {
|
|||
.false, .true => .bool_type,
|
||||
.empty_struct => .empty_struct_type,
|
||||
.@"unreachable" => .noreturn_type,
|
||||
.generic_poison => unreachable,
|
||||
.generic_poison => .generic_poison_type,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
@ -2671,6 +2673,10 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
|
|||
.only_possible_value => {
|
||||
const ty = @intToEnum(Index, data);
|
||||
return switch (ip.indexToKey(ty)) {
|
||||
.array_type, .vector_type => .{ .aggregate = .{
|
||||
.ty = ty,
|
||||
.storage = .{ .elems = &.{} },
|
||||
} },
|
||||
// TODO: migrate structs to properly use the InternPool rather
|
||||
// than using the SegmentedList trick, then the struct type will
|
||||
// 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 {
|
|||
assert(!(try ip.map.getOrPutAdapted(gpa, key, adapter)).found_existing);
|
||||
try ip.items.ensureUnusedCapacity(gpa, 1);
|
||||
ip.items.appendAssumeCapacity(.{
|
||||
.tag = .ptr_elem,
|
||||
.tag = switch (ptr.addr) {
|
||||
.elem => .ptr_elem,
|
||||
.field => .ptr_field,
|
||||
else => unreachable,
|
||||
},
|
||||
.data = try ip.addExtra(gpa, PtrBaseIndex{
|
||||
.ty = ptr.ty,
|
||||
.base = base_index.base,
|
||||
|
|
|
|||
|
|
@ -321,8 +321,9 @@ pub fn categorizeOperand(
|
|||
|
||||
.arg,
|
||||
.alloc,
|
||||
.inferred_alloc,
|
||||
.inferred_alloc_comptime,
|
||||
.ret_ptr,
|
||||
.constant,
|
||||
.interned,
|
||||
.trap,
|
||||
.breakpoint,
|
||||
|
|
@ -973,9 +974,7 @@ fn analyzeInst(
|
|||
.work_group_id,
|
||||
=> return analyzeOperands(a, pass, data, inst, .{ .none, .none, .none }),
|
||||
|
||||
.constant,
|
||||
.interned,
|
||||
=> unreachable,
|
||||
.inferred_alloc, .inferred_alloc_comptime, .interned => unreachable,
|
||||
|
||||
.trap,
|
||||
.unreach,
|
||||
|
|
@ -1269,10 +1268,7 @@ fn analyzeOperands(
|
|||
const operand = Air.refToIndexAllowNone(op_ref) orelse continue;
|
||||
|
||||
// Don't compute any liveness for constants
|
||||
switch (inst_tags[operand]) {
|
||||
.constant, .interned => continue,
|
||||
else => {},
|
||||
}
|
||||
if (inst_tags[operand] == .interned) continue;
|
||||
|
||||
_ = try data.live_set.put(gpa, operand, {});
|
||||
}
|
||||
|
|
@ -1305,10 +1301,7 @@ fn analyzeOperands(
|
|||
const operand = Air.refToIndexAllowNone(op_ref) orelse continue;
|
||||
|
||||
// Don't compute any liveness for constants
|
||||
switch (inst_tags[operand]) {
|
||||
.constant, .interned => continue,
|
||||
else => {},
|
||||
}
|
||||
if (inst_tags[operand] == .interned) continue;
|
||||
|
||||
const mask = @as(Bpi, 1) << @intCast(OperandInt, i);
|
||||
|
||||
|
|
@ -1839,10 +1832,7 @@ fn AnalyzeBigOperands(comptime pass: LivenessPass) type {
|
|||
|
||||
// Don't compute any liveness for constants
|
||||
const inst_tags = big.a.air.instructions.items(.tag);
|
||||
switch (inst_tags[operand]) {
|
||||
.constant, .interned => return,
|
||||
else => {},
|
||||
}
|
||||
if (inst_tags[operand] == .interned) return
|
||||
|
||||
// If our result is unused and the instruction doesn't need to be lowered, backends will
|
||||
// skip the lowering of this instruction, so we don't want to record uses of operands.
|
||||
|
|
|
|||
|
|
@ -41,8 +41,9 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
|
|||
// no operands
|
||||
.arg,
|
||||
.alloc,
|
||||
.inferred_alloc,
|
||||
.inferred_alloc_comptime,
|
||||
.ret_ptr,
|
||||
.constant,
|
||||
.interned,
|
||||
.breakpoint,
|
||||
.dbg_stmt,
|
||||
|
|
@ -554,16 +555,18 @@ fn verifyDeath(self: *Verify, inst: Air.Inst.Index, operand: Air.Inst.Index) Err
|
|||
}
|
||||
|
||||
fn verifyOperand(self: *Verify, inst: Air.Inst.Index, op_ref: Air.Inst.Ref, dies: bool) Error!void {
|
||||
const operand = Air.refToIndexAllowNone(op_ref) orelse return;
|
||||
switch (self.air.instructions.items(.tag)[operand]) {
|
||||
.constant, .interned => {},
|
||||
else => {
|
||||
if (dies) {
|
||||
if (!self.live.remove(operand)) return invalid("%{}: dead operand %{} reused and killed again", .{ inst, operand });
|
||||
} else {
|
||||
if (!self.live.contains(operand)) return invalid("%{}: dead operand %{} reused", .{ inst, operand });
|
||||
}
|
||||
},
|
||||
const operand = Air.refToIndexAllowNone(op_ref) orelse {
|
||||
assert(!dies);
|
||||
return;
|
||||
};
|
||||
if (self.air.instructions.items(.tag)[operand] == .interned) {
|
||||
assert(!dies);
|
||||
return;
|
||||
}
|
||||
if (dies) {
|
||||
if (!self.live.remove(operand)) return invalid("%{}: dead operand %{} reused and killed again", .{ inst, operand });
|
||||
} else {
|
||||
if (!self.live.contains(operand)) return invalid("%{}: dead operand %{} reused", .{ inst, operand });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -576,16 +579,11 @@ fn verifyInst(
|
|||
const dies = self.liveness.operandDies(inst, @intCast(Liveness.OperandInt, operand_index));
|
||||
try self.verifyOperand(inst, operand, dies);
|
||||
}
|
||||
const tag = self.air.instructions.items(.tag);
|
||||
switch (tag[inst]) {
|
||||
.constant, .interned => unreachable,
|
||||
else => {
|
||||
if (self.liveness.isUnused(inst)) {
|
||||
assert(!self.live.contains(inst));
|
||||
} else {
|
||||
try self.live.putNoClobber(self.gpa, inst, {});
|
||||
}
|
||||
},
|
||||
if (self.air.instructions.items(.tag)[inst] == .interned) return;
|
||||
if (self.liveness.isUnused(inst)) {
|
||||
assert(!self.live.contains(inst));
|
||||
} else {
|
||||
try self.live.putNoClobber(self.gpa, inst, {});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -764,14 +764,7 @@ pub const Decl = struct {
|
|||
|
||||
pub fn typedValue(decl: Decl) error{AnalysisFail}!TypedValue {
|
||||
if (!decl.has_tv) return error.AnalysisFail;
|
||||
return TypedValue{
|
||||
.ty = decl.ty,
|
||||
.val = decl.val,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn value(decl: *Decl) error{AnalysisFail}!Value {
|
||||
return (try decl.typedValue()).val;
|
||||
return TypedValue{ .ty = decl.ty, .val = decl.val };
|
||||
}
|
||||
|
||||
pub fn isFunction(decl: Decl, mod: *const Module) !bool {
|
||||
|
|
|
|||
1277
src/Sema.zig
1277
src/Sema.zig
File diff suppressed because it is too large
Load diff
|
|
@ -124,6 +124,60 @@ pub fn print(
|
|||
}
|
||||
return writer.writeAll(" }");
|
||||
},
|
||||
.slice => {
|
||||
if (level == 0) {
|
||||
return writer.writeAll(".{ ... }");
|
||||
}
|
||||
const payload = val.castTag(.slice).?.data;
|
||||
const elem_ty = ty.elemType2(mod);
|
||||
const len = payload.len.toUnsignedInt(mod);
|
||||
|
||||
if (elem_ty.eql(Type.u8, mod)) str: {
|
||||
const max_len = @intCast(usize, std.math.min(len, max_string_len));
|
||||
var buf: [max_string_len]u8 = undefined;
|
||||
|
||||
var i: u32 = 0;
|
||||
while (i < max_len) : (i += 1) {
|
||||
const elem_val = payload.ptr.elemValue(mod, i) catch |err| switch (err) {
|
||||
error.OutOfMemory => @panic("OOM"), // TODO: eliminate this panic
|
||||
};
|
||||
if (elem_val.isUndef(mod)) break :str;
|
||||
buf[i] = std.math.cast(u8, elem_val.toUnsignedInt(mod)) orelse break :str;
|
||||
}
|
||||
|
||||
// TODO would be nice if this had a bit of unicode awareness.
|
||||
const truncated = if (len > max_string_len) " (truncated)" else "";
|
||||
return writer.print("\"{}{s}\"", .{ std.zig.fmtEscapes(buf[0..max_len]), truncated });
|
||||
}
|
||||
|
||||
try writer.writeAll(".{ ");
|
||||
|
||||
const max_len = std.math.min(len, max_aggregate_items);
|
||||
var i: u32 = 0;
|
||||
while (i < max_len) : (i += 1) {
|
||||
if (i != 0) try writer.writeAll(", ");
|
||||
const elem_val = payload.ptr.elemValue(mod, i) catch |err| switch (err) {
|
||||
error.OutOfMemory => @panic("OOM"), // TODO: eliminate this panic
|
||||
};
|
||||
try print(.{
|
||||
.ty = elem_ty,
|
||||
.val = elem_val,
|
||||
}, writer, level - 1, mod);
|
||||
}
|
||||
if (len > max_aggregate_items) {
|
||||
try writer.writeAll(", ...");
|
||||
}
|
||||
return writer.writeAll(" }");
|
||||
},
|
||||
.eu_payload => {
|
||||
val = val.castTag(.eu_payload).?.data;
|
||||
ty = ty.errorUnionPayload(mod);
|
||||
},
|
||||
.opt_payload => {
|
||||
val = val.castTag(.opt_payload).?.data;
|
||||
ty = ty.optionalChild(mod);
|
||||
return print(.{ .ty = ty, .val = val }, writer, level, mod);
|
||||
},
|
||||
// TODO these should not appear in this function
|
||||
.inferred_alloc => return writer.writeAll("(inferred allocation value)"),
|
||||
.inferred_alloc_comptime => return writer.writeAll("(inferred comptime allocation value)"),
|
||||
|
|
|
|||
|
|
@ -845,8 +845,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
|||
.ptr_elem_val => try self.airPtrElemVal(inst),
|
||||
.ptr_elem_ptr => try self.airPtrElemPtr(inst),
|
||||
|
||||
.constant => unreachable, // excluded from function bodies
|
||||
.interned => unreachable, // excluded from function bodies
|
||||
.inferred_alloc, .inferred_alloc_comptime, .interned => unreachable,
|
||||
.unreach => self.finishAirBookkeeping(),
|
||||
|
||||
.optional_payload => try self.airOptionalPayload(inst),
|
||||
|
|
@ -919,8 +918,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
|||
|
||||
/// Asserts there is already capacity to insert into top branch inst_table.
|
||||
fn processDeath(self: *Self, inst: Air.Inst.Index) void {
|
||||
const air_tags = self.air.instructions.items(.tag);
|
||||
if (air_tags[inst] == .constant) return; // Constants are immortal.
|
||||
assert(self.air.instructions.items(.tag)[inst] != .interned);
|
||||
// When editing this function, note that the logic must synchronize with `reuseOperand`.
|
||||
const prev_value = self.getResolvedInstValue(inst);
|
||||
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 {
|
|||
});
|
||||
|
||||
switch (self.air.instructions.items(.tag)[inst_index]) {
|
||||
.constant => {
|
||||
.interned => {
|
||||
// Constants have static lifetimes, so they are always memoized in the outer most table.
|
||||
const branch = &self.branch_stack.items[0];
|
||||
const gop = try branch.inst_table.getOrPut(self.gpa, inst_index);
|
||||
if (!gop.found_existing) {
|
||||
const ty_pl = self.air.instructions.items(.data)[inst_index].ty_pl;
|
||||
const interned = self.air.instructions.items(.data)[inst_index].interned;
|
||||
gop.value_ptr.* = try self.genTypedValue(.{
|
||||
.ty = inst_ty,
|
||||
.val = self.air.values[ty_pl.payload],
|
||||
.val = interned.toValue(),
|
||||
});
|
||||
}
|
||||
return gop.value_ptr.*;
|
||||
|
|
|
|||
|
|
@ -829,8 +829,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
|||
.ptr_elem_val => try self.airPtrElemVal(inst),
|
||||
.ptr_elem_ptr => try self.airPtrElemPtr(inst),
|
||||
|
||||
.constant => unreachable, // excluded from function bodies
|
||||
.interned => unreachable, // excluded from function bodies
|
||||
.inferred_alloc, .inferred_alloc_comptime, .interned => unreachable,
|
||||
.unreach => self.finishAirBookkeeping(),
|
||||
|
||||
.optional_payload => try self.airOptionalPayload(inst),
|
||||
|
|
@ -903,8 +902,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
|||
|
||||
/// Asserts there is already capacity to insert into top branch inst_table.
|
||||
fn processDeath(self: *Self, inst: Air.Inst.Index) void {
|
||||
const air_tags = self.air.instructions.items(.tag);
|
||||
if (air_tags[inst] == .constant) return; // Constants are immortal.
|
||||
assert(self.air.instructions.items(.tag)[inst] != .interned);
|
||||
// When editing this function, note that the logic must synchronize with `reuseOperand`.
|
||||
const prev_value = self.getResolvedInstValue(inst);
|
||||
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 {
|
|||
});
|
||||
|
||||
switch (self.air.instructions.items(.tag)[inst_index]) {
|
||||
.constant => {
|
||||
.interned => {
|
||||
// Constants have static lifetimes, so they are always memoized in the outer most table.
|
||||
const branch = &self.branch_stack.items[0];
|
||||
const gop = try branch.inst_table.getOrPut(self.gpa, inst_index);
|
||||
if (!gop.found_existing) {
|
||||
const ty_pl = self.air.instructions.items(.data)[inst_index].ty_pl;
|
||||
const interned = self.air.instructions.items(.data)[inst_index].interned;
|
||||
gop.value_ptr.* = try self.genTypedValue(.{
|
||||
.ty = inst_ty,
|
||||
.val = self.air.values[ty_pl.payload],
|
||||
.val = interned.toValue(),
|
||||
});
|
||||
}
|
||||
return gop.value_ptr.*;
|
||||
|
|
|
|||
|
|
@ -659,8 +659,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
|||
.ptr_elem_val => try self.airPtrElemVal(inst),
|
||||
.ptr_elem_ptr => try self.airPtrElemPtr(inst),
|
||||
|
||||
.constant => unreachable, // excluded from function bodies
|
||||
.interned => unreachable, // excluded from function bodies
|
||||
.inferred_alloc, .inferred_alloc_comptime, .interned => unreachable,
|
||||
.unreach => self.finishAirBookkeeping(),
|
||||
|
||||
.optional_payload => try self.airOptionalPayload(inst),
|
||||
|
|
@ -730,8 +729,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
|||
|
||||
/// Asserts there is already capacity to insert into top branch inst_table.
|
||||
fn processDeath(self: *Self, inst: Air.Inst.Index) void {
|
||||
const air_tags = self.air.instructions.items(.tag);
|
||||
if (air_tags[inst] == .constant) return; // Constants are immortal.
|
||||
assert(self.air.instructions.items(.tag)[inst] != .interned);
|
||||
// When editing this function, note that the logic must synchronize with `reuseOperand`.
|
||||
const prev_value = self.getResolvedInstValue(inst);
|
||||
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 {
|
|||
});
|
||||
|
||||
switch (self.air.instructions.items(.tag)[inst_index]) {
|
||||
.constant => {
|
||||
.interned => {
|
||||
// Constants have static lifetimes, so they are always memoized in the outer most table.
|
||||
const branch = &self.branch_stack.items[0];
|
||||
const gop = try branch.inst_table.getOrPut(self.gpa, inst_index);
|
||||
if (!gop.found_existing) {
|
||||
const ty_pl = self.air.instructions.items(.data)[inst_index].ty_pl;
|
||||
const interned = self.air.instructions.items(.data)[inst_index].interned;
|
||||
gop.value_ptr.* = try self.genTypedValue(.{
|
||||
.ty = inst_ty,
|
||||
.val = self.air.values[ty_pl.payload],
|
||||
.val = interned.toValue(),
|
||||
});
|
||||
}
|
||||
return gop.value_ptr.*;
|
||||
|
|
|
|||
|
|
@ -679,8 +679,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
|||
.ptr_elem_val => try self.airPtrElemVal(inst),
|
||||
.ptr_elem_ptr => try self.airPtrElemPtr(inst),
|
||||
|
||||
.constant => unreachable, // excluded from function bodies
|
||||
.interned => unreachable, // excluded from function bodies
|
||||
.inferred_alloc, .inferred_alloc_comptime, .interned => unreachable,
|
||||
.unreach => self.finishAirBookkeeping(),
|
||||
|
||||
.optional_payload => try self.airOptionalPayload(inst),
|
||||
|
|
@ -4423,8 +4422,7 @@ fn performReloc(self: *Self, inst: Mir.Inst.Index) !void {
|
|||
|
||||
/// Asserts there is already capacity to insert into top branch inst_table.
|
||||
fn processDeath(self: *Self, inst: Air.Inst.Index) void {
|
||||
const air_tags = self.air.instructions.items(.tag);
|
||||
if (air_tags[inst] == .constant) return; // Constants are immortal.
|
||||
assert(self.air.instructions.items(.tag)[inst] != .interned);
|
||||
// When editing this function, note that the logic must synchronize with `reuseOperand`.
|
||||
const prev_value = self.getResolvedInstValue(inst);
|
||||
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 {
|
|||
|
||||
if (Air.refToIndex(ref)) |inst| {
|
||||
switch (self.air.instructions.items(.tag)[inst]) {
|
||||
.constant => {
|
||||
.interned => {
|
||||
// Constants have static lifetimes, so they are always memoized in the outer most table.
|
||||
const branch = &self.branch_stack.items[0];
|
||||
const gop = try branch.inst_table.getOrPut(self.gpa, inst);
|
||||
if (!gop.found_existing) {
|
||||
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
|
||||
const interned = self.air.instructions.items(.data)[inst].interned;
|
||||
gop.value_ptr.* = try self.genTypedValue(.{
|
||||
.ty = ty,
|
||||
.val = self.air.values[ty_pl.payload],
|
||||
.val = interned.toValue(),
|
||||
});
|
||||
}
|
||||
return gop.value_ptr.*;
|
||||
|
|
|
|||
|
|
@ -883,7 +883,7 @@ fn iterateBigTomb(func: *CodeGen, inst: Air.Inst.Index, operand_count: usize) !B
|
|||
|
||||
fn processDeath(func: *CodeGen, ref: Air.Inst.Ref) void {
|
||||
const inst = Air.refToIndex(ref) orelse return;
|
||||
if (func.air.instructions.items(.tag)[inst] == .constant) return;
|
||||
assert(func.air.instructions.items(.tag)[inst] != .interned);
|
||||
// Branches are currently only allowed to free locals allocated
|
||||
// within their own branch.
|
||||
// TODO: Upon branch consolidation free any locals if needed.
|
||||
|
|
@ -1832,8 +1832,7 @@ fn buildPointerOffset(func: *CodeGen, ptr_value: WValue, offset: u64, action: en
|
|||
fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const air_tags = func.air.instructions.items(.tag);
|
||||
return switch (air_tags[inst]) {
|
||||
.constant => unreachable,
|
||||
.interned => unreachable,
|
||||
.inferred_alloc, .inferred_alloc_comptime, .interned => unreachable,
|
||||
|
||||
.add => func.airBinOp(inst, .add),
|
||||
.add_sat => func.airSatBinOp(inst, .add),
|
||||
|
|
|
|||
|
|
@ -1922,8 +1922,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
|||
.ptr_elem_val => try self.airPtrElemVal(inst),
|
||||
.ptr_elem_ptr => try self.airPtrElemPtr(inst),
|
||||
|
||||
.constant => unreachable, // excluded from function bodies
|
||||
.interned => unreachable, // excluded from function bodies
|
||||
.inferred_alloc, .inferred_alloc_comptime, .interned => unreachable,
|
||||
.unreach => if (self.wantSafety()) try self.airTrap() else self.finishAirBookkeeping(),
|
||||
|
||||
.optional_payload => try self.airOptionalPayload(inst),
|
||||
|
|
@ -2097,10 +2096,8 @@ fn feed(self: *Self, bt: *Liveness.BigTomb, operand: Air.Inst.Ref) void {
|
|||
|
||||
/// Asserts there is already capacity to insert into top branch inst_table.
|
||||
fn processDeath(self: *Self, inst: Air.Inst.Index) void {
|
||||
switch (self.air.instructions.items(.tag)[inst]) {
|
||||
.constant => unreachable,
|
||||
else => self.inst_tracking.getPtr(inst).?.die(self, inst),
|
||||
}
|
||||
assert(self.air.instructions.items(.tag)[inst] != .interned);
|
||||
self.inst_tracking.getPtr(inst).?.die(self, inst);
|
||||
}
|
||||
|
||||
/// 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 {
|
|||
const dst_info = dst_ty.intInfo(mod);
|
||||
if (Air.refToIndex(dst_air)) |inst| {
|
||||
switch (air_tag[inst]) {
|
||||
.constant => {
|
||||
const src_val = self.air.values[air_data[inst].ty_pl.payload];
|
||||
.interned => {
|
||||
const src_val = air_data[inst].interned.toValue();
|
||||
var space: Value.BigIntSpace = undefined;
|
||||
const src_int = src_val.toBigInt(&space, mod);
|
||||
return @intCast(u16, src_int.bitCountTwosComp()) +
|
||||
|
|
@ -11584,11 +11581,11 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue {
|
|||
|
||||
if (Air.refToIndex(ref)) |inst| {
|
||||
const mcv = switch (self.air.instructions.items(.tag)[inst]) {
|
||||
.constant => tracking: {
|
||||
.interned => tracking: {
|
||||
const gop = try self.const_tracking.getOrPut(self.gpa, inst);
|
||||
if (!gop.found_existing) gop.value_ptr.* = InstTracking.init(try self.genTypedValue(.{
|
||||
.ty = ty,
|
||||
.val = (try self.air.value(ref, mod)).?,
|
||||
.val = self.air.instructions.items(.data)[inst].interned.toValue(),
|
||||
}));
|
||||
break :tracking gop.value_ptr;
|
||||
},
|
||||
|
|
@ -11605,7 +11602,7 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue {
|
|||
|
||||
fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) *InstTracking {
|
||||
const tracking = switch (self.air.instructions.items(.tag)[inst]) {
|
||||
.constant => &self.const_tracking,
|
||||
.interned => &self.const_tracking,
|
||||
else => &self.inst_tracking,
|
||||
}.getPtr(inst).?;
|
||||
return switch (tracking.short) {
|
||||
|
|
|
|||
|
|
@ -2890,8 +2890,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
|
|||
|
||||
const result_value = switch (air_tags[inst]) {
|
||||
// zig fmt: off
|
||||
.constant => unreachable, // excluded from function bodies
|
||||
.interned => unreachable, // excluded from function bodies
|
||||
.inferred_alloc, .inferred_alloc_comptime, .interned => unreachable,
|
||||
|
||||
.arg => try airArg(f, inst),
|
||||
|
||||
|
|
@ -7783,8 +7782,8 @@ fn reap(f: *Function, inst: Air.Inst.Index, operands: []const Air.Inst.Ref) !voi
|
|||
|
||||
fn die(f: *Function, inst: Air.Inst.Index, ref: Air.Inst.Ref) !void {
|
||||
const ref_inst = Air.refToIndex(ref) orelse return;
|
||||
assert(f.air.instructions.items(.tag)[ref_inst] != .interned);
|
||||
const c_value = (f.value_map.fetchRemove(ref_inst) orelse return).value;
|
||||
if (f.air.instructions.items(.tag)[ref_inst] == .constant) return;
|
||||
const local_index = switch (c_value) {
|
||||
.local, .new_local => |l| l,
|
||||
else => return,
|
||||
|
|
|
|||
|
|
@ -4530,8 +4530,7 @@ pub const FuncGen = struct {
|
|||
|
||||
.vector_store_elem => try self.airVectorStoreElem(inst),
|
||||
|
||||
.constant => unreachable,
|
||||
.interned => unreachable,
|
||||
.inferred_alloc, .inferred_alloc_comptime, .interned => unreachable,
|
||||
|
||||
.unreach => self.airUnreach(inst),
|
||||
.dbg_stmt => self.airDbgStmt(inst),
|
||||
|
|
|
|||
|
|
@ -1807,7 +1807,6 @@ pub const DeclGen = struct {
|
|||
.br => return self.airBr(inst),
|
||||
.breakpoint => return,
|
||||
.cond_br => return self.airCondBr(inst),
|
||||
.constant => unreachable,
|
||||
.dbg_stmt => return self.airDbgStmt(inst),
|
||||
.loop => return self.airLoop(inst),
|
||||
.ret => return self.airRet(inst),
|
||||
|
|
|
|||
|
|
@ -93,14 +93,10 @@ const Writer = struct {
|
|||
|
||||
fn writeAllConstants(w: *Writer, s: anytype) @TypeOf(s).Error!void {
|
||||
for (w.air.instructions.items(.tag), 0..) |tag, i| {
|
||||
if (tag != .interned) continue;
|
||||
const inst = @intCast(Air.Inst.Index, i);
|
||||
switch (tag) {
|
||||
.constant, .interned => {
|
||||
try w.writeInst(s, inst);
|
||||
try s.writeByte('\n');
|
||||
},
|
||||
else => continue,
|
||||
}
|
||||
try w.writeInst(s, inst);
|
||||
try s.writeByte('\n');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -304,7 +300,7 @@ const Writer = struct {
|
|||
|
||||
.struct_field_ptr => try w.writeStructField(s, inst),
|
||||
.struct_field_val => try w.writeStructField(s, inst),
|
||||
.constant => try w.writeConstant(s, inst),
|
||||
.inferred_alloc, .inferred_alloc_comptime => try w.writeConstant(s, inst),
|
||||
.interned => try w.writeInterned(s, inst),
|
||||
.assembly => try w.writeAssembly(s, inst),
|
||||
.dbg_stmt => try w.writeDbgStmt(s, inst),
|
||||
|
|
|
|||
198
src/value.zig
198
src/value.zig
|
|
@ -35,6 +35,22 @@ pub const Value = struct {
|
|||
// The first section of this enum are tags that require no payload.
|
||||
// After this, the tag requires a payload.
|
||||
|
||||
/// When the type is error union:
|
||||
/// * If the tag is `.@"error"`, the error union is an error.
|
||||
/// * If the tag is `.eu_payload`, the error union is a payload.
|
||||
/// * A nested error such as `anyerror!(anyerror!T)` in which the the outer error union
|
||||
/// is non-error, but the inner error union is an error, is represented as
|
||||
/// a tag of `.eu_payload`, with a sub-tag of `.@"error"`.
|
||||
eu_payload,
|
||||
/// When the type is optional:
|
||||
/// * If the tag is `.null_value`, the optional is null.
|
||||
/// * If the tag is `.opt_payload`, the optional is a payload.
|
||||
/// * A nested optional such as `??T` in which the the outer optional
|
||||
/// is non-null, but the inner optional is null, is represented as
|
||||
/// a tag of `.opt_payload`, with a sub-tag of `.null_value`.
|
||||
opt_payload,
|
||||
/// Pointer and length as sub `Value` objects.
|
||||
slice,
|
||||
/// A slice of u8 whose memory is managed externally.
|
||||
bytes,
|
||||
/// This value is repeated some number of times. The amount of times to repeat
|
||||
|
|
@ -58,14 +74,16 @@ pub const Value = struct {
|
|||
|
||||
pub fn Type(comptime t: Tag) type {
|
||||
return switch (t) {
|
||||
.repeated => Payload.SubValue,
|
||||
|
||||
.eu_payload,
|
||||
.opt_payload,
|
||||
.repeated,
|
||||
=> Payload.SubValue,
|
||||
.slice => Payload.Slice,
|
||||
.bytes => Payload.Bytes,
|
||||
|
||||
.inferred_alloc => Payload.InferredAlloc,
|
||||
.inferred_alloc_comptime => Payload.InferredAllocComptime,
|
||||
.aggregate => Payload.Aggregate,
|
||||
.@"union" => Payload.Union,
|
||||
.inferred_alloc => Payload.InferredAlloc,
|
||||
.inferred_alloc_comptime => Payload.InferredAllocComptime,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -172,7 +190,10 @@ pub const Value = struct {
|
|||
.legacy = .{ .ptr_otherwise = &new_payload.base },
|
||||
};
|
||||
},
|
||||
.repeated => {
|
||||
.eu_payload,
|
||||
.opt_payload,
|
||||
.repeated,
|
||||
=> {
|
||||
const payload = self.cast(Payload.SubValue).?;
|
||||
const new_payload = try arena.create(Payload.SubValue);
|
||||
new_payload.* = .{
|
||||
|
|
@ -184,6 +205,21 @@ pub const Value = struct {
|
|||
.legacy = .{ .ptr_otherwise = &new_payload.base },
|
||||
};
|
||||
},
|
||||
.slice => {
|
||||
const payload = self.castTag(.slice).?;
|
||||
const new_payload = try arena.create(Payload.Slice);
|
||||
new_payload.* = .{
|
||||
.base = payload.base,
|
||||
.data = .{
|
||||
.ptr = try payload.data.ptr.copy(arena),
|
||||
.len = try payload.data.len.copy(arena),
|
||||
},
|
||||
};
|
||||
return Value{
|
||||
.ip_index = .none,
|
||||
.legacy = .{ .ptr_otherwise = &new_payload.base },
|
||||
};
|
||||
},
|
||||
.aggregate => {
|
||||
const payload = self.castTag(.aggregate).?;
|
||||
const new_payload = try arena.create(Payload.Aggregate);
|
||||
|
|
@ -263,6 +299,15 @@ pub const Value = struct {
|
|||
try out_stream.writeAll("(repeated) ");
|
||||
val = val.castTag(.repeated).?.data;
|
||||
},
|
||||
.eu_payload => {
|
||||
try out_stream.writeAll("(eu_payload) ");
|
||||
val = val.castTag(.repeated).?.data;
|
||||
},
|
||||
.opt_payload => {
|
||||
try out_stream.writeAll("(opt_payload) ");
|
||||
val = val.castTag(.repeated).?.data;
|
||||
},
|
||||
.slice => return out_stream.writeAll("(slice)"),
|
||||
.inferred_alloc => return out_stream.writeAll("(inferred allocation value)"),
|
||||
.inferred_alloc_comptime => return out_stream.writeAll("(inferred comptime allocation value)"),
|
||||
};
|
||||
|
|
@ -1653,13 +1698,18 @@ pub const Value = struct {
|
|||
.Null,
|
||||
.Struct, // It sure would be nice to do something clever with structs.
|
||||
=> |zig_type_tag| std.hash.autoHash(hasher, zig_type_tag),
|
||||
.Pointer => {
|
||||
assert(ty.isSlice(mod));
|
||||
const slice = val.castTag(.slice).?.data;
|
||||
const ptr_ty = ty.slicePtrFieldType(mod);
|
||||
slice.ptr.hashUncoerced(ptr_ty, hasher, mod);
|
||||
},
|
||||
.Type,
|
||||
.Float,
|
||||
.ComptimeFloat,
|
||||
.Bool,
|
||||
.Int,
|
||||
.ComptimeInt,
|
||||
.Pointer,
|
||||
.Fn,
|
||||
.Optional,
|
||||
.ErrorSet,
|
||||
|
|
@ -1799,9 +1849,15 @@ pub const Value = struct {
|
|||
/// Asserts the value is a single-item pointer to an array, or an array,
|
||||
/// or an unknown-length pointer, and returns the element value at the index.
|
||||
pub fn elemValue(val: Value, mod: *Module, index: usize) Allocator.Error!Value {
|
||||
switch (val.toIntern()) {
|
||||
.undef => return Value.undef,
|
||||
else => return switch (mod.intern_pool.indexToKey(val.toIntern())) {
|
||||
return switch (val.ip_index) {
|
||||
.undef => Value.undef,
|
||||
.none => switch (val.tag()) {
|
||||
.repeated => val.castTag(.repeated).?.data,
|
||||
.aggregate => val.castTag(.aggregate).?.data[index],
|
||||
.slice => val.castTag(.slice).?.data.ptr.elemValue(mod, index),
|
||||
else => unreachable,
|
||||
},
|
||||
else => switch (mod.intern_pool.indexToKey(val.toIntern())) {
|
||||
.ptr => |ptr| switch (ptr.addr) {
|
||||
.decl => |decl| mod.declPtr(decl).val.elemValue(mod, index),
|
||||
.mut_decl => |mut_decl| mod.declPtr(mut_decl.decl).val.elemValue(mod, index),
|
||||
|
|
@ -1829,7 +1885,7 @@ pub const Value = struct {
|
|||
},
|
||||
else => unreachable,
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn isLazyAlign(val: Value, mod: *Module) bool {
|
||||
|
|
@ -1875,25 +1931,28 @@ pub const Value = struct {
|
|||
}
|
||||
|
||||
pub fn isPtrToThreadLocal(val: Value, mod: *Module) bool {
|
||||
return switch (mod.intern_pool.indexToKey(val.toIntern())) {
|
||||
.variable => |variable| variable.is_threadlocal,
|
||||
.ptr => |ptr| switch (ptr.addr) {
|
||||
.decl => |decl_index| {
|
||||
const decl = mod.declPtr(decl_index);
|
||||
assert(decl.has_tv);
|
||||
return decl.val.isPtrToThreadLocal(mod);
|
||||
return switch (val.ip_index) {
|
||||
.none => false,
|
||||
else => switch (mod.intern_pool.indexToKey(val.toIntern())) {
|
||||
.variable => |variable| variable.is_threadlocal,
|
||||
.ptr => |ptr| switch (ptr.addr) {
|
||||
.decl => |decl_index| {
|
||||
const decl = mod.declPtr(decl_index);
|
||||
assert(decl.has_tv);
|
||||
return decl.val.isPtrToThreadLocal(mod);
|
||||
},
|
||||
.mut_decl => |mut_decl| {
|
||||
const decl = mod.declPtr(mut_decl.decl);
|
||||
assert(decl.has_tv);
|
||||
return decl.val.isPtrToThreadLocal(mod);
|
||||
},
|
||||
.int => false,
|
||||
.eu_payload, .opt_payload => |base_ptr| base_ptr.toValue().isPtrToThreadLocal(mod),
|
||||
.comptime_field => |comptime_field| comptime_field.toValue().isPtrToThreadLocal(mod),
|
||||
.elem, .field => |base_index| base_index.base.toValue().isPtrToThreadLocal(mod),
|
||||
},
|
||||
.mut_decl => |mut_decl| {
|
||||
const decl = mod.declPtr(mut_decl.decl);
|
||||
assert(decl.has_tv);
|
||||
return decl.val.isPtrToThreadLocal(mod);
|
||||
},
|
||||
.int => false,
|
||||
.eu_payload, .opt_payload => |base_ptr| base_ptr.toValue().isPtrToThreadLocal(mod),
|
||||
.comptime_field => |comptime_field| comptime_field.toValue().isPtrToThreadLocal(mod),
|
||||
.elem, .field => |base_index| base_index.base.toValue().isPtrToThreadLocal(mod),
|
||||
else => false,
|
||||
},
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -1926,9 +1985,21 @@ pub const Value = struct {
|
|||
}
|
||||
|
||||
pub fn fieldValue(val: Value, mod: *Module, index: usize) !Value {
|
||||
switch (val.toIntern()) {
|
||||
.undef => return Value.undef,
|
||||
else => return switch (mod.intern_pool.indexToKey(val.toIntern())) {
|
||||
return switch (val.ip_index) {
|
||||
.undef => Value.undef,
|
||||
.none => switch (val.tag()) {
|
||||
.aggregate => {
|
||||
const field_values = val.castTag(.aggregate).?.data;
|
||||
return field_values[index];
|
||||
},
|
||||
.@"union" => {
|
||||
const payload = val.castTag(.@"union").?.data;
|
||||
// TODO assert the tag is correct
|
||||
return payload.val;
|
||||
},
|
||||
else => unreachable,
|
||||
},
|
||||
else => switch (mod.intern_pool.indexToKey(val.toIntern())) {
|
||||
.aggregate => |aggregate| switch (aggregate.storage) {
|
||||
.bytes => |bytes| try mod.intern(.{ .int = .{
|
||||
.ty = .u8_type,
|
||||
|
|
@ -1941,7 +2012,7 @@ pub const Value = struct {
|
|||
.un => |un| un.val.toValue(),
|
||||
else => unreachable,
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn unionTag(val: Value, mod: *Module) Value {
|
||||
|
|
@ -1956,36 +2027,17 @@ pub const Value = struct {
|
|||
/// Returns a pointer to the element value at the index.
|
||||
pub fn elemPtr(
|
||||
val: Value,
|
||||
ty: Type,
|
||||
elem_ptr_ty: Type,
|
||||
index: usize,
|
||||
mod: *Module,
|
||||
) Allocator.Error!Value {
|
||||
const elem_ty = ty.elemType2(mod);
|
||||
const ptr_ty_key = mod.intern_pool.indexToKey(ty.toIntern()).ptr_type;
|
||||
assert(ptr_ty_key.host_size == 0);
|
||||
assert(ptr_ty_key.bit_offset == 0);
|
||||
assert(ptr_ty_key.vector_index == .none);
|
||||
const elem_alignment = InternPool.Alignment.fromByteUnits(elem_ty.abiAlignment(mod));
|
||||
const alignment = switch (ptr_ty_key.alignment) {
|
||||
.none => .none,
|
||||
else => ptr_ty_key.alignment.min(
|
||||
@intToEnum(InternPool.Alignment, @ctz(index * elem_ty.abiSize(mod))),
|
||||
),
|
||||
};
|
||||
const ptr_ty = try mod.ptrType(.{
|
||||
.elem_type = elem_ty.toIntern(),
|
||||
.alignment = if (alignment == elem_alignment) .none else alignment,
|
||||
.is_const = ptr_ty_key.is_const,
|
||||
.is_volatile = ptr_ty_key.is_volatile,
|
||||
.is_allowzero = ptr_ty_key.is_allowzero,
|
||||
.address_space = ptr_ty_key.address_space,
|
||||
});
|
||||
const elem_ty = elem_ptr_ty.childType(mod);
|
||||
const ptr_val = switch (mod.intern_pool.indexToKey(val.toIntern())) {
|
||||
.ptr => |ptr| ptr: {
|
||||
switch (ptr.addr) {
|
||||
.elem => |elem| if (mod.intern_pool.typeOf(elem.base).toType().elemType2(mod).eql(elem_ty, mod))
|
||||
return (try mod.intern(.{ .ptr = .{
|
||||
.ty = ptr_ty.toIntern(),
|
||||
.ty = elem_ptr_ty.toIntern(),
|
||||
.addr = .{ .elem = .{
|
||||
.base = elem.base,
|
||||
.index = elem.index + index,
|
||||
|
|
@ -2001,7 +2053,7 @@ pub const Value = struct {
|
|||
else => val,
|
||||
};
|
||||
return (try mod.intern(.{ .ptr = .{
|
||||
.ty = ptr_ty.toIntern(),
|
||||
.ty = elem_ptr_ty.toIntern(),
|
||||
.addr = .{ .elem = .{
|
||||
.base = ptr_val.toIntern(),
|
||||
.index = index,
|
||||
|
|
@ -4058,9 +4110,12 @@ pub const Value = struct {
|
|||
pub const Payload = struct {
|
||||
tag: Tag,
|
||||
|
||||
pub const SubValue = struct {
|
||||
pub const Slice = struct {
|
||||
base: Payload,
|
||||
data: Value,
|
||||
data: struct {
|
||||
ptr: Value,
|
||||
len: Value,
|
||||
},
|
||||
};
|
||||
|
||||
pub const Bytes = struct {
|
||||
|
|
@ -4069,6 +4124,11 @@ pub const Value = struct {
|
|||
data: []const u8,
|
||||
};
|
||||
|
||||
pub const SubValue = struct {
|
||||
base: Payload,
|
||||
data: Value,
|
||||
};
|
||||
|
||||
pub const Aggregate = struct {
|
||||
base: Payload,
|
||||
/// Field values. The types are according to the struct or array type.
|
||||
|
|
@ -4076,6 +4136,18 @@ pub const Value = struct {
|
|||
data: []Value,
|
||||
};
|
||||
|
||||
pub const Union = struct {
|
||||
pub const base_tag = Tag.@"union";
|
||||
|
||||
base: Payload = .{ .tag = base_tag },
|
||||
data: Data,
|
||||
|
||||
pub const Data = struct {
|
||||
tag: Value,
|
||||
val: Value,
|
||||
};
|
||||
};
|
||||
|
||||
pub const InferredAlloc = struct {
|
||||
pub const base_tag = Tag.inferred_alloc;
|
||||
|
||||
|
|
@ -4110,18 +4182,6 @@ pub const Value = struct {
|
|||
alignment: u32,
|
||||
},
|
||||
};
|
||||
|
||||
pub const Union = struct {
|
||||
pub const base_tag = Tag.@"union";
|
||||
|
||||
base: Payload = .{ .tag = base_tag },
|
||||
data: Data,
|
||||
|
||||
pub const Data = struct {
|
||||
tag: Value,
|
||||
val: Value,
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
pub const BigIntSpace = InternPool.Key.Int.Storage.BigIntSpace;
|
||||
|
|
|
|||
|
|
@ -682,4 +682,10 @@ def __lldb_init_module(debugger, _=None):
|
|||
add(debugger, category='zig.stage2', regex=True, type='^Air\\.Inst\\.Data\\.Data__struct_[1-9][0-9]*$', inline_children=True, summary=True)
|
||||
add(debugger, category='zig.stage2', type='Module.Decl::Module.Decl.Index', synth=True)
|
||||
add(debugger, category='zig.stage2', type='InternPool.Index', synth=True)
|
||||
add(debugger, category='zig.stage2', type='InternPool.Key', identifier='zig_TaggedUnion', synth=True)
|
||||
add(debugger, category='zig.stage2', type='InternPool.Key.Int.Storage', identifier='zig_TaggedUnion', synth=True)
|
||||
add(debugger, category='zig.stage2', type='InternPool.Key.ErrorUnion.Value', identifier='zig_TaggedUnion', synth=True)
|
||||
add(debugger, category='zig.stage2', type='InternPool.Key.Float.Storage', identifier='zig_TaggedUnion', synth=True)
|
||||
add(debugger, category='zig.stage2', type='InternPool.Key.Ptr.Addr', identifier='zig_TaggedUnion', synth=True)
|
||||
add(debugger, category='zig.stage2', type='InternPool.Key.Aggregate.Storage', identifier='zig_TaggedUnion', synth=True)
|
||||
add(debugger, category='zig.stage2', type='arch.x86_64.CodeGen.MCValue', identifier='zig_TaggedUnion', synth=True, inline_children=True, summary=True)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue