JonChesterfield updated this revision to Diff 247776.
JonChesterfield added a comment.
- Error on redeclaration with loader_uninit in C
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,58 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only
+
+int good __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 {{variable with 'loader_uninitialized' attribute cannot have external linkage}}
+
+int noargs __attribute__((loader_uninitialized(0)));
+// expected-error@-1 {{'loader_uninitialized' attribute takes no arguments}}
+
+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}}
+
+int init_rejected __attribute__((loader_uninitialized)) = 42;
+// expected-error@-1 {{variable with 'loader_uninitialized' attribute cannot have an initializer}}
+
+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,18 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only
+// See also attr-loader-uninitialized.cpp
+
+int good __attribute__((loader_uninitialized));
+
+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));
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,21 @@
+// 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));
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);
+ 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 : Error<
+ "variable with 'loader_uninitialized' attribute cannot have external linkage">;
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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits