https://github.com/pvelesko updated 
https://github.com/llvm/llvm-project/pull/206902

>From 3973d6b66a239d6d5bee5f751dcb3fe1d3a0e3db Mon Sep 17 00:00:00 2001
From: Paulius Velesko <[email protected]>
Date: Tue, 30 Jun 2026 12:59:25 +0300
Subject: [PATCH 1/4] [Darwin] Add regression test for HIP-SPIR-V offload
 version-init crash

HIP-SPIR-V offloading to a Darwin host whose triple carries a Darwin
kernel version (e.g. `--target=arm64-apple-darwin24.3.0`) crashes the
driver: ensureTargetInitialized() records the kernel version (24.x) via
setTarget(), then AddDeploymentTarget() calls setTarget() again with the
macOS product version (15.x); the version mismatch trips the
"Target already initialized!" assertion.

This test fails (clang aborts) on the current behavior and is fixed by
the following commit.
---
 .../test/Driver/darwin-hip-spirv-version.hip  | 21 +++++++++++++++++++
 1 file changed, 21 insertions(+)
 create mode 100644 clang/test/Driver/darwin-hip-spirv-version.hip

diff --git a/clang/test/Driver/darwin-hip-spirv-version.hip 
b/clang/test/Driver/darwin-hip-spirv-version.hip
new file mode 100644
index 0000000000000..7e1ff20e7d662
--- /dev/null
+++ b/clang/test/Driver/darwin-hip-spirv-version.hip
@@ -0,0 +1,21 @@
+// Regression test: HIP-SPIR-V offloading to a Darwin host whose triple carries
+// a Darwin *kernel* version (e.g. darwin24.3.0) must not crash the driver.
+//
+// The HIP-SPIR-V offload path calls Darwin::ensureTargetInitialized() early.
+// It records the deployment version via setTarget(); the later host job calls
+// setTarget() again from AddDeploymentTarget(). setTarget()'s reinit guard 
only
+// short-circuits when the two versions match. ensureTargetInitialized() must
+// therefore record the converted macOS *product* version (15.x) rather than 
the
+// raw Darwin *kernel* version (24.x); otherwise the second call mismatches and
+// trips the "Target already initialized!" assertion.
+
+// REQUIRES: spirv-registered-target
+// UNSUPPORTED: system-windows, system-cygwin
+
+// RUN: %clang -### -x hip --offload=spirv64 --target=arm64-apple-darwin24.3.0 
\
+// RUN:   -nogpulib -nogpuinc %s 2>&1 | FileCheck %s
+
+// The Darwin host -cc1 job uses the converted macOS product version, and the
+// driver does not assert/crash.
+// CHECK: "-triple" "arm64-apple-macosx{{[0-9.]+}}"
+// CHECK-NOT: "-triple" "arm64-apple-darwin

>From 56fc4ab25aedb8b5085b2ea5887d3b9900f5f2f8 Mon Sep 17 00:00:00 2001
From: Paulius Velesko <[email protected]>
Date: Wed, 1 Jul 2026 12:02:44 +0300
Subject: [PATCH 2/4] [Darwin] Use macOS product version in
 ensureTargetInitialized

Darwin::ensureTargetInitialized() (the lazy target-init helper used by
the HIP-SPIR-V offload toolchain) passed setTarget() the raw triple OS
version from getOSVersion(). On macOS that is the Darwin *kernel* version
(e.g. 24.3.0), not the macOS *product* version (e.g. 15.0.0).

When clang later builds the offload host job, AddDeploymentTarget() calls
setTarget() again with the product version. setTarget()'s reinit guard
only short-circuits when the versions match; 24.3.0 != 15.0.0, so it
falls through to assert(!TargetInitialized) and clang aborts on every
'-x hip --offload=spirv64* --target=arm64-apple-darwin' compile.

Convert macOS kernel versions via getMacOSXVersion() so the lazy init
records the same version AddDeploymentTarget() later uses.
---
 clang/lib/Driver/ToolChains/Darwin.cpp | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp 
