Created
June 26, 2023 09:12
-
-
Save HurricanKai/3e08373cd4023869015c1507afbdf102 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pub const Instruction = MergeUnions(FillTemplatedAll(union(enum) { | |
I__Const: struct { value: u0 }, | |
F__Const: struct { value: u0 }, | |
}), IUnOp); | |
pub const IUnOp = FillTemplatedAll(union(enum) { I__Clz, I__Ctz, I__PopCnt }); | |
const std = @import("std"); | |
const BitWidth = enum { B32, B64 }; | |
fn FillTemplatedAll(comptime Template: type) type { | |
return MergeUnions(FillTemplatedBitWidth(BitWidth.B32, Template), FillTemplatedBitWidth(BitWidth.B64, Template)); | |
} | |
fn TransformTemplatedType(comptime bw: BitWidth, comptime is_float: bool, comptime T: type) type { | |
comptime { | |
return switch (@typeInfo(T)) { | |
.Struct => |s| if (s.fields.len == 1) { | |
var new_fields: [s.fields.len]std.builtin.Type.StructField = undefined; | |
for (&new_fields, s.fields) |*new_field, field| { | |
var new_type = TransformTemplatedType(bw, is_float, field.type); | |
new_field.* = .{ | |
.type = new_type, | |
.name = field.name, | |
.default_value = field.default_value, | |
.is_comptime = field.is_comptime, | |
.alignment = @alignOf(new_type), | |
}; | |
} | |
return @Type(.{ .Struct = .{ .layout = s.layout, .backing_integer = s.backing_integer, .fields = &new_fields, .decls = s.decls, .is_tuple = s.is_tuple } }); | |
} else T, | |
.Int => |int| if (int.bits == 0) switch (bw) { | |
BitWidth.B32 => if (is_float) f32 else u32, | |
BitWidth.B64 => if (is_float) f64 else u64, | |
} else T, | |
else => T, | |
}; | |
} | |
} | |
fn FillTemplatedBitWidth(comptime bw: BitWidth, comptime Template: type) type { | |
comptime { | |
var info = @typeInfo(Template).Union; | |
var new_fields: [info.fields.len]std.builtin.Type.UnionField = undefined; | |
for (&new_fields, info.fields) |*new_field, field| { | |
var new_type = field.type; | |
var new_align = field.alignment; | |
var new_name: [field.name.len]u8 = undefined; | |
@memset(&new_name, 0); | |
if (std.mem.replace(u8, field.name, "I__", switch (bw) { | |
BitWidth.B32 => "I32", | |
BitWidth.B64 => "I64", | |
}, &new_name) > 0) { | |
new_type = TransformTemplatedType(bw, false, new_type); | |
new_align = @alignOf(new_type); | |
} else if (std.mem.replace(u8, field.name, "F__", switch (bw) { | |
BitWidth.B32 => "F32", | |
BitWidth.B64 => "F64", | |
}, &new_name) > 0) { | |
new_type = TransformTemplatedType(bw, true, new_type); | |
new_align = @alignOf(new_type); | |
} | |
new_field.* = .{ | |
.name = &new_name, | |
.type = new_type, | |
.alignment = new_align, | |
}; | |
} | |
info.fields = &new_fields; | |
info.tag_type = RebuildTagType(info.fields); | |
const final_type = @Type(.{ .Union = info }); | |
return final_type; | |
} | |
} | |
fn MergeUnions(comptime First: type, comptime Second: type) type { | |
comptime { | |
var fields = @typeInfo(First).Union.fields ++ @typeInfo(Second).Union.fields; | |
var decls: [0]std.builtin.Type.Declaration = undefined; | |
return @Type(.{ .Union = .{ | |
.layout = std.builtin.Type.ContainerLayout.Auto, | |
.tag_type = RebuildTagType(fields), | |
.fields = fields, | |
.decls = &decls, | |
} }); | |
} | |
} | |
fn RebuildTagType(comptime fields: []const std.builtin.Type.UnionField) type { | |
var tag_fields: [fields.len]std.builtin.Type.EnumField = undefined; | |
for (&tag_fields, fields, 0..) |*tag_field, field, value| { | |
tag_field.* = .{ | |
.name = field.name, | |
.value = value, | |
}; | |
} | |
return @Type(.{ .Enum = .{ | |
.tag_type = std.math.IntFittingRange(0, tag_fields.len - 1), | |
.fields = &tag_fields, | |
.decls = &.{}, | |
.is_exhaustive = true, | |
} }); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment