diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 3e12a9307807..298d06805c54 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -622,6 +622,30 @@ def GlobalViewAttr : CIR_Attr<"GlobalView", "global_view", [TypedAttrInterface]>
       cir.global external @elt_ptr = #cir.global_view<@rgb, [1]> : !cir.ptr<i8>
       cir.global external @table_of_ptrs = #cir.const_array<[#cir.global_view<@rgb, [1]> : !cir.ptr<i8>] : !cir.array<!cir.ptr<i8> x 1>>
     ```
+    
+    Note, that unlike LLVM IR's gep instruction, CIR doesn't add the leading zero index
+    when it's known to be constant zero, e.g. for pointers, i.e. we use indexes exactly
+    to access sub elements or for the offset. The leading zero index is added later in
+    the lowering.
+        
+    Example:
+    ```
+    struct A {
+      int a;
+    };
+
+    struct B:  virtual A {
+      int b;
+    };
+    ```
+    VTT for B:
+    ```
+    cir.global linkonce_odr @_ZTT1B = #cir.const_array<[#cir.global_view<@_ZTV1B, [0 : i32, 3 : i32]> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 1>    
+    ```
+    The same for LLVM IR after CIR:
+    ```
+    @_ZTT1B = linkonce_odr global [1 x ptr] [ptr getelementptr inbounds ({ [3 x ptr] }, ptr @_ZTV1B, i32 0, i32 0, i32 3)], align 8
+    ```
   }];
 
   let parameters = (ins AttributeSelfTypeParameter<"">:$type,
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp b/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp
index a50cefe34c79..905ca67aafd5 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp
@@ -63,3 +63,74 @@ cir::ConstantOp CIRGenBuilderTy::getConstInt(mlir::Location loc, mlir::Type t,
   assert(intTy && "expected cir::IntType");
   return create<cir::ConstantOp>(loc, intTy, cir::IntAttr::get(t, C));
 }
+
+void CIRGenBuilderTy::computeGlobalViewIndicesFromFlatOffset(
+    int64_t Offset, mlir::Type Ty, cir::CIRDataLayout Layout,
+    llvm::SmallVectorImpl<int64_t> &Indices) {
+  if (!Offset)
+    return;
+
+  mlir::Type SubType;
+
+  auto getIndexAndNewOffset =
+      [](int64_t Offset, int64_t EltSize) -> std::pair<int64_t, int64_t> {
+    int64_t DivRet = Offset / EltSize;
+    if (DivRet < 0)
+      DivRet -= 1; // make sure offset is positive
+    int64_t ModRet = Offset - (DivRet * EltSize);
+    return {DivRet, ModRet};
+  };
+
+  if (auto ArrayTy = mlir::dyn_cast<cir::ArrayType>(Ty)) {
+    int64_t EltSize = Layout.getTypeAllocSize(ArrayTy.getEltType());
+    SubType = ArrayTy.getEltType();
+    const auto [Index, NewOffset] = getIndexAndNewOffset(Offset, EltSize);
+    Indices.push_back(Index);
+    Offset = NewOffset;
+  } else if (auto StructTy = mlir::dyn_cast<cir::StructType>(Ty)) {
+    auto Elts = StructTy.getMembers();
+    int64_t Pos = 0;
+    for (size_t I = 0; I < Elts.size(); ++I) {
+      int64_t EltSize =
+          (int64_t)Layout.getTypeAllocSize(Elts[I]).getFixedValue();
+      unsigned AlignMask = Layout.getABITypeAlign(Elts[I]).value() - 1;
+      if (StructTy.getPacked())
+        AlignMask = 0;
+      Pos = (Pos + AlignMask) & ~AlignMask;
+      assert(Offset >= 0);
+      if (Offset < Pos + EltSize) {
+        Indices.push_back(I);
+        SubType = Elts[I];
+        Offset -= Pos;
+        break;
+      }
+      Pos += EltSize;
+    }
+  } else {
+    llvm_unreachable("unexpected type");
+  }
+
+  assert(SubType);
+  computeGlobalViewIndicesFromFlatOffset(Offset, SubType, Layout, Indices);
+}
+
+uint64_t CIRGenBuilderTy::computeOffsetFromGlobalViewIndices(
+    const cir::CIRDataLayout &layout, mlir::Type typ,
+    llvm::ArrayRef<int64_t> indexes) {
+
+  uint64_t offset = 0;
+  for (auto idx : indexes) {
+    if (auto sTy = dyn_cast<cir::StructType>(typ)) {
+      offset += sTy.getElementOffset(layout.layout, idx);
+      assert(idx < sTy.getMembers().size());
+      typ = sTy.getMembers()[idx];
+    } else if (auto arTy = dyn_cast<cir::ArrayType>(typ)) {
+      typ = arTy.getEltType();
+      offset += layout.getTypeAllocSize(typ) * idx;
+    } else {
+      llvm_unreachable("NYI");
+    }
+  }
+
+  return offset;
+}
\ No newline at end of file
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index f41dcf871c6b..3a8a3955d7f2 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -146,6 +146,20 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
     return cir::GlobalViewAttr::get(type, symbol, indices);
   }
 
+  cir::GlobalViewAttr getGlobalViewAttr(cir::PointerType type,
+                                        cir::GlobalOp globalOp,
+                                        llvm::ArrayRef<int64_t> indices) {
+    llvm::SmallVector<mlir::Attribute> attrs;
+    for (auto ind : indices) {
+      auto a =
+          mlir::IntegerAttr::get(mlir::IntegerType::get(getContext(), 64), ind);
+      attrs.push_back(a);
+    }
+
+    mlir::ArrayAttr arAttr = mlir::ArrayAttr::get(getContext(), attrs);
+    return getGlobalViewAttr(type, globalOp, arAttr);
+  }
+
   mlir::Attribute getString(llvm::StringRef str, mlir::Type eltTy,
                             unsigned size = 0) {
     unsigned finalSize = size ? size : str.size();
@@ -941,51 +955,12 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
   // yet, return them.
   void computeGlobalViewIndicesFromFlatOffset(
       int64_t Offset, mlir::Type Ty, cir::CIRDataLayout Layout,
-      llvm::SmallVectorImpl<int64_t> &Indices) {
-    if (!Offset)
-      return;
-
-    mlir::Type SubType;
-
-    auto getIndexAndNewOffset =
-        [](int64_t Offset, int64_t EltSize) -> std::pair<int64_t, int64_t> {
-      int64_t DivRet = Offset / EltSize;
-      if (DivRet < 0)
-        DivRet -= 1; // make sure offset is positive
-      int64_t ModRet = Offset - (DivRet * EltSize);
-      return {DivRet, ModRet};
-    };
-
-    if (auto ArrayTy = mlir::dyn_cast<cir::ArrayType>(Ty)) {
-      int64_t EltSize = Layout.getTypeAllocSize(ArrayTy.getEltType());
-      SubType = ArrayTy.getEltType();
-      auto const [Index, NewOffset] = getIndexAndNewOffset(Offset, EltSize);
-      Indices.push_back(Index);
-      Offset = NewOffset;
-    } else if (auto StructTy = mlir::dyn_cast<cir::StructType>(Ty)) {
-      auto Elts = StructTy.getMembers();
-      int64_t Pos = 0;
-      for (size_t I = 0; I < Elts.size(); ++I) {
-        int64_t EltSize =
-            (int64_t)Layout.getTypeAllocSize(Elts[I]).getFixedValue();
-        unsigned AlignMask = Layout.getABITypeAlign(Elts[I]).value() - 1;
-        Pos = (Pos + AlignMask) & ~AlignMask;
-        assert(Offset >= 0);
-        if (Offset < Pos + EltSize) {
-          Indices.push_back(I);
-          SubType = Elts[I];
-          Offset -= Pos;
-          break;
-        }
-        Pos += EltSize;
-      }
-    } else {
-      llvm_unreachable("unexpected type");
-    }
+      llvm::SmallVectorImpl<int64_t> &Indices);
 
-    assert(SubType);
-    computeGlobalViewIndicesFromFlatOffset(Offset, SubType, Layout, Indices);
-  }
+  // Convert high-level indices (e.g. from GlobalViewAttr) to byte offset
+  uint64_t computeOffsetFromGlobalViewIndices(const cir::CIRDataLayout &layout,
+                                              mlir::Type t,
+                                              llvm::ArrayRef<int64_t> indexes);
 
   cir::StackSaveOp createStackSave(mlir::Location loc, mlir::Type ty) {
     return create<cir::StackSaveOp>(loc, ty);
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprConst.cpp b/clang/lib/CIR/CodeGen/CIRGenExprConst.cpp
index c2955d7ad3fa..f0ee6333c53a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprConst.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprConst.cpp
@@ -756,7 +756,6 @@ bool ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD,
               .getAddressPoint(BaseSubobject(CD, Offset));
       assert(!cir::MissingFeatures::ptrAuth());
       mlir::ArrayAttr indices = builder.getArrayAttr({
-          builder.getI32IntegerAttr(0),
           builder.getI32IntegerAttr(addressPoint.VTableIndex),
           builder.getI32IntegerAttr(addressPoint.AddressPointIndex),
       });
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index c93a145f35ce..521c41aa4504 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -9,9 +9,7 @@
 // This is the internal per-translation-unit state used for CIR translation.
 //
 //===----------------------------------------------------------------------===//
-
 #include "CIRGenModule.h"
-
 #include "CIRGenCXXABI.h"
 #include "CIRGenCstEmitter.h"
 #include "CIRGenFunction.h"
@@ -797,9 +795,75 @@ void CIRGenModule::setNonAliasAttributes(GlobalDecl GD, mlir::Operation *GO) {
   assert(!cir::MissingFeatures::setTargetAttributes());
 }
 
+static llvm::SmallVector<int64_t> indexesOfArrayAttr(mlir::ArrayAttr indexes) {
+  llvm::SmallVector<int64_t> inds;
+
+  for (mlir::Attribute i : indexes) {
+    auto ind = dyn_cast<mlir::IntegerAttr>(i);
+    assert(ind && "expect MLIR integer attribute");
+    inds.push_back(ind.getValue().getSExtValue());
+  }
+
+  return inds;
+}
+
+static bool isViewOnGlobal(GlobalOp glob, GlobalViewAttr view) {
+  return view.getSymbol().getValue() == glob.getSymName();
+}
+
+static GlobalViewAttr createNewGlobalView(CIRGenModule &CGM, GlobalOp newGlob,
+                                          GlobalViewAttr attr,
+                                          mlir::Type oldTy) {
+  if (!attr.getIndices() || !isViewOnGlobal(newGlob, attr))
+    return attr;
+
+  llvm::SmallVector<int64_t> oldInds = indexesOfArrayAttr(attr.getIndices());
+  llvm::SmallVector<int64_t> newInds;
+  CIRGenBuilderTy &bld = CGM.getBuilder();
+  const CIRDataLayout &layout = CGM.getDataLayout();
+  mlir::MLIRContext *ctxt = bld.getContext();
+  auto newTy = newGlob.getSymType();
+
+  auto offset = bld.computeOffsetFromGlobalViewIndices(layout, oldTy, oldInds);
+  bld.computeGlobalViewIndicesFromFlatOffset(offset, newTy, layout, newInds);
+  cir::PointerType newPtrTy;
+
+  if (isa<cir::StructType>(oldTy))
+    newPtrTy = cir::PointerType::get(ctxt, newTy);
+  else if (cir::ArrayType oldArTy = dyn_cast<cir::ArrayType>(oldTy))
+    newPtrTy = dyn_cast<cir::PointerType>(attr.getType());
+
+  if (newPtrTy)
+    return bld.getGlobalViewAttr(newPtrTy, newGlob, newInds);
+
+  llvm_unreachable("NYI");
+}
+
+static mlir::Attribute getNewInitValue(CIRGenModule &CGM, GlobalOp newGlob,
+                                       mlir::Type oldTy, GlobalOp user,
+                                       mlir::Attribute oldInit) {
+  if (auto oldView = mlir::dyn_cast<cir::GlobalViewAttr>(oldInit)) {
+    return createNewGlobalView(CGM, newGlob, oldView, oldTy);
+  } else if (auto oldArray = mlir::dyn_cast<ConstArrayAttr>(oldInit)) {
+    llvm::SmallVector<mlir::Attribute> newArray;
+    auto eltsAttr = dyn_cast<mlir::ArrayAttr>(oldArray.getElts());
+    for (auto elt : eltsAttr) {
+      if (auto view = dyn_cast<GlobalViewAttr>(elt))
+        newArray.push_back(createNewGlobalView(CGM, newGlob, view, oldTy));
+      else if (auto view = dyn_cast<ConstArrayAttr>(elt))
+        newArray.push_back(getNewInitValue(CGM, newGlob, oldTy, user, elt));
+    }
+
+    auto &builder = CGM.getBuilder();
+    mlir::Attribute ar = mlir::ArrayAttr::get(builder.getContext(), newArray);
+    return builder.getConstArray(ar, cast<cir::ArrayType>(oldArray.getType()));
+  } else {
+    llvm_unreachable("NYI");
+  }
+}
+
 void CIRGenModule::replaceGlobal(cir::GlobalOp Old, cir::GlobalOp New) {
   assert(Old.getSymName() == New.getSymName() && "symbol names must match");
-
   // If the types does not match, update all references to Old to the new type.
   auto OldTy = Old.getSymType();
   auto NewTy = New.getSymType();
@@ -809,6 +873,7 @@ void CIRGenModule::replaceGlobal(cir::GlobalOp Old, cir::GlobalOp New) {
   if (oldAS != newAS) {
     llvm_unreachable("NYI");
   }
+
   if (OldTy != NewTy) {
     auto OldSymUses = Old.getSymbolUses(theModule.getOperation());
     if (OldSymUses.has_value()) {
@@ -823,11 +888,16 @@ void CIRGenModule::replaceGlobal(cir::GlobalOp Old, cir::GlobalOp New) {
               cir::PointerType::get(&getMLIRContext(), NewTy));
 
           mlir::OpBuilder::InsertionGuard guard(builder);
-          builder.setInsertionPointAfter(UserOp);
+          builder.setInsertionPointAfter(GGO);
           mlir::Type ptrTy = builder.getPointerTo(OldTy);
           mlir::Value cast =
               builder.createBitcast(GGO->getLoc(), UseOpResultValue, ptrTy);
           UseOpResultValue.replaceAllUsesExcept(cast, cast.getDefiningOp());
+        } else if (auto glob = dyn_cast<cir::GlobalOp>(UserOp)) {
+          if (auto init = glob.getInitialValue()) {
+            auto nw = getNewInitValue(*this, New, OldTy, glob, init.value());
+            glob.setInitialValueAttr(nw);
+          }
         }
       }
     }
@@ -1083,7 +1153,8 @@ CIRGenModule::getAddrOfGlobalVarAttr(const VarDecl *D, mlir::Type Ty,
     Ty = getTypes().convertTypeForMem(ASTTy);
 
   auto globalOp = getOrCreateCIRGlobal(D, Ty, IsForDefinition);
-  return builder.getGlobalViewAttr(builder.getPointerTo(Ty), globalOp);
+  auto ptrTy = builder.getPointerTo(globalOp.getSymType());
+  return builder.getGlobalViewAttr(ptrTy, globalOp);
 }
 
 mlir::Operation *CIRGenModule::getWeakRefReference(const ValueDecl *VD) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenVTables.cpp b/clang/lib/CIR/CodeGen/CIRGenVTables.cpp
index 2fa51b534da4..81f7971ac787 100644
--- a/clang/lib/CIR/CodeGen/CIRGenVTables.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenVTables.cpp
@@ -622,8 +622,7 @@ void CIRGenVTables::emitVTTDefinition(cir::GlobalOp VTT,
              "Did not find ctor vtable address point!");
     }
 
-    mlir::Attribute Idxs[3] = {
-        CGM.getBuilder().getI32IntegerAttr(0),
+    mlir::Attribute Idxs[2] = {
         CGM.getBuilder().getI32IntegerAttr(AddressPoint.VTableIndex),
         CGM.getBuilder().getI32IntegerAttr(AddressPoint.AddressPointIndex),
     };
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 05679d9d86dd..0331122f35d2 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -680,12 +680,8 @@ lowerCirAttrAsValue(mlir::Operation *parentOp, cir::GlobalViewAttr globalAttr,
   if (globalAttr.getIndices()) {
     llvm::SmallVector<mlir::LLVM::GEPArg> indices;
 
-    if (auto stTy = dyn_cast<mlir::LLVM::LLVMStructType>(sourceType)) {
-      if (stTy.isIdentified())
-        indices.push_back(0);
-    } else if (isa<mlir::LLVM::LLVMArrayType>(sourceType)) {
+    if (isa<mlir::LLVM::LLVMArrayType, mlir::LLVM::LLVMStructType>(sourceType))
       indices.push_back(0);
-    }
 
     for (auto idx : globalAttr.getIndices()) {
       auto intAttr = dyn_cast<mlir::IntegerAttr>(idx);
diff --git a/clang/test/CIR/CodeGen/globals-ref-globals.c b/clang/test/CIR/CodeGen/globals-ref-globals.c
new file mode 100644
index 000000000000..8343153e3e8e
--- /dev/null
+++ b/clang/test/CIR/CodeGen/globals-ref-globals.c
@@ -0,0 +1,126 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
+
+typedef struct {
+   int f0 : 24;
+   int f1;
+   int f2;
+} S;
+
+static S g1 = {2799, 9, 123};
+static int *g2[4] = {&g1.f1, &g1.f1, &g1.f1, &g1.f1};
+static int **g3 = &g2[1];
+static int ***g4 = &g3;
+static int ****g5 = &g4;
+
+static S g6[2] = {{2799, 9, 123}, {2799, 9, 123}};
+static int *g7[2] = {&g6[0].f2, &g6[1].f2};
+static int **g8 = &g7[1];
+
+// CHECK-DAG: !ty_anon_struct = !cir.struct<struct  {!u8i, !u8i, !u8i, !u8i, !s32i, !s32i}>
+// CHECK-DAG: !ty_anon_struct1 = !cir.struct<struct  {!s8i, !cir.array<!u8i x 3>, !s32i}>
+// CHECK-DAG: !ty_anon_struct2 = !cir.struct<struct  {!u8i, !u8i, !u8i, !u8i, !u8i, !u8i, !u8i, !u8i, !ty_S4_}>
+// CHECK-DAG: !ty_anon_struct3 = !cir.struct<struct  {!s16i, !cir.array<!u8i x 2>, !s32i, !s8i, !cir.array<!u8i x 3>}>
+
+// CHECK-DAG: g1 = #cir.const_struct<{#cir.int<239> : !u8i, #cir.int<10> : !u8i, #cir.int<0> : !u8i, #cir.zero : !u8i, #cir.int<9> : !s32i, #cir.int<123> : !s32i}> : !ty_anon_struct
+// CHECK-DAG: g2 = #cir.const_array<[#cir.global_view<@g1, [4]> : !cir.ptr<!ty_anon_struct>, #cir.global_view<@g1, [4]> : !cir.ptr<!ty_anon_struct>, #cir.global_view<@g1, [4]> : !cir.ptr<!ty_anon_struct>, #cir.global_view<@g1, [4]> : !cir.ptr<!ty_anon_struct>]> : !cir.array<!cir.ptr<!s32i> x 4>
+// CHECK-DAG: g3 = #cir.global_view<@g2, [1 : i32]> : !cir.ptr<!cir.ptr<!s32i>>
+// CHECK-DAG: g4 = #cir.global_view<@g3> : !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>>
+// CHECK-DAG: g5 = #cir.global_view<@g4> : !cir.ptr<!cir.ptr<!cir.ptr<!cir.ptr<!s32i>>>>
+// CHECK-DAG: g6 = #cir.const_array<[#cir.const_struct<{#cir.int<239> : !u8i, #cir.int<10> : !u8i, #cir.int<0> : !u8i, #cir.zero : !u8i, #cir.int<9> : !s32i, #cir.int<123> : !s32i}> : !ty_anon_struct, #cir.const_struct<{#cir.int<239> : !u8i, #cir.int<10> : !u8i, #cir.int<0> : !u8i, #cir.zero : !u8i, #cir.int<9> : !s32i, #cir.int<123> : !s32i}> : !ty_anon_struct]> : !cir.array<!ty_anon_struct x 2> 
+// CHECK-DAG: g7 = #cir.const_array<[#cir.global_view<@g6, [0, 5]> : !cir.ptr<!s32i>, #cir.global_view<@g6, [1, 5]> : !cir.ptr<!s32i>]> : !cir.array<!cir.ptr<!s32i> x 2> 
+// CHECK-DAG: g8 = #cir.global_view<@g7, [1 : i32]> : !cir.ptr<!cir.ptr<!s32i>> 
+
+// LLVM-DAG: @g1 = internal global { i8, i8, i8, i8, i32, i32 } { i8 -17, i8 10, i8 0, i8 0, i32 9, i32 123 }, align 4
+// LLVM-DAG: @g2 = internal global [4 x ptr] [ptr getelementptr inbounds ({ i8, i8, i8, i8, i32, i32 }, ptr @g1, i32 0, i32 4), ptr getelementptr inbounds ({ i8, i8, i8, i8, i32, i32 }, ptr @g1, i32 0, i32 4), ptr getelementptr inbounds ({ i8, i8, i8, i8, i32, i32 }, ptr @g1, i32 0, i32 4), ptr getelementptr inbounds ({ i8, i8, i8, i8, i32, i32 }, ptr @g1, i32 0, i32 4)], align 16
+// LLVM-DAG: @g3 = internal global ptr getelementptr inbounds ([4 x ptr], ptr @g2, i32 0, i32 1), align 8
+// LLVM-DAG: @g4 = internal global ptr @g3, align 8
+// LLVM-DAG: @g5 = internal global ptr @g4, align 8
+// LLVM-DAG: @g6 = internal global [2 x { i8, i8, i8, i8, i32, i32 }] [{ i8, i8, i8, i8, i32, i32 } { i8 -17, i8 10, i8 0, i8 0, i32 9, i32 123 }, { i8, i8, i8, i8, i32, i32 } { i8 -17, i8 10, i8 0, i8 0, i32 9, i32 123 }], align 16
+// LLVM-DAG: @g7 = internal global [2 x ptr] [ptr getelementptr inbounds ([2 x { i8, i8, i8, i8, i32, i32 }], ptr @g6, i32 0, i32 0, i32 5), ptr getelementptr inbounds ([2 x { i8, i8, i8, i8, i32, i32 }], ptr @g6, i32 0, i32 1, i32 5)], align 16
+// LLVM-DAG: @g8 = internal global ptr getelementptr inbounds ([2 x ptr], ptr @g7, i32 0, i32 1), align 8
+
+// FIXME: LLVM output should be: @g2 = internal global [4 x ptr] [ptr getelementptr (i8, ptr @g1, i64 4), ptr getelementptr (i8, ptr @g1, i64 4), ptr getelementptr (i8, ptr @g1, i64 4), ptr getelementptr (i8, ptr @g1, i64 4)], align 16
+// FIXME: LLVM output should be: @g3 = internal global ptr getelementptr (i8, ptr @g2, i64 8), align 8
+// FIXME: LLVM output should be: @g7 = internal global [2 x ptr] [ptr getelementptr (i8, ptr @g6, i64 8), ptr getelementptr (i8, ptr @g6, i64 20)], align 16
+// FIXME: LLVM output should be: @g8 = internal global ptr getelementptr (i8, ptr @g7, i64 8), align 8
+
+typedef struct {
+   char f1;
+   int  f6;
+} S1;
+
+S1 g9 = {1, 42};
+int* g10 = &g9.f6;
+
+#pragma pack(push)
+#pragma pack(1)
+typedef struct {
+   char f1;
+   int  f6;
+} S2;
+#pragma pack(pop)
+
+S2 g11 = {1, 42};
+int* g12 = &g11.f6;
+
+// CHECK-DAG: g9 = #cir.const_struct<{#cir.int<1> : !s8i, #cir.const_array<[#cir.zero : !u8i, #cir.zero : !u8i, #cir.zero : !u8i]> : !cir.array<!u8i x 3>, #cir.int<42> : !s32i}> : !ty_anon_struct1 {alignment = 4 : i64}
+// CHECK-DAG: g10 = #cir.global_view<@g9, [2 : i32]> : !cir.ptr<!s32i> {alignment = 8 : i64}
+// CHECK-DAG: g11 = #cir.const_struct<{#cir.int<1> : !s8i, #cir.int<42> : !s32i}> : !ty_S2_ {alignment = 1 : i64}
+// CHECK-DAG: g12 = #cir.global_view<@g11, [1 : i32]> : !cir.ptr<!s32i> {alignment = 8 : i64} 
+
+// LLVM-DAG: @g9 = global { i8, [3 x i8], i32 } { i8 1, [3 x i8] zeroinitializer, i32 42 }, align 4
+// LLVM-DAG: @g10 = global ptr getelementptr inbounds ({ i8, [3 x i8], i32 }, ptr @g9, i32 0, i32 2), align 8
+// LLVM-DAG: @g11 = global %struct.S2 <{ i8 1, i32 42 }>, align 1
+// LLVM-DAG: @g12 = global ptr getelementptr inbounds (%struct.S2, ptr @g11, i32 0, i32 1), align 8
+
+// FIXME: LLVM output should be: @g10 = dso_local global ptr getelementptr (i8, ptr @g9, i64 4), align 8
+// FIXME: LLVM output should be: @g12 = dso_local global ptr getelementptr (i8, ptr @g11, i64 1), align 8
+
+
+typedef struct {
+   short f0;
+   int   f1;
+   char  f2;
+} S3;
+
+static S3 g13 = {-1L,0L,1L};
+static S3* g14[2][2] = {{&g13, &g13}, {&g13, &g13}};
+
+// CHECK-DAG: g13 = #cir.const_struct<{#cir.int<-1> : !s16i, #cir.const_array<[#cir.zero : !u8i, #cir.zero : !u8i]> : !cir.array<!u8i x 2>, #cir.int<0> : !s32i, #cir.int<1> : !s8i, #cir.const_array<[#cir.zero : !u8i, #cir.zero : !u8i, #cir.zero : !u8i]> : !cir.array<!u8i x 3>}> : !ty_anon_struct3
+// CHECK-DAG: g14 = #cir.const_array<[#cir.const_array<[#cir.global_view<@g13> : !cir.ptr<!ty_S3_>, #cir.global_view<@g13> : !cir.ptr<!ty_S3_>]> : !cir.array<!cir.ptr<!ty_S3_> x 2>, #cir.const_array<[#cir.global_view<@g13> : !cir.ptr<!ty_S3_>, #cir.global_view<@g13> : !cir.ptr<!ty_S3_>]> : !cir.array<!cir.ptr<!ty_S3_> x 2>]> : !cir.array<!cir.array<!cir.ptr<!ty_S3_> x 2> x 2>
+
+typedef struct {
+   int  f0;
+   int  f1;
+} S4;
+
+typedef struct {
+   int f0 : 17;
+   int f1 : 5;
+   int f2 : 19;
+   S4 f3;   
+} S5;
+
+static S5 g15 = {187,1,442,{123,321}};
+
+int* g16 = &g15.f3.f1;
+
+// CHECK-DAG: g15 = #cir.const_struct<{#cir.int<187> : !u8i, #cir.int<0> : !u8i, #cir.int<2> : !u8i, #cir.zero : !u8i, #cir.int<186> : !u8i, #cir.int<1> : !u8i, #cir.int<0> : !u8i, #cir.zero : !u8i, #cir.const_struct<{#cir.int<123> : !s32i, #cir.int<321> : !s32i}> : !ty_S4_}> : !ty_anon_struct2 {alignment = 4 : i64}
+// CHECK-DAG: g16 = #cir.global_view<@g15, [8, 1]> : !cir.ptr<!ty_anon_struct2> {alignment = 8 : i64}
+
+// LLVM-DAG: @g15 = internal global { i8, i8, i8, i8, i8, i8, i8, i8, %struct.S4 } { i8 -69, i8 0, i8 2, i8 0, i8 -70, i8 1, i8 0, i8 0, %struct.S4 { i32 123, i32 321 } }, align 4
+// LLVM-DAG: @g16 = global ptr getelementptr inbounds ({ i8, i8, i8, i8, i8, i8, i8, i8, %struct.S4 }, ptr @g15, i32 0, i32 8, i32 1), align 8
+
+// FIXME: LLVM output should be: @g16 = dso_local global ptr getelementptr (i8, ptr @g15, i64 12), align 8
+
+void use() {
+    int a = **g3;
+    int b = ***g4; 
+    int c = ****g5; 
+    int d = **g8;
+    S3 s = *g14[1][1];
+    int f = *g16;
+}
diff --git a/clang/test/CIR/CodeGen/union-padding.c b/clang/test/CIR/CodeGen/union-padding.c
index 8deb2890083c..85ed30d52ce5 100644
--- a/clang/test/CIR/CodeGen/union-padding.c
+++ b/clang/test/CIR/CodeGen/union-padding.c
@@ -19,7 +19,7 @@ short use() {
 // CHECK:       !ty_anon_struct = !cir.struct<struct  {!s16i, !cir.array<!u8i x 2>}>
 
 // CHECK:       @g3 = #cir.global_view<@g2> : !cir.ptr<!cir.ptr<!s16i>>
-// CHECK:       @g2 = #cir.const_array<[#cir.global_view<@g1, [1 : i32]> : !cir.ptr<!s16i>]> : !cir.array<!cir.ptr<!s16i> x 1> 
+// CHECK:       @g2 = #cir.const_array<[#cir.global_view<@g1, [1]> : !cir.ptr<!s16i>]> : !cir.array<!cir.ptr<!s16i> x 1>
 
 // CHECK:       @g1 = 
 // CHECK-SAME:    #cir.const_array<[
diff --git a/clang/test/CIR/CodeGen/vbase.cpp b/clang/test/CIR/CodeGen/vbase.cpp
index 1ba565b7cb79..574d2d943258 100644
--- a/clang/test/CIR/CodeGen/vbase.cpp
+++ b/clang/test/CIR/CodeGen/vbase.cpp
@@ -18,7 +18,7 @@ void ppp() { B b; }
 // CIR:  cir.global linkonce_odr @_ZTV1B = #cir.vtable<{#cir.const_array<[#cir.ptr<12 : i64> : !cir.ptr<!u8i>, #cir.ptr<null> : !cir.ptr<!u8i>, #cir.global_view<@_ZTI1B> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 3>}>
 
 // VTT for B.
-// CIR:  cir.global linkonce_odr @_ZTT1B = #cir.const_array<[#cir.global_view<@_ZTV1B, [0 : i32, 0 : i32, 3 : i32]> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 1>
+// CIR:  cir.global linkonce_odr @_ZTT1B = #cir.const_array<[#cir.global_view<@_ZTV1B, [0 : i32, 3 : i32]> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 1>
 
 // CIR:  cir.global "private" external @_ZTVN10__cxxabiv121__vmi_class_type_infoE
 
diff --git a/clang/test/CIR/CodeGen/vtable-emission.cpp b/clang/test/CIR/CodeGen/vtable-emission.cpp
index 6691167488c5..7f09f74de0d5 100644
--- a/clang/test/CIR/CodeGen/vtable-emission.cpp
+++ b/clang/test/CIR/CodeGen/vtable-emission.cpp
@@ -20,7 +20,7 @@ void S::key() {}
 // LLVM-SAME: [ptr null, ptr @_ZTI1S, ptr @_ZN1S3keyEv, ptr @_ZN1S6nonKeyEv] }, align 8
 
 // CHECK: cir.global external @sobj = #cir.const_struct
-// CHECK-SAME: <{#cir.global_view<@_ZTV1S, [0 : i32, 0 : i32, 2 : i32]> :
+// CHECK-SAME: <{#cir.global_view<@_ZTV1S, [0 : i32, 2 : i32]> :
 // CHECK-SAME: !cir.ptr<!ty_anon_struct1>}> : !ty_anon_struct2 {alignment = 8 : i64}
 // LLVM: @sobj = global { ptr } { ptr getelementptr inbounds
 // LLVM-SAME: ({ [4 x ptr] }, ptr @_ZTV1S, i32 0, i32 0, i32 2) }, align 8
diff --git a/clang/test/CIR/CodeGen/vtt.cpp b/clang/test/CIR/CodeGen/vtt.cpp
index ab8cc999f856..c32e242737cf 100644
--- a/clang/test/CIR/CodeGen/vtt.cpp
+++ b/clang/test/CIR/CodeGen/vtt.cpp
@@ -46,7 +46,7 @@ int f() {
 // Vtable of Class D
 // CIR: cir.global linkonce_odr @_ZTV1D = #cir.vtable<{#cir.const_array<[#cir.ptr<40 : i64> : !cir.ptr<!u8i>, #cir.ptr<null> : !cir.ptr<!u8i>, #cir.global_view<@_ZTI1D> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1B1wEv> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1D1yEv> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 5>, #cir.const_array<[#cir.ptr<24 : i64> : !cir.ptr<!u8i>, #cir.ptr<-16 : i64> : !cir.ptr<!u8i>, #cir.global_view<@_ZTI1D> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1C1xEv> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 4>, #cir.const_array<[#cir.ptr<null> : !cir.ptr<!u8i>, #cir.ptr<-40 : i64> : !cir.ptr<!u8i>, #cir.global_view<@_ZTI1D> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1A1vEv> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 4>}> : !ty_anon_struct4 {alignment = 8 : i64}
 // VTT of class D
-// CIR: cir.global linkonce_odr @_ZTT1D = #cir.const_array<[#cir.global_view<@_ZTV1D, [0 : i32, 0 : i32, 3 : i32]> : !cir.ptr<!u8i>, #cir.global_view<@_ZTC1D0_1B, [0 : i32, 0 : i32, 3 : i32]> : !cir.ptr<!u8i>, #cir.global_view<@_ZTC1D0_1B, [0 : i32, 1 : i32, 3 : i32]> : !cir.ptr<!u8i>, #cir.global_view<@_ZTC1D16_1C, [0 : i32, 0 : i32, 3 : i32]> : !cir.ptr<!u8i>, #cir.global_view<@_ZTC1D16_1C, [0 : i32, 1 : i32, 3 : i32]> : !cir.ptr<!u8i>, #cir.global_view<@_ZTV1D, [0 : i32, 2 : i32, 3 : i32]> : !cir.ptr<!u8i>, #cir.global_view<@_ZTV1D, [0 : i32, 1 : i32, 3 : i32]> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 7> {alignment = 8 : i64}
+// CIR: cir.global linkonce_odr @_ZTT1D = #cir.const_array<[#cir.global_view<@_ZTV1D, [0 : i32, 3 : i32]> : !cir.ptr<!u8i>, #cir.global_view<@_ZTC1D0_1B, [0 : i32, 3 : i32]> : !cir.ptr<!u8i>, #cir.global_view<@_ZTC1D0_1B, [1 : i32, 3 : i32]> : !cir.ptr<!u8i>, #cir.global_view<@_ZTC1D16_1C, [0 : i32, 3 : i32]> : !cir.ptr<!u8i>, #cir.global_view<@_ZTC1D16_1C, [1 : i32, 3 : i32]> : !cir.ptr<!u8i>, #cir.global_view<@_ZTV1D, [2 : i32, 3 : i32]> : !cir.ptr<!u8i>, #cir.global_view<@_ZTV1D, [1 : i32, 3 : i32]> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 7> {alignment = 8 : i64}
 
 // Class B constructor
 // CIR: cir.func linkonce_odr @_ZN1BC2Ev(%arg0: !cir.ptr<!ty_B>