Skip to content

Commit 4874b0d

Browse files
gbaraldiclaude
andcommitted
processor: fix multi-target matching + validate CPU targets at startup
- sysimg_init_cb: resolve only the first target from the cpu_target string (matching old behavior). "native" detects the host; explicit names like "haswell" use those features for matching. - jl_cpu_has_fma: check JIT target features, not host features - Add jl_check_cpu_target() called from init.c to validate the CPU target before sysimage loading: errors on unknown CPU names, multiple targets without --output-o, and clone_all without --output-o - Restore --cpu-target=help support via tp::print_cpu_targets() Update cpufeatures pin to c64dc9b which excludes ermsb/fsrm from hw_feature_mask and adds print_cpu_targets(). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent d99cf3d commit 4874b0d

File tree

5 files changed

+66
-25
lines changed

5 files changed

+66
-25
lines changed

deps/cpufeatures.version

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33
## source build
44
CPUFEATURES_VER := 0.2.0
55
CPUFEATURES_GIT_URL := https://github.com/gbaraldi/cpufeatures.git
6-
CPUFEATURES_TAR_URL := https://github.com/gbaraldi/cpufeatures/archive/09a9c883543ce23c06092a9a473ed76f873bd905.tar.gz
7-
CPUFEATURES_SHA := 09a9c883543ce23c06092a9a473ed76f873bd905
6+
CPUFEATURES_TAR_URL := https://github.com/gbaraldi/cpufeatures/archive/0fe7177edcd99a83c6e33b5ce4672079cfbac75c.tar.gz
7+
CPUFEATURES_SHA := 0fe7177edcd99a83c6e33b5ce4672079cfbac75c

src/init.c

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -585,14 +585,8 @@ static NOINLINE void _finish_jl_init_(jl_image_buf_t sysimage, jl_ptls_t ptls, j
585585
if (jl_options.cpu_target[0] == '\0')
586586
jl_error("Invalid target option: empty CPU name");
587587

588-
// When not generating output, multiple targets and clone_all are not allowed
589-
if (!jl_generating_output()) {
590-
if (strchr(jl_options.cpu_target, ';') != NULL) {
591-
jl_safe_printf("More than one command line CPU targets specified "
592-
"without a `--output-` flag specified");
593-
exit(1);
594-
}
595-
}
588+
// Validate CPU target: check for unknown names, multiple targets, clone_all
589+
jl_check_cpu_target(jl_options.cpu_target, jl_generating_output());
596590

597591
// Parse image, perform relocations, and init JIT targets, etc.
598592
jl_image_t parsed_image = jl_init_processor_sysimg(sysimage, jl_options.cpu_target);

src/processor.cpp

Lines changed: 54 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -374,19 +374,6 @@ static void ensure_jit_target(const char *cpu_target, bool imaging)
374374
if (specs.empty())
375375
jl_error("No targets specified");
376376

377-
if (!imaging) {
378-
if (specs.size() > 1) {
379-
jl_safe_printf("More than one command line CPU targets specified "
380-
"without a `--output-` flag specified");
381-
exit(1);
382-
}
383-
if (specs[0].flags & tp::TF_CLONE_ALL) {
384-
jl_safe_printf("\"clone_all\" feature specified "
385-
"without a `--output-` flag specified");
386-
exit(1);
387-
}
388-
}
389-
390377
// Set clone flags from feature diffs
391378
for (size_t i = 1; i < specs.size(); i++) {
392379
if (specs[i].flags & tp::TF_CLONE_ALL) {
@@ -414,9 +401,20 @@ static uint32_t sysimg_init_cb(void *ctx, const void *id, jl_value_t **rejection
414401
CF_DEBUG("[cpufeatures] sysimg_init_cb: cpu_target='%s'\n",
415402
cpu_target ? cpu_target : "(null)");
416403

417-
// Resolve JIT target against host
404+
// Resolve the first target from the cpu_target string.
405+
// "native" expands to the detected host CPU. For multi-target strings
406+
// (sysimage building), only the first target is used for matching.
418407
auto target_str = expand_cpu_target(cpu_target);
419-
auto host_specs = tp::resolve_targets_for_llvm(target_str);
408+
std::string first_target;
409+
auto semi = target_str.find(';');
410+
if (semi != std::string::npos)
411+
first_target = target_str.substr(0, semi);
412+
else
413+
first_target = target_str;
414+
if (first_target.empty())
415+
first_target = "native";
416+
417+
auto host_specs = tp::resolve_targets_for_llvm(first_target);
420418
if (host_specs.empty())
421419
jl_error("No targets specified");
422420

@@ -611,6 +609,47 @@ JL_DLLEXPORT jl_value_t *jl_cpu_has_fma(int bits)
611609
return jl_false;
612610
}
613611

612+
// Validate cpu_target string before any processing.
613+
// Called from init.c early in startup.
614+
extern "C" JL_DLLEXPORT void jl_check_cpu_target(const char *cpu_target, int imaging)
615+
{
616+
init_feature_names();
617+
if (!cpu_target || !*cpu_target)
618+
return; // NULL/empty handled elsewhere
619+
620+
auto target_str = expand_cpu_target(cpu_target);
621+
if (target_str.empty())
622+
return;
623+
624+
// Handle "help": print available CPU targets and exit
625+
if (target_str == "help" || target_str.find(",help") != std::string::npos) {
626+
tp::print_cpu_targets();
627+
exit(0);
628+
}
629+
630+
auto specs = tp::resolve_targets_for_llvm(target_str);
631+
632+
for (auto &s : specs) {
633+
if (s.flags & tp::TF_UNKNOWN_NAME) {
634+
jl_safe_printf("Unknown cpu target: \"%s\"\n", s.cpu_name.c_str());
635+
exit(1);
636+
}
637+
}
638+
639+
if (!imaging) {
640+
if (specs.size() > 1) {
641+
jl_safe_printf("More than one command line CPU targets specified "
642+
"without a `--output-` flag specified");
643+
exit(1);
644+
}
645+
if (!specs.empty() && (specs[0].flags & tp::TF_CLONE_ALL)) {
646+
jl_safe_printf("\"clone_all\" feature specified "
647+
"without a `--output-` flag specified");
648+
exit(1);
649+
}
650+
}
651+
}
652+
614653
jl_image_t jl_init_processor_sysimg(jl_image_buf_t image, const char *cpu_target)
615654
{
616655
init_feature_names();

src/processor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ typedef struct {
199199
*
200200
* Return the data about the function pointers selected.
201201
*/
202+
void jl_check_cpu_target(const char *cpu_target, int imaging);
202203
jl_image_t jl_init_processor_sysimg(jl_image_buf_t image, const char *cpu_target);
203204
jl_image_t jl_init_processor_pkgimg(jl_image_buf_t image);
204205

test/cmdlineargs.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,13 @@ end
197197
wait(p)
198198
@test p.exitcode == 1
199199
@test occursin("empty CPU name", String(take!(io)))
200+
201+
# Test --cpu-target=help prints available targets and exits cleanly
202+
let v = readchomperrors(`$(Base.julia_cmd(; cpu_target="help"))`)
203+
@test v[1] == true # exits with 0
204+
@test occursin("Available CPU targets:", v[2])
205+
@test occursin("Host CPU:", v[2])
206+
end
200207
end
201208

202209
let exename = `$(Base.julia_cmd()) --startup-file=no --color=no`

0 commit comments

Comments
 (0)