Skip to content

Commit ea72a4e

Browse files
committed
[CUDA][HIP] Fix template argument deduction
nvcc allows using std::malloc and std::free in device code. When std::malloc or std::free is passed as a template function argument with template argument deduction, there is no diagnostics. e.g. __global__ void kern() { void *p = std::malloc(1); std::free(p); } int main() { std::shared_ptr<float> a; a = std::shared_ptr<float>( (float*)std::malloc(sizeof(float) * 100), std::free ); return 0; } However, the same code fails to compile with clang (https://godbolt.org/z/1roGvo6YY). The reason is that clang does not have logic to choose a function argument from an overloaded set of candidates based on host/device attributes for template argument deduction. Currently, clang does have a logic to choose a candidate based on the constraints of the candidates. This patch extends that logic to account for the CUDA host/device-based preference. Reviewed by: Artem Belevich Differential Revision: https://reviews.llvm.org/D154300
1 parent f263f45 commit ea72a4e

File tree

2 files changed

+64
-4
lines changed

2 files changed

+64
-4
lines changed

clang/lib/Sema/SemaOverload.cpp

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12770,6 +12770,13 @@ Sema::resolveAddressOfSingleOverloadCandidate(Expr *E, DeclAccessPair &Pair) {
1277012770
DeclAccessPair DAP;
1277112771
SmallVector<FunctionDecl *, 2> AmbiguousDecls;
1277212772

12773+
// Return positive for better, negative for worse, 0 for equal preference.
12774+
auto CheckCUDAPreference = [&](FunctionDecl *FD1, FunctionDecl *FD2) {
12775+
FunctionDecl *Caller = getCurFunctionDecl(/*AllowLambda=*/true);
12776+
return static_cast<int>(IdentifyCUDAPreference(Caller, FD1)) -
12777+
static_cast<int>(IdentifyCUDAPreference(Caller, FD2));
12778+
};
12779+
1277312780
auto CheckMoreConstrained = [&](FunctionDecl *FD1,
1277412781
FunctionDecl *FD2) -> std::optional<bool> {
1277512782
if (FunctionDecl *MF = FD1->getInstantiatedFromMemberFunction())
@@ -12800,9 +12807,31 @@ Sema::resolveAddressOfSingleOverloadCandidate(Expr *E, DeclAccessPair &Pair) {
1280012807
if (!checkAddressOfFunctionIsAvailable(FD))
1280112808
continue;
1280212809

12810+
// If we found a better result, update Result.
12811+
auto FoundBetter = [&]() {
12812+
IsResultAmbiguous = false;
12813+
DAP = I.getPair();
12814+
Result = FD;
12815+
};
12816+
1280312817
// We have more than one result - see if it is more constrained than the
1280412818
// previous one.
1280512819
if (Result) {
12820+
// Check CUDA preference first. If the candidates have differennt CUDA
12821+
// preference, choose the one with higher CUDA preference. Otherwise,
12822+
// choose the one with more constraints.
12823+
if (getLangOpts().CUDA) {
12824+
int PreferenceByCUDA = CheckCUDAPreference(FD, Result);
12825+
// FD has different preference than Result.
12826+
if (PreferenceByCUDA != 0) {
12827+
// FD is more preferable than Result.
12828+
if (PreferenceByCUDA > 0)
12829+
FoundBetter();
12830+
continue;
12831+
}
12832+
}
12833+
// FD has the same CUDA prefernece than Result. Continue check
12834+
// constraints.
1280612835
std::optional<bool> MoreConstrainedThanPrevious =
1280712836
CheckMoreConstrained(FD, Result);
1280812837
if (!MoreConstrainedThanPrevious) {
@@ -12814,9 +12843,7 @@ Sema::resolveAddressOfSingleOverloadCandidate(Expr *E, DeclAccessPair &Pair) {
1281412843
continue;
1281512844
// FD is more constrained - replace Result with it.
1281612845
}
12817-
IsResultAmbiguous = false;
12818-
DAP = I.getPair();
12819-
Result = FD;
12846+
FoundBetter();
1282012847
}
1282112848

1282212849
if (IsResultAmbiguous)
@@ -12826,9 +12853,15 @@ Sema::resolveAddressOfSingleOverloadCandidate(Expr *E, DeclAccessPair &Pair) {
1282612853
SmallVector<const Expr *, 1> ResultAC;
1282712854
// We skipped over some ambiguous declarations which might be ambiguous with
1282812855
// the selected result.
12829-
for (FunctionDecl *Skipped : AmbiguousDecls)
12856+
for (FunctionDecl *Skipped : AmbiguousDecls) {
12857+
// If skipped candidate has different CUDA preference than the result,
12858+
// there is no ambiguity. Otherwise check whether they have different
12859+
// constraints.
12860+
if (getLangOpts().CUDA && CheckCUDAPreference(Skipped, Result) != 0)
12861+
continue;
1283012862
if (!CheckMoreConstrained(Skipped, Result))
1283112863
return nullptr;
12864+
}
1283212865
Pair = DAP;
1283312866
}
1283412867
return Result;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsyntax-only -verify %s
2+
// RUN: %clang_cc1 -triple nvptx64-nvidia-cuda -fsyntax-only -fcuda-is-device -verify %s
3+
4+
// expected-no-diagnostics
5+
6+
#include "Inputs/cuda.h"
7+
8+
void foo();
9+
__device__ void foo();
10+
11+
template<class F>
12+
void host_temp(F f);
13+
14+
template<class F>
15+
__device__ void device_temp(F f);
16+
17+
void host_caller() {
18+
host_temp(foo);
19+
}
20+
21+
__global__ void kernel_caller() {
22+
device_temp(foo);
23+
}
24+
25+
__device__ void device_caller() {
26+
device_temp(foo);
27+
}

0 commit comments

Comments
 (0)