Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [NoTrivialAutoVarInitDocs];
let SimpleHandler = 1;
}
12 changes: 12 additions & 0 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -8719,6 +8719,18 @@ Attribute used by `clspv`_ (OpenCL-C to Vulkan SPIR-V compiler) to identify func
}];
}

def NoTrivialAutoVarInitDocs : Documentation {
let Category = DocCatDecl;
let Content = [{
The ``__declspec(no_init_all)`` attribute disables the automatic initialization that the
`-ftrivial-auto-var-init`_ flag would have applied to locals in a marked function, or instances of
a marked type. Note that this attribute has no effect for locals that are automatically initialized
without the `-ftrivial-auto-var-init`_ flag.

.. _`-ftrivial-auto-var-init`: ClangCommandLineReference.html#cmdoption-clang-ftrivial-auto-var-init
}];
}

def DocCatNonBlockingNonAllocating : DocumentationCategory<"Performance Constraint Attributes"> {
let Content = [{
The ``nonblocking``, ``blocking``, ``nonallocating`` and ``allocating`` attributes can be attached
Expand Down
22 changes: 12 additions & 10 deletions clang/lib/CodeGen/CGDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1899,13 +1899,16 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
const Address Loc =
locIsByrefHeader ? emission.getObjectAddress(*this) : emission.Addr;

auto hasNoTrivialAutoVarInitAttr = [&](const Decl *D) {
return D && D->hasAttr<NoTrivialAutoVarInitAttr>();
};
// Note: constexpr already initializes everything correctly.
LangOptions::TrivialAutoVarInitKind trivialAutoVarInit =
(D.isConstexpr()
((D.isConstexpr() || D.getAttr<UninitializedAttr>() ||
hasNoTrivialAutoVarInitAttr(type->getAsTagDecl()) ||
hasNoTrivialAutoVarInitAttr(CurFuncDecl))
? LangOptions::TrivialAutoVarInitKind::Uninitialized
: (D.getAttr<UninitializedAttr>()
? LangOptions::TrivialAutoVarInitKind::Uninitialized
: getContext().getLangOpts().getTrivialAutoVarInit()));
: getContext().getLangOpts().getTrivialAutoVarInit());

auto initializeWhatIsTechnicallyUninitialized = [&](Address Loc) {
if (trivialAutoVarInit ==
Expand Down Expand Up @@ -1944,13 +1947,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());
}
Expand All @@ -1967,8 +1970,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);
}
}
Expand Down
59 changes: 59 additions & 0 deletions clang/test/CodeGenCXX/auto-var-init-attr.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
}
Loading