https://github.com/AmrDeveloper updated 
https://github.com/llvm/llvm-project/pull/134536

>From 81e1cd76594d3eaeda67d5888e5e5daa63fb0e12 Mon Sep 17 00:00:00 2001
From: AmrDeveloper <am...@programmer.net>
Date: Sun, 6 Apr 2025 14:31:35 +0200
Subject: [PATCH 1/8] [CIR] Upstream ArraySubscriptExpr for fixed size array

---
 clang/include/clang/CIR/MissingFeatures.h  |   1 +
 clang/lib/CIR/CodeGen/CIRGenBuilder.cpp    |  40 ++++++
 clang/lib/CIR/CodeGen/CIRGenBuilder.h      |  13 ++
 clang/lib/CIR/CodeGen/CIRGenExpr.cpp       | 156 +++++++++++++++++++++
 clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp |   9 ++
 clang/lib/CIR/CodeGen/CIRGenFunction.cpp   |   2 +
 clang/lib/CIR/CodeGen/CIRGenFunction.h     |   2 +
 clang/lib/CIR/CodeGen/CMakeLists.txt       |   1 +
 clang/test/CIR/CodeGen/array.cpp           |  21 ++-
 clang/test/CIR/Lowering/array.cpp          |  34 +++--
 10 files changed, 268 insertions(+), 11 deletions(-)
 create mode 100644 clang/lib/CIR/CodeGen/CIRGenBuilder.cpp

diff --git a/clang/include/clang/CIR/MissingFeatures.h 
b/clang/include/clang/CIR/MissingFeatures.h
index 86fdaf1ddaf51..6872f50565721 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -108,6 +108,7 @@ struct MissingFeatures {
   static bool cgFPOptionsRAII() { return false; }
   static bool metaDataNode() { return false; }
   static bool fastMathFlags() { return false; }
+  static bool emitCheckedInBoundsGEP() { return false; }
 
   // Missing types
   static bool dataMemberType() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp 
b/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp
new file mode 100644
index 0000000000000..2f1940e656172
--- /dev/null
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp
@@ -0,0 +1,40 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "CIRGenBuilder.h"
+
+using namespace clang::CIRGen;
+
+mlir::Value CIRGenBuilderTy::maybeBuildArrayDecay(mlir::Location loc,
+                                                  mlir::Value arrayPtr,
+                                                  mlir::Type eltTy) {
+  const auto arrayPtrTy = mlir::cast<cir::PointerType>(arrayPtr.getType());
+  const auto arrayTy = mlir::dyn_cast<cir::ArrayType>(arrayPtrTy.getPointee());
+
+  if (arrayTy) {
+    const cir::PointerType flatPtrTy = getPointerTo(arrayTy.getEltType());
+    return create<cir::CastOp>(loc, flatPtrTy, 
cir::CastKind::array_to_ptrdecay,
+                               arrayPtr);
+  }
+
+  assert(arrayPtrTy.getPointee() == eltTy &&
+         "flat pointee type must match original array element type");
+  return arrayPtr;
+}
+
+mlir::Value CIRGenBuilderTy::getArrayElement(mlir::Location arrayLocBegin,
+                                             mlir::Location arrayLocEnd,
+                                             mlir::Value arrayPtr,
+                                             mlir::Type eltTy, mlir::Value idx,
+                                             bool shouldDecay) {
+  mlir::Value basePtr = arrayPtr;
+  if (shouldDecay)
+    basePtr = maybeBuildArrayDecay(arrayLocBegin, arrayPtr, eltTy);
+  const mlir::Type flatPtrTy = basePtr.getType();
+  return create<cir::PtrStrideOp>(arrayLocEnd, flatPtrTy, basePtr, idx);
+}
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h 
b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index 61a747254b3d0..e659a8fbf4eff 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -198,6 +198,19 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
 
     return create<cir::BinOp>(loc, cir::BinOpKind::Div, lhs, rhs);
   }
+
+  /// Create a cir.ptr_stride operation to get access to an array element.
+  /// idx is the index of the element to access, shouldDecay is true if the
+  /// result should decay to a pointer to the element type.
+  mlir::Value getArrayElement(mlir::Location arrayLocBegin,
+                              mlir::Location arrayLocEnd, mlir::Value arrayPtr,
+                              mlir::Type eltTy, mlir::Value idx,
+                              bool shouldDecay);
+
+  /// Returns a decayed pointer to the first element of the array
+  /// pointed to by arrayPtr.
+  mlir::Value maybeBuildArrayDecay(mlir::Location loc, mlir::Value arrayPtr,
+                                   mlir::Type eltTy);
 };
 
 } // namespace clang::CIRGen
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index f01e03a89981d..f1a15e46265b5 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -12,6 +12,7 @@
 
 #include "Address.h"
 #include "CIRGenFunction.h"
+#include "CIRGenModule.h"
 #include "CIRGenValue.h"
 #include "mlir/IR/BuiltinAttributes.h"
 #include "clang/AST/Attr.h"
@@ -232,6 +233,161 @@ LValue CIRGenFunction::emitUnaryOpLValue(const 
UnaryOperator *e) {
   llvm_unreachable("Unknown unary operator kind!");
 }
 
