mirror of
https://github.com/ziglang/zig.git
synced 2026-02-20 08:14:48 +00:00
stage2: make zir.Inst.Ref a non-exhaustive enum
This provides us greatly increased type safety and prevents the common mistake of using a zir.Inst.Ref where a zir.Inst.Index was expected or vice-versa. It also increases the ergonomics of using the typed values which can be directly referenced with a Ref over the previous zir.Const approach. The main pain point is casting between a []Ref and []u32, which could be alleviated in the future with a new std.mem function.
This commit is contained in:
parent
a1afe69395
commit
0c601965ab
@ -32,7 +32,7 @@ pub fn EnumFieldStruct(comptime E: type, comptime Data: type, comptime field_def
|
||||
.fields = fields,
|
||||
.decls = &[_]std.builtin.TypeInfo.Declaration{},
|
||||
.is_tuple = false,
|
||||
}});
|
||||
} });
|
||||
}
|
||||
|
||||
/// Looks up the supplied fields in the given enum type.
|
||||
@ -70,7 +70,7 @@ pub fn values(comptime E: type) []const E {
|
||||
|
||||
test "std.enum.values" {
|
||||
const E = extern enum { a, b, c, d = 0 };
|
||||
testing.expectEqualSlices(E, &.{.a, .b, .c, .d}, values(E));
|
||||
testing.expectEqualSlices(E, &.{ .a, .b, .c, .d }, values(E));
|
||||
}
|
||||
|
||||
/// Returns the set of all unique named values in the given enum, in
|
||||
@ -82,10 +82,10 @@ pub fn uniqueValues(comptime E: type) []const E {
|
||||
|
||||
test "std.enum.uniqueValues" {
|
||||
const E = extern enum { a, b, c, d = 0, e, f = 3 };
|
||||
testing.expectEqualSlices(E, &.{.a, .b, .c, .f}, uniqueValues(E));
|
||||
testing.expectEqualSlices(E, &.{ .a, .b, .c, .f }, uniqueValues(E));
|
||||
|
||||
const F = enum { a, b, c };
|
||||
testing.expectEqualSlices(F, &.{.a, .b, .c}, uniqueValues(F));
|
||||
testing.expectEqualSlices(F, &.{ .a, .b, .c }, uniqueValues(F));
|
||||
}
|
||||
|
||||
/// Returns the set of all unique field values in the given enum, in
|
||||
@ -102,8 +102,7 @@ pub fn uniqueFields(comptime E: type) []const EnumField {
|
||||
}
|
||||
|
||||
var unique_fields: []const EnumField = &[_]EnumField{};
|
||||
outer:
|
||||
for (raw_fields) |candidate| {
|
||||
outer: for (raw_fields) |candidate| {
|
||||
for (unique_fields) |u| {
|
||||
if (u.value == candidate.value)
|
||||
continue :outer;
|
||||
@ -116,28 +115,25 @@ pub fn uniqueFields(comptime E: type) []const EnumField {
|
||||
}
|
||||
|
||||
/// Determines the length of a direct-mapped enum array, indexed by
|
||||
/// @intCast(usize, @enumToInt(enum_value)). The enum must be exhaustive.
|
||||
/// @intCast(usize, @enumToInt(enum_value)).
|
||||
/// If the enum is non-exhaustive, the resulting length will only be enough
|
||||
/// to hold all explicit fields.
|
||||
/// If the enum contains any fields with values that cannot be represented
|
||||
/// by usize, a compile error is issued. The max_unused_slots parameter limits
|
||||
/// the total number of items which have no matching enum key (holes in the enum
|
||||
/// numbering). So for example, if an enum has values 1, 2, 5, and 6, max_unused_slots
|
||||
/// must be at least 3, to allow unused slots 0, 3, and 4.
|
||||
fn directEnumArrayLen(comptime E: type, comptime max_unused_slots: comptime_int) comptime_int {
|
||||
const info = @typeInfo(E).Enum;
|
||||
if (!info.is_exhaustive) {
|
||||
@compileError("Cannot create direct array of non-exhaustive enum "++@typeName(E));
|
||||
}
|
||||
|
||||
var max_value: comptime_int = -1;
|
||||
const max_usize: comptime_int = ~@as(usize, 0);
|
||||
const fields = uniqueFields(E);
|
||||
for (fields) |f| {
|
||||
if (f.value < 0) {
|
||||
@compileError("Cannot create a direct enum array for "++@typeName(E)++", field ."++f.name++" has a negative value.");
|
||||
@compileError("Cannot create a direct enum array for " ++ @typeName(E) ++ ", field ." ++ f.name ++ " has a negative value.");
|
||||
}
|
||||
if (f.value > max_value) {
|
||||
if (f.value > max_usize) {
|
||||
@compileError("Cannot create a direct enum array for "++@typeName(E)++", field ."++f.name++" is larger than the max value of usize.");
|
||||
@compileError("Cannot create a direct enum array for " ++ @typeName(E) ++ ", field ." ++ f.name ++ " is larger than the max value of usize.");
|
||||
}
|
||||
max_value = f.value;
|
||||
}
|
||||
@ -147,14 +143,16 @@ fn directEnumArrayLen(comptime E: type, comptime max_unused_slots: comptime_int)
|
||||
if (unused_slots > max_unused_slots) {
|
||||
const unused_str = std.fmt.comptimePrint("{d}", .{unused_slots});
|
||||
const allowed_str = std.fmt.comptimePrint("{d}", .{max_unused_slots});
|
||||
@compileError("Cannot create a direct enum array for "++@typeName(E)++". It would have "++unused_str++" unused slots, but only "++allowed_str++" are allowed.");
|
||||
@compileError("Cannot create a direct enum array for " ++ @typeName(E) ++ ". It would have " ++ unused_str ++ " unused slots, but only " ++ allowed_str ++ " are allowed.");
|
||||
}
|
||||
|
||||
return max_value + 1;
|
||||
}
|
||||
|
||||
/// Initializes an array of Data which can be indexed by
|
||||
/// @intCast(usize, @enumToInt(enum_value)). The enum must be exhaustive.
|
||||
/// @intCast(usize, @enumToInt(enum_value)).
|
||||
/// If the enum is non-exhaustive, the resulting array will only be large enough
|
||||
/// to hold all explicit fields.
|
||||
/// If the enum contains any fields with values that cannot be represented
|
||||
/// by usize, a compile error is issued. The max_unused_slots parameter limits
|
||||
/// the total number of items which have no matching enum key (holes in the enum
|
||||
@ -243,9 +241,9 @@ pub fn nameCast(comptime E: type, comptime value: anytype) E {
|
||||
if (@hasField(E, n)) {
|
||||
return @field(E, n);
|
||||
}
|
||||
@compileError("Enum "++@typeName(E)++" has no field named "++n);
|
||||
@compileError("Enum " ++ @typeName(E) ++ " has no field named " ++ n);
|
||||
}
|
||||
@compileError("Cannot cast from "++@typeName(@TypeOf(value))++" to "++@typeName(E));
|
||||
@compileError("Cannot cast from " ++ @typeName(@TypeOf(value)) ++ " to " ++ @typeName(E));
|
||||
}
|
||||
}
|
||||
|
||||
@ -256,7 +254,7 @@ test "std.enums.nameCast" {
|
||||
testing.expectEqual(A.a, nameCast(A, A.a));
|
||||
testing.expectEqual(A.a, nameCast(A, B.a));
|
||||
testing.expectEqual(A.a, nameCast(A, "a"));
|
||||
testing.expectEqual(A.a, nameCast(A, @as(*const[1]u8, "a")));
|
||||
testing.expectEqual(A.a, nameCast(A, @as(*const [1]u8, "a")));
|
||||
testing.expectEqual(A.a, nameCast(A, @as([:0]const u8, "a")));
|
||||
testing.expectEqual(A.a, nameCast(A, @as([]const u8, "a")));
|
||||
|
||||
@ -398,12 +396,12 @@ pub fn EnumArray(comptime E: type, comptime V: type) type {
|
||||
pub fn NoExtension(comptime Self: type) type {
|
||||
return NoExt;
|
||||
}
|
||||
const NoExt = struct{};
|
||||
const NoExt = struct {};
|
||||
|
||||
/// A set type with an Indexer mapping from keys to indices.
|
||||
/// Presence or absence is stored as a dense bitfield. This
|
||||
/// type does no allocation and can be copied by value.
|
||||
pub fn IndexedSet(comptime I: type, comptime Ext: fn(type)type) type {
|
||||
pub fn IndexedSet(comptime I: type, comptime Ext: fn (type) type) type {
|
||||
comptime ensureIndexer(I);
|
||||
return struct {
|
||||
const Self = @This();
|
||||
@ -422,7 +420,7 @@ pub fn IndexedSet(comptime I: type, comptime Ext: fn(type)type) type {
|
||||
|
||||
bits: BitSet = BitSet.initEmpty(),
|
||||
|
||||
/// Returns a set containing all possible keys.
|
||||
/// Returns a set containing all possible keys.
|
||||
pub fn initFull() Self {
|
||||
return .{ .bits = BitSet.initFull() };
|
||||
}
|
||||
@ -492,7 +490,8 @@ pub fn IndexedSet(comptime I: type, comptime Ext: fn(type)type) type {
|
||||
pub fn next(self: *Iterator) ?Key {
|
||||
return if (self.inner.next()) |index|
|
||||
Indexer.keyForIndex(index)
|
||||
else null;
|
||||
else
|
||||
null;
|
||||
}
|
||||
};
|
||||
};
|
||||
@ -501,7 +500,7 @@ pub fn IndexedSet(comptime I: type, comptime Ext: fn(type)type) type {
|
||||
/// A map from keys to values, using an index lookup. Uses a
|
||||
/// bitfield to track presence and a dense array of values.
|
||||
/// This type does no allocation and can be copied by value.
|
||||
pub fn IndexedMap(comptime I: type, comptime V: type, comptime Ext: fn(type)type) type {
|
||||
pub fn IndexedMap(comptime I: type, comptime V: type, comptime Ext: fn (type) type) type {
|
||||
comptime ensureIndexer(I);
|
||||
return struct {
|
||||
const Self = @This();
|
||||
@ -652,7 +651,8 @@ pub fn IndexedMap(comptime I: type, comptime V: type, comptime Ext: fn(type)type
|
||||
.key = Indexer.keyForIndex(index),
|
||||
.value = &self.values[index],
|
||||
}
|
||||
else null;
|
||||
else
|
||||
null;
|
||||
}
|
||||
};
|
||||
};
|
||||
@ -660,7 +660,7 @@ pub fn IndexedMap(comptime I: type, comptime V: type, comptime Ext: fn(type)type
|
||||
|
||||
/// A dense array of values, using an indexed lookup.
|
||||
/// This type does no allocation and can be copied by value.
|
||||
pub fn IndexedArray(comptime I: type, comptime V: type, comptime Ext: fn(type)type) type {
|
||||
pub fn IndexedArray(comptime I: type, comptime V: type, comptime Ext: fn (type) type) type {
|
||||
comptime ensureIndexer(I);
|
||||
return struct {
|
||||
const Self = @This();
|
||||
@ -769,9 +769,9 @@ pub fn ensureIndexer(comptime T: type) void {
|
||||
if (!@hasDecl(T, "count")) @compileError("Indexer must have decl count: usize.");
|
||||
if (@TypeOf(T.count) != usize) @compileError("Indexer.count must be a usize.");
|
||||
if (!@hasDecl(T, "indexOf")) @compileError("Indexer.indexOf must be a fn(Key)usize.");
|
||||
if (@TypeOf(T.indexOf) != fn(T.Key)usize) @compileError("Indexer must have decl indexOf: fn(Key)usize.");
|
||||
if (@TypeOf(T.indexOf) != fn (T.Key) usize) @compileError("Indexer must have decl indexOf: fn(Key)usize.");
|
||||
if (!@hasDecl(T, "keyForIndex")) @compileError("Indexer must have decl keyForIndex: fn(usize)Key.");
|
||||
if (@TypeOf(T.keyForIndex) != fn(usize)T.Key) @compileError("Indexer.keyForIndex must be a fn(usize)Key.");
|
||||
if (@TypeOf(T.keyForIndex) != fn (usize) T.Key) @compileError("Indexer.keyForIndex must be a fn(usize)Key.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -802,14 +802,18 @@ pub fn EnumIndexer(comptime E: type) type {
|
||||
return struct {
|
||||
pub const Key = E;
|
||||
pub const count: usize = 0;
|
||||
pub fn indexOf(e: E) usize { unreachable; }
|
||||
pub fn keyForIndex(i: usize) E { unreachable; }
|
||||
pub fn indexOf(e: E) usize {
|
||||
unreachable;
|
||||
}
|
||||
pub fn keyForIndex(i: usize) E {
|
||||
unreachable;
|
||||
}
|
||||
};
|
||||
}
|
||||
std.sort.sort(EnumField, &fields, {}, ascByValue);
|
||||
const min = fields[0].value;
|
||||
const max = fields[fields.len-1].value;
|
||||
if (max - min == fields.len-1) {
|
||||
const max = fields[fields.len - 1].value;
|
||||
if (max - min == fields.len - 1) {
|
||||
return struct {
|
||||
pub const Key = E;
|
||||
pub const count = fields.len;
|
||||
@ -844,7 +848,7 @@ pub fn EnumIndexer(comptime E: type) type {
|
||||
}
|
||||
|
||||
test "std.enums.EnumIndexer dense zeroed" {
|
||||
const E = enum{ b = 1, a = 0, c = 2 };
|
||||
const E = enum { b = 1, a = 0, c = 2 };
|
||||
const Indexer = EnumIndexer(E);
|
||||
ensureIndexer(Indexer);
|
||||
testing.expectEqual(E, Indexer.Key);
|
||||
@ -908,7 +912,7 @@ test "std.enums.EnumIndexer sparse" {
|
||||
}
|
||||
|
||||
test "std.enums.EnumIndexer repeats" {
|
||||
const E = extern enum{ a = -2, c = 6, b = 4, b2 = 4 };
|
||||
const E = extern enum { a = -2, c = 6, b = 4, b2 = 4 };
|
||||
const Indexer = EnumIndexer(E);
|
||||
ensureIndexer(Indexer);
|
||||
testing.expectEqual(E, Indexer.Key);
|
||||
@ -957,7 +961,8 @@ test "std.enums.EnumSet" {
|
||||
}
|
||||
|
||||
var mut = Set.init(.{
|
||||
.a=true, .c=true,
|
||||
.a = true,
|
||||
.c = true,
|
||||
});
|
||||
testing.expectEqual(@as(usize, 2), mut.count());
|
||||
testing.expectEqual(true, mut.contains(.a));
|
||||
@ -986,7 +991,7 @@ test "std.enums.EnumSet" {
|
||||
testing.expectEqual(@as(?E, null), it.next());
|
||||
}
|
||||
|
||||
mut.toggleSet(Set.init(.{ .a=true, .b=true }));
|
||||
mut.toggleSet(Set.init(.{ .a = true, .b = true }));
|
||||
testing.expectEqual(@as(usize, 2), mut.count());
|
||||
testing.expectEqual(true, mut.contains(.a));
|
||||
testing.expectEqual(false, mut.contains(.b));
|
||||
@ -994,7 +999,7 @@ test "std.enums.EnumSet" {
|
||||
testing.expectEqual(true, mut.contains(.d));
|
||||
testing.expectEqual(true, mut.contains(.e)); // aliases a
|
||||
|
||||
mut.setUnion(Set.init(.{ .a=true, .b=true }));
|
||||
mut.setUnion(Set.init(.{ .a = true, .b = true }));
|
||||
testing.expectEqual(@as(usize, 3), mut.count());
|
||||
testing.expectEqual(true, mut.contains(.a));
|
||||
testing.expectEqual(true, mut.contains(.b));
|
||||
@ -1009,7 +1014,7 @@ test "std.enums.EnumSet" {
|
||||
testing.expectEqual(false, mut.contains(.c));
|
||||
testing.expectEqual(true, mut.contains(.d));
|
||||
|
||||
mut.setIntersection(Set.init(.{ .a=true, .b=true }));
|
||||
mut.setIntersection(Set.init(.{ .a = true, .b = true }));
|
||||
testing.expectEqual(@as(usize, 1), mut.count());
|
||||
testing.expectEqual(true, mut.contains(.a));
|
||||
testing.expectEqual(false, mut.contains(.b));
|
||||
@ -1072,7 +1077,7 @@ test "std.enums.EnumArray sized" {
|
||||
const undef = Array.initUndefined();
|
||||
var inst = Array.initFill(5);
|
||||
const inst2 = Array.init(.{ .a = 1, .b = 2, .c = 3, .d = 4 });
|
||||
const inst3 = Array.initDefault(6, .{.b = 4, .c = 2});
|
||||
const inst3 = Array.initDefault(6, .{ .b = 4, .c = 2 });
|
||||
|
||||
testing.expectEqual(@as(usize, 5), inst.get(.a));
|
||||
testing.expectEqual(@as(usize, 5), inst.get(.b));
|
||||
@ -1272,10 +1277,12 @@ test "std.enums.EnumMap sized" {
|
||||
var iter = a.iterator();
|
||||
const Entry = Map.Entry;
|
||||
testing.expectEqual(@as(?Entry, Entry{
|
||||
.key = .b, .value = &a.values[1],
|
||||
.key = .b,
|
||||
.value = &a.values[1],
|
||||
}), iter.next());
|
||||
testing.expectEqual(@as(?Entry, Entry{
|
||||
.key = .d, .value = &a.values[3],
|
||||
.key = .d,
|
||||
.value = &a.values[3],
|
||||
}), iter.next());
|
||||
testing.expectEqual(@as(?Entry, null), iter.next());
|
||||
}
|
||||
|
||||
@ -914,16 +914,16 @@ pub const Scope = struct {
|
||||
parent: *Scope,
|
||||
/// All `GenZir` scopes for the same ZIR share this.
|
||||
zir_code: *WipZirCode,
|
||||
/// Keeps track of the list of instructions in this scope only. References
|
||||
/// Keeps track of the list of instructions in this scope only. Indexes
|
||||
/// to instructions in `zir_code`.
|
||||
instructions: std.ArrayListUnmanaged(zir.Inst.Ref) = .{},
|
||||
instructions: std.ArrayListUnmanaged(zir.Inst.Index) = .{},
|
||||
label: ?Label = null,
|
||||
break_block: zir.Inst.Index = 0,
|
||||
continue_block: zir.Inst.Index = 0,
|
||||
/// Only valid when setBlockResultLoc is called.
|
||||
break_result_loc: astgen.ResultLoc = undefined,
|
||||
/// When a block has a pointer result location, here it is.
|
||||
rl_ptr: zir.Inst.Ref = 0,
|
||||
rl_ptr: zir.Inst.Ref = .none,
|
||||
/// Keeps track of how many branches of a block did not actually
|
||||
/// consume the result location. astgen uses this to figure out
|
||||
/// whether to rely on break instructions or writing to the result
|
||||
@ -1001,8 +1001,8 @@ pub const Scope = struct {
|
||||
ret_ty: zir.Inst.Ref,
|
||||
cc: zir.Inst.Ref,
|
||||
}) !zir.Inst.Ref {
|
||||
assert(args.ret_ty != 0);
|
||||
assert(args.cc != 0);
|
||||
assert(args.ret_ty != .none);
|
||||
assert(args.cc != .none);
|
||||
const gpa = gz.zir_code.gpa;
|
||||
try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
|
||||
try gz.zir_code.instructions.ensureCapacity(gpa, gz.zir_code.instructions.len + 1);
|
||||
@ -1013,7 +1013,7 @@ pub const Scope = struct {
|
||||
.cc = args.cc,
|
||||
.param_types_len = @intCast(u32, args.param_types.len),
|
||||
});
|
||||
gz.zir_code.extra.appendSliceAssumeCapacity(args.param_types);
|
||||
gz.zir_code.extra.appendSliceAssumeCapacity(mem.bytesAsSlice(u32, mem.sliceAsBytes(args.param_types)));
|
||||
|
||||
const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len);
|
||||
gz.zir_code.instructions.appendAssumeCapacity(.{
|
||||
@ -1024,7 +1024,7 @@ pub const Scope = struct {
|
||||
} },
|
||||
});
|
||||
gz.instructions.appendAssumeCapacity(new_index);
|
||||
return new_index + gz.zir_code.ref_start_index;
|
||||
return zir.Inst.Ref.fromIndex(new_index, gz.zir_code.param_count);
|
||||
}
|
||||
|
||||
pub fn addFnType(
|
||||
@ -1033,7 +1033,7 @@ pub const Scope = struct {
|
||||
ret_ty: zir.Inst.Ref,
|
||||
param_types: []const zir.Inst.Ref,
|
||||
) !zir.Inst.Ref {
|
||||
assert(ret_ty != 0);
|
||||
assert(ret_ty != .none);
|
||||
const gpa = gz.zir_code.gpa;
|
||||
try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
|
||||
try gz.zir_code.instructions.ensureCapacity(gpa, gz.zir_code.instructions.len + 1);
|
||||
@ -1043,7 +1043,7 @@ pub const Scope = struct {
|
||||
const payload_index = gz.zir_code.addExtraAssumeCapacity(zir.Inst.FnType{
|
||||
.param_types_len = @intCast(u32, param_types.len),
|
||||
});
|
||||
gz.zir_code.extra.appendSliceAssumeCapacity(param_types);
|
||||
gz.zir_code.extra.appendSliceAssumeCapacity(mem.bytesAsSlice(u32, mem.sliceAsBytes(param_types)));
|
||||
|
||||
const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len);
|
||||
gz.zir_code.instructions.appendAssumeCapacity(.{
|
||||
@ -1054,7 +1054,7 @@ pub const Scope = struct {
|
||||
} },
|
||||
});
|
||||
gz.instructions.appendAssumeCapacity(new_index);
|
||||
return new_index + gz.zir_code.ref_start_index;
|
||||
return zir.Inst.Ref.fromIndex(new_index, gz.zir_code.param_count);
|
||||
}
|
||||
|
||||
pub fn addCall(
|
||||
@ -1065,7 +1065,7 @@ pub const Scope = struct {
|
||||
/// Absolute node index. This function does the conversion to offset from Decl.
|
||||
src_node: ast.Node.Index,
|
||||
) !zir.Inst.Ref {
|
||||
assert(callee != 0);
|
||||
assert(callee != .none);
|
||||
assert(src_node != 0);
|
||||
const gpa = gz.zir_code.gpa;
|
||||
try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
|
||||
@ -1077,7 +1077,7 @@ pub const Scope = struct {
|
||||
.callee = callee,
|
||||
.args_len = @intCast(u32, args.len),
|
||||
});
|
||||
gz.zir_code.extra.appendSliceAssumeCapacity(args);
|
||||
gz.zir_code.extra.appendSliceAssumeCapacity(mem.bytesAsSlice(u32, mem.sliceAsBytes(args)));
|
||||
|
||||
const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len);
|
||||
gz.zir_code.instructions.appendAssumeCapacity(.{
|
||||
@ -1088,7 +1088,7 @@ pub const Scope = struct {
|
||||
} },
|
||||
});
|
||||
gz.instructions.appendAssumeCapacity(new_index);
|
||||
return new_index + gz.zir_code.ref_start_index;
|
||||
return zir.Inst.Ref.fromIndex(new_index, gz.zir_code.param_count);
|
||||
}
|
||||
|
||||
/// Note that this returns a `zir.Inst.Index` not a ref.
|
||||
@ -1098,7 +1098,7 @@ pub const Scope = struct {
|
||||
tag: zir.Inst.Tag,
|
||||
lhs: zir.Inst.Ref,
|
||||
) !zir.Inst.Index {
|
||||
assert(lhs != 0);
|
||||
assert(lhs != .none);
|
||||
const gpa = gz.zir_code.gpa;
|
||||
try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
|
||||
try gz.zir_code.instructions.ensureCapacity(gpa, gz.zir_code.instructions.len + 1);
|
||||
@ -1129,7 +1129,7 @@ pub const Scope = struct {
|
||||
/// Absolute node index. This function does the conversion to offset from Decl.
|
||||
src_node: ast.Node.Index,
|
||||
) !zir.Inst.Ref {
|
||||
assert(operand != 0);
|
||||
assert(operand != .none);
|
||||
return gz.add(.{
|
||||
.tag = tag,
|
||||
.data = .{ .un_node = .{
|
||||
@ -1160,7 +1160,7 @@ pub const Scope = struct {
|
||||
} },
|
||||
});
|
||||
gz.instructions.appendAssumeCapacity(new_index);
|
||||
return new_index + gz.zir_code.ref_start_index;
|
||||
return zir.Inst.Ref.fromIndex(new_index, gz.zir_code.param_count);
|
||||
}
|
||||
|
||||
pub fn addArrayTypeSentinel(
|
||||
@ -1186,7 +1186,7 @@ pub const Scope = struct {
|
||||
} },
|
||||
});
|
||||
gz.instructions.appendAssumeCapacity(new_index);
|
||||
return new_index + gz.zir_code.ref_start_index;
|
||||
return zir.Inst.Ref.fromIndex(new_index, gz.zir_code.param_count);
|
||||
}
|
||||
|
||||
pub fn addUnTok(
|
||||
@ -1196,7 +1196,7 @@ pub const Scope = struct {
|
||||
/// Absolute token index. This function does the conversion to Decl offset.
|
||||
abs_tok_index: ast.TokenIndex,
|
||||
) !zir.Inst.Ref {
|
||||
assert(operand != 0);
|
||||
assert(operand != .none);
|
||||
return gz.add(.{
|
||||
.tag = tag,
|
||||
.data = .{ .un_tok = .{
|
||||
@ -1228,8 +1228,8 @@ pub const Scope = struct {
|
||||
lhs: zir.Inst.Ref,
|
||||
rhs: zir.Inst.Ref,
|
||||
) !zir.Inst.Ref {
|
||||
assert(lhs != 0);
|
||||
assert(rhs != 0);
|
||||
assert(lhs != .none);
|
||||
assert(rhs != .none);
|
||||
return gz.add(.{
|
||||
.tag = tag,
|
||||
.data = .{ .bin = .{
|
||||
@ -1317,7 +1317,7 @@ pub const Scope = struct {
|
||||
const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len);
|
||||
gz.zir_code.instructions.appendAssumeCapacity(inst);
|
||||
gz.instructions.appendAssumeCapacity(new_index);
|
||||
return gz.zir_code.ref_start_index + new_index;
|
||||
return zir.Inst.Ref.fromIndex(new_index, gz.zir_code.param_count);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1331,7 +1331,7 @@ pub const Scope = struct {
|
||||
parent: *Scope,
|
||||
gen_zir: *GenZir,
|
||||
name: []const u8,
|
||||
inst: zir.Inst.Index,
|
||||
inst: zir.Inst.Ref,
|
||||
/// Source location of the corresponding variable declaration.
|
||||
src: LazySrcLoc,
|
||||
};
|
||||
@ -1346,7 +1346,7 @@ pub const Scope = struct {
|
||||
parent: *Scope,
|
||||
gen_zir: *GenZir,
|
||||
name: []const u8,
|
||||
ptr: zir.Inst.Index,
|
||||
ptr: zir.Inst.Ref,
|
||||
/// Source location of the corresponding variable declaration.
|
||||
src: LazySrcLoc,
|
||||
};
|
||||
@ -1366,9 +1366,9 @@ pub const WipZirCode = struct {
|
||||
instructions: std.MultiArrayList(zir.Inst) = .{},
|
||||
string_bytes: std.ArrayListUnmanaged(u8) = .{},
|
||||
extra: std.ArrayListUnmanaged(u32) = .{},
|
||||
/// The end of special indexes. `zir.Inst.Ref` subtracts against this number to convert
|
||||
/// to `zir.Inst.Index`. The default here is correct if there are 0 parameters.
|
||||
ref_start_index: u32 = zir.const_inst_list.len,
|
||||
/// We need to keep track of this count in order to convert between
|
||||
/// `zir.Inst.Ref` and `zir.Inst.Index` types.
|
||||
param_count: u32 = 0,
|
||||
decl: *Decl,
|
||||
gpa: *Allocator,
|
||||
arena: *Allocator,
|
||||
@ -1383,15 +1383,18 @@ pub const WipZirCode = struct {
|
||||
const fields = std.meta.fields(@TypeOf(extra));
|
||||
const result = @intCast(u32, wzc.extra.items.len);
|
||||
inline for (fields) |field| {
|
||||
comptime assert(field.field_type == u32);
|
||||
wzc.extra.appendAssumeCapacity(@field(extra, field.name));
|
||||
wzc.extra.appendAssumeCapacity(switch (field.field_type) {
|
||||
u32 => @field(extra, field.name),
|
||||
zir.Inst.Ref => @enumToInt(@field(extra, field.name)),
|
||||
else => unreachable,
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn refIsNoReturn(wzc: WipZirCode, zir_inst_ref: zir.Inst.Ref) bool {
|
||||
if (zir_inst_ref >= wzc.ref_start_index) {
|
||||
const zir_inst = zir_inst_ref - wzc.ref_start_index;
|
||||
if (zir_inst_ref == .unreachable_value) return true;
|
||||
if (zir_inst_ref.toIndex(wzc.param_count)) |zir_inst| {
|
||||
return wzc.instructions.items(.tag)[zir_inst].isNoReturn();
|
||||
}
|
||||
return false;
|
||||
@ -2072,7 +2075,7 @@ fn astgenAndSemaFn(
|
||||
// The AST params array does not contain anytype and ... parameters.
|
||||
// We must iterate to count how many param types to allocate.
|
||||
const param_count = blk: {
|
||||
var count: usize = 0;
|
||||
var count: u32 = 0;
|
||||
var it = fn_proto.iterate(tree);
|
||||
while (it.next()) |param| {
|
||||
if (param.anytype_ellipsis3) |some| if (token_tags[some] == .ellipsis3) break;
|
||||
@ -2081,7 +2084,6 @@ fn astgenAndSemaFn(
|
||||
break :blk count;
|
||||
};
|
||||
const param_types = try fn_type_scope_arena.allocator.alloc(zir.Inst.Ref, param_count);
|
||||
const type_type_rl: astgen.ResultLoc = .{ .ty = @enumToInt(zir.Const.type_type) };
|
||||
|
||||
var is_var_args = false;
|
||||
{
|
||||
@ -2106,7 +2108,7 @@ fn astgenAndSemaFn(
|
||||
const param_type_node = param.type_expr;
|
||||
assert(param_type_node != 0);
|
||||
param_types[param_type_i] =
|
||||
try astgen.expr(mod, &fn_type_scope.base, type_type_rl, param_type_node);
|
||||
try astgen.expr(mod, &fn_type_scope.base, .{ .ty = .type_type }, param_type_node);
|
||||
}
|
||||
assert(param_type_i == param_count);
|
||||
}
|
||||
@ -2178,7 +2180,7 @@ fn astgenAndSemaFn(
|
||||
const return_type_inst = try astgen.expr(
|
||||
mod,
|
||||
&fn_type_scope.base,
|
||||
type_type_rl,
|
||||
.{ .ty = .type_type },
|
||||
fn_proto.ast.return_type,
|
||||
);
|
||||
|
||||
@ -2187,19 +2189,22 @@ fn astgenAndSemaFn(
|
||||
else
|
||||
false;
|
||||
|
||||
const cc: zir.Inst.Index = if (fn_proto.ast.callconv_expr != 0)
|
||||
const cc: zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0)
|
||||
// TODO instead of enum literal type, this needs to be the
|
||||
// std.builtin.CallingConvention enum. We need to implement importing other files
|
||||
// and enums in order to fix this.
|
||||
try astgen.comptimeExpr(mod, &fn_type_scope.base, .{
|
||||
.ty = @enumToInt(zir.Const.enum_literal_type),
|
||||
}, fn_proto.ast.callconv_expr)
|
||||
try astgen.comptimeExpr(
|
||||
mod,
|
||||
&fn_type_scope.base,
|
||||
.{ .ty = .enum_literal_type },
|
||||
fn_proto.ast.callconv_expr,
|
||||
)
|
||||
else if (is_extern) // note: https://github.com/ziglang/zig/issues/5269
|
||||
try fn_type_scope.addSmallStr(.enum_literal_small, "C")
|
||||
else
|
||||
0;
|
||||
.none;
|
||||
|
||||
const fn_type_inst: zir.Inst.Ref = if (cc != 0) fn_type: {
|
||||
const fn_type_inst: zir.Inst.Ref = if (cc != .none) fn_type: {
|
||||
const tag: zir.Inst.Tag = if (is_var_args) .fn_type_cc_var_args else .fn_type_cc;
|
||||
break :fn_type try fn_type_scope.addFnTypeCc(tag, .{
|
||||
.ret_ty = return_type_inst,
|
||||
@ -2292,7 +2297,7 @@ fn astgenAndSemaFn(
|
||||
.decl = decl,
|
||||
.arena = &decl_arena.allocator,
|
||||
.gpa = mod.gpa,
|
||||
.ref_start_index = @intCast(u32, zir.const_inst_list.len + param_count),
|
||||
.param_count = param_count,
|
||||
};
|
||||
defer wip_zir_code.deinit();
|
||||
|
||||
@ -2309,7 +2314,7 @@ fn astgenAndSemaFn(
|
||||
try wip_zir_code.extra.ensureCapacity(mod.gpa, param_count);
|
||||
|
||||
var params_scope = &gen_scope.base;
|
||||
var i: usize = 0;
|
||||
var i: u32 = 0;
|
||||
var it = fn_proto.iterate(tree);
|
||||
while (it.next()) |param| : (i += 1) {
|
||||
const name_token = param.name_token.?;
|
||||
@ -2320,7 +2325,7 @@ fn astgenAndSemaFn(
|
||||
.gen_zir = &gen_scope,
|
||||
.name = param_name,
|
||||
// Implicit const list first, then implicit arg list.
|
||||
.inst = @intCast(u32, zir.const_inst_list.len + i),
|
||||
.inst = zir.Inst.Ref.fromParam(i),
|
||||
.src = decl.tokSrcLoc(name_token),
|
||||
};
|
||||
params_scope = &sub_scope.base;
|
||||
@ -2344,8 +2349,7 @@ fn astgenAndSemaFn(
|
||||
// astgen uses result location semantics to coerce return operands.
|
||||
// Since we are adding the return instruction here, we must handle the coercion.
|
||||
// We do this by using the `ret_coerce` instruction.
|
||||
const void_inst: zir.Inst.Ref = @enumToInt(zir.Const.void_value);
|
||||
_ = try gen_scope.addUnTok(.ret_coerce, void_inst, tree.lastToken(body_node));
|
||||
_ = try gen_scope.addUnTok(.ret_coerce, .void_value, tree.lastToken(body_node));
|
||||
}
|
||||
|
||||
const code = try gen_scope.finish();
|
||||
@ -2514,9 +2518,7 @@ fn astgenAndSemaVarDecl(
|
||||
defer gen_scope.instructions.deinit(mod.gpa);
|
||||
|
||||
const init_result_loc: astgen.ResultLoc = if (var_decl.ast.type_node != 0) .{
|
||||
.ty = try astgen.expr(mod, &gen_scope.base, .{
|
||||
.ty = @enumToInt(zir.Const.type_type),
|
||||
}, var_decl.ast.type_node),
|
||||
.ty = try astgen.expr(mod, &gen_scope.base, .{ .ty = .type_type }, var_decl.ast.type_node),
|
||||
} else .none;
|
||||
|
||||
const init_inst = try astgen.comptimeExpr(
|
||||
|
||||
66
src/Sema.zig
66
src/Sema.zig
@ -78,7 +78,7 @@ pub fn rootAsType(sema: *Sema, root_block: *Scope.Block) !Type {
|
||||
/// return type of `analyzeBody` so that we can tail call them.
|
||||
/// Only appropriate to return when the instruction is known to be NoReturn
|
||||
/// solely based on the ZIR tag.
|
||||
const always_noreturn: InnerError!zir.Inst.Ref = @as(zir.Inst.Index, 0);
|
||||
const always_noreturn: InnerError!zir.Inst.Ref = .none;
|
||||
|
||||
/// This function is the main loop of `Sema` and it can be used in two different ways:
|
||||
/// * The traditional way where there are N breaks out of the block and peer type
|
||||
@ -88,7 +88,7 @@ const always_noreturn: InnerError!zir.Inst.Ref = @as(zir.Inst.Index, 0);
|
||||
/// * The "flat" way. There is only 1 break out of the block, and it is with a `break_flat`
|
||||
/// instruction. In this case, the `zir.Inst.Index` part of the return value will be
|
||||
/// the block result value. No block scope needs to be created for this strategy.
|
||||
pub fn analyzeBody(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Index) !zir.Inst.Index {
|
||||
pub fn analyzeBody(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Index) !zir.Inst.Ref {
|
||||
// No tracy calls here, to avoid interfering with the tail call mechanism.
|
||||
|
||||
const map = block.sema.inst_map;
|
||||
@ -300,28 +300,18 @@ pub fn analyzeBody(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Inde
|
||||
}
|
||||
|
||||
/// TODO when we rework TZIR memory layout, this function will no longer have a possible error.
|
||||
/// Until then we allocate memory for a new, mutable `ir.Inst` to match what TZIR expects.
|
||||
pub fn resolveInst(sema: *Sema, zir_ref: zir.Inst.Ref) error{OutOfMemory}!*ir.Inst {
|
||||
var i: usize = zir_ref;
|
||||
|
||||
// First section of indexes correspond to a set number of constant values.
|
||||
if (i < zir.const_inst_list.len) {
|
||||
// TODO when we rework TZIR memory layout, this function can be as simple as:
|
||||
// if (zir_ref < zir.const_inst_list.len + sema.param_count)
|
||||
// return zir_ref;
|
||||
// Until then we allocate memory for a new, mutable `ir.Inst` to match what
|
||||
// TZIR expects.
|
||||
return sema.mod.constInst(sema.arena, .unneeded, zir.const_inst_list[i]);
|
||||
if (zir_ref.toTypedValue()) |typed_value| {
|
||||
return sema.mod.constInst(sema.arena, .unneeded, typed_value);
|
||||
}
|
||||
i -= zir.const_inst_list.len;
|
||||
|
||||
// Next section of indexes correspond to function parameters, if any.
|
||||
if (i < sema.param_inst_list.len) {
|
||||
return sema.param_inst_list[i];
|
||||
const param_count = @intCast(u32, sema.param_inst_list.len);
|
||||
if (zir_ref.toParam(param_count)) |param| {
|
||||
return sema.param_inst_list[param];
|
||||
}
|
||||
i -= sema.param_inst_list.len;
|
||||
|
||||
// Finally, the last section of indexes refers to the map of ZIR=>TZIR.
|
||||
return sema.inst_map[i];
|
||||
return sema.inst_map[zir_ref.toIndex(param_count).?];
|
||||
}
|
||||
|
||||
fn resolveConstString(
|
||||
@ -745,7 +735,7 @@ fn zirInt(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*In
|
||||
return sema.mod.constIntUnsigned(sema.arena, .unneeded, Type.initTag(.comptime_int), int);
|
||||
}
|
||||
|
||||
fn zirCompileError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Index {
|
||||
fn zirCompileError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Ref {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
@ -763,7 +753,10 @@ fn zirCompileLog(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr
|
||||
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
|
||||
const extra = sema.code.extraData(zir.Inst.MultiOp, inst_data.payload_index);
|
||||
for (sema.code.extra[extra.end..][0..extra.data.operands_len]) |arg_ref, i| {
|
||||
const raw_args = sema.code.extra[extra.end..][0..extra.data.operands_len];
|
||||
const args = mem.bytesAsSlice(zir.Inst.Ref, mem.sliceAsBytes(raw_args));
|
||||
|
||||
for (args) |arg_ref, i| {
|
||||
if (i != 0) try writer.print(", ", .{});
|
||||
|
||||
const arg = try sema.resolveInst(arg_ref);
|
||||
@ -998,7 +991,7 @@ fn zirBreakpoint(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr
|
||||
_ = try block.addNoOp(src, Type.initTag(.void), .breakpoint);
|
||||
}
|
||||
|
||||
fn zirBreak(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Index {
|
||||
fn zirBreak(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Ref {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
@ -1007,7 +1000,7 @@ fn zirBreak(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!z
|
||||
return sema.analyzeBreak(block, sema.src, inst_data.block_inst, operand);
|
||||
}
|
||||
|
||||
fn zirBreakVoidNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Index {
|
||||
fn zirBreakVoidNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Ref {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
@ -1112,7 +1105,8 @@ fn zirCall(
|
||||
const func_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node };
|
||||
const call_src = inst_data.src();
|
||||
const extra = sema.code.extraData(zir.Inst.Call, inst_data.payload_index);
|
||||
const args = sema.code.extra[extra.end..][0..extra.data.args_len];
|
||||
const raw_args = sema.code.extra[extra.end..][0..extra.data.args_len];
|
||||
const args = mem.bytesAsSlice(zir.Inst.Ref, mem.sliceAsBytes(raw_args));
|
||||
|
||||
return sema.analyzeCall(block, extra.data.callee, func_src, call_src, modifier, ensure_result_used, args);
|
||||
}
|
||||
@ -1739,7 +1733,8 @@ fn zirFnType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index, var_args: b
|
||||
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].fn_type;
|
||||
const extra = sema.code.extraData(zir.Inst.FnType, inst_data.payload_index);
|
||||
const param_types = sema.code.extra[extra.end..][0..extra.data.param_types_len];
|
||||
const raw_param_types = sema.code.extra[extra.end..][0..extra.data.param_types_len];
|
||||
const param_types = mem.bytesAsSlice(zir.Inst.Ref, mem.sliceAsBytes(raw_param_types));
|
||||
|
||||
return sema.fnTypeCommon(
|
||||
block,
|
||||
@ -1757,7 +1752,8 @@ fn zirFnTypeCc(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index, var_args:
|
||||
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].fn_type;
|
||||
const extra = sema.code.extraData(zir.Inst.FnTypeCc, inst_data.payload_index);
|
||||
const param_types = sema.code.extra[extra.end..][0..extra.data.param_types_len];
|
||||
const raw_param_types = sema.code.extra[extra.end..][0..extra.data.param_types_len];
|
||||
const param_types = mem.bytesAsSlice(zir.Inst.Ref, mem.sliceAsBytes(raw_param_types));
|
||||
|
||||
const cc_tv = try sema.resolveInstConst(block, .todo, extra.data.cc);
|
||||
// TODO once we're capable of importing and analyzing decls from
|
||||
@ -2487,7 +2483,7 @@ fn zirNegate(
|
||||
const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
|
||||
const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
|
||||
const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
|
||||
const lhs = try sema.resolveInst(@enumToInt(zir.Const.zero));
|
||||
const lhs = try sema.resolveInst(.zero);
|
||||
const rhs = try sema.resolveInst(inst_data.operand);
|
||||
|
||||
return sema.analyzeArithmetic(block, tag_override, lhs, rhs, src, lhs_src, rhs_src);
|
||||
@ -2641,7 +2637,7 @@ fn zirAsm(
|
||||
|
||||
var extra_i = extra.end;
|
||||
const Output = struct { name: []const u8, inst: *Inst };
|
||||
const output: ?Output = if (extra.data.output != 0) blk: {
|
||||
const output: ?Output = if (extra.data.output != .none) blk: {
|
||||
const name = sema.code.nullTerminatedString(sema.code.extra[extra_i]);
|
||||
extra_i += 1;
|
||||
break :blk Output{
|
||||
@ -2655,7 +2651,7 @@ fn zirAsm(
|
||||
const clobbers = try sema.arena.alloc([]const u8, extra.data.clobbers_len);
|
||||
|
||||
for (args) |*arg| {
|
||||
arg.* = try sema.resolveInst(sema.code.extra[extra_i]);
|
||||
arg.* = try sema.resolveInst(@intToEnum(zir.Inst.Ref, sema.code.extra[extra_i]));
|
||||
extra_i += 1;
|
||||
}
|
||||
for (inputs) |*name| {
|
||||
@ -2772,11 +2768,13 @@ fn zirTypeofPeer(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
|
||||
const src = inst_data.src();
|
||||
const extra = sema.code.extraData(zir.Inst.MultiOp, inst_data.payload_index);
|
||||
const raw_args = sema.code.extra[extra.end..][0..extra.data.operands_len];
|
||||
const args = mem.bytesAsSlice(zir.Inst.Ref, mem.sliceAsBytes(raw_args));
|
||||
|
||||
const inst_list = try sema.gpa.alloc(*ir.Inst, extra.data.operands_len);
|
||||
defer sema.gpa.free(inst_list);
|
||||
|
||||
for (sema.code.extra[extra.end..][0..extra.data.operands_len]) |arg_ref, i| {
|
||||
for (args) |arg_ref, i| {
|
||||
inst_list[i] = try sema.resolveInst(arg_ref);
|
||||
}
|
||||
|
||||
@ -3115,25 +3113,25 @@ fn zirPtrType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError
|
||||
var extra_i = extra.end;
|
||||
|
||||
const sentinel = if (inst_data.flags.has_sentinel) blk: {
|
||||
const ref = sema.code.extra[extra_i];
|
||||
const ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_i]);
|
||||
extra_i += 1;
|
||||
break :blk (try sema.resolveInstConst(block, .unneeded, ref)).val;
|
||||
} else null;
|
||||
|
||||
const abi_align = if (inst_data.flags.has_align) blk: {
|
||||
const ref = sema.code.extra[extra_i];
|
||||
const ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_i]);
|
||||
extra_i += 1;
|
||||
break :blk try sema.resolveAlreadyCoercedInt(block, .unneeded, ref, u32);
|
||||
} else 0;
|
||||
|
||||
const bit_start = if (inst_data.flags.has_bit_range) blk: {
|
||||
const ref = sema.code.extra[extra_i];
|
||||
const ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_i]);
|
||||
extra_i += 1;
|
||||
break :blk try sema.resolveAlreadyCoercedInt(block, .unneeded, ref, u16);
|
||||
} else 0;
|
||||
|
||||
const bit_end = if (inst_data.flags.has_bit_range) blk: {
|
||||
const ref = sema.code.extra[extra_i];
|
||||
const ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_i]);
|
||||
extra_i += 1;
|
||||
break :blk try sema.resolveAlreadyCoercedInt(block, .unneeded, ref, u16);
|
||||
} else 0;
|
||||
|
||||
191
src/astgen.zig
191
src/astgen.zig
@ -58,11 +58,8 @@ pub const ResultLoc = union(enum) {
|
||||
};
|
||||
};
|
||||
|
||||
const void_inst: zir.Inst.Ref = @enumToInt(zir.Const.void_value);
|
||||
|
||||
pub fn typeExpr(mod: *Module, scope: *Scope, type_node: ast.Node.Index) InnerError!zir.Inst.Ref {
|
||||
const type_rl: ResultLoc = .{ .ty = @enumToInt(zir.Const.type_type) };
|
||||
return expr(mod, scope, type_rl, type_node);
|
||||
return expr(mod, scope, .{ .ty = .type_type }, type_node);
|
||||
}
|
||||
|
||||
fn lvalExpr(mod: *Module, scope: *Scope, node: ast.Node.Index) InnerError!zir.Inst.Ref {
|
||||
@ -291,59 +288,59 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
|
||||
|
||||
.assign => {
|
||||
try assign(mod, scope, node);
|
||||
return rvalue(mod, scope, rl, void_inst, node);
|
||||
return rvalue(mod, scope, rl, .void_value, node);
|
||||
},
|
||||
.assign_bit_and => {
|
||||
try assignOp(mod, scope, node, .bit_and);
|
||||
return rvalue(mod, scope, rl, void_inst, node);
|
||||
return rvalue(mod, scope, rl, .void_value, node);
|
||||
},
|
||||
.assign_bit_or => {
|
||||
try assignOp(mod, scope, node, .bit_or);
|
||||
return rvalue(mod, scope, rl, void_inst, node);
|
||||
return rvalue(mod, scope, rl, .void_value, node);
|
||||
},
|
||||
.assign_bit_shift_left => {
|
||||
try assignOp(mod, scope, node, .shl);
|
||||
return rvalue(mod, scope, rl, void_inst, node);
|
||||
return rvalue(mod, scope, rl, .void_value, node);
|
||||
},
|
||||
.assign_bit_shift_right => {
|
||||
try assignOp(mod, scope, node, .shr);
|
||||
return rvalue(mod, scope, rl, void_inst, node);
|
||||
return rvalue(mod, scope, rl, .void_value, node);
|
||||
},
|
||||
.assign_bit_xor => {
|
||||
try assignOp(mod, scope, node, .xor);
|
||||
return rvalue(mod, scope, rl, void_inst, node);
|
||||
return rvalue(mod, scope, rl, .void_value, node);
|
||||
},
|
||||
.assign_div => {
|
||||
try assignOp(mod, scope, node, .div);
|
||||
return rvalue(mod, scope, rl, void_inst, node);
|
||||
return rvalue(mod, scope, rl, .void_value, node);
|
||||
},
|
||||
.assign_sub => {
|
||||
try assignOp(mod, scope, node, .sub);
|
||||
return rvalue(mod, scope, rl, void_inst, node);
|
||||
return rvalue(mod, scope, rl, .void_value, node);
|
||||
},
|
||||
.assign_sub_wrap => {
|
||||
try assignOp(mod, scope, node, .subwrap);
|
||||
return rvalue(mod, scope, rl, void_inst, node);
|
||||
return rvalue(mod, scope, rl, .void_value, node);
|
||||
},
|
||||
.assign_mod => {
|
||||
try assignOp(mod, scope, node, .mod_rem);
|
||||
return rvalue(mod, scope, rl, void_inst, node);
|
||||
return rvalue(mod, scope, rl, .void_value, node);
|
||||
},
|
||||
.assign_add => {
|
||||
try assignOp(mod, scope, node, .add);
|
||||
return rvalue(mod, scope, rl, void_inst, node);
|
||||
return rvalue(mod, scope, rl, .void_value, node);
|
||||
},
|
||||
.assign_add_wrap => {
|
||||
try assignOp(mod, scope, node, .addwrap);
|
||||
return rvalue(mod, scope, rl, void_inst, node);
|
||||
return rvalue(mod, scope, rl, .void_value, node);
|
||||
},
|
||||
.assign_mul => {
|
||||
try assignOp(mod, scope, node, .mul);
|
||||
return rvalue(mod, scope, rl, void_inst, node);
|
||||
return rvalue(mod, scope, rl, .void_value, node);
|
||||
},
|
||||
.assign_mul_wrap => {
|
||||
try assignOp(mod, scope, node, .mulwrap);
|
||||
return rvalue(mod, scope, rl, void_inst, node);
|
||||
return rvalue(mod, scope, rl, .void_value, node);
|
||||
},
|
||||
|
||||
.add => return simpleBinOp(mod, scope, rl, node, .add),
|
||||
@ -450,22 +447,10 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
|
||||
const result = try expr(mod, scope, .ref, node_datas[node].lhs);
|
||||
return rvalue(mod, scope, rl, result, node);
|
||||
},
|
||||
.undefined_literal => {
|
||||
const result = @enumToInt(zir.Const.undef);
|
||||
return rvalue(mod, scope, rl, result, node);
|
||||
},
|
||||
.true_literal => {
|
||||
const result = @enumToInt(zir.Const.bool_true);
|
||||
return rvalue(mod, scope, rl, result, node);
|
||||
},
|
||||
.false_literal => {
|
||||
const result = @enumToInt(zir.Const.bool_false);
|
||||
return rvalue(mod, scope, rl, result, node);
|
||||
},
|
||||
.null_literal => {
|
||||
const result = @enumToInt(zir.Const.null_value);
|
||||
return rvalue(mod, scope, rl, result, node);
|
||||
},
|
||||
.undefined_literal => return rvalue(mod, scope, rl, .undef, node),
|
||||
.true_literal => return rvalue(mod, scope, rl, .bool_true, node),
|
||||
.false_literal => return rvalue(mod, scope, rl, .bool_false, node),
|
||||
.null_literal => return rvalue(mod, scope, rl, .null_value, node),
|
||||
.optional_type => {
|
||||
const operand = try typeExpr(mod, scope, node_datas[node].lhs);
|
||||
const result = try gz.addUnNode(.optional_type, operand, node);
|
||||
@ -830,7 +815,7 @@ pub fn blockExpr(
|
||||
}
|
||||
|
||||
try blockExprStmts(mod, scope, block_node, statements);
|
||||
return rvalue(mod, scope, rl, void_inst, block_node);
|
||||
return rvalue(mod, scope, rl, .void_value, block_node);
|
||||
}
|
||||
|
||||
fn checkLabelRedefinition(mod: *Module, parent_scope: *Scope, label: ast.TokenIndex) !void {
|
||||
@ -935,13 +920,13 @@ fn labeledBlockExpr(
|
||||
// The code took advantage of the result location as a pointer.
|
||||
// Turn the break instruction operands into void.
|
||||
for (block_scope.labeled_breaks.items) |br| {
|
||||
zir_datas[br].@"break".operand = @enumToInt(zir.Const.void_value);
|
||||
zir_datas[br].@"break".operand = .void_value;
|
||||
}
|
||||
// TODO technically not needed since we changed the tag to break_void but
|
||||
// would be better still to elide the ones that are in this list.
|
||||
try block_scope.setBlockBody(block_inst);
|
||||
|
||||
return gz.zir_code.ref_start_index + block_inst;
|
||||
return zir.Inst.Ref.fromIndex(block_inst, gz.zir_code.param_count);
|
||||
},
|
||||
.break_operand => {
|
||||
// All break operands are values that did not use the result location pointer.
|
||||
@ -954,7 +939,7 @@ fn labeledBlockExpr(
|
||||
// would be better still to elide the ones that are in this list.
|
||||
}
|
||||
try block_scope.setBlockBody(block_inst);
|
||||
const block_ref = gz.zir_code.ref_start_index + block_inst;
|
||||
const block_ref = zir.Inst.Ref.fromIndex(block_inst, gz.zir_code.param_count);
|
||||
switch (rl) {
|
||||
.ref => return block_ref,
|
||||
else => return rvalue(mod, parent_scope, rl, block_ref, block_node),
|
||||
@ -1006,8 +991,7 @@ fn blockExprStmts(
|
||||
// We need to emit an error if the result is not `noreturn` or `void`, but
|
||||
// we want to avoid adding the ZIR instruction if possible for performance.
|
||||
const maybe_unused_result = try expr(mod, scope, .none, statement);
|
||||
const elide_check = if (maybe_unused_result >= gz.zir_code.ref_start_index) b: {
|
||||
const inst = maybe_unused_result - gz.zir_code.ref_start_index;
|
||||
const elide_check = if (maybe_unused_result.toIndex(gz.zir_code.param_count)) |inst| b: {
|
||||
// Note that this array becomes invalid after appending more items to it
|
||||
// in the above while loop.
|
||||
const zir_tags = gz.zir_code.instructions.items(.tag);
|
||||
@ -1167,10 +1151,10 @@ fn blockExprStmts(
|
||||
=> break :b true,
|
||||
}
|
||||
} else switch (maybe_unused_result) {
|
||||
@enumToInt(zir.Const.unused) => unreachable,
|
||||
.none => unreachable,
|
||||
|
||||
@enumToInt(zir.Const.void_value),
|
||||
@enumToInt(zir.Const.unreachable_value),
|
||||
.void_value,
|
||||
.unreachable_value,
|
||||
=> true,
|
||||
|
||||
else => false,
|
||||
@ -1283,8 +1267,8 @@ fn varDecl(
|
||||
};
|
||||
defer init_scope.instructions.deinit(mod.gpa);
|
||||
|
||||
var resolve_inferred_alloc: zir.Inst.Ref = 0;
|
||||
var opt_type_inst: zir.Inst.Ref = 0;
|
||||
var resolve_inferred_alloc: zir.Inst.Ref = .none;
|
||||
var opt_type_inst: zir.Inst.Ref = .none;
|
||||
if (var_decl.ast.type_node != 0) {
|
||||
const type_inst = try typeExpr(mod, &init_scope.base, var_decl.ast.type_node);
|
||||
opt_type_inst = type_inst;
|
||||
@ -1308,14 +1292,14 @@ fn varDecl(
|
||||
const expected_len = parent_zir.items.len + init_scope.instructions.items.len - 2;
|
||||
try parent_zir.ensureCapacity(mod.gpa, expected_len);
|
||||
for (init_scope.instructions.items) |src_inst| {
|
||||
if (wzc.ref_start_index + src_inst == init_scope.rl_ptr) continue;
|
||||
if (zir.Inst.Ref.fromIndex(src_inst, wzc.param_count) == init_scope.rl_ptr) continue;
|
||||
if (zir_tags[src_inst] == .store_to_block_ptr) {
|
||||
if (zir_datas[src_inst].bin.lhs == init_scope.rl_ptr) continue;
|
||||
}
|
||||
parent_zir.appendAssumeCapacity(src_inst);
|
||||
}
|
||||
assert(parent_zir.items.len == expected_len);
|
||||
const casted_init = if (opt_type_inst != 0)
|
||||
const casted_init = if (opt_type_inst != .none)
|
||||
try gz.addPlNode(.as_node, var_decl.ast.type_node, zir.Inst.As{
|
||||
.dest_type = opt_type_inst,
|
||||
.operand = init_inst,
|
||||
@ -1348,7 +1332,7 @@ fn varDecl(
|
||||
parent_zir.appendAssumeCapacity(src_inst);
|
||||
}
|
||||
assert(parent_zir.items.len == expected_len);
|
||||
if (resolve_inferred_alloc != 0) {
|
||||
if (resolve_inferred_alloc != .none) {
|
||||
_ = try gz.addUnNode(.resolve_inferred_alloc, resolve_inferred_alloc, node);
|
||||
}
|
||||
const sub_scope = try block_arena.create(Scope.LocalPtr);
|
||||
@ -1362,7 +1346,7 @@ fn varDecl(
|
||||
return &sub_scope.base;
|
||||
},
|
||||
.keyword_var => {
|
||||
var resolve_inferred_alloc: zir.Inst.Ref = 0;
|
||||
var resolve_inferred_alloc: zir.Inst.Ref = .none;
|
||||
const var_data: struct {
|
||||
result_loc: ResultLoc,
|
||||
alloc: zir.Inst.Ref,
|
||||
@ -1377,7 +1361,7 @@ fn varDecl(
|
||||
break :a .{ .alloc = alloc, .result_loc = .{ .inferred_ptr = alloc } };
|
||||
};
|
||||
const init_inst = try expr(mod, scope, var_data.result_loc, var_decl.ast.init_node);
|
||||
if (resolve_inferred_alloc != 0) {
|
||||
if (resolve_inferred_alloc != .none) {
|
||||
_ = try gz.addUnNode(.resolve_inferred_alloc, resolve_inferred_alloc, node);
|
||||
}
|
||||
const sub_scope = try block_arena.create(Scope.LocalPtr);
|
||||
@ -1440,7 +1424,7 @@ fn boolNot(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn
|
||||
const tree = scope.tree();
|
||||
const node_datas = tree.nodes.items(.data);
|
||||
|
||||
const operand = try expr(mod, scope, .{ .ty = @enumToInt(zir.Const.bool_type) }, node_datas[node].lhs);
|
||||
const operand = try expr(mod, scope, .{ .ty = .bool_type }, node_datas[node].lhs);
|
||||
const gz = scope.getGenZir();
|
||||
const result = try gz.addUnNode(.bool_not, operand, node);
|
||||
return rvalue(mod, scope, rl, result, node);
|
||||
@ -1501,10 +1485,10 @@ fn ptrType(
|
||||
return rvalue(mod, scope, rl, result, node);
|
||||
}
|
||||
|
||||
var sentinel_ref: zir.Inst.Ref = 0;
|
||||
var align_ref: zir.Inst.Ref = 0;
|
||||
var bit_start_ref: zir.Inst.Ref = 0;
|
||||
var bit_end_ref: zir.Inst.Ref = 0;
|
||||
var sentinel_ref: zir.Inst.Ref = .none;
|
||||
var align_ref: zir.Inst.Ref = .none;
|
||||
var bit_start_ref: zir.Inst.Ref = .none;
|
||||
var bit_end_ref: zir.Inst.Ref = .none;
|
||||
var trailing_count: u32 = 0;
|
||||
|
||||
if (ptr_info.ast.sentinel != 0) {
|
||||
@ -1529,24 +1513,28 @@ fn ptrType(
|
||||
@typeInfo(zir.Inst.PtrType).Struct.fields.len + trailing_count);
|
||||
|
||||
const payload_index = gz.zir_code.addExtraAssumeCapacity(zir.Inst.PtrType{ .elem_type = elem_type });
|
||||
if (sentinel_ref != 0) gz.zir_code.extra.appendAssumeCapacity(sentinel_ref);
|
||||
if (align_ref != 0) gz.zir_code.extra.appendAssumeCapacity(align_ref);
|
||||
if (bit_start_ref != 0) {
|
||||
gz.zir_code.extra.appendAssumeCapacity(bit_start_ref);
|
||||
gz.zir_code.extra.appendAssumeCapacity(bit_end_ref);
|
||||
if (sentinel_ref != .none) {
|
||||
gz.zir_code.extra.appendAssumeCapacity(@enumToInt(sentinel_ref));
|
||||
}
|
||||
if (align_ref != .none) {
|
||||
gz.zir_code.extra.appendAssumeCapacity(@enumToInt(align_ref));
|
||||
}
|
||||
if (bit_start_ref != .none) {
|
||||
gz.zir_code.extra.appendAssumeCapacity(@enumToInt(bit_start_ref));
|
||||
gz.zir_code.extra.appendAssumeCapacity(@enumToInt(bit_end_ref));
|
||||
}
|
||||
|
||||
const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len);
|
||||
const result = new_index + gz.zir_code.ref_start_index;
|
||||
const result = zir.Inst.Ref.fromIndex(new_index, gz.zir_code.param_count);
|
||||
gz.zir_code.instructions.appendAssumeCapacity(.{ .tag = .ptr_type, .data = .{
|
||||
.ptr_type = .{
|
||||
.flags = .{
|
||||
.is_allowzero = ptr_info.allowzero_token != null,
|
||||
.is_mutable = ptr_info.const_token == null,
|
||||
.is_volatile = ptr_info.volatile_token != null,
|
||||
.has_sentinel = sentinel_ref != 0,
|
||||
.has_align = align_ref != 0,
|
||||
.has_bit_range = bit_start_ref != 0,
|
||||
.has_sentinel = sentinel_ref != .none,
|
||||
.has_align = align_ref != .none,
|
||||
.has_bit_range = bit_start_ref != .none,
|
||||
},
|
||||
.size = ptr_info.size,
|
||||
.payload_index = payload_index,
|
||||
@ -1561,10 +1549,9 @@ fn arrayType(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !
|
||||
const tree = scope.tree();
|
||||
const node_datas = tree.nodes.items(.data);
|
||||
const gz = scope.getGenZir();
|
||||
const usize_type = @enumToInt(zir.Const.usize_type);
|
||||
|
||||
// TODO check for [_]T
|
||||
const len = try expr(mod, scope, .{ .ty = usize_type }, node_datas[node].lhs);
|
||||
const len = try expr(mod, scope, .{ .ty = .usize_type }, node_datas[node].lhs);
|
||||
const elem_type = try typeExpr(mod, scope, node_datas[node].rhs);
|
||||
|
||||
const result = try gz.addBin(.array_type, len, elem_type);
|
||||
@ -1576,10 +1563,9 @@ fn arrayTypeSentinel(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.
|
||||
const node_datas = tree.nodes.items(.data);
|
||||
const extra = tree.extraData(node_datas[node].rhs, ast.Node.ArrayTypeSentinel);
|
||||
const gz = scope.getGenZir();
|
||||
const usize_type = @enumToInt(zir.Const.usize_type);
|
||||
|
||||
// TODO check for [_]T
|
||||
const len = try expr(mod, scope, .{ .ty = usize_type }, node_datas[node].lhs);
|
||||
const len = try expr(mod, scope, .{ .ty = .usize_type }, node_datas[node].lhs);
|
||||
const elem_type = try typeExpr(mod, scope, extra.elem_type);
|
||||
const sentinel = try expr(mod, scope, .{ .ty = elem_type }, extra.sentinel);
|
||||
|
||||
@ -1784,7 +1770,7 @@ fn finishThenElseBlock(
|
||||
} },
|
||||
});
|
||||
}
|
||||
const elide_else = if (else_result != 0) wzc.refIsNoReturn(else_result) else false;
|
||||
const elide_else = if (else_result != .none) wzc.refIsNoReturn(else_result) else false;
|
||||
if (!elide_else) {
|
||||
_ = try else_scope.add(.{
|
||||
.tag = .break_void_node,
|
||||
@ -1796,7 +1782,7 @@ fn finishThenElseBlock(
|
||||
}
|
||||
assert(!strat.elide_store_to_block_ptr_instructions);
|
||||
try setCondBrPayload(condbr, cond, then_scope, else_scope);
|
||||
return wzc.ref_start_index + main_block;
|
||||
return zir.Inst.Ref.fromIndex(main_block, wzc.param_count);
|
||||
},
|
||||
.break_operand => {
|
||||
if (!wzc.refIsNoReturn(then_result)) {
|
||||
@ -1808,7 +1794,7 @@ fn finishThenElseBlock(
|
||||
} },
|
||||
});
|
||||
}
|
||||
if (else_result != 0) {
|
||||
if (else_result != .none) {
|
||||
if (!wzc.refIsNoReturn(else_result)) {
|
||||
_ = try else_scope.add(.{
|
||||
.tag = .@"break",
|
||||
@ -1832,7 +1818,7 @@ fn finishThenElseBlock(
|
||||
} else {
|
||||
try setCondBrPayload(condbr, cond, then_scope, else_scope);
|
||||
}
|
||||
const block_ref = wzc.ref_start_index + main_block;
|
||||
const block_ref = zir.Inst.Ref.fromIndex(main_block, wzc.param_count);
|
||||
switch (rl) {
|
||||
.ref => return block_ref,
|
||||
else => return rvalue(mod, parent_scope, rl, block_ref, node),
|
||||
@ -1981,9 +1967,8 @@ fn boolBinOp(
|
||||
) InnerError!zir.Inst.Ref {
|
||||
const gz = scope.getGenZir();
|
||||
const node_datas = gz.tree().nodes.items(.data);
|
||||
const bool_type = @enumToInt(zir.Const.bool_type);
|
||||
|
||||
const lhs = try expr(mod, scope, .{ .ty = bool_type }, node_datas[node].lhs);
|
||||
const lhs = try expr(mod, scope, .{ .ty = .bool_type }, node_datas[node].lhs);
|
||||
const bool_br = try gz.addBoolBr(zir_tag, lhs);
|
||||
|
||||
var rhs_scope: Scope.GenZir = .{
|
||||
@ -1992,11 +1977,11 @@ fn boolBinOp(
|
||||
.force_comptime = gz.force_comptime,
|
||||
};
|
||||
defer rhs_scope.instructions.deinit(mod.gpa);
|
||||
const rhs = try expr(mod, &rhs_scope.base, .{ .ty = bool_type }, node_datas[node].rhs);
|
||||
const rhs = try expr(mod, &rhs_scope.base, .{ .ty = .bool_type }, node_datas[node].rhs);
|
||||
_ = try rhs_scope.addUnNode(.break_flat, rhs, node);
|
||||
try rhs_scope.setBoolBrBody(bool_br);
|
||||
|
||||
const block_ref = gz.zir_code.ref_start_index + bool_br;
|
||||
const block_ref = zir.Inst.Ref.fromIndex(bool_br, gz.zir_code.param_count);
|
||||
return rvalue(mod, scope, rl, block_ref, node);
|
||||
}
|
||||
|
||||
@ -2024,8 +2009,7 @@ fn ifExpr(
|
||||
} else if (if_full.payload_token) |payload_token| {
|
||||
return mod.failTok(scope, payload_token, "TODO implement if optional", .{});
|
||||
} else {
|
||||
const bool_rl: ResultLoc = .{ .ty = @enumToInt(zir.Const.bool_type) };
|
||||
break :c try expr(mod, &block_scope.base, bool_rl, if_full.ast.cond_expr);
|
||||
break :c try expr(mod, &block_scope.base, .{ .ty = .bool_type }, if_full.ast.cond_expr);
|
||||
}
|
||||
};
|
||||
|
||||
@ -2073,7 +2057,7 @@ fn ifExpr(
|
||||
};
|
||||
} else .{
|
||||
.src = if_full.ast.then_expr,
|
||||
.result = 0,
|
||||
.result = .none,
|
||||
};
|
||||
|
||||
return finishThenElseBlock(
|
||||
@ -2185,7 +2169,7 @@ fn whileExpr(
|
||||
} else if (while_full.payload_token) |payload_token| {
|
||||
return mod.failTok(scope, payload_token, "TODO implement while optional", .{});
|
||||
} else {
|
||||
const bool_type_rl: ResultLoc = .{ .ty = @enumToInt(zir.Const.bool_type) };
|
||||
const bool_type_rl: ResultLoc = .{ .ty = .bool_type };
|
||||
break :c try expr(mod, &continue_scope.base, bool_type_rl, while_full.ast.cond_expr);
|
||||
}
|
||||
};
|
||||
@ -2200,8 +2184,7 @@ fn whileExpr(
|
||||
// and there are no `continue` statements.
|
||||
// The "repeat" at the end of a loop body is implied.
|
||||
if (while_full.ast.cont_expr != 0) {
|
||||
const void_type_rl: ResultLoc = .{ .ty = @enumToInt(zir.Const.void_type) };
|
||||
_ = try expr(mod, &loop_scope.base, void_type_rl, while_full.ast.cont_expr);
|
||||
_ = try expr(mod, &loop_scope.base, .{ .ty = .void_type }, while_full.ast.cont_expr);
|
||||
}
|
||||
const is_inline = while_full.inline_token != null;
|
||||
const repeat_tag: zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat;
|
||||
@ -2251,7 +2234,7 @@ fn whileExpr(
|
||||
};
|
||||
} else .{
|
||||
.src = while_full.ast.then_expr,
|
||||
.result = 0,
|
||||
.result = .none,
|
||||
};
|
||||
|
||||
if (loop_scope.label) |some| {
|
||||
@ -2838,7 +2821,7 @@ fn ret(mod: *Module, scope: *Scope, node: ast.Node.Index) InnerError!zir.Inst.Re
|
||||
.ty = try gz.addNode(.ret_type, node),
|
||||
};
|
||||
break :operand try expr(mod, scope, rl, operand_node);
|
||||
} else void_inst;
|
||||
} else .void_value;
|
||||
return gz.addUnNode(.ret_node, operand, node);
|
||||
}
|
||||
|
||||
@ -2862,8 +2845,8 @@ fn identifier(
|
||||
return mod.failNode(scope, ident, "TODO implement '_' identifier", .{});
|
||||
}
|
||||
|
||||
if (simple_types.get(ident_name)) |zir_const_tag| {
|
||||
return rvalue(mod, scope, rl, @enumToInt(zir_const_tag), ident);
|
||||
if (simple_types.get(ident_name)) |zir_const_ref| {
|
||||
return rvalue(mod, scope, rl, zir_const_ref, ident);
|
||||
}
|
||||
|
||||
if (ident_name.len >= 2) integer: {
|
||||
@ -3028,9 +3011,9 @@ fn integerLiteral(
|
||||
const prefixed_bytes = tree.tokenSlice(int_token);
|
||||
const gz = scope.getGenZir();
|
||||
if (std.fmt.parseInt(u64, prefixed_bytes, 0)) |small_int| {
|
||||
const result: zir.Inst.Index = switch (small_int) {
|
||||
0 => @enumToInt(zir.Const.zero),
|
||||
1 => @enumToInt(zir.Const.one),
|
||||
const result: zir.Inst.Ref = switch (small_int) {
|
||||
0 => .zero,
|
||||
1 => .one,
|
||||
else => try gz.addInt(small_int),
|
||||
};
|
||||
return rvalue(mod, scope, rl, result, node);
|
||||
@ -3078,14 +3061,11 @@ fn asmExpr(
|
||||
const node_datas = tree.nodes.items(.data);
|
||||
const gz = scope.getGenZir();
|
||||
|
||||
const str_type = @enumToInt(zir.Const.const_slice_u8_type);
|
||||
const str_type_rl: ResultLoc = .{ .ty = str_type };
|
||||
const asm_source = try expr(mod, scope, str_type_rl, full.ast.template);
|
||||
const asm_source = try expr(mod, scope, .{ .ty = .const_slice_u8_type }, full.ast.template);
|
||||
|
||||
if (full.outputs.len != 0) {
|
||||
return mod.failTok(scope, full.ast.asm_token, "TODO implement asm with an output", .{});
|
||||
}
|
||||
const return_type = @enumToInt(zir.Const.void_type);
|
||||
|
||||
const constraints = try arena.alloc(u32, full.inputs.len);
|
||||
const args = try arena.alloc(zir.Inst.Ref, full.inputs.len);
|
||||
@ -3098,22 +3078,21 @@ fn asmExpr(
|
||||
try mod.parseStrLit(scope, constraint_token, string_bytes, token_bytes, 0);
|
||||
try string_bytes.append(mod.gpa, 0);
|
||||
|
||||
const usize_rl: ResultLoc = .{ .ty = @enumToInt(zir.Const.usize_type) };
|
||||
args[i] = try expr(mod, scope, usize_rl, node_datas[input].lhs);
|
||||
args[i] = try expr(mod, scope, .{ .ty = .usize_type }, node_datas[input].lhs);
|
||||
}
|
||||
|
||||
const tag: zir.Inst.Tag = if (full.volatile_token != null) .asm_volatile else .@"asm";
|
||||
const result = try gz.addPlNode(tag, node, zir.Inst.Asm{
|
||||
.asm_source = asm_source,
|
||||
.return_type = return_type,
|
||||
.output = 0,
|
||||
.return_type = .void_type,
|
||||
.output = .none,
|
||||
.args_len = @intCast(u32, full.inputs.len),
|
||||
.clobbers_len = 0, // TODO implement asm clobbers
|
||||
});
|
||||
|
||||
try gz.zir_code.extra.ensureCapacity(mod.gpa, gz.zir_code.extra.items.len +
|
||||
args.len + constraints.len);
|
||||
gz.zir_code.extra.appendSliceAssumeCapacity(args);
|
||||
gz.zir_code.extra.appendSliceAssumeCapacity(mem.bytesAsSlice(u32, mem.sliceAsBytes(args)));
|
||||
gz.zir_code.extra.appendSliceAssumeCapacity(constraints);
|
||||
|
||||
return rvalue(mod, scope, rl, result, node);
|
||||
@ -3185,7 +3164,7 @@ fn asRlPtr(
|
||||
const expected_len = parent_zir.items.len + as_scope.instructions.items.len - 2;
|
||||
try parent_zir.ensureCapacity(mod.gpa, expected_len);
|
||||
for (as_scope.instructions.items) |src_inst| {
|
||||
if (wzc.ref_start_index + src_inst == as_scope.rl_ptr) continue;
|
||||
if (zir.Inst.Ref.fromIndex(src_inst, wzc.param_count) == as_scope.rl_ptr) continue;
|
||||
if (zir_tags[src_inst] == .store_to_block_ptr) {
|
||||
if (zir_datas[src_inst].bin.lhs == as_scope.rl_ptr) continue;
|
||||
}
|
||||
@ -3272,11 +3251,12 @@ fn typeOf(
|
||||
}
|
||||
const arena = scope.arena();
|
||||
var items = try arena.alloc(zir.Inst.Ref, params.len);
|
||||
for (params) |param, param_i|
|
||||
for (params) |param, param_i| {
|
||||
items[param_i] = try expr(mod, scope, .none, param);
|
||||
}
|
||||
|
||||
const result = try gz.addPlNode(.typeof_peer, node, zir.Inst.MultiOp{ .operands_len = @intCast(u32, params.len) });
|
||||
try gz.zir_code.extra.appendSlice(gz.zir_code.gpa, items);
|
||||
try gz.zir_code.extra.appendSlice(gz.zir_code.gpa, mem.bytesAsSlice(u32, mem.sliceAsBytes(items)));
|
||||
|
||||
return rvalue(mod, scope, rl, result, node);
|
||||
}
|
||||
@ -3351,8 +3331,7 @@ fn builtinCall(
|
||||
return rvalue(mod, scope, rl, result, node);
|
||||
},
|
||||
.set_eval_branch_quota => {
|
||||
const u32_rl: ResultLoc = .{ .ty = @enumToInt(zir.Const.u32_type) };
|
||||
const quota = try expr(mod, scope, u32_rl, params[0]);
|
||||
const quota = try expr(mod, scope, .{ .ty = .u32_type }, params[0]);
|
||||
const result = try gz.addUnNode(.set_eval_branch_quota, quota, node);
|
||||
return rvalue(mod, scope, rl, result, node);
|
||||
},
|
||||
@ -3498,7 +3477,7 @@ fn callExpr(
|
||||
}
|
||||
const lhs = try expr(mod, scope, .none, call.ast.fn_expr);
|
||||
|
||||
const args = try mod.gpa.alloc(zir.Inst.Index, call.ast.params.len);
|
||||
const args = try mod.gpa.alloc(zir.Inst.Ref, call.ast.params.len);
|
||||
defer mod.gpa.free(args);
|
||||
|
||||
const gz = scope.getGenZir();
|
||||
@ -3517,7 +3496,7 @@ fn callExpr(
|
||||
true => .async_kw,
|
||||
false => .auto,
|
||||
};
|
||||
const result: zir.Inst.Index = res: {
|
||||
const result: zir.Inst.Ref = res: {
|
||||
const tag: zir.Inst.Tag = switch (modifier) {
|
||||
.auto => switch (args.len == 0) {
|
||||
true => break :res try gz.addUnNode(.call_none, lhs, node),
|
||||
@ -3536,7 +3515,7 @@ fn callExpr(
|
||||
return rvalue(mod, scope, rl, result, node); // TODO function call with result location
|
||||
}
|
||||
|
||||
pub const simple_types = std.ComptimeStringMap(zir.Const, .{
|
||||
pub const simple_types = std.ComptimeStringMap(zir.Inst.Ref, .{
|
||||
.{ "u8", .u8_type },
|
||||
.{ "i8", .i8_type },
|
||||
.{ "u16", .u16_type },
|
||||
|
||||
633
src/zir.zig
633
src/zir.zig
@ -48,8 +48,11 @@ pub const Code = struct {
|
||||
var i: usize = index;
|
||||
var result: T = undefined;
|
||||
inline for (fields) |field| {
|
||||
comptime assert(field.field_type == u32);
|
||||
@field(result, field.name) = code.extra[i];
|
||||
@field(result, field.name) = switch (field.field_type) {
|
||||
u32 => code.extra[i],
|
||||
Inst.Ref => @intToEnum(Inst.Ref, code.extra[i]),
|
||||
else => unreachable,
|
||||
};
|
||||
i += 1;
|
||||
}
|
||||
return .{
|
||||
@ -105,284 +108,6 @@ pub const Code = struct {
|
||||
}
|
||||
};
|
||||
|
||||
/// These correspond to the first N tags of Value.
|
||||
/// A ZIR instruction refers to another one by index. However the first N indexes
|
||||
/// correspond to this enum, and the next M indexes correspond to the parameters
|
||||
/// of the current function. After that, they refer to other instructions in the
|
||||
/// instructions array for the function.
|
||||
/// When adding to this, consider adding a corresponding entry o `simple_types`
|
||||
/// in astgen.
|
||||
pub const Const = enum {
|
||||
/// The 0 value is reserved so that ZIR instruction indexes can use it to
|
||||
/// mean "null".
|
||||
unused,
|
||||
|
||||
u8_type,
|
||||
i8_type,
|
||||
u16_type,
|
||||
i16_type,
|
||||
u32_type,
|
||||
i32_type,
|
||||
u64_type,
|
||||
i64_type,
|
||||
u128_type,
|
||||
i128_type,
|
||||
usize_type,
|
||||
isize_type,
|
||||
c_short_type,
|
||||
c_ushort_type,
|
||||
c_int_type,
|
||||
c_uint_type,
|
||||
c_long_type,
|
||||
c_ulong_type,
|
||||
c_longlong_type,
|
||||
c_ulonglong_type,
|
||||
c_longdouble_type,
|
||||
f16_type,
|
||||
f32_type,
|
||||
f64_type,
|
||||
f128_type,
|
||||
c_void_type,
|
||||
bool_type,
|
||||
void_type,
|
||||
type_type,
|
||||
anyerror_type,
|
||||
comptime_int_type,
|
||||
comptime_float_type,
|
||||
noreturn_type,
|
||||
null_type,
|
||||
undefined_type,
|
||||
fn_noreturn_no_args_type,
|
||||
fn_void_no_args_type,
|
||||
fn_naked_noreturn_no_args_type,
|
||||
fn_ccc_void_no_args_type,
|
||||
single_const_pointer_to_comptime_int_type,
|
||||
const_slice_u8_type,
|
||||
enum_literal_type,
|
||||
|
||||
/// `undefined` (untyped)
|
||||
undef,
|
||||
/// `0` (comptime_int)
|
||||
zero,
|
||||
/// `1` (comptime_int)
|
||||
one,
|
||||
/// `{}`
|
||||
void_value,
|
||||
/// `unreachable` (noreturn type)
|
||||
unreachable_value,
|
||||
/// `null` (untyped)
|
||||
null_value,
|
||||
/// `true`
|
||||
bool_true,
|
||||
/// `false`
|
||||
bool_false,
|
||||
};
|
||||
|
||||
pub const const_inst_list = std.enums.directEnumArray(Const, TypedValue, 0, .{
|
||||
.unused = undefined,
|
||||
.u8_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.u8_type),
|
||||
},
|
||||
.i8_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.i8_type),
|
||||
},
|
||||
.u16_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.u16_type),
|
||||
},
|
||||
.i16_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.i16_type),
|
||||
},
|
||||
.u32_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.u32_type),
|
||||
},
|
||||
.i32_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.i32_type),
|
||||
},
|
||||
.u64_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.u64_type),
|
||||
},
|
||||
.i64_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.i64_type),
|
||||
},
|
||||
.u128_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.u128_type),
|
||||
},
|
||||
.i128_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.i128_type),
|
||||
},
|
||||
.usize_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.usize_type),
|
||||
},
|
||||
.isize_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.isize_type),
|
||||
},
|
||||
.c_short_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.c_short_type),
|
||||
},
|
||||
.c_ushort_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.c_ushort_type),
|
||||
},
|
||||
.c_int_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.c_int_type),
|
||||
},
|
||||
.c_uint_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.c_uint_type),
|
||||
},
|
||||
.c_long_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.c_long_type),
|
||||
},
|
||||
.c_ulong_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.c_ulong_type),
|
||||
},
|
||||
.c_longlong_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.c_longlong_type),
|
||||
},
|
||||
.c_ulonglong_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.c_ulonglong_type),
|
||||
},
|
||||
.c_longdouble_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.c_longdouble_type),
|
||||
},
|
||||
.f16_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.f16_type),
|
||||
},
|
||||
.f32_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.f32_type),
|
||||
},
|
||||
.f64_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.f64_type),
|
||||
},
|
||||
.f128_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.f128_type),
|
||||
},
|
||||
.c_void_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.c_void_type),
|
||||
},
|
||||
.bool_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.bool_type),
|
||||
},
|
||||
.void_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.void_type),
|
||||
},
|
||||
.type_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.type_type),
|
||||
},
|
||||
.anyerror_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.anyerror_type),
|
||||
},
|
||||
.comptime_int_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.comptime_int_type),
|
||||
},
|
||||
.comptime_float_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.comptime_float_type),
|
||||
},
|
||||
.noreturn_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.noreturn_type),
|
||||
},
|
||||
.null_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.null_type),
|
||||
},
|
||||
.undefined_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.undefined_type),
|
||||
},
|
||||
.fn_noreturn_no_args_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.fn_noreturn_no_args_type),
|
||||
},
|
||||
.fn_void_no_args_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.fn_void_no_args_type),
|
||||
},
|
||||
.fn_naked_noreturn_no_args_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.fn_naked_noreturn_no_args_type),
|
||||
},
|
||||
.fn_ccc_void_no_args_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.fn_ccc_void_no_args_type),
|
||||
},
|
||||
.single_const_pointer_to_comptime_int_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.single_const_pointer_to_comptime_int_type),
|
||||
},
|
||||
.const_slice_u8_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.const_slice_u8_type),
|
||||
},
|
||||
.enum_literal_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.enum_literal_type),
|
||||
},
|
||||
|
||||
.undef = .{
|
||||
.ty = Type.initTag(.@"undefined"),
|
||||
.val = Value.initTag(.undef),
|
||||
},
|
||||
.zero = .{
|
||||
.ty = Type.initTag(.comptime_int),
|
||||
.val = Value.initTag(.zero),
|
||||
},
|
||||
.one = .{
|
||||
.ty = Type.initTag(.comptime_int),
|
||||
.val = Value.initTag(.one),
|
||||
},
|
||||
.void_value = .{
|
||||
.ty = Type.initTag(.void),
|
||||
.val = Value.initTag(.void_value),
|
||||
},
|
||||
.unreachable_value = .{
|
||||
.ty = Type.initTag(.noreturn),
|
||||
.val = Value.initTag(.unreachable_value),
|
||||
},
|
||||
.null_value = .{
|
||||
.ty = Type.initTag(.@"null"),
|
||||
.val = Value.initTag(.null_value),
|
||||
},
|
||||
.bool_true = .{
|
||||
.ty = Type.initTag(.bool),
|
||||
.val = Value.initTag(.bool_true),
|
||||
},
|
||||
.bool_false = .{
|
||||
.ty = Type.initTag(.bool),
|
||||
.val = Value.initTag(.bool_false),
|
||||
},
|
||||
});
|
||||
|
||||
/// These are untyped instructions generated from an Abstract Syntax Tree.
|
||||
/// The data here is immutable because it is possible to have multiple
|
||||
/// analyses on the same ZIR happening at the same time.
|
||||
@ -1032,14 +757,319 @@ pub const Inst = struct {
|
||||
/// The position of a ZIR instruction within the `Code` instructions array.
|
||||
pub const Index = u32;
|
||||
|
||||
/// A reference to another ZIR instruction. If this value is below a certain
|
||||
/// threshold, it implicitly refers to a constant-known value from the `Const` enum.
|
||||
/// Below a second threshold, it implicitly refers to a parameter of the current
|
||||
/// function.
|
||||
/// Finally, after subtracting that offset, it refers to another instruction in
|
||||
/// the instruction array.
|
||||
/// This logic is implemented in `Sema.resolveRef`.
|
||||
pub const Ref = u32;
|
||||
/// A reference to a TypedValue, parameter of the current function,
|
||||
/// or ZIR instruction.
|
||||
///
|
||||
/// If the Ref has a tag in this enum, it refers to a TypedValue which may be
|
||||
/// retrieved with Ref.toTypedValue().
|
||||
///
|
||||
/// If the value of a Ref does not have a tag, it referes to either a parameter
|
||||
/// of the current function or a ZIR instruction.
|
||||
///
|
||||
/// The first values after the the last tag refer to parameters which may be
|
||||
/// derived by subtracting typed_value_count.
|
||||
///
|
||||
/// All further values refer to ZIR instructions which may be derived by
|
||||
/// subtracting typed_value_count and the number of parameters.
|
||||
///
|
||||
/// When adding a tag to this enum, consider adding a corresponding entry to
|
||||
/// `simple_types` in astgen.
|
||||
///
|
||||
/// This is packed so that it is safe to cast between `[]u32` and `[]Ref`.
|
||||
pub const Ref = packed enum(u32) {
|
||||
/// This Ref does not correspond to any ZIR instruction or constant
|
||||
/// value and may instead be used as a sentinel to indicate null.
|
||||
none,
|
||||
|
||||
u8_type,
|
||||
i8_type,
|
||||
u16_type,
|
||||
i16_type,
|
||||
u32_type,
|
||||
i32_type,
|
||||
u64_type,
|
||||
i64_type,
|
||||
usize_type,
|
||||
isize_type,
|
||||
c_short_type,
|
||||
c_ushort_type,
|
||||
c_int_type,
|
||||
c_uint_type,
|
||||
c_long_type,
|
||||
c_ulong_type,
|
||||
c_longlong_type,
|
||||
c_ulonglong_type,
|
||||
c_longdouble_type,
|
||||
f16_type,
|
||||
f32_type,
|
||||
f64_type,
|
||||
f128_type,
|
||||
c_void_type,
|
||||
bool_type,
|
||||
void_type,
|
||||
type_type,
|
||||
anyerror_type,
|
||||
comptime_int_type,
|
||||
comptime_float_type,
|
||||
noreturn_type,
|
||||
null_type,
|
||||
undefined_type,
|
||||
fn_noreturn_no_args_type,
|
||||
fn_void_no_args_type,
|
||||
fn_naked_noreturn_no_args_type,
|
||||
fn_ccc_void_no_args_type,
|
||||
single_const_pointer_to_comptime_int_type,
|
||||
const_slice_u8_type,
|
||||
enum_literal_type,
|
||||
|
||||
/// `undefined` (untyped)
|
||||
undef,
|
||||
/// `0` (comptime_int)
|
||||
zero,
|
||||
/// `1` (comptime_int)
|
||||
one,
|
||||
/// `{}`
|
||||
void_value,
|
||||
/// `unreachable` (noreturn type)
|
||||
unreachable_value,
|
||||
/// `null` (untyped)
|
||||
null_value,
|
||||
/// `true`
|
||||
bool_true,
|
||||
/// `false`
|
||||
bool_false,
|
||||
|
||||
_,
|
||||
|
||||
pub const typed_value_count = @as(u32, typed_value_map.len);
|
||||
const typed_value_map = std.enums.directEnumArray(Ref, TypedValue, 0, .{
|
||||
.none = undefined,
|
||||
|
||||
.u8_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.u8_type),
|
||||
},
|
||||
.i8_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.i8_type),
|
||||
},
|
||||
.u16_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.u16_type),
|
||||
},
|
||||
.i16_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.i16_type),
|
||||
},
|
||||
.u32_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.u32_type),
|
||||
},
|
||||
.i32_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.i32_type),
|
||||
},
|
||||
.u64_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.u64_type),
|
||||
},
|
||||
.i64_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.i64_type),
|
||||
},
|
||||
.usize_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.usize_type),
|
||||
},
|
||||
.isize_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.isize_type),
|
||||
},
|
||||
.c_short_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.c_short_type),
|
||||
},
|
||||
.c_ushort_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.c_ushort_type),
|
||||
},
|
||||
.c_int_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.c_int_type),
|
||||
},
|
||||
.c_uint_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.c_uint_type),
|
||||
},
|
||||
.c_long_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.c_long_type),
|
||||
},
|
||||
.c_ulong_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.c_ulong_type),
|
||||
},
|
||||
.c_longlong_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.c_longlong_type),
|
||||
},
|
||||
.c_ulonglong_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.c_ulonglong_type),
|
||||
},
|
||||
.c_longdouble_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.c_longdouble_type),
|
||||
},
|
||||
.f16_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.f16_type),
|
||||
},
|
||||
.f32_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.f32_type),
|
||||
},
|
||||
.f64_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.f64_type),
|
||||
},
|
||||
.f128_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.f128_type),
|
||||
},
|
||||
.c_void_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.c_void_type),
|
||||
},
|
||||
.bool_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.bool_type),
|
||||
},
|
||||
.void_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.void_type),
|
||||
},
|
||||
.type_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.type_type),
|
||||
},
|
||||
.anyerror_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.anyerror_type),
|
||||
},
|
||||
.comptime_int_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.comptime_int_type),
|
||||
},
|
||||
.comptime_float_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.comptime_float_type),
|
||||
},
|
||||
.noreturn_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.noreturn_type),
|
||||
},
|
||||
.null_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.null_type),
|
||||
},
|
||||
.undefined_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.undefined_type),
|
||||
},
|
||||
.fn_noreturn_no_args_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.fn_noreturn_no_args_type),
|
||||
},
|
||||
.fn_void_no_args_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.fn_void_no_args_type),
|
||||
},
|
||||
.fn_naked_noreturn_no_args_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.fn_naked_noreturn_no_args_type),
|
||||
},
|
||||
.fn_ccc_void_no_args_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.fn_ccc_void_no_args_type),
|
||||
},
|
||||
.single_const_pointer_to_comptime_int_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.single_const_pointer_to_comptime_int_type),
|
||||
},
|
||||
.const_slice_u8_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.const_slice_u8_type),
|
||||
},
|
||||
.enum_literal_type = .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.enum_literal_type),
|
||||
},
|
||||
|
||||
.undef = .{
|
||||
.ty = Type.initTag(.@"undefined"),
|
||||
.val = Value.initTag(.undef),
|
||||
},
|
||||
.zero = .{
|
||||
.ty = Type.initTag(.comptime_int),
|
||||
.val = Value.initTag(.zero),
|
||||
},
|
||||
.one = .{
|
||||
.ty = Type.initTag(.comptime_int),
|
||||
.val = Value.initTag(.one),
|
||||
},
|
||||
.void_value = .{
|
||||
.ty = Type.initTag(.void),
|
||||
.val = Value.initTag(.void_value),
|
||||
},
|
||||
.unreachable_value = .{
|
||||
.ty = Type.initTag(.noreturn),
|
||||
.val = Value.initTag(.unreachable_value),
|
||||
},
|
||||
.null_value = .{
|
||||
.ty = Type.initTag(.@"null"),
|
||||
.val = Value.initTag(.null_value),
|
||||
},
|
||||
.bool_true = .{
|
||||
.ty = Type.initTag(.bool),
|
||||
.val = Value.initTag(.bool_true),
|
||||
},
|
||||
.bool_false = .{
|
||||
.ty = Type.initTag(.bool),
|
||||
.val = Value.initTag(.bool_false),
|
||||
},
|
||||
});
|
||||
|
||||
pub fn fromParam(param: u32) Ref {
|
||||
return @intToEnum(Ref, typed_value_count + param);
|
||||
}
|
||||
|
||||
pub fn fromIndex(index: Index, param_count: u32) Ref {
|
||||
return @intToEnum(Ref, typed_value_count + param_count + index);
|
||||
}
|
||||
|
||||
pub fn toTypedValue(ref: Ref) ?TypedValue {
|
||||
assert(ref != .none);
|
||||
if (@enumToInt(ref) >= typed_value_count) return null;
|
||||
return typed_value_map[@enumToInt(ref)];
|
||||
}
|
||||
|
||||
pub fn toParam(ref: Ref, param_count: u32) ?u32 {
|
||||
assert(ref != .none);
|
||||
if (@enumToInt(ref) < typed_value_count or
|
||||
@enumToInt(ref) >= typed_value_count + param_count)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return @enumToInt(ref) - typed_value_count;
|
||||
}
|
||||
|
||||
pub fn toIndex(ref: Ref, param_count: u32) ?Index {
|
||||
assert(ref != .none);
|
||||
if (@enumToInt(ref) < typed_value_count + param_count) return null;
|
||||
return @enumToInt(ref) - typed_value_count - param_count;
|
||||
}
|
||||
};
|
||||
|
||||
/// All instructions have an 8-byte payload, which is contained within
|
||||
/// this union. `Tag` determines which union field is active, as well as
|
||||
@ -1642,7 +1672,9 @@ const Writer = struct {
|
||||
fn writePlNodeCall(self: *Writer, stream: anytype, inst: Inst.Index) !void {
|
||||
const inst_data = self.code.instructions.items(.data)[inst].pl_node;
|
||||
const extra = self.code.extraData(Inst.Call, inst_data.payload_index);
|
||||
const args = self.code.extra[extra.end..][0..extra.data.args_len];
|
||||
const raw_args = self.code.extra[extra.end..][0..extra.data.args_len];
|
||||
const args = mem.bytesAsSlice(Inst.Ref, mem.sliceAsBytes(raw_args));
|
||||
|
||||
try self.writeInstRef(stream, extra.data.callee);
|
||||
try stream.writeAll(", [");
|
||||
for (args) |arg, i| {
|
||||
@ -1735,9 +1767,9 @@ const Writer = struct {
|
||||
) (@TypeOf(stream).Error || error{OutOfMemory})!void {
|
||||
const inst_data = self.code.instructions.items(.data)[inst].fn_type;
|
||||
const extra = self.code.extraData(Inst.FnType, inst_data.payload_index);
|
||||
const param_types = self.code.extra[extra.end..][0..extra.data.param_types_len];
|
||||
const cc: Inst.Ref = 0;
|
||||
return self.writeFnTypeCommon(stream, param_types, inst_data.return_type, var_args, cc);
|
||||
const raw_param_types = self.code.extra[extra.end..][0..extra.data.param_types_len];
|
||||
const param_types = mem.bytesAsSlice(Inst.Ref, mem.sliceAsBytes(raw_param_types));
|
||||
return self.writeFnTypeCommon(stream, param_types, inst_data.return_type, var_args, .none);
|
||||
}
|
||||
|
||||
fn writeBoolBr(self: *Writer, stream: anytype, inst: Inst.Index) !void {
|
||||
@ -1761,7 +1793,8 @@ const Writer = struct {
|
||||
) (@TypeOf(stream).Error || error{OutOfMemory})!void {
|
||||
const inst_data = self.code.instructions.items(.data)[inst].fn_type;
|
||||
const extra = self.code.extraData(Inst.FnTypeCc, inst_data.payload_index);
|
||||
const param_types = self.code.extra[extra.end..][0..extra.data.param_types_len];
|
||||
const raw_param_types = self.code.extra[extra.end..][0..extra.data.param_types_len];
|
||||
const param_types = mem.bytesAsSlice(Inst.Ref, mem.sliceAsBytes(raw_param_types));
|
||||
const cc = extra.data.cc;
|
||||
return self.writeFnTypeCommon(stream, param_types, inst_data.return_type, var_args, cc);
|
||||
}
|
||||
@ -1828,13 +1861,13 @@ const Writer = struct {
|
||||
try stream.print("\"{}\")", .{std.zig.fmtEscapes(str)});
|
||||
}
|
||||
|
||||
fn writeInstRef(self: *Writer, stream: anytype, inst: Inst.Ref) !void {
|
||||
var i: usize = inst;
|
||||
fn writeInstRef(self: *Writer, stream: anytype, ref: Inst.Ref) !void {
|
||||
var i: usize = @enumToInt(ref);
|
||||
|
||||
if (i < const_inst_list.len) {
|
||||
return stream.print("@{d}", .{i});
|
||||
if (i < Inst.Ref.typed_value_count) {
|
||||
return stream.print("@{}", .{ref});
|
||||
}
|
||||
i -= const_inst_list.len;
|
||||
i -= Inst.Ref.typed_value_count;
|
||||
|
||||
if (i < self.param_count) {
|
||||
return stream.print("${d}", .{i});
|
||||
@ -1852,9 +1885,9 @@ const Writer = struct {
|
||||
self: *Writer,
|
||||
stream: anytype,
|
||||
prefix: []const u8,
|
||||
inst: Inst.Index,
|
||||
inst: Inst.Ref,
|
||||
) !void {
|
||||
if (inst == 0) return;
|
||||
if (inst == .none) return;
|
||||
try stream.writeAll(prefix);
|
||||
try self.writeInstRef(stream, inst);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user