Skip to content
This repository was archived by the owner on Oct 24, 2019. It is now read-only.

Commit 799b95f

Browse files
committed
Variable auto-init: don't initialize aggregate padding of all aggregates
Summary: C guarantees that brace-init with fewer initializers than members in the aggregate will initialize the rest of the aggregate as-if it were static initialization. In turn static initialization guarantees that padding is initialized to zero bits. Quoth the Standard: C17 6.7.9 Initialization ❡21 If there are fewer initializers in a brace-enclosed list than there are elements or members of an aggregate, or fewer characters in a string literal used to initialize an array of known size than there are elements in the array, the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration. C17 6.7.9 Initialization ❡10 If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate. If an object that has static or thread storage duration is not initialized explicitly, then: * if it has pointer type, it is initialized to a null pointer; * if it has arithmetic type, it is initialized to (positive or unsigned) zero; * if it is an aggregate, every member is initialized (recursively) according to these rules, and any padding is initialized to zero bits; * if it is a union, the first named member is initialized (recursively) according to these rules, and any padding is initialized to zero bits; <rdar://problem/50188861> Reviewers: glider, pcc, kcc, rjmccall, erik.pilkington Subscribers: jkorous, dexonsmith, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D61280 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@359628 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent a98dc4a commit 799b95f

File tree

2 files changed

+61
-3
lines changed

2 files changed

+61
-3
lines changed

lib/CodeGen/CGDecl.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1788,13 +1788,20 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
17881788
if (emission.IsConstantAggregate || D.isConstexpr()) {
17891789
assert(!capturedByInit && "constant init contains a capturing block?");
17901790
constant = ConstantEmitter(*this).tryEmitAbstractForInitializer(D);
1791-
if (constant && trivialAutoVarInit !=
1792-
LangOptions::TrivialAutoVarInitKind::Uninitialized) {
1791+
if (constant && !constant->isZeroValue() &&
1792+
(trivialAutoVarInit !=
1793+
LangOptions::TrivialAutoVarInitKind::Uninitialized)) {
17931794
IsPattern isPattern =
17941795
(trivialAutoVarInit == LangOptions::TrivialAutoVarInitKind::Pattern)
17951796
? IsPattern::Yes
17961797
: IsPattern::No;
1797-
constant = constWithPadding(CGM, isPattern,
1798+
// C guarantees that brace-init with fewer initializers than members in
1799+
// the aggregate will initialize the rest of the aggregate as-if it were
1800+
// static initialization. In turn static initialization guarantees that
1801+
// padding is initialized to zero bits. We could instead pattern-init if D
1802+
// has any ImplicitValueInitExpr, but that seems to be unintuitive
1803+
// behavior.
1804+
constant = constWithPadding(CGM, IsPattern::No,
17981805
replaceUndef(CGM, isPattern, constant));
17991806
}
18001807
}

test/CodeGen/padding-init.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ftrivial-auto-var-init=pattern %s -emit-llvm -o - | FileCheck %s
2+
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ftrivial-auto-var-init=zero %s -emit-llvm -o - | FileCheck %s
3+
4+
// C guarantees that brace-init with fewer initializers than members in the
5+
// aggregate will initialize the rest of the aggregate as-if it were static
6+
// initialization. In turn static initialization guarantees that padding is
7+
// initialized to zero bits.
8+
9+
// CHECK: @__const.partial_init.s = private unnamed_addr constant { i8, [7 x i8], i64 } { i8 42, [7 x i8] zeroinitializer, i64 0 }, align 8
10+
11+
// Technically, we could initialize this padding to non-zero because all of the
12+
// struct's members have initializers.
13+
14+
// CHECK: @__const.init_all.s = private unnamed_addr constant { i8, [7 x i8], i64 } { i8 42, [7 x i8] zeroinitializer, i64 -2401053089374216531 }, align 8
15+
16+
struct S {
17+
char c;
18+
long long l;
19+
};
20+
21+
void use(struct S*);
22+
23+
// CHECK-LABEL: @empty_braces(
24+
// CHECK: %s = alloca
25+
// CHECK-NEXT: %[[B:[0-9+]]] = bitcast %struct.S* %s to i8*
26+
// CHECK-NEXT: call void @llvm.memset{{.*}}(i8* align 8 %[[B]], i8 0,
27+
// CHECK-NEXT: call void @use(%struct.S* %s)
28+
void empty_braces() {
29+
struct S s = {};
30+
return use(&s);
31+
}
32+
33+
// CHECK-LABEL: @partial_init(
34+
// CHECK: %s = alloca
35+
// CHECK-NEXT: %[[B:[0-9+]]] = bitcast %struct.S* %s to i8*
36+
// CHECK-NEXT: call void @llvm.memcpy{{.*}}(i8* align 8 %[[B]], {{.*}}@__const.partial_init.s
37+
// CHECK-NEXT: call void @use(%struct.S* %s)
38+
void partial_init() {
39+
struct S s = { .c = 42 };
40+
return use(&s);
41+
}
42+
43+
// CHECK-LABEL: @init_all(
44+
// CHECK: %s = alloca
45+
// CHECK-NEXT: %[[B:[0-9+]]] = bitcast %struct.S* %s to i8*
46+
// CHECK-NEXT: call void @llvm.memcpy{{.*}}(i8* align 8 %[[B]], {{.*}}@__const.init_all.s
47+
// CHECK-NEXT: call void @use(%struct.S* %s)
48+
void init_all() {
49+
struct S s = { .c = 42, .l = 0xdeadbeefc0fedead };
50+
return use(&s);
51+
}

0 commit comments

Comments
 (0)