Here's a patch to fix non-constant struct initializers.  If this seems
a bit too big, I can split it into a few pieces, but I figured I would
post the whole thing since I have it.  The only thing that's missing,
as far as I know, is support for initializers with elided braces; I
don't think we really have a good solution for that yet, though.

The patch is pretty straightforward; I don't think I need to say
anything more about it.

-Eli
Index: CodeGen/CGExprAgg.cpp
===================================================================
--- CodeGen/CGExprAgg.cpp       (revision 46904)
+++ CodeGen/CGExprAgg.cpp       (working copy)
@@ -18,6 +18,7 @@
 #include "llvm/Function.h"
 #include "llvm/GlobalVariable.h"
 #include "llvm/Support/Compiler.h"
+#include "llvm/Intrinsics.h"
 using namespace clang;
 using namespace CodeGen;
 
@@ -81,6 +82,9 @@
   
   void VisitConditionalOperator(const ConditionalOperator *CO);
   void VisitInitListExpr(InitListExpr *E);
+
+  void EmitInitializationToLValue(Expr *E, LValue Address);
+  void EmitNullInitializationToLValue(LValue Address, QualType T);
   //  case Expr::ChooseExprClass:
 };
 }  // end anonymous namespace.
@@ -223,81 +233,129 @@
   CGF.EmitBlock(ContBlock);
 }
 
