https://github.com/lfmeadow updated https://github.com/llvm/llvm-project/pull/225162
>From c35fcf6cae91e0084ffbbbfcd0c05a2bb74bea42 Mon Sep 17 00:00:00 2001 From: Larry Meadows <[email protected]> Date: Mon, 21 Sep 2026 13:40:33 -0500 Subject: [PATCH] [clang][OpenMP] Don't put HIP's ::min and ::max in an OpenMP TU __clang_hip_math.h defines templated ::min and ::max for CUDA source compatibility. The OpenMP math wrapper includes that header for the amdgcn device pass, so an OpenMP translation unit -- ordinary C++ that never opted into HIP -- gets them too, and an unqualified min(a, b) after `using namespace std` becomes ambiguous against std::min. Guard them with __OPENMP_AMDGCN__, matching the host min/max block below, which is already excluded from OpenMP for the same reason. Co-authored-by: Cursor <[email protected]> --- clang/lib/Headers/__clang_hip_math.h | 2 + .../test/Headers/amdgcn_openmp_device_math.c | 53 ++++++++++++++++--- 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/clang/lib/Headers/__clang_hip_math.h b/clang/lib/Headers/__clang_hip_math.h index f0e6d46ed0af4a..c1fc112c95a4c1 100644 --- a/clang/lib/Headers/__clang_hip_math.h +++ b/clang/lib/Headers/__clang_hip_math.h @@ -1284,6 +1284,7 @@ double __fma_rn(double __x, double __y, double __z) { #endif // !defined(__cplusplus) && __STDC_VERSION__ >= 201112L #if defined(__cplusplus) +#ifndef __OPENMP_AMDGCN__ template <class T> __DEVICE__ T min(T __arg1, T __arg2) { return (__arg1 < __arg2) ? __arg1 : __arg2; } @@ -1291,6 +1292,7 @@ template <class T> __DEVICE__ T min(T __arg1, T __arg2) { template <class T> __DEVICE__ T max(T __arg1, T __arg2) { return (__arg1 > __arg2) ? __arg1 : __arg2; } +#endif __DEVICE__ int min(int __arg1, int __arg2) { return (__arg1 < __arg2) ? __arg1 : __arg2; diff --git a/clang/test/Headers/amdgcn_openmp_device_math.c b/clang/test/Headers/amdgcn_openmp_device_math.c index d653b1c03cb19d..52e9a476f6e0e1 100644 --- a/clang/test/Headers/amdgcn_openmp_device_math.c +++ b/clang/test/Headers/amdgcn_openmp_device_math.c @@ -5,6 +5,7 @@ // RUN: %clang_cc1 -internal-isystem %S/../../lib/Headers/openmp_wrappers -include __clang_openmp_device_functions.h -internal-isystem %S/../../lib/Headers/openmp_wrappers -internal-isystem %S/Inputs/include -x c++ -fopenmp -triple amdgpu-amd-amdhsa -aux-triple x86_64-unknown-unknown -fopenmp-targets=amdgpu-amd-amdhsa -emit-llvm %s -fopenmp-is-target-device -fopenmp-host-ir-file-path %t-host.bc -o - | FileCheck %s --check-prefixes=CHECK,CHECK-CPP #ifdef __cplusplus +#include <algorithm> #include <cmath> #else #include <math.h> @@ -100,13 +101,13 @@ // CHECK-CPP-NEXT: [[__X_ADDR_ASCAST_I:%.*]] = addrspacecast ptr addrspace(5) [[__X_ADDR_I]] to ptr // CHECK-CPP-NEXT: store double [[TMP0]], ptr [[__X_ADDR_ASCAST_I]], align 8 // CHECK-CPP-NEXT: [[TMP1:%.*]] = load double, ptr [[__X_ADDR_ASCAST_I]], align 8 -// CHECK-CPP-NEXT: [[CALL_I:%.*]] = call noundef double @__ocml_sin_f64(double noundef [[TMP1]]) #[[ATTR3:[0-9]+]] +// CHECK-CPP-NEXT: [[CALL_I:%.*]] = call noundef double @__ocml_sin_f64(double noundef [[TMP1]]) #[[ATTR5:[0-9]+]] // CHECK-CPP-NEXT: store double [[CALL_I]], ptr [[L1_ASCAST]], align 8 // CHECK-CPP-NEXT: [[TMP2:%.*]] = load double, ptr [[X_ADDR_ASCAST]], align 8 // CHECK-CPP-NEXT: [[__X_ADDR_ASCAST_I5:%.*]] = addrspacecast ptr addrspace(5) [[__X_ADDR_I4]] to ptr // CHECK-CPP-NEXT: store double [[TMP2]], ptr [[__X_ADDR_ASCAST_I5]], align 8 // CHECK-CPP-NEXT: [[TMP3:%.*]] = load double, ptr [[__X_ADDR_ASCAST_I5]], align 8 -// CHECK-CPP-NEXT: [[CALL_I6:%.*]] = call noundef double @__ocml_cos_f64(double noundef [[TMP3]]) #[[ATTR3]] +// CHECK-CPP-NEXT: [[CALL_I6:%.*]] = call noundef double @__ocml_cos_f64(double noundef [[TMP3]]) #[[ATTR5]] // CHECK-CPP-NEXT: store double [[CALL_I6]], ptr [[L2_ASCAST]], align 8 // CHECK-CPP-NEXT: [[TMP4:%.*]] = load double, ptr [[X_ADDR_ASCAST]], align 8 // CHECK-CPP-NEXT: [[__X_ADDR_ASCAST_I8:%.*]] = addrspacecast ptr addrspace(5) [[__X_ADDR_I7]] to ptr @@ -244,7 +245,7 @@ void test_math_f64(double x, double y, double z) { // CHECK-CPP-NEXT: [[__X_ADDR_ASCAST_I14:%.*]] = addrspacecast ptr addrspace(5) [[__X_ADDR_I13]] to ptr // CHECK-CPP-NEXT: store float [[TMP1]], ptr [[__X_ADDR_ASCAST_I14]], align 4 // CHECK-CPP-NEXT: [[TMP2:%.*]] = load float, ptr [[__X_ADDR_ASCAST_I14]], align 4 -// CHECK-CPP-NEXT: [[CALL_I15:%.*]] = call noundef float @__ocml_sin_f32(float noundef [[TMP2]]) #[[ATTR3]] +// CHECK-CPP-NEXT: [[CALL_I15:%.*]] = call noundef float @__ocml_sin_f32(float noundef [[TMP2]]) #[[ATTR5]] // CHECK-CPP-NEXT: store float [[CALL_I15]], ptr [[L1_ASCAST]], align 4 // CHECK-CPP-NEXT: [[TMP3:%.*]] = load float, ptr [[X_ADDR_ASCAST]], align 4 // CHECK-CPP-NEXT: [[__X_ADDR_ASCAST_I5:%.*]] = addrspacecast ptr addrspace(5) [[__X_ADDR_I4]] to ptr @@ -253,7 +254,7 @@ void test_math_f64(double x, double y, double z) { // CHECK-CPP-NEXT: [[__X_ADDR_ASCAST_I17:%.*]] = addrspacecast ptr addrspace(5) [[__X_ADDR_I16]] to ptr // CHECK-CPP-NEXT: store float [[TMP4]], ptr [[__X_ADDR_ASCAST_I17]], align 4 // CHECK-CPP-NEXT: [[TMP5:%.*]] = load float, ptr [[__X_ADDR_ASCAST_I17]], align 4 -// CHECK-CPP-NEXT: [[CALL_I:%.*]] = call noundef float @__ocml_cos_f32(float noundef [[TMP5]]) #[[ATTR3]] +// CHECK-CPP-NEXT: [[CALL_I:%.*]] = call noundef float @__ocml_cos_f32(float noundef [[TMP5]]) #[[ATTR5]] // CHECK-CPP-NEXT: store float [[CALL_I]], ptr [[L2_ASCAST]], align 4 // CHECK-CPP-NEXT: [[TMP6:%.*]] = load float, ptr [[X_ADDR_ASCAST]], align 4 // CHECK-CPP-NEXT: [[__X_ADDR_ASCAST_I8:%.*]] = addrspacecast ptr addrspace(5) [[__X_ADDR_I7]] to ptr @@ -384,13 +385,13 @@ void test_math_f32(float x, float y, float z) { // CHECK-CPP-NEXT: [[__X_ADDR_ASCAST_I:%.*]] = addrspacecast ptr addrspace(5) [[__X_ADDR_I]] to ptr // CHECK-CPP-NEXT: store float [[TMP0]], ptr [[__X_ADDR_ASCAST_I]], align 4 // CHECK-CPP-NEXT: [[TMP1:%.*]] = load float, ptr [[__X_ADDR_ASCAST_I]], align 4 -// CHECK-CPP-NEXT: [[CALL_I:%.*]] = call noundef float @__ocml_sin_f32(float noundef [[TMP1]]) #[[ATTR3]] +// CHECK-CPP-NEXT: [[CALL_I:%.*]] = call noundef float @__ocml_sin_f32(float noundef [[TMP1]]) #[[ATTR5]] // CHECK-CPP-NEXT: store float [[CALL_I]], ptr [[L1_ASCAST]], align 4 // CHECK-CPP-NEXT: [[TMP2:%.*]] = load float, ptr [[X_ADDR_ASCAST]], align 4 // CHECK-CPP-NEXT: [[__X_ADDR_ASCAST_I5:%.*]] = addrspacecast ptr addrspace(5) [[__X_ADDR_I4]] to ptr // CHECK-CPP-NEXT: store float [[TMP2]], ptr [[__X_ADDR_ASCAST_I5]], align 4 // CHECK-CPP-NEXT: [[TMP3:%.*]] = load float, ptr [[__X_ADDR_ASCAST_I5]], align 4 -// CHECK-CPP-NEXT: [[CALL_I6:%.*]] = call noundef float @__ocml_cos_f32(float noundef [[TMP3]]) #[[ATTR3]] +// CHECK-CPP-NEXT: [[CALL_I6:%.*]] = call noundef float @__ocml_cos_f32(float noundef [[TMP3]]) #[[ATTR5]] // CHECK-CPP-NEXT: store float [[CALL_I6]], ptr [[L2_ASCAST]], align 4 // CHECK-CPP-NEXT: [[TMP4:%.*]] = load float, ptr [[X_ADDR_ASCAST]], align 4 // CHECK-CPP-NEXT: [[__X_ADDR_ASCAST_I8:%.*]] = addrspacecast ptr addrspace(5) [[__X_ADDR_I7]] to ptr @@ -421,6 +422,46 @@ void test_math_f32_suffix(float x, float y, float z) { float l4 = fmaf(x, y, z); } +#ifdef __cplusplus +// The templated ::min and ::max in __clang_hip_math.h are a CUDA extension for +// HIP. In OpenMP these unqualified calls must resolve to std without ambiguity. +// CHECK-CPP-LABEL: @_Z12test_std_minll( +// CHECK-CPP-NEXT: entry: +// CHECK-CPP-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4, addrspace(5) +// CHECK-CPP-NEXT: [[__A:%.*]] = call align 8 ptr @__kmpc_alloc_shared(i64 8) +// CHECK-CPP-NEXT: [[__B:%.*]] = call align 8 ptr @__kmpc_alloc_shared(i64 8) +// CHECK-CPP-NEXT: store i64 [[__A1:%.*]], ptr [[__A]], align 8 +// CHECK-CPP-NEXT: store i64 [[__B2:%.*]], ptr [[__B]], align 8 +// CHECK-CPP-NEXT: [[CALL:%.*]] = call noundef nonnull align 8 dereferenceable(8) ptr @_ZSt3minIlERKT_S2_S2_(ptr noundef nonnull align 8 dereferenceable(8) [[__A]], ptr noundef nonnull align 8 dereferenceable(8) [[__B]]) #[[ATTR6:[0-9]+]] +// CHECK-CPP-NEXT: [[TMP0:%.*]] = load i64, ptr [[CALL]], align 8 +// CHECK-CPP-NEXT: call void @__kmpc_free_shared(ptr [[__B]], i64 8) +// CHECK-CPP-NEXT: call void @__kmpc_free_shared(ptr [[__A]], i64 8) +// CHECK-CPP-NEXT: ret i64 [[TMP0]] +// +long test_std_min(long __a, long __b) { + using namespace std; + return min(__a, __b); +} + +// CHECK-CPP-LABEL: @_Z12test_std_maxll( +// CHECK-CPP-NEXT: entry: +// CHECK-CPP-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4, addrspace(5) +// CHECK-CPP-NEXT: [[__A:%.*]] = call align 8 ptr @__kmpc_alloc_shared(i64 8) +// CHECK-CPP-NEXT: [[__B:%.*]] = call align 8 ptr @__kmpc_alloc_shared(i64 8) +// CHECK-CPP-NEXT: store i64 [[__A1:%.*]], ptr [[__A]], align 8 +// CHECK-CPP-NEXT: store i64 [[__B2:%.*]], ptr [[__B]], align 8 +// CHECK-CPP-NEXT: [[CALL:%.*]] = call noundef nonnull align 8 dereferenceable(8) ptr @_ZSt3maxIlERKT_S2_S2_(ptr noundef nonnull align 8 dereferenceable(8) [[__A]], ptr noundef nonnull align 8 dereferenceable(8) [[__B]]) #[[ATTR6]] +// CHECK-CPP-NEXT: [[TMP0:%.*]] = load i64, ptr [[CALL]], align 8 +// CHECK-CPP-NEXT: call void @__kmpc_free_shared(ptr [[__B]], i64 8) +// CHECK-CPP-NEXT: call void @__kmpc_free_shared(ptr [[__A]], i64 8) +// CHECK-CPP-NEXT: ret i64 [[TMP0]] +// +long test_std_max(long __a, long __b) { + using namespace std; + return max(__a, __b); +} +#endif + #pragma omp end declare target //// NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: // CHECK: {{.*}} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