+/// If the specified expr is a simple decay from an array to pointer,
+/// return the array subexpression.
+/// FIXME: this could be abstracted into a commeon AST helper.
+static const Expr *isSimpleArrayDecayOperand(const Expr *e) {
+  // If this isn't just an array->pointer decay, bail out.
+  const auto *castExpr = dyn_cast<CastExpr>(e);
+  if (!castExpr || castExpr->getCastKind() != CK_ArrayToPointerDecay)
+    return nullptr;
+
+  // If this is a decay from variable width array, bail out.
+  const Expr *subExpr = castExpr->getSubExpr();
+  if (subExpr->getType()->isVariableArrayType())
+    return nullptr;
+
+  return subExpr;
+}
+
+static mlir::IntegerAttr getConstantIndexOrNull(mlir::Value idx) {
+  // TODO(cir): should we consider using MLIRs IndexType instead of 
IntegerAttr?
+  if (auto constantOp = dyn_cast<cir::ConstantOp>(idx.getDefiningOp()))
+    return mlir::dyn_cast<mlir::IntegerAttr>(constantOp.getValue());
+  return {};
+}
+
+static CharUnits getArrayElementAlign(CharUnits arrayAlign, mlir::Value idx,
+                                      CharUnits eltSize) {
+  // If we have a constant index, we can use the exact offset of the
+  // element we're accessing.
+  const mlir::IntegerAttr constantIdx = getConstantIndexOrNull(idx);
+  if (constantIdx) {
+    const CharUnits offset = constantIdx.getValue().getZExtValue() * eltSize;
+    return arrayAlign.alignmentAtOffset(offset);
+  }
+  // Otherwise, use the worst-case alignment for any element.
+  return arrayAlign.alignmentOfArrayElement(eltSize);
+}
+
+static QualType getFixedSizeElementType(const ASTContext &astContext,
+                                        const VariableArrayType *vla) {
+  QualType eltType;
+  do {
+    eltType = vla->getElementType();
+  } while ((vla = astContext.getAsVariableArrayType(eltType)));
+  return eltType;
+}
+
+static mlir::Value
+emitArraySubscriptPtr(CIRGenFunction &cgf, mlir::Location beginLoc,
+                      mlir::Location endLoc, mlir::Value ptr, mlir::Type eltTy,
+                      ArrayRef<mlir::Value> indices, bool inbounds,
+                      bool signedIndices, bool shouldDecay,
+                      const llvm::Twine &name = "arrayidx") {
+  if (indices.size() > 1) {
+    cgf.cgm.errorNYI("emitArraySubscriptPtr: handle multiple indices");
+    return {};
+  }
+
+  const mlir::Value idx = indices.back();
+  CIRGenModule &cgm = cgf.getCIRGenModule();
+  // TODO(cir): LLVM codegen emits in bound gep check here, is there anything
+  // that would enhance tracking this later in CIR?
+  if (inbounds)
+    assert(!cir::MissingFeatures::emitCheckedInBoundsGEP() && "NYI");
+  return cgm.getBuilder().getArrayElement(beginLoc, endLoc, ptr, eltTy, idx,
+                                          shouldDecay);
+}
+
+static Address emitArraySubscriptPtr(
+    CIRGenFunction &cgf, mlir::Location beginLoc, mlir::Location endLoc,
+    Address addr, ArrayRef<mlir::Value> indices, QualType eltType,
+    bool inbounds, bool signedIndices, mlir::Location loc, bool shouldDecay,
+    QualType *arrayType = nullptr, const Expr *base = nullptr,
+    const llvm::Twine &name = "arrayidx") {
+
+  // Determine the element size of the statically-sized base.  This is
+  // the thing that the indices are expressed in terms of.
+  if (const VariableArrayType *vla =
+          cgf.getContext().getAsVariableArrayType(eltType)) {
+    eltType = getFixedSizeElementType(cgf.getContext(), vla);
+  }
+
+  // We can use that to compute the best alignment of the element.
+  const CharUnits eltSize = cgf.getContext().getTypeSizeInChars(eltType);
+  const CharUnits eltAlign =
+      getArrayElementAlign(addr.getAlignment(), indices.back(), eltSize);
+
+  mlir::Value eltPtr;
+  const mlir::IntegerAttr lastIndex = getConstantIndexOrNull(indices.back());
+  if (!lastIndex) {
+    eltPtr = emitArraySubscriptPtr(cgf, beginLoc, endLoc, addr.getPointer(),
+                                   addr.getElementType(), indices, inbounds,
+                                   signedIndices, shouldDecay, name);
+  }
+  const mlir::Type elementType = cgf.convertTypeForMem(eltType);
+  return Address(eltPtr, elementType, eltAlign);
+}
+
+LValue
+CIRGenFunction::emitArraySubscriptExpr(const clang::ArraySubscriptExpr *e) {
+  if (e->getBase()->getType()->isVectorType() &&
+      !isa<ExtVectorElementExpr>(e->getBase())) {
+    cgm.errorNYI(e->getSourceRange(), "emitArraySubscriptExpr: VectorType");
+    return {};
+  }
+
+  if (isa<ExtVectorElementExpr>(e->getBase())) {
+    cgm.errorNYI(e->getSourceRange(),
+                 "emitArraySubscriptExpr: ExtVectorElementExpr");
+    return {};
+  }
+
+  if (getContext().getAsVariableArrayType(e->getType())) {
+    cgm.errorNYI(e->getSourceRange(),
+                 "emitArraySubscriptExpr: VariableArrayType");
+    return {};
+  }
+
+  if (e->getType()->getAs<ObjCObjectType>()) {
+    cgm.errorNYI(e->getSourceRange(), "emitArraySubscriptExpr: 
ObjCObjectType");
+    return {};
+  }
+
+  // The index must always be an integer, which is not an aggregate.  Emit it
+  // in lexical order (this complexity is, sadly, required by C++17).
+  assert((e->getIdx() == e->getLHS() || e->getIdx() == e->getRHS()) &&
+         "index was neither LHS nor RHS");
+  const mlir::Value idx = emitScalarExpr(e->getIdx());
+  const QualType idxTy = e->getIdx()->getType();
+  const bool signedIndices = idxTy->isSignedIntegerOrEnumerationType();
+
+  if (const Expr *array = isSimpleArrayDecayOperand(e->getBase())) {
+    LValue arrayLV;
+    if (const auto *ase = dyn_cast<ArraySubscriptExpr>(array))
+      arrayLV = emitArraySubscriptExpr(ase);
+    else
+      arrayLV = emitLValue(array);
+
+    // Propagate the alignment from the array itself to the result.
+    QualType arrayType = array->getType();
+    const Address addr = emitArraySubscriptPtr(
+        *this, cgm.getLoc(array->getBeginLoc()), 
cgm.getLoc(array->getEndLoc()),
+        arrayLV.getAddress(), {idx}, e->getType(),
+        !getLangOpts().isSignedOverflowDefined(), signedIndices,
+        cgm.getLoc(e->getExprLoc()), /*shouldDecay=*/true, &arrayType,
+        e->getBase());
+
+    return LValue::makeAddr(addr, e->getType());
+  }
+
+  // The base must be a pointer; emit it with an estimate of its alignment.
+  cgm.errorNYI(e->getSourceRange(),
+               "emitArraySubscriptExpr: The base must be a pointer");
+  return {};
+}
+
 LValue CIRGenFunction::emitBinaryOperatorLValue(const BinaryOperator *e) {
   // Comma expressions just emit their LHS then their RHS as an l-value.
   if (e->getOpcode() == BO_Comma) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 3863d21487531..09794a782b0be 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -157,6 +157,15 @@ class ScalarExprEmitter : public 
StmtVisitor<ScalarExprEmitter, mlir::Value> {
 
   mlir::Value VisitCastExpr(CastExpr *e);
 
+  mlir::Value VisitArraySubscriptExpr(ArraySubscriptExpr *e) {
+    if (e->getBase()->getType()->isVectorType()) {
+      assert(!cir::MissingFeatures::scalableVectors() &&
+             "NYI: index into scalable vector");
+    }
+    // Just load the lvalue formed by the subscript expression.
+    return emitLoadOfLValue(e);
+  }
+
   mlir::Value VisitExplicitCastExpr(ExplicitCastExpr *e) {
     return VisitCastExpr(e);
   }
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp 
b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index 2465ccffd19d6..b518a3286f7aa 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -444,6 +444,8 @@ LValue CIRGenFunction::emitLValue(const Expr *e) {
                                std::string("l-value not implemented for '") +
                                    e->getStmtClassName() + "'");
     return LValue();
+  case Expr::ArraySubscriptExprClass:
+    return emitArraySubscriptExpr(cast<ArraySubscriptExpr>(e));
   case Expr::UnaryOperatorClass:
     return emitUnaryOpLValue(cast<UnaryOperator>(e));
   case Expr::BinaryOperatorClass:
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 1bedbe28ae625..f279a821b3292 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -387,6 +387,8 @@ class CIRGenFunction : public CIRGenTypeCache {
   /// should be returned.
   RValue emitAnyExpr(const clang::Expr *e);
 
+  LValue emitArraySubscriptExpr(const clang::ArraySubscriptExpr *e);
+
   AutoVarEmission emitAutoVarAlloca(const clang::VarDecl &d);
 
   /// Emit code and set up symbol table for a variable declaration with auto,
diff --git a/clang/lib/CIR/CodeGen/CMakeLists.txt 
b/clang/lib/CIR/CodeGen/CMakeLists.txt
index da8d63ca569af..90544582e4415 100644
--- a/clang/lib/CIR/CodeGen/CMakeLists.txt
+++ b/clang/lib/CIR/CodeGen/CMakeLists.txt
@@ -8,6 +8,7 @@ get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS)
 
 add_clang_library(clangCIR
   CIRGenerator.cpp
+  CIRGenBuilder.cpp
   CIRGenDecl.cpp
   CIRGenExpr.cpp
   CIRGenExprAggregate.cpp
diff --git a/clang/test/CIR/CodeGen/array.cpp b/clang/test/CIR/CodeGen/array.cpp
index 0d28ebc66f83c..387c32742b891 100644
--- a/clang/test/CIR/CodeGen/array.cpp
+++ b/clang/test/CIR/CodeGen/array.cpp
@@ -29,8 +29,15 @@ int f[5] = {1, 2};
 
 void func() {
   int arr[10];
-
   // CHECK: %[[ARR:.*]] = cir.alloca !cir.array<!s32i x 10>, 
!cir.ptr<!cir.array<!s32i x 10>>, ["arr"]
+
+  int e = arr[1];
+  // CHECK: %[[INIT:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["e", init]
+  // CHECK: %[[IDX:.*]] = cir.const #cir.int<1> : !s32i
+  // CHECK: %[[ARR_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR]] : 
!cir.ptr<!cir.array<!s32i x 10>>), !cir.ptr<!s32i>
+  // CHECK: %[[ELE_PTR:.*]] = cir.ptr_stride(%[[ARR_PTR]] : !cir.ptr<!s32i>, 
%[[IDX]] : !s32i), !cir.ptr<!s32i>
+  // CHECK: %[[TMP:.*]] = cir.load %[[ELE_PTR]] : !cir.ptr<!s32i>, !s32i
+  // CHECK" cir.store %[[TMP]], %[[INIT]] : !s32i, !cir.ptr<!s32i>
 }
 
 void func2() {
@@ -69,6 +76,7 @@ void func4() {
   int arr[2][1] = {{5}, {6}};
 
   // CHECK: %[[ARR:.*]] = cir.alloca !cir.array<!cir.array<!s32i x 1> x 2>, 
!cir.ptr<!cir.array<!cir.array<!s32i x 1> x 2>>, ["arr", init]
+  // CHECK: %[[INIT:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["e", init]
   // CHECK: %[[ARR_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR]] : 
!cir.ptr<!cir.array<!cir.array<!s32i x 1> x 2>>), !cir.ptr<!cir.array<!s32i x 
1>>
   // CHECK: %[[ARR_0_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR_PTR]] : 
!cir.ptr<!cir.array<!s32i x 1>>), !cir.ptr<!s32i>
   // CHECK: %[[V_0_0:.*]] = cir.const #cir.int<5> : !s32i
@@ -78,6 +86,17 @@ void func4() {
   // CHECK: %[[ARR_1_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR_1]] : 
!cir.ptr<!cir.array<!s32i x 1>>), !cir.ptr<!s32i>
   // CHECK: %[[V_1_0:.*]] = cir.const #cir.int<6> : !s32i
   // CHECK: cir.store %[[V_1_0]], %[[ARR_1_PTR]] : !s32i, !cir.ptr<!s32i>
+
+  int e = arr[1][0];
+
+  // CHECK: %[[IDX:.*]] = cir.const #cir.int<0> : !s32i
+  // CHECK: %[[IDX_1:.*]] = cir.const #cir.int<1> : !s32i
+  // CHECK: %[[ARR_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR]] : 
!cir.ptr<!cir.array<!cir.array<!s32i x 1> x 2>>), !cir.ptr<!cir.array<!s32i x 
1>>
+  // CHECK: %[[ARR_1:.*]] = cir.ptr_stride(%[[ARR_PTR]] : 
!cir.ptr<!cir.array<!s32i x 1>>, %[[IDX_1]] : !s32i), !cir.ptr<!cir.array<!s32i 
x 1>>
+  // CHECK: %[[ARR_1_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR_1]] : 
!cir.ptr<!cir.array<!s32i x 1>>), !cir.ptr<!s32i>
+  // CHECK: %[[ELE_0:.*]] = cir.ptr_stride(%[[ARR_1_PTR]] : !cir.ptr<!s32i>, 
%[[IDX]] : !s32i), !cir.ptr<!s32i>
+  // CHECK: %[[TMP:.*]] = cir.load %[[ELE_0]] : !cir.ptr<!s32i>, !s32i
+  // CHECK: cir.store %[[TMP]], %[[INIT]] : !s32i, !cir.ptr<!s32i>
 }
 
 void func5() {
diff --git a/clang/test/CIR/Lowering/array.cpp 
b/clang/test/CIR/Lowering/array.cpp
index e1c977eb43141..8519525db07ec 100644
--- a/clang/test/CIR/Lowering/array.cpp
+++ b/clang/test/CIR/Lowering/array.cpp
@@ -31,12 +31,18 @@ int f[5] = {1, 2};
 
 void func() {
   int arr[10];
+  int e = arr[1];
 }
 // CHECK: define void @func()
-// CHECK-NEXT: alloca [10 x i32], i64 1, align 16
+// CHECK-NEXT: %[[ARR_ALLOCA:.*]] = alloca [10 x i32], i64 1, align 16
+// CHECK-NEXT: %[[INIT:.*]] = alloca i32, i64 1, align 4
+// CHECK-NEXT: %[[ARR_PTR:.*]] = getelementptr i32, ptr %[[ARR_ALLOCA]], i32 0
+// CHECK-NEXT: %[[ELE_PTR:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i64 1
+// CHECK-NEXT: %[[TMP:.*]] = load i32, ptr %[[ELE_PTR]], align 4
+// CHECK-NEXT: store i32 %[[TMP]], ptr %[[INIT]], align 4
 
 void func2() {
-  int arr2[2] = {5};
+  int arr[2] = {5};
 }
 // CHECK: define void @func2()
 // CHECK:  %[[ARR_ALLOCA:.*]] = alloca [2 x i32], i64 1, align 4
@@ -61,19 +67,27 @@ void func3() {
 // CHECK:  store i32 6, ptr %[[ELE_1_PTR]], align 4
 
 void func4() {
-  int arr4[2][1] = {{5}, {6}};
+  int arr[2][1] = {{5}, {6}};
+  int e = arr[1][0];
 }
 // CHECK: define void @func4()
 // CHECK:  %[[ARR_ALLOCA:.*]] = alloca [2 x [1 x i32]], i64 1, align 4
-// CHECK:  %[[ARR_0:.*]] = getelementptr [1 x i32], ptr %[[ARR_ALLOCA]], i32 0
-// CHECK:  %[[ARR_0_ELE_0:.*]] = getelementptr i32, ptr %[[ARR_0]], i32 0
-// CHECK:  store i32 5, ptr %[[ARR_0_ELE_0]], align 4
-// CHECK:  %[[ARR_1:.*]] = getelementptr [1 x i32], ptr %2, i64 1
-// CHECK:  %[[ARR_0_ELE_0:.*]] = getelementptr i32, ptr %[[ARR_1]], i32 0
-// CHECK:  store i32 6, ptr %[[ARR_0_ELE_0]], align 4
+// CHECK:  %[[INIT:.*]] = alloca i32, i64 1, align 4
+// CHECK:  %[[ARR_PTR:.*]] = getelementptr [1 x i32], ptr %[[ARR_ALLOCA]], i32 0
+// CHECK:  %[[ARR_0_0:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i32 0
+// CHECK:  store i32 5, ptr %[[ARR_0_0]], align 4
+// CHECK:  %[[ARR_1:.*]] = getelementptr [1 x i32], ptr %[[ARR_PTR]], i64 1
+// CHECK:  %[[ARR_1_0:.*]] = getelementptr i32, ptr %[[ARR_1]], i32 0
+// CHECK:  store i32 6, ptr %[[ARR_1_0]], align 4
+// CHECK:  %[[ARR_PTR:.*]] = getelementptr [1 x i32], ptr %[[ARR_ALLOCA]], i32 0
+// CHECK:  %[[ARR_1:.*]] = getelementptr [1 x i32], ptr %[[ARR_PTR]], i64 1
+// CHECK:  %[[ARR_1_0:.*]] = getelementptr i32, ptr %[[ARR_1]], i32 0
+// CHECK:  %[[ELE_PTR:.*]] = getelementptr i32, ptr %[[ARR_1_0]], i64 0
+// CHECK:  %[[TMP:.*]] = load i32, ptr %[[ELE_PTR]], align 4
+// CHECK:  store i32 %[[TMP]], ptr %[[INIT]], align 4
 
 void func5() {
-  int arr5[2][1] = {{5}};
+  int arr[2][1] = {{5}};
 }
 // CHECK: define void @func5()
 // CHECK:  %[[ARR_ALLOCA:.*]] = alloca [2 x [1 x i32]], i64 1, align 4

>From 8d2acb1d47d2162bd410849861725ec1dee4bdcb Mon Sep 17 00:00:00 2001
From: AmrDeveloper <am...@programmer.net>
Date: Mon, 7 Apr 2025 19:53:21 +0200
Subject: [PATCH 2/8] Fix typo in comment

---
 clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index f1a15e46265b5..3b188b38cd5b8 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -235,7 +235,7 @@ LValue CIRGenFunction::emitUnaryOpLValue(const 
UnaryOperator *e) {
 
 /// If the specified expr is a simple decay from an array to pointer,
 /// return the array subexpression.
-/// FIXME: this could be abstracted into a commeon AST helper.
+/// FIXME: this could be abstracted into a common AST helper.
 static const Expr *isSimpleArrayDecayOperand(const Expr *e) {
   // If this isn't just an array->pointer decay, bail out.
   const auto *castExpr = dyn_cast<CastExpr>(e);

>From e7d093b891d1378e4910bfb53345bb1df8a2183a Mon Sep 17 00:00:00 2001
From: AmrDeveloper <am...@programmer.net>
Date: Tue, 8 Apr 2025 19:26:19 +0200
Subject: [PATCH 3/8] Address code review comments

---
 clang/lib/CIR/CodeGen/CIRGenBuilder.h      |  6 +-
 clang/lib/CIR/CodeGen/CIRGenExpr.cpp       | 65 ++++++++++------------
 clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp |  5 +-
 clang/test/CIR/CodeGen/array.cpp           | 15 ++++-
 clang/test/CIR/Lowering/array.cpp          | 10 +++-
 5 files changed, 54 insertions(+), 47 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h 
b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index e659a8fbf4eff..0d8568742e960 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -200,15 +200,15 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
   }
 
   /// Create a cir.ptr_stride operation to get access to an array element.
-  /// idx is the index of the element to access, shouldDecay is true if the
-  /// result should decay to a pointer to the element type.
+  /// \p idx is the index of the element to access, \p shouldDecay is true if
+  /// the result should decay to a pointer to the element type.
   mlir::Value getArrayElement(mlir::Location arrayLocBegin,
                               mlir::Location arrayLocEnd, mlir::Value arrayPtr,
                               mlir::Type eltTy, mlir::Value idx,
                               bool shouldDecay);
 
   /// Returns a decayed pointer to the first element of the array
-  /// pointed to by arrayPtr.
+  /// pointed to by \p arrayPtr.
   mlir::Value maybeBuildArrayDecay(mlir::Location loc, mlir::Value arrayPtr,
                                    mlir::Type eltTy);
 };
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index 3b188b38cd5b8..f29eeff074332 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -236,7 +236,7 @@ LValue CIRGenFunction::emitUnaryOpLValue(const 
UnaryOperator *e) {
 /// If the specified expr is a simple decay from an array to pointer,
 /// return the array subexpression.
 /// FIXME: this could be abstracted into a common AST helper.
-static const Expr *isSimpleArrayDecayOperand(const Expr *e) {
+static const Expr *getSimpleArrayDecayOperand(const Expr *e) {
   // If this isn't just an array->pointer decay, bail out.
   const auto *castExpr = dyn_cast<CastExpr>(e);
   if (!castExpr || castExpr->getCastKind() != CK_ArrayToPointerDecay)
@@ -279,18 +279,12 @@ static QualType getFixedSizeElementType(const ASTContext 
&astContext,
   return eltType;
 }
 
-static mlir::Value
-emitArraySubscriptPtr(CIRGenFunction &cgf, mlir::Location beginLoc,
-                      mlir::Location endLoc, mlir::Value ptr, mlir::Type eltTy,
-                      ArrayRef<mlir::Value> indices, bool inbounds,
-                      bool signedIndices, bool shouldDecay,
-                      const llvm::Twine &name = "arrayidx") {
-  if (indices.size() > 1) {
-    cgf.cgm.errorNYI("emitArraySubscriptPtr: handle multiple indices");
-    return {};
-  }
-
-  const mlir::Value idx = indices.back();
+static mlir::Value emitArraySubscriptPtr(CIRGenFunction &cgf,
+                                         mlir::Location beginLoc,
+                                         mlir::Location endLoc, mlir::Value 
ptr,
+                                         mlir::Type eltTy, mlir::Value idx,
+                                         bool inbounds, bool signedIndices,
+                                         bool shouldDecay) {
   CIRGenModule &cgm = cgf.getCIRGenModule();
   // TODO(cir): LLVM codegen emits in bound gep check here, is there anything
   // that would enhance tracking this later in CIR?
@@ -300,12 +294,11 @@ emitArraySubscriptPtr(CIRGenFunction &cgf, mlir::Location 
beginLoc,
                                           shouldDecay);
 }
 
-static Address emitArraySubscriptPtr(
-    CIRGenFunction &cgf, mlir::Location beginLoc, mlir::Location endLoc,
-    Address addr, ArrayRef<mlir::Value> indices, QualType eltType,
-    bool inbounds, bool signedIndices, mlir::Location loc, bool shouldDecay,
-    QualType *arrayType = nullptr, const Expr *base = nullptr,
-    const llvm::Twine &name = "arrayidx") {
+static Address
+emitArraySubscriptPtr(CIRGenFunction &cgf, mlir::Location beginLoc,
+                      mlir::Location endLoc, Address addr, QualType eltType,
+                      mlir::Value idx, bool inbounds, mlir::Location loc,
+                      bool shouldDecay, QualType *arrayType, const Expr *base) 
{
 
   // Determine the element size of the statically-sized base.  This is
   // the thing that the indices are expressed in terms of.
@@ -317,14 +310,16 @@ static Address emitArraySubscriptPtr(
   // We can use that to compute the best alignment of the element.
   const CharUnits eltSize = cgf.getContext().getTypeSizeInChars(eltType);
   const CharUnits eltAlign =
-      getArrayElementAlign(addr.getAlignment(), indices.back(), eltSize);
+      getArrayElementAlign(addr.getAlignment(), idx, eltSize);
 
   mlir::Value eltPtr;
-  const mlir::IntegerAttr lastIndex = getConstantIndexOrNull(indices.back());
-  if (!lastIndex) {
-    eltPtr = emitArraySubscriptPtr(cgf, beginLoc, endLoc, addr.getPointer(),
-                                   addr.getElementType(), indices, inbounds,
-                                   signedIndices, shouldDecay, name);
+  const mlir::IntegerAttr index = getConstantIndexOrNull(idx);
+  if (!index) {
+    eltPtr = emitArraySubscriptPtr(
+        cgf, beginLoc, endLoc, addr.getPointer(), addr.getElementType(), idx,
+        inbounds, idx.getType().isSignlessIntOrIndex(), shouldDecay);
+  } else {
+    cgf.cgm.errorNYI("emitArraySubscriptExpr: Non Constant Index");
   }
   const mlir::Type elementType = cgf.convertTypeForMem(eltType);
   return Address(eltPtr, elementType, eltAlign);
@@ -335,24 +330,24 @@ CIRGenFunction::emitArraySubscriptExpr(const 
clang::ArraySubscriptExpr *e) {
   if (e->getBase()->getType()->isVectorType() &&
       !isa<ExtVectorElementExpr>(e->getBase())) {
     cgm.errorNYI(e->getSourceRange(), "emitArraySubscriptExpr: VectorType");
-    return {};
+    return LValue::makeAddr(Address::invalid(), e->getType());
   }
 
   if (isa<ExtVectorElementExpr>(e->getBase())) {
     cgm.errorNYI(e->getSourceRange(),
                  "emitArraySubscriptExpr: ExtVectorElementExpr");
-    return {};
+    return LValue::makeAddr(Address::invalid(), e->getType());
   }
 
   if (getContext().getAsVariableArrayType(e->getType())) {
     cgm.errorNYI(e->getSourceRange(),
                  "emitArraySubscriptExpr: VariableArrayType");
-    return {};
+    return LValue::makeAddr(Address::invalid(), e->getType());
   }
 
   if (e->getType()->getAs<ObjCObjectType>()) {
     cgm.errorNYI(e->getSourceRange(), "emitArraySubscriptExpr: 
ObjCObjectType");
-    return {};
+    return LValue::makeAddr(Address::invalid(), e->getType());
   }
 
   // The index must always be an integer, which is not an aggregate.  Emit it
@@ -360,10 +355,7 @@ CIRGenFunction::emitArraySubscriptExpr(const 
clang::ArraySubscriptExpr *e) {
   assert((e->getIdx() == e->getLHS() || e->getIdx() == e->getRHS()) &&
          "index was neither LHS nor RHS");
   const mlir::Value idx = emitScalarExpr(e->getIdx());
-  const QualType idxTy = e->getIdx()->getType();
-  const bool signedIndices = idxTy->isSignedIntegerOrEnumerationType();
-
-  if (const Expr *array = isSimpleArrayDecayOperand(e->getBase())) {
+  if (const Expr *array = getSimpleArrayDecayOperand(e->getBase())) {
     LValue arrayLV;
     if (const auto *ase = dyn_cast<ArraySubscriptExpr>(array))
       arrayLV = emitArraySubscriptExpr(ase);
@@ -374,10 +366,9 @@ CIRGenFunction::emitArraySubscriptExpr(const 
clang::ArraySubscriptExpr *e) {
     QualType arrayType = array->getType();
     const Address addr = emitArraySubscriptPtr(
         *this, cgm.getLoc(array->getBeginLoc()), 
cgm.getLoc(array->getEndLoc()),
-        arrayLV.getAddress(), {idx}, e->getType(),
-        !getLangOpts().isSignedOverflowDefined(), signedIndices,
-        cgm.getLoc(e->getExprLoc()), /*shouldDecay=*/true, &arrayType,
-        e->getBase());
+        arrayLV.getAddress(), e->getType(), idx,
+        !getLangOpts().isSignedOverflowDefined(), cgm.getLoc(e->getExprLoc()),
+        /*shouldDecay=*/true, &arrayType, e->getBase());
 
     return LValue::makeAddr(addr, e->getType());
   }
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 09794a782b0be..67a32ab6caf1c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -159,8 +159,9 @@ class ScalarExprEmitter : public 
StmtVisitor<ScalarExprEmitter, mlir::Value> {
 
   mlir::Value VisitArraySubscriptExpr(ArraySubscriptExpr *e) {
     if (e->getBase()->getType()->isVectorType()) {
-      assert(!cir::MissingFeatures::scalableVectors() &&
-             "NYI: index into scalable vector");
+      assert(!cir::MissingFeatures::scalableVectors());
+      cgf.getCIRGenModule().errorNYI("VisitArraySubscriptExpr: VectorType");
+      return {};
     }
     // Just load the lvalue formed by the subscript expression.
     return emitLoadOfLValue(e);
diff --git a/clang/test/CIR/CodeGen/array.cpp b/clang/test/CIR/CodeGen/array.cpp
index 387c32742b891..c3799b98e2ada 100644
--- a/clang/test/CIR/CodeGen/array.cpp
+++ b/clang/test/CIR/CodeGen/array.cpp
@@ -29,15 +29,24 @@ int f[5] = {1, 2};
 
 void func() {
   int arr[10];
-  // CHECK: %[[ARR:.*]] = cir.alloca !cir.array<!s32i x 10>, 
!cir.ptr<!cir.array<!s32i x 10>>, ["arr"]
+  int e = arr[0];
+  int e2 = arr[1];
 
-  int e = arr[1];
+  // CHECK: %[[ARR:.*]] = cir.alloca !cir.array<!s32i x 10>, 
!cir.ptr<!cir.array<!s32i x 10>>, ["arr"]
   // CHECK: %[[INIT:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["e", init]
-  // CHECK: %[[IDX:.*]] = cir.const #cir.int<1> : !s32i
+  // CHECK: %[[INIT_2:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["e2", init]
+
+  // CHECK: %[[IDX:.*]] = cir.const #cir.int<0> : !s32i
   // CHECK: %[[ARR_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR]] : 
!cir.ptr<!cir.array<!s32i x 10>>), !cir.ptr<!s32i>
   // CHECK: %[[ELE_PTR:.*]] = cir.ptr_stride(%[[ARR_PTR]] : !cir.ptr<!s32i>, 
%[[IDX]] : !s32i), !cir.ptr<!s32i>
   // CHECK: %[[TMP:.*]] = cir.load %[[ELE_PTR]] : !cir.ptr<!s32i>, !s32i
   // CHECK" cir.store %[[TMP]], %[[INIT]] : !s32i, !cir.ptr<!s32i>
+
+  // CHECK: %[[IDX:.*]] = cir.const #cir.int<1> : !s32i
+  // CHECK: %[[ARR_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR]] : 
!cir.ptr<!cir.array<!s32i x 10>>), !cir.ptr<!s32i>
+  // CHECK: %[[ELE_PTR:.*]] = cir.ptr_stride(%[[ARR_PTR]] : !cir.ptr<!s32i>, 
%[[IDX]] : !s32i), !cir.ptr<!s32i>
+  // CHECK: %[[TMP:.*]] = cir.load %[[ELE_PTR]] : !cir.ptr<!s32i>, !s32i
+  // CHECK" cir.store %[[TMP]], %[[INIT_2]] : !s32i, !cir.ptr<!s32i>
 }
 
 void func2() {
diff --git a/clang/test/CIR/Lowering/array.cpp 
b/clang/test/CIR/Lowering/array.cpp
index 8519525db07ec..036a7b4f2d613 100644
--- a/clang/test/CIR/Lowering/array.cpp
+++ b/clang/test/CIR/Lowering/array.cpp
@@ -31,15 +31,21 @@ int f[5] = {1, 2};
 
 void func() {
   int arr[10];
-  int e = arr[1];
+  int e = arr[0];
+  int e2 = arr[1];
 }
 // CHECK: define void @func()
 // CHECK-NEXT: %[[ARR_ALLOCA:.*]] = alloca [10 x i32], i64 1, align 16
 // CHECK-NEXT: %[[INIT:.*]] = alloca i32, i64 1, align 4
+// CHECK-NEXT: %[[INIT_2:.*]] = alloca i32, i64 1, align 4
 // CHECK-NEXT: %[[ARR_PTR:.*]] = getelementptr i32, ptr %[[ARR_ALLOCA]], i32 0
-// CHECK-NEXT: %[[ELE_PTR:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i64 1
+// CHECK-NEXT: %[[ELE_PTR:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i64 0
 // CHECK-NEXT: %[[TMP:.*]] = load i32, ptr %[[ELE_PTR]], align 4
 // CHECK-NEXT: store i32 %[[TMP]], ptr %[[INIT]], align 4
+// CHECK-NEXT: %[[ARR_PTR:.*]] = getelementptr i32, ptr %[[ARR_ALLOCA]], i32 0
+// CHECK-NEXT: %[[ELE_PTR:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i64 1
+// CHECK-NEXT: %[[TMP:.*]] = load i32, ptr %[[ELE_PTR]], align 4
+// CHECK-NEXT: store i32 %[[TMP]], ptr %[[INIT_2]], align 4
 
 void func2() {
   int arr[2] = {5};

>From e069e0e0ad23b528d016b774b31fa9d9aeb366e8 Mon Sep 17 00:00:00 2001
From: AmrDeveloper <am...@programmer.net>
Date: Tue, 8 Apr 2025 21:12:25 +0200
Subject: [PATCH 4/8] Address code review comments

---
 clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 23 +++++++++++------------
 1 file changed, 11 insertions(+), 12 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index f29eeff074332..aa5195c959f30 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -283,8 +283,7 @@ static mlir::Value emitArraySubscriptPtr(CIRGenFunction 
&cgf,
                                          mlir::Location beginLoc,
                                          mlir::Location endLoc, mlir::Value 
ptr,
                                          mlir::Type eltTy, mlir::Value idx,
-                                         bool inbounds, bool signedIndices,
-                                         bool shouldDecay) {
+                                         bool inbounds, bool shouldDecay) {
   CIRGenModule &cgm = cgf.getCIRGenModule();
   // TODO(cir): LLVM codegen emits in bound gep check here, is there anything
   // that would enhance tracking this later in CIR?
@@ -294,11 +293,12 @@ static mlir::Value emitArraySubscriptPtr(CIRGenFunction 
&cgf,
                                           shouldDecay);
 }
 
-static Address
-emitArraySubscriptPtr(CIRGenFunction &cgf, mlir::Location beginLoc,
-                      mlir::Location endLoc, Address addr, QualType eltType,
-                      mlir::Value idx, bool inbounds, mlir::Location loc,
-                      bool shouldDecay, QualType *arrayType, const Expr *base) 
{
+static Address emitArraySubscriptPtr(CIRGenFunction &cgf,
+                                     mlir::Location beginLoc,
+                                     mlir::Location endLoc, Address addr,
+                                     QualType eltType, mlir::Value idx,
+                                     bool inbounds, mlir::Location loc,
+                                     bool shouldDecay) {
 
   // Determine the element size of the statically-sized base.  This is
   // the thing that the indices are expressed in terms of.
@@ -315,9 +315,9 @@ emitArraySubscriptPtr(CIRGenFunction &cgf, mlir::Location 
beginLoc,
   mlir::Value eltPtr;
   const mlir::IntegerAttr index = getConstantIndexOrNull(idx);
   if (!index) {
-    eltPtr = emitArraySubscriptPtr(
-        cgf, beginLoc, endLoc, addr.getPointer(), addr.getElementType(), idx,
-        inbounds, idx.getType().isSignlessIntOrIndex(), shouldDecay);
+    eltPtr = emitArraySubscriptPtr(cgf, beginLoc, endLoc, addr.getPointer(),
+                                   addr.getElementType(), idx, inbounds,
+                                   shouldDecay);
   } else {
     cgf.cgm.errorNYI("emitArraySubscriptExpr: Non Constant Index");
   }
@@ -363,12 +363,11 @@ CIRGenFunction::emitArraySubscriptExpr(const 
clang::ArraySubscriptExpr *e) {
       arrayLV = emitLValue(array);
 
     // Propagate the alignment from the array itself to the result.
-    QualType arrayType = array->getType();
     const Address addr = emitArraySubscriptPtr(
         *this, cgm.getLoc(array->getBeginLoc()), 
cgm.getLoc(array->getEndLoc()),
         arrayLV.getAddress(), e->getType(), idx,
         !getLangOpts().isSignedOverflowDefined(), cgm.getLoc(e->getExprLoc()),
-        /*shouldDecay=*/true, &arrayType, e->getBase());
+        /*shouldDecay=*/true);
 
     return LValue::makeAddr(addr, e->getType());
   }

>From ac0e8c34b52adb683a551c87de25ec29a32a0486 Mon Sep 17 00:00:00 2001
From: AmrDeveloper <am...@programmer.net>
Date: Tue, 8 Apr 2025 21:28:05 +0200
Subject: [PATCH 5/8] Address new comments

---
 clang/include/clang/CIR/MissingFeatures.h |   1 +
 clang/lib/CIR/CodeGen/CIRGenExpr.cpp      |   1 +
 clang/test/CIR/CodeGen/array.cpp          | 398 +++++++++++++++-------
 3 files changed, 286 insertions(+), 114 deletions(-)

diff --git a/clang/include/clang/CIR/MissingFeatures.h 
b/clang/include/clang/CIR/MissingFeatures.h
index 6872f50565721..1e5ee4f95d3e0 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -109,6 +109,7 @@ struct MissingFeatures {
   static bool metaDataNode() { return false; }
   static bool fastMathFlags() { return false; }
   static bool emitCheckedInBoundsGEP() { return false; }
+  static bool preservedAccessIndexRegion() { return false; }
 
   // Missing types
   static bool dataMemberType() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index aa5195c959f30..ae3cb4ec9eb8b 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -315,6 +315,7 @@ static Address emitArraySubscriptPtr(CIRGenFunction &cgf,
   mlir::Value eltPtr;
   const mlir::IntegerAttr index = getConstantIndexOrNull(idx);
   if (!index) {
+    assert(!cir::MissingFeatures::preservedAccessIndexRegion());
     eltPtr = emitArraySubscriptPtr(cgf, beginLoc, endLoc, addr.getPointer(),
                                    addr.getElementType(), idx, inbounds,
                                    shouldDecay);
diff --git a/clang/test/CIR/CodeGen/array.cpp b/clang/test/CIR/CodeGen/array.cpp
index c3799b98e2ada..4533b0e053509 100644
--- a/clang/test/CIR/CodeGen/array.cpp
+++ b/clang/test/CIR/CodeGen/array.cpp
@@ -1,169 +1,339 @@
-// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir 
-emit-cir %s -o - 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value 
-fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value 
-fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value 
-emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
 
 int a[10];
-// CHECK: cir.global external @a = #cir.zero : !cir.array<!s32i x 10>
+// CIR: cir.global external @a = #cir.zero : !cir.array<!s32i x 10>
+
+// LLVM: @a = dso_local global [10 x i32] zeroinitializer
+
+// OGCG: @a = global [10 x i32] zeroinitializer
 
 int aa[10][5];
-// CHECK: cir.global external @aa = #cir.zero : !cir.array<!cir.array<!s32i x 
5> x 10>
+// CIR: cir.global external @aa = #cir.zero : !cir.array<!cir.array<!s32i x 5> 
x 10>
+
+// LLVM: @aa = dso_local global [10 x [5 x i32]] zeroinitializer
+
+// OGCG: @aa = global [10 x [5 x i32]] zeroinitializer
 
 extern int b[10];
-// CHECK: cir.global external @b = #cir.zero : !cir.array<!s32i x 10>
+// CIR: cir.global external @b = #cir.zero : !cir.array<!s32i x 10>
+
+// LLVM: @b = dso_local global [10 x i32] zeroinitializer
 
 extern int bb[10][5];
-// CHECK: cir.global external @bb = #cir.zero : !cir.array<!cir.array<!s32i x 
5> x 10>
+// CIR: cir.global external @bb = #cir.zero : !cir.array<!cir.array<!s32i x 5> 
x 10>
+
+// LLVM: @bb = dso_local global [10 x [5 x i32]] zeroinitializer
 
 int c[10] = {};
-// CHECK: cir.global external @c = #cir.zero : !cir.array<!s32i x 10>
+// CIR: cir.global external @c = #cir.zero : !cir.array<!s32i x 10>
+
+// LLVM: @c = dso_local global [10 x i32] zeroinitializer
+
+// OGCG: @c = global [10 x i32] zeroinitializer
 
 int d[3] = {1, 2, 3};
-// CHECK: cir.global external @d = #cir.const_array<[#cir.int<1> : !s32i, 
#cir.int<2> : !s32i, #cir.int<3> : !s32i]> : !cir.array<!s32i x 3>
+// CIR: cir.global external @d = #cir.const_array<[#cir.int<1> : !s32i, 
#cir.int<2> : !s32i, #cir.int<3> : !s32i]> : !cir.array<!s32i x 3>
+
+// LLVM: @d = dso_local global [3 x i32] [i32 1, i32 2, i32 3]
+
+// OGCG: @d = global [3 x i32] [i32 1, i32 2, i32 3]
 
 int dd[3][2] = {{1, 2}, {3, 4}, {5, 6}};
-// CHECK: cir.global external @dd = 
#cir.const_array<[#cir.const_array<[#cir.int<1> : !s32i, #cir.int<2> : !s32i]> 
: !cir.array<!s32i x 2>, #cir.const_array<[#cir.int<3> : !s32i, #cir.int<4> : 
!s32i]> : !cir.array<!s32i x 2>, #cir.const_array<[#cir.int<5> : !s32i, 
#cir.int<6> : !s32i]> : !cir.array<!s32i x 2>]> : !cir.array<!cir.array<!s32i x 
2> x 3>
+// CIR: cir.global external @dd = 
#cir.const_array<[#cir.const_array<[#cir.int<1> : !s32i, #cir.int<2> : !s32i]> 
: !cir.array<!s32i x 2>, #cir.const_array<[#cir.int<3> : !s32i, #cir.int<4> : 
!s32i]> : !cir.array<!s32i x 2>, #cir.const_array<[#cir.int<5> : !s32i, 
#cir.int<6> : !s32i]> : !cir.array<!s32i x 2>]> : !cir.array<!cir.array<!s32i x 
2> x 3>
+
+// LLVM: @dd = dso_local global [3 x [2 x i32]] [
+// LLVM: [2 x i32] [i32 1, i32 2], [2 x i32]
+// LLVM: [i32 3, i32 4], [2 x i32] [i32 5, i32 6]]
+
+// OGCG: @dd = global [3 x [2 x i32]] [
+// OGCG: [2 x i32] [i32 1, i32 2], [2 x i32]
+// OGCG: [i32 3, i32 4], [2 x i32] [i32 5, i32 6]]
 
 int e[10] = {1, 2};
-// CHECK: cir.global external @e = #cir.const_array<[#cir.int<1> : !s32i, 
#cir.int<2> : !s32i], trailing_zeros> : !cir.array<!s32i x 10>
+// CIR: cir.global external @e = #cir.const_array<[#cir.int<1> : !s32i, 
#cir.int<2> : !s32i], trailing_zeros> : !cir.array<!s32i x 10>
+
+// LLVM: @e = dso_local global [10 x i32] [i32 1, i32 2, i32 0, i32 0, i32 0, 
i32 0, i32 0, i32 0, i32 0, i32 0]
 
 int f[5] = {1, 2};
-// CHECK: cir.global external @f = #cir.const_array<[#cir.int<1> : !s32i, 
#cir.int<2> : !s32i, #cir.int<0> : !s32i, #cir.int<0> : !s32i, #cir.int<0> : 
!s32i]> : !cir.array<!s32i x 5>
+// CIR: cir.global external @f = #cir.const_array<[#cir.int<1> : !s32i, 
#cir.int<2> : !s32i, #cir.int<0> : !s32i, #cir.int<0> : !s32i, #cir.int<0> : 
!s32i]> : !cir.array<!s32i x 5>
+
+// LLVM: @f = dso_local global [5 x i32] [i32 1, i32 2, i32 0, i32 0, i32 0]
+
+// OGCG: @f = global [5 x i32] [i32 1, i32 2, i32 0, i32 0, i32 0]
+
+// OGCG: @[[FUN2_ARR:.*]] = private unnamed_addr constant [2 x i32] [i32 5, 
i32 0], align 4
+// OGCG: @[[FUN3_ARR:.*]] = private unnamed_addr constant [2 x i32] [i32 5, 
i32 6], align 4
+// OGCG: @[[FUN4_ARR:.*]] = private unnamed_addr constant [2 x [1 x i32]] [
+// OGCG: [1 x i32] [i32 5], [1 x i32] [i32 6]], align 4
+// OGCG: @[[FUN5_ARR:.*]] = private unnamed_addr constant [2 x [1 x i32]] [
+// OGCG: [1 x i32] [i32 5], [1 x i32] zeroinitializer], align 4
 
 void func() {
   int arr[10];
   int e = arr[0];
   int e2 = arr[1];
-
-  // CHECK: %[[ARR:.*]] = cir.alloca !cir.array<!s32i x 10>, 
!cir.ptr<!cir.array<!s32i x 10>>, ["arr"]
-  // CHECK: %[[INIT:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["e", init]
-  // CHECK: %[[INIT_2:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["e2", init]
-
-  // CHECK: %[[IDX:.*]] = cir.const #cir.int<0> : !s32i
-  // CHECK: %[[ARR_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR]] : 
!cir.ptr<!cir.array<!s32i x 10>>), !cir.ptr<!s32i>
-  // CHECK: %[[ELE_PTR:.*]] = cir.ptr_stride(%[[ARR_PTR]] : !cir.ptr<!s32i>, 
%[[IDX]] : !s32i), !cir.ptr<!s32i>
-  // CHECK: %[[TMP:.*]] = cir.load %[[ELE_PTR]] : !cir.ptr<!s32i>, !s32i
-  // CHECK" cir.store %[[TMP]], %[[INIT]] : !s32i, !cir.ptr<!s32i>
-
-  // CHECK: %[[IDX:.*]] = cir.const #cir.int<1> : !s32i
-  // CHECK: %[[ARR_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR]] : 
!cir.ptr<!cir.array<!s32i x 10>>), !cir.ptr<!s32i>
-  // CHECK: %[[ELE_PTR:.*]] = cir.ptr_stride(%[[ARR_PTR]] : !cir.ptr<!s32i>, 
%[[IDX]] : !s32i), !cir.ptr<!s32i>
-  // CHECK: %[[TMP:.*]] = cir.load %[[ELE_PTR]] : !cir.ptr<!s32i>, !s32i
-  // CHECK" cir.store %[[TMP]], %[[INIT_2]] : !s32i, !cir.ptr<!s32i>
 }
 
+// CIR: %[[ARR:.*]] = cir.alloca !cir.array<!s32i x 10>, 
!cir.ptr<!cir.array<!s32i x 10>>, ["arr"]
+// CIR: %[[INIT:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["e", init]
+// CIR: %[[INIT_2:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["e2", init]
+// CIR: %[[IDX:.*]] = cir.const #cir.int<0> : !s32i
+// CIR: %[[ARR_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR]] : 
!cir.ptr<!cir.array<!s32i x 10>>), !cir.ptr<!s32i>
+// CIR: %[[ELE_PTR:.*]] = cir.ptr_stride(%[[ARR_PTR]] : !cir.ptr<!s32i>, 
%[[IDX]] : !s32i), !cir.ptr<!s32i>
+// CIR: %[[TMP:.*]] = cir.load %[[ELE_PTR]] : !cir.ptr<!s32i>, !s32i
+// CIR" cir.store %[[TMP]], %[[INIT]] : !s32i, !cir.ptr<!s32i>
+// CIR: %[[IDX:.*]] = cir.const #cir.int<1> : !s32i
+// CIR: %[[ARR_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR]] : 
!cir.ptr<!cir.array<!s32i x 10>>), !cir.ptr<!s32i>
+// CIR: %[[ELE_PTR:.*]] = cir.ptr_stride(%[[ARR_PTR]] : !cir.ptr<!s32i>, 
%[[IDX]] : !s32i), !cir.ptr<!s32i>
+// CIR: %[[TMP:.*]] = cir.load %[[ELE_PTR]] : !cir.ptr<!s32i>, !s32i
+// CIR" cir.store %[[TMP]], %[[INIT_2]] : !s32i, !cir.ptr<!s32i>
+
+// LLVM: define void @func()
+// LLVM-NEXT: %[[ARR_ALLOCA:.*]] = alloca [10 x i32], i64 1, align 16
+// LLVM-NEXT: %[[INIT:.*]] = alloca i32, i64 1, align 4
+// LLVM-NEXT: %[[INIT_2:.*]] = alloca i32, i64 1, align 4
+// LLVM-NEXT: %[[ARR_PTR:.*]] = getelementptr i32, ptr %[[ARR_ALLOCA]], i32 0
+// LLVM-NEXT: %[[ELE_PTR:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i64 0
+// LLVM-NEXT: %[[TMP:.*]] = load i32, ptr %[[ELE_PTR]], align 4
+// LLVM-NEXT: store i32 %[[TMP]], ptr %[[INIT]], align 4
+// LLVM-NEXT: %[[ARR_PTR:.*]] = getelementptr i32, ptr %[[ARR_ALLOCA]], i32 0
+// LLVM-NEXT: %[[ELE_PTR:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i64 1
+// LLVM-NEXT: %[[TMP:.*]] = load i32, ptr %[[ELE_PTR]], align 4
+
+// OGCG: %arr = alloca [10 x i32], align 16
+// OGCG: %e = alloca i32, align 4
+// OGCG: %e2 = alloca i32, align 4
+// OGCG: %arrayidx = getelementptr inbounds [10 x i32], ptr %arr, i64 0, i64 0
+// OGCG: %0 = load i32, ptr %arrayidx, align 16
+// OGCG: store i32 %0, ptr %e, align 4
+// OGCG: %arrayidx1 = getelementptr inbounds [10 x i32], ptr %arr, i64 0, i64 1
+// OGCG: %1 = load i32, ptr %arrayidx1, align 4
+// OGCG: store i32 %1, ptr %e2, align 4
+
 void func2() {
   int arr[2] = {5};
-
-  // CHECK: %[[ARR2:.*]] = cir.alloca !cir.array<!s32i x 2>, 
!cir.ptr<!cir.array<!s32i x 2>>, ["arr", init]
-  // CHECK: %[[ELE_ALLOCA:.*]] = cir.alloca !cir.ptr<!s32i>, 
!cir.ptr<!cir.ptr<!s32i>>, ["arrayinit.temp", init]
-  // CHECK: %[[ARR_2_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR2]] : 
!cir.ptr<!cir.array<!s32i x 2>>), !cir.ptr<!s32i>
-  // CHECK: %[[V1:.*]] = cir.const #cir.int<5> : !s32i
-  // CHECK: cir.store %[[V1]], %[[ARR_2_PTR]] : !s32i, !cir.ptr<!s32i>
-  // CHECK: %[[OFFSET_0:.*]] = cir.const #cir.int<1> : !s64i
-  // CHECK: %[[ELE_PTR:.*]] = cir.ptr_stride(%[[ARR_2_PTR]] : !cir.ptr<!s32i>, 
%[[OFFSET_0]] : !s64i), !cir.ptr<!s32i>
-  // CHECK: cir.store %[[ELE_PTR]], %[[ELE_ALLOCA]] : !cir.ptr<!s32i>, 
!cir.ptr<!cir.ptr<!s32i>>
-  // CHECK: %[[LOAD_1:.*]] = cir.load %[[ELE_ALLOCA]] : 
!cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
-  // CHECK: %[[V2:.*]] = cir.const #cir.int<0> : !s32i
-  // CHECK: cir.store %[[V2]], %[[LOAD_1]] : !s32i, !cir.ptr<!s32i>
-  // CHECK: %[[OFFSET_1:.*]] = cir.const #cir.int<1> : !s64i
-  // CHECK: %[[ELE_1_PTR:.*]] = cir.ptr_stride(%[[LOAD_1]] : !cir.ptr<!s32i>, 
%[[OFFSET_1]] : !s64i), !cir.ptr<!s32i>
-  // CHECK: cir.store %[[ELE_1_PTR]], %[[ELE_ALLOCA]] : !cir.ptr<!s32i>, 
!cir.ptr<!cir.ptr<!s32i>>
 }
 
+// CIR: %[[ARR2:.*]] = cir.alloca !cir.array<!s32i x 2>, 
!cir.ptr<!cir.array<!s32i x 2>>, ["arr", init]
+// CIR: %[[ELE_ALLOCA:.*]] = cir.alloca !cir.ptr<!s32i>, 
!cir.ptr<!cir.ptr<!s32i>>, ["arrayinit.temp", init]
+// CIR: %[[ARR_2_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR2]] : 
!cir.ptr<!cir.array<!s32i x 2>>), !cir.ptr<!s32i>
+// CIR: %[[V1:.*]] = cir.const #cir.int<5> : !s32i
+// CIR: cir.store %[[V1]], %[[ARR_2_PTR]] : !s32i, !cir.ptr<!s32i>
+// CIR: %[[OFFSET_0:.*]] = cir.const #cir.int<1> : !s64i
+// CIR: %[[ELE_PTR:.*]] = cir.ptr_stride(%[[ARR_2_PTR]] : !cir.ptr<!s32i>, 
%[[OFFSET_0]] : !s64i), !cir.ptr<!s32i>
+// CIR: cir.store %[[ELE_PTR]], %[[ELE_ALLOCA]] : !cir.ptr<!s32i>, 
!cir.ptr<!cir.ptr<!s32i>>
+// CIR: %[[LOAD_1:.*]] = cir.load %[[ELE_ALLOCA]] : !cir.ptr<!cir.ptr<!s32i>>, 
!cir.ptr<!s32i>
+// CIR: %[[V2:.*]] = cir.const #cir.int<0> : !s32i
+// CIR: cir.store %[[V2]], %[[LOAD_1]] : !s32i, !cir.ptr<!s32i>
+// CIR: %[[OFFSET_1:.*]] = cir.const #cir.int<1> : !s64i
+// CIR: %[[ELE_1_PTR:.*]] = cir.ptr_stride(%[[LOAD_1]] : !cir.ptr<!s32i>, 
%[[OFFSET_1]] : !s64i), !cir.ptr<!s32i>
+// CIR: cir.store %[[ELE_1_PTR]], %[[ELE_ALLOCA]] : !cir.ptr<!s32i>, 
!cir.ptr<!cir.ptr<!s32i>>
+
+// LLVM: define void @func2()
+// LLVM:  %[[ARR_ALLOCA:.*]] = alloca [2 x i32], i64 1, align 4
+// LLVM:  %[[TMP:.*]] = alloca ptr, i64 1, align 8
+// LLVM:  %[[ARR_PTR:.*]] = getelementptr i32, ptr %[[ARR_ALLOCA]], i32 0
+// LLVM:  store i32 5, ptr %[[ARR_PTR]], align 4
+// LLVM:  %[[ELE_1_PTR:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i64 1
+// LLVM:  store ptr %[[ELE_1_PTR]], ptr %[[TMP]], align 8
+// LLVM:  %[[TMP2:.*]] = load ptr, ptr %[[TMP]], align 8
+// LLVM:  store i32 0, ptr %[[TMP2]], align 4
+// LLVM:  %[[ELE_1:.*]] = getelementptr i32, ptr %[[TMP2]], i64 1
+// LLVM:  store ptr %[[ELE_1]], ptr %[[TMP]], align 8
+
+// OGCG: %arr = alloca [2 x i32], align 4
+// OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %arr, ptr align 4 
@[[FUN2_ARR]], i64 8, i1 false)
+
 void func3() {
   int arr[2] = {5, 6};
-
-  // CHECK: %[[ARR3:.*]] = cir.alloca !cir.array<!s32i x 2>, 
!cir.ptr<!cir.array<!s32i x 2>>, ["arr", init]
-  // CHECK: %[[ARR_3_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR3]] : 
!cir.ptr<!cir.array<!s32i x 2>>), !cir.ptr<!s32i>
-  // CHECK: %[[V0:.*]] = cir.const #cir.int<5> : !s32i
-  // CHECK: cir.store %[[V0]], %[[ARR_3_PTR]] : !s32i, !cir.ptr<!s32i>
-  // CHECK: %[[OFFSET_0:.*]] = cir.const #cir.int<1> : !s64i
-  // CHECK: %[[ELE_1_PTR:.*]] = cir.ptr_stride(%[[ARR_3_PTR]] : 
!cir.ptr<!s32i>, %[[OFFSET_0]] : !s64i), !cir.ptr<!s32i>
-  // CHECK: %[[V1:.*]] = cir.const #cir.int<6> : !s32i
-  // CHECK: cir.store %[[V1]], %[[ELE_1_PTR]] : !s32i, !cir.ptr<!s32i>
 }
 
