JonChesterfield updated this revision to Diff 248807.
JonChesterfield marked 2 inline comments as done.
JonChesterfield added a comment.

- Review comments, add tests for private_extern


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D74361/new/

https://reviews.llvm.org/D74361

Files:
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/AST/DeclBase.cpp
  clang/lib/CodeGen/CGDecl.cpp
  clang/lib/CodeGen/CodeGenModule.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/test/CodeGen/attr-loader-uninitialized.c
  clang/test/CodeGenCXX/attr-loader-uninitialized.cpp
  clang/test/Misc/pragma-attribute-supported-attributes-list.test
  clang/test/Sema/attr-loader-uninitialized.c
  clang/test/Sema/attr-loader-uninitialized.cpp

Index: clang/test/Sema/attr-loader-uninitialized.cpp
===================================================================
--- /dev/null
+++ clang/test/Sema/attr-loader-uninitialized.cpp
@@ -0,0 +1,60 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only
+
+int good __attribute__((loader_uninitialized));
+static int local_ok __attribute__((loader_uninitialized));
+int hidden_ok __attribute__((visibility("hidden"))) __attribute__((loader_uninitialized));
+
+const int still_cant_be_const __attribute__((loader_uninitialized));
+// expected-error@-1 {{default initialization of an object of const type}}
+extern int external_rejected __attribute__((loader_uninitialized));
+// expected-error@-1 {{external declaration of variable cannot have the 'loader_uninitialized' attribute}}
+
+int noargs __attribute__((loader_uninitialized(0)));
+// expected-error@-1 {{'loader_uninitialized' attribute takes no arguments}} 
+
+int init_rejected __attribute__((loader_uninitialized)) = 42;
+// expected-error@-1 {{variable with 'loader_uninitialized' attribute cannot have an initializer}}
+
+void func() __attribute__((loader_uninitialized))
+// expected-warning@-1 {{'loader_uninitialized' attribute only applies to global variables}}
+{
+  int local __attribute__((loader_uninitialized));
+  // expected-warning@-1 {{'loader_uninitialized' attribute only applies to global variables}}
+
+  static int sl __attribute__((loader_uninitialized));
+}
+
+struct s {
+  __attribute__((loader_uninitialized)) int field;
+  // expected-warning@-1 {{'loader_uninitialized' attribute only applies to global variables}}
+
+  static __attribute__((loader_uninitialized)) int sfield;
+
+} __attribute__((loader_uninitialized));
+// expected-warning@-1 {{'loader_uninitialized' attribute only applies to global variables}}
+
+int redef_attr_first __attribute__((loader_uninitialized));
+int redef_attr_first;
+// expected-error@-1 {{redefinition of 'redef_attr_first'}}
+// expected-note@-3 {{previous definition is here}}
+
+int redef_attr_second; 
+int redef_attr_second __attribute__((loader_uninitialized)); 
+// expected-warning@-1 {{attribute declaration must precede definition}}
+// expected-note@-3 {{previous definition is here}}
+// expected-error@-3 {{redefinition of 'redef_attr_second'}}
+// expected-note@-5 {{previous definition is here}}
+
+struct trivial {};
+
+trivial default_ok __attribute__((loader_uninitialized));
+trivial value_rejected  __attribute__((loader_uninitialized)) {};
+// expected-error@-1 {{variable with 'loader_uninitialized' attribute cannot have an initializer}}
+
+struct nontrivial
+{
+  nontrivial() {}
+};
+
+nontrivial needs_trivial_ctor __attribute__((loader_uninitialized));
+// expected-error@-1 {{variable with 'loader_uninitialized' attribute must have a trivial default constructor}}
Index: clang/test/Sema/attr-loader-uninitialized.c
===================================================================
--- /dev/null
+++ clang/test/Sema/attr-loader-uninitialized.c
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only
+// See also attr-loader-uninitialized.cpp
+
+int good __attribute__((loader_uninitialized));
+static int local_ok __attribute__((loader_uninitialized));
+int hidden_ok __attribute__((visibility("hidden"))) __attribute__((loader_uninitialized));
+
+const int can_still_be_const __attribute__((loader_uninitialized));
+
+extern int external_rejected __attribute__((loader_uninitialized));
+// expected-error@-1 {{external declaration of variable cannot have the 'loader_uninitialized' attribute}}
+
+int noargs __attribute__((loader_uninitialized(0)));
+// expected-error@-1 {{'loader_uninitialized' attribute takes no arguments}}
+
+int init_rejected __attribute__((loader_uninitialized)) = 42;
+// expected-error@-1 {{variable with 'loader_uninitialized' attribute cannot have an initializer}}
+
+int declaration_then_uninit_ok;
+int declaration_then_uninit_ok __attribute__((loader_uninitialized));
+
+int definition_then_uninit_rejected = 0;
+int definition_then_uninit_rejected __attribute__((loader_uninitialized));
+// expected-error@-1 {{redeclaration cannot add 'loader_uninitialized' attribute}}
+// expected-note@-3 {{previous definition is here}}
+
+int tentative_repeated_ok __attribute__((loader_uninitialized));
+int tentative_repeated_ok __attribute__((loader_uninitialized));
+
+__private_extern__ int private_extern_can_be_initialised = 10;
+__private_extern__ int therefore_uninit_private_extern_ok __attribute__((loader_uninitialized));
+
+__private_extern__ int initialized_private_extern_rejected __attribute__((loader_uninitialized)) = 5;
+// expected-error@-1 {{variable with 'loader_uninitialized' attribute cannot have an initializer}}
+
+extern __attribute__((visibility("hidden"))) int extern_hidden __attribute__((loader_uninitialized));
+// expected-error@-1 {{external declaration of variable cannot have the 'loader_uninitialized' attribute}}
Index: clang/test/Misc/pragma-attribute-supported-attributes-list.test
===================================================================
--- clang/test/Misc/pragma-attribute-supported-attributes-list.test
+++ clang/test/Misc/pragma-attribute-supported-attributes-list.test
@@ -65,6 +65,7 @@
 // CHECK-NEXT: InitPriority (SubjectMatchRule_variable)
 // CHECK-NEXT: InternalLinkage (SubjectMatchRule_variable, SubjectMatchRule_function, SubjectMatchRule_record)
 // CHECK-NEXT: LTOVisibilityPublic (SubjectMatchRule_record)
