Hahnfeld created this revision.
Hahnfeld added a reviewer: tra.
Herald added a subscriber: cfe-commits.

This is needed for relocatable device code with CUDA 9 and later.
Before this patch, linking two or more object files resulted in
"Multiple definition" errors for a group of functions from
cuda_device_runtime_api.h which are annoted with "nv_weak".

CUDA headers already used this attribute in earlier releases, but
until CUDA 8.0 the only definitions in cuda_device_runtime_api.h
were conditional under `defined(__CUDABE__)` which is explicitly
undefined in Clang's wrapper. However since CUDA 9.0 this has
changed to `!defined(__CUDACC_RTC__)`. Trying to add that define
resulted in errors that nvrtc_device_runtime.h could not be found.

Reported by Andrea Bocci!


Repository:
  rC Clang

https://reviews.llvm.org/D47201

Files:
  include/clang/Basic/Attr.td
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/CodeGen/CodeGenModule.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaDeclAttr.cpp
  test/CodeGenCUDA/nv_weak.cu
  test/SemaCUDA/attr-declspec.cu
  test/SemaCUDA/attr-nv_weak.cu
  test/SemaCUDA/attributes-on-non-cuda.cu

Index: test/SemaCUDA/attributes-on-non-cuda.cu
===================================================================
--- test/SemaCUDA/attributes-on-non-cuda.cu
+++ test/SemaCUDA/attributes-on-non-cuda.cu
@@ -7,11 +7,12 @@
 // RUN: %clang_cc1 -DEXPECT_WARNINGS -fsyntax-only -verify -x c %s
 
 #if defined(EXPECT_WARNINGS)
-// expected-warning@+12 {{'device' attribute ignored}}
-// expected-warning@+12 {{'global' attribute ignored}}
-// expected-warning@+12 {{'constant' attribute ignored}}
-// expected-warning@+12 {{'shared' attribute ignored}}
-// expected-warning@+12 {{'host' attribute ignored}}
+// expected-warning@+13 {{'device' attribute ignored}}
+// expected-warning@+13 {{'global' attribute ignored}}
+// expected-warning@+13 {{'constant' attribute ignored}}
+// expected-warning@+13 {{'shared' attribute ignored}}
+// expected-warning@+13 {{'host' attribute ignored}}
+// expected-warning@+13 {{'nv_weak' attribute ignored}}
 //
 // NOTE: IgnoredAttr in clang which is used for the rest of
 // attributes ignores LangOpts, so there are no warnings.
@@ -24,11 +25,11 @@
 __attribute__((constant)) int* g_constant;
 __attribute__((shared)) float *g_shared;
 __attribute__((host)) void f_host();
+__attribute__((nv_weak)) void f_nv_weak();
 __attribute__((device_builtin)) void f_device_builtin();
 typedef __attribute__((device_builtin)) const void *t_device_builtin;
 enum __attribute__((device_builtin)) e_device_builtin {E};
 __attribute__((device_builtin)) int v_device_builtin;
 __attribute__((cudart_builtin)) void f_cudart_builtin();
-__attribute__((nv_weak)) void f_nv_weak();
 __attribute__((device_builtin_surface_type)) unsigned long long surface_var;
 __attribute__((device_builtin_texture_type)) unsigned long long texture_var;
Index: test/SemaCUDA/attr-nv_weak.cu
===================================================================
--- /dev/null
+++ test/SemaCUDA/attr-nv_weak.cu
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -verify -fsyntax-only %s
+
+extern int f0() __attribute__((nv_weak));
+extern int g0 __attribute__((nv_weak)); // expected-warning {{'nv_weak' attribute only applies to functions}}
+int f1() __attribute__((nv_weak));
+int g1 __attribute__((nv_weak)); // expected-warning {{'nv_weak' attribute only applies to functions}}
+
+
+struct __attribute__((nv_weak)) s0 {}; // expected-warning {{'nv_weak' attribute only applies to functions}}
+
+static int f() __attribute__((nv_weak)); // expected-error {{nv_weak declaration cannot have internal linkage}}
+
+static void pr14946_f();
+void pr14946_f() __attribute__((nv_weak)); // expected-error {{nv_weak declaration cannot have internal linkage}}
Index: test/SemaCUDA/attr-declspec.cu
===================================================================
--- test/SemaCUDA/attr-declspec.cu
+++ test/SemaCUDA/attr-declspec.cu
@@ -6,11 +6,12 @@
 // RUN: %clang_cc1 -DEXPECT_WARNINGS -fms-extensions -fsyntax-only -verify -x c %s
 
 #if defined(EXPECT_WARNINGS)
-// expected-warning@+12 {{'__device__' attribute ignored}}
-// expected-warning@+12 {{'__global__' attribute ignored}}
-// expected-warning@+12 {{'__constant__' attribute ignored}}
-// expected-warning@+12 {{'__shared__' attribute ignored}}
-// expected-warning@+12 {{'__host__' attribute ignored}}
+// expected-warning@+13 {{'__device__' attribute ignored}}
+// expected-warning@+13 {{'__global__' attribute ignored}}
+// expected-warning@+13 {{'__constant__' attribute ignored}}
+// expected-warning@+13 {{'__shared__' attribute ignored}}
+// expected-warning@+13 {{'__host__' attribute ignored}}
+// expected-warning@+13 {{'__nv_weak__' attribute ignored}}
 //
 // (Currently we don't for the other attributes. They are implemented with
 // IgnoredAttr, which is ignored irrespective of any LangOpts.)