+// CIR: %[[ARR3:.*]] = cir.alloca !cir.array<!s32i x 2>, 
!cir.ptr<!cir.array<!s32i x 2>>, ["arr", init]
+// CIR: %[[ARR_3_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR3]] : 
!cir.ptr<!cir.array<!s32i x 2>>), !cir.ptr<!s32i>
+// CIR: %[[V0:.*]] = cir.const #cir.int<5> : !s32i
+// CIR: cir.store %[[V0]], %[[ARR_3_PTR]] : !s32i, !cir.ptr<!s32i>
+// CIR: %[[OFFSET_0:.*]] = cir.const #cir.int<1> : !s64i
+// CIR: %[[ELE_1_PTR:.*]] = cir.ptr_stride(%[[ARR_3_PTR]] : !cir.ptr<!s32i>, 
%[[OFFSET_0]] : !s64i), !cir.ptr<!s32i>
+// CIR: %[[V1:.*]] = cir.const #cir.int<6> : !s32i
+// CIR: cir.store %[[V1]], %[[ELE_1_PTR]] : !s32i, !cir.ptr<!s32i>
+
+// LLVM: define void @func3()
+// LLVM:  %[[ARR_ALLOCA:.*]] = alloca [2 x i32], i64 1, align 4
+// LLVM:  %[[ARR_PTR:.*]] = getelementptr i32, ptr %[[ARR_ALLOCA]], i32 0
+// LLVM:  store i32 5, ptr %[[ARR_PTR]], align 4
+// LLVM:  %[[ELE_1_PTR:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i64 1
+// LLVM:  store i32 6, ptr %[[ELE_1_PTR]], align 4
+
+// OGCG: %arr = alloca [2 x i32], align 4
+// OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %arr, ptr align 4 
@[[FUN3_ARR]], i64 8, i1 false)
+
 void func4() {
   int arr[2][1] = {{5}, {6}};
+  int e = arr[1][0];
+}
 
