[llvm-commits] [dragonegg] r146558 - /dragonegg/trunk/src/Constants.cpp

Duncan Sands baldrick at free.fr
Wed Dec 14 01:27:42 PST 2011


Author: baldrick
Date: Wed Dec 14 03:27:42 2011
New Revision: 146558

URL: http://llvm.org/viewvc/llvm-project?rev=146558&view=rev
Log:
When creating a global variable initializer of struct type, the
created initializer typically has an anonymous type which is
structurally equivalent to the type of the global variable which
is usually a named struct type.  If so, ensure the initial value
also gets that named type.  This makes the IR more readable.

Modified:
    dragonegg/trunk/src/Constants.cpp

Modified: dragonegg/trunk/src/Constants.cpp
URL: http://llvm.org/viewvc/llvm-project/dragonegg/trunk/src/Constants.cpp?rev=146558&r1=146557&r2=146558&view=diff
==============================================================================
--- dragonegg/trunk/src/Constants.cpp (original)
+++ dragonegg/trunk/src/Constants.cpp Wed Dec 14 03:27:42 2011
@@ -673,26 +673,90 @@
   return Result;
 }
 
+/// OnlyDifferTrivially - Return 'true' if the given types do not differ in any
+/// significant way.  This means for example that reinterpreting a value of one
+/// of the types as having the other type does not lose any information.
+static bool OnlyDifferTrivially(Type *Ty1, Type *Ty2) {
+  if (Ty1 == Ty2)
+    return true;
+  Type::TypeID Id1 = Ty1->getTypeID(), Id2 = Ty2->getTypeID();
+
+  switch (Id1) {
+  default:
+    DieAbjectly("Unsupported type!");
+  case Type::PointerTyID:
+    // Different pointer types do not differ in any significant way.
+    return Id2 == Type::PointerTyID;
+  case Type::DoubleTyID:
+  case Type::FloatTyID:
+  case Type::FP128TyID:
+  case Type::IntegerTyID:
+  case Type::PPC_FP128TyID:
+  case Type::X86_FP80TyID:
+  case Type::X86_MMXTyID:
+    return false; // The types are already known to be different.
+  case Type::ArrayTyID: {
+    if (Id2 != Type::ArrayTyID)
+      return false;
+    ArrayType *ATy1 = cast<ArrayType>(Ty1), *ATy2 = cast<ArrayType>(Ty2);
+    if (ATy1->getNumElements() != ATy2->getNumElements())
+      return false;
+    return OnlyDifferTrivially(ATy1->getElementType(), ATy2->getElementType());
+  }
+  case Type::StructTyID: {
+    if (Id2 != Type::StructTyID)
+      return false;
+    StructType *STy1 = cast<StructType>(Ty1), *STy2 = cast<StructType>(Ty2);
+    if (STy1->isPacked() != STy2->isPacked() ||
+        STy1->getNumElements() != STy2->getNumElements())
+      return false;
+    for (unsigned i = 0, e = STy1->getNumElements(); i != e; ++i)
+      if (!OnlyDifferTrivially(STy1->getElementType(i),
+                               STy2->getElementType(i)))
+        return false;
+    return true;
+  }
+  case Type::VectorTyID: {
+    if (Id2 != Type::VectorTyID)
+      return false;
+    VectorType *VTy1 = cast<VectorType>(Ty1), *VTy2 = cast<VectorType>(Ty2);
+    if (VTy1->getNumElements() != VTy2->getNumElements())
+      return false;
+    return OnlyDifferTrivially(VTy1->getElementType(), VTy2->getElementType());
+  }
+  }
+}
+
 /// ConvertInitializerWithCast - Convert the initial value for a global variable
 /// to an equivalent LLVM constant then cast to the given type if both the type
-/// and the initializer are scalar.  This is convenient for making explicit the
-/// implicit scalar casts that GCC allows in "assignments" such as initializing
-/// a record field.
+/// and the initializer are scalar, or if the initializer's type only differs in
+/// trivial ways from the given type.  This is convenient for avoiding confusing
+/// and pointless type changes in the IR, and for making explicit the implicit
+/// scalar casts that GCC allows in "assignments" such as initializing a record
+/// field.
 static Constant *ConvertInitializerWithCast(tree exp, tree type,
                                             TargetFolder &Folder) {
-  // Convert the initializer.
+  // Convert the initializer.  Note that the type of the returned value may be
+  // pretty much anything.
   Constant *C = ConvertInitializerImpl(exp, Folder);
 
-  // If no cast is needed, or it would not be a scalar cast, then just return
-  // the initializer as is.
-  if (type == TREE_TYPE(exp) || AGGREGATE_TYPE_P(TREE_TYPE(exp)) ||
-      AGGREGATE_TYPE_P(type))
+  // If casting to or from an aggregate and the types only differ in a trivial
+  // way then reinterpret the initializer as having the desired type.  If the
+  // types differ significantly then this is probably something like a struct
+  // ending in a flexible array being initialized with a struct ending in an
+  // array of some definite size, so just return the initializer as is.
+  if (AGGREGATE_TYPE_P(type) || AGGREGATE_TYPE_P(TREE_TYPE(exp))) {
+    Type *DestTy = ConvertType(type);
+    if (OnlyDifferTrivially(C->getType(), DestTy))
+      return InterpretAsType(C, DestTy, 0, Folder);
     return C;
-  // No cast is needed if the LLVM types are the same.  This occurs often since
-  // many different GCC types usually map to the same LLVM type.
-  Type *SrcTy = getRegType(TREE_TYPE(exp));
+  }
+
+  // Scalar to scalar cast.  This is where the implicit scalar casts that GCC
+  // permits are made explicit.
   Type *DestTy = getRegType(type);
-  if (SrcTy == DestTy)
+  if (C->getType() == DestTy)
+    // No cast is needed if the type is already correct.
     return C;
 
   // Ensure that the initializer has a sensible type.  Note that it would be
@@ -1371,7 +1435,8 @@
 
   // Make the IR easier to read by converting the bunch of bytes returned by
   // ConvertCST into a less surprising type when it is safe to do so.
-  if (!AGGREGATE_TYPE_P(TREE_TYPE(exp)))
+  if (!AGGREGATE_TYPE_P(TREE_TYPE(exp)) ||
+      OnlyDifferTrivially(Init->getType(), ConvertType(TREE_TYPE(exp))))
     Init = InterpretAsType(Init, ConvertType(TREE_TYPE(exp)), 0, Folder);
 
 #ifndef NDEBUG





More information about the llvm-commits mailing list