[llvm-commits] CVS: llvm-gcc/gcc/llvm-types.c

Chris Lattner lattner at cs.uiuc.edu
Mon Jul 25 18:17:33 PDT 2005



Changes in directory llvm-gcc/gcc:

llvm-types.c updated: 1.24 -> 1.25
---
Log message:

Fix PR449: http://llvm.cs.uiuc.edu/PR449  and PR603: http://llvm.cs.uiuc.edu/PR603  by being VERY VERY careful to match the target layout
when laying out the LLVM type for a C type.  In particular, do not assume
silly things (like types always having the same alignment whenever they
are used) that hold for every target but darwin.

This fixes Regression/C++/ofstream_ctor.cpp.



---
Diffs of the changes:  (+113 -74)

 llvm-types.c |  187 +++++++++++++++++++++++++++++++++++------------------------
 1 files changed, 113 insertions(+), 74 deletions(-)


Index: llvm-gcc/gcc/llvm-types.c
diff -u llvm-gcc/gcc/llvm-types.c:1.24 llvm-gcc/gcc/llvm-types.c:1.25
--- llvm-gcc/gcc/llvm-types.c:1.24	Fri Jul 22 13:53:38 2005
+++ llvm-gcc/gcc/llvm-types.c	Mon Jul 25 20:17:22 2005
@@ -75,48 +75,30 @@
  */
 static unsigned PrimitiveAlignments[OpaqueTyID];
 
-static unsigned getMinTargetAlignment(tree Type) {
-  unsigned BasicAlignment = TYPE_ALIGN(Type);
-  unsigned TestAlignment;
+static void InitializeAlignments(void) {
+  unsigned MaxAlign = BIGGEST_ALIGNMENT;
+#ifdef BIGGEST_FIELD_ALIGNMENT
+  MaxAlign = MIN(MaxAlign, BIGGEST_FIELD_ALIGNMENT);
+#endif
   
-  /* Some targets do funny things with structs.  Form a struct that has a
-   * character member as the first element, then Type as the second element.
-   * If that alignment is less than BasicAlignment, use it.
-   */
-  tree recordtype = (*lang_hooks.types.make_type) (RECORD_TYPE);
-  tree field, fields;
-  /* First character field. */
-  fields = build_decl (FIELD_DECL, NULL_TREE, unsigned_intQI_type_node);
-
-  /* A field of type Type. */
-  field = build_decl (FIELD_DECL, NULL_TREE, Type);
-  TREE_CHAIN (field) = fields;
-  finish_builtin_struct(recordtype, "", field, NULL_TREE);
-
-  llvm_type_dump(llvm_type_get_from_tree(recordtype));
+#ifdef LLVM_TARGET_MAX_ALIGN_IS_POINTER_SIZE
+  /* Targets like PowerPC where the longs and doubles are 4-byte aligned. */
+  MaxAlign = MIN(MaxAlign, POINTER_SIZE/BITS_PER_UNIT);
+#endif
   
-  TestAlignment = TYPE_ALIGN(recordtype);
-  BasicAlignment = MIN(BasicAlignment, TestAlignment);
-  return BasicAlignment/8;
-}
-
-static void InitializeAlignments(void) {
   /* Figure out the alignments of the primitive types. */
   PrimitiveAlignments[BoolTyID]   = 1;
   PrimitiveAlignments[SByteTyID]  = 1;
   PrimitiveAlignments[UByteTyID]  = 1;
-  PrimitiveAlignments[ShortTyID]  = getMinTargetAlignment(intHI_type_node);
-  PrimitiveAlignments[UShortTyID] =
-    getMinTargetAlignment(unsigned_intHI_type_node);
-  PrimitiveAlignments[IntTyID]  = getMinTargetAlignment(intSI_type_node);
-  PrimitiveAlignments[UIntTyID] = 
-    getMinTargetAlignment(unsigned_intSI_type_node);
-  PrimitiveAlignments[LongTyID]  = getMinTargetAlignment(intDI_type_node);
-  PrimitiveAlignments[ULongTyID] =
-    getMinTargetAlignment(unsigned_intDI_type_node);
-  PrimitiveAlignments[FloatTyID] = getMinTargetAlignment(float_type_node);
-  PrimitiveAlignments[DoubleTyID]  = getMinTargetAlignment(double_type_node);
-  PrimitiveAlignments[PointerTyID] = getMinTargetAlignment(ptr_type_node);
+  PrimitiveAlignments[ShortTyID]  = PrimitiveAlignments[UShortTyID]
+    = MIN(2, MaxAlign);
+  PrimitiveAlignments[IntTyID]  = PrimitiveAlignments[UIntTyID]
+    = MIN(4, MaxAlign);
+  PrimitiveAlignments[ULongTyID] = PrimitiveAlignments[LongTyID]
+    = MIN(8, MaxAlign);
+  PrimitiveAlignments[FloatTyID] = MIN(4, MaxAlign);
+  PrimitiveAlignments[DoubleTyID]  = MIN(8, MaxAlign);
+  PrimitiveAlignments[PointerTyID] = MIN(POINTER_SIZE/BITS_PER_UNIT, MaxAlign);
 }
 
 unsigned llvm_type_get_alignment(llvm_type *Ty) {
@@ -739,7 +721,7 @@
   llvm_type_print(FieldTy, stderr);
   fprintf(stderr, " name='%s' talign=%d dalign=%d\n", DECL_NAME(field) ? 
           IDENTIFIER_POINTER(DECL_NAME(field)) : "<empty>",
-          GetFieldAlignmentInBits(field), TYPE_ALIGN(TREE_TYPE(field))/8);
+          GetFieldAlignmentInBytes(field), TYPE_ALIGN(TREE_TYPE(field))/8);
 }
 #endif
 
