Fix alignment issues in LLVM.
authorJames Y Knight <jyknight@google.com>
Wed, 17 Jun 2015 01:21:20 +0000 (01:21 +0000)
committerJames Y Knight <jyknight@google.com>
Wed, 17 Jun 2015 01:21:20 +0000 (01:21 +0000)
Adds static_asserts to ensure alignment of concatenated objects is
correct, and fixes them where they are not.

Also changes the definition of AlignOf to use constexpr, except on
MSVC, to avoid enum comparison warnings from GCC.

(There's not too much of this in llvm itself, most of the fun is in
clang).

This seems to make LLVM actually work without Bus Error on 32bit
sparc.

Differential Revision: http://reviews.llvm.org/D10271

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

include/llvm/IR/DerivedTypes.h
include/llvm/IR/User.h
include/llvm/Support/AlignOf.h
lib/IR/AttributeImpl.h
lib/IR/Metadata.cpp
lib/IR/User.cpp

index 38f1af0d70dab9f76c686e38e7d4484aa0084e54..4a94499b4cf508606e7b1114f5431d4ee2527e8c 100644 (file)
@@ -140,7 +140,8 @@ public:
     return T->getTypeID() == FunctionTyID;
   }
 };
-
+static_assert(AlignOf<FunctionType>::Alignment >= AlignOf<Type *>::Alignment,
+              "Alignment sufficient for objects appended to FunctionType");
 
 /// CompositeType - Common super class of ArrayType, StructType, PointerType
 /// and VectorType.
index 87be88da591e3250a9d13ea8921a72365b305fa2..9aaad2dcf8cda276cb1aae6692183bf36dc2f995 100644 (file)
@@ -22,6 +22,7 @@
 #include "llvm/ADT/iterator.h"
 #include "llvm/ADT/iterator_range.h"
 #include "llvm/IR/Value.h"
+#include "llvm/Support/AlignOf.h"
 #include "llvm/Support/ErrorHandling.h"
 
 namespace llvm {
@@ -226,6 +227,11 @@ public:
     return isa<Instruction>(V) || isa<Constant>(V);
   }
 };
+// Either Use objects, or a Use pointer can be prepended to User.
+static_assert(AlignOf<Use>::Alignment >= AlignOf<User>::Alignment,
+              "Alignment sufficient after objects prepended to User");
+static_assert(AlignOf<Use *>::Alignment >= AlignOf<User>::Alignment,
+              "Alignment sufficient after objects prepended to User");
 
 template<> struct simplify_type<User::op_iterator> {
   typedef Value* SimpleType;
index 574b514aef39b06b725f4c84783063daa3e1f3fd..07da02d063c7d863b7848c83a5e9ca93398aa9cc 100644 (file)
@@ -44,9 +44,18 @@ private:
 ///  compile-time constant (e.g., for template instantiation).
 template <typename T>
 struct AlignOf {
+#ifndef _MSC_VER
+  // Avoid warnings from GCC like:
+  //   comparison between 'enum llvm::AlignOf<X>::<anonymous>' and 'enum
+  //   llvm::AlignOf<Y>::<anonymous>' [-Wenum-compare]
+  // by using constexpr instead of enum.
+  // (except on MSVC, since it doesn't support constexpr yet).
+  static constexpr unsigned Alignment =
+      static_cast<unsigned int>(sizeof(AlignmentCalcImpl<T>) - sizeof(T));
+#else
   enum { Alignment =
          static_cast<unsigned int>(sizeof(AlignmentCalcImpl<T>) - sizeof(T)) };
-
+#endif
   enum { Alignment_GreaterEqual_2Bytes = Alignment >= 2 ? 1 : 0 };
   enum { Alignment_GreaterEqual_4Bytes = Alignment >= 4 ? 1 : 0 };
   enum { Alignment_GreaterEqual_8Bytes = Alignment >= 8 ? 1 : 0 };
@@ -58,6 +67,10 @@ struct AlignOf {
   enum { Alignment_LessEqual_16Bytes = Alignment <= 16 ? 1 : 0 };
 };
 
+#ifndef _MSC_VER
+template <typename T> constexpr unsigned AlignOf<T>::Alignment;
+#endif
+
 /// alignOf - A templated function that returns the minimum alignment of
 ///  of a type.  This provides no extra functionality beyond the AlignOf
 ///  class besides some cosmetic cleanliness.  Example usage:
index dbd7d63a892bced249156c3eb74dd5b8647de30d..88a68a4e0059313a3f3b96a32df276764da0e036 100644 (file)
@@ -181,6 +181,9 @@ public:
       AttrList[I].Profile(ID);
   }
 };