-void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
-
-  unsigned NumInitElements = E->getNumInits();
-
-  if (!E->getType()->isArrayType()) {
-    CGF.WarnUnsupported(E, "aggregate init-list expression");
+void AggExprEmitter::EmitInitializationToLValue(Expr* E, LValue LV) {
+  // FIXME: Are initializers affected by volatile?
+  if (E->getType()->isComplexType()) {
+    CGF.EmitComplexExprIntoAddr(E, LV.getAddress(), false);
     return;
   }
+  RValue RV = CGF.EmitAnyExpr(E, LV.getAddress(), false);
+  if (CGF.hasAggregateLLVMType(E->getType()))
+    return;
+  CGF.EmitStoreThroughLValue(RV, LV, E->getType());
+}
 
-  std::vector<llvm::Constant*> ArrayElts;
-  const llvm::PointerType *APType = 
cast<llvm::PointerType>(DestPtr->getType());
-  const llvm::ArrayType *AType = 
-    cast<llvm::ArrayType>(APType->getElementType());
+void AggExprEmitter::EmitNullInitializationToLValue(LValue LV, QualType T) {
+  if (!CGF.hasAggregateLLVMType(T)) {
+    // For non-aggregates, we can store zero
+    const llvm::Type *T =
+      cast<llvm::PointerType>(LV.getAddress()->getType())->getElementType();
+    Builder.CreateStore(llvm::Constant::getNullValue(T), LV.getAddress());
+  } else {
+    // Otherwise, just memset the whole thing to zero.  This is legal
+    // because in LLVM, all default initializers are guaranteed to have a
+    // bit pattern of all zeros.
+    // There's a potential optimization opportunity in combining
+    // memsets; that would be easy for arrays, but relatively
+    // difficult for structures with the current code.
+    llvm::Value* memset = CGF.CGM.getIntrinsic(llvm::Intrinsic::memset_i64);
+    uint64_t size = CGF.getContext().getTypeSize(T, SourceLocation());
 
-  // Copy initializer elements.
-  bool AllConstElements = true;
-  unsigned i = 0;
-  for (i = 0; i != NumInitElements; ++i) {
-    if (llvm::Constant *C = 
-        dyn_cast<llvm::Constant>(CGF.EmitScalarExpr(E->getInit(i))))
-      ArrayElts.push_back(C);
-    else {
-      AllConstElements = false;
-      break;
-    }
+    const llvm::Type *BP = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+    llvm::Value* DestPtr = Builder.CreateBitCast(LV.getAddress(), BP, "tmp");
+
+    llvm::Value *MemSetOps[4] = {
+      DestPtr, llvm::ConstantInt::get(llvm::Type::Int8Ty, 0),
+      llvm::ConstantInt::get(llvm::Type::Int64Ty, size/8),
+      llvm::ConstantInt::get(llvm::Type::Int32Ty, 0)
+    };
+
+    Builder.CreateCall(memset, MemSetOps, MemSetOps+4);
   }
+}
 
-  unsigned NumArrayElements = AType->getNumElements();
-  const llvm::Type *ElementType = CGF.ConvertType(E->getInit(0)->getType());
+void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
+  if (E->isConstantExpr(CGF.getContext(), 0)) {
+    // FIXME: call into const expr emitter so that we can emit
+    // a memcpy instead of storing the individual members.
+    // This is purely for perf; both codepaths lead to equivalent
+    // (although not necessarily identical) code.
+    // It's worth noting that LLVM keeps on getting smarter, though,
+    // so it might not be worth bothering.
+  }
 
-  if (AllConstElements) {
-    // Initialize remaining array elements.
-    for (/*Do not initialize i*/; i < NumArrayElements; ++i)
-      ArrayElts.push_back(llvm::Constant::getNullValue(ElementType));
+  if (E->getType()->isArrayType()) {
+    const llvm::PointerType *APType = 
cast<llvm::PointerType>(DestPtr->getType());
+    const llvm::ArrayType *AType = 
+      cast<llvm::ArrayType>(APType->getElementType());
 
-    // Create global value to hold this array.
-    llvm::Constant *V = llvm::ConstantArray::get(AType, ArrayElts);
-    V = new llvm::GlobalVariable(V->getType(), true, 
-                                 llvm::GlobalValue::InternalLinkage,
-                                 V, ".array", 
-                                 &CGF.CGM.getModule());
-    
-    EmitAggregateCopy(DestPtr, V , E->getType());
+    unsigned NumInitElements = E->getNumInits();
+    unsigned NumArrayElements = AType->getNumElements();
+    QualType ElementType = E->getType()->getAsArrayType()->getElementType();
+    llvm::Value *Idxs[] = {
+      llvm::Constant::getNullValue(llvm::Type::Int32Ty),
+      NULL
+    };
+    llvm::Value *NextVal;
+
+    for (unsigned i = 0; i < NumArrayElements; ++i) {
+      Idxs[1] = llvm::ConstantInt::get(llvm::Type::Int32Ty, i);
+      NextVal = Builder.CreateGEP(DestPtr, Idxs, Idxs + 2, ".array");
+      if (i < NumInitElements)
+        EmitInitializationToLValue(E->getInit(i), LValue::MakeAddr(NextVal));
+      else
+        EmitNullInitializationToLValue(LValue::MakeAddr(NextVal),
+                                       ElementType);
+    }
+
     return;
   }
 
-  // Emit indiviudal array element stores.
-  unsigned index = 0;
-  llvm::Value *NextVal = NULL;
-  llvm::Value *Idxs[] = {
-    llvm::Constant::getNullValue(llvm::Type::Int32Ty),
-    NULL
-  };
-  
-  // Emit already seen constants initializers.
-  for (i = 0; i < ArrayElts.size(); i++) {
-    Idxs[1] = llvm::ConstantInt::get(llvm::Type::Int32Ty, index++);
-    NextVal = Builder.CreateGEP(DestPtr, Idxs, Idxs + 2, ".array");
-    Builder.CreateStore(ArrayElts[i], NextVal);
-  }
+  assert(E->getType()->isRecordType() && "Only support structs/unions here!");
 
-  // Emit remaining initializers
-  for (/*Do not initizalize i*/; i < NumInitElements; ++i) {
-    Idxs[1] = llvm::ConstantInt::get(llvm::Type::Int32Ty, index++);
-    NextVal = Builder.CreateGEP(DestPtr, Idxs, Idxs + 2, ".array");
-    llvm::Value *V = CGF.EmitScalarExpr(E->getInit(i));
-    Builder.CreateStore(V, NextVal);
+  // Do struct initialization; this code just sets each individual member
+  // to the approprate value.  This makes bitfield support automatic;
+  // the disadvantage is that the generated code is more difficult for
+  // the optimizer, especially with bitfields.
+  unsigned NumInitElements = E->getNumInits();
+  RecordDecl *SD = E->getType()->getAsRecordType()->getDecl();
+  unsigned numMembers = SD->getNumMembers() -
+                        SD->hasFlexibleArrayMember();
+  unsigned curInit = 0;
+  bool isUnion = E->getType()->isUnionType();
+  // Here we iterate over the fields; this makes it simpler to both
+  // default-initialize fields and skip over unnamed fields.
+  for (unsigned curFieldNo = 0; curFieldNo < numMembers; ++curFieldNo) {
+    if (curInit >= NumInitElements) {
+      // No more initializers; we're done
+      break;
+    }
+    FieldDecl *curField = SD->getMember(curFieldNo);
+    if (!curField->getIdentifier()) {
+      // Initializers can't initialize unnamed fields, e.g. "int : 20;"
+      continue;
+    }
+    LValue curLocation = CGF.EmitLValueForField(DestPtr, curField, isUnion);
+    if (curInit < NumInitElements) {
+      // Store the initializer into the field
+      // This will probably have to get a bit smarter when we support
+      // designators in initializers
+      Expr* expr = E->getInit(curInit);
+      ++curInit;
+      EmitInitializationToLValue(expr, curLocation);
+    } else {
+      // We're out of initalizers; default-initialize to null
+      EmitNullInitializationToLValue(curLocation, curField->getType());
+    }
+
+    // Unions only initialize one field
+    // (things can get weird with designators, but they aren't
+    // supported yet.)
+    if (E->getType()->isUnionType())
+      break;
   }
 
-  // Emit remaining default initializers
-  for (/*Do not initialize i*/; i < NumArrayElements; ++i) {
-    Idxs[1] = llvm::ConstantInt::get(llvm::Type::Int32Ty, index++);
-    NextVal = Builder.CreateGEP(DestPtr, Idxs, Idxs + 2, ".array");
-    Builder.CreateStore(llvm::Constant::getNullValue(ElementType), NextVal);
-  }
+  return;
 }
 
 
//===----------------------------------------------------------------------===//
_______________________________________________
cfe-dev mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev

Reply via email to