@@ -23,12 +24,11 @@
 __declspec(__constant__) int* g_constant;
 __declspec(__shared__) float *g_shared;
 __declspec(__host__) void f_host();
+__declspec(__nv_weak__) void f_nv_weak();
 __declspec(__device_builtin__) void f_device_builtin();
 typedef __declspec(__device_builtin__) const void *t_device_builtin;
 enum __declspec(__device_builtin__) e_device_builtin {E};
 __declspec(__device_builtin__) int v_device_builtin;
 __declspec(__cudart_builtin__) void f_cudart_builtin();
 __declspec(__device_builtin_surface_type__) unsigned long long surface_var;
 __declspec(__device_builtin_texture_type__) unsigned long long texture_var;
-
-// Note that there's no __declspec spelling of nv_weak.
Index: test/CodeGenCUDA/nv_weak.cu
===================================================================
--- /dev/null
+++ test/CodeGenCUDA/nv_weak.cu
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm \
+// RUN:     -o - %s | FileCheck %s
+
+// RUN: %clang_cc1 -fcuda-is-device -triple nvptx64-nvidia-cuda -emit-llvm \
+// RUN:     -o - %s | FileCheck %s
+
+#include "Inputs/cuda.h"
+
+// CHECK-DAG: declare extern_weak i32 @_Z2f1v()
+extern
+#if defined(__CUDA_ARCH__)
+__device__
+#endif
+int f1() __attribute__((nv_weak));
+
+// CHECK-DAG: define weak i32 @_Z2f2v()
+#if defined(__CUDA_ARCH__)
+__device__
+#endif
+int f2() __attribute__((nv_weak)) {
+  return f1();
+}
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -6179,6 +6179,9 @@
   case AttributeList::AT_Weak:
     handleSimpleAttribute<WeakAttr>(S, D, AL);
     break;
+  case AttributeList::AT_NvWeak:
+    handleSimpleAttribute<NvWeakAttr>(S, D, AL);
+    break;
   case AttributeList::AT_WeakRef:
     handleWeakRefAttr(S, D, AL);
     break;
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -5942,10 +5942,16 @@
   // 'weak' only applies to declarations with external linkage.
   if (WeakAttr *Attr = ND.getAttr<WeakAttr>()) {
     if (!ND.isExternallyVisible()) {
-      S.Diag(Attr->getLocation(), diag::err_attribute_weak_static);
+      S.Diag(Attr->getLocation(), diag::err_attribute_weak_static) << 0;
       ND.dropAttr<WeakAttr>();
     }
   }
+  if (NvWeakAttr *Attr = ND.getAttr<NvWeakAttr>()) {
+    if (!ND.isExternallyVisible()) {
+      S.Diag(Attr->getLocation(), diag::err_attribute_weak_static) << 1;
+      ND.dropAttr<NvWeakAttr>();
+    }
+  }
   if (WeakRefAttr *Attr = ND.getAttr<WeakRefAttr>()) {
     if (ND.isExternallyVisible()) {
       S.Diag(Attr->getLocation(), diag::err_attribute_weakref_not_static);
Index: lib/CodeGen/CodeGenModule.cpp
===================================================================
--- lib/CodeGen/CodeGenModule.cpp
+++ lib/CodeGen/CodeGenModule.cpp
@@ -1374,7 +1374,7 @@
   // "extern_weak" is overloaded in LLVM; we probably should have
   // separate linkage types for this.
   if (isExternallyVisible(LV.getLinkage()) &&
-      (ND->hasAttr<WeakAttr>() || ND->isWeakImported()))
+      (ND->hasAttr<WeakAttr>() || ND->hasAttr<NvWeakAttr>() || ND->isWeakImported()))
     GV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
 }
 
@@ -3442,7 +3442,7 @@
   if (Linkage == GVA_Internal)
     return llvm::Function::InternalLinkage;
 
-  if (D->hasAttr<WeakAttr>()) {
+  if (D->hasAttr<WeakAttr>() || D->hasAttr<NvWeakAttr>()) {
     if (IsConstantVariable)
       return llvm::GlobalVariable::WeakODRLinkage;
     else
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -2757,7 +2757,7 @@
 def warn_weak_identifier_undeclared : Warning<
   "weak identifier %0 never declared">;
 def err_attribute_weak_static : Error<
-  "weak declaration cannot have internal linkage">;
+  "%select{weak|nv_weak}0 declaration cannot have internal linkage">;
 def err_attribute_selectany_non_extern_data : Error<
   "'selectany' can only be applied to data items with external linkage">;
 def err_declspec_thread_on_thread_variable : Error<
Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -1508,12 +1508,11 @@
   let Documentation = [NoThrowDocs];
 }
 
-def NvWeak : IgnoredAttr {
-  // No Declspec spelling of this attribute; the CUDA headers use
-  // __attribute__((nv_weak)) unconditionally. Does not receive an [[]]
-  // spelling because it is a CUDA attribute.
-  let Spellings = [GNU<"nv_weak">];
+def NvWeak : InheritableAttr {
+  let Spellings = [GNU<"nv_weak">, Declspec<"__nv_weak__">];
+  let Subjects = SubjectList<[Function]>;
   let LangOpts = [CUDA];
+  let Documentation = [Undocumented];
 }
 
 def ObjCBridge : InheritableAttr {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to