+// CHECK-NEXT: LoaderUninitialized (SubjectMatchRule_variable_is_global)
 // CHECK-NEXT: Lockable (SubjectMatchRule_record)
 // CHECK-NEXT: MIGServerRoutine (SubjectMatchRule_function, SubjectMatchRule_objc_method, SubjectMatchRule_block)
 // CHECK-NEXT: MSStruct (SubjectMatchRule_record)
Index: clang/test/CodeGenCXX/attr-loader-uninitialized.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGenCXX/attr-loader-uninitialized.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+
+// CHECK: @defn = global i32 undef
+int defn  [[clang::loader_uninitialized]];
+
+// CHECK: @_ZL11defn_static = internal global i32 undef
+static int defn_static [[clang::loader_uninitialized]] __attribute__((used));
+
+// CHECK: @_ZZ4funcvE4data = internal global i32 undef
+int* func(void)
+{
+  static int data [[clang::loader_uninitialized]];
+  return &data;
+}
+
+class trivial
+{
+  float x;
+};
+
+// CHECK: @ut = global %class.trivial undef
+trivial ut [[clang::loader_uninitialized]];
+
+// CHECK: @arr = global [32 x double] undef, align 16
+double arr[32] __attribute__((loader_uninitialized));
+
+// Defining as arr2[] [[clang..]] raises the error: attribute cannot be applied to types
+// CHECK: @arr2 = global [4 x double] undef, align 16
+double arr2 [[clang::loader_uninitialized]] [4];
Index: clang/test/CodeGen/attr-loader-uninitialized.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/attr-loader-uninitialized.c
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
+
+// CHECK: @tentative_attr_first = weak global i32 undef, align 4
+int tentative_attr_first __attribute__((loader_uninitialized));
+int tentative_attr_first;
+
+// CHECK: @tentative_attr_second = weak global i32 undef, align 4
+int tentative_attr_second;
+int tentative_attr_second __attribute__((loader_uninitialized));
+
+// CHECK: @array = weak global [16 x float] undef, align 16
+float array[16] __attribute__((loader_uninitialized));
+
+typedef struct
+{
+  int x;
+  float y;
+} s;
+
+// CHECK: @i = weak global %struct.s undef, align 4
+s i __attribute__((loader_uninitialized));
+
+// CHECK: @private_extern_ok = hidden global i32 undef, align 4
+__private_extern__ int private_extern_ok __attribute__((loader_uninitialized));
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -7427,6 +7427,10 @@
     handleUninitializedAttr(S, D, AL);
     break;
 
