struct Feature [src]
Fields
index: Set.Index = undefinedThe bit index into Set. Has a default value of undefined because the canonical
structures are populated via comptime logic.
name: []const u8 = undefinedHas a default value of undefined because the canonical
structures are populated via comptime logic.
llvm_name: ?[:0]const u8If this corresponds to an LLVM-recognized feature, this will be populated;
otherwise null.
description: []const u8Human-friendly UTF-8 text.
dependencies: SetSparse Set of features this depends on.
Members
- FeatureSetFns (Type Function)
- Set (struct)
Source
pub const Feature = struct {
/// The bit index into `Set`. Has a default value of `undefined` because the canonical
/// structures are populated via comptime logic.
index: Set.Index = undefined,
/// Has a default value of `undefined` because the canonical
/// structures are populated via comptime logic.
name: []const u8 = undefined,
/// If this corresponds to an LLVM-recognized feature, this will be populated;
/// otherwise null.
llvm_name: ?[:0]const u8,
/// Human-friendly UTF-8 text.
description: []const u8,
/// Sparse `Set` of features this depends on.
dependencies: Set,
/// A bit set of all the features.
pub const Set = struct {
ints: [usize_count]usize,
pub const needed_bit_count = 288;
pub const byte_count = (needed_bit_count + 7) / 8;
pub const usize_count = (byte_count + (@sizeOf(usize) - 1)) / @sizeOf(usize);
pub const Index = std.math.Log2Int(std.meta.Int(.unsigned, usize_count * @bitSizeOf(usize)));
pub const ShiftInt = std.math.Log2Int(usize);
pub const empty = Set{ .ints = [1]usize{0} ** usize_count };
pub fn isEmpty(set: Set) bool {
return for (set.ints) |x| {
if (x != 0) break false;
} else true;
}
pub fn count(set: Set) std.math.IntFittingRange(0, needed_bit_count) {
var sum: usize = 0;
for (set.ints) |x| sum += @popCount(x);
return @intCast(sum);
}
pub fn isEnabled(set: Set, arch_feature_index: Index) bool {
const usize_index = arch_feature_index / @bitSizeOf(usize);
const bit_index: ShiftInt = @intCast(arch_feature_index % @bitSizeOf(usize));
return (set.ints[usize_index] & (@as(usize, 1) << bit_index)) != 0;
}
/// Adds the specified feature but not its dependencies.
pub fn addFeature(set: *Set, arch_feature_index: Index) void {
const usize_index = arch_feature_index / @bitSizeOf(usize);
const bit_index: ShiftInt = @intCast(arch_feature_index % @bitSizeOf(usize));
set.ints[usize_index] |= @as(usize, 1) << bit_index;
}
/// Adds the specified feature set but not its dependencies.
pub fn addFeatureSet(set: *Set, other_set: Set) void {
if (builtin.zig_backend == .stage2_x86_64 and builtin.object_format == .coff) {
for (&set.ints, other_set.ints) |*set_int, other_set_int| set_int.* |= other_set_int;
} else {
set.ints = @as(@Vector(usize_count, usize), set.ints) | @as(@Vector(usize_count, usize), other_set.ints);
}
}
/// Removes the specified feature but not its dependents.
pub fn removeFeature(set: *Set, arch_feature_index: Index) void {
const usize_index = arch_feature_index / @bitSizeOf(usize);
const bit_index: ShiftInt = @intCast(arch_feature_index % @bitSizeOf(usize));
set.ints[usize_index] &= ~(@as(usize, 1) << bit_index);
}
/// Removes the specified feature but not its dependents.
pub fn removeFeatureSet(set: *Set, other_set: Set) void {
if (builtin.zig_backend == .stage2_x86_64 and builtin.object_format == .coff) {
for (&set.ints, other_set.ints) |*set_int, other_set_int| set_int.* &= ~other_set_int;
} else {
set.ints = @as(@Vector(usize_count, usize), set.ints) & ~@as(@Vector(usize_count, usize), other_set.ints);
}
}
pub fn populateDependencies(set: *Set, all_features_list: []const Cpu.Feature) void {
@setEvalBranchQuota(1000000);
var old = set.ints;
while (true) {
for (all_features_list, 0..) |feature, index_usize| {
const index: Index = @intCast(index_usize);
if (set.isEnabled(index)) {
set.addFeatureSet(feature.dependencies);
}
}
const nothing_changed = std.mem.eql(usize, &old, &set.ints);
if (nothing_changed) return;
old = set.ints;
}
}
pub fn asBytes(set: *const Set) *const [byte_count]u8 {
return std.mem.sliceAsBytes(&set.ints)[0..byte_count];
}
pub fn eql(set: Set, other_set: Set) bool {
return std.mem.eql(usize, &set.ints, &other_set.ints);
}
pub fn isSuperSetOf(set: Set, other_set: Set) bool {
if (builtin.zig_backend == .stage2_x86_64 and builtin.object_format == .coff) {
var result = true;
for (&set.ints, other_set.ints) |*set_int, other_set_int|
result = result and (set_int.* & other_set_int) == other_set_int;
return result;
} else {
const V = @Vector(usize_count, usize);
const set_v: V = set.ints;
const other_v: V = other_set.ints;
return @reduce(.And, (set_v & other_v) == other_v);
}
}
};
pub fn FeatureSetFns(comptime F: type) type {
return struct {
/// Populates only the feature bits specified.
pub fn featureSet(features: []const F) Set {
var x = Set.empty;
for (features) |feature| {
x.addFeature(@intFromEnum(feature));
}
return x;
}
/// Returns true if the specified feature is enabled.
pub fn featureSetHas(set: Set, feature: F) bool {
return set.isEnabled(@intFromEnum(feature));
}
/// Returns true if any specified feature is enabled.
pub fn featureSetHasAny(set: Set, features: anytype) bool {
inline for (features) |feature| {
if (set.isEnabled(@intFromEnum(@as(F, feature)))) return true;
}
return false;
}
/// Returns true if every specified feature is enabled.
pub fn featureSetHasAll(set: Set, features: anytype) bool {
inline for (features) |feature| {
if (!set.isEnabled(@intFromEnum(@as(F, feature)))) return false;
}
return true;
}
};
}
}