CodeGen: Fix PR40605 by splitting constant struct initializers

When emitting initializers for local structures for code built with
-ftrivial-auto-var-init, replace constant structures with sequences of
stores.

This appears to greatly help removing dead initialization stores to those
locals that are later overwritten by other data.
This also removes a lot of .rodata constants (see PR40605), replacing most
of them with immediate values (for Linux kernel the .rodata size is
reduced by ~1.9%)

llvm-svn: 355181
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index 91b0c97..a008ad0 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -969,6 +969,20 @@
   return llvm::isBytewiseValue(Init);
 }
 
+/// Decide whether we want to split a constant structure store into a sequence
+/// of its fields' stores. This may cost us code size and compilation speed,
+/// but plays better with store optimizations.
+static bool shouldSplitStructStore(CodeGenModule &CGM,
+                                   uint64_t GlobalByteSize) {
+  // Don't break structures that occupy more than one cacheline.
+  uint64_t ByteSizeLimit = 64;
+  if (CGM.getCodeGenOpts().OptimizationLevel == 0)
+    return false;
+  if (GlobalByteSize <= ByteSizeLimit)
+    return true;
+  return false;
+}
+
 static llvm::Constant *patternFor(CodeGenModule &CGM, llvm::Type *Ty) {
   // The following value is a guaranteed unmappable pointer value and has a
   // repeated byte-pattern which makes it easier to synthesize. We use it for
@@ -1201,6 +1215,8 @@
   // If the initializer is all or mostly the same, codegen with bzero / memset
   // then do a few stores afterward.
   uint64_t ConstantSize = CGM.getDataLayout().getTypeAllocSize(Ty);
+  if (!ConstantSize)
+    return;
   auto *SizeVal = llvm::ConstantInt::get(IntPtrTy, ConstantSize);
   if (shouldUseBZeroPlusStoresToInitialize(constant, ConstantSize)) {
     Builder.CreateMemSet(Loc, llvm::ConstantInt::get(Int8Ty, 0), SizeVal,
@@ -1228,6 +1244,20 @@
     return;
   }
 
+  llvm::StructType *STy = dyn_cast<llvm::StructType>(Ty);
+  // FIXME: handle the case when STy != Loc.getElementType().
+  // FIXME: handle non-struct aggregate types.
+  if (STy && (STy == Loc.getElementType()) &&
+      shouldSplitStructStore(CGM, ConstantSize)) {
+    for (unsigned i = 0; i != constant->getNumOperands(); i++) {
+      Address EltPtr = Builder.CreateStructGEP(Loc, i);
+      emitStoresForConstant(
+          CGM, D, EltPtr, isVolatile, Builder,
+          cast<llvm::Constant>(Builder.CreateExtractValue(constant, i)));
+    }
+    return;
+  }
+
   Builder.CreateMemCpy(
       Loc,
       createUnnamedGlobalFrom(CGM, D, Builder, constant, Loc.getAlignment()),