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
- aggregateLen (Function)
- Array (extern struct)
- changeLength (Function)
- changeLengthAssumeCapacity (Function)
- changeScalar (Function)
- changeScalarAssumeCapacity (Function)
- childType (Function)
- childTypeAt (Function)
- fmt (Function)
- Function (struct)
- functionKind (Function)
- functionParameters (Function)
- functionReturn (Function)
- isAggregate (Function)
- isFloatingPoint (Function)
- isFunction (Function)
- isInteger (Function)
- isPointer (Function)
- isSized (Function)
- isStruct (Function)
- isVector (Function)
- Item (struct)
- NamedStructure (struct)
- pointerAddrSpace (Function)
- ptr_amdgpu_constant (Constant)
- scalarBits (Function)
- scalarTag (Function)
- scalarType (Function)
- Simple (enum)
- structFields (Function)
- structKind (Function)
- Structure (struct)
- tag (Function)
- Tag (enum)
- Target (extern struct)
- targetLayoutType (Function)
- unnamedTag (Function)
- Vector (extern struct)
- vectorKind (Function)
- vectorLen (Function)
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);
},
};
},
};
}
}