[clang] [clang] Diagnose host/device pointer related type mismatches (PR #215620)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Sep 30 03:28:48 PDT 2026
https://github.com/schittir updated https://github.com/llvm/llvm-project/pull/215620
>From e465e699bacb7e0be98902a68a7c53c04270f32f Mon Sep 17 00:00:00 2001
From: Sindhu Chittireddy <sindhu.chittireddy at intel.com>
Date: Tue, 11 Aug 2026 10:05:44 -0700
Subject: [PATCH 1/8] [clang] Diagnose host/device pointer width mismatches in
offload compilations
SPIR, physical SPIR-V, and NVPTX device targets take their pointer
related types from the host target, so a host whose pointer width
differs from the device's leaves size_t, ptrdiff_t, and intptr_t
inconsistent with the device data layout. Such pairings were previously
accepted and silently miscompiled.
This patch diagnoses these invalid combinations by calling the
diagnostic at:
1. Driver::CreateOffloadingDeviceToolChains(), covering --offload=,
--offload-targets=, and -fsycl.
2. TargetInfo::CreateTargetInfo(), covering -cc1 -triple X -aux-triple Y
and anything else that bypasses the driver.
This is the follow-up to #208196, as discussed during review.
---
clang/docs/ReleaseNotes.md | 6 +++
.../clang/Basic/DiagnosticCommonKinds.td | 3 ++
clang/lib/Basic/Targets.cpp | 24 +++++++++
clang/lib/Basic/Targets/SPIR.h | 50 +++++++++++--------
clang/lib/Driver/Driver.cpp | 16 ++++++
clang/test/CodeGenCUDA/anon-ns.cu | 4 +-
clang/test/CodeGenCUDA/long-double.cu | 2 +-
.../CodeGenCUDASPIRV/copy-aggregate-byval.cu | 4 +-
.../test/CodeGenCUDASPIRV/kernel-argument.cu | 4 +-
.../CodeGenSYCL/kernel-caller-entry-point.cpp | 9 ----
clang/test/Driver/cuda-device-triple.cu | 2 +-
clang/test/Frontend/sycl-aux-triple.cpp | 4 +-
clang/test/SemaCUDA/allow-int128.cu | 2 +-
.../SemaCUDA/cuda-inherits-calling-conv.cu | 2 +-
...v-implicit-alloc-function-calling-conv.hip | 2 -
15 files changed, 91 insertions(+), 43 deletions(-)
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 2f13ec59483ee4..d1651cdb925815 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -51,6 +51,12 @@ The previous behavior can be restored with `-Wno-error=unicode-whitespace`.
Clang will stop accepting non-ascii whitespaces as token separators
in a future version of Clang.
+- Offload compilations that pair a SPIR, physical SPIR-V, or NVPTX device target
+ with a host of a different pointer width are now rejected, for example
+ `--offload=spirv32` with an `x86_64` host. These targets take `size_t`,
+ `ptrdiff_t`, and `intptr_t` from the host, so a mismatch disagreed with the
+ device data layout. Select a device target whose width matches the host's.
+
### C++ Specific Potentially Breaking Changes
### ABI Changes in This Version
diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td
index 192fdf9299eb44..ece27b02f840ee 100644
--- a/clang/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td
@@ -338,6 +338,9 @@ def err_target_unknown_cpu : Error<"unknown target CPU '%0'">;
def note_valid_options : Note<"valid target CPU values are: %0">;
def err_target_unsupported_cpu_for_micromips : Error<
"micromips is not supported for target CPU '%0'">;
+def err_target_unsupported_host_device_pointer_width : Error<
+ "device target '%0' with %1-bit pointers is incompatible with host target "
+ "'%2' with %3-bit pointers">;
def err_target_unknown_abi : Error<"unknown target ABI '%0'">;
def err_target_unsupported_abi : Error<"ABI '%0' is not supported on CPU '%1'">;
def err_target_unsupported_abi_for_triple : Error<
diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp
index 8c01cfca8ccb48..a939eb9b944707 100644
--- a/clang/lib/Basic/Targets.cpp
+++ b/clang/lib/Basic/Targets.cpp
@@ -835,6 +835,15 @@ std::unique_ptr<TargetInfo> AllocateTarget(const llvm::Triple &Triple,
} // namespace clang
using namespace clang::targets;
+
+/// Returns true if Triple names a target that takes its pointer related types
+/// from a host target. Logical SPIR-V is excluded; it uses fixed values for
+/// those types regardless of the host.
+static bool adaptsToHostTarget(const llvm::Triple &Triple) {
+ return (Triple.isSPIROrSPIRV() && Triple.getArch() != llvm::Triple::spirv) ||
+ Triple.isNVPTX();
+}
+
/// CreateTargetInfo - Return the target info object for the specified target
/// options.
TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
@@ -843,6 +852,21 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
llvm::Triple Triple(llvm::Triple::normalize(Opts->Triple));
+ // Host and device pointer related type widths must match. Reject a mismatch
+ // before constructing the device target, which asserts on this.
+ if (adaptsToHostTarget(Triple) && !Opts->HostTriple.empty()) {
+ llvm::Triple HostTriple(llvm::Triple::normalize(Opts->HostTriple));
+ if (!adaptsToHostTarget(HostTriple) &&
+ HostTriple.getArch() != llvm::Triple::UnknownArch &&
+ Triple.getArchPointerBitWidth() !=
+ HostTriple.getArchPointerBitWidth()) {
+ Diags.Report(diag::err_target_unsupported_host_device_pointer_width)
+ << Triple.str() << Triple.getArchPointerBitWidth() << HostTriple.str()
+ << HostTriple.getArchPointerBitWidth();
+ return nullptr;
+ }
+ }
+
// Construct the target
std::unique_ptr<TargetInfo> Target = AllocateTarget(Triple, *Opts);
if (!Target) {
diff --git a/clang/lib/Basic/Targets/SPIR.h b/clang/lib/Basic/Targets/SPIR.h
index 20d8efdc832343..17f90e80dc5fdd 100644
--- a/clang/lib/Basic/Targets/SPIR.h
+++ b/clang/lib/Basic/Targets/SPIR.h
@@ -254,16 +254,18 @@ class LLVM_LIBRARY_VISIBILITY SPIR32TargetInfo : public SPIRTargetInfo {
: SPIRTargetInfo(Triple, Opts) {
assert(Triple.getArch() == llvm::Triple::spir &&
"Invalid architecture for 32-bit SPIR.");
- // FIXME: Assert that a present host target's pointer types match the ones
- // set below, once the driver diagnoses unsupported host/device combinations
- // (until then such an assert would fire on existing tests).
PointerWidth = PointerAlign = 32;
- const TargetInfo *HostTarget = getHostTarget();
- if (!HostTarget || HostTarget->getPointerWidth(LangAS::Default) != 32) {
+ if (!getHostTarget()) {
SizeType = TargetInfo::UnsignedInt;
PtrDiffType = IntPtrType = TargetInfo::SignedInt;
}
+ // Host and device pointer related type widths must match.
+ assert(PointerWidth == 32 && PointerAlign == 32 &&
+ getTypeWidth(SizeType) == 32 && getTypeWidth(PtrDiffType) == 32 &&
+ getTypeWidth(IntPtrType) == 32 &&
+ "Invalid pointer related types for SPIR32");
+
// SPIR32 has support for atomic ops if atomic extension is enabled.
// Take the maximum because it's possible the Host supports wider types.
MaxAtomicInlineWidth = std::max<unsigned char>(MaxAtomicInlineWidth, 64);
@@ -281,16 +283,18 @@ class LLVM_LIBRARY_VISIBILITY SPIR64TargetInfo : public SPIRTargetInfo {
: SPIRTargetInfo(Triple, Opts) {
assert(Triple.getArch() == llvm::Triple::spir64 &&
"Invalid architecture for 64-bit SPIR.");
- // FIXME: Assert that a present host target's pointer types match the ones
- // set below, once the driver diagnoses unsupported host/device combinations
- // (until then such an assert would fire on existing tests).
PointerWidth = PointerAlign = 64;
- const TargetInfo *HostTarget = getHostTarget();
- if (!HostTarget || HostTarget->getPointerWidth(LangAS::Default) != 64) {
+ if (!getHostTarget()) {
SizeType = TargetInfo::UnsignedLong;
PtrDiffType = IntPtrType = TargetInfo::SignedLong;
}
+ // Host and device pointer related type widths must match.
+ assert(PointerWidth == 64 && PointerAlign == 64 &&
+ getTypeWidth(SizeType) == 64 && getTypeWidth(PtrDiffType) == 64 &&
+ getTypeWidth(IntPtrType) == 64 &&
+ "Invalid pointer related types for SPIR64");
+
// SPIR64 has support for atomic ops if atomic extension is enabled.
// Take the maximum because it's possible the Host supports wider types.
MaxAtomicInlineWidth = std::max<unsigned char>(MaxAtomicInlineWidth, 64);
@@ -379,15 +383,18 @@ class LLVM_LIBRARY_VISIBILITY SPIRV32TargetInfo : public BaseSPIRVTargetInfo {
"32-bit SPIR-V target must use unknown, chipstar, or vulkan OS");
assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment &&
"32-bit SPIR-V target must use unknown environment type");
- // FIXME: Assert that a present host target's pointer types match the ones
- // set below, once the driver diagnoses unsupported host/device combinations
- // (until then such an assert would fire on existing tests).
PointerWidth = PointerAlign = 32;
- const TargetInfo *HostTarget = getHostTarget();
- if (!HostTarget || HostTarget->getPointerWidth(LangAS::Default) != 32) {
+ if (!getHostTarget()) {
SizeType = TargetInfo::UnsignedInt;
PtrDiffType = IntPtrType = TargetInfo::SignedInt;
}
+
+ // Host and device pointer related type widths must match.
+ assert(PointerWidth == 32 && PointerAlign == 32 &&
+ getTypeWidth(SizeType) == 32 && getTypeWidth(PtrDiffType) == 32 &&
+ getTypeWidth(IntPtrType) == 32 &&
+ "Invalid pointer related types for SPIR-V 32");
+
// SPIR-V has core support for atomic ops, and Int32 is always available;
// we take the maximum because it's possible the Host supports wider types.
MaxAtomicInlineWidth = std::max<unsigned char>(MaxAtomicInlineWidth, 64);
@@ -410,15 +417,18 @@ class LLVM_LIBRARY_VISIBILITY SPIRV64TargetInfo : public BaseSPIRVTargetInfo {
"64-bit SPIR-V target must use unknown, chipstar, or vulkan OS");
assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment &&
"64-bit SPIR-V target must use unknown environment type");
- // FIXME: Assert that a present host target's pointer types match the ones
- // set below, once the driver diagnoses unsupported host/device combinations
- // (until then such an assert would fire on existing tests).
PointerWidth = PointerAlign = 64;
- const TargetInfo *HostTarget = getHostTarget();
- if (!HostTarget || HostTarget->getPointerWidth(LangAS::Default) != 64) {
+ if (!getHostTarget()) {
SizeType = TargetInfo::UnsignedLong;
PtrDiffType = IntPtrType = TargetInfo::SignedLong;
}
+
+ // Host and device pointer related type widths must match.
+ assert(PointerWidth == 64 && PointerAlign == 64 &&
+ getTypeWidth(SizeType) == 64 && getTypeWidth(PtrDiffType) == 64 &&
+ getTypeWidth(IntPtrType) == 64 &&
+ "Invalid pointer related types for SPIR-V 64");
+
// SPIR-V has core support for atomic ops, and Int64 is always available;
// we take the maximum because it's possible the Host supports wider types.
MaxAtomicInlineWidth = std::max<unsigned char>(MaxAtomicInlineWidth, 64);
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index 3b5d0c0aad9819..cf7e49932a1a25 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -1129,6 +1129,22 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
continue;
}
+ const llvm::Triple &HostTriple = C.getDefaultToolChain().getTriple();
+ // Logical SPIR-V is excluded; it overrides those types with fixed values.
+ auto AdaptsToHostTarget = [](const llvm::Triple &T) {
+ return (T.isSPIROrSPIRV() && T.getArch() != llvm::Triple::spirv) ||
+ T.isNVPTX();
+ };
+ // Target and host pointer related type widths must match.
+ if (AdaptsToHostTarget(Target) && !AdaptsToHostTarget(HostTriple) &&
+ Target.getArchPointerBitWidth() !=
+ HostTriple.getArchPointerBitWidth()) {
+ Diag(diag::err_target_unsupported_host_device_pointer_width)
+ << Target.str() << Target.getArchPointerBitWidth()
+ << HostTriple.str() << HostTriple.getArchPointerBitWidth();
+ continue;
+ }
+
std::string NormalizedName = Target.normalize();
auto [TripleIt, Inserted] =
FoundNormalizedTriples.try_emplace(NormalizedName, Target.str());
diff --git a/clang/test/CodeGenCUDA/anon-ns.cu b/clang/test/CodeGenCUDA/anon-ns.cu
index 651a20c653458c..e2b290bd21c3d5 100644
--- a/clang/test/CodeGenCUDA/anon-ns.cu
+++ b/clang/test/CodeGenCUDA/anon-ns.cu
@@ -11,12 +11,12 @@
// RUN: echo "GPU binary" > %t.fatbin
-// RUN: %clang_cc1 -triple nvptx -fcuda-is-device -cuid=abc \
+// RUN: %clang_cc1 -triple nvptx64 -fcuda-is-device -cuid=abc \
// RUN: -aux-triple x86_64-unknown-linux-gnu -std=c++17 -fgpu-rdc \
// RUN: -emit-llvm -o - %s > %t.dev
// RUN: %clang_cc1 -triple x86_64-gnu-linux -cuid=abc \
-// RUN: -aux-triple nvptx -std=c++17 -fgpu-rdc -fcuda-include-gpubinary %t.fatbin \
+// RUN: -aux-triple nvptx64 -std=c++17 -fgpu-rdc -fcuda-include-gpubinary %t.fatbin \
// RUN: -emit-llvm -o - %s > %t.host
// RUN: cat %t.dev %t.host | FileCheck -check-prefixes=CUDA,COMMON %s
diff --git a/clang/test/CodeGenCUDA/long-double.cu b/clang/test/CodeGenCUDA/long-double.cu
index b4116c0b815944..0a06fbe5db6d07 100644
--- a/clang/test/CodeGenCUDA/long-double.cu
+++ b/clang/test/CodeGenCUDA/long-double.cu
@@ -6,7 +6,7 @@
// RUN: -aux-triple x86_64-unknown-gnu-linux -fcuda-is-device \
// RUN: -emit-llvm -o - -x hip %s 2>&1 | FileCheck %s
-// RUN: %clang_cc1 -triple nvptx \
+// RUN: %clang_cc1 -triple nvptx64 \
// RUN: -aux-triple x86_64-unknown-gnu-linux -fcuda-is-device \
// RUN: -emit-llvm -o - %s 2>&1 | FileCheck %s
diff --git a/clang/test/CodeGenCUDASPIRV/copy-aggregate-byval.cu b/clang/test/CodeGenCUDASPIRV/copy-aggregate-byval.cu
index 2692ce4c92b288..fa6521b1fa5e3f 100644
--- a/clang/test/CodeGenCUDASPIRV/copy-aggregate-byval.cu
+++ b/clang/test/CodeGenCUDASPIRV/copy-aggregate-byval.cu
@@ -2,12 +2,12 @@
// destructor, copy constructor or move constructor defined by user.
// RUN: %clang -emit-llvm --cuda-device-only --offload=spirv32 \
-// RUN: -nocudalib -nocudainc %s -o %t.bc -c 2>&1
+// RUN: --target=i386-unknown-linux-gnu -nocudalib -nocudainc %s -o %t.bc -c 2>&1
// RUN: llvm-dis %t.bc -o %t.ll
// RUN: FileCheck %s --input-file=%t.ll
// RUN: %clang -emit-llvm --cuda-device-only --offload=spirv64 \
-// RUN: -nocudalib -nocudainc %s -o %t.bc -c 2>&1
+// RUN: --target=x86_64-unknown-linux-gnu -nocudalib -nocudainc %s -o %t.bc -c 2>&1
// RUN: llvm-dis %t.bc -o %t.ll
// RUN: FileCheck %s --input-file=%t.ll
diff --git a/clang/test/CodeGenCUDASPIRV/kernel-argument.cu b/clang/test/CodeGenCUDASPIRV/kernel-argument.cu
index ab885eb3d85c4a..8ec47949d0092f 100644
--- a/clang/test/CodeGenCUDASPIRV/kernel-argument.cu
+++ b/clang/test/CodeGenCUDASPIRV/kernel-argument.cu
@@ -2,12 +2,12 @@
// RUN: %clang -emit-llvm --cuda-device-only --offload=spirv32 \
-// RUN: -nocudalib -nocudainc %s -o %t.bc -c 2>&1
+// RUN: --target=i386-unknown-linux-gnu -nocudalib -nocudainc %s -o %t.bc -c 2>&1
// RUN: llvm-dis %t.bc -o %t.ll
// RUN: FileCheck %s --input-file=%t.ll
// RUN: %clang -emit-llvm --cuda-device-only --offload=spirv64 \
-// RUN: -nocudalib -nocudainc %s -o %t.bc -c 2>&1
+// RUN: --target=x86_64-unknown-linux-gnu -nocudalib -nocudainc %s -o %t.bc -c 2>&1
// RUN: llvm-dis %t.bc -o %t.ll
// RUN: FileCheck %s --input-file=%t.ll
diff --git a/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp b/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp
index cc751cc683b594..bbbf4c037f7609 100644
--- a/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp
+++ b/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp
@@ -1,26 +1,17 @@
// RUN: %clang_cc1 -fsycl-is-host -emit-llvm -triple x86_64-unknown-linux-gnu -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-HOST,CHECK-HOST-LINUX %s
// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-unknown-linux-gnu -triple amdgpu-amd-amdhsa -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-AMDGCN %s
-// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-unknown-linux-gnu -triple nvptx-nvidia-cuda -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-NVPTX %s
// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-unknown-linux-gnu -triple nvptx64-nvidia-cuda -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-NVPTX %s
-// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-unknown-linux-gnu -triple spir-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR,CHECK-SPIRNV %s
// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-unknown-linux-gnu -triple spir64-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR,CHECK-SPIRNV %s
-// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-unknown-linux-gnu -triple spirv32-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR,CHECK-SPIRV %s
// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-unknown-linux-gnu -triple spirv64-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR,CHECK-SPIRV %s
// RUN: %clang_cc1 -fsycl-is-host -emit-llvm -triple x86_64-pc-windows-msvc -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-HOST,CHECK-HOST-WINDOWS %s
// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-pc-windows-msvc -triple amdgpu-amd-amdhsa -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-AMDGCN %s
-// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-pc-windows-msvc -triple nvptx-nvidia-cuda -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-NVPTX %s
// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-pc-windows-msvc -triple nvptx64-nvidia-cuda -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-NVPTX %s
-// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-pc-windows-msvc -triple spir-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR,CHECK-SPIRNV %s
// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-pc-windows-msvc -triple spir64-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR,CHECK-SPIRNV %s
-// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-pc-windows-msvc -triple spirv32-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR,CHECK-SPIRV %s
// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-pc-windows-msvc -triple spirv64-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR,CHECK-SPIRV %s
// RUN: %clang_cc1 -fsycl-is-host -emit-llvm -triple x86_64-uefi -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-HOST,CHECK-HOST-WINDOWS %s
// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-uefi -triple amdgpu-amd-amdhsa -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-AMDGCN %s
-// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-uefi -triple nvptx-nvidia-cuda -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-NVPTX %s
// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-uefi -triple nvptx64-nvidia-cuda -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-NVPTX %s
-// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-uefi -triple spir-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR,CHECK-SPIRNV %s
// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-uefi -triple spir64-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR,CHECK-SPIRNV %s
-// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-uefi -triple spirv32-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR,CHECK-SPIRV %s
// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-uefi -triple spirv64-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR,CHECK-SPIRV %s
// Test code generation for functions declared with the sycl_kernel_entry_point
diff --git a/clang/test/Driver/cuda-device-triple.cu b/clang/test/Driver/cuda-device-triple.cu
index 8acd4585b8c828..5abdcbf2b7381a 100644
--- a/clang/test/Driver/cuda-device-triple.cu
+++ b/clang/test/Driver/cuda-device-triple.cu
@@ -1,4 +1,4 @@
-// RUN: %clang -### -emit-llvm --cuda-device-only \
+// RUN: %clang -### -emit-llvm --cuda-device-only --target=i386-unknown-linux-gnu \
// RUN: -nocudalib -nocudainc --offload=spirv32-unknown-unknown -c %s 2>&1 | FileCheck %s
// Make sure there's no sm_* suffix on the output name
diff --git a/clang/test/Frontend/sycl-aux-triple.cpp b/clang/test/Frontend/sycl-aux-triple.cpp
index 38b6a24fb3ce99..2ab23fd1cf7e80 100644
--- a/clang/test/Frontend/sycl-aux-triple.cpp
+++ b/clang/test/Frontend/sycl-aux-triple.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 %s -triple spir -aux-triple x86_64-unknown-linux-gnu -E -dM | FileCheck %s
-// RUN: %clang_cc1 %s -fsycl-is-device -triple spir -aux-triple x86_64-unknown-linux-gnu -E -dM | FileCheck --check-prefix=CHECK-SYCL %s
+// RUN: %clang_cc1 %s -triple spir64 -aux-triple x86_64-unknown-linux-gnu -E -dM | FileCheck %s
+// RUN: %clang_cc1 %s -fsycl-is-device -triple spir64 -aux-triple x86_64-unknown-linux-gnu -E -dM | FileCheck --check-prefix=CHECK-SYCL %s
// CHECK-NOT:#define __x86_64__ 1
// CHECK-SYCL:#define __x86_64__ 1
diff --git a/clang/test/SemaCUDA/allow-int128.cu b/clang/test/SemaCUDA/allow-int128.cu
index 44f8fefa3aa051..5d2f484bcd44d9 100644
--- a/clang/test/SemaCUDA/allow-int128.cu
+++ b/clang/test/SemaCUDA/allow-int128.cu
@@ -4,7 +4,7 @@
// RUN: %clang_cc1 -triple spirv64-amd-amdhsa \
// RUN: -aux-triple x86_64-unknown-linux-gnu \
// RUN: -fcuda-is-device -verify -fsyntax-only %s
-// RUN: %clang_cc1 -triple nvptx \
+// RUN: %clang_cc1 -triple nvptx64 \
// RUN: -aux-triple x86_64-unknown-linux-gnu \
// RUN: -fcuda-is-device -verify -fsyntax-only %s
diff --git a/clang/test/SemaCUDA/cuda-inherits-calling-conv.cu b/clang/test/SemaCUDA/cuda-inherits-calling-conv.cu
index a6928e71f3ae09..a4a6292e012e44 100644
--- a/clang/test/SemaCUDA/cuda-inherits-calling-conv.cu
+++ b/clang/test/SemaCUDA/cuda-inherits-calling-conv.cu
@@ -5,7 +5,7 @@
// RUN: -aux-triple i386-windows-msvc -fsyntax-only \
// RUN: -fcuda-is-device -verify %s
-// RUN: %clang_cc1 -std=c++11 -triple nvptx-nvidia-cuda \
+// RUN: %clang_cc1 -std=c++11 -triple nvptx64-nvidia-cuda \
// RUN: -aux-triple x86_64-linux-gnu -fsyntax-only \
// RUN: -fcuda-is-device -verify -verify-ignore-unexpected=note \
// RUN: -DEXPECT_ERR %s
diff --git a/clang/test/SemaHIP/amdgcnspirv-implicit-alloc-function-calling-conv.hip b/clang/test/SemaHIP/amdgcnspirv-implicit-alloc-function-calling-conv.hip
index c3e7e1a5cd59ee..66bf9b359e65ad 100644
--- a/clang/test/SemaHIP/amdgcnspirv-implicit-alloc-function-calling-conv.hip
+++ b/clang/test/SemaHIP/amdgcnspirv-implicit-alloc-function-calling-conv.hip
@@ -1,10 +1,8 @@
// RUN: %clang_cc1 %s -fcuda-is-device -std=c++17 -triple spirv32 -verify
// RUN: %clang_cc1 %s -fcuda-is-device -std=c++17 -triple spirv64 -verify
// RUN: %clang_cc1 %s -fcuda-is-device -std=c++17 -triple spirv64-amd-amdhsa -verify
-// RUN: %clang_cc1 %s -fcuda-is-device -std=c++17 -triple spirv32 -aux-triple x86_64-unknown-linux-gnu -verify
// RUN: %clang_cc1 %s -fcuda-is-device -std=c++17 -triple spirv64 -aux-triple x86_64-unknown-linux-gnu -verify
// RUN: %clang_cc1 %s -fcuda-is-device -std=c++17 -triple spirv64-amd-amdhsa -aux-triple x86_64-unknown-linux-gnu -verify
-// RUN: %clang_cc1 %s -fcuda-is-device -std=c++17 -triple spirv32 -aux-triple x86_64-pc-windows-msvc -verify
// RUN: %clang_cc1 %s -fcuda-is-device -std=c++17 -triple spirv64 -aux-triple x86_64-pc-windows-msvc -verify
// RUN: %clang_cc1 %s -fcuda-is-device -std=c++17 -triple spirv64-amd-amdhsa -aux-triple x86_64-pc-windows-msvc -verify
>From 306f69d8643631f04d935f9b3834f1031f61576a Mon Sep 17 00:00:00 2001
From: Sindhu Chittireddy <sindhu.chittireddy at intel.com>
Date: Fri, 28 Aug 2026 10:44:07 -0700
Subject: [PATCH 2/8] Diagnose other type and size mismatches in addition to
pointer width
---
clang/docs/ReleaseNotes.md | 9 ++-
.../clang/Basic/DiagnosticCommonKinds.td | 7 +-
clang/include/clang/Basic/TargetInfo.h | 30 +++++++
clang/lib/Basic/Targets.cpp | 79 ++++++++++++++-----
clang/lib/Basic/Targets/SPIR.h | 32 +-------
clang/lib/Driver/Driver.cpp | 18 ++---
clang/lib/Frontend/CompilerInstance.cpp | 8 +-
clang/test/Driver/hip-autolink.hip | 6 +-
clang/test/SemaCUDA/amdgpu-bf16.cu | 4 +-
9 files changed, 121 insertions(+), 72 deletions(-)
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index d1651cdb925815..42f52a2fd1a835 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -51,11 +51,12 @@ The previous behavior can be restored with `-Wno-error=unicode-whitespace`.
Clang will stop accepting non-ascii whitespaces as token separators
in a future version of Clang.
-- Offload compilations that pair a SPIR, physical SPIR-V, or NVPTX device target
- with a host of a different pointer width are now rejected, for example
- `--offload=spirv32` with an `x86_64` host. These targets take `size_t`,
+- Offload compilations that pair a SPIR, physical SPIR-V, NVPTX, or AMDGPU device
+ target with an incompatible host target are now rejected, for example
+ `--offload=spirv32` with an `x86_64` host, or `--offload-arch=gfx906` with an
+ `i386` host. These targets take the pointer width and alignment, `size_t`,
`ptrdiff_t`, and `intptr_t` from the host, so a mismatch disagreed with the
- device data layout. Select a device target whose width matches the host's.
+ device data layout. Select a host and device target that agree on those types.
### C++ Specific Potentially Breaking Changes
diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td
index ece27b02f840ee..bbf9882ffda069 100644
--- a/clang/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td
@@ -338,9 +338,10 @@ def err_target_unknown_cpu : Error<"unknown target CPU '%0'">;
def note_valid_options : Note<"valid target CPU values are: %0">;
def err_target_unsupported_cpu_for_micromips : Error<
"micromips is not supported for target CPU '%0'">;
-def err_target_unsupported_host_device_pointer_width : Error<
- "device target '%0' with %1-bit pointers is incompatible with host target "
- "'%2' with %3-bit pointers">;
+def err_target_unsupported_host_pointer_related_type : Error<
+ "device target '%0' takes %select{a pointer width|a pointer alignment|"
+ "a 'size_t' width|a 'ptrdiff_t' width|an 'intptr_t' width}2 of %3 bits from "
+ "host target '%1', but requires %4 bits">;
def err_target_unknown_abi : Error<"unknown target ABI '%0'">;
def err_target_unsupported_abi : Error<"ABI '%0' is not supported on CPU '%1'">;
def err_target_unsupported_abi_for_triple : Error<
diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h
index 6311b6b567a5e1..f0f5bf735ae953 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -327,6 +327,36 @@ class TargetInfo : public TransferrableTargetInfo,
static TargetInfo *CreateTargetInfo(DiagnosticsEngine &Diags,
TargetOptions &Opts);
+ /// When a device target takes its pointer related types (the pointer width
+ /// and alignment, size_t, ptrdiff_t, and intptr_t) from a host target.
+ enum class HostAdaptation {
+ /// It keeps its own pointer related types.
+ None,
+ /// It adapts in its constructor, from TargetOptions::HostTriple.
+ Constructor,
+ SetAuxTarget,
+ };
+
+ /// Returns when the device target takes its pointer related types from the
+ /// host target, mirroring the conditions under which the TargetInfo
+ /// subclasses adapt. A device that declines a host keeps its own types, which
+ /// the driver's triple level check must not report as a mismatch.
+ static HostAdaptation getHostAdaptation(const llvm::Triple &DeviceTriple,
+ const llvm::Triple &HostTriple);
+
+ static bool adaptsToHostTarget(const llvm::Triple &DeviceTriple,
+ const llvm::Triple &HostTriple) {
+ return getHostAdaptation(DeviceTriple, HostTriple) != HostAdaptation::None;
+ }
+
+ /// Reports an error if this target adapts to the given host target at the
+ /// given stage and ended up with pointer related types that disagree with its
+ /// own data layout. Does nothing if it does not adapt at that stage. Returns
+ /// true if no error was reported.
+ bool checkHostPointerRelatedTypes(DiagnosticsEngine &Diags,
+ const llvm::Triple &HostTriple,
+ HostAdaptation Stage) const;
+
virtual ~TargetInfo();
/// Retrieve the target options.
diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp
index a939eb9b944707..ed48400a947f96 100644
--- a/clang/lib/Basic/Targets.cpp
+++ b/clang/lib/Basic/Targets.cpp
@@ -836,12 +836,59 @@ std::unique_ptr<TargetInfo> AllocateTarget(const llvm::Triple &Triple,
using namespace clang::targets;
-/// Returns true if Triple names a target that takes its pointer related types
-/// from a host target. Logical SPIR-V is excluded; it uses fixed values for
-/// those types regardless of the host.
-static bool adaptsToHostTarget(const llvm::Triple &Triple) {
- return (Triple.isSPIROrSPIRV() && Triple.getArch() != llvm::Triple::spirv) ||
- Triple.isNVPTX();
+TargetInfo::HostAdaptation
+TargetInfo::getHostAdaptation(const llvm::Triple &DeviceTriple,
+ const llvm::Triple &HostTriple) {
+ // No recognizable host triple, so nothing to adapt to.
+ if (HostTriple.getArch() == llvm::Triple::UnknownArch)
+ return HostAdaptation::None;
+
+ // setAuxTarget() overwrites these, so constructor values are not yet final.
+ if (DeviceTriple.isAMDGPU() ||
+ (DeviceTriple.getArch() == llvm::Triple::spirv64 &&
+ DeviceTriple.getOS() == llvm::Triple::AMDHSA))
+ return HostAdaptation::SetAuxTarget;
+
+ // Logical SPIR-V sets these itself, with a 32-bit size_t by design.
+ if (DeviceTriple.isSPIRVLogical())
+ return HostAdaptation::None;
+
+ if (DeviceTriple.isSPIROrSPIRV())
+ return HostTriple.isSPIROrSPIRV() ? HostAdaptation::None
+ : HostAdaptation::Constructor;
+ if (DeviceTriple.isNVPTX())
+ return HostTriple.isNVPTX() ? HostAdaptation::None
+ : HostAdaptation::Constructor;
+
+ return HostAdaptation::None;
+}
+
+bool TargetInfo::checkHostPointerRelatedTypes(DiagnosticsEngine &Diags,
+ const llvm::Triple &HostTriple,
+ HostAdaptation Stage) const {
+ assert(Stage != HostAdaptation::None && "Nothing to check");
+ if (getHostAdaptation(getTriple(), HostTriple) != Stage)
+ return true;
+
+ // The device data layout fixes the width of every one of these types.
+ unsigned Required = getTriple().getArchPointerBitWidth();
+ // The order matches the %select in the diagnostic below.
+ unsigned Widths[] = {getPointerWidth(LangAS::Default),
+ getPointerAlign(LangAS::Default),
+ getTypeWidth(getSizeType()),
+ getTypeWidth(getPtrDiffType(LangAS::Default)),
+ getTypeWidth(getIntPtrType())};
+
+ for (auto [Which, Width] : llvm::enumerate(Widths)) {
+ if (Width != Required) {
+ Diags.Report(diag::err_target_unsupported_host_pointer_related_type)
+ << getTriple().str() << HostTriple.str()
+ << static_cast<unsigned>(Which) << Width << Required;
+ return false;
+ }
+ }
+
+ return true;
}
/// CreateTargetInfo - Return the target info object for the specified target
@@ -852,21 +899,6 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
llvm::Triple Triple(llvm::Triple::normalize(Opts->Triple));
- // Host and device pointer related type widths must match. Reject a mismatch
- // before constructing the device target, which asserts on this.
- if (adaptsToHostTarget(Triple) && !Opts->HostTriple.empty()) {
- llvm::Triple HostTriple(llvm::Triple::normalize(Opts->HostTriple));
- if (!adaptsToHostTarget(HostTriple) &&
- HostTriple.getArch() != llvm::Triple::UnknownArch &&
- Triple.getArchPointerBitWidth() !=
- HostTriple.getArchPointerBitWidth()) {
- Diags.Report(diag::err_target_unsupported_host_device_pointer_width)
- << Triple.str() << Triple.getArchPointerBitWidth() << HostTriple.str()
- << HostTriple.getArchPointerBitWidth();
- return nullptr;
- }
- }
-
// Construct the target
std::unique_ptr<TargetInfo> Target = AllocateTarget(Triple, *Opts);
if (!Target) {
@@ -875,6 +907,11 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
}
Target->TargetOpts = Opts;
+ // Targets that adapt in their constructor have done so by now.
+ if (!Target->checkHostPointerRelatedTypes(
+ Diags, llvm::Triple(Opts->HostTriple), HostAdaptation::Constructor))
+ return nullptr;
+
// Set the target CPU if specified.
if (!Opts->CPU.empty() && !Target->setCPU(Opts->CPU)) {
Diags.Report(diag::err_target_unknown_cpu) << Opts->CPU;
diff --git a/clang/lib/Basic/Targets/SPIR.h b/clang/lib/Basic/Targets/SPIR.h
index 17f90e80dc5fdd..b5400cddf575c6 100644
--- a/clang/lib/Basic/Targets/SPIR.h
+++ b/clang/lib/Basic/Targets/SPIR.h
@@ -254,18 +254,12 @@ class LLVM_LIBRARY_VISIBILITY SPIR32TargetInfo : public SPIRTargetInfo {
: SPIRTargetInfo(Triple, Opts) {
assert(Triple.getArch() == llvm::Triple::spir &&
"Invalid architecture for 32-bit SPIR.");
- PointerWidth = PointerAlign = 32;
if (!getHostTarget()) {
+ PointerWidth = PointerAlign = 32;
SizeType = TargetInfo::UnsignedInt;
PtrDiffType = IntPtrType = TargetInfo::SignedInt;
}
- // Host and device pointer related type widths must match.
- assert(PointerWidth == 32 && PointerAlign == 32 &&
- getTypeWidth(SizeType) == 32 && getTypeWidth(PtrDiffType) == 32 &&
- getTypeWidth(IntPtrType) == 32 &&
- "Invalid pointer related types for SPIR32");
-
// SPIR32 has support for atomic ops if atomic extension is enabled.
// Take the maximum because it's possible the Host supports wider types.
MaxAtomicInlineWidth = std::max<unsigned char>(MaxAtomicInlineWidth, 64);
@@ -283,18 +277,12 @@ class LLVM_LIBRARY_VISIBILITY SPIR64TargetInfo : public SPIRTargetInfo {
: SPIRTargetInfo(Triple, Opts) {
assert(Triple.getArch() == llvm::Triple::spir64 &&
"Invalid architecture for 64-bit SPIR.");
- PointerWidth = PointerAlign = 64;
if (!getHostTarget()) {
+ PointerWidth = PointerAlign = 64;
SizeType = TargetInfo::UnsignedLong;
PtrDiffType = IntPtrType = TargetInfo::SignedLong;
}
- // Host and device pointer related type widths must match.
- assert(PointerWidth == 64 && PointerAlign == 64 &&
- getTypeWidth(SizeType) == 64 && getTypeWidth(PtrDiffType) == 64 &&
- getTypeWidth(IntPtrType) == 64 &&
- "Invalid pointer related types for SPIR64");
-
// SPIR64 has support for atomic ops if atomic extension is enabled.
// Take the maximum because it's possible the Host supports wider types.
MaxAtomicInlineWidth = std::max<unsigned char>(MaxAtomicInlineWidth, 64);
@@ -383,18 +371,12 @@ class LLVM_LIBRARY_VISIBILITY SPIRV32TargetInfo : public BaseSPIRVTargetInfo {
"32-bit SPIR-V target must use unknown, chipstar, or vulkan OS");
assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment &&
"32-bit SPIR-V target must use unknown environment type");
- PointerWidth = PointerAlign = 32;
if (!getHostTarget()) {
+ PointerWidth = PointerAlign = 32;
SizeType = TargetInfo::UnsignedInt;
PtrDiffType = IntPtrType = TargetInfo::SignedInt;
}
- // Host and device pointer related type widths must match.
- assert(PointerWidth == 32 && PointerAlign == 32 &&
- getTypeWidth(SizeType) == 32 && getTypeWidth(PtrDiffType) == 32 &&
- getTypeWidth(IntPtrType) == 32 &&
- "Invalid pointer related types for SPIR-V 32");
-
// SPIR-V has core support for atomic ops, and Int32 is always available;
// we take the maximum because it's possible the Host supports wider types.
MaxAtomicInlineWidth = std::max<unsigned char>(MaxAtomicInlineWidth, 64);
@@ -417,18 +399,12 @@ class LLVM_LIBRARY_VISIBILITY SPIRV64TargetInfo : public BaseSPIRVTargetInfo {
"64-bit SPIR-V target must use unknown, chipstar, or vulkan OS");
assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment &&
"64-bit SPIR-V target must use unknown environment type");
- PointerWidth = PointerAlign = 64;
if (!getHostTarget()) {
+ PointerWidth = PointerAlign = 64;
SizeType = TargetInfo::UnsignedLong;
PtrDiffType = IntPtrType = TargetInfo::SignedLong;
}
- // Host and device pointer related type widths must match.
- assert(PointerWidth == 64 && PointerAlign == 64 &&
- getTypeWidth(SizeType) == 64 && getTypeWidth(PtrDiffType) == 64 &&
- getTypeWidth(IntPtrType) == 64 &&
- "Invalid pointer related types for SPIR-V 64");
-
// SPIR-V has core support for atomic ops, and Int64 is always available;
// we take the maximum because it's possible the Host supports wider types.
MaxAtomicInlineWidth = std::max<unsigned char>(MaxAtomicInlineWidth, 64);
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index cf7e49932a1a25..f90c2804b805c4 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -55,6 +55,7 @@
#include "ToolChains/ZOS.h"
#include "clang/Basic/DiagnosticDriver.h"
#include "clang/Basic/TargetID.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Version.h"
#include "clang/Config/config.h"
#include "clang/Driver/Action.h"
@@ -1129,19 +1130,16 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
continue;
}
+ // A triple level approximation that catches the common cases early; the
+ // types are checked once the device adapts.
const llvm::Triple &HostTriple = C.getDefaultToolChain().getTriple();
- // Logical SPIR-V is excluded; it overrides those types with fixed values.
- auto AdaptsToHostTarget = [](const llvm::Triple &T) {
- return (T.isSPIROrSPIRV() && T.getArch() != llvm::Triple::spirv) ||
- T.isNVPTX();
- };
- // Target and host pointer related type widths must match.
- if (AdaptsToHostTarget(Target) && !AdaptsToHostTarget(HostTriple) &&
+ if (TargetInfo::adaptsToHostTarget(Target, HostTriple) &&
Target.getArchPointerBitWidth() !=
HostTriple.getArchPointerBitWidth()) {
- Diag(diag::err_target_unsupported_host_device_pointer_width)
- << Target.str() << Target.getArchPointerBitWidth()
- << HostTriple.str() << HostTriple.getArchPointerBitWidth();
+ Diag(diag::err_target_unsupported_host_pointer_related_type)
+ << Target.str() << HostTriple.str() << /*pointer width*/ 0
+ << HostTriple.getArchPointerBitWidth()
+ << Target.getArchPointerBitWidth();
continue;
}
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index 66662a786e6fca..7a7373b82ebb9a 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -167,9 +167,15 @@ bool CompilerInstance::createTarget() {
// created. This complexity should be lifted elsewhere.
getTarget().adjust(getDiagnostics(), getLangOpts(), getAuxTarget());
- if (auto *Aux = getAuxTarget())
+ if (auto *Aux = getAuxTarget()) {
getTarget().setAuxTarget(Aux);
+ if (!getTarget().checkHostPointerRelatedTypes(
+ getDiagnostics(), Aux->getTriple(),
+ TargetInfo::HostAdaptation::SetAuxTarget))
+ return false;
+ }
+
return true;
}
diff --git a/clang/test/Driver/hip-autolink.hip b/clang/test/Driver/hip-autolink.hip
index cce3977375d2e0..e37c6e5d7e5029 100644
--- a/clang/test/Driver/hip-autolink.hip
+++ b/clang/test/Driver/hip-autolink.hip
@@ -1,10 +1,10 @@
-// RUN: %clang --target=i386-pc-windows-msvc --cuda-gpu-arch=gfx906 -nogpulib -nogpuinc \
+// RUN: %clang --target=x86_64-pc-windows-msvc --cuda-gpu-arch=gfx906 -nogpulib -nogpuinc \
// RUN: --cuda-device-only %s -### 2>&1 | FileCheck --check-prefix=DEV %s
-// RUN: %clang --target=i386-pc-windows-msvc --cuda-gpu-arch=gfx906 -nogpulib -nogpuinc \
+// RUN: %clang --target=x86_64-pc-windows-msvc --cuda-gpu-arch=gfx906 -nogpulib -nogpuinc \
// RUN: --cuda-host-only %s -### 2>&1 | FileCheck --check-prefix=HOST %s
// DEV: "-cc1" "-triple" "amdgcn-amd-amdhsa"
// DEV-SAME: "-fno-autolink"
-// HOST: "-cc1" "-triple" "i386-pc-windows-msvc{{.*}}"
+// HOST: "-cc1" "-triple" "x86_64-pc-windows-msvc{{.*}}"
// HOST-NOT: "-fno-autolink"
diff --git a/clang/test/SemaCUDA/amdgpu-bf16.cu b/clang/test/SemaCUDA/amdgpu-bf16.cu
index 0b5ce1a4f64cf5..b14a3dd608aeb2 100644
--- a/clang/test/SemaCUDA/amdgpu-bf16.cu
+++ b/clang/test/SemaCUDA/amdgpu-bf16.cu
@@ -1,8 +1,8 @@
// REQUIRES: amdgpu-registered-target
// REQUIRES: x86-registered-target
-// RUN: %clang_cc1 "-aux-triple" "x86_64-unknown-linux-gnu" "-triple" "r600-unknown-unknown"\
-// RUN: -fcuda-is-device "-aux-target-cpu" "x86-64" -fsyntax-only -verify=r600 %s
+// RUN: %clang_cc1 "-aux-triple" "i386-unknown-linux-gnu" "-triple" "r600-unknown-unknown"\
+// RUN: -fcuda-is-device "-aux-target-cpu" "i686" -fsyntax-only -verify=r600 %s
// AMDGCN has storage-only support for bf16. R600 does not support it should error out when
// it's the main target.
>From 8aa1d9a9082399bb2350654cc708b16a61884fe3 Mon Sep 17 00:00:00 2001
From: Sindhu Chittireddy <sindhu.chittireddy at intel.com>
Date: Fri, 28 Aug 2026 12:43:03 -0700
Subject: [PATCH 3/8] Static cast to unsigned.
---
clang/lib/Basic/Targets.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp
index ed48400a947f96..a328f175b5afc4 100644
--- a/clang/lib/Basic/Targets.cpp
+++ b/clang/lib/Basic/Targets.cpp
@@ -873,8 +873,8 @@ bool TargetInfo::checkHostPointerRelatedTypes(DiagnosticsEngine &Diags,
// The device data layout fixes the width of every one of these types.
unsigned Required = getTriple().getArchPointerBitWidth();
// The order matches the %select in the diagnostic below.
- unsigned Widths[] = {getPointerWidth(LangAS::Default),
- getPointerAlign(LangAS::Default),
+ unsigned Widths[] = {static_cast<unsigned>(getPointerWidth(LangAS::Default)),
+ static_cast<unsigned>(getPointerAlign(LangAS::Default)),
getTypeWidth(getSizeType()),
getTypeWidth(getPtrDiffType(LangAS::Default)),
getTypeWidth(getIntPtrType())};
>From 67dfe736a64ab5cb021b69a45b85b831b9924cc1 Mon Sep 17 00:00:00 2001
From: Sindhu Chittireddy <sindhu.chittireddy at intel.com>
Date: Mon, 31 Aug 2026 19:35:26 -0700
Subject: [PATCH 4/8] [clang] Add tests for the host/device pointer related
type diagnostic
Add the driver and frontend tests for the diagnostic, and adapt two
existing tests that pair a 64-bit device target with a 32-bit host:
Preprocessor/init-amdgpu.c and
SemaHIP/amdgcnspirv-host-cconv-in-abstract-type.hip
---
.../Driver/offload-pointer-width-mismatch.c | 31 +++++++
.../offload-pointer-width-mismatch.cpp | 93 +++++++++++++++++++
clang/test/Preprocessor/init-amdgpu.c | 2 +-
...mdgcnspirv-host-cconv-in-abstract-type.hip | 1 -
4 files changed, 125 insertions(+), 2 deletions(-)
create mode 100644 clang/test/Driver/offload-pointer-width-mismatch.c
create mode 100644 clang/test/Frontend/offload-pointer-width-mismatch.cpp
diff --git a/clang/test/Driver/offload-pointer-width-mismatch.c b/clang/test/Driver/offload-pointer-width-mismatch.c
new file mode 100644
index 00000000000000..98fd079d5edae8
--- /dev/null
+++ b/clang/test/Driver/offload-pointer-width-mismatch.c
@@ -0,0 +1,31 @@
+// Offload targets that take their pointer related types from the host target
+// are rejected early, before any compilation job is built.
+
+// RUN: not %clang -### --target=i386-unknown-linux-gnu -x hip --offload-arch=gfx906 \
+// RUN: -nogpulib -nogpuinc -c %s 2>&1 | FileCheck --check-prefix=AMDGPU %s
+// RUN: not %clang -### --target=i386-unknown-linux-gnu -x cuda --offload=nvptx64-nvidia-cuda \
+// RUN: --offload-arch=sm_60 -nogpulib -nogpuinc -c %s 2>&1 | FileCheck --check-prefix=NVPTX %s
+// RUN: not %clang -### --target=x86_64-unknown-linux-gnu -x cuda --cuda-device-only \
+// RUN: -nogpulib -nogpuinc --offload=spirv32-unknown-unknown -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=SPIRV32 %s
+// RUN: not %clang -### --target=i386-unknown-linux-gnu -x cuda \
+// RUN: --offload-targets=nvptx64-nvidia-cuda --offload-arch=sm_60 -nogpulib -nogpuinc \
+// RUN: -c %s 2>&1 | FileCheck --check-prefix=NVPTX %s
+
+// OpenMP offloading reaches the same check.
+
+// RUN: not %clang -### --target=i386-unknown-linux-gnu -fopenmp \
+// RUN: -fopenmp-targets=nvptx64-nvidia-cuda -nogpulib -nogpuinc -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=NVPTX %s
+// RUN: not %clang -### --target=i386-unknown-linux-gnu -fopenmp --offload-arch=gfx906 \
+// RUN: -nogpulib -nogpuinc -c %s 2>&1 | FileCheck --check-prefix=AMDGPU %s
+
+// AMDGPU: error: device target 'amdgpu-amd-amdhsa' takes a pointer width of 32 bits from host target 'i386-unknown-linux-gnu', but requires 64 bits
+// NVPTX: error: device target 'nvptx64-nvidia-cuda' takes a pointer width of 32 bits from host target 'i386-unknown-linux-gnu', but requires 64 bits
+// SPIRV32: error: device target 'spirv32-unknown-unknown' takes a pointer width of 64 bits from host target 'x86_64-unknown-linux-gnu', but requires 32 bits
+
+// RUN: %clang -### --target=x86_64-unknown-linux-gnu -x hip --offload-arch=gfx906 \
+// RUN: -nogpulib -nogpuinc -c %s 2>&1 | FileCheck --check-prefix=OK %s
+
+// OK-NOT: error:
+// OK: "-cc1" "-triple" "amdgpu9.06-amd-amdhsa" "-aux-triple" "x86_64-unknown-linux-gnu"
diff --git a/clang/test/Frontend/offload-pointer-width-mismatch.cpp b/clang/test/Frontend/offload-pointer-width-mismatch.cpp
new file mode 100644
index 00000000000000..4d1107079253cf
--- /dev/null
+++ b/clang/test/Frontend/offload-pointer-width-mismatch.cpp
@@ -0,0 +1,93 @@
+// REQUIRES: amdgpu-registered-target, nvptx-registered-target
+// REQUIRES: spirv-registered-target, x86-registered-target
+
+// RUN: not %clang_cc1 -triple amdgcn-amd-amdhsa -aux-triple i386-unknown-linux-gnu \
+// RUN: -fcuda-is-device -fsyntax-only -x hip %s 2>&1 | FileCheck --check-prefix=AMDGCN %s
+// RUN: not %clang_cc1 -triple r600-unknown-unknown -aux-triple x86_64-unknown-linux-gnu \
+// RUN: -fcuda-is-device -fsyntax-only -x hip %s 2>&1 | FileCheck --check-prefix=R600 %s
+// RUN: not %clang_cc1 -triple nvptx64-nvidia-cuda -aux-triple i386-unknown-linux-gnu \
+// RUN: -fcuda-is-device -fsyntax-only -x cuda %s 2>&1 | FileCheck --check-prefix=NVPTX %s
+// RUN: not %clang_cc1 -triple spir-unknown-unknown -aux-triple x86_64-unknown-linux-gnu \
+// RUN: -fsycl-is-device -fsyntax-only %s 2>&1 | FileCheck --check-prefix=SPIR %s
+// RUN: not %clang_cc1 -triple spirv64-unknown-unknown -aux-triple i386-unknown-linux-gnu \
+// RUN: -fsycl-is-device -fsyntax-only %s 2>&1 | FileCheck --check-prefix=SPIRV %s
+
+// AMDGCN: error: device target 'amdgcn-amd-amdhsa' takes a pointer width of 32 bits from host target 'i386-unknown-linux-gnu', but requires 64 bits
+// R600: error: device target 'r600-unknown-unknown' takes a pointer width of 64 bits from host target 'x86_64-unknown-linux-gnu', but requires 32 bits
+// NVPTX: error: device target 'nvptx64-nvidia-cuda' takes a pointer width of 32 bits from host target 'i386-unknown-linux-gnu', but requires 64 bits
+// SPIR: error: device target 'spir-unknown-unknown' takes a pointer width of 64 bits from host target 'x86_64-unknown-linux-gnu', but requires 32 bits
+// SPIRV: error: device target 'spirv64-unknown-unknown' takes a pointer width of 32 bits from host target 'i386-unknown-linux-gnu', but requires 64 bits
+
+// OpenMP device compilation adapts at both stages too.
+
+// RUN: not %clang_cc1 -fopenmp -fopenmp-is-target-device -triple amdgcn-amd-amdhsa \
+// RUN: -aux-triple i386-unknown-linux-gnu -fsyntax-only %s 2>&1 \
+// RUN: | FileCheck --check-prefix=AMDGCN %s
+// RUN: not %clang_cc1 -fopenmp -fopenmp-is-target-device -triple nvptx64-nvidia-cuda \
+// RUN: -aux-triple i386-unknown-linux-gnu -fsyntax-only %s 2>&1 \
+// RUN: | FileCheck --check-prefix=NVPTX %s
+
+// A host target that is itself a device target is no exception.
+
+// RUN: not %clang_cc1 -triple spirv64-unknown-unknown -aux-triple nvptx-nvidia-cuda \
+// RUN: -fsycl-is-device -fsyntax-only %s 2>&1 | FileCheck --check-prefix=SPIRV-NVPTX %s
+// RUN: not %clang_cc1 -triple amdgcn-amd-amdhsa -aux-triple r600-unknown-unknown \
+// RUN: -fcuda-is-device -fsyntax-only -x hip %s 2>&1 | FileCheck --check-prefix=AMDGCN-R600 %s
+// RUN: not %clang_cc1 -triple spirv64-amd-amdhsa -aux-triple spir-unknown-unknown \
+// RUN: -fsycl-is-device -fsyntax-only %s 2>&1 | FileCheck --check-prefix=AMDHSA-SPIR %s
+
+// SPIRV-NVPTX: error: device target 'spirv64-unknown-unknown' takes a pointer width of 32 bits from host target 'nvptx-nvidia-cuda', but requires 64 bits
+// AMDGCN-R600: error: device target 'amdgcn-amd-amdhsa' takes a pointer width of 32 bits from host target 'r600-unknown-unknown', but requires 64 bits
+// AMDHSA-SPIR: error: device target 'spirv64-amd-amdhsa' takes a pointer width of 32 bits from host target 'spir-unknown-unknown', but requires 64 bits
+
+// The host pointer width is taken from the host target rather than from its
+// triple, so an ABI that narrows pointers is caught too.
+
+// RUN: not %clang_cc1 -triple spir64-unknown-unknown -aux-triple x86_64-unknown-linux-gnux32 \
+// RUN: -fsycl-is-device -fsyntax-only %s 2>&1 | FileCheck --check-prefix=SPIR64-X32 %s
+// RUN: not %clang_cc1 -triple nvptx64-nvidia-cuda -aux-triple x86_64-unknown-linux-gnux32 \
+// RUN: -fcuda-is-device -fsyntax-only -x cuda %s 2>&1 | FileCheck --check-prefix=NVPTX64-X32 %s
+// RUN: not %clang_cc1 -triple amdgcn-amd-amdhsa -aux-triple x86_64-unknown-linux-gnux32 \
+// RUN: -fcuda-is-device -fsyntax-only -x hip %s 2>&1 | FileCheck --check-prefix=AMDGCN-X32 %s
+
+// SPIR64-X32: error: device target 'spir64-unknown-unknown' takes a pointer width of 32 bits from host target 'x86_64-unknown-linux-gnux32', but requires 64 bits
+// NVPTX64-X32: error: device target 'nvptx64-nvidia-cuda' takes a pointer width of 32 bits from host target 'x86_64-unknown-linux-gnux32', but requires 64 bits
+// AMDGCN-X32: error: device target 'amdgcn-amd-amdhsa' takes a pointer width of 32 bits from host target 'x86_64-unknown-linux-gnux32', but requires 64 bits
+
+// NVPTX and AMDGPU take the pointer alignment from the host too, so a host that
+// under aligns pointers is a mismatch even where the widths agree.
+
+// RUN: not %clang_cc1 -triple nvptx-nvidia-cuda -aux-triple m68k-unknown-linux-gnu \
+// RUN: -fcuda-is-device -fsyntax-only -x cuda %s 2>&1 | FileCheck --check-prefix=NVPTX-M68K %s
+// RUN: not %clang_cc1 -triple r600-unknown-unknown -aux-triple m68k-unknown-linux-gnu \
+// RUN: -fcuda-is-device -fsyntax-only -x hip %s 2>&1 | FileCheck --check-prefix=R600-M68K %s
+
+// NVPTX-M68K: error: device target 'nvptx-nvidia-cuda' takes a pointer alignment of 16 bits from host target 'm68k-unknown-linux-gnu', but requires 32 bits
+// R600-M68K: error: device target 'r600-unknown-unknown' takes a pointer alignment of 16 bits from host target 'm68k-unknown-linux-gnu', but requires 32 bits
+
+// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -aux-triple x86_64-unknown-linux-gnu \
+// RUN: -fcuda-is-device -fsyntax-only -x hip %s
+// RUN: %clang_cc1 -triple r600-unknown-unknown -aux-triple i386-unknown-linux-gnu \
+// RUN: -fcuda-is-device -fsyntax-only -x hip %s
+// RUN: %clang_cc1 -triple nvptx-nvidia-cuda -aux-triple i386-unknown-linux-gnu \
+// RUN: -fcuda-is-device -fsyntax-only -x cuda %s
+// RUN: %clang_cc1 -triple spir64-unknown-unknown -aux-triple x86_64-unknown-linux-gnu \
+// RUN: -fsycl-is-device -fsyntax-only %s
+// RUN: %clang_cc1 -triple spir64-unknown-unknown -aux-triple x86_64-pc-windows-msvc \
+// RUN: -fsycl-is-device -fsyntax-only %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-is-target-device -triple amdgcn-amd-amdhsa \
+// RUN: -aux-triple x86_64-unknown-linux-gnu -fsyntax-only %s
+
+// SPIR and SPIR-V align pointers to their own width rather than to the host
+// alignment, so an under aligning host is not a mismatch there.
+
+// RUN: %clang_cc1 -triple spir-unknown-unknown -aux-triple m68k-unknown-linux-gnu \
+// RUN: -fsycl-is-device -fsyntax-only %s
+
+// SPIR, SPIR-V, and NVPTX keep their own pointer related types when the host is
+// of their own family, so a differing width is not a mismatch there.
+
+// RUN: %clang_cc1 -triple spirv64-unknown-unknown -aux-triple spir-unknown-unknown \
+// RUN: -fsycl-is-device -fsyntax-only %s
+// RUN: %clang_cc1 -triple nvptx64-nvidia-cuda -aux-triple nvptx-nvidia-cuda \
+// RUN: -fcuda-is-device -fsyntax-only -x cuda %s
diff --git a/clang/test/Preprocessor/init-amdgpu.c b/clang/test/Preprocessor/init-amdgpu.c
index 9e938ab4502a51..5a88de5b9a71f5 100644
--- a/clang/test/Preprocessor/init-amdgpu.c
+++ b/clang/test/Preprocessor/init-amdgpu.c
@@ -32,7 +32,7 @@
// RUN: -aux-triple x86_64-pc-windows-msvc < /dev/null \
// RUN: | FileCheck -match-full-lines -check-prefix=LLP64 %s
// RUN: %clang_cc1 -x hip -fcuda-is-device -E -dM -triple=amdgpu12.50-amd-amdhsa \
-// RUN: -aux-triple i386-unknown-linux-gnu < /dev/null \
+// RUN: -aux-triple x86_64-pc-windows-msvc < /dev/null \
// RUN: | FileCheck -match-full-lines -check-prefix=LLP64 %s
// RUN: %clang_cc1 -fopenmp -fopenmp-is-target-device -E -dM \
// RUN: -triple=amdgpu9.0a-amd-amdhsa -aux-triple x86_64-pc-windows-msvc < /dev/null \
diff --git a/clang/test/SemaHIP/amdgcnspirv-host-cconv-in-abstract-type.hip b/clang/test/SemaHIP/amdgcnspirv-host-cconv-in-abstract-type.hip
index f6b4ed3d6c33e0..95c1154a68f5fe 100644
--- a/clang/test/SemaHIP/amdgcnspirv-host-cconv-in-abstract-type.hip
+++ b/clang/test/SemaHIP/amdgcnspirv-host-cconv-in-abstract-type.hip
@@ -1,4 +1,3 @@
-// RUN: %clang_cc1 %s -fcuda-is-device -std=c++17 -triple spirv32 -aux-triple x86_64-pc-windows-msvc -fms-extensions -verify
// RUN: %clang_cc1 %s -fcuda-is-device -std=c++17 -triple spirv64 -aux-triple x86_64-pc-windows-msvc -fms-extensions -verify
// RUN: %clang_cc1 %s -fcuda-is-device -std=c++17 -triple spirv64-amd-amdhsa -aux-triple x86_64-pc-windows-msvc -fms-extensions -verify
>From 06b60e4757e11fb6f91c0f5622122e63967c895b Mon Sep 17 00:00:00 2001
From: Sindhu Chittireddy <sindhu.chittireddy at intel.com>
Date: Tue, 1 Sep 2026 09:18:15 -0700
Subject: [PATCH 5/8] [clang] Report host/device target incompatibility with
notes per type
---
.../clang/Basic/DiagnosticCommonKinds.td | 9 +--
clang/include/clang/Basic/TargetInfo.h | 14 ++---
clang/lib/Basic/Targets.cpp | 59 ++++++++++++-------
clang/lib/Driver/Driver.cpp | 9 +--
clang/lib/Frontend/CompilerInstance.cpp | 2 +-
.../Driver/offload-pointer-width-mismatch.c | 11 +++-
.../offload-pointer-width-mismatch.cpp | 50 ++++++++++++----
7 files changed, 100 insertions(+), 54 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td
index bbf9882ffda069..7415a2768050c2 100644
--- a/clang/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td
@@ -338,10 +338,11 @@ def err_target_unknown_cpu : Error<"unknown target CPU '%0'">;
def note_valid_options : Note<"valid target CPU values are: %0">;
def err_target_unsupported_cpu_for_micromips : Error<
"micromips is not supported for target CPU '%0'">;
-def err_target_unsupported_host_pointer_related_type : Error<
- "device target '%0' takes %select{a pointer width|a pointer alignment|"
- "a 'size_t' width|a 'ptrdiff_t' width|an 'intptr_t' width}2 of %3 bits from "
- "host target '%1', but requires %4 bits">;
+def err_incompatible_host_and_device_targets : Error<
+ "device target '%0' is not compatible with host target '%1'">;
+def note_incompatible_host_and_device_type : Note<
+ "%select{alignment|size}0 of type '%1' for the host target (%2 bytes) does "
+ "not match the %select{alignment|size}0 for the device target (%3 bytes)">;
def err_target_unknown_abi : Error<"unknown target ABI '%0'">;
def err_target_unsupported_abi : Error<"ABI '%0' is not supported on CPU '%1'">;
def err_target_unsupported_abi_for_triple : Error<
diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h
index 52c2f40b85aed2..741b0cc3852c08 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -348,13 +348,13 @@ class TargetInfo : public TransferrableTargetInfo,
return getHostAdaptation(DeviceTriple, HostTriple) != HostAdaptation::None;
}
- /// Reports an error if this target adapts to the given host target at the
- /// given stage and ended up with pointer related types that disagree with its
- /// own data layout. Does nothing if it does not adapt at that stage. Returns
- /// true if no error was reported.
- bool checkHostPointerRelatedTypes(DiagnosticsEngine &Diags,
- const llvm::Triple &HostTriple,
- HostAdaptation Stage) const;
+ /// Reports an error, and a note per offending type, if this target adapts to
+ /// the given host target at the given stage and ended up with pointer related
+ /// types that disagree with its own data layout. Does nothing if it does not
+ /// adapt at that stage. Returns true if no error was reported.
+ bool checkHostCompatibility(DiagnosticsEngine &Diags,
+ const llvm::Triple &HostTriple,
+ HostAdaptation Stage) const;
virtual ~TargetInfo();
diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp
index a328f175b5afc4..81608ef3d06263 100644
--- a/clang/lib/Basic/Targets.cpp
+++ b/clang/lib/Basic/Targets.cpp
@@ -863,32 +863,47 @@ TargetInfo::getHostAdaptation(const llvm::Triple &DeviceTriple,
return HostAdaptation::None;
}
-bool TargetInfo::checkHostPointerRelatedTypes(DiagnosticsEngine &Diags,
- const llvm::Triple &HostTriple,
- HostAdaptation Stage) const {
+bool TargetInfo::checkHostCompatibility(DiagnosticsEngine &Diags,
+ const llvm::Triple &HostTriple,
+ HostAdaptation Stage) const {
assert(Stage != HostAdaptation::None && "Nothing to check");
if (getHostAdaptation(getTriple(), HostTriple) != Stage)
return true;
- // The device data layout fixes the width of every one of these types.
+ // The device data layout fixes the size and the alignment of a pointer, and
+ // with them the width of every integer type that has to hold one.
unsigned Required = getTriple().getArchPointerBitWidth();
- // The order matches the %select in the diagnostic below.
- unsigned Widths[] = {static_cast<unsigned>(getPointerWidth(LangAS::Default)),
- static_cast<unsigned>(getPointerAlign(LangAS::Default)),
- getTypeWidth(getSizeType()),
- getTypeWidth(getPtrDiffType(LangAS::Default)),
- getTypeWidth(getIntPtrType())};
-
- for (auto [Which, Width] : llvm::enumerate(Widths)) {
- if (Width != Required) {
- Diags.Report(diag::err_target_unsupported_host_pointer_related_type)
- << getTriple().str() << HostTriple.str()
- << static_cast<unsigned>(Which) << Width << Required;
- return false;
- }
- }
+ struct Mismatch {
+ unsigned Which;
+ const char *TypeName;
+ unsigned HostBits;
+ };
+ // The order matches the %select in note_incompatible_host_and_device_type.
+ enum { Alignment, Size };
+
+ SmallVector<Mismatch, 5> Mismatches;
+ auto Check = [&](unsigned Which, const char *TypeName, uint64_t HostBits) {
+ if (HostBits != Required)
+ Mismatches.push_back({Which, TypeName, static_cast<unsigned>(HostBits)});
+ };
+
+ Check(Size, "void *", getPointerWidth(LangAS::Default));
+ Check(Alignment, "void *", getPointerAlign(LangAS::Default));
+ Check(Size, "size_t", getTypeWidth(getSizeType()));
+ Check(Size, "ptrdiff_t", getTypeWidth(getPtrDiffType(LangAS::Default)));
+ Check(Size, "intptr_t", getTypeWidth(getIntPtrType()));
+
+ if (Mismatches.empty())
+ return true;
+
+ Diags.Report(diag::err_incompatible_host_and_device_targets)
+ << getTriple().str() << HostTriple.str();
+ for (const Mismatch &M : Mismatches)
+ Diags.Report(diag::note_incompatible_host_and_device_type)
+ << M.Which << M.TypeName << M.HostBits / getCharWidth()
+ << Required / getCharWidth();
- return true;
+ return false;
}
/// CreateTargetInfo - Return the target info object for the specified target
@@ -908,8 +923,8 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
Target->TargetOpts = Opts;
// Targets that adapt in their constructor have done so by now.
- if (!Target->checkHostPointerRelatedTypes(
- Diags, llvm::Triple(Opts->HostTriple), HostAdaptation::Constructor))
+ if (!Target->checkHostCompatibility(Diags, llvm::Triple(Opts->HostTriple),
+ HostAdaptation::Constructor))
return nullptr;
// Set the target CPU if specified.
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index 54ca09f1b793a6..ac075e9de5f96f 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -1168,10 +1168,11 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
if (TargetInfo::adaptsToHostTarget(Target, HostTriple) &&
Target.getArchPointerBitWidth() !=
HostTriple.getArchPointerBitWidth()) {
- Diag(diag::err_target_unsupported_host_pointer_related_type)
- << Target.str() << HostTriple.str() << /*pointer width*/ 0
- << HostTriple.getArchPointerBitWidth()
- << Target.getArchPointerBitWidth();
+ Diag(diag::err_incompatible_host_and_device_targets)
+ << Target.str() << HostTriple.str();
+ Diag(diag::note_incompatible_host_and_device_type)
+ << /*size*/ 1 << "void *" << HostTriple.getArchPointerBitWidth() / 8
+ << Target.getArchPointerBitWidth() / 8;
continue;
}
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index 6ed32d91f4f247..cad0215ae32340 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -170,7 +170,7 @@ bool CompilerInstance::createTarget() {
if (auto *Aux = getAuxTarget()) {
getTarget().setAuxTarget(Aux);
- if (!getTarget().checkHostPointerRelatedTypes(
+ if (!getTarget().checkHostCompatibility(
getDiagnostics(), Aux->getTriple(),
TargetInfo::HostAdaptation::SetAuxTarget))
return false;
diff --git a/clang/test/Driver/offload-pointer-width-mismatch.c b/clang/test/Driver/offload-pointer-width-mismatch.c
index 98fd079d5edae8..9fefa4df9f17b1 100644
--- a/clang/test/Driver/offload-pointer-width-mismatch.c
+++ b/clang/test/Driver/offload-pointer-width-mismatch.c
@@ -20,9 +20,14 @@
// RUN: not %clang -### --target=i386-unknown-linux-gnu -fopenmp --offload-arch=gfx906 \
// RUN: -nogpulib -nogpuinc -c %s 2>&1 | FileCheck --check-prefix=AMDGPU %s
-// AMDGPU: error: device target 'amdgpu-amd-amdhsa' takes a pointer width of 32 bits from host target 'i386-unknown-linux-gnu', but requires 64 bits
-// NVPTX: error: device target 'nvptx64-nvidia-cuda' takes a pointer width of 32 bits from host target 'i386-unknown-linux-gnu', but requires 64 bits
-// SPIRV32: error: device target 'spirv32-unknown-unknown' takes a pointer width of 64 bits from host target 'x86_64-unknown-linux-gnu', but requires 32 bits
+// The driver only knows the triples, so it notes the pointer size alone.
+
+// AMDGPU: error: device target 'amdgpu-amd-amdhsa' is not compatible with host target 'i386-unknown-linux-gnu'
+// AMDGPU-NEXT: note: size of type 'void *' for the host target (4 bytes) does not match the size for the device target (8 bytes)
+// NVPTX: error: device target 'nvptx64-nvidia-cuda' is not compatible with host target 'i386-unknown-linux-gnu'
+// NVPTX-NEXT: note: size of type 'void *' for the host target (4 bytes) does not match the size for the device target (8 bytes)
+// SPIRV32: error: device target 'spirv32-unknown-unknown' is not compatible with host target 'x86_64-unknown-linux-gnu'
+// SPIRV32-NEXT: note: size of type 'void *' for the host target (8 bytes) does not match the size for the device target (4 bytes)
// RUN: %clang -### --target=x86_64-unknown-linux-gnu -x hip --offload-arch=gfx906 \
// RUN: -nogpulib -nogpuinc -c %s 2>&1 | FileCheck --check-prefix=OK %s
diff --git a/clang/test/Frontend/offload-pointer-width-mismatch.cpp b/clang/test/Frontend/offload-pointer-width-mismatch.cpp
index 4d1107079253cf..9ad94417a115f9 100644
--- a/clang/test/Frontend/offload-pointer-width-mismatch.cpp
+++ b/clang/test/Frontend/offload-pointer-width-mismatch.cpp
@@ -12,11 +12,23 @@
// RUN: not %clang_cc1 -triple spirv64-unknown-unknown -aux-triple i386-unknown-linux-gnu \
// RUN: -fsycl-is-device -fsyntax-only %s 2>&1 | FileCheck --check-prefix=SPIRV %s
-// AMDGCN: error: device target 'amdgcn-amd-amdhsa' takes a pointer width of 32 bits from host target 'i386-unknown-linux-gnu', but requires 64 bits
-// R600: error: device target 'r600-unknown-unknown' takes a pointer width of 64 bits from host target 'x86_64-unknown-linux-gnu', but requires 32 bits
-// NVPTX: error: device target 'nvptx64-nvidia-cuda' takes a pointer width of 32 bits from host target 'i386-unknown-linux-gnu', but requires 64 bits
-// SPIR: error: device target 'spir-unknown-unknown' takes a pointer width of 64 bits from host target 'x86_64-unknown-linux-gnu', but requires 32 bits
-// SPIRV: error: device target 'spirv64-unknown-unknown' takes a pointer width of 32 bits from host target 'i386-unknown-linux-gnu', but requires 64 bits
+// Every type that disagrees with the device data layout is noted.
+
+// AMDGCN: error: device target 'amdgcn-amd-amdhsa' is not compatible with host target 'i386-unknown-linux-gnu'
+// AMDGCN-NEXT: note: size of type 'void *' for the host target (4 bytes) does not match the size for the device target (8 bytes)
+// AMDGCN-NEXT: note: alignment of type 'void *' for the host target (4 bytes) does not match the alignment for the device target (8 bytes)
+// AMDGCN-NEXT: note: size of type 'size_t' for the host target (4 bytes) does not match the size for the device target (8 bytes)
+// AMDGCN-NEXT: note: size of type 'ptrdiff_t' for the host target (4 bytes) does not match the size for the device target (8 bytes)
+// AMDGCN-NEXT: note: size of type 'intptr_t' for the host target (4 bytes) does not match the size for the device target (8 bytes)
+
+// R600: error: device target 'r600-unknown-unknown' is not compatible with host target 'x86_64-unknown-linux-gnu'
+// R600-NEXT: note: size of type 'void *' for the host target (8 bytes) does not match the size for the device target (4 bytes)
+// NVPTX: error: device target 'nvptx64-nvidia-cuda' is not compatible with host target 'i386-unknown-linux-gnu'
+// NVPTX-NEXT: note: size of type 'void *' for the host target (4 bytes) does not match the size for the device target (8 bytes)
+// SPIR: error: device target 'spir-unknown-unknown' is not compatible with host target 'x86_64-unknown-linux-gnu'
+// SPIR-NEXT: note: size of type 'void *' for the host target (8 bytes) does not match the size for the device target (4 bytes)
+// SPIRV: error: device target 'spirv64-unknown-unknown' is not compatible with host target 'i386-unknown-linux-gnu'
+// SPIRV-NEXT: note: size of type 'void *' for the host target (4 bytes) does not match the size for the device target (8 bytes)
// OpenMP device compilation adapts at both stages too.
@@ -36,9 +48,12 @@
// RUN: not %clang_cc1 -triple spirv64-amd-amdhsa -aux-triple spir-unknown-unknown \
// RUN: -fsycl-is-device -fsyntax-only %s 2>&1 | FileCheck --check-prefix=AMDHSA-SPIR %s
-// SPIRV-NVPTX: error: device target 'spirv64-unknown-unknown' takes a pointer width of 32 bits from host target 'nvptx-nvidia-cuda', but requires 64 bits
-// AMDGCN-R600: error: device target 'amdgcn-amd-amdhsa' takes a pointer width of 32 bits from host target 'r600-unknown-unknown', but requires 64 bits
-// AMDHSA-SPIR: error: device target 'spirv64-amd-amdhsa' takes a pointer width of 32 bits from host target 'spir-unknown-unknown', but requires 64 bits
+// SPIRV-NVPTX: error: device target 'spirv64-unknown-unknown' is not compatible with host target 'nvptx-nvidia-cuda'
+// SPIRV-NVPTX-NEXT: note: size of type 'void *' for the host target (4 bytes) does not match the size for the device target (8 bytes)
+// AMDGCN-R600: error: device target 'amdgcn-amd-amdhsa' is not compatible with host target 'r600-unknown-unknown'
+// AMDGCN-R600-NEXT: note: size of type 'void *' for the host target (4 bytes) does not match the size for the device target (8 bytes)
+// AMDHSA-SPIR: error: device target 'spirv64-amd-amdhsa' is not compatible with host target 'spir-unknown-unknown'
+// AMDHSA-SPIR-NEXT: note: size of type 'void *' for the host target (4 bytes) does not match the size for the device target (8 bytes)
// The host pointer width is taken from the host target rather than from its
// triple, so an ABI that narrows pointers is caught too.
@@ -50,9 +65,12 @@
// RUN: not %clang_cc1 -triple amdgcn-amd-amdhsa -aux-triple x86_64-unknown-linux-gnux32 \
// RUN: -fcuda-is-device -fsyntax-only -x hip %s 2>&1 | FileCheck --check-prefix=AMDGCN-X32 %s
-// SPIR64-X32: error: device target 'spir64-unknown-unknown' takes a pointer width of 32 bits from host target 'x86_64-unknown-linux-gnux32', but requires 64 bits
-// NVPTX64-X32: error: device target 'nvptx64-nvidia-cuda' takes a pointer width of 32 bits from host target 'x86_64-unknown-linux-gnux32', but requires 64 bits
-// AMDGCN-X32: error: device target 'amdgcn-amd-amdhsa' takes a pointer width of 32 bits from host target 'x86_64-unknown-linux-gnux32', but requires 64 bits
+// SPIR64-X32: error: device target 'spir64-unknown-unknown' is not compatible with host target 'x86_64-unknown-linux-gnux32'
+// SPIR64-X32-NEXT: note: size of type 'void *' for the host target (4 bytes) does not match the size for the device target (8 bytes)
+// NVPTX64-X32: error: device target 'nvptx64-nvidia-cuda' is not compatible with host target 'x86_64-unknown-linux-gnux32'
+// NVPTX64-X32-NEXT: note: size of type 'void *' for the host target (4 bytes) does not match the size for the device target (8 bytes)
+// AMDGCN-X32: error: device target 'amdgcn-amd-amdhsa' is not compatible with host target 'x86_64-unknown-linux-gnux32'
+// AMDGCN-X32-NEXT: note: size of type 'void *' for the host target (4 bytes) does not match the size for the device target (8 bytes)
// NVPTX and AMDGPU take the pointer alignment from the host too, so a host that
// under aligns pointers is a mismatch even where the widths agree.
@@ -62,8 +80,14 @@
// RUN: not %clang_cc1 -triple r600-unknown-unknown -aux-triple m68k-unknown-linux-gnu \
// RUN: -fcuda-is-device -fsyntax-only -x hip %s 2>&1 | FileCheck --check-prefix=R600-M68K %s
-// NVPTX-M68K: error: device target 'nvptx-nvidia-cuda' takes a pointer alignment of 16 bits from host target 'm68k-unknown-linux-gnu', but requires 32 bits
-// R600-M68K: error: device target 'r600-unknown-unknown' takes a pointer alignment of 16 bits from host target 'm68k-unknown-linux-gnu', but requires 32 bits
+// The alignment is then the only type detail noted.
+
+// NVPTX-M68K: error: device target 'nvptx-nvidia-cuda' is not compatible with host target 'm68k-unknown-linux-gnu'
+// NVPTX-M68K-NEXT: note: alignment of type 'void *' for the host target (2 bytes) does not match the alignment for the device target (4 bytes)
+// NVPTX-M68K-NOT: note:
+// R600-M68K: error: device target 'r600-unknown-unknown' is not compatible with host target 'm68k-unknown-linux-gnu'
+// R600-M68K-NEXT: note: alignment of type 'void *' for the host target (2 bytes) does not match the alignment for the device target (4 bytes)
+// R600-M68K-NOT: note:
// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -aux-triple x86_64-unknown-linux-gnu \
// RUN: -fcuda-is-device -fsyntax-only -x hip %s
>From d3cd49ebde2cadbb69777622e3c7d69f63dedf0f Mon Sep 17 00:00:00 2001
From: Sindhu Chittireddy <sindhu.chittireddy at intel.com>
Date: Tue, 1 Sep 2026 10:40:29 -0700
Subject: [PATCH 6/8] [clang] Check the built device target instead of tracking
adaptation
---
clang/include/clang/Basic/TargetInfo.h | 35 +++------------
clang/lib/Basic/Targets.cpp | 44 +++----------------
clang/lib/Driver/Driver.cpp | 15 -------
clang/lib/Frontend/CompilerInstance.cpp | 6 +--
.../Driver/offload-pointer-width-mismatch.c | 44 +++++++------------
5 files changed, 33 insertions(+), 111 deletions(-)
diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h
index 741b0cc3852c08..d3a98eb1018bde 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -326,35 +326,14 @@ class TargetInfo : public TransferrableTargetInfo,
static TargetInfo *CreateTargetInfo(DiagnosticsEngine &Diags,
TargetOptions &Opts);
- /// When a device target takes its pointer related types (the pointer width
- /// and alignment, size_t, ptrdiff_t, and intptr_t) from a host target.
- enum class HostAdaptation {
- /// It keeps its own pointer related types.
- None,
- /// It adapts in its constructor, from TargetOptions::HostTriple.
- Constructor,
- SetAuxTarget,
- };
-
- /// Returns when the device target takes its pointer related types from the
- /// host target, mirroring the conditions under which the TargetInfo
- /// subclasses adapt. A device that declines a host keeps its own types, which
- /// the driver's triple level check must not report as a mismatch.
- static HostAdaptation getHostAdaptation(const llvm::Triple &DeviceTriple,
- const llvm::Triple &HostTriple);
-
- static bool adaptsToHostTarget(const llvm::Triple &DeviceTriple,
- const llvm::Triple &HostTriple) {
- return getHostAdaptation(DeviceTriple, HostTriple) != HostAdaptation::None;
- }
-
- /// Reports an error, and a note per offending type, if this target adapts to
- /// the given host target at the given stage and ended up with pointer related
- /// types that disagree with its own data layout. Does nothing if it does not
- /// adapt at that stage. Returns true if no error was reported.
+ /// Reports an error, and a note per offending type, if a pointer related type
+ /// (the pointer size and alignment, size_t, ptrdiff_t, and intptr_t) that
+ /// this device target took from the given host target disagrees with its own
+ /// data layout. Returns true if no error was reported. Call this once the
+ /// target has taken whatever it takes from the host target, that is, after
+ /// setAuxTarget().
bool checkHostCompatibility(DiagnosticsEngine &Diags,
- const llvm::Triple &HostTriple,
- HostAdaptation Stage) const;
+ const llvm::Triple &HostTriple) const;
virtual ~TargetInfo();
diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp
index 81608ef3d06263..eccd91d14778bf 100644
--- a/clang/lib/Basic/Targets.cpp
+++ b/clang/lib/Basic/Targets.cpp
@@ -836,42 +836,15 @@ std::unique_ptr<TargetInfo> AllocateTarget(const llvm::Triple &Triple,
using namespace clang::targets;
-TargetInfo::HostAdaptation
-TargetInfo::getHostAdaptation(const llvm::Triple &DeviceTriple,
- const llvm::Triple &HostTriple) {
- // No recognizable host triple, so nothing to adapt to.
- if (HostTriple.getArch() == llvm::Triple::UnknownArch)
- return HostAdaptation::None;
-
- // setAuxTarget() overwrites these, so constructor values are not yet final.
- if (DeviceTriple.isAMDGPU() ||
- (DeviceTriple.getArch() == llvm::Triple::spirv64 &&
- DeviceTriple.getOS() == llvm::Triple::AMDHSA))
- return HostAdaptation::SetAuxTarget;
-
- // Logical SPIR-V sets these itself, with a 32-bit size_t by design.
- if (DeviceTriple.isSPIRVLogical())
- return HostAdaptation::None;
-
- if (DeviceTriple.isSPIROrSPIRV())
- return HostTriple.isSPIROrSPIRV() ? HostAdaptation::None
- : HostAdaptation::Constructor;
- if (DeviceTriple.isNVPTX())
- return HostTriple.isNVPTX() ? HostAdaptation::None
- : HostAdaptation::Constructor;
-
- return HostAdaptation::None;
-}
-
bool TargetInfo::checkHostCompatibility(DiagnosticsEngine &Diags,
- const llvm::Triple &HostTriple,
- HostAdaptation Stage) const {
- assert(Stage != HostAdaptation::None && "Nothing to check");
- if (getHostAdaptation(getTriple(), HostTriple) != Stage)
+ const llvm::Triple &HostTriple) const {
+ // Logical SPIR-V has no pointer size to require.
+ if (getTriple().isSPIRVLogical())
return true;
- // The device data layout fixes the size and the alignment of a pointer, and
- // with them the width of every integer type that has to hold one.
+ // Whatever this target took from the host target, it has to hold a pointer,
+ // whose size and alignment its own data layout fixes. A target that took
+ // nothing agrees with itself and is reported here in no case.
unsigned Required = getTriple().getArchPointerBitWidth();
struct Mismatch {
unsigned Which;
@@ -922,11 +895,6 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
}
Target->TargetOpts = Opts;
- // Targets that adapt in their constructor have done so by now.
- if (!Target->checkHostCompatibility(Diags, llvm::Triple(Opts->HostTriple),
- HostAdaptation::Constructor))
- return nullptr;
-
// Set the target CPU if specified.
if (!Opts->CPU.empty() && !Target->setCPU(Opts->CPU)) {
Diags.Report(diag::err_target_unknown_cpu) << Opts->CPU;
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index ac075e9de5f96f..f06f1c5a75ff81 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -55,7 +55,6 @@
#include "ToolChains/ZOS.h"
#include "clang/Basic/DiagnosticDriver.h"
#include "clang/Basic/TargetID.h"
-#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Version.h"
#include "clang/Config/config.h"
#include "clang/Driver/Action.h"
@@ -1162,20 +1161,6 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
continue;
}
- // A triple level approximation that catches the common cases early; the
- // types are checked once the device adapts.
- const llvm::Triple &HostTriple = C.getDefaultToolChain().getTriple();
- if (TargetInfo::adaptsToHostTarget(Target, HostTriple) &&
- Target.getArchPointerBitWidth() !=
- HostTriple.getArchPointerBitWidth()) {
- Diag(diag::err_incompatible_host_and_device_targets)
- << Target.str() << HostTriple.str();
- Diag(diag::note_incompatible_host_and_device_type)
- << /*size*/ 1 << "void *" << HostTriple.getArchPointerBitWidth() / 8
- << Target.getArchPointerBitWidth() / 8;
- continue;
- }
-
std::string NormalizedName = Target.normalize();
auto [TripleIt, Inserted] =
FoundNormalizedTriples.try_emplace(NormalizedName, Target.str());
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index cad0215ae32340..b3eef5301e41af 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -170,9 +170,9 @@ bool CompilerInstance::createTarget() {
if (auto *Aux = getAuxTarget()) {
getTarget().setAuxTarget(Aux);
- if (!getTarget().checkHostCompatibility(
- getDiagnostics(), Aux->getTriple(),
- TargetInfo::HostAdaptation::SetAuxTarget))
+ // The target has taken everything it takes from the host target by now.
+ if (getLangOpts().isTargetDevice() &&
+ !getTarget().checkHostCompatibility(getDiagnostics(), Aux->getTriple()))
return false;
}
diff --git a/clang/test/Driver/offload-pointer-width-mismatch.c b/clang/test/Driver/offload-pointer-width-mismatch.c
index 9fefa4df9f17b1..d443c80613efe7 100644
--- a/clang/test/Driver/offload-pointer-width-mismatch.c
+++ b/clang/test/Driver/offload-pointer-width-mismatch.c
@@ -1,36 +1,26 @@
-// Offload targets that take their pointer related types from the host target
-// are rejected early, before any compilation job is built.
+// An offload compilation whose device target takes its pointer related types
+// from an incompatible host target fails when the device compilation runs.
-// RUN: not %clang -### --target=i386-unknown-linux-gnu -x hip --offload-arch=gfx906 \
-// RUN: -nogpulib -nogpuinc -c %s 2>&1 | FileCheck --check-prefix=AMDGPU %s
-// RUN: not %clang -### --target=i386-unknown-linux-gnu -x cuda --offload=nvptx64-nvidia-cuda \
-// RUN: --offload-arch=sm_60 -nogpulib -nogpuinc -c %s 2>&1 | FileCheck --check-prefix=NVPTX %s
-// RUN: not %clang -### --target=x86_64-unknown-linux-gnu -x cuda --cuda-device-only \
-// RUN: -nogpulib -nogpuinc --offload=spirv32-unknown-unknown -c %s 2>&1 \
-// RUN: | FileCheck --check-prefix=SPIRV32 %s
-// RUN: not %clang -### --target=i386-unknown-linux-gnu -x cuda \
-// RUN: --offload-targets=nvptx64-nvidia-cuda --offload-arch=sm_60 -nogpulib -nogpuinc \
-// RUN: -c %s 2>&1 | FileCheck --check-prefix=NVPTX %s
+// REQUIRES: amdgpu-registered-target, nvptx-registered-target
-// OpenMP offloading reaches the same check.
-
-// RUN: not %clang -### --target=i386-unknown-linux-gnu -fopenmp \
-// RUN: -fopenmp-targets=nvptx64-nvidia-cuda -nogpulib -nogpuinc -c %s 2>&1 \
+// RUN: not %clang --target=i386-unknown-linux-gnu -x hip --offload-arch=gfx906 \
+// RUN: -nogpulib -nogpuinc -fsyntax-only %s 2>&1 | FileCheck --check-prefix=AMDGPU %s
+// RUN: not %clang --target=i386-unknown-linux-gnu -x cuda --offload=nvptx64-nvidia-cuda \
+// RUN: --offload-arch=sm_60 -nogpulib -nogpuinc -fsyntax-only %s 2>&1 \
// RUN: | FileCheck --check-prefix=NVPTX %s
-// RUN: not %clang -### --target=i386-unknown-linux-gnu -fopenmp --offload-arch=gfx906 \
-// RUN: -nogpulib -nogpuinc -c %s 2>&1 | FileCheck --check-prefix=AMDGPU %s
-
-// The driver only knows the triples, so it notes the pointer size alone.
+// RUN: not %clang --target=i386-unknown-linux-gnu -fopenmp \
+// RUN: -fopenmp-targets=nvptx64-nvidia-cuda --offload-arch=sm_60 -nogpulib -nogpuinc \
+// RUN: -fsyntax-only %s 2>&1 | FileCheck --check-prefix=NVPTX %s
-// AMDGPU: error: device target 'amdgpu-amd-amdhsa' is not compatible with host target 'i386-unknown-linux-gnu'
+// AMDGPU: error: device target 'amdgpu9.06-amd-amdhsa' is not compatible with host target 'i386-unknown-linux-gnu'
// AMDGPU-NEXT: note: size of type 'void *' for the host target (4 bytes) does not match the size for the device target (8 bytes)
// NVPTX: error: device target 'nvptx64-nvidia-cuda' is not compatible with host target 'i386-unknown-linux-gnu'
// NVPTX-NEXT: note: size of type 'void *' for the host target (4 bytes) does not match the size for the device target (8 bytes)
-// SPIRV32: error: device target 'spirv32-unknown-unknown' is not compatible with host target 'x86_64-unknown-linux-gnu'
-// SPIRV32-NEXT: note: size of type 'void *' for the host target (8 bytes) does not match the size for the device target (4 bytes)
-// RUN: %clang -### --target=x86_64-unknown-linux-gnu -x hip --offload-arch=gfx906 \
-// RUN: -nogpulib -nogpuinc -c %s 2>&1 | FileCheck --check-prefix=OK %s
+// A host target of a matching pointer width is accepted, and so is the 32-bit
+// device target that a 32-bit host selects by default.
-// OK-NOT: error:
-// OK: "-cc1" "-triple" "amdgpu9.06-amd-amdhsa" "-aux-triple" "x86_64-unknown-linux-gnu"
+// RUN: %clang --target=x86_64-unknown-linux-gnu -x hip --offload-arch=gfx906 \
+// RUN: -nogpulib -nogpuinc -fsyntax-only %s
+// RUN: %clang --target=i386-unknown-linux-gnu -x cuda --offload-arch=sm_60 \
+// RUN: -nogpulib -nogpuinc -fsyntax-only %s
>From 1ceb1fb76a28c00b7c02b120e940a9fd712c723b Mon Sep 17 00:00:00 2001
From: Sindhu Chittireddy <sindhu.chittireddy at intel.com>
Date: Tue, 1 Sep 2026 12:12:47 -0700
Subject: [PATCH 7/8] [clang] Take the auxiliary target compatibility check to
its own interface
---
clang/include/clang/Basic/TargetInfo.h | 12 ++++--------
clang/lib/Basic/Targets.cpp | 17 +++++++++++------
clang/lib/Frontend/CompilerInstance.cpp | 6 +++---
3 files changed, 18 insertions(+), 17 deletions(-)
diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h
index d3a98eb1018bde..b2c0d870324a22 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -326,14 +326,10 @@ class TargetInfo : public TransferrableTargetInfo,
static TargetInfo *CreateTargetInfo(DiagnosticsEngine &Diags,
TargetOptions &Opts);
- /// Reports an error, and a note per offending type, if a pointer related type
- /// (the pointer size and alignment, size_t, ptrdiff_t, and intptr_t) that
- /// this device target took from the given host target disagrees with its own
- /// data layout. Returns true if no error was reported. Call this once the
- /// target has taken whatever it takes from the host target, that is, after
- /// setAuxTarget().
- bool checkHostCompatibility(DiagnosticsEngine &Diags,
- const llvm::Triple &HostTriple) const;
+ /// Diagnoses the pointer related types that this target took from its
+ /// auxiliary target if they disagree with its own data layout. Returns true
+ /// if no error was reported. Call after setAuxTarget().
+ bool checkAuxTargetCompatibility(DiagnosticsEngine &Diags) const;
virtual ~TargetInfo();
diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp
index eccd91d14778bf..fe46d979152aad 100644
--- a/clang/lib/Basic/Targets.cpp
+++ b/clang/lib/Basic/Targets.cpp
@@ -836,15 +836,20 @@ std::unique_ptr<TargetInfo> AllocateTarget(const llvm::Triple &Triple,
using namespace clang::targets;
-bool TargetInfo::checkHostCompatibility(DiagnosticsEngine &Diags,
- const llvm::Triple &HostTriple) const {
+bool TargetInfo::checkAuxTargetCompatibility(DiagnosticsEngine &Diags) const {
+ // Only a device target takes its pointer related types from another target,
+ // and only such a target is given the triple of the target it takes them
+ // from.
+ StringRef HostTriple = getTargetOpts().HostTriple;
+ if (HostTriple.empty())
+ return true;
+
// Logical SPIR-V has no pointer size to require.
if (getTriple().isSPIRVLogical())
return true;
- // Whatever this target took from the host target, it has to hold a pointer,
- // whose size and alignment its own data layout fixes. A target that took
- // nothing agrees with itself and is reported here in no case.
+ // These getters return what the target took from the host, so a disagreement
+ // with the width its own data layout fixes is a host/device mismatch.
unsigned Required = getTriple().getArchPointerBitWidth();
struct Mismatch {
unsigned Which;
@@ -870,7 +875,7 @@ bool TargetInfo::checkHostCompatibility(DiagnosticsEngine &Diags,
return true;
Diags.Report(diag::err_incompatible_host_and_device_targets)
- << getTriple().str() << HostTriple.str();
+ << getTriple().str() << HostTriple;
for (const Mismatch &M : Mismatches)
Diags.Report(diag::note_incompatible_host_and_device_type)
<< M.Which << M.TypeName << M.HostBits / getCharWidth()
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index b3eef5301e41af..a1784bdd1cd937 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -170,9 +170,9 @@ bool CompilerInstance::createTarget() {
if (auto *Aux = getAuxTarget()) {
getTarget().setAuxTarget(Aux);
- // The target has taken everything it takes from the host target by now.
- if (getLangOpts().isTargetDevice() &&
- !getTarget().checkHostCompatibility(getDiagnostics(), Aux->getTriple()))
+ // The target has taken everything it takes from the auxiliary target by
+ // now, which TargetInfo::adjust() above is too early for.
+ if (!getTarget().checkAuxTargetCompatibility(getDiagnostics()))
return false;
}
>From 747dccfa0e2efdac53446430697781ada012e0a4 Mon Sep 17 00:00:00 2001
From: Sindhu Chittireddy <sindhu.chittireddy at intel.com>
Date: Wed, 2 Sep 2026 07:24:14 -0700
Subject: [PATCH 8/8] [clang] Add asserts on SPIR and SPIR-V target pointer
types/sizes
---
clang/lib/Basic/Targets/SPIR.h | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/clang/lib/Basic/Targets/SPIR.h b/clang/lib/Basic/Targets/SPIR.h
index 7c36ac5e0ef36d..73ff5030320782 100644
--- a/clang/lib/Basic/Targets/SPIR.h
+++ b/clang/lib/Basic/Targets/SPIR.h
@@ -253,6 +253,12 @@ class LLVM_LIBRARY_VISIBILITY SPIR32TargetInfo : public SPIRTargetInfo {
PointerWidth = PointerAlign = 32;
SizeType = TargetInfo::UnsignedInt;
PtrDiffType = IntPtrType = TargetInfo::SignedInt;
+
+ assert(PointerWidth == 32);
+ assert(PointerAlign == 32);
+ assert(getTypeWidth(SizeType) == 32);
+ assert(getTypeWidth(PtrDiffType) == 32);
+ assert(getTypeWidth(IntPtrType) == 32);
}
// SPIR32 has support for atomic ops if atomic extension is enabled.
@@ -276,6 +282,11 @@ class LLVM_LIBRARY_VISIBILITY SPIR64TargetInfo : public SPIRTargetInfo {
PointerWidth = PointerAlign = 64;
SizeType = TargetInfo::UnsignedLong;
PtrDiffType = IntPtrType = TargetInfo::SignedLong;
+ assert(PointerWidth == 64);
+ assert(PointerAlign == 64);
+ assert(getTypeWidth(SizeType) == 64);
+ assert(getTypeWidth(PtrDiffType) == 64);
+ assert(getTypeWidth(IntPtrType) == 64);
}
// SPIR64 has support for atomic ops if atomic extension is enabled.
@@ -370,6 +381,11 @@ class LLVM_LIBRARY_VISIBILITY SPIRV32TargetInfo : public BaseSPIRVTargetInfo {
PointerWidth = PointerAlign = 32;
SizeType = TargetInfo::UnsignedInt;
PtrDiffType = IntPtrType = TargetInfo::SignedInt;
+ assert(PointerWidth == 32);
+ assert(PointerAlign == 32);
+ assert(getTypeWidth(SizeType) == 32);
+ assert(getTypeWidth(PtrDiffType) == 32);
+ assert(getTypeWidth(IntPtrType) == 32);
}
// SPIR-V has core support for atomic ops, and Int32 is always available;
@@ -398,6 +414,11 @@ class LLVM_LIBRARY_VISIBILITY SPIRV64TargetInfo : public BaseSPIRVTargetInfo {
PointerWidth = PointerAlign = 64;
SizeType = TargetInfo::UnsignedLong;
PtrDiffType = IntPtrType = TargetInfo::SignedLong;
+ assert(PointerWidth == 64);
+ assert(PointerAlign == 64);
+ assert(getTypeWidth(SizeType) == 64);
+ assert(getTypeWidth(PtrDiffType) == 64);
+ assert(getTypeWidth(IntPtrType) == 64);
}
// SPIR-V has core support for atomic ops, and Int64 is always available;
@@ -445,6 +466,17 @@ class LLVM_LIBRARY_VISIBILITY SPIRV64AMDGCNTargetInfo final
PointerWidth = PointerAlign = 64;
SizeType = TargetInfo::UnsignedLong;
PtrDiffType = IntPtrType = TargetInfo::SignedLong;
+
+ // With a host target the widths above are the host's until setAuxTarget()
+ // replaces them, so only what this target sets itself is asserted.
+ if (!getHostTarget()) {
+ assert(PointerWidth == 64);
+ assert(PointerAlign == 64);
+ assert(getTypeWidth(SizeType) == 64);
+ assert(getTypeWidth(PtrDiffType) == 64);
+ assert(getTypeWidth(IntPtrType) == 64);
+ }
+
AddrSpaceMap = &SPIRDefIsGenMap;
resetDataLayout();
More information about the cfe-commits
mailing list