[llvm-commits] [dragonegg] r97803 - in /dragonegg/trunk: llvm-abi-default.cpp llvm-backend.cpp llvm-convert.cpp llvm-internal.h llvm-types.cpp

Duncan Sands baldrick at free.fr
Fri Mar 5 01:50:26 PST 2010


Author: baldrick
Date: Fri Mar  5 03:50:26 2010
New Revision: 97803

URL: http://llvm.org/viewvc/llvm-project?rev=97803&view=rev
Log:
Make dragonegg capable of building clang.  The problem was the following:
a GCC record type can occur in several variants.  When converting records
to LLVM types we convert the main variant.  During the type conversion,
the index of the LLVM field corresponding to each GCC field is cached in
the GCC field.  However, these are the fields of the main variant, not of
the original type.  In fact the fields of type variants are never the same
as the fields of the main variant, because their DECL_CONTEXT points to the
containing type, which differs by definition between variants.  As a result,
if we had a COMPONENT_REF with a field of a variant, there would be no LLVM
index cached in the field, and we would fall over with an assertion failure.
For example, when compiling clang.  Curiously llvm-gcc does not fail on this,
yet it has exactly the same bug.  Presumably this means that gcc-4.2 never
does a COMPONENT_REF on a type variant.  Indeed gcc-4.5 hardly ever does it
either - it takes weird template code to produce an example (the testcase is
CodeCompleteConsumer.ii in the dragonegg testsuite).

There are several ways of fixing this.  I chose a rather exotic way: don't
have the type conversion logic calculate LLVM indices for fields at all.
Instead, compute them (and cache them) on the fly when needed.  The result
should be exactly the same as before (less the crashes), except for bitfields:
if a bitfield does not start in the first byte of the LLVM field then you get
worse code.  I plan to do something about this later.

Modified:
    dragonegg/trunk/llvm-abi-default.cpp
    dragonegg/trunk/llvm-backend.cpp
    dragonegg/trunk/llvm-convert.cpp
    dragonegg/trunk/llvm-internal.h
    dragonegg/trunk/llvm-types.cpp

Modified: dragonegg/trunk/llvm-abi-default.cpp
URL: http://llvm.org/viewvc/llvm-project/dragonegg/trunk/llvm-abi-default.cpp?rev=97803&r1=97802&r2=97803&view=diff
==============================================================================
--- dragonegg/trunk/llvm-abi-default.cpp (original)
+++ dragonegg/trunk/llvm-abi-default.cpp Fri Mar  5 03:50:26 2010
@@ -136,8 +136,8 @@
       if (TREE_CODE(Field) == FIELD_DECL) {
         const tree Ftype = getDeclaredType(Field);
         const Type *FTy = ConvertType(Ftype);
-        int FNo = GetFieldIndex(Field);
-        assert(FNo >= 0 && FNo != INT_MAX && "Case not handled yet!");
+        unsigned FNo = GetFieldIndex(Field, Ty);
+        assert(FNo < INT_MAX && "Case not handled yet!");
 
         // Currently, a bvyal type inside a non-byval struct is a zero-length
         // object inside a bigger object on x86-64.  This type should be

Modified: dragonegg/trunk/llvm-backend.cpp
URL: http://llvm.org/viewvc/llvm-project/dragonegg/trunk/llvm-backend.cpp?rev=97803&r1=97802&r2=97803&view=diff
==============================================================================
--- dragonegg/trunk/llvm-backend.cpp (original)
+++ dragonegg/trunk/llvm-backend.cpp Fri Mar  5 03:50:26 2010
@@ -156,29 +156,23 @@
   return (Value *)llvm_get_cached(t);
 }
 
