diff --git a/src-self-hosted/stage1.zig b/src-self-hosted/stage1.zig index ec683e4ba8..fc6cb18bf2 100644 --- a/src-self-hosted/stage1.zig +++ b/src-self-hosted/stage1.zig @@ -6,9 +6,12 @@ const io = std.io; const mem = std.mem; const fs = std.fs; const process = std.process; +const feature = std.target.feature; +const cpu = std.target.cpu; const Allocator = mem.Allocator; const ArrayList = std.ArrayList; const Buffer = std.Buffer; +const Target = std.Target; const self_hosted_main = @import("main.zig"); const errmsg = @import("errmsg.zig"); const DepTokenizer = @import("dep_tokenizer.zig").Tokenizer; @@ -527,3 +530,99 @@ export fn stage2_progress_update_node(node: *std.Progress.Node, done_count: usiz node.activate(); node.context.maybeRefresh(); } + +// ABI warning +export fn stage2_list_features_for_arch(arch_name_ptr: [*]const u8, arch_name_len: usize, show_subfeatures: bool) void { + print_features_for_arch(arch_name_ptr[0..arch_name_len], show_subfeatures) catch |err| { + std.debug.warn("Failed to list features: {}\n", .{ @errorName(err) }); + }; +} + +fn print_features_for_arch(arch_name: []const u8, show_subfeatures: bool) !void { + const stdout_stream = &std.io.getStdOut().outStream().stream; + + const arch = Target.parseArchTag(arch_name) catch { + std.debug.warn("Failed to parse arch '{}'\nInvoke 'zig targets' for a list of valid architectures\n", .{ arch_name }); + return; + }; + + inline for (@typeInfo(@TagType(Target.Arch)).Enum.fields) |arch_enum_field| { + if (@enumToInt(arch) == arch_enum_field.value) { + const enum_arch = @intToEnum(@TagType(Target.Arch), arch_enum_field.value); + + const feature_infos = feature.ArchFeature(enum_arch).feature_infos; + + try stdout_stream.print("Available features for {}:\n", .{ arch_enum_field.name }); + + var longest_len: usize = 0; + for (feature_infos) |feature_info| { + if (feature_info.name.len > longest_len) longest_len = feature_info.name.len; + } + + for (feature_infos) |feature_info| { + try stdout_stream.print(" {}", .{ feature_info.name }); + + var i: usize = 0; + while (i < longest_len - feature_info.name.len) : (i += 1) { + try stdout_stream.write(" "); + } + + try stdout_stream.print(" - {}\n", .{ feature_info.description }); + + if (show_subfeatures and feature_info.subfeatures.len > 0) { + for (feature_info.subfeatures) |subfeature| { + try stdout_stream.print(" {}\n", .{ subfeature.getInfo().name }); + } + } + } + } + } +} + +// ABI warning +export fn stage2_list_cpus_for_arch(arch_name_ptr: [*]const u8, arch_name_len: usize, show_subfeatures: bool) void { + print_cpus_for_arch(arch_name_ptr[0..arch_name_len], show_subfeatures) catch |err| { + std.debug.warn("Failed to list features: {}\n", .{ @errorName(err) }); + }; +} + +fn print_cpus_for_arch(arch_name: []const u8, show_subfeatures: bool) !void { + const stdout_stream = &std.io.getStdOut().outStream().stream; + + const arch = Target.parseArchTag(arch_name) catch { + std.debug.warn("Failed to parse arch '{}'\nInvoke 'zig targets' for a list of valid architectures\n", .{ arch_name }); + return; + }; + + inline for (@typeInfo(@TagType(Target.Arch)).Enum.fields) |arch_enum_field| { + if (@enumToInt(arch) == arch_enum_field.value) { + const enum_arch = @intToEnum(@TagType(Target.Arch), arch_enum_field.value); + + const cpu_infos = cpu.ArchCpu(enum_arch).cpu_infos; + + try stdout_stream.print("Available cpus for {}:\n", .{ arch_enum_field.name }); + + var longest_len: usize = 0; + for (cpu_infos) |cpu_info| { + if (cpu_info.name.len > longest_len) longest_len = cpu_info.name.len; + } + + for (cpu_infos) |cpu_info| { + try stdout_stream.print(" {}", .{ cpu_info.name }); + + var i: usize = 0; + while (i < longest_len - cpu_info.name.len) : (i += 1) { + try stdout_stream.write(" "); + } + + try stdout_stream.write("\n"); + + if (show_subfeatures and cpu_info.features.len > 0) { + for (cpu_info.features) |subfeature| { + try stdout_stream.print(" {}\n", .{ subfeature.getInfo().name }); + } + } + } + } + } +} diff --git a/src/main.cpp b/src/main.cpp index d89ac352a5..5c0a0b23fc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -129,6 +129,11 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) { " --test-name-prefix [text] add prefix to all tests\n" " --test-cmd [arg] specify test execution command one arg at a time\n" " --test-cmd-bin appends test binary path to test cmd args\n" + "\n" + "Targets Options:\n" + " --list-features [arch] list available features for the given architecture\n" + " --list-cpus [arch] list available cpus for the given architecture\n" + " --show-subfeatures list subfeatures for each entry from --list-features or --list-cpus\n" , arg0); return return_code; } @@ -529,6 +534,10 @@ int main(int argc, char **argv) { WantCSanitize want_sanitize_c = WantCSanitizeAuto; bool function_sections = false; + const char *targets_list_features_arch = nullptr; + const char *targets_list_cpus_arch = nullptr; + bool targets_show_subfeatures = false; + ZigList llvm_argv = {0}; llvm_argv.append("zig (LLVM option parsing)"); @@ -779,6 +788,8 @@ int main(int argc, char **argv) { cur_pkg = cur_pkg->parent; } else if (strcmp(arg, "-ffunction-sections") == 0) { function_sections = true; + } else if (strcmp(arg, "--show-subfeatures") == 0) { + targets_show_subfeatures = true; } else if (i + 1 >= argc) { fprintf(stderr, "Expected another argument after %s\n", arg); return print_error_usage(arg0); @@ -936,7 +947,11 @@ int main(int argc, char **argv) { , argv[i]); return EXIT_FAILURE; } - } else { + } else if (strcmp(arg, "--list-features") == 0) { + targets_list_features_arch = argv[i]; + } else if (strcmp(arg, "--list-cpus") == 0) { + targets_list_cpus_arch = argv[i]; + }else { fprintf(stderr, "Invalid argument: %s\n", arg); return print_error_usage(arg0); } @@ -1413,7 +1428,21 @@ int main(int argc, char **argv) { return main_exit(root_progress_node, EXIT_SUCCESS); } case CmdTargets: - return print_target_list(stdout); + if (targets_list_features_arch != nullptr) { + stage2_list_features_for_arch( + targets_list_features_arch, + strlen(targets_list_features_arch), + targets_show_subfeatures); + return 0; + } else if (targets_list_cpus_arch != nullptr) { + stage2_list_cpus_for_arch( + targets_list_cpus_arch, + strlen(targets_list_cpus_arch), + targets_show_subfeatures); + return 0; + } else { + return print_target_list(stdout); + } case CmdNone: return print_full_usage(arg0, stderr, EXIT_FAILURE); } diff --git a/src/userland.cpp b/src/userland.cpp index 263ef0cbc3..87ef99c03a 100644 --- a/src/userland.cpp +++ b/src/userland.cpp @@ -88,3 +88,6 @@ void stage2_progress_end(Stage2ProgressNode *node) {} void stage2_progress_complete_one(Stage2ProgressNode *node) {} void stage2_progress_disable_tty(Stage2Progress *progress) {} void stage2_progress_update_node(Stage2ProgressNode *node, size_t completed_count, size_t estimated_total_items){} + +void stage2_list_features_for_arch(const char *arch_name_ptr, size_t arch_name_len, bool show_subfeatures) {} +void stage2_list_cpus_for_arch(const char *arch_name_ptr, size_t arch_name_len, bool show_subfeatures) {} diff --git a/src/userland.h b/src/userland.h index fe3f072ae5..c85684cb36 100644 --- a/src/userland.h +++ b/src/userland.h @@ -174,4 +174,10 @@ ZIG_EXTERN_C void stage2_progress_complete_one(Stage2ProgressNode *node); ZIG_EXTERN_C void stage2_progress_update_node(Stage2ProgressNode *node, size_t completed_count, size_t estimated_total_items); +// ABI warning +ZIG_EXTERN_C void stage2_list_features_for_arch(const char *arch_name_ptr, size_t arch_name_len, bool show_subfeatures); + +// ABI warning +ZIG_EXTERN_C void stage2_list_cpus_for_arch(const char *arch_name_ptr, size_t arch_name_len, bool show_subfeatures); + #endif