]> granicus.if.org Git - clang/commitdiff
Fix and enable generating general union initializers. Essentially, what
authorEli Friedman <eli.friedman@gmail.com>
Fri, 30 May 2008 19:58:50 +0000 (19:58 +0000)
committerEli Friedman <eli.friedman@gmail.com>
Fri, 30 May 2008 19:58:50 +0000 (19:58 +0000)
this does is reconstruct the type for structs and arrays if the type
wouldn't be compatible otherwise.

The assertion about packing in the struct type reconstruction code
sucks, but I don't see any obvious way to fix it.  Maybe we need a general
utility method to take a list of types and alignments and try to construct an
unpacked type if possible?

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@51785 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGExprConstant.cpp
test/CodeGen/union-init.c [new file with mode: 0644]

index 1144cf1c9155e16513901659a1d051b788dd79cd..4cb3c7bb2a0c1ba6a081809c9cb2368cfe4ced12 100644 (file)
@@ -92,15 +92,26 @@ public:
 
     // Copy initializer elements.
     unsigned i = 0;
+    bool RewriteType = false;
     for (; i < NumInitableElts; ++i) {
       llvm::Constant *C = Visit(ILE->getInit(i));
+      RewriteType |= (C->getType() != ElemTy);
       Elts.push_back(C);
     }
-    
+
     // Initialize remaining array elements.
     for (; i < NumElements; ++i)
       Elts.push_back(llvm::Constant::getNullValue(ElemTy));
 
+    if (RewriteType) {
+      // FIXME: Try to avoid packing the array
+      std::vector<const llvm::Type*> Types;
+      for (unsigned i = 0; i < Elts.size(); ++i)
+        Types.push_back(Elts[i]->getType());
+      const llvm::StructType *SType = llvm::StructType::get(Types, true);
+      return llvm::ConstantStruct::get(SType, Elts);
+    }
+
     return llvm::ConstantArray::get(AType, Elts);    
   }
 
@@ -166,6 +177,7 @@ public:
     // Copy initializer elements. Skip padding fields.
     unsigned EltNo = 0;  // Element no in ILE
     int FieldNo = 0; // Field no in RecordDecl
+    bool RewriteType = false;
     while (EltNo < ILE->getNumInits() && FieldNo < RD->getNumMembers()) {
       FieldDecl* curField = RD->getMember(FieldNo);
       FieldNo++;
@@ -175,22 +187,27 @@ public:
       if (curField->isBitField()) {
         InsertBitfieldIntoStruct(Elts, curField, ILE->getInit(EltNo));
       } else {
-        Elts[CGM.getTypes().getLLVMFieldNo(curField)] =
-            Visit(ILE->getInit(EltNo));
+        unsigned FieldNo = CGM.getTypes().getLLVMFieldNo(curField);
+        llvm::Constant* C = Visit(ILE->getInit(EltNo));
+        RewriteType |= (C->getType() != Elts[FieldNo]->getType());
+        Elts[FieldNo] = C;
       }
       EltNo++;
     }
 
+    if (RewriteType) {
+      // FIXME: Make this work for non-packed structs
+      assert(SType->isPacked() && "Cannot recreate unpacked structs");
+      std::vector<const llvm::Type*> Types;
+      for (unsigned i = 0; i < Elts.size(); ++i)
+        Types.push_back(Elts[i]->getType());
+      SType = llvm::StructType::get(Types, true);
+    }
+
     return llvm::ConstantStruct::get(SType, Elts);
   }
 
   llvm::Constant *EmitUnionInitialization(InitListExpr *ILE) {
-    // FIXME: Need to make this work correctly for unions in structs/arrays
-    CGM.WarnUnsupported(ILE, "bitfield initialization");
-    return llvm::UndefValue::get(CGM.getTypes().ConvertType(ILE->getType()));
-
-    // Following is a partial implementation; it doesn't work correctly
-    // because the parent struct/arrays don't adapt their type yet, though
     RecordDecl *RD = ILE->getType()->getAsRecordType()->getDecl();
     const llvm::Type *Ty = ConvertType(ILE->getType());
 
diff --git a/test/CodeGen/union-init.c b/test/CodeGen/union-init.c
new file mode 100644 (file)
index 0000000..9a515a7
--- /dev/null
@@ -0,0 +1,31 @@
+// RUN: clang -emit-llvm < %s -o -
+
+// A nice and complicated initialization example with unions from Python
+typedef int Py_ssize_t;
+
+typedef union _gc_head {
+       struct {
+               union _gc_head *gc_next;
+               union _gc_head *gc_prev;
+               Py_ssize_t gc_refs;
+       } gc;
+       long double dummy;  /* force worst-case alignment */
+} PyGC_Head;
+
+struct gc_generation {
+       PyGC_Head head;
+       int threshold; /* collection threshold */
+       int count; /* count of allocations or collections of younger
+                     generations */
+};
+
+#define NUM_GENERATIONS 3
+#define GEN_HEAD(n) (&generations[n].head)
+
+/* linked lists of container objects */
+struct gc_generation generations[NUM_GENERATIONS] = {
+       /* PyGC_Head,                           threshold,      count */
+       {{{GEN_HEAD(0), GEN_HEAD(0), 0}},       700,            0},
+       {{{GEN_HEAD(1), GEN_HEAD(1), 0}},       10,             0},
+       {{{GEN_HEAD(2), GEN_HEAD(2), 0}},       10,             0},
+};