[clang] [clang] Only set the trailing bytes to zero when filling a partially … (PR #79502)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Jan 25 22:56:28 PST 2024
https://github.com/serge-sans-paille updated https://github.com/llvm/llvm-project/pull/79502
>From e2231f4de6e835618cf30b0bab6b3cc72839dc94 Mon Sep 17 00:00:00 2001
From: serge-sans-paille <sguelton at mozilla.com>
Date: Thu, 25 Jan 2024 22:12:55 +0100
Subject: [PATCH] [clang] Only set the trailing bytes to zero when filling a
partially initialized array
Fix #79500
---
clang/lib/CodeGen/CGDecl.cpp | 60 ++++++++++++++++++-
.../test/CodeGenCXX/trivial-auto-var-init.cpp | 6 +-
.../test/CodeGenOpenCL/partial_initializer.cl | 3 +-
3 files changed, 64 insertions(+), 5 deletions(-)
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index bbe14ef4c17244f..e5a2561502afa99 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -905,6 +905,47 @@ void CodeGenFunction::EmitScalarInit(const Expr *init, const ValueDecl *D,
EmitStoreOfScalar(value, lvalue, /* isInitialization */ true);
}
+static size_t
+CountLeadingNonNullBytes(const llvm::DataLayout &DL, llvm::Constant *Init) {
+ // Zero and Undef never requires any extra stores.
+ if (Init->isNullValue() || isa<llvm::ConstantAggregateZero>(Init) ||
+ isa<llvm::ConstantPointerNull>(Init) || isa<llvm::UndefValue>(Init))
+ return 0u;
+ if (isa<llvm::ConstantInt>(Init) || isa<llvm::ConstantFP>(Init) ||
+ isa<llvm::ConstantVector>(Init) || isa<llvm::BlockAddress>(Init) ||
+ isa<llvm::ConstantExpr>(Init))
+ return DL.getTypeAllocSize(Init->getType());
+
+ // See if we can emit each element.
+ if (isa<llvm::ConstantArray>(Init) || isa<llvm::ConstantStruct>(Init)) {
+ size_t LeadingNonNullBytes = 0;
+ for (unsigned i = 0, e = Init->getNumOperands(); i != e; ++i) {
+ llvm::Constant *Elt = cast<llvm::Constant>(Init->getOperand(i));
+ size_t ExtraBytes = CountLeadingNonNullBytes(DL, Elt);
+ if (!ExtraBytes)
+ return LeadingNonNullBytes;
+ LeadingNonNullBytes += ExtraBytes;
+ }
+ return LeadingNonNullBytes;
+ }
+
+ if (llvm::ConstantDataSequential *CDS =
+ dyn_cast<llvm::ConstantDataSequential>(Init)) {
+ size_t LeadingNonNullBytes = 0;
+ for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i) {
+ llvm::Constant *Elt = CDS->getElementAsConstant(i);
+ size_t ExtraBytes = CountLeadingNonNullBytes(DL, Elt);
+ if (!ExtraBytes)
+ return LeadingNonNullBytes;
+ LeadingNonNullBytes += ExtraBytes;
+ }
+ return LeadingNonNullBytes;
+ }
+
+ // Anything else is hard and scary.
+ return 0;
+}
+
/// Decide whether we can emit the non-zero parts of the specified initializer
/// with equal or fewer than NumStores scalar stores.
static bool canEmitInitWithFewStoresAfterBZero(llvm::Constant *Init,
@@ -1209,8 +1250,23 @@ static void emitStoresForConstant(CodeGenModule &CGM, const VarDecl &D,
// If the initializer is all or mostly the same, codegen with bzero / memset
// then do a few stores afterward.
if (shouldUseBZeroPlusStoresToInitialize(constant, ConstantSize)) {
- auto *I = Builder.CreateMemSet(Loc, llvm::ConstantInt::get(CGM.Int8Ty, 0),
- SizeVal, isVolatile);
+ size_t LeadingNonNullBytes =
+ CountLeadingNonNullBytes(CGM.getDataLayout(), constant);
+ // llvm::errs() << LeadingNonNullBytes << " out of " << ConstantSize <<
+ // "\n";
+
+ llvm::Constant *Z8 = llvm::ConstantInt::get(CGM.Int8Ty, 0);
+ Address AdjustedLoc =
+ LeadingNonNullBytes ? Builder.CreateConstInBoundsByteGEP(
+ Loc.withElementType(CGM.Int8Ty),
+ CharUnits::fromQuantity(LeadingNonNullBytes))
+ : Loc;
+ auto *I = Builder.CreateMemSet(
+ AdjustedLoc, Z8,
+ llvm::ConstantInt::get(CGM.IntPtrTy,
+ ConstantSize - LeadingNonNullBytes),
+ isVolatile);
+
if (IsAutoInit)
I->addAnnotationMetadata("auto-init");
diff --git a/clang/test/CodeGenCXX/trivial-auto-var-init.cpp b/clang/test/CodeGenCXX/trivial-auto-var-init.cpp
index eed9868cad07f84..b0deb8149ed936f 100644
--- a/clang/test/CodeGenCXX/trivial-auto-var-init.cpp
+++ b/clang/test/CodeGenCXX/trivial-auto-var-init.cpp
@@ -288,14 +288,16 @@ void test_huge_uninit() {
// UNINIT-LABEL: test_huge_small_init(
// ZERO-LABEL: test_huge_small_init(
-// ZERO: call void @llvm.memset{{.*}}, i8 0, i64 65536,
+// ZERO: %[[v0:.*]] = getelementptr inbounds i8, ptr %{{.*}}, i64 4
+// ZERO: call void @llvm.memset{{.*}}(ptr {{.*}} %[[v0]], i8 0, i64 65532,
// ZERO-NOT: !annotation
// ZERO: store i8 97,
// ZERO: store i8 98,
// ZERO: store i8 99,
// ZERO: store i8 100,
// PATTERN-LABEL: test_huge_small_init(
-// PATTERN: call void @llvm.memset{{.*}}, i8 0, i64 65536,
+// PATTERN: %[[v0:.*]] = getelementptr inbounds i8, ptr %{{.*}}, i64 4
+// PATTERN: call void @llvm.memset{{.*}}(ptr {{.*}} %[[v0]], i8 0, i64 65532,
// PATTERN-NOT: !annotation
// PATTERN: store i8 97,
// PATTERN: store i8 98,
diff --git a/clang/test/CodeGenOpenCL/partial_initializer.cl b/clang/test/CodeGenOpenCL/partial_initializer.cl
index 5cc4e2b246003a1..7c01c750d1afef2 100644
--- a/clang/test/CodeGenOpenCL/partial_initializer.cl
+++ b/clang/test/CodeGenOpenCL/partial_initializer.cl
@@ -35,7 +35,8 @@ void f(void) {
// CHECK: %[[compoundliteral1:.*]] = alloca <2 x i32>, align 8
// CHECK: %[[V2:.*]] = alloca <4 x i32>, align 16
- // CHECK: call void @llvm.memset.p0.i32(ptr align 4 %A, i8 0, i32 144, i1 false)
+ // CHECK: %[[v0:.*]] = getelementptr inbounds i8, ptr %A, i32 8
+ // CHECK: call void @llvm.memset.p0.i32(ptr align 4 %[[v0]], i8 0, i32 136, i1 false)
// CHECK: %[[v2:.*]] = getelementptr inbounds [6 x [6 x float]], ptr %A, i32 0, i32 0
// CHECK: %[[v3:.*]] = getelementptr inbounds [6 x float], ptr %[[v2]], i32 0, i32 0
// CHECK: store float 1.000000e+00, ptr %[[v3]], align 4
More information about the cfe-commits
mailing list