enum Type [src]

Fields

void
half
bfloat
float
double
fp128
x86_fp80
ppc_fp128
x86_amx
x86_mmx
label
token
metadata
i1
i8
i16
i29
i32
i64
i80
i128
ptr
@"ptr addrspace(4)"
none = std.math.maxInt(u32)
_

Members

Source

pub const Type = enum(u32) { void, half, bfloat, float, double, fp128, x86_fp80, ppc_fp128, x86_amx, x86_mmx, label, token, metadata, i1, i8, i16, i29, i32, i64, i80, i128, ptr, @"ptr addrspace(4)", none = std.math.maxInt(u32), _, pub const ptr_amdgpu_constant = @field(Type, std.fmt.comptimePrint("ptr{ }", .{AddrSpace.amdgpu.constant})); pub const Tag = enum(u4) { simple, function, vararg_function, integer, pointer, target, vector, scalable_vector, small_array, array, structure, packed_structure, named_structure, }; pub const Simple = enum(u5) { void = 2, half = 10, bfloat = 23, float = 3, double = 4, fp128 = 14, x86_fp80 = 13, ppc_fp128 = 15, x86_amx = 24, x86_mmx = 17, label = 5, token = 22, metadata = 16, }; pub const Function = struct { ret: Type, params_len: u32, //params: [params_len]Value, pub const Kind = enum { normal, vararg }; }; pub const Target = extern struct { name: String, types_len: u32, ints_len: u32, //types: [types_len]Type, //ints: [ints_len]u32, }; pub const Vector = extern struct { len: u32, child: Type, fn length(self: Vector) u32 { return self.len; } pub const Kind = enum { normal, scalable }; }; pub const Array = extern struct { len_lo: u32, len_hi: u32, child: Type, fn length(self: Array) u64 { return @as(u64, self.len_hi) << 32 | self.len_lo; } }; pub const Structure = struct { fields_len: u32, //fields: [fields_len]Type, pub const Kind = enum { normal, @"packed" }; }; pub const NamedStructure = struct { id: String, body: Type, }; pub const Item = packed struct(u32) { tag: Tag, data: ExtraIndex, pub const ExtraIndex = u28; }; pub fn tag(self: Type, builder: *const Builder) Tag { return builder.type_items.items[@intFromEnum(self)].tag; } pub fn unnamedTag(self: Type, builder: *const Builder) Tag { const item = builder.type_items.items[@intFromEnum(self)]; return switch (item.tag) { .named_structure => builder.typeExtraData(Type.NamedStructure, item.data).body .unnamedTag(builder), else => item.tag, }; } pub fn scalarTag(self: Type, builder: *const Builder) Tag { const item = builder.type_items.items[@intFromEnum(self)]; return switch (item.tag) { .vector, .scalable_vector => builder.typeExtraData(Type.Vector, item.data) .child.tag(builder), else => item.tag, }; } pub fn isFloatingPoint(self: Type) bool { return switch (self) { .half, .bfloat, .float, .double, .fp128, .x86_fp80, .ppc_fp128 => true, else => false, }; } pub fn isInteger(self: Type, builder: *const Builder) bool { return switch (self) { .i1, .i8, .i16, .i29, .i32, .i64, .i80, .i128 => true, else => switch (self.tag(builder)) { .integer => true, else => false, }, }; } pub fn isPointer(self: Type, builder: *const Builder) bool { return switch (self) { .ptr => true, else => switch (self.tag(builder)) { .pointer => true, else => false, }, }; } pub fn pointerAddrSpace(self: Type, builder: *const Builder) AddrSpace { switch (self) { .ptr => return .default, else => { const item = builder.type_items.items[@intFromEnum(self)]; assert(item.tag == .pointer); return @enumFromInt(item.data); }, } } pub fn isFunction(self: Type, builder: *const Builder) bool { return switch (self.tag(builder)) { .function, .vararg_function => true, else => false, }; } pub fn functionKind(self: Type, builder: *const Builder) Type.Function.Kind { return switch (self.tag(builder)) { .function => .normal, .vararg_function => .vararg, else => unreachable, }; } pub fn functionParameters(self: Type, builder: *const Builder) []const Type { const item = builder.type_items.items[@intFromEnum(self)]; switch (item.tag) { .function, .vararg_function, => { var extra = builder.typeExtraDataTrail(Type.Function, item.data); return extra.trail.next(extra.data.params_len, Type, builder); }, else => unreachable, } } pub fn functionReturn(self: Type, builder: *const Builder) Type { const item = builder.type_items.items[@intFromEnum(self)]; switch (item.tag) { .function, .vararg_function, => return builder.typeExtraData(Type.Function, item.data).ret, else => unreachable, } } pub fn isVector(self: Type, builder: *const Builder) bool { return switch (self.tag(builder)) { .vector, .scalable_vector => true, else => false, }; } pub fn vectorKind(self: Type, builder: *const Builder) Type.Vector.Kind { return switch (self.tag(builder)) { .vector => .normal, .scalable_vector => .scalable, else => unreachable, }; } pub fn isStruct(self: Type, builder: *const Builder) bool { return switch (self.tag(builder)) { .structure, .packed_structure, .named_structure => true, else => false, }; } pub fn structKind(self: Type, builder: *const Builder) Type.Structure.Kind { return switch (self.unnamedTag(builder)) { .structure => .normal, .packed_structure => .@"packed", else => unreachable, }; } pub fn isAggregate(self: Type, builder: *const Builder) bool { return switch (self.tag(builder)) { .small_array, .array, .structure, .packed_structure, .named_structure => true, else => false, }; } pub fn scalarBits(self: Type, builder: *const Builder) u24 { return switch (self) { .void, .label, .token, .metadata, .none, .x86_amx => unreachable, .i1 => 1, .i8 => 8, .half, .bfloat, .i16 => 16, .i29 => 29, .float, .i32 => 32, .double, .i64, .x86_mmx => 64, .x86_fp80, .i80 => 80, .fp128, .ppc_fp128, .i128 => 128, .ptr, .@"ptr addrspace(4)" => @panic("TODO: query data layout"), _ => { const item = builder.type_items.items[@intFromEnum(self)]; return switch (item.tag) { .simple, .function, .vararg_function, => unreachable, .integer => @intCast(item.data), .pointer => @panic("TODO: query data layout"), .target => unreachable, .vector, .scalable_vector, => builder.typeExtraData(Type.Vector, item.data).child.scalarBits(builder), .small_array, .array, .structure, .packed_structure, .named_structure, => unreachable, }; }, }; } pub fn childType(self: Type, builder: *const Builder) Type { const item = builder.type_items.items[@intFromEnum(self)]; return switch (item.tag) { .vector, .scalable_vector, .small_array, => builder.typeExtraData(Type.Vector, item.data).child, .array => builder.typeExtraData(Type.Array, item.data).child, .named_structure => builder.typeExtraData(Type.NamedStructure, item.data).body, else => unreachable, }; } pub fn scalarType(self: Type, builder: *const Builder) Type { if (self.isFloatingPoint()) return self; const item = builder.type_items.items[@intFromEnum(self)]; return switch (item.tag) { .integer, .pointer, => self, .vector, .scalable_vector, => builder.typeExtraData(Type.Vector, item.data).child, else => unreachable, }; } pub fn changeScalar(self: Type, scalar: Type, builder: *Builder) Allocator.Error!Type { try builder.ensureUnusedTypeCapacity(1, Type.Vector, 0); return self.changeScalarAssumeCapacity(scalar, builder); } pub fn changeScalarAssumeCapacity(self: Type, scalar: Type, builder: *Builder) Type { if (self.isFloatingPoint()) return scalar; const item = builder.type_items.items[@intFromEnum(self)]; return switch (item.tag) { .integer, .pointer, => scalar, inline .vector, .scalable_vector, => |kind| builder.vectorTypeAssumeCapacity( switch (kind) { .vector => .normal, .scalable_vector => .scalable, else => unreachable, }, builder.typeExtraData(Type.Vector, item.data).len, scalar, ), else => unreachable, }; } pub fn vectorLen(self: Type, builder: *const Builder) u32 { const item = builder.type_items.items[@intFromEnum(self)]; return switch (item.tag) { .vector, .scalable_vector, => builder.typeExtraData(Type.Vector, item.data).len, else => unreachable, }; } pub fn changeLength(self: Type, len: u32, builder: *Builder) Allocator.Error!Type { try builder.ensureUnusedTypeCapacity(1, Type.Array, 0); return self.changeLengthAssumeCapacity(len, builder); } pub fn changeLengthAssumeCapacity(self: Type, len: u32, builder: *Builder) Type { const item = builder.type_items.items[@intFromEnum(self)]; return switch (item.tag) { inline .vector, .scalable_vector, => |kind| builder.vectorTypeAssumeCapacity( switch (kind) { .vector => .normal, .scalable_vector => .scalable, else => unreachable, }, len, builder.typeExtraData(Type.Vector, item.data).child, ), .small_array => builder.arrayTypeAssumeCapacity( len, builder.typeExtraData(Type.Vector, item.data).child, ), .array => builder.arrayTypeAssumeCapacity( len, builder.typeExtraData(Type.Array, item.data).child, ), else => unreachable, }; } pub fn aggregateLen(self: Type, builder: *const Builder) usize { const item = builder.type_items.items[@intFromEnum(self)]; return switch (item.tag) { .vector, .scalable_vector, .small_array, => builder.typeExtraData(Type.Vector, item.data).len, .array => @intCast(builder.typeExtraData(Type.Array, item.data).length()), .structure, .packed_structure, => builder.typeExtraData(Type.Structure, item.data).fields_len, .named_structure => builder.typeExtraData(Type.NamedStructure, item.data).body .aggregateLen(builder), else => unreachable, }; } pub fn structFields(self: Type, builder: *const Builder) []const Type { const item = builder.type_items.items[@intFromEnum(self)]; switch (item.tag) { .structure, .packed_structure, => { var extra = builder.typeExtraDataTrail(Type.Structure, item.data); return extra.trail.next(extra.data.fields_len, Type, builder); }, .named_structure => return builder.typeExtraData(Type.NamedStructure, item.data).body .structFields(builder), else => unreachable, } } pub fn childTypeAt(self: Type, indices: []const u32, builder: *const Builder) Type { if (indices.len == 0) return self; const item = builder.type_items.items[@intFromEnum(self)]; return switch (item.tag) { .small_array => builder.typeExtraData(Type.Vector, item.data).child .childTypeAt(indices[1..], builder), .array => builder.typeExtraData(Type.Array, item.data).child .childTypeAt(indices[1..], builder), .structure, .packed_structure, => { var extra = builder.typeExtraDataTrail(Type.Structure, item.data); const fields = extra.trail.next(extra.data.fields_len, Type, builder); return fields[indices[0]].childTypeAt(indices[1..], builder); }, .named_structure => builder.typeExtraData(Type.NamedStructure, item.data).body .childTypeAt(indices, builder), else => unreachable, }; } pub fn targetLayoutType(self: Type, builder: *const Builder) Type { _ = self; _ = builder; @panic("TODO: implement targetLayoutType"); } pub fn isSized(self: Type, builder: *const Builder) Allocator.Error!bool { var visited: IsSizedVisited = .{}; defer visited.deinit(builder.gpa); const result = try self.isSizedVisited(&visited, builder); return result; } const FormatData = struct { type: Type, builder: *const Builder, }; fn format( data: FormatData, comptime fmt_str: []const u8, fmt_opts: std.fmt.FormatOptions, writer: anytype, ) @TypeOf(writer).Error!void { assert(data.type != .none); if (comptime std.mem.eql(u8, fmt_str, "m")) { const item = data.builder.type_items.items[@intFromEnum(data.type)]; switch (item.tag) { .simple => try writer.writeAll(switch (@as(Simple, @enumFromInt(item.data))) { .void => "isVoid", .half => "f16", .bfloat => "bf16", .float => "f32", .double => "f64", .fp128 => "f128", .x86_fp80 => "f80", .ppc_fp128 => "ppcf128", .x86_amx => "x86amx", .x86_mmx => "x86mmx", .label, .token => unreachable, .metadata => "Metadata", }), .function, .vararg_function => |kind| { var extra = data.builder.typeExtraDataTrail(Type.Function, item.data); const params = extra.trail.next(extra.data.params_len, Type, data.builder); try writer.print("f_{m}", .{extra.data.ret.fmt(data.builder)}); for (params) |param| try writer.print("{m}", .{param.fmt(data.builder)}); switch (kind) { .function => {}, .vararg_function => try writer.writeAll("vararg"), else => unreachable, } try writer.writeByte('f'); }, .integer => try writer.print("i{d}", .{item.data}), .pointer => try writer.print("p{d}", .{item.data}), .target => { var extra = data.builder.typeExtraDataTrail(Type.Target, item.data); const types = extra.trail.next(extra.data.types_len, Type, data.builder); const ints = extra.trail.next(extra.data.ints_len, u32, data.builder); try writer.print("t{s}", .{extra.data.name.slice(data.builder).?}); for (types) |ty| try writer.print("_{m}", .{ty.fmt(data.builder)}); for (ints) |int| try writer.print("_{d}", .{int}); try writer.writeByte('t'); }, .vector, .scalable_vector => |kind| { const extra = data.builder.typeExtraData(Type.Vector, item.data); try writer.print("{s}v{d}{m}", .{ switch (kind) { .vector => "", .scalable_vector => "nx", else => unreachable, }, extra.len, extra.child.fmt(data.builder), }); }, inline .small_array, .array => |kind| { const extra = data.builder.typeExtraData(switch (kind) { .small_array => Type.Vector, .array => Type.Array, else => unreachable, }, item.data); try writer.print("a{d}{m}", .{ extra.length(), extra.child.fmt(data.builder) }); }, .structure, .packed_structure => { var extra = data.builder.typeExtraDataTrail(Type.Structure, item.data); const fields = extra.trail.next(extra.data.fields_len, Type, data.builder); try writer.writeAll("sl_"); for (fields) |field| try writer.print("{m}", .{field.fmt(data.builder)}); try writer.writeByte('s'); }, .named_structure => { const extra = data.builder.typeExtraData(Type.NamedStructure, item.data); try writer.writeAll("s_"); if (extra.id.slice(data.builder)) |id| try writer.writeAll(id); }, } return; } if (std.enums.tagName(Type, data.type)) |name| return writer.writeAll(name); const item = data.builder.type_items.items[@intFromEnum(data.type)]; switch (item.tag) { .simple => unreachable, .function, .vararg_function => |kind| { var extra = data.builder.typeExtraDataTrail(Type.Function, item.data); const params = extra.trail.next(extra.data.params_len, Type, data.builder); if (!comptime std.mem.eql(u8, fmt_str, ">")) try writer.print("{%} ", .{extra.data.ret.fmt(data.builder)}); if (!comptime std.mem.eql(u8, fmt_str, "<")) { try writer.writeByte('('); for (params, 0..) |param, index| { if (index > 0) try writer.writeAll(", "); try writer.print("{%}", .{param.fmt(data.builder)}); } switch (kind) { .function => {}, .vararg_function => { if (params.len > 0) try writer.writeAll(", "); try writer.writeAll("..."); }, else => unreachable, } try writer.writeByte(')'); } }, .integer => try writer.print("i{d}", .{item.data}), .pointer => try writer.print("ptr{ }", .{@as(AddrSpace, @enumFromInt(item.data))}), .target => { var extra = data.builder.typeExtraDataTrail(Type.Target, item.data); const types = extra.trail.next(extra.data.types_len, Type, data.builder); const ints = extra.trail.next(extra.data.ints_len, u32, data.builder); try writer.print( \\target({"} , .{extra.data.name.fmt(data.builder)}); for (types) |ty| try writer.print(", {%}", .{ty.fmt(data.builder)}); for (ints) |int| try writer.print(", {d}", .{int}); try writer.writeByte(')'); }, .vector, .scalable_vector => |kind| { const extra = data.builder.typeExtraData(Type.Vector, item.data); try writer.print("<{s}{d} x {%}>", .{ switch (kind) { .vector => "", .scalable_vector => "vscale x ", else => unreachable, }, extra.len, extra.child.fmt(data.builder), }); }, inline .small_array, .array => |kind| { const extra = data.builder.typeExtraData(switch (kind) { .small_array => Type.Vector, .array => Type.Array, else => unreachable, }, item.data); try writer.print("[{d} x {%}]", .{ extra.length(), extra.child.fmt(data.builder) }); }, .structure, .packed_structure => |kind| { var extra = data.builder.typeExtraDataTrail(Type.Structure, item.data); const fields = extra.trail.next(extra.data.fields_len, Type, data.builder); switch (kind) { .structure => {}, .packed_structure => try writer.writeByte('<'), else => unreachable, } try writer.writeAll("{ "); for (fields, 0..) |field, index| { if (index > 0) try writer.writeAll(", "); try writer.print("{%}", .{field.fmt(data.builder)}); } try writer.writeAll(" }"); switch (kind) { .structure => {}, .packed_structure => try writer.writeByte('>'), else => unreachable, } }, .named_structure => { const extra = data.builder.typeExtraData(Type.NamedStructure, item.data); if (comptime std.mem.eql(u8, fmt_str, "%")) try writer.print("%{}", .{ extra.id.fmt(data.builder), }) else switch (extra.body) { .none => try writer.writeAll("opaque"), else => try format(.{ .type = extra.body, .builder = data.builder, }, fmt_str, fmt_opts, writer), } }, } } pub fn fmt(self: Type, builder: *const Builder) std.fmt.Formatter(format) { return .{ .data = .{ .type = self, .builder = builder } }; } const IsSizedVisited = std.AutoHashMapUnmanaged(Type, void); fn isSizedVisited( self: Type, visited: *IsSizedVisited, builder: *const Builder, ) Allocator.Error!bool { return switch (self) { .void, .label, .token, .metadata, => false, .half, .bfloat, .float, .double, .fp128, .x86_fp80, .ppc_fp128, .x86_amx, .x86_mmx, .i1, .i8, .i16, .i29, .i32, .i64, .i80, .i128, .ptr, .@"ptr addrspace(4)", => true, .none => unreachable, _ => { const item = builder.type_items.items[@intFromEnum(self)]; return switch (item.tag) { .simple => unreachable, .function, .vararg_function, => false, .integer, .pointer, => true, .target => self.targetLayoutType(builder).isSizedVisited(visited, builder), .vector, .scalable_vector, .small_array, => builder.typeExtraData(Type.Vector, item.data) .child.isSizedVisited(visited, builder), .array => builder.typeExtraData(Type.Array, item.data) .child.isSizedVisited(visited, builder), .structure, .packed_structure, => { if (try visited.fetchPut(builder.gpa, self, {})) |_| return false; var extra = builder.typeExtraDataTrail(Type.Structure, item.data); const fields = extra.trail.next(extra.data.fields_len, Type, builder); for (fields) |field| { if (field.isVector(builder) and field.vectorKind(builder) == .scalable) return false; if (!try field.isSizedVisited(visited, builder)) return false; } return true; }, .named_structure => { const body = builder.typeExtraData(Type.NamedStructure, item.data).body; return body != .none and try body.isSizedVisited(visited, builder); }, }; }, }; } }