-  // CHECK: %[[ARR:.*]] = cir.alloca !cir.array<!cir.array<!s32i x 1> x 2>, 
!cir.ptr<!cir.array<!cir.array<!s32i x 1> x 2>>, ["arr", init]
-  // CHECK: %[[INIT:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["e", init]
-  // CHECK: %[[ARR_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR]] : 
!cir.ptr<!cir.array<!cir.array<!s32i x 1> x 2>>), !cir.ptr<!cir.array<!s32i x 
1>>
-  // CHECK: %[[ARR_0_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR_PTR]] : 
!cir.ptr<!cir.array<!s32i x 1>>), !cir.ptr<!s32i>
-  // CHECK: %[[V_0_0:.*]] = cir.const #cir.int<5> : !s32i
-  // CHECK: cir.store %[[V_0_0]], %[[ARR_0_PTR]] : !s32i, !cir.ptr<!s32i>
-  // CHECK: %[[OFFSET:.*]] = cir.const #cir.int<1> : !s64i
-  // CHECK: %[[ARR_1:.*]] = cir.ptr_stride(%[[ARR_PTR]] : 
!cir.ptr<!cir.array<!s32i x 1>>, %[[OFFSET]] : !s64i), 
!cir.ptr<!cir.array<!s32i x 1>>
-  // CHECK: %[[ARR_1_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR_1]] : 
!cir.ptr<!cir.array<!s32i x 1>>), !cir.ptr<!s32i>
-  // CHECK: %[[V_1_0:.*]] = cir.const #cir.int<6> : !s32i
-  // CHECK: cir.store %[[V_1_0]], %[[ARR_1_PTR]] : !s32i, !cir.ptr<!s32i>
+// CIR: %[[ARR:.*]] = cir.alloca !cir.array<!cir.array<!s32i x 1> x 2>, 
!cir.ptr<!cir.array<!cir.array<!s32i x 1> x 2>>, ["arr", init]
+// CIR: %[[INIT:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["e", init]
+// CIR: %[[ARR_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR]] : 
!cir.ptr<!cir.array<!cir.array<!s32i x 1> x 2>>), !cir.ptr<!cir.array<!s32i x 
1>>
+// CIR: %[[ARR_0_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR_PTR]] : 
!cir.ptr<!cir.array<!s32i x 1>>), !cir.ptr<!s32i>
+// CIR: %[[V_0_0:.*]] = cir.const #cir.int<5> : !s32i
+// CIR: cir.store %[[V_0_0]], %[[ARR_0_PTR]] : !s32i, !cir.ptr<!s32i>
+// CIR: %[[OFFSET:.*]] = cir.const #cir.int<1> : !s64i
+// CIR: %[[ARR_1:.*]] = cir.ptr_stride(%[[ARR_PTR]] : 
!cir.ptr<!cir.array<!s32i x 1>>, %[[OFFSET]] : !s64i), 
!cir.ptr<!cir.array<!s32i x 1>>
+// CIR: %[[ARR_1_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR_1]] : 
!cir.ptr<!cir.array<!s32i x 1>>), !cir.ptr<!s32i>
+// CIR: %[[V_1_0:.*]] = cir.const #cir.int<6> : !s32i
+// CIR: cir.store %[[V_1_0]], %[[ARR_1_PTR]] : !s32i, !cir.ptr<!s32i>
+// CIR: %[[IDX:.*]] = cir.const #cir.int<0> : !s32i
+// CIR: %[[IDX_1:.*]] = cir.const #cir.int<1> : !s32i
+// CIR: %[[ARR_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR]] : 
!cir.ptr<!cir.array<!cir.array<!s32i x 1> x 2>>), !cir.ptr<!cir.array<!s32i x 
1>>
+// CIR: %[[ARR_1:.*]] = cir.ptr_stride(%[[ARR_PTR]] : 
!cir.ptr<!cir.array<!s32i x 1>>, %[[IDX_1]] : !s32i), !cir.ptr<!cir.array<!s32i 
x 1>>
+// CIR: %[[ARR_1_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR_1]] : 
!cir.ptr<!cir.array<!s32i x 1>>), !cir.ptr<!s32i>
+// CIR: %[[ELE_0:.*]] = cir.ptr_stride(%[[ARR_1_PTR]] : !cir.ptr<!s32i>, 
%[[IDX]] : !s32i), !cir.ptr<!s32i>
+// CIR: %[[TMP:.*]] = cir.load %[[ELE_0]] : !cir.ptr<!s32i>, !s32i
+// CIR: cir.store %[[TMP]], %[[INIT]] : !s32i, !cir.ptr<!s32i>
 
-  int e = arr[1][0];
+// LLVM: define void @func4()
+// LLVM:  %[[ARR_ALLOCA:.*]] = alloca [2 x [1 x i32]], i64 1, align 4
+// LLVM:  %[[INIT:.*]] = alloca i32, i64 1, align 4
+// LLVM:  %[[ARR_PTR:.*]] = getelementptr [1 x i32], ptr %[[ARR_ALLOCA]], i32 0
+// LLVM:  %[[ARR_0_0:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i32 0
+// LLVM:  store i32 5, ptr %[[ARR_0_0]], align 4
+// LLVM:  %[[ARR_1:.*]] = getelementptr [1 x i32], ptr %[[ARR_PTR]], i64 1
+// LLVM:  %[[ARR_1_0:.*]] = getelementptr i32, ptr %[[ARR_1]], i32 0
+// LLVM:  store i32 6, ptr %[[ARR_1_0]], align 4
+// LLVM:  %[[ARR_PTR:.*]] = getelementptr [1 x i32], ptr %[[ARR_ALLOCA]], i32 0
+// LLVM:  %[[ARR_1:.*]] = getelementptr [1 x i32], ptr %[[ARR_PTR]], i64 1
+// LLVM:  %[[ARR_1_0:.*]] = getelementptr i32, ptr %[[ARR_1]], i32 0
+// LLVM:  %[[ELE_PTR:.*]] = getelementptr i32, ptr %[[ARR_1_0]], i64 0
+// LLVM:  %[[TMP:.*]] = load i32, ptr %[[ELE_PTR]], align 4
+// LLVM:  store i32 %[[TMP]], ptr %[[INIT]], align 4
 
