| ... | @@ -228,30 +228,40 @@ pub const Target = union(enum) { | ... | @@ -228,30 +228,40 @@ pub const Target = union(enum) { |
| 228 | | 228 | |
| 229 | var it = mem.tokenize(features_text, ","); | 229 | var it = mem.tokenize(features_text, ","); |
| 230 | while (it.next()) |item_text| { | 230 | while (it.next()) |item_text| { |
| 231 | const feature_name = blk: { | 231 | var feature_name: []const u8 = undefined; |
| 232 | if (mem.startsWith(u8, item_text, "+")) { | 232 | var op: enum { |
| 233 | switch (mode) { | 233 | add, |
| 234 | .unknown, .baseline => mode = .baseline, | 234 | sub, |
| 235 | .whitelist => return error.InvalidCpuFeatures, | 235 | } = undefined; |
| 236 | } | 236 | if (mem.startsWith(u8, item_text, "+")) { |
| 237 | break :blk item_text[1..]; | 237 | switch (mode) { |
| 238 | } else if (mem.startsWith(u8, item_text, "-")) { | 238 | .unknown, .baseline => mode = .baseline, |
| 239 | switch (mode) { | 239 | .whitelist => return error.InvalidCpuFeatures, |
| 240 | .unknown, .baseline => mode = .baseline, | | |
| 241 | .whitelist => return error.InvalidCpuFeatures, | | |
| 242 | } | | |
| 243 | break :blk item_text[1..]; | | |
| 244 | } else { | | |
| 245 | switch (mode) { | | |
| 246 | .unknown, .whitelist => mode = .whitelist, | | |
| 247 | .baseline => return error.InvalidCpuFeatures, | | |
| 248 | } | | |
| 249 | break :blk item_text; | | |
| 250 | } | 240 | } |
| 251 | }; | 241 | op = .add; |
| | 242 | feature_name = item_text[1..]; |
| | 243 | } else if (mem.startsWith(u8, item_text, "-")) { |
| | 244 | switch (mode) { |
| | 245 | .unknown, .baseline => mode = .baseline, |
| | 246 | .whitelist => return error.InvalidCpuFeatures, |
| | 247 | } |
| | 248 | op = .sub; |
| | 249 | feature_name = item_text[1..]; |
| | 250 | } else { |
| | 251 | switch (mode) { |
| | 252 | .unknown, .whitelist => mode = .whitelist, |
| | 253 | .baseline => return error.InvalidCpuFeatures, |
| | 254 | } |
| | 255 | op = .add; |
| | 256 | feature_name = item_text; |
| | 257 | } |
| 252 | for (arch.allFeaturesList()) |feature, index| { | 258 | for (arch.allFeaturesList()) |feature, index| { |
| 253 | if (mem.eql(u8, feature_name, feature.name)) { | 259 | if (mem.eql(u8, feature_name, feature.name)) { |
| 254 | set |= @splat(2, @as(Cpu.Feature.Set, 1) << @intCast(u7, index)); | 260 | const one_bit = @as(Cpu.Feature.Set, 1) << @intCast(u7, index); |
| | 261 | switch (op) { |
| | 262 | .add => set |= @splat(2, one_bit), |
| | 263 | .sub => set &= @splat(2, ~one_bit), |
| | 264 | } |
| 255 | break; | 265 | break; |
| 256 | } | 266 | } |
| 257 | } else { | 267 | } else { |
| ... | @@ -1050,3 +1060,13 @@ pub const Target = union(enum) { | ... | @@ -1050,3 +1060,13 @@ pub const Target = union(enum) { |
| 1050 | return .unavailable; | 1060 | return .unavailable; |
| 1051 | } | 1061 | } |
| 1052 | }; | 1062 | }; |
| | 1063 | |
| | 1064 | test "parseCpuFeatureSet" { |
| | 1065 | const set = try @as(Target.Arch, .x86_64).parseCpuFeatureSet("-sse,-avx,-cx8"); |
| | 1066 | std.testing.expect(!Target.x86.featureSetHas(set, .sse)); |
| | 1067 | std.testing.expect(!Target.x86.featureSetHas(set, .avx)); |
| | 1068 | std.testing.expect(!Target.x86.featureSetHas(set, .cx8)); |
| | 1069 | // These are expected because they are part of the baseline |
| | 1070 | std.testing.expect(Target.x86.featureSetHas(set, .cmov)); |
| | 1071 | std.testing.expect(Target.x86.featureSetHas(set, .fxsr)); |
| | 1072 | } |