r342749 - [CUDA] Ignore uncallable functions when we check for usual deallocators.

Artem Belevich via cfe-commits cfe-commits at lists.llvm.org
Fri Sep 21 10:29:33 PDT 2018


Author: tra
Date: Fri Sep 21 10:29:33 2018
New Revision: 342749

URL: http://llvm.org/viewvc/llvm-project?rev=342749&view=rev
Log:
[CUDA] Ignore uncallable functions when we check for usual deallocators.

Previously clang considered function variants from both sides of
compilation and that resulted in picking up wrong deallocation function.

Differential Revision: https://reviews.llvm.org/D51808

Added:
    cfe/trunk/test/CodeGenCUDA/usual-deallocators.cu
    cfe/trunk/test/SemaCUDA/usual-deallocators.cu
Modified:
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/test/SemaCUDA/call-host-fn-from-device.cu

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=342749&r1=342748&r2=342749&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Fri Sep 21 10:29:33 2018
@@ -2109,10 +2109,15 @@ public:
         Base, IsAppleKext);
   }
 
-  /// Determine whether this is a usual deallocation function
-  /// (C++ [basic.stc.dynamic.deallocation]p2), which is an overloaded
-  /// delete or delete[] operator with a particular signature.
-  bool isUsualDeallocationFunction() const;
+  /// Determine whether this is a usual deallocation function (C++
+  /// [basic.stc.dynamic.deallocation]p2), which is an overloaded delete or
+  /// delete[] operator with a particular signature. Populates \p PreventedBy
+  /// with the declarations of the functions of the same kind if they were the
+  /// reason for this function returning false. This is used by
+  /// Sema::isUsualDeallocationFunction to reconsider the answer based on the
+  /// context.
+  bool isUsualDeallocationFunction(
+      SmallVectorImpl<const FunctionDecl *> &PreventedBy) const;
 
   /// Determine whether this is a copy-assignment operator, regardless
   /// of whether it was declared implicitly or explicitly.

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=342749&r1=342748&r2=342749&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Fri Sep 21 10:29:33 2018
@@ -1619,6 +1619,8 @@ public:
       SourceLocation Loc, const NamedDecl *D,
       ArrayRef<const NamedDecl *> Equiv);
 
+  bool isUsualDeallocationFunction(const CXXMethodDecl *FD);
+
   bool isCompleteType(SourceLocation Loc, QualType T) {
     return !RequireCompleteTypeImpl(Loc, T, nullptr);
   }

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=342749&r1=342748&r2=342749&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Fri Sep 21 10:29:33 2018
@@ -2005,7 +2005,9 @@ CXXMethodDecl *CXXMethodDecl::getDevirtu
   return nullptr;
 }
 