-  // CHECK: %[[IDX:.*]] = cir.const #cir.int<0> : !s32i
-  // CHECK: %[[IDX_1:.*]] = cir.const #cir.int<1> : !s32i
-  // CHECK: %[[ARR_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR]] : 
!cir.ptr<!cir.array<!cir.array<!s32i x 1> x 2>>), !cir.ptr<!cir.array<!s32i x 
1>>
-  // CHECK: %[[ARR_1:.*]] = cir.ptr_stride(%[[ARR_PTR]] : 
!cir.ptr<!cir.array<!s32i x 1>>, %[[IDX_1]] : !s32i), !cir.ptr<!cir.array<!s32i 
x 1>>
-  // CHECK: %[[ARR_1_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR_1]] : 
!cir.ptr<!cir.array<!s32i x 1>>), !cir.ptr<!s32i>
-  // CHECK: %[[ELE_0:.*]] = cir.ptr_stride(%[[ARR_1_PTR]] : !cir.ptr<!s32i>, 
%[[IDX]] : !s32i), !cir.ptr<!s32i>
-  // CHECK: %[[TMP:.*]] = cir.load %[[ELE_0]] : !cir.ptr<!s32i>, !s32i
-  // CHECK: cir.store %[[TMP]], %[[INIT]] : !s32i, !cir.ptr<!s32i>
-}
+// OGCG: %arr = alloca [2 x [1 x i32]], align 4
+// OGCG: %e = alloca i32, align 4
+// OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %arr, ptr align 4 
@[[FUN4_ARR]], i64 8, i1 false)
+// OGCG: %arrayidx = getelementptr inbounds [2 x [1 x i32]], ptr %arr, i64 0, 
i64 1
+// OGCG: %arrayidx1 = getelementptr inbounds [1 x i32], ptr %arrayidx, i64 0, 
i64 0
+// OGCG: %0 = load i32, ptr %arrayidx1, align 4
+// OGCG: store i32 %0, ptr %e, align 4
 
 void func5() {
   int arr[2][1] = {{5}};
-
-  // CHECK: %[[ARR:.*]] = cir.alloca !cir.array<!cir.array<!s32i x 1> x 2>, 
!cir.ptr<!cir.array<!cir.array<!s32i x 1> x 2>>, ["arr", init]
-  // CHECK: %[[ARR_PTR:.*]] = cir.alloca !cir.ptr<!cir.array<!s32i x 1>>, 
!cir.ptr<!cir.ptr<!cir.array<!s32i x 1>>>, ["arrayinit.temp", init]
-  // CHECK: %[[ARR_0:.*]] = cir.cast(array_to_ptrdecay, %0 : 
!cir.ptr<!cir.array<!cir.array<!s32i x 1> x 2>>), !cir.ptr<!cir.array<!s32i x 
1>>
-  // CHECK: %[[ARR_0_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR_0]] : 
!cir.ptr<!cir.array<!s32i x 1>>), !cir.ptr<!s32i>
-  // CHECK: %[[V_0_0:.*]] = cir.const #cir.int<5> : !s32i
-  // CHECK: cir.store %[[V_0_0]], %[[ARR_0_PTR]] : !s32i, !cir.ptr<!s32i>
-  // CHECK: %[[OFFSET:.*]] = cir.const #cir.int<1> : !s64i
-  // CHECK: %6 = cir.ptr_stride(%[[ARR_0]] : !cir.ptr<!cir.array<!s32i x 1>>, 
%[[OFFSET]] : !s64i), !cir.ptr<!cir.array<!s32i x 1>>
-  // CHECK: cir.store %6, %[[ARR_PTR]] : !cir.ptr<!cir.array<!s32i x 1>>, 
!cir.ptr<!cir.ptr<!cir.array<!s32i x 1>>>
-  // CHECK: %7 = cir.load %[[ARR_PTR]] : !cir.ptr<!cir.ptr<!cir.array<!s32i x 
1>>>, !cir.ptr<!cir.array<!s32i x 1>>
-  // CHECK: %8 = cir.const #cir.zero : !cir.array<!s32i x 1>
-  // CHECK: cir.store %8, %7 : !cir.array<!s32i x 1>, 
!cir.ptr<!cir.array<!s32i x 1>>
-  // CHECK: %[[OFFSET_1:.*]] = cir.const #cir.int<1> : !s64i
-  // CHECK: %10 = cir.ptr_stride(%7 : !cir.ptr<!cir.array<!s32i x 1>>, 
%[[OFFSET_1]] : !s64i), !cir.ptr<!cir.array<!s32i x 1>>
-  // CHECK: cir.store %10, %[[ARR_PTR]] : !cir.ptr<!cir.array<!s32i x 1>>, 
!cir.ptr<!cir.ptr<!cir.array<!s32i x 1>>>
 }
 
+// CIR: %[[ARR:.*]] = cir.alloca !cir.array<!cir.array<!s32i x 1> x 2>, 
!cir.ptr<!cir.array<!cir.array<!s32i x 1> x 2>>, ["arr", init]
+// CIR: %[[ARR_PTR:.*]] = cir.alloca !cir.ptr<!cir.array<!s32i x 1>>, 
!cir.ptr<!cir.ptr<!cir.array<!s32i x 1>>>, ["arrayinit.temp", init]
+// CIR: %[[ARR_0:.*]] = cir.cast(array_to_ptrdecay, %0 : 
!cir.ptr<!cir.array<!cir.array<!s32i x 1> x 2>>), !cir.ptr<!cir.array<!s32i x 
1>>
+// CIR: %[[ARR_0_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR_0]] : 
!cir.ptr<!cir.array<!s32i x 1>>), !cir.ptr<!s32i>
+// CIR: %[[V_0_0:.*]] = cir.const #cir.int<5> : !s32i
+// CIR: cir.store %[[V_0_0]], %[[ARR_0_PTR]] : !s32i, !cir.ptr<!s32i>
+// CIR: %[[OFFSET:.*]] = cir.const #cir.int<1> : !s64i
+// CIR: %6 = cir.ptr_stride(%[[ARR_0]] : !cir.ptr<!cir.array<!s32i x 1>>, 
%[[OFFSET]] : !s64i), !cir.ptr<!cir.array<!s32i x 1>>
+// CIR: cir.store %6, %[[ARR_PTR]] : !cir.ptr<!cir.array<!s32i x 1>>, 
!cir.ptr<!cir.ptr<!cir.array<!s32i x 1>>>
+// CIR: %7 = cir.load %[[ARR_PTR]] : !cir.ptr<!cir.ptr<!cir.array<!s32i x 
1>>>, !cir.ptr<!cir.array<!s32i x 1>>
+// CIR: %8 = cir.const #cir.zero : !cir.array<!s32i x 1>
+// CIR: cir.store %8, %7 : !cir.array<!s32i x 1>, !cir.ptr<!cir.array<!s32i x 
1>>
+// CIR: %[[OFFSET_1:.*]] = cir.const #cir.int<1> : !s64i
+// CIR: %10 = cir.ptr_stride(%7 : !cir.ptr<!cir.array<!s32i x 1>>, 
%[[OFFSET_1]] : !s64i), !cir.ptr<!cir.array<!s32i x 1>>
+// CIR: cir.store %10, %[[ARR_PTR]] : !cir.ptr<!cir.array<!s32i x 1>>, 
!cir.ptr<!cir.ptr<!cir.array<!s32i x 1>>>
+
+// LLVM: define void @func5()
+// LLVM:  %[[ARR_ALLOCA:.*]] = alloca [2 x [1 x i32]], i64 1, align 4
+// LLVM:  %[[TMP:.*]] = alloca ptr, i64 1, align 8
+// LLVM:  %[[ARR_PTR:.*]] = getelementptr [1 x i32], ptr %[[ARR_ALLOCA]], i32 0
+// LLVM:  %[[ARR_0:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i32 0
+// LLVM:  store i32 5, ptr %[[ARR_0]], align 4
+// LLVM:  %[[ARR_1:.*]] = getelementptr [1 x i32], ptr %[[ARR_PTR]], i64 1
+// LLVM:  store ptr %[[ARR_1]], ptr %[[TMP]], align 8
+// LLVM:  %[[ARR_1_VAL:.*]] = load ptr, ptr %[[TMP]], align 8
+// LLVM:  store [1 x i32] zeroinitializer, ptr %[[ARR_1_VAL]], align 4
+// LLVM:  %[[ARR_1_PTR:.*]] = getelementptr [1 x i32], ptr %[[ARR_1_VAL]], i64 
1
+// LLVM:  store ptr %[[ARR_1_PTR]], ptr %[[TMP]], align 8
+
+// ORGC: %arr = alloca [2 x [1 x i32]], align 4
+// ORGC: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %arr, ptr align 4 
@[[FUN5_ARR]], i64 8, i1 false)
+
 void func6() {
   int x = 4;
   int arr[2] = { x, 5 };
-
-  // CHECK: %[[VAR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["x", init]
-  // CHECK: %[[ARR:.*]] = cir.alloca !cir.array<!s32i x 2>, 
!cir.ptr<!cir.array<!s32i x 2>>, ["arr", init]
-  // CHECK: %[[V:.*]] = cir.const #cir.int<4> : !s32i
-  // CHECK: cir.store %[[V]], %[[VAR]] : !s32i, !cir.ptr<!s32i>
-  // CHECK: %[[ARR_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR]] : 
!cir.ptr<!cir.array<!s32i x 2>>), !cir.ptr<!s32i>
-  // CHECK: %[[TMP:.*]] = cir.load %[[VAR]] : !cir.ptr<!s32i>, !s32i
-  // CHECK: cir.store %[[TMP]], %[[ARR_PTR]] : !s32i, !cir.ptr<!s32i>
-  // CHECK: %[[OFFSET:.*]] = cir.const #cir.int<1> : !s64i
-  // CHECK: %[[ELE_PTR:.*]] = cir.ptr_stride(%[[ARR_PTR]] : !cir.ptr<!s32i>, 
%[[OFFSET]] : !s64i), !cir.ptr<!s32i>
-  // CHECK: %[[V1:.*]] = cir.const #cir.int<5> : !s32i
-  // CHECK: cir.store %[[V1]], %[[ELE_PTR]] : !s32i, !cir.ptr<!s32i>
 }
 
