Refactor ConstantInitBuilder to allow other frontends to more
easily extend the aggregate-builder API.  Stupid missing language
features.

Also add APIs for constructing a relative reference and computing
the offset of a position from the start of the initializer.

llvm-svn: 296979
diff --git a/clang/lib/CodeGen/ConstantInitBuilder.cpp b/clang/lib/CodeGen/ConstantInitBuilder.cpp
index 772391e..d1a707b 100644
--- a/clang/lib/CodeGen/ConstantInitBuilder.cpp
+++ b/clang/lib/CodeGen/ConstantInitBuilder.cpp
@@ -20,12 +20,12 @@
 using namespace CodeGen;
 
 llvm::GlobalVariable *
-ConstantInitBuilder::createGlobal(llvm::Constant *initializer,
-                                  const llvm::Twine &name,
-                                  CharUnits alignment,
-                                  bool constant,
-                                  llvm::GlobalValue::LinkageTypes linkage,
-                                  unsigned addressSpace) {
+ConstantInitBuilderBase::createGlobal(llvm::Constant *initializer,
+                                      const llvm::Twine &name,
+                                      CharUnits alignment,
+                                      bool constant,
+                                      llvm::GlobalValue::LinkageTypes linkage,
+                                      unsigned addressSpace) {
   auto GV = new llvm::GlobalVariable(CGM.getModule(),
                                      initializer->getType(),
                                      constant,
@@ -40,15 +40,15 @@
   return GV;
 }
 
-void ConstantInitBuilder::setGlobalInitializer(llvm::GlobalVariable *GV,
-                                               llvm::Constant *initializer) {
+void ConstantInitBuilderBase::setGlobalInitializer(llvm::GlobalVariable *GV,
+                                                   llvm::Constant *initializer){
   GV->setInitializer(initializer);
 
   if (!SelfReferences.empty())
     resolveSelfReferences(GV);
 }
 
-void ConstantInitBuilder::resolveSelfReferences(llvm::GlobalVariable *GV) {
+void ConstantInitBuilderBase::resolveSelfReferences(llvm::GlobalVariable *GV) {
   for (auto &entry : SelfReferences) {
     llvm::Constant *resolvedReference =
       llvm::ConstantExpr::getInBoundsGetElementPtr(
@@ -58,13 +58,31 @@
   }
 }
 
-void ConstantInitBuilder::AggregateBuilderBase::addSize(CharUnits size) {
+void ConstantAggregateBuilderBase::addSize(CharUnits size) {
   add(Builder.CGM.getSize(size));
 }
 
 llvm::Constant *
-ConstantInitBuilder::AggregateBuilderBase::getAddrOfCurrentPosition(
-                                                            llvm::Type *type) {
+ConstantAggregateBuilderBase::getRelativeOffset(llvm::IntegerType *offsetType,
+                                                llvm::Constant *target) {
+  // Compute the address of the relative-address slot.
+  auto base = getAddrOfCurrentPosition(offsetType);
+
+  // Subtract.
+  base = llvm::ConstantExpr::getPtrToInt(base, Builder.CGM.IntPtrTy);
+  target = llvm::ConstantExpr::getPtrToInt(target, Builder.CGM.IntPtrTy);
+  llvm::Constant *offset = llvm::ConstantExpr::getSub(target, base);
+
+  // Truncate to the relative-address type if necessary.
+  if (Builder.CGM.IntPtrTy != offsetType) {
+    offset = llvm::ConstantExpr::getTrunc(offset, offsetType);
+  }
+
+  return offset;
+}
+
+llvm::Constant *
+ConstantAggregateBuilderBase::getAddrOfCurrentPosition(llvm::Type *type) {
   // Make a global variable.  We will replace this with a GEP to this
   // position after installing the initializer.
   auto dummy =
@@ -77,7 +95,7 @@
   return dummy;
 }
 
-void ConstantInitBuilder::AggregateBuilderBase::getGEPIndicesTo(
+void ConstantAggregateBuilderBase::getGEPIndicesTo(
                                llvm::SmallVectorImpl<llvm::Constant*> &indices,
                                size_t position) const {
   // Recurse on the parent builder if present.
@@ -97,22 +115,64 @@
                                            position - Begin));
 }
 
-llvm::Constant *ConstantArrayBuilder::finishImpl() {
+CharUnits ConstantAggregateBuilderBase::getOffsetFromGlobalTo(size_t end) const{
+  size_t cacheEnd = CachedOffsetEnd;
+  assert(cacheEnd <= end);
+
+  // Fast path: if the cache is valid, just use it.
+  if (cacheEnd == end) {
+    return CachedOffsetFromGlobal;
+  }
+
+  // If the cached range ends before the index at which the current
+  // aggregate starts, recurse for the parent.
+  CharUnits offset;
+  if (cacheEnd < Begin) {
+    assert(cacheEnd == 0);
+    assert(Parent && "Begin != 0 for root builder");
+    cacheEnd = Begin;
+    offset = Parent->getOffsetFromGlobalTo(Begin);
+  } else {
+    offset = CachedOffsetFromGlobal;
+  }
+
+  // Perform simple layout on the elements in cacheEnd..<end.
+  if (cacheEnd != end) {
+    auto &layout = Builder.CGM.getDataLayout();
+    do {
+      llvm::Constant *element = Builder.Buffer[cacheEnd];
+      assert(element != nullptr &&
+             "cannot compute offset when a placeholder is present");
+      llvm::Type *elementType = element->getType();
+      offset = offset.alignTo(CharUnits::fromQuantity(
+                                layout.getABITypeAlignment(elementType)));
+      offset += CharUnits::fromQuantity(layout.getTypeStoreSize(elementType));
+    } while (++cacheEnd != end);
+  }
+
+  // Cache and return.
+  CachedOffsetEnd = cacheEnd;
+  CachedOffsetFromGlobal = offset;
+  return offset;
+}
+
+llvm::Constant *ConstantAggregateBuilderBase::finishArray(llvm::Type *eltTy) {
   markFinished();
 
   auto &buffer = getBuffer();
   assert((Begin < buffer.size() ||
-          (Begin == buffer.size() && EltTy))
+          (Begin == buffer.size() && eltTy))
          && "didn't add any array elements without element type");
   auto elts = llvm::makeArrayRef(buffer).slice(Begin);
-  auto eltTy = EltTy ? EltTy : elts[0]->getType();
+  if (!eltTy) eltTy = elts[0]->getType();
   auto type = llvm::ArrayType::get(eltTy, elts.size());
   auto constant = llvm::ConstantArray::get(type, elts);
   buffer.erase(buffer.begin() + Begin, buffer.end());
   return constant;
 }
 
-llvm::Constant *ConstantStructBuilder::finishImpl() {
+llvm::Constant *
+ConstantAggregateBuilderBase::finishStruct(llvm::StructType *ty) {
   markFinished();
 
   auto &buffer = getBuffer();
@@ -120,8 +180,8 @@
   auto elts = llvm::makeArrayRef(buffer).slice(Begin);
 
   llvm::Constant *constant;
-  if (Ty) {
-    constant = llvm::ConstantStruct::get(Ty, elts);
+  if (ty) {
+    constant = llvm::ConstantStruct::get(ty, elts);
   } else {
     constant = llvm::ConstantStruct::getAnon(elts, /*packed*/ false);
   }