-/// SetFieldIndex - Set the index of the LLVM field that corresponds to the
-/// given FIELD_DECL.  By convention, a value of INT_MAX indicates that there
-/// is no such LLVM field.
-void SetFieldIndex(tree t, int i) {
-  assert(TREE_CODE(t) == FIELD_DECL && "Expected a FIELD_DECL!");
-  assert(!CODE_CONTAINS_STRUCT(FIELD_DECL, TS_DECL_WRTL) &&
-         "FIELD_DECL has RTL!");
+/// set_decl_index - Associate a non-negative number with the given GCC
+/// declaration.
+int set_decl_index(tree t, int i) {
+  assert(!HAS_RTL_P(t) && "Expected a declaration without RTL!");
   assert(i >= 0 && "Negative indices not allowed!");
-  // In order to use zero as a special value (see GetFieldIndex), map the range
+  // In order to use zero as a special value (see get_decl_index) map the range
   // 0 .. INT_MAX to -1 .. INT_MIN.
   llvm_set_cached(t, (void *)(intptr_t)(-i - 1));
+  return i;
 }
 
-/// GetFieldIndex - Get the index of the LLVM field that corresponds to the
-/// given FIELD_DECL.  By convention, a value of INT_MAX indicates that there
-/// is no such LLVM field.  Returns a negative number if no index was yet set
-/// for the field.
-int GetFieldIndex(tree t) {
-  assert(TREE_CODE(t) == FIELD_DECL && "Expected a FIELD_DECL!");
-  assert(!CODE_CONTAINS_STRUCT(FIELD_DECL, TS_DECL_WRTL) &&
-         "FIELD_DECL has RTL!");
-  // Map the range -1 .. INT_MIN back to 0 .. INT_MAX (see SetFieldIndex), while
-  // sending 0 (aka void) to -1.
+/// get_decl_index - Get the non-negative number associated with the given GCC
+/// declaration.  Returns a negative value if no such association has been made.
+int get_decl_index(tree t) {
+  assert(!HAS_RTL_P(t) && "Expected a declaration without RTL!");
+  // Map the range -1 .. INT_MIN back to 0 .. INT_MAX (see set_decl_index) and
+  // send 0 (aka void) to -1.
   return -(1 + (int)(intptr_t)llvm_get_cached(t));
 }
 

Modified: dragonegg/trunk/llvm-convert.cpp
URL: http://llvm.org/viewvc/llvm-project/dragonegg/trunk/llvm-convert.cpp?rev=97803&r1=97802&r2=97803&view=diff
==============================================================================
--- dragonegg/trunk/llvm-convert.cpp (original)
+++ dragonegg/trunk/llvm-convert.cpp Fri Mar  5 03:50:26 2010
@@ -5329,19 +5329,17 @@
   unsigned BitStart;
   Value *FieldPtr;
 
-  // If this is a normal field at a fixed offset from the start, handle it.
-  if (OffsetIsLLVMCompatible(FieldDecl)) {
+  // If the GCC field directly corresponds to an LLVM field, handle it.
+  unsigned MemberIndex = GetFieldIndex(FieldDecl, StructTy);
+  if (MemberIndex < INT_MAX) {
     BitStart = getFieldOffsetInBits(TREE_OPERAND(exp, 1));
     assert(!TREE_OPERAND(exp, 2) && "Constant not gimple min invariant?");
-    int MemberIndex = GetFieldIndex(FieldDecl);
-    assert(MemberIndex >= 0 && MemberIndex != INT_MAX &&
-           "Type not laid out for LLVM?");
 
     // If the LLVM struct has zero field, don't try to index into it, just use
     // the current pointer.
     FieldPtr = StructAddrLV.Ptr;
     if (StructTy->getNumContainedTypes() != 0) {
-      assert(MemberIndex < (int)StructTy->getNumContainedTypes() &&
+      assert(MemberIndex < StructTy->getNumContainedTypes() &&
              "Field Idx out of range!");
       FieldPtr = Builder.CreateStructGEP(FieldPtr, MemberIndex);
     }
@@ -8610,12 +8608,10 @@
   Constant *FieldPtr;
   const TargetData &TD = getTargetData();
 
-  // If this is a normal field at a fixed offset from the start, handle it.
-  if (OffsetIsLLVMCompatible(FieldDecl)) {
+  // If the GCC field directly corresponds to an LLVM field, handle it.
+  unsigned MemberIndex = GetFieldIndex(FieldDecl, StructTy);
+  if (MemberIndex < INT_MAX) {
     BitStart = getFieldOffsetInBits(TREE_OPERAND(exp, 1));
-    int MemberIndex = GetFieldIndex(FieldDecl);
-    assert(MemberIndex >= 0 && MemberIndex != INT_MAX &&
-           "Type not laid out for LLVM?");
 
     Constant *Ops[] = {
       StructAddrLV,

Modified: dragonegg/trunk/llvm-internal.h
URL: http://llvm.org/viewvc/llvm-project/dragonegg/trunk/llvm-internal.h?rev=97803&r1=97802&r2=97803&view=diff
==============================================================================
--- dragonegg/trunk/llvm-internal.h (original)
+++ dragonegg/trunk/llvm-internal.h Fri Mar  5 03:50:26 2010
@@ -97,7 +97,8 @@
 /// annotate attribute to a vector to be emitted later.
 extern void AddAnnotateAttrsToGlobal(GlobalValue *GV, union tree_node* decl);
 
-// Mapping between GCC declarations and LLVM values.
+// Mapping between GCC declarations and LLVM values.  The GCC declaration must
+// satisfy HAS_RTL_P.
 
 /// DECL_LLVM - Returns the LLVM declaration of a global variable or function.
 extern Value *make_decl_llvm(union tree_node *);
@@ -121,18 +122,16 @@
 Value *make_definition_llvm(union tree_node *decl);
 #define DEFINITION_LLVM(NODE) make_definition_llvm(NODE)
 
-// Mapping between GCC field declarations and LLVM indices.
+// Mapping between GCC declarations and non-negative integers.  The GCC
+// declaration must not satisfy HAS_RTL_P.
 
-/// SetFieldIndex - Set the index of the LLVM field that corresponds to the
-/// given FIELD_DECL.  By convention, a value of INT_MAX indicates that there
-/// is no such LLVM field.
-void SetFieldIndex(union tree_node *, int);
-
-/// GetFieldIndex - Get the index of the LLVM field that corresponds to the
-/// given FIELD_DECL.  By convention, a value of INT_MAX indicates that there
-/// is no such LLVM field.  Returns a negative number if no index was yet set
-/// for the field.
-int GetFieldIndex(union tree_node *);
+/// set_decl_index - Associate a non-negative number with the given GCC
+/// declaration.
+int set_decl_index(union tree_node *, int);
+
+/// get_decl_index - Get the non-negative number associated with the given GCC
+/// declaration.  Returns a negative value if no such association has been made.
+int get_decl_index(union tree_node *);
 
 void changeLLVMConstant(Constant *Old, Constant *New);
 void register_ctor_dtor(Function *, int, bool);
@@ -210,6 +209,13 @@
   return TheTypeConverter->ConvertType(type);
 }
 
+/// GetFieldIndex - Return the index of the field in the given LLVM type that
+/// corresponds to the GCC field declaration 'decl'.  This means that the LLVM
+/// and GCC fields start in the same byte (if 'decl' is a bitfield, this means
+/// that its first bit is within the byte the LLVM field starts at).  Returns
+/// INT_MAX if there is no such LLVM field.
+int GetFieldIndex(union tree_node *decl, const Type *Ty);
+
 /// getINTEGER_CSTVal - Return the specified INTEGER_CST value as a uint64_t.
 ///
 uint64_t getINTEGER_CSTVal(tree_node *exp);

Modified: dragonegg/trunk/llvm-types.cpp
URL: http://llvm.org/viewvc/llvm-project/dragonegg/trunk/llvm-types.cpp?rev=97803&r1=97802&r2=97803&view=diff
==============================================================================
--- dragonegg/trunk/llvm-types.cpp (original)
+++ dragonegg/trunk/llvm-types.cpp Fri Mar  5 03:50:26 2010
@@ -458,6 +458,54 @@
 //                              Helper Routines
 //===----------------------------------------------------------------------===//
 
+/// GetFieldIndex - Return the index of the field in the given LLVM type that
+/// corresponds to the GCC field declaration 'decl'.  This means that the LLVM
+/// and GCC fields start in the same byte (if 'decl' is a bitfield, this means
+/// that its first bit is within the byte the LLVM field starts at).  Returns
+/// INT_MAX if there is no such LLVM field.
+int GetFieldIndex(tree decl, const Type *Ty) {
+  assert(TREE_CODE(decl) == FIELD_DECL && "Expected a FIELD_DECL!");
+  assert(Ty == ConvertType(DECL_CONTEXT(decl)) && "Field not for this type!");
+
+  // If we previously cached the field index, return the cached value.
+  unsigned Index = (unsigned)get_decl_index(decl);
+  if (Index <= INT_MAX)
+    return Index;
+
+  // TODO: At this point we could process all fields of DECL_CONTEXT(decl), and
+  // incrementally advance over the StructLayout.  This would make indexing be
+  // O(N) rather than O(N log N) if all N fields are used.  It's not clear if it
+  // would really be a win though.
+
+  const StructType *STy = dyn_cast<StructType>(Ty);
+  // If this is not a struct type, then for sure there is no corresponding LLVM
+  // field (we do not require GCC record types to be converted to LLVM structs).
+  if (!STy)
+    return set_decl_index(decl, INT_MAX);
+
+  // If the field declaration is at a variable or humongous offset then there
+  // can be no corresponding LLVM field.
+  if (!OffsetIsLLVMCompatible(decl))
+    return set_decl_index(decl, INT_MAX);
+
+  // Find the LLVM field that contains the first bit of the GCC field.
+  uint64_t OffsetInBytes = getFieldOffsetInBits(decl) / 8; // Ignore bit in byte
+  const StructLayout *SL = getTargetData().getStructLayout(STy);
+  Index = SL->getElementContainingOffset(OffsetInBytes);
+
+  // The GCC field must start in the first byte of the LLVM field.
+  if (OffsetInBytes != SL->getElementOffset(Index))
+    return set_decl_index(decl, INT_MAX);
+
+  // We are not able to cache values bigger than INT_MAX, so bail out if the
+  // LLVM field index is that huge.
+  if (Index >= INT_MAX)
+    return set_decl_index(decl, INT_MAX);
+
+  // Found an appropriate LLVM field - return it.
+  return set_decl_index(decl, Index);
+}
+
 /// FindLLVMTypePadding - If the specified struct has any inter-element padding,
 /// add it to the Padding array.
 static void FindLLVMTypePadding(const Type *Ty, tree type, uint64_t BitOffset,
@@ -1470,60 +1518,6 @@
     return getFieldEndOffsetInBytes(ElementOffsetInBytes.size()-1);
   }
 
-  /// getLLVMFieldFor - When we are assigning indices to FieldDecls, this
-  /// method determines which struct element to use.  Since the offset of
-  /// the fields cannot go backwards, CurFieldNo retains the last element we
-  /// looked at, to keep this a nice fast linear process.  If isZeroSizeField
-  /// is true, this should return some zero sized field that starts at the
-  /// specified offset.
-  ///
-  /// This returns the first field that contains the specified bit.
-  ///
-  int getLLVMFieldFor(uint64_t FieldOffsetInBits, unsigned &CurFieldNo,
-                      bool isZeroSizeField) {
-    if (!isZeroSizeField) {
-      // Skip over LLVM fields that start and end before the GCC field starts.
-      while (CurFieldNo < ElementOffsetInBytes.size() &&
-             getFieldEndOffsetInBytes(CurFieldNo)*8 <= FieldOffsetInBits)
-        ++CurFieldNo;
-      if (CurFieldNo < ElementOffsetInBytes.size())
-        return CurFieldNo;
-      // Otherwise, we couldn't find the field!
-      // FIXME: this works around a latent bug!
-      //assert(0 && "Could not find field!");
-      return INT_MAX;
-    }
-
-    // Handle zero sized fields now.
-
-    // Skip over LLVM fields that start and end before the GCC field starts.
-    // Such fields are always nonzero sized, and we don't want to skip past
-    // zero sized ones as well, which happens if you use only the Offset
-    // comparison.
-    while (CurFieldNo < ElementOffsetInBytes.size() &&
-           getFieldEndOffsetInBytes(CurFieldNo)*8 <
-           FieldOffsetInBits + (ElementSizeInBytes[CurFieldNo] != 0))
-      ++CurFieldNo;
-
-    // If the next field is zero sized, advance past this one.  This is a nicety
-    // that causes us to assign C fields different LLVM fields in cases like
-    // struct X {}; struct Y { struct X a, b, c };
-    if (CurFieldNo+1 < ElementOffsetInBytes.size() &&
-        ElementSizeInBytes[CurFieldNo+1] == 0) {
-      return CurFieldNo++;
-    }
-
-    // Otherwise, if this is a zero sized field, return it.
-    if (CurFieldNo < ElementOffsetInBytes.size() &&
-        ElementSizeInBytes[CurFieldNo] == 0) {
-      return CurFieldNo;
-    }
-    
-    // Otherwise, we couldn't find the field!
-    assert(0 && "Could not find field!");
-    return INT_MAX;
-  }
-
   void addNewBitField(uint64_t Size, uint64_t FirstUnallocatedByte);
 
   void dump() const;
@@ -2012,56 +2006,6 @@
   } else
     Info->RemoveExtraBytes();
 
-  // Now that the LLVM struct is finalized, figure out a safe place to index to
-  // and set index values for each FieldDecl that doesn't start at a variable
-  // offset.
-  unsigned CurFieldNo = 0;
-  for (unsigned i = 0, e = Fields.size(); i < e; i++) {
-    tree Field = Fields[i].first;
-    uint64_t FieldOffsetInBits = Fields[i].second;
-
-    // A field with a non-negative constant offset that fits in 64 bits.
-    if (HasOnlyZeroOffsets) {
-      // Set the field idx to zero for all members of a union.
-      SetFieldIndex(Field, 0);
-    } else {
-      tree FieldType = getDeclaredType(Field);
-      const Type *FieldTy = ConvertType(FieldType);
-
-      // If this is a bitfield, we may want to adjust the FieldOffsetInBits
-      // to produce safe code.  In particular, bitfields will be
-      // loaded/stored as their *declared* type, not the smallest integer
-      // type that contains them.  As such, we need to respect the alignment
-      // of the declared type.
-      if (isBitfield(Field)) {
-        // If this is a bitfield, the declared type must be an integral type.
-        unsigned BitAlignment = Info->getTypeAlignment(FieldTy)*8;
-
-        FieldOffsetInBits &= ~(BitAlignment-1ULL);
-        // When we fix the field alignment, we must restart the FieldNo
-        // search because the FieldOffsetInBits can be lower than it was in
-        // the previous iteration.
-        CurFieldNo = 0;
-
-        // Skip 'int:0', which just affects layout.
-        if (integer_zerop(DECL_SIZE(Field)))
-          continue;
-      }
-
-      // Figure out if this field is zero bits wide, e.g. {} or [0 x int].
-      bool isZeroSizeField = FieldTy->isSized() &&
-        getTargetData().getTypeSizeInBits(FieldTy) == 0;
-
-      int FieldNo =
-        Info->getLLVMFieldFor(FieldOffsetInBits, CurFieldNo, isZeroSizeField);
-      SetFieldIndex(Field, FieldNo);
-
-      assert((isBitfield(Field) || FieldNo == INT_MAX ||
-              FieldOffsetInBits == 8*Info->ElementOffsetInBytes[FieldNo]) &&
-             "Wrong LLVM field offset!");
-    }
-  }
-
   const Type *ResultTy = Info->getLLVMType();
   StructTypeInfoMap[type] = Info;
 





More information about the llvm-commits mailing list