+  case ParsedAttr::AT_LoaderUninitialized:
+    handleSimpleAttribute<LoaderUninitializedAttr>(S, D, AL);
+    break;
+
   case ParsedAttr::AT_ObjCExternallyRetained:
     handleObjCExternallyRetainedAttr(S, D, AL);
     break;
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -2712,6 +2712,18 @@
         --E;
         continue;
       }
+    } else if (isa<LoaderUninitializedAttr>(NewAttribute)) {
+      // If there is a C definition followed by a redeclaration with this
+      // attribute then there are two different definitions. In C++, prefer the
+      // standard diagnostics.
+      if (!S.getLangOpts().CPlusPlus) {
+        S.Diag(NewAttribute->getLocation(),
+               diag::err_loader_uninitialized_redeclaration);
+        S.Diag(Def->getLocation(), diag::note_previous_definition);
+        NewAttributes.erase(NewAttributes.begin() + I);
+        --E;
+        continue;
+      }
     } else if (isa<SelectAnyAttr>(NewAttribute) &&
                cast<VarDecl>(New)->isInline() &&
                !cast<VarDecl>(New)->isInlineSpecified()) {
@@ -11934,6 +11946,13 @@
     return;
   }
 
+  // The LoaderUninitialized attribute acts as a definition (of undef).
+  if (VDecl->hasAttr<LoaderUninitializedAttr>()) {
+    Diag(VDecl->getLocation(), diag::err_loader_uninitialized_cant_init);
+    VDecl->setInvalidDecl();
+    return;
+  }
+
   // Get the decls type and save a reference for later, since
   // CheckInitializerTypes may change it.
   QualType DclT = VDecl->getType(), SavT = DclT;
@@ -12347,6 +12366,21 @@
       return;
     }
 
+    if (!Var->isInvalidDecl() && RealDecl->hasAttr<LoaderUninitializedAttr>()) {
+      if (CXXRecordDecl *RD = Var->getType()->getAsCXXRecordDecl()) {
+        if (!RD->hasTrivialDefaultConstructor()) {
+          Diag(Var->getLocation(), diag::err_loader_uninitialized_trivial_ctor);
+          Var->setInvalidDecl();
+          return;
+        }
+      }
+      if (Var->getStorageClass() == SC_Extern) {
+        Diag(Var->getLocation(), diag::err_loader_uninitialized_extern_decl);
+        Var->setInvalidDecl();
+        return;
+      }
+    }
+
     VarDecl::DefinitionKind DefKind = Var->isThisDeclarationADefinition();
     if (!Var->isInvalidDecl() && DefKind != VarDecl::DeclarationOnly &&
         Var->getType().hasNonTrivialToPrimitiveDefaultInitializeCUnion())
Index: clang/lib/CodeGen/CodeGenModule.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenModule.cpp
+++ clang/lib/CodeGen/CodeGenModule.cpp
@@ -3942,6 +3942,8 @@
   if (getLangOpts().CUDA &&
       (IsCUDASharedVar || IsCUDAShadowVar || IsHIPPinnedShadowVar))
     Init = llvm::UndefValue::get(getTypes().ConvertType(ASTTy));