@@ -787,32 +769,33 @@
   llvm_type *Ty = llvm_type_get_from_tree(TREE_TYPE(field));
   /* Get the starting offset in the record... */
   unsigned StartOffset = GetFieldOffset(field);               /* In bits */
-  unsigned BitAlignment = GetFieldAlignmentInBits(field);    /* In bits */
-  unsigned ByteAlignment = (BitAlignment+7)/8;
+  unsigned ByteAlignment = llvm_type_get_alignment(Ty);
   
   if (!TypeIsRecursivelyIntegral(Ty)) {             /* Not an integral field? */
+    unsigned OrigSize = *Size;
     /* If this field is not an integral type, just include it directly. */
     assert((StartOffset & 7) == 0 && "Member not byte aligned??");
 
     /* Round *Size up to take into consideration alignment of this field */
     *Size = (*Size + ByteAlignment - 1) & ~(ByteAlignment-1);
 
-    /* Check to see if there is "magic padding" that got inserted into the
-     * structure.  This can happen, for example, when the C++ ABI declares that
-     * two types to not exist at the same offset.  For this reason, a byte of
-     * padding is inserted, and then the layout of the next element occurs at
-     * whatever alignment is reasonable for it.
+    /* Check to see if the next element starts further from the previous element
+     * than the LLVM alignment would put it.  If so, insert some dummy padding
+     * to ensure that the LLVM conception of where this element lands is the
+     * same as what GCC thinks.
      */
-    if (*Size < StartOffset/8)
-      /* Only fix things if it is because of this "magic padding" */
-      if (*Size + ByteAlignment == StartOffset/8) {
-        ElementTys[*Idx] = UByteTy;    /* Random pad element */
-        ElementOffsets[*Idx] = *Size;
-        ElementAlignments[*Idx] = 1;
-        ++*Idx;
-        *Size = StartOffset/8;
-      }
-
+    if (*Size < StartOffset/8) {
+      unsigned PadBytes = StartOffset/8 - OrigSize;
+      if (PadBytes == 1)
+        ElementTys[*Idx] = UByteTy;
+      else
+        ElementTys[*Idx] = llvm_type_get_array(UByteTy, PadBytes);
+      ElementOffsets[*Idx] = OrigSize;
+      ElementAlignments[*Idx] = 1;
+      ++*Idx;
+      *Size = OrigSize + PadBytes;
+    }
+    
 #if 0  /* FIXME: This assertion should be kept!!! */
     assert(*Size == StartOffset/8 &&
            "Member does not start where we think it does?");
@@ -826,14 +809,17 @@
              DECL_BIT_FIELD(field)) {
     unsigned NumPads;
     unsigned DeclSize = GetDeclSize(field);
+    unsigned FieldCBitAlignment = GetFieldAlignmentInBits(field);
+    unsigned FieldCByteAlignment = (FieldCBitAlignment+7)/8;
     /* Is it attempting to align the current offset to some value? */
     if (DeclSize == 0) {
-      NumPads = ByteAlignment - (*Size % ByteAlignment);
-      if (NumPads == ByteAlignment) NumPads = 0;
-      assert((*Size+NumPads) % ByteAlignment == 0 &&"Incorrect padding calc?");
+      NumPads = FieldCByteAlignment - (*Size % FieldCByteAlignment);
+      if (NumPads == FieldCByteAlignment) NumPads = 0;
+      assert((*Size+NumPads) % FieldCByteAlignment == 0 &&
+             "Incorrect padding calc?");
 #if DEBUG_STRUCT_LAYOUT
       fprintf(stderr, "Anon field: align=%db pads = %d ",
-              BitAlignment, NumPads);
+              FieldCByteAlignment, NumPads);
       PrintFieldInfo(field);
 #endif
     } else {
@@ -864,15 +850,18 @@
      * if the alignment allows for it.  Thus, we start out with the element
      * size, and round up to the alignment as necessary.
      */
-    unsigned ElSize = GetDeclSize(field);  /* In bits */
+    unsigned ElSizeInBits = GetDeclSize(field);  /* In bits */
+    unsigned FieldCBitAlignment = GetFieldAlignmentInBits(field);
+    unsigned FieldCByteAlignment = (FieldCBitAlignment+7)/8;
+
     int HasSignedField;
     unsigned StartByte;
-    if (ElSize && BitAlignment > ElSize) ElSize = BitAlignment;
+    if (ElSizeInBits) ElSizeInBits = MAX(ElSizeInBits, FieldCBitAlignment);
 
     HasSignedField = !TREE_UNSIGNED(TREE_TYPE(field));
 
     /* Calculate the first byte occupied by this field */
-    StartByte = StartOffset/8 - (StartOffset/8) % ByteAlignment;
+    StartByte = StartOffset/8 - (StartOffset/8) % FieldCByteAlignment;
 
     /* Check to see if we have emitted any structure elements that overlap with
      * the current bitfield.
@@ -882,9 +871,9 @@
        * encompasses this type.  If so, we just have to update the signedness if
        * the field is not yet signed.
        */
-      if (StartByte*8+ElSize <= *Size * 8) {
+      if (StartByte*8+ElSizeInBits <= *Size * 8) {
         assert(ElementOffsets[*Idx-1] <= StartByte &&
-               ElementAlignments[*Idx-1] >= ByteAlignment &&
+               ElementAlignments[*Idx-1] >= FieldCByteAlignment &&
                "Less aligned field overlaps with later, more aligned, field?");
         /* If the last field is a bool, expand it to be a uchar */
         if (ElementTys[*Idx-1] == BoolTy)
@@ -910,8 +899,8 @@
       } while (*Idx && *Size > StartByte);
 
       /* Output this as a series of integer fields. */
-      while (ElSize > 64) {
-        unsigned UnitSize = ElSize & 63;
+      while (ElSizeInBits > 64) {
+        unsigned UnitSize = ElSizeInBits & 63;
         /* Eliminate all but one bit from the size */
         if ((UnitSize & (UnitSize-1)) != 0)
           UnitSize = UnitSize ^ (UnitSize & (UnitSize-1));
@@ -923,10 +912,27 @@
         ElementAlignments[*Idx] = 1;
         ++*Idx;
         StartByte += UnitSize/8;
-        ElSize -= UnitSize;
+        ElSizeInBits -= UnitSize;
       }
 
-      Ty = llvm_type_get_integer(ElSize, !HasSignedField);
+      Ty = llvm_type_get_integer(ElSizeInBits, !HasSignedField);
+    }
+
+    /* Check to see if the next element starts further from the previous element
+     * than the LLVM alignment would put it.  If so, insert some dummy padding
+     * to ensure that the LLVM conception of where this element lands is the
+     * same as what GCC thinks.
+     */
+    if (((*Size + ByteAlignment - 1) & ~(ByteAlignment-1)) < StartOffset/8) {
+      unsigned PadBytes = StartOffset/8 - *Size;
+      if (PadBytes == 1)
+        ElementTys[*Idx] = UByteTy;
+      else
+        ElementTys[*Idx] = llvm_type_get_array(UByteTy, PadBytes);
+      ElementOffsets[*Idx] = *Size;
+      ElementAlignments[*Idx] = 1;
+      ++*Idx;
+      *Size = *Size + PadBytes;
     }
 
     /* Check to see if there is "magic padding" that got inserted into the
@@ -939,7 +945,7 @@
       /* Only fix things if it is because of this "magic padding" */
       if (*Size + ByteAlignment == StartByte) {
         /* Random pad element */
-        ElementTys[*Idx] = llvm_type_get_integer(BitAlignment, 1);
+        ElementTys[*Idx] = llvm_type_get_integer(ByteAlignment*8, 1);
         ElementOffsets[*Idx] = *Size;
         ElementAlignments[*Idx] = ByteAlignment;
         ++*Idx;
@@ -1443,13 +1449,46 @@
 #endif
     }
 
-    /* Empty C++ structures == { ubyte } in LLVM so that sizes are correct. */
-    if (Idx == 0 && (int)TREE_INT_CST_LOW(TYPE_SIZE(type)) == 8) {
-      StructElements[0] = UByteTy;
-      ElementOffsets[0] = 0;
-      ++Idx;
-    }
+    /* If we are missing elements from the end of the structure (which
+     * contribute to its size but are not accessed by the program), add dummy
+     * elements so that the LLVM code will have the right size for the
+     * structure.
+     */
+    {
+      unsigned GCCTypeSize = ((unsigned)TREE_INT_CST_LOW(TYPE_SIZE(type))+7)/8;
+      unsigned LLVMTypeSize, LLVMStructAlign = 1, i;
+      
+      /* To determine what LLVM will think the size of this struct is, compute
+       * the LLVM alignment the struct will have.
+      */
+      for (i = 0; i != Idx; ++i) {
+        unsigned EltAlign = llvm_type_get_alignment(StructElements[i]);
+        LLVMStructAlign = MAX(LLVMStructAlign, EltAlign);
+      }
+      
+      /* The LLVM size of the struct will be the current size, rounded up to the
+       * next multiple of StructAlign.
+       */
+      assert((LLVMStructAlign & (LLVMStructAlign-1)) == 0 &&
+             "Alignment not a power of 2!");
+      LLVMTypeSize = (Size+LLVMStructAlign-1) & ~(LLVMStructAlign-1);
 
+      /* If the LLVM type will end up being too small, add elements to the end
+       * of the struct to pad it out.
+       */
+      if (LLVMTypeSize < GCCTypeSize) {
+        unsigned PadBytes = GCCTypeSize - Size;
+        if (PadBytes == 1)
+          StructElements[Idx] = UByteTy;
+        else
+          StructElements[Idx] = llvm_type_get_array(UByteTy, PadBytes);
+        ElementOffsets[Idx] = Size;
+        ElementAlignments[Idx] = 1;
+        ++Idx;
+        Size += PadBytes;
+      }
+    }
+      
     /* End of the hack, set the real number of elements. */
     Result->NumElements = Idx;
 






More information about the llvm-commits mailing list