+// CIR: %[[VAR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["x", init]
+// CIR: %[[ARR:.*]] = cir.alloca !cir.array<!s32i x 2>, 
!cir.ptr<!cir.array<!s32i x 2>>, ["arr", init]
+// CIR: %[[V:.*]] = cir.const #cir.int<4> : !s32i
+// CIR: cir.store %[[V]], %[[VAR]] : !s32i, !cir.ptr<!s32i>
+// CIR: %[[ARR_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR]] : 
!cir.ptr<!cir.array<!s32i x 2>>), !cir.ptr<!s32i>
+// CIR: %[[TMP:.*]] = cir.load %[[VAR]] : !cir.ptr<!s32i>, !s32i
+// CIR: cir.store %[[TMP]], %[[ARR_PTR]] : !s32i, !cir.ptr<!s32i>
+// CIR: %[[OFFSET:.*]] = cir.const #cir.int<1> : !s64i
+// CIR: %[[ELE_PTR:.*]] = cir.ptr_stride(%[[ARR_PTR]] : !cir.ptr<!s32i>, 
%[[OFFSET]] : !s64i), !cir.ptr<!s32i>
+// CIR: %[[V1:.*]] = cir.const #cir.int<5> : !s32i
+// CIR: cir.store %[[V1]], %[[ELE_PTR]] : !s32i, !cir.ptr<!s32i>
+
+// LLVM: define void @func6()
+// LLVM:  %[[VAR:.*]] = alloca i32, i64 1, align 4
+// LLVM:  %[[ARR:.*]] = alloca [2 x i32], i64 1, align 4
+// LLVM:  store i32 4, ptr %[[VAR]], align 4
+// LLVM:  %[[ELE_0:.*]] = getelementptr i32, ptr %[[ARR]], i32 0
+// LLVM:  %[[TMP:.*]] = load i32, ptr %[[VAR]], align 4
+// LLVM:  store i32 %[[TMP]], ptr %[[ELE_0]], align 4
+// LLVM:  %[[ELE_1:.*]] = getelementptr i32, ptr %[[ELE_0]], i64 1
+// LLVM:  store i32 5, ptr %[[ELE_1]], align 4
+
+// OGCG:  %x = alloca i32, align 4
+// OGCG:  %arr = alloca [2 x i32], align 4
+// OGCG:  store i32 4, ptr %x, align 4
+// OGCG:  %0 = load i32, ptr %x, align 4
+// OGCG:  store i32 %0, ptr %arr, align 4
+// OGCG:  %arrayinit.element = getelementptr inbounds i32, ptr %arr, i64 1
+// OGCG:  store i32 5, ptr %arrayinit.element, align 4
+
 void func7() {
   int* arr[1] = {};
-
-  // CHECK: %[[ARR:.*]] = cir.alloca !cir.array<!cir.ptr<!s32i> x 1>, 
!cir.ptr<!cir.array<!cir.ptr<!s32i> x 1>>, ["arr", init]
-  // CHECK: %[[ARR_TMP:.*]] = cir.alloca !cir.ptr<!cir.ptr<!s32i>>, 
!cir.ptr<!cir.ptr<!cir.ptr<!s32i>>>, ["arrayinit.temp", init]
-  // CHECK: %[[ARR_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR]] : 
!cir.ptr<!cir.array<!cir.ptr<!s32i> x 1>>), !cir.ptr<!cir.ptr<!s32i>>
-  // CHECK: cir.store %[[ARR_PTR]], %[[ARR_TMP]] : !cir.ptr<!cir.ptr<!s32i>>, 
!cir.ptr<!cir.ptr<!cir.ptr<!s32i>>>
-  // CHECK: %[[TMP:.*]] = cir.load %[[ARR_TMP]] : 
!cir.ptr<!cir.ptr<!cir.ptr<!s32i>>>, !cir.ptr<!cir.ptr<!s32i>>
-  // CHECK: %[[NULL_PTR:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!s32i>
-  // CHECK: cir.store %[[NULL_PTR]], %[[TMP]] : !cir.ptr<!s32i>, 
!cir.ptr<!cir.ptr<!s32i>>
-  // CHECK: %[[OFFSET:.*]] = cir.const #cir.int<1> : !s64i
-  // CHECK: %[[ELE_PTR:.*]] = cir.ptr_stride(%[[TMP]] : 
!cir.ptr<!cir.ptr<!s32i>>, %[[OFFSET]] : !s64i), !cir.ptr<!cir.ptr<!s32i>>
-  // CHECK: cir.store %[[ELE_PTR]], %[[ARR_TMP]] : !cir.ptr<!cir.ptr<!s32i>>, 
!cir.ptr<!cir.ptr<!cir.ptr<!s32i>>>
 }
 
+// CIR: %[[ARR:.*]] = cir.alloca !cir.array<!cir.ptr<!s32i> x 1>, 
!cir.ptr<!cir.array<!cir.ptr<!s32i> x 1>>, ["arr", init]
+// CIR: %[[ARR_TMP:.*]] = cir.alloca !cir.ptr<!cir.ptr<!s32i>>, 
!cir.ptr<!cir.ptr<!cir.ptr<!s32i>>>, ["arrayinit.temp", init]
+// CIR: %[[ARR_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR]] : 
!cir.ptr<!cir.array<!cir.ptr<!s32i> x 1>>), !cir.ptr<!cir.ptr<!s32i>>
+// CIR: cir.store %[[ARR_PTR]], %[[ARR_TMP]] : !cir.ptr<!cir.ptr<!s32i>>, 
!cir.ptr<!cir.ptr<!cir.ptr<!s32i>>>
+// CIR: %[[TMP:.*]] = cir.load %[[ARR_TMP]] : 
!cir.ptr<!cir.ptr<!cir.ptr<!s32i>>>, !cir.ptr<!cir.ptr<!s32i>>
+// CIR: %[[NULL_PTR:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!s32i>
+// CIR: cir.store %[[NULL_PTR]], %[[TMP]] : !cir.ptr<!s32i>, 
!cir.ptr<!cir.ptr<!s32i>>
+// CIR: %[[OFFSET:.*]] = cir.const #cir.int<1> : !s64i
+// CIR: %[[ELE_PTR:.*]] = cir.ptr_stride(%[[TMP]] : !cir.ptr<!cir.ptr<!s32i>>, 
%[[OFFSET]] : !s64i), !cir.ptr<!cir.ptr<!s32i>>
+// CIR: cir.store %[[ELE_PTR]], %[[ARR_TMP]] : !cir.ptr<!cir.ptr<!s32i>>, 
!cir.ptr<!cir.ptr<!cir.ptr<!s32i>>>
+
+// LLVM: define void @func7()
+// LLVM:  %[[ARR:.*]] = alloca [1 x ptr], i64 1, align 8
+// LLVM:  %[[ALLOCA:.*]] = alloca ptr, i64 1, align 8
+// LLVM:  %[[ELE_PTR:.*]] = getelementptr ptr, ptr %[[ARR]], i32 0
+// LLVM:  store ptr %[[ELE_PTR]], ptr %[[ALLOCA]], align 8
+// LLVM:  %[[TMP:.*]] = load ptr, ptr %[[ALLOCA]], align 8
+// LLVM:  store ptr null, ptr %[[TMP]], align 8
+// LLVM:  %[[ELE:.*]] = getelementptr ptr, ptr %[[TMP]], i64 1
+// LLVM:  store ptr %[[ELE]], ptr %[[ALLOCA]], align 8
+
+// OGCG: %[[ARR:.*]] = alloca [1 x ptr], align 8
+// OGCG: call void @llvm.memset.p0.i64(ptr align 8 %[[ARR]], i8 0, i64 8, i1 
false)
+
 void func8(int p[10]) {}
-// CHECK: cir.func @func8(%arg0: !cir.ptr<!s32i>
-// CHECK: cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["p", init]
+// CIR: cir.func @func8(%arg0: !cir.ptr<!s32i>
+// CIR: cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["p", init]
+
+// LLVM: define void @func8(ptr {{%.*}})
+// LLVM-NEXT: alloca ptr, i64 1, align 8
+
+// OGCG: alloca ptr, align 8
 
 void func9(int pp[10][5]) {}
-// CHECK: cir.func @func9(%arg0: !cir.ptr<!cir.array<!s32i x 5>>
-// CHECK: cir.alloca !cir.ptr<!cir.array<!s32i x 5>>, 
!cir.ptr<!cir.ptr<!cir.array<!s32i x 5>>>
+// CIR: cir.func @func9(%arg0: !cir.ptr<!cir.array<!s32i x 5>>
+// CIR: cir.alloca !cir.ptr<!cir.array<!s32i x 5>>, 
!cir.ptr<!cir.ptr<!cir.array<!s32i x 5>>>
+
+// LLVM: define void @func9(ptr {{%.*}})
+// LLVM-NEXT: alloca ptr, i64 1, align 8
+
+// OGCG: alloca ptr, align 8

>From 9d07a291caadfae7ca99137bb8a3d3c8470fba27 Mon Sep 17 00:00:00 2001
From: AmrDeveloper <am...@programmer.net>
Date: Tue, 8 Apr 2025 23:06:29 +0200
Subject: [PATCH 6/8] Remove inbounds for now

---
 clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 14 +++++---------
 1 file changed, 5 insertions(+), 9 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index b777d3c04636b..5dd11cfd62c57 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -441,12 +441,11 @@ static mlir::Value emitArraySubscriptPtr(CIRGenFunction 
&cgf,
                                          mlir::Location beginLoc,
                                          mlir::Location endLoc, mlir::Value 
ptr,
                                          mlir::Type eltTy, mlir::Value idx,
-                                         bool inbounds, bool shouldDecay) {
+                                         bool shouldDecay) {
   CIRGenModule &cgm = cgf.getCIRGenModule();
   // TODO(cir): LLVM codegen emits in bound gep check here, is there anything
   // that would enhance tracking this later in CIR?
-  if (inbounds)
-    assert(!cir::MissingFeatures::emitCheckedInBoundsGEP() && "NYI");
+  assert(!cir::MissingFeatures::emitCheckedInBoundsGEP());
   return cgm.getBuilder().getArrayElement(beginLoc, endLoc, ptr, eltTy, idx,
                                           shouldDecay);
 }