b/clang/lib/Driver/ToolChains/Darwin.cpp
index 64bc96a900f30..de62a7c8ee9c2 100644
--- a/clang/lib/Driver/ToolChains/Darwin.cpp
+++ b/clang/lib/Driver/ToolChains/Darwin.cpp
@@ -1210,7 +1210,18 @@ void Darwin::ensureTargetInitialized() const {
   else if (getTriple().isMacCatalystEnvironment())
     Environment = MacCatalyst;
 
-  VersionTuple OsVer = getTriple().getOSVersion();
+  VersionTuple OsVer;
+  if (Platform == MacOS) {
+    // Convert a Darwin kernel version (e.g. darwin24.3.0) to the macOS product
+    // version (e.g. 15.0.0). The raw getOSVersion() returns the kernel 
version,
+    // which mismatches the macOS version that AddDeploymentTarget() later
+    // passes to setTarget(), tripping its "Target already initialized!"
+    // assertion on the HIP-SPIR-V offload path.
+    if (!getTriple().getMacOSXVersion(OsVer))
+      return;
+  } else {
+    OsVer = getTriple().getOSVersion();
+  }
   setTarget(Platform, Environment, OsVer.getMajor(),
             OsVer.getMinor().value_or(0), OsVer.getSubminor().value_or(0),
             VersionTuple());

>From a61ef01d8f114e2ec34baf280ebd97c6a615f259 Mon Sep 17 00:00:00 2001
From: Paulius Velesko <[email protected]>
Date: Thu, 9 Jul 2026 15:03:31 +0300
Subject: [PATCH 3/4] [Darwin] Tighten ensureTargetInitialized comment and
 version test

Reword the version-conversion comment to state the invariant rather than
the bug history, and pin the expected product version (macosx15) in the
regression test so it verifies the darwin24->macosx15 mapping, not just
the triple spelling.
---
 clang/lib/Driver/ToolChains/Darwin.cpp         |  8 +++-----
 clang/test/Driver/darwin-hip-spirv-version.hip | 14 ++++----------
 2 files changed, 7 insertions(+), 15 deletions(-)

diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp 
b/clang/lib/Driver/ToolChains/Darwin.cpp
index de62a7c8ee9c2..934325a37bc0c 100644
--- a/clang/lib/Driver/ToolChains/Darwin.cpp
+++ b/clang/lib/Driver/ToolChains/Darwin.cpp
@@ -1212,11 +1212,9 @@ void Darwin::ensureTargetInitialized() const {
 
   VersionTuple OsVer;
   if (Platform == MacOS) {
-    // Convert a Darwin kernel version (e.g. darwin24.3.0) to the macOS product
-    // version (e.g. 15.0.0). The raw getOSVersion() returns the kernel 
version,
-    // which mismatches the macOS version that AddDeploymentTarget() later
-    // passes to setTarget(), tripping its "Target already initialized!"
-    // assertion on the HIP-SPIR-V offload path.
+    // Record the macOS product version (e.g. macosx15), not the Darwin kernel
+    // version (e.g. darwin24.3): version checks against the lazily-recorded
+    // target must behave as if AddDeploymentTarget() had computed it.
     if (!getTriple().getMacOSXVersion(OsVer))
       return;
   } else {
diff --git a/clang/test/Driver/darwin-hip-spirv-version.hip 
b/clang/test/Driver/darwin-hip-spirv-version.hip
index 7e1ff20e7d662..299fff5d08083 100644
--- a/clang/test/Driver/darwin-hip-spirv-version.hip
+++ b/clang/test/Driver/darwin-hip-spirv-version.hip
@@ -1,13 +1,7 @@
 // Regression test: HIP-SPIR-V offloading to a Darwin host whose triple carries
-// a Darwin *kernel* version (e.g. darwin24.3.0) must not crash the driver.
-//
-// The HIP-SPIR-V offload path calls Darwin::ensureTargetInitialized() early.
-// It records the deployment version via setTarget(); the later host job calls
-// setTarget() again from AddDeploymentTarget(). setTarget()'s reinit guard 
only
-// short-circuits when the two versions match. ensureTargetInitialized() must
-// therefore record the converted macOS *product* version (15.x) rather than 
the
-// raw Darwin *kernel* version (24.x); otherwise the second call mismatches and
-// trips the "Target already initialized!" assertion.
+// a Darwin *kernel* version (e.g. darwin24.3.0) must not crash the driver:
+// ensureTargetInitialized() must record the macOS *product* version that
+// AddDeploymentTarget() later derives, or setTarget()'s reinit guard asserts.
 
 // REQUIRES: spirv-registered-target
 // UNSUPPORTED: system-windows, system-cygwin
@@ -17,5 +11,5 @@
 
 // The Darwin host -cc1 job uses the converted macOS product version, and the
 // driver does not assert/crash.
-// CHECK: "-triple" "arm64-apple-macosx{{[0-9.]+}}"
+// CHECK: "-triple" "arm64-apple-macosx15{{[0-9.]*}}"
 // CHECK-NOT: "-triple" "arm64-apple-darwin

>From a0faa08eb7ebd76f77c334dc9c718352d000d0b1 Mon Sep 17 00:00:00 2001
From: Paulius Velesko <[email protected]>
Date: Thu, 9 Jul 2026 15:03:45 +0300
Subject: [PATCH 4/4] [Darwin] Let AddDeploymentTarget overwrite a
 lazily-initialized target

ensureTargetInitialized() can only guess the deployment target from the
triple, but AddDeploymentTarget() may derive a different version from
-mmacosx-version-min, MACOSX_DEPLOYMENT_TARGET, the SDK, or the host
system. Any such difference still tripped setTarget()'s "Target already
initialized!" assertion on the offload path. Track lazy initialization
and let the authoritative setTarget() call overwrite it.
---
 clang/lib/Driver/ToolChains/Darwin.cpp        |  4 +++
 clang/lib/Driver/ToolChains/Darwin.h          | 16 ++++++++--
 .../test/Driver/darwin-hip-spirv-version.hip  | 32 +++++++++++++++----
 3 files changed, 43 insertions(+), 9 deletions(-)

diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp 
b/clang/lib/Driver/ToolChains/Darwin.cpp
index 934325a37bc0c..0f5635827b84f 100644
--- a/clang/lib/Driver/ToolChains/Darwin.cpp
+++ b/clang/lib/Driver/ToolChains/Darwin.cpp
@@ -1223,6 +1223,10 @@ void Darwin::ensureTargetInitialized() const {
   setTarget(Platform, Environment, OsVer.getMajor(),
             OsVer.getMinor().value_or(0), OsVer.getSubminor().value_or(0),
             VersionTuple());
+  // The version above is a guess from the triple alone; AddDeploymentTarget()
+  // may later derive a different deployment target from flags, environment
+  // variables, or the SDK, and overwrite this initialization.
+  TargetInitializedLazily = true;
 }
 
 AppleMachO::~AppleMachO() {}
diff --git a/clang/lib/Driver/ToolChains/Darwin.h 
b/clang/lib/Driver/ToolChains/Darwin.h
index 97520a89d8042..c41bb6c2eead5 100644
--- a/clang/lib/Driver/ToolChains/Darwin.h
+++ b/clang/lib/Driver/ToolChains/Darwin.h
@@ -355,6 +355,11 @@ class LLVM_LIBRARY_VISIBILITY Darwin : public AppleMachO {
   // the argument translation business.
   mutable bool TargetInitialized;
 
+  /// Whether the target was lazily initialized from the triple by
+  /// ensureTargetInitialized() rather than by AddDeploymentTarget(). Such a
+  /// target is a best-effort guess that setTarget() may overwrite.
+  mutable bool TargetInitializedLazily = false;
+
   // TODO: Are these useful? Can we use Triple::OSType/EnvironmentType instead?
   enum DarwinPlatformKind {
     MacOS,
@@ -447,10 +452,17 @@ class LLVM_LIBRARY_VISIBILITY Darwin : public AppleMachO {
     if (TargetInitialized && TargetPlatform == Platform &&
         TargetEnvironment == Environment &&
         (Environment == MacCatalyst ? OSTargetVersion : TargetVersion) ==
-            VersionTuple(Major, Minor, Micro))
+            VersionTuple(Major, Minor, Micro)) {
+      TargetInitializedLazily = false;
       return;
+    }
 
-    assert(!TargetInitialized && "Target already initialized!");
+    // A lazily-initialized target (see ensureTargetInitialized()) is a
+    // best-effort guess from the triple alone; the authoritative
+    // initialization from AddDeploymentTarget() may overwrite it.
+    assert((!TargetInitialized || TargetInitializedLazily) &&
+           "Target already initialized!");
+    TargetInitializedLazily = false;
     TargetInitialized = true;
     TargetPlatform = Platform;
     TargetEnvironment = Environment;
diff --git a/clang/test/Driver/darwin-hip-spirv-version.hip 
b/clang/test/Driver/darwin-hip-spirv-version.hip
index 299fff5d08083..754c7a1d079d6 100644
--- a/clang/test/Driver/darwin-hip-spirv-version.hip
+++ b/clang/test/Driver/darwin-hip-spirv-version.hip
@@ -1,15 +1,33 @@
-// Regression test: HIP-SPIR-V offloading to a Darwin host whose triple carries
-// a Darwin *kernel* version (e.g. darwin24.3.0) must not crash the driver:
-// ensureTargetInitialized() must record the macOS *product* version that
-// AddDeploymentTarget() later derives, or setTarget()'s reinit guard asserts.
+// The HIP-SPIR-V offload path lazily initializes the Darwin host target from
+// the triple (ensureTargetInitialized) before AddDeploymentTarget() computes
+// the authoritative deployment target; a disagreement between the two used to
+// trip setTarget()'s "Target already initialized!" assertion.
 
 // REQUIRES: spirv-registered-target
 // UNSUPPORTED: system-windows, system-cygwin
 
+// A Darwin *kernel* version in the triple (darwin24.3.0) is recorded as the
+// macOS *product* version (macosx15) and the driver does not crash.
 // RUN: %clang -### -x hip --offload=spirv64 --target=arm64-apple-darwin24.3.0 
\
 // RUN:   -nogpulib -nogpuinc %s 2>&1 | FileCheck %s
-
-// The Darwin host -cc1 job uses the converted macOS product version, and the
-// driver does not assert/crash.
 // CHECK: "-triple" "arm64-apple-macosx15{{[0-9.]*}}"
 // CHECK-NOT: "-triple" "arm64-apple-darwin
+
+// A deployment target from the environment overrides the lazily-recorded
+// triple version instead of asserting.
+// RUN: env MACOSX_DEPLOYMENT_TARGET=14.0 %clang -### -x hip \
+// RUN:   --offload=spirv64 --target=arm64-apple-darwin24.3.0 \
+// RUN:   -nogpulib -nogpuinc %s 2>&1 | FileCheck --check-prefix=DEPLOY %s
+// DEPLOY: "-triple" "arm64-apple-macosx14.0.0"
+
+// Same for -mmacosx-version-min.
+// RUN: %clang -### -x hip --offload=spirv64 --target=arm64-apple-darwin24.3.0 
\
+// RUN:   -mmacosx-version-min=14.0 -nogpulib -nogpuinc %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=VERMIN %s
+// VERMIN: "-triple" "arm64-apple-macosx14.0.0"
+
+// An unversioned triple must not crash either; the version is inferred (and
+// on a macOS host may differ from the lazily-recorded default).
+// RUN: %clang -### -x hip --offload=spirv64 --target=arm64-apple-darwin \
+// RUN:   -nogpulib -nogpuinc %s 2>&1 | FileCheck --check-prefix=NOVER %s
+// NOVER: "-triple" "arm64-apple-macosx{{[0-9.]+}}"

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to