+  else if (D->hasAttr<LoaderUninitializedAttr>())
+    Init = llvm::UndefValue::get(getTypes().ConvertType(ASTTy));
   else if (!InitExpr) {
     // This is a tentative definition; tentative definitions are
     // implicitly initialized with { 0 }.
Index: clang/lib/CodeGen/CGDecl.cpp
===================================================================
--- clang/lib/CodeGen/CGDecl.cpp
+++ clang/lib/CodeGen/CGDecl.cpp
@@ -249,7 +249,7 @@
   // variables cannot have an initializer.
   llvm::Constant *Init = nullptr;
   if (Ty.getAddressSpace() == LangAS::opencl_local ||
-      D.hasAttr<CUDASharedAttr>())
+      D.hasAttr<CUDASharedAttr>() || D.hasAttr<LoaderUninitializedAttr>())
     Init = llvm::UndefValue::get(LTy);
   else
     Init = EmitNullConstant(Ty);
Index: clang/lib/AST/DeclBase.cpp
===================================================================
--- clang/lib/AST/DeclBase.cpp
+++ clang/lib/AST/DeclBase.cpp
@@ -454,7 +454,8 @@
 }
 
 bool Decl::hasDefiningAttr() const {
-  return hasAttr<AliasAttr>() || hasAttr<IFuncAttr>();
+  return hasAttr<AliasAttr>() || hasAttr<IFuncAttr>() ||
+         hasAttr<LoaderUninitializedAttr>();
 }
 
 const Attr *Decl::getDefiningAttr() const {
@@ -462,6 +463,8 @@
     return AA;
   if (auto *IFA = getAttr<IFuncAttr>())
     return IFA;
+  if (auto *NZA = getAttr<LoaderUninitializedAttr>())
+    return NZA;  
   return nullptr;
 }
 
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5334,6 +5334,14 @@
   "initializer for aggregate is not a compile-time constant">, InGroup<C99>;
 def err_local_cant_init : Error<
   "'__local' variable cannot have an initializer">;
+def err_loader_uninitialized_cant_init : Error<
+  "variable with 'loader_uninitialized' attribute cannot have an initializer">;
+def err_loader_uninitialized_trivial_ctor : Error<
+  "variable with 'loader_uninitialized' attribute must have a trivial default constructor">;
+def err_loader_uninitialized_redeclaration : Error<
+  "redeclaration cannot add 'loader_uninitialized' attribute">;
+def err_loader_uninitialized_extern_decl : Error<
+  "external declaration of variable cannot have the 'loader_uninitialized' attribute">;
 def err_block_extern_cant_init : Error<
   "'extern' variable cannot have an initializer">;
 def warn_extern_init : Warning<"'extern' variable has an initializer">,
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ clang/include/clang/Basic/AttrDocs.td
@@ -4358,6 +4358,29 @@
   }];
 }
 
+def LoaderUninitializedDocs : Documentation {
+  let Category = DocCatVariable;
+  let Content = [{
+The ``loader_uninitialized`` attribute can be placed on global variables to
+indicate that the variable does not need to be zero initialized by the loader.
+On most targets, zero-initialization does not incur any additional cost.
+For example, most general purpose operating systems deliberately ensure
+that all memory is properly initialized in order to avoid leaking privileged
+information from the kernel or other programs. However, some targets
+do not make this guarantee, and on these targets, avoiding an unnecessary
+zero-initialization can have a significant impact on load times and/or code
+size.
+
+A declaration with this attribute is a non-tentative definition just as if it
+provided an initializer. Variables with this attribute are considered to be
+uninitialized in the same sense as a local variable, and the programs must
+write to them before reading from them. If the variable's type is a C++ class
+type with a non-trivial default constructor, or an array thereof, this attribute
+only suppresses the static zero-initialization of the variable, not the dynamic
+initialization provided by executing the default constructor.
+  }];
+}
+
 def CallbackDocs : Documentation {
   let Category = DocCatFunction;
   let Content = [{
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -3430,6 +3430,12 @@
   let Documentation = [UninitializedDocs];
 }
 
+def LoaderUninitialized : Attr {
+  let Spellings = [Clang<"loader_uninitialized">];
+  let Subjects = SubjectList<[GlobalVar]>;
+  let Documentation = [LoaderUninitializedDocs];
+}
+  
 def ObjCExternallyRetained : InheritableAttr {
   let LangOpts = [ObjCAutoRefCount];
   let Spellings = [Clang<"objc_externally_retained">];
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to