-bool CXXMethodDecl::isUsualDeallocationFunction() const {
+bool CXXMethodDecl::isUsualDeallocationFunction(
+    SmallVectorImpl<const FunctionDecl *> &PreventedBy) const {
+  assert(PreventedBy.empty() && "PreventedBy is expected to be empty");
   if (getOverloadedOperator() != OO_Delete &&
       getOverloadedOperator() != OO_Array_Delete)
     return false;
@@ -2063,14 +2065,16 @@ bool CXXMethodDecl::isUsualDeallocationF
   // This function is a usual deallocation function if there are no
   // single-parameter deallocation functions of the same kind.
   DeclContext::lookup_result R = getDeclContext()->lookup(getDeclName());
-  for (DeclContext::lookup_result::iterator I = R.begin(), E = R.end();
-       I != E; ++I) {
-    if (const auto *FD = dyn_cast<FunctionDecl>(*I))
-      if (FD->getNumParams() == 1)
-        return false;
+  bool Result = true;
+  for (const auto *D : R) {
+    if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
+      if (FD->getNumParams() == 1) {
+        PreventedBy.push_back(FD);
+        Result = false;
+      }
+    }
   }
-
-  return true;
+  return Result;
 }
 
 bool CXXMethodDecl::isCopyAssignmentOperator() const {

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=342749&r1=342748&r2=342749&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Fri Sep 21 10:29:33 2018
@@ -13183,7 +13183,8 @@ CheckOperatorDeleteDeclaration(Sema &Sem
   // C++ P0722:
   //   A destroying operator delete shall be a usual deallocation function.
   if (MD && !MD->getParent()->isDependentContext() &&
-      MD->isDestroyingOperatorDelete() && !MD->isUsualDeallocationFunction()) {
+      MD->isDestroyingOperatorDelete() &&
+      !SemaRef.isUsualDeallocationFunction(MD)) {
     SemaRef.Diag(MD->getLocation(),
                  diag::err_destroying_operator_delete_not_usual);
     return true;

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=342749&r1=342748&r2=342749&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Fri Sep 21 10:29:33 2018
@@ -1448,11 +1448,33 @@ Sema::BuildCXXTypeConstructExpr(TypeSour
   return Result;
 }
 
+bool Sema::isUsualDeallocationFunction(const CXXMethodDecl *Method) {
+  // [CUDA] Ignore this function, if we can't call it.
+  const FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext);
+  if (getLangOpts().CUDA &&
+      IdentifyCUDAPreference(Caller, Method) <= CFP_WrongSide)
+    return false;
+
+  SmallVector<const FunctionDecl*, 4> PreventedBy;
+  bool Result = Method->isUsualDeallocationFunction(PreventedBy);
+
+  if (Result || !getLangOpts().CUDA || PreventedBy.empty())
+    return Result;
+
+  // In case of CUDA, return true if none of the 1-argument deallocator
+  // functions are actually callable.
+  return llvm::none_of(PreventedBy, [&](const FunctionDecl *FD) {
+    assert(FD->getNumParams() == 1 &&
+           "Only single-operand functions should be in PreventedBy");
+    return IdentifyCUDAPreference(Caller, FD) >= CFP_HostDevice;
+  });
+}
+
 /// Determine whether the given function is a non-placement
 /// deallocation function.
 static bool isNonPlacementDeallocationFunction(Sema &S, FunctionDecl *FD) {
   if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FD))
-    return Method->isUsualDeallocationFunction();
+    return S.isUsualDeallocationFunction(Method);
 
   if (FD->getOverloadedOperator() != OO_Delete &&
       FD->getOverloadedOperator() != OO_Array_Delete)

Added: cfe/trunk/test/CodeGenCUDA/usual-deallocators.cu
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCUDA/usual-deallocators.cu?rev=342749&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCUDA/usual-deallocators.cu (added)
+++ cfe/trunk/test/CodeGenCUDA/usual-deallocators.cu Fri Sep 21 10:29:33 2018
@@ -0,0 +1,133 @@
+// RUN: %clang_cc1 %s --std=c++11 -triple nvptx-unknown-unknown -fcuda-is-device \
+// RUN:   -emit-llvm -o - | FileCheck %s --check-prefixes=COMMON,DEVICE
+// RUN: %clang_cc1 %s --std=c++11 -triple nvptx-unknown-unknown \
+// RUN:   -emit-llvm -o - | FileCheck %s --check-prefixes=COMMON,HOST
+// RUN: %clang_cc1 %s --std=c++17 -triple nvptx-unknown-unknown -fcuda-is-device \
+// RUN:   -emit-llvm -o - | FileCheck %s --check-prefixes=COMMON,DEVICE
+// RUN: %clang_cc1 %s --std=c++17 -triple nvptx-unknown-unknown \
+// RUN:   -emit-llvm -o - | FileCheck %s --check-prefixes=COMMON,HOST
+
+#include "Inputs/cuda.h"
+extern "C" __host__ void host_fn();
+extern "C" __device__ void dev_fn();
+extern "C" __host__ __device__ void hd_fn();
+
+struct H1D1 {
+  __host__ void operator delete(void *) { host_fn(); };
+  __device__ void operator delete(void *) { dev_fn(); };
+};
+
+struct H1D2 {
+  __host__ void operator delete(void *) { host_fn(); };
+  __device__ void operator delete(void *, __SIZE_TYPE__) { dev_fn(); };
+};
+
+struct H2D1 {
+  __host__ void operator delete(void *, __SIZE_TYPE__) { host_fn(); };
+  __device__ void operator delete(void *) { dev_fn(); };
+};
+
+struct H2D2 {
+  __host__ void operator delete(void *, __SIZE_TYPE__) { host_fn(); };
+  __device__ void operator delete(void *, __SIZE_TYPE__) { dev_fn(); };
+};
+
+struct H1D1D2 {
+  __host__ void operator delete(void *) { host_fn(); };
+  __device__ void operator delete(void *) { dev_fn(); };
+  __device__ void operator delete(void *, __SIZE_TYPE__) { dev_fn(); };
+};
+
+struct H1H2D1 {
+  __host__ void operator delete(void *) { host_fn(); };
+  __host__ void operator delete(void *, __SIZE_TYPE__) { host_fn(); };
+  __device__ void operator delete(void *) { dev_fn(); };
+};
+
+struct H1H2D2 {
+  __host__ void operator delete(void *) { host_fn(); };
+  __host__ void operator delete(void *, __SIZE_TYPE__) { host_fn(); };
+  __device__ void operator delete(void *, __SIZE_TYPE__) { dev_fn(); };
+};
+
+struct H1H2D1D2 {
+  __host__ void operator delete(void *) { host_fn(); };
+  __host__ void operator delete(void *, __SIZE_TYPE__) { host_fn(); };
+  __device__ void operator delete(void *) { dev_fn(); };
+  __device__ void operator delete(void *, __SIZE_TYPE__) { dev_fn(); };
+};
+
+
+template <typename T>
+__host__ __device__ void test_hd(void *p) {
+  T *t = (T *)p;
+  delete t;
+}
+
+// Make sure we call the right variant of usual deallocator.
+__host__ __device__ void tests_hd(void *t) {
+  // COMMON-LABEL: define linkonce_odr void @_Z7test_hdI4H1D1EvPv
+  // COMMON: call void @_ZN4H1D1dlEPv
+  test_hd<H1D1>(t);
+  // COMMON-LABEL: define linkonce_odr void @_Z7test_hdI4H1D2EvPv
+  // DEVICE: call void @_ZN4H1D2dlEPvj(i8* {{.*}}, i32 1)
+  // HOST:   call void @_ZN4H1D2dlEPv(i8* {{.*}})
+  test_hd<H1D2>(t);
+  // COMMON-LABEL: define linkonce_odr void @_Z7test_hdI4H2D1EvPv
+  // DEVICE: call void @_ZN4H2D1dlEPv(i8* {{.*}})
+  // HOST:   call void @_ZN4H2D1dlEPvj(i8* %3, i32 1)
+  test_hd<H2D1>(t);
+  // COMMON-LABEL: define linkonce_odr void @_Z7test_hdI4H2D2EvPv
+  // COMMON: call void @_ZN4H2D2dlEPvj(i8* {{.*}}, i32 1)
+  test_hd<H2D2>(t);
+  // COMMON-LABEL: define linkonce_odr void @_Z7test_hdI6H1D1D2EvPv
+  // COMMON: call void @_ZN6H1D1D2dlEPv(i8* %3)
+  test_hd<H1D1D2>(t);
+  // COMMON-LABEL: define linkonce_odr void @_Z7test_hdI6H1H2D1EvPv
+  // COMMON: call void @_ZN6H1H2D1dlEPv(i8* {{.*}})
+  test_hd<H1H2D1>(t);
+  // COMMON-LABEL: define linkonce_odr void @_Z7test_hdI6H1H2D2EvPv
+  // DEVICE: call void @_ZN6H1H2D2dlEPvj(i8* {{.*}}, i32 1)
+  // HOST:   call void @_ZN6H1H2D2dlEPv(i8* {{.*}})
+  test_hd<H1H2D2>(t);
+  // COMMON-LABEL: define linkonce_odr void @_Z7test_hdI8H1H2D1D2EvPv
+  // COMMON: call void @_ZN8H1H2D1D2dlEPv(i8* {{.*}})
+  test_hd<H1H2D1D2>(t);
+}
+
+// Make sure we've picked deallocator for the correct side of compilation.
+
+// COMMON-LABEL: define  linkonce_odr void @_ZN4H1D1dlEPv(i8*)
+// DEVICE: call void @dev_fn()
+// HOST:   call void @host_fn()
+
+// DEVICE-LABEL: define  linkonce_odr void @_ZN4H1D2dlEPvj(i8*, i32)
+// DEVICE: call void @dev_fn()
+// HOST-LABEL: define linkonce_odr void @_ZN4H1D2dlEPv(i8*)
+// HOST: call void @host_fn()
+
+// DEVICE-LABEL: define  linkonce_odr void @_ZN4H2D1dlEPv(i8*)
+// DEVICE: call void @dev_fn()
+// HOST-LABEL:  define linkonce_odr void @_ZN4H2D1dlEPvj(i8*, i32)
+// HOST: call void @host_fn()
+
+// COMMON-LABEL: define  linkonce_odr void @_ZN4H2D2dlEPvj(i8*, i32)
+// DEVICE: call void @dev_fn()
+// HOST: call void @host_fn()
+
+// COMMON-LABEL: define  linkonce_odr void @_ZN6H1D1D2dlEPv(i8*)
+// DEVICE: call void @dev_fn()
+// HOST: call void @host_fn()
+
+// COMMON-LABEL: define  linkonce_odr void @_ZN6H1H2D1dlEPv(i8*)
+// DEVICE: call void @dev_fn()
+// HOST: call void @host_fn()
+
+// DEVICE-LABEL: define  linkonce_odr void @_ZN6H1H2D2dlEPvj(i8*, i32)
+// DEVICE: call void @dev_fn()
+// HOST-LABEL: define linkonce_odr void @_ZN6H1H2D2dlEPv(i8*)
+// HOST: call void @host_fn()
+
+// COMMON-LABEL: define  linkonce_odr void @_ZN8H1H2D1D2dlEPv(i8*)
+// DEVICE: call void @dev_fn()
+// HOST: call void @host_fn()

Modified: cfe/trunk/test/SemaCUDA/call-host-fn-from-device.cu
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCUDA/call-host-fn-from-device.cu?rev=342749&r1=342748&r2=342749&view=diff
==============================================================================
--- cfe/trunk/test/SemaCUDA/call-host-fn-from-device.cu (original)
+++ cfe/trunk/test/SemaCUDA/call-host-fn-from-device.cu Fri Sep 21 10:29:33 2018
@@ -41,12 +41,12 @@ struct T {
   operator Dummy() { return Dummy(); }
   // expected-note at -1 {{'operator Dummy' declared here}}
 
-  __host__ void operator delete(void*);
-  __device__ void operator delete(void*, size_t);
+  __host__ void operator delete(void *) { host_fn(); };
+  __device__ void operator delete(void*, __SIZE_TYPE__);
 };
 
 struct U {
-  __device__ void operator delete(void*, size_t) = delete;
+  __device__ void operator delete(void*, __SIZE_TYPE__) = delete;
   __host__ __device__ void operator delete(void*);
 };
 

Added: cfe/trunk/test/SemaCUDA/usual-deallocators.cu
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCUDA/usual-deallocators.cu?rev=342749&view=auto
==============================================================================
--- cfe/trunk/test/SemaCUDA/usual-deallocators.cu (added)
+++ cfe/trunk/test/SemaCUDA/usual-deallocators.cu Fri Sep 21 10:29:33 2018
@@ -0,0 +1,95 @@
+// RUN: %clang_cc1 %s --std=c++11 -triple nvptx-unknown-unknown -fcuda-is-device \
+// RUN:   -emit-llvm -o /dev/null -verify=device
+// RUN: %clang_cc1 %s --std=c++11 -triple nvptx-unknown-unknown \
+// RUN:   -emit-llvm -o /dev/null -verify=host
+// RUN: %clang_cc1 %s --std=c++17 -triple nvptx-unknown-unknown -fcuda-is-device \
+// RUN:   -emit-llvm -o /dev/null -verify=device
+// RUN: %clang_cc1 %s --std=c++17 -triple nvptx-unknown-unknown \
+// RUN:   -emit-llvm -o /dev/null -verify=host
+
+#include "Inputs/cuda.h"
+extern __host__ void host_fn();
+extern __device__ void dev_fn();
+extern __host__ __device__ void hd_fn();
+
+struct H1D1 {
+  __host__ void operator delete(void *) { host_fn(); };
+  __device__ void operator delete(void *) { dev_fn(); };
+};
+
+struct h1D1 {
+  __host__ void operator delete(void *) = delete;
+  // host-note at -1 {{'operator delete' has been explicitly marked deleted here}}
+  __device__ void operator delete(void *) { dev_fn(); };
+};
+
+struct H1d1 {
+  __host__ void operator delete(void *) { host_fn(); };
+  __device__ void operator delete(void *) = delete;
+  // device-note at -1 {{'operator delete' has been explicitly marked deleted here}}
+};
+
+struct H1D2 {
+  __host__ void operator delete(void *) { host_fn(); };
+  __device__ void operator delete(void *, __SIZE_TYPE__) { dev_fn(); };
+};
+
+struct H2D1 {
+  __host__ void operator delete(void *, __SIZE_TYPE__) { host_fn(); };
+  __device__ void operator delete(void *) { dev_fn(); };
+};
+
+struct H2D2 {
+  __host__ void operator delete(void *, __SIZE_TYPE__) { host_fn(); };
+  __device__ void operator delete(void *, __SIZE_TYPE__) { dev_fn(); };
+};
+
+struct H1D1D2 {
+  __host__ void operator delete(void *) { host_fn(); };
+  __device__ void operator delete(void *) { dev_fn(); };
+  __device__ void operator delete(void *, __SIZE_TYPE__) { dev_fn(); };
+};
+
+struct H1H2D1 {
+  __host__ void operator delete(void *) { host_fn(); };
+  __host__ void operator delete(void *, __SIZE_TYPE__) { host_fn(); };
+  __device__ void operator delete(void *) { dev_fn(); };
+};
+
+struct H1H2D2 {
+  __host__ void operator delete(void *) { host_fn(); };
+  __host__ void operator delete(void *, __SIZE_TYPE__) { host_fn(); };
+  __device__ void operator delete(void *, __SIZE_TYPE__) { dev_fn(); };
+};
+
+struct H1H2D1D2 {
+  __host__ void operator delete(void *) { host_fn(); };
+  __host__ void operator delete(void *, __SIZE_TYPE__) { host_fn(); };
+  __device__ void operator delete(void *) { dev_fn(); };
+  __device__ void operator delete(void *, __SIZE_TYPE__) { dev_fn(); };
+};
+
+
+template <typename T>
+__host__ __device__ void test_hd(void *p) {
+  T *t = (T *)p;
+  delete t;
+  // host-error at -1 {{attempt to use a deleted function}}
+  // device-error at -2 {{attempt to use a deleted function}}
+}
+
+__host__ __device__ void tests_hd(void *t) {
+  test_hd<H1D1>(t);
+  test_hd<h1D1>(t);
+  // host-note at -1 {{in instantiation of function template specialization 'test_hd<h1D1>' requested here}}
+  test_hd<H1d1>(t);
+  // device-note at -1 {{in instantiation of function template specialization 'test_hd<H1d1>' requested here}}
+  test_hd<H1D2>(t);
+  test_hd<H2D1>(t);
+  test_hd<H2D2>(t);
+  test_hd<H1D1D2>(t);
+  test_hd<H1H2D1>(t);
+  test_hd<H1H2D1>(t);
+  test_hd<H1H2D2>(t);
+  test_hd<H1H2D1D2>(t);
+}




More information about the cfe-commits mailing list