+static_assert(AlignOf<AttributeSetNode>::Alignment >=
+                  AlignOf<Attribute>::Alignment,
+              "Alignment sufficient for objects appended to AttributeSetNode");
 
 //===----------------------------------------------------------------------===//
 /// \class
@@ -189,9 +192,11 @@ public:
 class AttributeSetImpl : public FoldingSetNode {
   friend class AttributeSet;
 
-  LLVMContext &Context;
-
+public:
   typedef std::pair<unsigned, AttributeSetNode*> IndexAttrPair;
+
+private:
+  LLVMContext &Context;
   unsigned NumAttrs; ///< Number of entries in this set.
 
   /// \brief Return a pointer to the IndexAttrPair for the specified slot.
@@ -206,6 +211,7 @@ public:
   AttributeSetImpl(LLVMContext &C,
                    ArrayRef<std::pair<unsigned, AttributeSetNode *> > Attrs)
       : Context(C), NumAttrs(Attrs.size()) {
+
 #ifndef NDEBUG
     if (Attrs.size() >= 2) {
       for (const std::pair<unsigned, AttributeSetNode *> *i = Attrs.begin() + 1,
@@ -267,6 +273,9 @@ public:
 
   void dump() const;
 };
+static_assert(AlignOf<AttributeSetImpl>::Alignment >=
+                  AlignOf<AttributeSetImpl::IndexAttrPair>::Alignment,
+              "Alignment sufficient for objects appended to AttributeSetImpl");
 
 } // end llvm namespace
 
index 75b4046ef4429f2fbec92e0ad36e5b92d0cca1c6..de1587d28a08f953404d32c4373dd2dd92f0a8c7 100644 (file)
@@ -381,20 +381,35 @@ StringRef MDString::getString() const {
 // MDNode implementation.
 //
 
+// Assert that the MDNode types will not be unaligned by the objects
+// prepended to them.
+#define HANDLE_MDNODE_LEAF(CLASS)                                              \
+  static_assert(llvm::AlignOf<uint64_t>::Alignment >=                          \
+                    llvm::AlignOf<CLASS>::Alignment,                           \
+                "Alignment sufficient after objects prepended to " #CLASS);
+#include "llvm/IR/Metadata.def"
+
 void *MDNode::operator new(size_t Size, unsigned NumOps) {
-  void *Ptr = ::operator new(Size + NumOps * sizeof(MDOperand));
+  size_t OpSize = NumOps * sizeof(MDOperand);
+  // uint64_t is the most aligned type we need support (ensured by static_assert
+  // above)
+  OpSize = RoundUpToAlignment(OpSize, llvm::alignOf<uint64_t>());
+  void *Ptr = reinterpret_cast<char *>(::operator new(OpSize + Size)) + OpSize;
   MDOperand *O = static_cast<MDOperand *>(Ptr);
-  for (MDOperand *E = O + NumOps; O != E; ++O)
-    (void)new (O) MDOperand;
-  return O;
+  for (MDOperand *E = O - NumOps; O != E; --O)
+    (void)new (O - 1) MDOperand;
+  return Ptr;
 }
 
 void MDNode::operator delete(void *Mem) {
   MDNode *N = static_cast<MDNode *>(Mem);
+  size_t OpSize = N->NumOperands * sizeof(MDOperand);
+  OpSize = RoundUpToAlignment(OpSize, llvm::alignOf<uint64_t>());
+
   MDOperand *O = static_cast<MDOperand *>(Mem);
   for (MDOperand *E = O - N->NumOperands; O != E; --O)
     (O - 1)->~MDOperand();
-  ::operator delete(O);
+  ::operator delete(reinterpret_cast<char *>(Mem) - OpSize);
 }
 
 MDNode::MDNode(LLVMContext &Context, unsigned ID, StorageType Storage,
index c6e4e89bb34cf3d047d7cd7ff0cf626c687c3ee7..ab25670d3899f268f7b6124f64a157e44644b4b9 100644 (file)
@@ -42,6 +42,12 @@ void User::replaceUsesOfWith(Value *From, Value *To) {
 
 void User::allocHungoffUses(unsigned N, bool IsPhi) {
   assert(HasHungOffUses && "alloc must have hung off uses");
+
+  static_assert(AlignOf<Use>::Alignment >= AlignOf<Use::UserRef>::Alignment,
+                "Alignment sufficient for hung-off-uses pieces");
+  static_assert(AlignOf<Use::UserRef>::Alignment >= AlignOf<BasicBlock *>::Alignment,
+                "Alignment sufficient for hung-off-uses pieces");
+
   // Allocate the array of Uses, followed by a pointer (with bottom bit set) to
   // the User.
   size_t size = N * sizeof(Use) + sizeof(Use::UserRef);