@@ -455,8 +454,7 @@ static Address emitArraySubscriptPtr(CIRGenFunction &cgf,
                                      mlir::Location beginLoc,
                                      mlir::Location endLoc, Address addr,
                                      QualType eltType, mlir::Value idx,
-                                     bool inbounds, mlir::Location loc,
-                                     bool shouldDecay) {
+                                     mlir::Location loc, bool shouldDecay) {
 
   // Determine the element size of the statically-sized base.  This is
   // the thing that the indices are expressed in terms of.
@@ -475,8 +473,7 @@ static Address emitArraySubscriptPtr(CIRGenFunction &cgf,
   if (!index) {
     assert(!cir::MissingFeatures::preservedAccessIndexRegion());
     eltPtr = emitArraySubscriptPtr(cgf, beginLoc, endLoc, addr.getPointer(),
-                                   addr.getElementType(), idx, inbounds,
-                                   shouldDecay);
+                                   addr.getElementType(), idx, shouldDecay);
   } else {
     cgf.cgm.errorNYI("emitArraySubscriptExpr: Non Constant Index");
   }
@@ -524,8 +521,7 @@ CIRGenFunction::emitArraySubscriptExpr(const 
clang::ArraySubscriptExpr *e) {
     // Propagate the alignment from the array itself to the result.
     const Address addr = emitArraySubscriptPtr(
         *this, cgm.getLoc(array->getBeginLoc()), 
cgm.getLoc(array->getEndLoc()),
-        arrayLV.getAddress(), e->getType(), idx,
-        !getLangOpts().isSignedOverflowDefined(), cgm.getLoc(e->getExprLoc()),
+        arrayLV.getAddress(), e->getType(), idx, cgm.getLoc(e->getExprLoc()),
         /*shouldDecay=*/true);
 
     return LValue::makeAddr(addr, e->getType());

>From abd9621e3446cf361480afe47350f35211cb6eb4 Mon Sep 17 00:00:00 2001
From: AmrDeveloper <am...@programmer.net>
Date: Thu, 10 Apr 2025 18:49:50 +0200
Subject: [PATCH 7/8] Remove unneeded check and add tests for variable index

---
 clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 21 ++++++--------
 clang/test/CIR/CodeGen/array.cpp     | 41 ++++++++++++++++++++++++----
 2 files changed, 43 insertions(+), 19 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index 5dd11cfd62c57..bbf3f562f71b5 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -408,10 +408,10 @@ static const Expr *getSimpleArrayDecayOperand(const Expr 
*e) {
   return subExpr;
 }
 
-static mlir::IntegerAttr getConstantIndexOrNull(mlir::Value idx) {
+static cir::IntAttr getConstantIndexOrNull(mlir::Value idx) {
   // TODO(cir): should we consider using MLIRs IndexType instead of 
IntegerAttr?
   if (auto constantOp = dyn_cast<cir::ConstantOp>(idx.getDefiningOp()))
-    return mlir::dyn_cast<mlir::IntegerAttr>(constantOp.getValue());
+    return mlir::dyn_cast<cir::IntAttr>(constantOp.getValue());
   return {};
 }
 
@@ -419,7 +419,7 @@ static CharUnits getArrayElementAlign(CharUnits arrayAlign, 
mlir::Value idx,
                                       CharUnits eltSize) {
   // If we have a constant index, we can use the exact offset of the
   // element we're accessing.
-  const mlir::IntegerAttr constantIdx = getConstantIndexOrNull(idx);
+  const cir::IntAttr constantIdx = getConstantIndexOrNull(idx);
   if (constantIdx) {
     const CharUnits offset = constantIdx.getValue().getZExtValue() * eltSize;
     return arrayAlign.alignmentAtOffset(offset);
@@ -468,17 +468,12 @@ static Address emitArraySubscriptPtr(CIRGenFunction &cgf,
   const CharUnits eltAlign =
       getArrayElementAlign(addr.getAlignment(), idx, eltSize);
 
-  mlir::Value eltPtr;
-  const mlir::IntegerAttr index = getConstantIndexOrNull(idx);
-  if (!index) {
     assert(!cir::MissingFeatures::preservedAccessIndexRegion());
-    eltPtr = emitArraySubscriptPtr(cgf, beginLoc, endLoc, addr.getPointer(),
-                                   addr.getElementType(), idx, shouldDecay);
-  } else {
-    cgf.cgm.errorNYI("emitArraySubscriptExpr: Non Constant Index");
-  }
-  const mlir::Type elementType = cgf.convertTypeForMem(eltType);
-  return Address(eltPtr, elementType, eltAlign);
+    const mlir::Value eltPtr =
+        emitArraySubscriptPtr(cgf, beginLoc, endLoc, addr.getPointer(),
+                              addr.getElementType(), idx, shouldDecay);
+    const mlir::Type elementType = cgf.convertTypeForMem(eltType);
+    return Address(eltPtr, elementType, eltAlign);
 }
 
 LValue
diff --git a/clang/test/CIR/CodeGen/array.cpp b/clang/test/CIR/CodeGen/array.cpp
index 4533b0e053509..431164c797f76 100644
--- a/clang/test/CIR/CodeGen/array.cpp
+++ b/clang/test/CIR/CodeGen/array.cpp
@@ -151,26 +151,55 @@ void func2() {
 
 void func3() {
   int arr[2] = {5, 6};
+
+  int idx = 1;
+  int e = arr[idx];
 }
 
-// CIR: %[[ARR3:.*]] = cir.alloca !cir.array<!s32i x 2>, 
!cir.ptr<!cir.array<!s32i x 2>>, ["arr", init]
-// CIR: %[[ARR_3_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR3]] : 
!cir.ptr<!cir.array<!s32i x 2>>), !cir.ptr<!s32i>
+// CIR: %[[ARR:.*]] = cir.alloca !cir.array<!s32i x 2>, 
!cir.ptr<!cir.array<!s32i x 2>>, ["arr", init]
+// CIR: %[[IDX:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["idx", init]
+// CIR: %[[INIT:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["e", init]
+// CIR: %[[ARR_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR]] : 
!cir.ptr<!cir.array<!s32i x 2>>), !cir.ptr<!s32i>
 // CIR: %[[V0:.*]] = cir.const #cir.int<5> : !s32i
-// CIR: cir.store %[[V0]], %[[ARR_3_PTR]] : !s32i, !cir.ptr<!s32i>
+// CIR: cir.store %[[V0]], %[[ARR_PTR]] : !s32i, !cir.ptr<!s32i>
 // CIR: %[[OFFSET_0:.*]] = cir.const #cir.int<1> : !s64i
-// CIR: %[[ELE_1_PTR:.*]] = cir.ptr_stride(%[[ARR_3_PTR]] : !cir.ptr<!s32i>, 
%[[OFFSET_0]] : !s64i), !cir.ptr<!s32i>
+// CIR: %[[ELE_1_PTR:.*]] = cir.ptr_stride(%[[ARR_PTR]] : !cir.ptr<!s32i>, 
%[[OFFSET_0]] : !s64i), !cir.ptr<!s32i>
 // CIR: %[[V1:.*]] = cir.const #cir.int<6> : !s32i
 // CIR: cir.store %[[V1]], %[[ELE_1_PTR]] : !s32i, !cir.ptr<!s32i>
+// CIR: %[[IDX_V:.*]] = cir.const #cir.int<1> : !s32i
+// CIR: cir.store %[[IDX_V]], %[[IDX]] : !s32i, !cir.ptr<!s32i>
+// CIR: %[[TMP_IDX:.*]] = cir.load %[[IDX]] : !cir.ptr<!s32i>, !s32i
+// CIR: %[[ARR_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR]] : 
!cir.ptr<!cir.array<!s32i x 2>>), !cir.ptr<!s32i>
+// CIR: %[[ELE_PTR:.*]] = cir.ptr_stride(%[[ARR_PTR]] : !cir.ptr<!s32i>, 
%[[TMP_IDX]] : !s32i), !cir.ptr<!s32i>
+// CIR: %[[ELE_TMP:.*]] = cir.load %[[ELE_PTR]] : !cir.ptr<!s32i>, !s32i
+// CIR: cir.store %[[ELE_TMP]], %[[INIT]] : !s32i, !cir.ptr<!s32i>
 
 // LLVM: define void @func3()
 // LLVM:  %[[ARR_ALLOCA:.*]] = alloca [2 x i32], i64 1, align 4
+// LLVM:  %[[IDX:.*]] = alloca i32, i64 1, align 4
+// LLVM:  %[[INIT:.*]] = alloca i32, i64 1, align 4
 // LLVM:  %[[ARR_PTR:.*]] = getelementptr i32, ptr %[[ARR_ALLOCA]], i32 0
 // LLVM:  store i32 5, ptr %[[ARR_PTR]], align 4
 // LLVM:  %[[ELE_1_PTR:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i64 1
 // LLVM:  store i32 6, ptr %[[ELE_1_PTR]], align 4
+// LLVM:  store i32 1, ptr %[[IDX]], align 4
+// LLVM:  %[[TMP1:.*]] = load i32, ptr %[[IDX]], align 4
+// LLVM:  %[[ARR_PTR:.*]] = getelementptr i32, ptr %[[ARR_ALLOCA]], i32 0
+// LLVM:  %[[IDX_I64:.*]] = sext i32 %[[TMP1]] to i64
+// LLVM:  %[[ELE:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i64 %[[IDX_I64]]
+// LLVM:  %[[TMP2:.*]] = load i32, ptr %[[ELE]], align 4
+// LLVM:  store i32 %[[TMP2]], ptr %[[INIT]], align 4
 
-// OGCG: %arr = alloca [2 x i32], align 4
-// OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %arr, ptr align 4 
@[[FUN3_ARR]], i64 8, i1 false)
+// OGCG:  %arr = alloca [2 x i32], align 4
+// OGCG:  %idx = alloca i32, align 4
+// OGCG:  %e = alloca i32, align 4
+// OGCG:  call void @llvm.memcpy.p0.p0.i64(ptr align 4 %arr, ptr align 4 
@[[FUN3_ARR]], i64 8, i1 false)
+// OGCG:  store i32 1, ptr %idx, align 4
+// OGCG:  %0 = load i32, ptr %idx, align 4
+// OGCG:  %idxprom = sext i32 %0 to i64
+// OGCG:  %arrayidx = getelementptr inbounds [2 x i32], ptr %arr, i64 0, i64 
%idxprom
+// OGCG:  %1 = load i32, ptr %arrayidx, align 4
+// OGCG:  store i32 %1, ptr %e, align 4
 
 void func4() {
   int arr[2][1] = {{5}, {6}};

>From c2f5f0f912ae002cb5c4a96c04b69839ebc9db7e Mon Sep 17 00:00:00 2001
From: AmrDeveloper <am...@programmer.net>
Date: Thu, 10 Apr 2025 19:33:27 +0200
Subject: [PATCH 8/8] Merge with the master

---
 clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 20 ++++++++++----------
 clang/lib/CIR/CodeGen/CIRGenValue.h  |  3 +++
 2 files changed, 13 insertions(+), 10 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index 6b9068a751374..48dbc49302850 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -471,12 +471,12 @@ static Address emitArraySubscriptPtr(CIRGenFunction &cgf,
   const CharUnits eltAlign =
       getArrayElementAlign(addr.getAlignment(), idx, eltSize);
 
-    assert(!cir::MissingFeatures::preservedAccessIndexRegion());
-    const mlir::Value eltPtr =
-        emitArraySubscriptPtr(cgf, beginLoc, endLoc, addr.getPointer(),
+  assert(!cir::MissingFeatures::preservedAccessIndexRegion());
+  const mlir::Value eltPtr =
+      emitArraySubscriptPtr(cgf, beginLoc, endLoc, addr.getPointer(),
                               addr.getElementType(), idx, shouldDecay);
-    const mlir::Type elementType = cgf.convertTypeForMem(eltType);
-    return Address(eltPtr, elementType, eltAlign);
+  const mlir::Type elementType = cgf.convertTypeForMem(eltType);
+  return Address(eltPtr, elementType, eltAlign);
 }
 
 LValue
@@ -484,24 +484,24 @@ CIRGenFunction::emitArraySubscriptExpr(const 
clang::ArraySubscriptExpr *e) {
   if (e->getBase()->getType()->isVectorType() &&
       !isa<ExtVectorElementExpr>(e->getBase())) {
     cgm.errorNYI(e->getSourceRange(), "emitArraySubscriptExpr: VectorType");
-    return LValue::makeAddr(Address::invalid(), e->getType());
+    return LValue::makeAddr(Address::invalid(), e->getType(), 
LValueBaseInfo());
   }
 
   if (isa<ExtVectorElementExpr>(e->getBase())) {
     cgm.errorNYI(e->getSourceRange(),
                  "emitArraySubscriptExpr: ExtVectorElementExpr");
-    return LValue::makeAddr(Address::invalid(), e->getType());
+    return LValue::makeAddr(Address::invalid(), e->getType(), 
LValueBaseInfo());
   }
 
   if (getContext().getAsVariableArrayType(e->getType())) {
     cgm.errorNYI(e->getSourceRange(),
                  "emitArraySubscriptExpr: VariableArrayType");
-    return LValue::makeAddr(Address::invalid(), e->getType());
+    return LValue::makeAddr(Address::invalid(), e->getType(), 
LValueBaseInfo());
   }
 
   if (e->getType()->getAs<ObjCObjectType>()) {
     cgm.errorNYI(e->getSourceRange(), "emitArraySubscriptExpr: 
ObjCObjectType");
-    return LValue::makeAddr(Address::invalid(), e->getType());
+    return LValue::makeAddr(Address::invalid(), e->getType(), 
LValueBaseInfo());
   }
 
   // The index must always be an integer, which is not an aggregate.  Emit it
@@ -522,7 +522,7 @@ CIRGenFunction::emitArraySubscriptExpr(const 
clang::ArraySubscriptExpr *e) {
         arrayLV.getAddress(), e->getType(), idx, cgm.getLoc(e->getExprLoc()),
         /*shouldDecay=*/true);
 
-    return LValue::makeAddr(addr, e->getType());
+    return LValue::makeAddr(addr, e->getType(), LValueBaseInfo());
   }
 
   // The base must be a pointer; emit it with an estimate of its alignment.
diff --git a/clang/lib/CIR/CodeGen/CIRGenValue.h 
b/clang/lib/CIR/CodeGen/CIRGenValue.h
index 1b702daae4b4c..da4e92d817cd6 100644
--- a/clang/lib/CIR/CodeGen/CIRGenValue.h
+++ b/clang/lib/CIR/CodeGen/CIRGenValue.h
@@ -23,6 +23,9 @@
 
 #include "mlir/IR/Value.h"
 
+
+#include "clang/CIR/MissingFeatures.h"
+
 namespace clang::CIRGen {
 
 /// This trivial value class is used to represent the result of an

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to