llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang-codegen Author: Daniel Paoliello (dpaoliello) <details> <summary>Changes</summary> In MSVC, when `/d1initall` is enabled, `__declspec(no_init_all)` can be applied to a type to suppress auto-initialization for all instances of that type or to a function to suppress auto-initialization for all locals within that function. This change does the same for Clang, except that it applies to the `-ftrivial-auto-var-init` flag instead. NOTE: * I did not add a Clang-specific spelling for this but would be happy to make a followup PR if folks are interested in that. * Since this is implementing a `__declspec` only, I chose to leave it undocumented. --- Full diff: https://github.com/llvm/llvm-project/pull/116847.diff 3 Files Affected: - (modified) clang/include/clang/Basic/Attr.td (+7) - (modified) clang/lib/CodeGen/CGDecl.cpp (+12-7) - (added) clang/test/CodeGenCXX/auto-var-init-attr.cpp (+59) ``````````diff diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 6035a563d5fce7..5d3270280c17f6 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -4888,3 +4888,10 @@ def ClspvLibclcBuiltin: InheritableAttr { let Documentation = [ClspvLibclcBuiltinDoc]; let SimpleHandler = 1; } + +def NoTrivialAutoVarInit: InheritableAttr { + let Spellings = [Declspec<"no_init_all">]; + let Subjects = SubjectList<[Function, Tag]>; + let Documentation = [Undocumented]; + let SimpleHandler = 1; +} diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 6e9d28cea28e79..ff53ffae4459af 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -1900,10 +1900,16 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) { locIsByrefHeader ? emission.getObjectAddress(*this) : emission.Addr; // Note: constexpr already initializes everything correctly. + auto typeHasNoTrivialAutoVarInitAttr = [&]() { + auto *TD = type->getAsTagDecl(); + return TD && TD->hasAttr<NoTrivialAutoVarInitAttr>(); + }; LangOptions::TrivialAutoVarInitKind trivialAutoVarInit = (D.isConstexpr() ? LangOptions::TrivialAutoVarInitKind::Uninitialized - : (D.getAttr<UninitializedAttr>() + : ((D.getAttr<UninitializedAttr>() || + typeHasNoTrivialAutoVarInitAttr() || + CurFuncDecl->hasAttr<NoTrivialAutoVarInitAttr>()) ? LangOptions::TrivialAutoVarInitKind::Uninitialized : getContext().getLangOpts().getTrivialAutoVarInit())); @@ -1944,13 +1950,13 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) { replaceUndef(CGM, isPattern, constant)); } - if (constant && D.getType()->isBitIntType() && - CGM.getTypes().typeRequiresSplitIntoByteArray(D.getType())) { + if (constant && type->isBitIntType() && + CGM.getTypes().typeRequiresSplitIntoByteArray(type)) { // Constants for long _BitInt types are split into individual bytes. // Try to fold these back into an integer constant so it can be stored // properly. - llvm::Type *LoadType = CGM.getTypes().convertTypeForLoadStore( - D.getType(), constant->getType()); + llvm::Type *LoadType = + CGM.getTypes().convertTypeForLoadStore(type, constant->getType()); constant = llvm::ConstantFoldLoadFromConst( constant, LoadType, llvm::APInt::getZero(32), CGM.getDataLayout()); } @@ -1967,8 +1973,7 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) { // It may be that the Init expression uses other uninitialized memory, // but auto-var-init here would not help, as auto-init would get // overwritten by Init. - if (!D.getType()->isScalarType() || capturedByInit || - isAccessedBy(D, Init)) { + if (!type->isScalarType() || capturedByInit || isAccessedBy(D, Init)) { initializeWhatIsTechnicallyUninitialized(Loc); } } diff --git a/clang/test/CodeGenCXX/auto-var-init-attr.cpp b/clang/test/CodeGenCXX/auto-var-init-attr.cpp new file mode 100644 index 00000000000000..5481c6e8613c56 --- /dev/null +++ b/clang/test/CodeGenCXX/auto-var-init-attr.cpp @@ -0,0 +1,59 @@ +// RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown -fblocks -fdeclspec -ftrivial-auto-var-init=zero %s -emit-llvm -o - | FileCheck %s + +struct S { char c; }; +class C { char c; }; +enum class E { ZERO }; +union U { char c; int i; }; + +struct __declspec(no_init_all) NoInitS { char c; }; +class __declspec(no_init_all) NoInitC { char c; }; +enum class __declspec(no_init_all) NoInitE { ZERO }; +union __declspec(no_init_all) NoInitU { char c; int i; }; + +extern "C" { + void test_no_attr() { + // CHECK-LABEL: @test_no_attr() + // CHECK-NEXT: entry: + // CHECK-NEXT: %s = alloca %struct.S, align 1 + // CHECK-NEXT: %c = alloca %class.C, align 1 + // CHECK-NEXT: %e = alloca i32, align 4 + // CHECK-NEXT: %u = alloca %union.U, align 4 + // CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 1 %s, i8 0, i64 1, i1 false) + // CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 1 %c, i8 0, i64 1, i1 false) + // CHECK-NEXT: store i32 0, ptr %e, align 4 + // CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 4 %u, i8 0, i64 4, i1 false) + // CHECK-NEXT ret void + S s; + C c; + E e; + U u; + } + + void __declspec(no_init_all) test_attr_on_function() { + // CHECK-LABEL: @test_attr_on_function() + // CHECK-NEXT: entry: + // CHECK-NEXT: %s = alloca %struct.S, align 1 + // CHECK-NEXT: %c = alloca %class.C, align 1 + // CHECK-NEXT: %e = alloca i32, align 4 + // CHECK-NEXT: %u = alloca %union.U, align 4 + // CHECK-NEXT: ret void + S s; + C c; + E e; + U u; + } + + void test_attr_on_decl() { + // CHECK-LABEL: @test_attr_on_decl() + // CHECK-NEXT: entry: + // CHECK-NEXT: %s = alloca %struct.NoInitS, align 1 + // CHECK-NEXT: %c = alloca %class.NoInitC, align 1 + // CHECK-NEXT: %e = alloca i32, align 4 + // CHECK-NEXT: %u = alloca %union.NoInitU, align 4 + // CHECK-NEXT: ret void + NoInitS s; + NoInitC c; + NoInitE e; + NoInitU u; + } +} \ No newline at end of file `````````` </details> https://github.com/llvm/llvm-project/pull/116847 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits