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

>From 4dc1e77299c71b8f01fb73f7fba5f14e0fbe3edd Mon Sep 17 00:00:00 2001
From: AmrDeveloper <am...@programmer.net>
Date: Fri, 21 Mar 2025 21:07:11 +0100
Subject: [PATCH 1/7] [CIR] [Upstream local initialization for ArrayType

---
 .../CIR/Dialect/Builder/CIRBaseBuilder.h      |  35 +++
 .../include/clang/CIR/Dialect/IR/CIRDialect.h |  25 ++
 clang/include/clang/CIR/Dialect/IR/CIROps.td  |  44 +++
 clang/include/clang/CIR/LoweringHelpers.h     |  40 +++
 clang/lib/CIR/CodeGen/Address.h               |  10 +
 clang/lib/CIR/CodeGen/CIRGenBuilder.h         |   4 +
 clang/lib/CIR/CodeGen/CIRGenDecl.cpp          |   2 +-
 clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp | 277 ++++++++++++++++++
 clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp  |  23 ++
 clang/lib/CIR/CodeGen/CIRGenFunction.cpp      |  46 +++
 clang/lib/CIR/CodeGen/CIRGenFunction.h        |  12 +-
 clang/lib/CIR/CodeGen/CIRGenModule.cpp        |  12 +
 clang/lib/CIR/CodeGen/CIRGenModule.h          |   5 +
 clang/lib/CIR/CodeGen/CIRGenTypeCache.h       |  13 +
 clang/lib/CIR/CodeGen/CIRGenTypes.cpp         |  24 ++
 clang/lib/CIR/CodeGen/CIRGenTypes.h           |   4 +
 clang/lib/CIR/CodeGen/CIRGenValue.h           |  44 ++-
 clang/lib/CIR/CodeGen/CMakeLists.txt          |   1 +
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp       |  42 ++-
 clang/lib/CIR/Lowering/CMakeLists.txt         |   1 +
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 109 +++++++
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.h   |  15 +
 clang/lib/CIR/Lowering/LoweringHelpers.cpp    | 150 ++++++++++
 clang/test/CIR/CodeGen/array.cpp              |  97 +++++-
 clang/test/CIR/Lowering/array.cpp             |  77 ++++-
 25 files changed, 1087 insertions(+), 25 deletions(-)
 create mode 100644 clang/include/clang/CIR/LoweringHelpers.h
 create mode 100644 clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
 create mode 100644 clang/lib/CIR/Lowering/LoweringHelpers.cpp

diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h 
b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index c6aea10d46b63..4c7e6ec061d46 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -32,6 +32,11 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
     return create<cir::ConstantOp>(loc, attr.getType(), attr);
   }
 
+  // Creates constant null value for integral type ty.
+  cir::ConstantOp getNullValue(mlir::Type ty, mlir::Location loc) {
+    return create<cir::ConstantOp>(loc, ty, getZeroInitAttr(ty));
+  }
+
   cir::ConstantOp getBool(bool state, mlir::Location loc) {
     return create<cir::ConstantOp>(loc, getBoolTy(), getCIRBoolAttr(state));
   }
@@ -68,6 +73,36 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
         getContext(), mlir::cast<cir::PointerType>(type), valueAttr);
   }
 
+  mlir::TypedAttr getConstNullPtrAttr(mlir::Type t) {
+    assert(mlir::isa<cir::PointerType>(t) && "expected cir.ptr");
+    return getConstPtrAttr(t, 0);
+  }
+
+  mlir::TypedAttr getZeroAttr(mlir::Type t) {
+    return cir::ZeroAttr::get(getContext(), t);
+  }
+
+  mlir::TypedAttr getZeroInitAttr(mlir::Type ty) {
+    if (mlir::isa<cir::IntType>(ty))
+      return cir::IntAttr::get(ty, 0);
+    if (auto fltType = mlir::dyn_cast<cir::SingleType>(ty))
+      return cir::FPAttr::getZero(fltType);
+    if (auto fltType = mlir::dyn_cast<cir::DoubleType>(ty))
+      return cir::FPAttr::getZero(fltType);
+    if (auto fltType = mlir::dyn_cast<cir::FP16Type>(ty))
+      return cir::FPAttr::getZero(fltType);
+    if (auto fltType = mlir::dyn_cast<cir::BF16Type>(ty))
+      return cir::FPAttr::getZero(fltType);
+    if (auto arrTy = mlir::dyn_cast<cir::ArrayType>(ty))
+      return getZeroAttr(arrTy);
+    if (auto ptrTy = mlir::dyn_cast<cir::PointerType>(ty))
+      return getConstNullPtrAttr(ptrTy);
+    if (mlir::isa<cir::BoolType>(ty)) {
+      return getCIRBoolAttr(false);
+    }
+    llvm_unreachable("Zero initializer for given type is NYI");
+  }
+
   mlir::Value createAlloca(mlir::Location loc, cir::PointerType addrType,
                            mlir::Type type, llvm::StringRef name,
                            mlir::IntegerAttr alignment) {
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.h 
b/clang/include/clang/CIR/Dialect/IR/CIRDialect.h
index da3b41371b9ab..ba7bbedf4714e 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.h
+++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.h
@@ -32,6 +32,31 @@
 #include "clang/CIR/Interfaces/CIRLoopOpInterface.h"
 #include "clang/CIR/Interfaces/CIROpInterfaces.h"
 
+namespace mlir {
+namespace OpTrait {
+
+namespace impl {
+// These functions are out-of-line implementations of the methods in the
+// corresponding trait classes.  This avoids them being template
+// instantiated/duplicated.
+LogicalResult verifySameFirstOperandAndResultType(Operation *op);
+} // namespace impl
+
+/// This class provides verification for ops that are known to have the same
+/// first operand and result type.
+///
+template <typename ConcreteType>
+class SameFirstOperandAndResultType
+    : public TraitBase<ConcreteType, SameFirstOperandAndResultType> {
+public:
+  static llvm::LogicalResult verifyTrait(Operation *op) {
+    return impl::verifySameFirstOperandAndResultType(op);
+  }
+};
+
+} // namespace OpTrait
+} // namespace mlir
+
 // TableGen'erated files for MLIR dialects require that a macro be defined when
 // they are included.  GET_OP_CLASSES tells the file to define the classes for
 // the operations of that dialect.
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index d7d63e040a2ba..7784c8a51fdf3 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -79,6 +79,13 @@ class LLVMLoweringInfo {
 class CIR_Op<string mnemonic, list<Trait> traits = []> :
     Op<CIR_Dialect, mnemonic, traits>, LLVMLoweringInfo;
 
+//===----------------------------------------------------------------------===//
+// CIR Op Traits
+//===----------------------------------------------------------------------===//
+
+def SameFirstOperandAndResultType :
+  NativeOpTrait<"SameFirstOperandAndResultType">;
+
 
//===----------------------------------------------------------------------===//
 // CastOp
 
//===----------------------------------------------------------------------===//
@@ -229,6 +236,43 @@ def CastOp : CIR_Op<"cast",
   let hasFolder = 1;
 }
 
+
+//===----------------------------------------------------------------------===//
+// PtrStrideOp
+//===----------------------------------------------------------------------===//
+
+def PtrStrideOp : CIR_Op<"ptr_stride",
+                         [Pure, SameFirstOperandAndResultType]> {
+  let summary = "Pointer access with stride";
+  let description = [{
+    Given a base pointer as first operand, provides a new pointer after 
applying
+    a stride (second operand).
+
+    ```mlir
+    %3 = cir.const 0 : i32
+    %4 = cir.ptr_stride(%2 : !cir.ptr<i32>, %3 : i32), !cir.ptr<i32>
+    ```
+  }];
+
+  let arguments = (ins CIR_PointerType:$base, PrimitiveInt:$stride);
+  let results = (outs CIR_PointerType:$result);
+
+  let assemblyFormat = [{
+    `(` $base `:` qualified(type($base)) `,` $stride `:` 
qualified(type($stride)) `)`
+    `,` qualified(type($result)) attr-dict
+  }];
+
+  let extraClassDeclaration = [{
+    // Get type pointed by the base pointer.
+    mlir::Type getElementTy() {
+      return mlir::cast<cir::PointerType>(getBase().getType()).getPointee();
+    }
+  }];
+
+  // SameFirstOperandAndResultType already checks all we need.
+  let hasVerifier = 0;
+}
+
 
//===----------------------------------------------------------------------===//
 // ConstantOp
 
//===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/LoweringHelpers.h 
b/clang/include/clang/CIR/LoweringHelpers.h
new file mode 100644
index 0000000000000..3077010ee5ffe
--- /dev/null
+++ b/clang/include/clang/CIR/LoweringHelpers.h
@@ -0,0 +1,40 @@
+//====- LoweringHelpers.h - Lowering helper functions 
---------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares helper functions for lowering from CIR to LLVM or MLIR.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_CIR_LOWERINGHELPERS_H
+#define LLVM_CLANG_CIR_LOWERINGHELPERS_H
+
+#include "mlir/IR/BuiltinAttributes.h"
+#include "mlir/Transforms/DialectConversion.h"
+#include "clang/CIR/Dialect/IR/CIRDialect.h"
+
+mlir::DenseElementsAttr
+convertStringAttrToDenseElementsAttr(cir::ConstArrayAttr attr, mlir::Type 
type);
+
+template <typename StorageTy> StorageTy getZeroInitFromType(mlir::Type ty);
+template <> mlir::APInt getZeroInitFromType(mlir::Type ty);
+template <> mlir::APFloat getZeroInitFromType(mlir::Type ty);
+
+template <typename AttrTy, typename StorageTy>
+void convertToDenseElementsAttrImpl(cir::ConstArrayAttr attr,
+                                    llvm::SmallVectorImpl<StorageTy> &values);
+
+template <typename AttrTy, typename StorageTy>
+mlir::DenseElementsAttr
+convertToDenseElementsAttr(cir::ConstArrayAttr attr,
+                           const llvm::SmallVectorImpl<int64_t> &dims,
+                           mlir::Type type);
+
+std::optional<mlir::Attribute>
+lowerConstArrayAttr(cir::ConstArrayAttr constArr,
+                    const mlir::TypeConverter *converter);
+
+#endif
diff --git a/clang/lib/CIR/CodeGen/Address.h b/clang/lib/CIR/CodeGen/Address.h
index fba1ffd90877b..2cc8ada783197 100644
--- a/clang/lib/CIR/CodeGen/Address.h
+++ b/clang/lib/CIR/CodeGen/Address.h
@@ -70,6 +70,14 @@ class Address {
     return pointerAndKnownNonNull.getPointer();
   }
 
+  mlir::Type getType() const {
+    assert(mlir::cast<cir::PointerType>(
+               pointerAndKnownNonNull.getPointer().getType())
+               .getPointee() == elementType);
+
+    return mlir::cast<cir::PointerType>(getPointer().getType());
+  }
+
   mlir::Type getElementType() const {
     assert(isValid());
     assert(mlir::cast<cir::PointerType>(
@@ -77,6 +85,8 @@ class Address {
                .getPointee() == elementType);
     return elementType;
   }
+
+  clang::CharUnits getAlignment() const { return alignment; }
 };
 
 } // namespace clang::CIRGen
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h 
b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index fef290612149a..d1a81f85b66fc 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -83,6 +83,10 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
 
   bool isInt(mlir::Type i) { return mlir::isa<cir::IntType>(i); }
 
+  bool isInt8Ty(mlir::Type i) {
+    return i == typeCache.UInt8Ty || i == typeCache.SInt8Ty;
+  }
+
   // Creates constant nullptr for pointer type ty.
   cir::ConstantOp getNullPtr(mlir::Type ty, mlir::Location loc) {
     assert(!cir::MissingFeatures::targetCodeGenInfoGetNullPointer());
diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp 
b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
index a93e8dbcb42de..a0c6b832faa24 100644
--- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
@@ -250,7 +250,7 @@ void CIRGenFunction::emitExprAsInit(const Expr *init, const 
ValueDecl *d,
     return;
   }
   case cir::TEK_Aggregate:
-    cgm.errorNYI(init->getSourceRange(), "emitExprAsInit: aggregate type");
+    emitAggExpr(init, AggValueSlot::forLValue(lvalue));
     return;
   }
   llvm_unreachable("bad evaluation kind");
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
new file mode 100644
index 0000000000000..3bd898422f4d6
--- /dev/null
+++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
@@ -0,0 +1,277 @@
+//===--- CIRGenExprAgg.cpp - Emit CIR Code from Aggregate Expressions 
-----===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This contains code to emit Aggregate Expr nodes as CIR code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CIRGenBuilder.h"
+#include "CIRGenFunction.h"
+#include "CIRGenValue.h"
+#include "clang/CIR/Dialect/IR/CIRAttrs.h"
+
+#include "clang/AST/Expr.h"
+#include "clang/AST/StmtVisitor.h"
+#include <cstdint>
+
+using namespace clang;
+using namespace clang::CIRGen;
+
+namespace {
+class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
+
+  CIRGenFunction &cgf;
+  AggValueSlot dest;
+
+  AggValueSlot ensureSlot(mlir::Location loc, QualType t) {
+    if (!dest.isIgnored())
+      return dest;
+    llvm_unreachable("Slot for ignored address NTI");
+  }
+
+public:
+  AggExprEmitter(CIRGenFunction &cgf, AggValueSlot dest)
+      : cgf(cgf), dest(dest) {}
+
+  void emitArrayInit(Address destPtr, cir::ArrayType arrayTy, QualType 
arrayQTy,
+                     Expr *exprToVisit, ArrayRef<Expr *> args,
+                     Expr *arrayFiller);
+
+  void emitInitializationToLValue(Expr *e, LValue lv);
+
+  void emitNullInitializationToLValue(mlir::Location loc, LValue lv);
+
+  void Visit(Expr *e) { StmtVisitor<AggExprEmitter>::Visit(e); }
+
+  void VisitInitListExpr(InitListExpr *e);
+
+  void visitCXXParenListOrInitListExpr(Expr *e, ArrayRef<Expr *> args,
+                                       FieldDecl *initializedFieldInUnion,
+                                       Expr *arrayFiller);
+};
+
+} // namespace
+
+static bool isTrivialFiller(Expr *e) {
+  if (!e)
+    return true;
+
+  if (isa<ImplicitValueInitExpr>(e))
+    return true;
+
+  if (auto *ile = dyn_cast<InitListExpr>(e)) {
+    if (ile->getNumInits())
+      return false;
+    return isTrivialFiller(ile->getArrayFiller());
+  }
+
+  if (const auto *cons = dyn_cast_or_null<CXXConstructExpr>(e))
+    return cons->getConstructor()->isDefaultConstructor() &&
+           cons->getConstructor()->isTrivial();
+
+  return false;
+}
+
+void AggExprEmitter::emitArrayInit(Address destPtr, cir::ArrayType arrayTy,
+                                   QualType arrayQTy, Expr *e,
+                                   ArrayRef<Expr *> args, Expr *arrayFiller) {
+  CIRGenBuilderTy &builder = cgf.getBuilder();
+  const mlir::Location loc = cgf.getLoc(e->getSourceRange());
+
+  const uint64_t numInitElements = args.size();
+
+  const QualType elementType =
+      cgf.getContext().getAsArrayType(arrayQTy)->getElementType();
+
+  if (elementType.isDestructedType()) {
+    llvm_unreachable("dtorKind NYI");
+  }
+
+  const QualType elementPtrType = cgf.getContext().getPointerType(elementType);
+
+  const mlir::Type cirElementType = cgf.convertType(elementType);
+  const cir::PointerType cirElementPtrType =
+      builder.getPointerTo(cirElementType);
+
+  auto begin = builder.create<cir::CastOp>(loc, cirElementPtrType,
+                                           cir::CastKind::array_to_ptrdecay,
+                                           destPtr.getPointer());
+
+  const CharUnits elementSize =
+      cgf.getContext().getTypeSizeInChars(elementType);
+  const CharUnits elementAlign =
+      destPtr.getAlignment().alignmentOfArrayElement(elementSize);
+
+  // The 'current element to initialize'.  The invariants on this
+  // variable are complicated.  Essentially, after each iteration of
+  // the loop, it points to the last initialized element, except
+  // that it points to the beginning of the array before any
+  // elements have been initialized.
+  mlir::Value element = begin;
+
+  // Don't build the 'one' before the cycle to avoid
+  // emmiting the redundant `cir.const 1` instrs.
+  mlir::Value one;
+
+  // Emit the explicit initializers.
+  for (uint64_t i = 0; i != numInitElements; ++i) {
+    // Advance to the next element.
+    if (i > 0) {
+      one = builder.create<cir::ConstantOp>(
+          loc, cgf.PtrDiffTy, cir::IntAttr::get(cgf.PtrDiffTy, i));
+      element =
+          builder.create<cir::PtrStrideOp>(loc, cirElementPtrType, begin, one);
+    }
+
+    const Address address = Address(element, cirElementType, elementAlign);
+    const LValue elementLV = LValue::makeAddr(address, elementType);
+    emitInitializationToLValue(args[i], elementLV);
+  }
+
+  const uint64_t numArrayElements = arrayTy.getSize();
+
+  // Check whether there's a non-trivial array-fill expression.
+  const bool hasTrivialFiller = isTrivialFiller(arrayFiller);
+
+  // Any remaining elements need to be zero-initialized, possibly
+  // using the filler expression.  We can skip this if the we're
+  // emitting to zeroed memory.
+  if (numInitElements != numArrayElements &&
+      !(dest.isZeroed() && hasTrivialFiller &&
+        cgf.getTypes().isZeroInitializable(elementType))) {
+    // Advance to the start of the rest of the array.
+    if (numInitElements) {
+      one = builder.create<cir::ConstantOp>(
+          loc, cgf.PtrDiffTy, cir::IntAttr::get(cgf.PtrDiffTy, 1));
+      element = builder.create<cir::PtrStrideOp>(loc, cirElementPtrType,
+                                                 element, one);
+    }
+
+    // Allocate the temporary variable
+    // to store the pointer to first unitialized element
+    auto tmpAddr = cgf.createTempAlloca(
+        cirElementPtrType, cgf.getPointerAlign(), loc, "arrayinit.temp");
+    LValue tmpLV = LValue::makeAddr(tmpAddr, elementPtrType);
+    cgf.emitStoreThroughLValue(RValue::get(element), tmpLV);
+
+    // TODO:Replace this part later with cir::DoWhileOp
+    for (unsigned i = numInitElements; i != numArrayElements; ++i) {
+      auto currentElement = builder.createLoad(loc, tmpAddr.getPointer());
+
+      // Emit the actual filler expression.
+      const LValue elementLV = LValue::makeAddr(
+          Address(currentElement, cirElementType, elementAlign), elementType);
+
+      if (arrayFiller)
+        emitInitializationToLValue(arrayFiller, elementLV);
+      else
+        emitNullInitializationToLValue(loc, elementLV);
+
+      // Advance pointer and store them to temporary variable
+      one = builder.create<cir::ConstantOp>(
+          loc, cgf.PtrDiffTy, cir::IntAttr::get(cgf.PtrDiffTy, 1));
+
+      auto nextElement = builder.create<cir::PtrStrideOp>(
+          loc, cirElementPtrType, currentElement, one);
+      cgf.emitStoreThroughLValue(RValue::get(nextElement), tmpLV);
+    }
+  }
+}
+
+void AggExprEmitter::emitInitializationToLValue(Expr *e, LValue lv) {
+  const QualType type = lv.getType();
+
+  if (isa<ImplicitValueInitExpr, CXXScalarValueInitExpr>(e)) {
+    const auto loc = e->getSourceRange().isValid()
+                         ? cgf.getLoc(e->getSourceRange())
+                         : *cgf.currSrcLoc;
+    return emitNullInitializationToLValue(loc, lv);
+  }
+
+  if (isa<NoInitExpr>(e))
+    return;
+
+  if (type->isReferenceType()) {
+    llvm_unreachable("NTI");
+  }
+
+  switch (cgf.getEvaluationKind(type)) {
+  case cir::TEK_Complex:
+    llvm_unreachable("TEK_Complex NYI");
+    break;
+  case cir::TEK_Aggregate:
+    cgf.emitAggExpr(e, AggValueSlot::forLValue(lv));
+    return;
+  case cir::TEK_Scalar:
+    if (lv.isSimple())
+      cgf.emitScalarInit(e, cgf.getLoc(e->getSourceRange()), lv);
+    else
+      cgf.emitStoreThroughLValue(RValue::get(cgf.emitScalarExpr(e)), lv);
+    return;
+  }
+}
+
+void AggExprEmitter::emitNullInitializationToLValue(mlir::Location loc,
+                                                    LValue lv) {
+  const QualType type = lv.getType();
+
+  // If the destination slot is already zeroed out before the aggregate is
+  // copied into it, we don't have to emit any zeros here.
+  if (dest.isZeroed() && cgf.getTypes().isZeroInitializable(type))
+    return;
+
+  if (cgf.hasScalarEvaluationKind(type)) {
+    // For non-aggregates, we can store the appropriate null constant.
+    auto null = cgf.cgm.emitNullConstant(type, loc);
+    if (lv.isSimple()) {
+      cgf.emitStoreOfScalar(null, lv, /* isInitialization */ true);
+      return;
+    }
+
+    llvm_unreachable("emitStoreThroughBitfieldLValue NYI");
+    return;
+  }
+
+  // There's a potential optimization opportunity in combining
+  // memsets; that would be easy for arrays, but relatively
+  // difficult for structures with the current code.
+  cgf.emitNullInitialization(loc, lv.getAddress(), lv.getType());
+}
+
+void AggExprEmitter::VisitInitListExpr(InitListExpr *e) {
+  if (e->hadArrayRangeDesignator())
+    llvm_unreachable("GNU array range designator extension");
+
+  if (e->isTransparent())
+    return Visit(e->getInit(0));
+
+  visitCXXParenListOrInitListExpr(
+      e, e->inits(), e->getInitializedFieldInUnion(), e->getArrayFiller());
+}
+
+void AggExprEmitter::visitCXXParenListOrInitListExpr(
+    Expr *e, ArrayRef<Expr *> args, FieldDecl *initializedFieldInUnion,
+    Expr *arrayFiller) {
+
+  const AggValueSlot dest =
+      ensureSlot(cgf.getLoc(e->getSourceRange()), e->getType());
+
+  if (e->getType()->isConstantArrayType()) {
+    cir::ArrayType arrayTy =
+        cast<cir::ArrayType>(dest.getAddress().getElementType());
+    emitArrayInit(dest.getAddress(), arrayTy, e->getType(), e, args,
+                  arrayFiller);
+    return;
+  }
+
+  llvm_unreachable("NYI");
+}
+
+void CIRGenFunction::emitAggExpr(const Expr *e, AggValueSlot slot) {
+  AggExprEmitter(*this, slot).Visit(const_cast<Expr *>(e));
+}
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
index fc49d6da97206..06fcc0e2c040a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
@@ -412,3 +412,26 @@ mlir::Attribute ConstantEmitter::tryEmitPrivate(const 
APValue &value,
   }
   llvm_unreachable("Unknown APValue kind");
 }
+
+mlir::Value CIRGenModule::emitNullConstant(QualType t, mlir::Location loc) {
+  if (t->getAs<PointerType>()) {
+    return builder.getNullPtr(getTypes().convertTypeForMem(t), loc);
+  }
+
+  if (getTypes().isZeroInitializable(t))
+    return builder.getNullValue(getTypes().convertTypeForMem(t), loc);
+
+  if (const ConstantArrayType *cat =
+          getASTContext().getAsConstantArrayType(t)) {
+    llvm_unreachable("NYI");
+  }
+
+  if (const RecordType *rt = t->getAs<RecordType>())
+    llvm_unreachable("NYI");
+
+  assert(t->isMemberDataPointerType() &&
+         "Should only see pointers to data members here!");
+
+  llvm_unreachable("NYI");
+  return {};
+}
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp 
b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index 16547f2401292..ea24104e3075d 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -449,4 +449,50 @@ LValue CIRGenFunction::emitLValue(const Expr *e) {
   }
 }
 
+void CIRGenFunction::emitNullInitialization(mlir::Location loc, Address 
destPtr,
+                                            QualType ty) {
+  // Ignore empty classes in C++.
+  if (getLangOpts().CPlusPlus) {
+    if (const RecordType *rt = ty->getAs<RecordType>()) {
+      if (cast<CXXRecordDecl>(rt->getDecl())->isEmpty())
+        return;
+    }
+  }
+
+  // Cast the dest ptr to the appropriate i8 pointer type.
+  if (builder.isInt8Ty(destPtr.getElementType())) {
+    llvm_unreachable("NYI");
+  }
+
+  // Get size and alignment info for this aggregate.
+  const CharUnits size = getContext().getTypeSizeInChars(ty);
+  if (size.isZero()) {
+    // But note that getTypeInfo returns 0 for a VLA.
+    if (const VariableArrayType *vlatype = dyn_cast_or_null<VariableArrayType>(
+            getContext().getAsArrayType(ty))) {
+      cgm.errorNYI(loc,
+                   "emitNullInitialization for zero size VariableArrayType");
+    } else {
+      return;
+    }
+  }
+
+  // If the type contains a pointer to data member we can't memset it to zero.
+  // Instead, create a null constant and copy it to the destination.
+  // TODO: there are other patterns besides zero that we can usefully memset,
+  // like -1, which happens to be the pattern used by member-pointers.
+  if (!cgm.getTypes().isZeroInitializable(ty)) {
+    cgm.errorNYI(loc, "type is not zero initializable");
+  }
+
+  // In LLVM Codegen: otherwise, just memset the whole thing to zero using
+  // Builder.CreateMemSet. In CIR just emit a store of #cir.zero to the
+  // respective address.
+  // Builder.CreateMemSet(DestPtr, Builder.getInt8(0), SizeVal, false);
+  auto zeroAttr = cir::ZeroAttr::get(builder.getContext(), convertType(ty));
+  auto zeroValue =
+      builder.create<cir::ConstantOp>(loc, convertType(ty), zeroAttr);
+  builder.createStore(loc, zeroValue, destPtr.getPointer());
+}
+
 } // namespace clang::CIRGen
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 631217cf67762..6ef44919864f2 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -80,11 +80,11 @@ class CIRGenFunction : public CIRGenTypeCache {
   /// this fuction. These can potentially set the return value.
   bool sawAsmBlock = false;
 
-  mlir::Type convertTypeForMem(QualType T);
+  mlir::Type convertTypeForMem(QualType t);
 
-  mlir::Type convertType(clang::QualType T);
-  mlir::Type convertType(const TypeDecl *T) {
-    return convertType(getContext().getTypeDeclType(T));
+  mlir::Type convertType(clang::QualType t);
+  mlir::Type convertType(const TypeDecl *t) {
+    return convertType(getContext().getTypeDeclType(t));
   }
 
   ///  Return the cir::TypeEvaluationKind of QualType \c type.
@@ -115,6 +115,10 @@ class CIRGenFunction : public CIRGenTypeCache {
 
   mlir::Value createDummyValue(mlir::Location loc, clang::QualType qt);
 
+  void emitAggExpr(const clang::Expr *e, AggValueSlot slot);
+
+  void emitNullInitialization(mlir::Location loc, Address destPtr, QualType 
ty);
+
 private:
   // Track current variable initialization (if there's one)
   const clang::VarDecl *currVarDecl = nullptr;
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp 
b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 9776a4e09f9e0..47dc93f4ae023 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -57,6 +57,18 @@ CIRGenModule::CIRGenModule(mlir::MLIRContext &mlirContext,
   FP80Ty = cir::FP80Type::get(&getMLIRContext());
   FP128Ty = cir::FP128Type::get(&getMLIRContext());
 
+  PointerAlignInBytes =
+      astContext
+          .toCharUnitsFromBits(
+              astContext.getTargetInfo().getPointerAlign(LangAS::Default))
+          .getQuantity();
+
+  // TODO(CIR): Should be updated once TypeSizeInfoAttr is upstreamed
+  const unsigned sizeTypeSize =
+      astContext.getTypeSize(astContext.getSignedSizeType());
+  PtrDiffTy =
+      cir::IntType::get(&getMLIRContext(), sizeTypeSize, /*isSigned=*/true);
+
   theModule->setAttr(cir::CIRDialect::getTripleAttrName(),
                      builder.getStringAttr(getTriple().str()));
 }
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h 
b/clang/lib/CIR/CodeGen/CIRGenModule.h
index 734cafa2e07bb..87a9eef16e7f9 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.h
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -113,6 +113,11 @@ class CIRGenModule : public CIRGenTypeCache {
   void emitGlobalVarDefinition(const clang::VarDecl *vd,
                                bool isTentative = false);
 
+  // Return the result of value-initializing the given type, i.e. a null
+  /// expression of the given type.  This is usually, but not always, an LLVM
+  /// null constant.
+  mlir::Value emitNullConstant(QualType t, mlir::Location loc);
+
   cir::FuncOp
   getOrCreateCIRFunction(llvm::StringRef mangledName, mlir::Type funcType,
                          clang::GlobalDecl gd, bool forVTable,
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypeCache.h 
b/clang/lib/CIR/CodeGen/CIRGenTypeCache.h
index 99c0123c64b28..a5b7f0c9579b4 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypeCache.h
+++ b/clang/lib/CIR/CodeGen/CIRGenTypeCache.h
@@ -13,6 +13,7 @@
 #ifndef LLVM_CLANG_LIB_CIR_CIRGENTYPECACHE_H
 #define LLVM_CLANG_LIB_CIR_CIRGENTYPECACHE_H
 
+#include "clang/AST/CharUnits.h"
 #include "clang/CIR/Dialect/IR/CIRTypes.h"
 
 namespace clang::CIRGen {
@@ -47,6 +48,18 @@ struct CIRGenTypeCache {
   cir::DoubleType DoubleTy;
   cir::FP80Type FP80Ty;
   cir::FP128Type FP128Ty;
+
+  mlir::Type PtrDiffTy;
+
+  /// The size and alignment of a pointer into the generic address space.
+  union {
+    unsigned char PointerAlignInBytes;
+    unsigned char PointerSizeInBytes;
+  };
+
+  clang::CharUnits getPointerAlign() const {
+    return clang::CharUnits::fromQuantity(PointerAlignInBytes);
+  }
 };
 
 } // namespace clang::CIRGen
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp 
b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
index aaf3fe240f3c3..2684fde728fa0 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
@@ -254,3 +254,27 @@ mlir::Type CIRGenTypes::convertTypeForMem(clang::QualType 
qualType,
 
   return convertedType;
 }
+
+bool CIRGenTypes::isZeroInitializable(clang::QualType t) {
+  if (t->getAs<PointerType>())
+    return astContext.getTargetNullPointerValue(t) == 0;
+
+  if (const auto *at = astContext.getAsArrayType(t)) {
+    if (isa<IncompleteArrayType>(at))
+      return true;
+
+    if (const auto *cat = dyn_cast<ConstantArrayType>(at))
+      if (astContext.getConstantArrayElementCount(cat) == 0)
+        return true;
+  }
+
+  if (const RecordType *rt = t->getAs<RecordType>()) {
+    cgm.errorNYI(SourceLocation(), "isZeroInitializable for RecordType", t);
+  }
+
+  if (const MemberPointerType *mpt = t->getAs<MemberPointerType>())
+    cgm.errorNYI(SourceLocation(), "isZeroInitializable for MemberPointerType",
+                 t);
+
+  return true;
+}
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.h 
b/clang/lib/CIR/CodeGen/CIRGenTypes.h
index f280e17ebddc6..73948f5c63e6a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypes.h
+++ b/clang/lib/CIR/CodeGen/CIRGenTypes.h
@@ -71,6 +71,10 @@ class CIRGenTypes {
   /// representation is usually i8 or i32, depending on the target.
   // TODO: convert this comment to account for MLIR's equivalence
   mlir::Type convertTypeForMem(clang::QualType, bool forBitField = false);
+
+  /// Return whether a type can be zero-initialized (in the C++ sense) with an
+  /// LLVM zeroinitializer.
+  bool isZeroInitializable(clang::QualType t);
 };
 
 } // namespace clang::CIRGen
diff --git a/clang/lib/CIR/CodeGen/CIRGenValue.h 
b/clang/lib/CIR/CodeGen/CIRGenValue.h
index c559e853aad39..d22d518ef4904 100644
--- a/clang/lib/CIR/CodeGen/CIRGenValue.h
+++ b/clang/lib/CIR/CodeGen/CIRGenValue.h
@@ -85,11 +85,15 @@ class LValue {
     MatrixElt     // This is a matrix element, use getVector*
   } lvType;
   clang::QualType type;
+  clang::Qualifiers quals;
 
   mlir::Value v;
   mlir::Type elementType;
 
-  void initialize(clang::QualType type) { this->type = type; }
+  void initialize(clang::QualType type, clang::Qualifiers quals) {
+    this->type = type;
+    this->quals = quals;
+  }
 
 public:
   bool isSimple() const { return lvType == Simple; }
@@ -111,16 +115,52 @@ class LValue {
     return Address(getPointer(), elementType, getAlignment());
   }
 
+  const clang::Qualifiers &getQuals() const { return quals; }
+
   static LValue makeAddr(Address address, clang::QualType t) {
     LValue r;
     r.lvType = Simple;
     r.v = address.getPointer();
     r.elementType = address.getElementType();
-    r.initialize(t);
+    r.initialize(t, t.getQualifiers());
     return r;
   }
 };
 
+/// An aggregate value slot.
+class AggValueSlot {
+
+  Address addr;
+  clang::Qualifiers quals;
+
+  /// This is set to true if the memory in the slot is known to be zero before
+  /// the assignment into it.  This means that zero fields don't need to be 
set.
+  bool zeroedFlag : 1;
+
+public:
+  enum IsZeroed_t { IsNotZeroed, IsZeroed };
+
+  AggValueSlot(Address addr, clang::Qualifiers quals, bool zeroedFlag)
+      : addr(addr), quals(quals), zeroedFlag(zeroedFlag) {}
+
+  static AggValueSlot forAddr(Address addr, clang::Qualifiers quals,
+                              IsZeroed_t isZeroed = IsNotZeroed) {
+    return AggValueSlot(addr, quals, isZeroed);
+  }
+
+  static AggValueSlot forLValue(const LValue &lv) {
+    return forAddr(lv.getAddress(), lv.getQuals());
+  }
+
+  clang::Qualifiers getQualifiers() const { return quals; }
+
+  Address getAddress() const { return addr; }
+
+  bool isIgnored() const { return !addr.isValid(); }
+
+  IsZeroed_t isZeroed() const { return IsZeroed_t(zeroedFlag); }
+};
+
 } // namespace clang::CIRGen
 
 #endif // CLANG_LIB_CIR_CIRGENVALUE_H
diff --git a/clang/lib/CIR/CodeGen/CMakeLists.txt 
b/clang/lib/CIR/CodeGen/CMakeLists.txt
index 8ee65c2763e70..da8d63ca569af 100644
--- a/clang/lib/CIR/CodeGen/CMakeLists.txt
+++ b/clang/lib/CIR/CodeGen/CMakeLists.txt
@@ -10,6 +10,7 @@ add_clang_library(clangCIR
   CIRGenerator.cpp
   CIRGenDecl.cpp
   CIRGenExpr.cpp
+  CIRGenExprAggregate.cpp
   CIRGenExprConstant.cpp
   CIRGenExprScalar.cpp
   CIRGenFunction.cpp
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp 
b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index ae86fefcf3657..99f9670c02d28 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -246,8 +246,8 @@ OpFoldResult cir::ConstantOp::fold(FoldAdaptor /*adaptor*/) 
{
 
//===----------------------------------------------------------------------===//
 
 LogicalResult cir::CastOp::verify() {
-  auto resType = getResult().getType();
-  auto srcType = getSrc().getType();
+  const auto resType = getResult().getType();
+  const auto srcType = getSrc().getType();
 
   switch (getKind()) {
   case cir::CastKind::int_to_bool: {
@@ -271,6 +271,15 @@ LogicalResult cir::CastOp::verify() {
       return emitOpError() << "requires !cir.int type for source";
     return success();
   }
+  case cir::CastKind::array_to_ptrdecay: {
+    const auto arrayPtrTy = mlir::dyn_cast<cir::PointerType>(srcType);
+    const auto flatPtrTy = mlir::dyn_cast<cir::PointerType>(resType);
+    if (!arrayPtrTy || !flatPtrTy)
+      return emitOpError() << "requires !cir.ptr type for source and result";
+
+    // TODO: Make sure the AddrSpace of both types are equals
+    return success();
+  }
   case cir::CastKind::bitcast: {
     // Handle the pointer types first.
     auto srcPtrTy = mlir::dyn_cast<cir::PointerType>(srcType);
@@ -453,9 +462,9 @@ mlir::LogicalResult cir::ReturnOp::verify() {
 
 /// Given the region at `index`, or the parent operation if `index` is None,
 /// return the successor regions. These are the regions that may be selected
-/// during the flow of control. `operands` is a set of optional attributes that
-/// correspond to a constant value for each operand, or null if that operand is
-/// not a constant.
+/// during the flow of control. `operands` is a set of optional attributes
+/// that correspond to a constant value for each operand, or null if that
+/// operand is not a constant.
 void cir::ScopeOp::getSuccessorRegions(
     mlir::RegionBranchPoint point, SmallVectorImpl<RegionSuccessor> &regions) {
   // The only region always branch back to the parent operation.
@@ -697,8 +706,8 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, 
OperationState &state) {
 }
 
 bool cir::FuncOp::isDeclaration() {
-  // TODO(CIR): This function will actually do something once external function
-  // declarations and aliases are upstreamed.
+  // TODO(CIR): This function will actually do something once external
+  // function declarations and aliases are upstreamed.
   return false;
 }
 
@@ -724,6 +733,25 @@ void cir::FuncOp::print(OpAsmPrinter &p) {
   }
 }
 
+//===----------------------------------------------------------------------===//
+// CIR defined traits
+//===----------------------------------------------------------------------===//
+
+LogicalResult
+mlir::OpTrait::impl::verifySameFirstOperandAndResultType(Operation *op) {
+  if (failed(verifyAtLeastNOperands(op, 1)) || failed(verifyOneResult(op)))
+    return failure();
+
+  const Type type = op->getResult(0).getType();
+  const Type opType = op->getOperand(0).getType();
+
+  if (type != opType)
+    return op->emitOpError()
+           << "requires the same type for first operand and result";
+
+  return success();
+}
+
 // TODO(CIR): The properties of functions that require verification haven't
 // been implemented yet.
 mlir::LogicalResult cir::FuncOp::verify() { return success(); }
diff --git a/clang/lib/CIR/Lowering/CMakeLists.txt 
b/clang/lib/CIR/Lowering/CMakeLists.txt
index 09e48862df63c..28ec3c551018c 100644
--- a/clang/lib/CIR/Lowering/CMakeLists.txt
+++ b/clang/lib/CIR/Lowering/CMakeLists.txt
@@ -7,6 +7,7 @@ get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS)
 
 add_clang_library(clangCIRLoweringCommon
   CIRPasses.cpp
+  LoweringHelpers.cpp
 
   LINK_LIBS
   clangCIR
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 30cbee48b4bdc..56b4e2a5ad03d 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -13,6 +13,7 @@
 #include "LowerToLLVM.h"
 
 #include <deque>
+#include <optional>
 
 #include "mlir/Conversion/LLVMCommon/TypeConverter.h"
 #include "mlir/Dialect/DLTI/DLTI.h"
@@ -28,6 +29,7 @@
 #include "mlir/Transforms/DialectConversion.h"
 #include "clang/CIR/Dialect/IR/CIRDialect.h"
 #include "clang/CIR/Dialect/Passes.h"
+#include "clang/CIR/LoweringHelpers.h"
 #include "clang/CIR/MissingFeatures.h"
 #include "clang/CIR/Passes.h"
 #include "llvm/ADT/TypeSwitch.h"
@@ -540,6 +542,68 @@ mlir::LogicalResult 
CIRToLLVMCastOpLowering::matchAndRewrite(
   return mlir::success();
 }
 
+mlir::LogicalResult CIRToLLVMPtrStrideOpLowering::matchAndRewrite(
+    cir::PtrStrideOp ptrStrideOp, OpAdaptor adaptor,
+    mlir::ConversionPatternRewriter &rewriter) const {
+
+  const mlir::DataLayout llvmLayout(
+      ptrStrideOp->getParentOfType<mlir::ModuleOp>());
+  const mlir::TypeConverter *tc = getTypeConverter();
+  const mlir::Type resultTy = tc->convertType(ptrStrideOp.getType());
+
+  mlir::Type elementTy =
+      convertTypeForMemory(*tc, dataLayout, ptrStrideOp.getElementTy());
+  mlir::MLIRContext *ctx = elementTy.getContext();
+
+  // void and function types doesn't really have a layout to use in GEPs,
+  // make it i8 instead.
+  if (mlir::isa<mlir::LLVM::LLVMVoidType>(elementTy) ||
+      mlir::isa<mlir::LLVM::LLVMFunctionType>(elementTy))
+    elementTy = mlir::IntegerType::get(elementTy.getContext(), 8,
+                                       mlir::IntegerType::Signless);
+  // Zero-extend, sign-extend or trunc the pointer value.
+  mlir::Value index = adaptor.getStride();
+  const unsigned width =
+      mlir::cast<mlir::IntegerType>(index.getType()).getWidth();
+  const std::optional<std::uint64_t> layoutWidth =
+      llvmLayout.getTypeIndexBitwidth(adaptor.getBase().getType());
+
+  const auto indexOp = index.getDefiningOp();
+  if (indexOp && layoutWidth && width != *layoutWidth) {
+    // If the index comes from a subtraction, make sure the extension happens
+    // before it. To achieve that, look at unary minus, which already got
+    // lowered to "sub 0, x".
+    const auto sub = dyn_cast<mlir::LLVM::SubOp>(indexOp);
+    auto unary = dyn_cast_if_present<cir::UnaryOp>(
+        ptrStrideOp.getStride().getDefiningOp());
+    bool rewriteSub =
+        unary && unary.getKind() == cir::UnaryOpKind::Minus && sub;
+    if (rewriteSub)
+      index = indexOp->getOperand(1);
+
+    // Handle the cast
+    const auto llvmDstType = mlir::IntegerType::get(ctx, *layoutWidth);
+    index = getLLVMIntCast(rewriter, index, llvmDstType,
+                           ptrStrideOp.getStride().getType().isUnsigned(),
+                           width, *layoutWidth);
+
+    // Rewrite the sub in front of extensions/trunc
+    if (rewriteSub) {
+      index = rewriter.create<mlir::LLVM::SubOp>(
+          index.getLoc(), index.getType(),
+          rewriter.create<mlir::LLVM::ConstantOp>(
+              index.getLoc(), index.getType(),
+              mlir::IntegerAttr::get(index.getType(), 0)),
+          index);
+      rewriter.eraseOp(sub);
+    }
+  }
+
+  rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(
+      ptrStrideOp, resultTy, elementTy, adaptor.getBase(), index);
+  return mlir::success();
+}
+
 mlir::LogicalResult CIRToLLVMAllocaOpLowering::matchAndRewrite(
     cir::AllocaOp op, OpAdaptor adaptor,
     mlir::ConversionPatternRewriter &rewriter) const {
@@ -620,6 +684,28 @@ mlir::LogicalResult 
CIRToLLVMStoreOpLowering::matchAndRewrite(
   return mlir::LogicalResult::success();
 }
 
+/// Switches on the type of attribute and calls the appropriate conversion.
+mlir::Value lowerCirAttrAsValue(mlir::Operation *parentOp,
+                                const mlir::Attribute attr,
+                                mlir::ConversionPatternRewriter &rewriter,
+                                const mlir::TypeConverter *converter,
+                                mlir::DataLayout const &dataLayout) {
+  CIRAttrToValue valueConverter(parentOp, rewriter, converter);
+  auto value = valueConverter.visit(attr);
+  if (!value)
+    llvm_unreachable("unhandled attribute type");
+  return value;
+}
+
+bool hasTrailingZeros(cir::ConstArrayAttr attr) {
+  auto array = mlir::dyn_cast<mlir::ArrayAttr>(attr.getElts());
+  return attr.hasTrailingZeros() ||
+         (array && std::count_if(array.begin(), array.end(), [](auto elt) {
+            auto ar = dyn_cast<cir::ConstArrayAttr>(elt);
+            return ar && hasTrailingZeros(ar);
+          }));
+}
+
 mlir::LogicalResult CIRToLLVMConstantOpLowering::matchAndRewrite(
     cir::ConstantOp op, OpAdaptor adaptor,
     mlir::ConversionPatternRewriter &rewriter) const {
@@ -658,6 +744,27 @@ mlir::LogicalResult 
CIRToLLVMConstantOpLowering::matchAndRewrite(
     }
     assert(!cir::MissingFeatures::opGlobalViewAttr());
     attr = op.getValue();
+  } else if (const auto arrTy = mlir::dyn_cast<cir::ArrayType>(op.getType())) {
+    const auto constArr = mlir::dyn_cast<cir::ConstArrayAttr>(op.getValue());
+    if (!constArr && !isa<cir::ZeroAttr, cir::UndefAttr>(op.getValue()))
+      return op.emitError() << "array does not have a constant initializer";
+
+    std::optional<mlir::Attribute> denseAttr;
+    if (constArr && hasTrailingZeros(constArr)) {
+      auto newOp = lowerCirAttrAsValue(op, constArr, rewriter,
+                                       getTypeConverter(), dataLayout);
+      rewriter.replaceOp(op, newOp);
+      return mlir::success();
+    } else if (constArr &&
+               (denseAttr = lowerConstArrayAttr(constArr, typeConverter))) {
+      attr = denseAttr.value();
+    } else {
+      auto initVal = lowerCirAttrAsValue(op, op.getValue(), rewriter,
+                                         typeConverter, dataLayout);
+      rewriter.replaceAllUsesWith(op, initVal);
+      rewriter.eraseOp(op);
+      return mlir::success();
+    }
   } else {
     return op.emitError() << "unsupported constant type " << op.getType();
   }
@@ -1128,6 +1235,8 @@ void ConvertCIRToLLVMPass::runOnOperation() {
   patterns.add<CIRToLLVMStoreOpLowering>(converter, patterns.getContext(), dl);
   patterns.add<CIRToLLVMGlobalOpLowering>(converter, patterns.getContext(), 
dl);
   patterns.add<CIRToLLVMCastOpLowering>(converter, patterns.getContext(), dl);
+  patterns.add<CIRToLLVMPtrStrideOpLowering>(converter, patterns.getContext(),
+                                             dl);
   patterns.add<CIRToLLVMConstantOpLowering>(converter, patterns.getContext(),
                                             dl);
   patterns.add<
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
index a01a9a5f4f076..a54cf933b16ea 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
@@ -196,6 +196,21 @@ class CIRToLLVMTrapOpLowering : public 
mlir::OpConversionPattern<cir::TrapOp> {
                   mlir::ConversionPatternRewriter &) const override;
 };
 
+class CIRToLLVMPtrStrideOpLowering
+    : public mlir::OpConversionPattern<cir::PtrStrideOp> {
+  mlir::DataLayout const &dataLayout;
+
+public:
+  CIRToLLVMPtrStrideOpLowering(const mlir::TypeConverter &typeConverter,
+                               mlir::MLIRContext *context,
+                               mlir::DataLayout const &dataLayout)
+      : OpConversionPattern(typeConverter, context), dataLayout(dataLayout) {}
+  using mlir::OpConversionPattern<cir::PtrStrideOp>::OpConversionPattern;
+
+  mlir::LogicalResult
+  matchAndRewrite(cir::PtrStrideOp op, OpAdaptor,
+                  mlir::ConversionPatternRewriter &) const override;
+};
 } // namespace direct
 } // namespace cir
 
diff --git a/clang/lib/CIR/Lowering/LoweringHelpers.cpp 
b/clang/lib/CIR/Lowering/LoweringHelpers.cpp
new file mode 100644
index 0000000000000..e0635d97fceb5
--- /dev/null
+++ b/clang/lib/CIR/Lowering/LoweringHelpers.cpp
@@ -0,0 +1,150 @@
+//====- LoweringHelpers.cpp - Lowering helper functions 
-------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains helper functions for lowering from CIR to LLVM or MLIR.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/CIR/LoweringHelpers.h"
+
+mlir::DenseElementsAttr
+convertStringAttrToDenseElementsAttr(cir::ConstArrayAttr attr,
+                                     mlir::Type type) {
+  auto values = llvm::SmallVector<mlir::APInt, 8>{};
+  const auto stringAttr = mlir::dyn_cast<mlir::StringAttr>(attr.getElts());
+  assert(stringAttr && "expected string attribute here");
+
+  for (auto element : stringAttr)
+    values.push_back({8, (uint64_t)element});
+
+  const auto arrayTy = mlir::dyn_cast<cir::ArrayType>(attr.getType());
+  assert(arrayTy && "String attribute must have an array type");
+  if (arrayTy.getSize() != stringAttr.size())
+    llvm_unreachable("array type of the length not equal to that of the string 
"
+                     "attribute is not supported yet");
+
+  return mlir::DenseElementsAttr::get(
+      mlir::RankedTensorType::get({(int64_t)values.size()}, type),
+      llvm::ArrayRef(values));
+}
+
+template <> mlir::APInt getZeroInitFromType(mlir::Type ty) {
+  assert(mlir::isa<cir::IntType>(ty) && "expected int type");
+  const auto intTy = mlir::cast<cir::IntType>(ty);
+  return mlir::APInt::getZero(intTy.getWidth());
+}
+
+template <> mlir::APFloat getZeroInitFromType(mlir::Type ty) {
+  assert((mlir::isa<cir::SingleType, cir::DoubleType>(ty)) &&
+         "only float and double supported");
+
+  if (ty.isF32() || mlir::isa<cir::SingleType>(ty))
+    return mlir::APFloat(0.f);
+
+  if (ty.isF64() || mlir::isa<cir::DoubleType>(ty))
+    return mlir::APFloat(0.0);
+
+  llvm_unreachable("NYI");
+}
+
+/// \param attr the ConstArrayAttr to convert
+/// \param values the output parameter, the values array to fill
+/// \param currentDims the shpae of tensor we're going to convert to
+/// \param dimIndex the current dimension we're processing
+/// \param currentIndex the current index in the values array
+template <typename AttrTy, typename StorageTy>
+void convertToDenseElementsAttrImpl(
+    cir::ConstArrayAttr attr, llvm::SmallVectorImpl<StorageTy> &values,
+    const llvm::SmallVectorImpl<int64_t> &currentDims, int64_t dimIndex,
+    int64_t currentIndex) {
+  if (auto stringAttr = mlir::dyn_cast<mlir::StringAttr>(attr.getElts())) {
+    if (auto arrayType = mlir::dyn_cast<cir::ArrayType>(attr.getType())) {
+      for (auto element : stringAttr) {
+        auto intAttr = cir::IntAttr::get(arrayType.getEltType(), element);
+        values[currentIndex++] = mlir::dyn_cast<AttrTy>(intAttr).getValue();
+      }
+      return;
+    }
+  }
+
+  dimIndex++;
+  std::size_t elementsSizeInCurrentDim = 1;
+  for (std::size_t i = dimIndex; i < currentDims.size(); i++)
+    elementsSizeInCurrentDim *= currentDims[i];
+
+  auto arrayAttr = mlir::cast<mlir::ArrayAttr>(attr.getElts());
+  for (auto eltAttr : arrayAttr) {
+    if (auto valueAttr = mlir::dyn_cast<AttrTy>(eltAttr)) {
+      values[currentIndex++] = valueAttr.getValue();
+      continue;
+    }
+
+    if (auto subArrayAttr = mlir::dyn_cast<cir::ConstArrayAttr>(eltAttr)) {
+      convertToDenseElementsAttrImpl<AttrTy>(subArrayAttr, values, currentDims,
+                                             dimIndex, currentIndex);
+      currentIndex += elementsSizeInCurrentDim;
+      continue;
+    }
+
+    if (mlir::isa<cir::ZeroAttr, cir::UndefAttr>(eltAttr)) {
+      currentIndex += elementsSizeInCurrentDim;
+      continue;
+    }
+
+    llvm_unreachable("unknown element in ConstArrayAttr");
+  }
+}
+
+template <typename AttrTy, typename StorageTy>
+mlir::DenseElementsAttr convertToDenseElementsAttr(
+    cir::ConstArrayAttr attr, const llvm::SmallVectorImpl<int64_t> &dims,
+    mlir::Type elementType, mlir::Type convertedElementType) {
+  unsigned vectorSize = 1;
+  for (auto dim : dims)
+    vectorSize *= dim;
+  auto values = llvm::SmallVector<StorageTy, 8>(
+      vectorSize, getZeroInitFromType<StorageTy>(elementType));
+  convertToDenseElementsAttrImpl<AttrTy>(attr, values, dims, /*currentDim=*/0,
+                                         /*initialIndex=*/0);
+  return mlir::DenseElementsAttr::get(
+      mlir::RankedTensorType::get(dims, convertedElementType),
+      llvm::ArrayRef(values));
+}
+
+std::optional<mlir::Attribute>
+lowerConstArrayAttr(cir::ConstArrayAttr constArr,
+                    const mlir::TypeConverter *converter) {
+
+  // Ensure ConstArrayAttr has a type.
+  auto typedConstArr = mlir::dyn_cast<mlir::TypedAttr>(constArr);
+  assert(typedConstArr && "cir::ConstArrayAttr is not a mlir::TypedAttr");
+
+  // Ensure ConstArrayAttr type is a ArrayType.
+  auto cirArrayType = mlir::dyn_cast<cir::ArrayType>(typedConstArr.getType());
+  assert(cirArrayType && "cir::ConstArrayAttr is not a cir::ArrayType");
+
+  // Is a ConstArrayAttr with an cir::ArrayType: fetch element type.
+  mlir::Type type = cirArrayType;
+  auto dims = llvm::SmallVector<int64_t, 2>{};
+  while (auto arrayType = mlir::dyn_cast<cir::ArrayType>(type)) {
+    dims.push_back(arrayType.getSize());
+    type = arrayType.getEltType();
+  }
+
+  if (mlir::isa<mlir::StringAttr>(constArr.getElts()))
+    return convertStringAttrToDenseElementsAttr(constArr,
+                                                converter->convertType(type));
+  if (mlir::isa<cir::IntType>(type))
+    return convertToDenseElementsAttr<cir::IntAttr, mlir::APInt>(
+        constArr, dims, type, converter->convertType(type));
+  if (mlir::isa<cir::CIRFPTypeInterface>(type))
+    return convertToDenseElementsAttr<cir::FPAttr, mlir::APFloat>(
+        constArr, dims, type, converter->convertType(type));
+
+  return std::nullopt;
+}
diff --git a/clang/test/CIR/CodeGen/array.cpp b/clang/test/CIR/CodeGen/array.cpp
index a59880352e050..29313e6960896 100644
--- a/clang/test/CIR/CodeGen/array.cpp
+++ b/clang/test/CIR/CodeGen/array.cpp
@@ -28,14 +28,99 @@ 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>
 
 void func() {
-  int l[10];
-  // CHECK: %[[ARR:.*]] = cir.alloca !cir.array<!s32i x 10>, 
!cir.ptr<!cir.array<!s32i x 10>>, ["l"]
+  int arr[10];
+
+  // CHECK: %[[ARR:.*]] = cir.alloca !cir.array<!s32i x 10>, 
!cir.ptr<!cir.array<!s32i x 10>>, ["arr"]
+}
+
+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>>
+}
+
+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>
+}
+
+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: %[[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>
+}
+
+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>>>
+}
+
+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>
 }
 
-void func2(int p[10]) {}
-// CHECK: cir.func @func2(%arg0: !cir.ptr<!s32i>
+void func7(int p[10]) {}
+// CHECK: cir.func @func7(%arg0: !cir.ptr<!s32i>
 // CHECK: cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["p", init]
 
-void func3(int pp[10][5]) {}
-// CHECK: cir.func @func3(%arg0: !cir.ptr<!cir.array<!s32i x 5>>
+void func8(int pp[10][5]) {}
+// CHECK: cir.func @func8(%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>>>
diff --git a/clang/test/CIR/Lowering/array.cpp 
b/clang/test/CIR/Lowering/array.cpp
index 763980b9124a3..692f82ddf201a 100644
--- a/clang/test/CIR/Lowering/array.cpp
+++ b/clang/test/CIR/Lowering/array.cpp
@@ -30,15 +30,82 @@ int f[5] = {1, 2};
 // CHECK: @f = dso_local global [5 x i32] [i32 1, i32 2, i32 0, i32 0, i32 0]
 
 void func() {
-  int l[10];
+  int arr[10];
 }
 // CHECK: define void @func()
 // CHECK-NEXT: alloca [10 x i32], i64 1, align 16
 
-void func2(int p[10]) {}
-// CHECK: define void @func2(ptr {{%.*}})
+void func2() {
+  int arr2[2] = {5};
+}
+// CHECK: define void @func2()
+// CHECK:  %[[ARR_ALLOCA:.*]] = alloca [2 x i32], i64 1, align 4
+// CHECK:  %[[TMP:.*]] = alloca ptr, i64 1, align 8
+// CHECK:  %[[ARR_PTR:.*]] = getelementptr i32, ptr %[[ARR_ALLOCA]], i32 0
+// CHECK:  store i32 5, ptr %[[ARR_PTR]], align 4
+// CHECK:  %[[ELE_1_PTR:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i64 1
+// CHECK:  store ptr %[[ELE_1_PTR]], ptr %[[TMP]], align 8
+// CHECK:  %[[TMP2:.*]] = load ptr, ptr %[[TMP]], align 8
+// CHECK:  store i32 0, ptr %[[TMP2]], align 4
+// CHECK:  %[[ELE_1:.*]] = getelementptr i32, ptr %[[TMP2]], i64 1
+// CHECK:  store ptr %[[ELE_1]], ptr %[[TMP]], align 8
+
+void func3() {
+  int arr3[2] = {5, 6};
+}
+// CHECK: define void @func3()
+// CHECK:  %[[ARR_ALLOCA:.*]] = alloca [2 x i32], i64 1, align 4
+// CHECK:  %[[ARR_PTR:.*]] = getelementptr i32, ptr %[[ARR_ALLOCA]], i32 0
+// CHECK:  store i32 5, ptr %[[ARR_PTR]], align 4
+// CHECK:  %[[ELE_1_PTR:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i64 1
+// CHECK:  store i32 6, ptr %[[ELE_1_PTR]], align 4
+
+void func4() {
+  int arr4[2][1] = {{5}, {6}};
+}
+// 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
+
+void func5() {
+  int arr5[2][1] = {{5}};
+}
+// CHECK: define void @func5()
+// CHECK:  %[[ARR_ALLOCA:.*]] = alloca [2 x [1 x i32]], i64 1, align 4
+// CHECK:  %[[TMP:.*]] = alloca ptr, i64 1, align 8
+// CHECK:  %[[ARR_PTR:.*]] = getelementptr [1 x i32], ptr %[[ARR_ALLOCA]], i32 0
+// CHECK:  %[[ARR_0:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i32 0
+// CHECK:  store i32 5, ptr %[[ARR_0]], align 4
+// CHECK:  %[[ARR_1:.*]] = getelementptr [1 x i32], ptr %[[ARR_PTR]], i64 1
+// CHECK:  store ptr %[[ARR_1]], ptr %[[TMP]], align 8
+// CHECK:  %[[ARR_1_VAL:.*]] = load ptr, ptr %[[TMP]], align 8
+// CHECK:  store [1 x i32] zeroinitializer, ptr %[[ARR_1_VAL]], align 4
+// CHECK:  %[[ARR_1_PTR:.*]] = getelementptr [1 x i32], ptr %[[ARR_1_VAL]], 
i64 1
+// CHECK:  store ptr %[[ARR_1_PTR]], ptr %[[TMP]], align 8
+
+void func6() {
+  int x = 4;
+  int arr[2] = { x, 5 };
+}
+// CHECK: define void @func6()
+// CHECK:  %[[VAR:.*]] = alloca i32, i64 1, align 4
+// CHECK:  %[[ARR:.*]] = alloca [2 x i32], i64 1, align 4
+// CHECK:  store i32 4, ptr %[[VAR]], align 4
+// CHECK:  %[[ELE_0:.*]] = getelementptr i32, ptr %[[ARR]], i32 0
+// CHECK:  %[[TMP:.*]] = load i32, ptr %[[VAR]], align 4
+// CHECK:  store i32 %[[TMP]], ptr %[[ELE_0]], align 4
+// CHECK:  %[[ELE_1:.*]] = getelementptr i32, ptr %[[ELE_0]], i64 1
+// CHECK:  store i32 5, ptr %[[ELE_1]], align 4
+
+void func7(int p[10]) {}
+// CHECK: define void @func7(ptr {{%.*}})
 // CHECK-NEXT: alloca ptr, i64 1, align 8
 
-void func3(int pp[10][5]) {}
-// CHECK: define void @func3(ptr {{%.*}})
+void func8(int pp[10][5]) {}
+// CHECK: define void @func8(ptr {{%.*}})
 // CHECK-NEXT: alloca ptr, i64 1, align 8

>From ee9c92f81b1bf1f38c031a7e9aaa5b28ebfbc969 Mon Sep 17 00:00:00 2001
From: AmrDeveloper <am...@programmer.net>
Date: Tue, 25 Mar 2025 22:24:47 +0100
Subject: [PATCH 2/7] Address code review comments and add getConstantInt

---
 .../include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h |  5 +++++
 clang/include/clang/CIR/Dialect/IR/CIROps.td           |  3 ---
 clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp          | 10 +++-------
 clang/lib/CIR/CodeGen/CIRGenFunction.cpp               |  4 +---
 4 files changed, 9 insertions(+), 13 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h 
b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index 4c7e6ec061d46..1581b79c87a7e 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -32,6 +32,11 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
     return create<cir::ConstantOp>(loc, attr.getType(), attr);
   }
 
+  cir::ConstantOp getConstantInt(mlir::Location loc, mlir::Type ty,
+                                 int64_t value) {
+    return create<cir::ConstantOp>(loc, ty, cir::IntAttr::get(ty, value));
+  }
+
   // Creates constant null value for integral type ty.
   cir::ConstantOp getNullValue(mlir::Type ty, mlir::Location loc) {
     return create<cir::ConstantOp>(loc, ty, getZeroInitAttr(ty));
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 7784c8a51fdf3..01d0189c5cb9e 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -268,9 +268,6 @@ def PtrStrideOp : CIR_Op<"ptr_stride",
       return mlir::cast<cir::PointerType>(getBase().getType()).getPointee();
     }
   }];
-
-  // SameFirstOperandAndResultType already checks all we need.
-  let hasVerifier = 0;
 }
 
 
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
index 3bd898422f4d6..e1be99edeb4cf 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
@@ -122,8 +122,7 @@ void AggExprEmitter::emitArrayInit(Address destPtr, 
cir::ArrayType arrayTy,
   for (uint64_t i = 0; i != numInitElements; ++i) {
     // Advance to the next element.
     if (i > 0) {
-      one = builder.create<cir::ConstantOp>(
-          loc, cgf.PtrDiffTy, cir::IntAttr::get(cgf.PtrDiffTy, i));
+      one = builder.getConstantInt(loc, cgf.PtrDiffTy, i);
       element =
           builder.create<cir::PtrStrideOp>(loc, cirElementPtrType, begin, one);
     }
@@ -146,8 +145,7 @@ void AggExprEmitter::emitArrayInit(Address destPtr, 
cir::ArrayType arrayTy,
         cgf.getTypes().isZeroInitializable(elementType))) {
     // Advance to the start of the rest of the array.
     if (numInitElements) {
-      one = builder.create<cir::ConstantOp>(
-          loc, cgf.PtrDiffTy, cir::IntAttr::get(cgf.PtrDiffTy, 1));
+      one = builder.getConstantInt(loc, cgf.PtrDiffTy, 1);
       element = builder.create<cir::PtrStrideOp>(loc, cirElementPtrType,
                                                  element, one);
     }
@@ -173,9 +171,7 @@ void AggExprEmitter::emitArrayInit(Address destPtr, 
cir::ArrayType arrayTy,
         emitNullInitializationToLValue(loc, elementLV);
 
       // Advance pointer and store them to temporary variable
-      one = builder.create<cir::ConstantOp>(
-          loc, cgf.PtrDiffTy, cir::IntAttr::get(cgf.PtrDiffTy, 1));
-
+      one = builder.getConstantInt(loc, cgf.PtrDiffTy, 1);
       auto nextElement = builder.create<cir::PtrStrideOp>(
           loc, cirElementPtrType, currentElement, one);
       cgf.emitStoreThroughLValue(RValue::get(nextElement), tmpLV);
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp 
b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index ea24104e3075d..4390a18f496a8 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -489,9 +489,7 @@ void CIRGenFunction::emitNullInitialization(mlir::Location 
loc, Address destPtr,
   // Builder.CreateMemSet. In CIR just emit a store of #cir.zero to the
   // respective address.
   // Builder.CreateMemSet(DestPtr, Builder.getInt8(0), SizeVal, false);
-  auto zeroAttr = cir::ZeroAttr::get(builder.getContext(), convertType(ty));
-  auto zeroValue =
-      builder.create<cir::ConstantOp>(loc, convertType(ty), zeroAttr);
+  auto zeroValue = builder.getNullValue(convertType(ty), loc);
   builder.createStore(loc, zeroValue, destPtr.getPointer());
 }
 

>From d479f0d2c6ccc4698cf17803dc3f86e79c4918e6 Mon Sep 17 00:00:00 2001
From: AmrDeveloper <am...@programmer.net>
Date: Wed, 26 Mar 2025 00:01:47 +0100
Subject: [PATCH 3/7] Address code review comments

---
 clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h | 4 ++--
 clang/include/clang/CIR/Dialect/IR/CIROps.td             | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h 
b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index 1581b79c87a7e..c7165df2f92c0 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -34,12 +34,12 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
 
   cir::ConstantOp getConstantInt(mlir::Location loc, mlir::Type ty,
                                  int64_t value) {
-    return create<cir::ConstantOp>(loc, ty, cir::IntAttr::get(ty, value));
+    return getConstant(loc, cir::IntAttr::get(ty, value));
   }
 
   // Creates constant null value for integral type ty.
   cir::ConstantOp getNullValue(mlir::Type ty, mlir::Location loc) {
-    return create<cir::ConstantOp>(loc, ty, getZeroInitAttr(ty));
+    return getConstant(loc, getZeroInitAttr(ty));
   }
 
   cir::ConstantOp getBool(bool state, mlir::Location loc) {
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 01d0189c5cb9e..d77dd576d01f6 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -258,8 +258,8 @@ def PtrStrideOp : CIR_Op<"ptr_stride",
   let results = (outs CIR_PointerType:$result);
 
   let assemblyFormat = [{
-    `(` $base `:` qualified(type($base)) `,` $stride `:` 
qualified(type($stride)) `)`
-    `,` qualified(type($result)) attr-dict
+    `(` $base `:` qualified(type($base)) `,` $stride `:`
+    qualified(type($stride)) `)` `,` qualified(type($result)) attr-dict
   }];
 
   let extraClassDeclaration = [{

>From 9e10f04fcc5212fc087f6c6886d6565c5c1f5ac5 Mon Sep 17 00:00:00 2001
From: AmrDeveloper <am...@programmer.net>
Date: Wed, 26 Mar 2025 12:20:35 +0100
Subject: [PATCH 4/7] Address code review comments

---
 clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp | 21 +++++++++--------
 clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp  | 11 ++++-----
 clang/lib/CIR/CodeGen/CIRGenFunction.cpp      |  4 ++--
 clang/lib/CIR/CodeGen/CIRGenModule.h          |  5 ++--
 clang/lib/CIR/CodeGen/CIRGenTypes.cpp         |  7 ++++--
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp       |  4 ++--
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 16 ++++++-------
 clang/lib/CIR/Lowering/LoweringHelpers.cpp    |  8 +++----
 clang/test/CIR/CodeGen/array.cpp              | 23 +++++++++++++++----
 clang/test/CIR/Lowering/array.cpp             | 21 +++++++++++++----
 10 files changed, 73 insertions(+), 47 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
index e1be99edeb4cf..cdfb55f5565d9 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
@@ -159,7 +159,8 @@ void AggExprEmitter::emitArrayInit(Address destPtr, 
cir::ArrayType arrayTy,
 
     // TODO:Replace this part later with cir::DoWhileOp
     for (unsigned i = numInitElements; i != numArrayElements; ++i) {
-      auto currentElement = builder.createLoad(loc, tmpAddr.getPointer());
+      cir::LoadOp currentElement =
+          builder.createLoad(loc, tmpAddr.getPointer());
 
       // Emit the actual filler expression.
       const LValue elementLV = LValue::makeAddr(
@@ -183,22 +184,21 @@ void AggExprEmitter::emitInitializationToLValue(Expr *e, 
LValue lv) {
   const QualType type = lv.getType();
 
   if (isa<ImplicitValueInitExpr, CXXScalarValueInitExpr>(e)) {
-    const auto loc = e->getSourceRange().isValid()
-                         ? cgf.getLoc(e->getSourceRange())
-                         : *cgf.currSrcLoc;
+    const mlir::Location loc = e->getSourceRange().isValid()
+                                   ? cgf.getLoc(e->getSourceRange())
+                                   : *cgf.currSrcLoc;
     return emitNullInitializationToLValue(loc, lv);
   }
 
   if (isa<NoInitExpr>(e))
     return;
 
-  if (type->isReferenceType()) {
-    llvm_unreachable("NTI");
-  }
+  if (type->isReferenceType())
+    cgf.cgm.errorNYI("emitInitializationToLValue ReferenceType");
 
   switch (cgf.getEvaluationKind(type)) {
   case cir::TEK_Complex:
-    llvm_unreachable("TEK_Complex NYI");
+    cgf.cgm.errorNYI("emitInitializationToLValue TEK_Complex");
     break;
   case cir::TEK_Aggregate:
     cgf.emitAggExpr(e, AggValueSlot::forLValue(lv));
@@ -229,7 +229,7 @@ void 
AggExprEmitter::emitNullInitializationToLValue(mlir::Location loc,
       return;
     }
 
-    llvm_unreachable("emitStoreThroughBitfieldLValue NYI");
+    cgf.cgm.errorNYI("emitStoreThroughBitfieldLValue");
     return;
   }
 
@@ -265,7 +265,8 @@ void AggExprEmitter::visitCXXParenListOrInitListExpr(
     return;
   }
 
-  llvm_unreachable("NYI");
+  cgf.cgm.errorNYI(
+      "visitCXXParenListOrInitListExpr Record or VariableSizeArray type");
 }
 
 void CIRGenFunction::emitAggExpr(const Expr *e, AggValueSlot slot) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
index 06fcc0e2c040a..50fa029851f33 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
@@ -421,17 +421,16 @@ mlir::Value CIRGenModule::emitNullConstant(QualType t, 
mlir::Location loc) {
   if (getTypes().isZeroInitializable(t))
     return builder.getNullValue(getTypes().convertTypeForMem(t), loc);
 
-  if (const ConstantArrayType *cat =
-          getASTContext().getAsConstantArrayType(t)) {
-    llvm_unreachable("NYI");
+  if (getASTContext().getAsConstantArrayType(t)) {
+    errorNYI("CIRGenModule::emitNullConstant ConstantArrayType");
   }
 
-  if (const RecordType *rt = t->getAs<RecordType>())
-    llvm_unreachable("NYI");
+  if (t->getAs<RecordType>())
+    errorNYI("CIRGenModule::emitNullConstant RecordType");
 
   assert(t->isMemberDataPointerType() &&
          "Should only see pointers to data members here!");
 
-  llvm_unreachable("NYI");
+  errorNYI("CIRGenModule::emitNullConstant unsupported type");
   return {};
 }
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp 
b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index 4390a18f496a8..b02eb3f283eea 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -461,7 +461,7 @@ void CIRGenFunction::emitNullInitialization(mlir::Location 
loc, Address destPtr,
 
   // Cast the dest ptr to the appropriate i8 pointer type.
   if (builder.isInt8Ty(destPtr.getElementType())) {
-    llvm_unreachable("NYI");
+    cgm.errorNYI(loc, "Cast the dest ptr to the appropriate i8 pointer type");
   }
 
   // Get size and alignment info for this aggregate.
@@ -489,7 +489,7 @@ void CIRGenFunction::emitNullInitialization(mlir::Location 
loc, Address destPtr,
   // Builder.CreateMemSet. In CIR just emit a store of #cir.zero to the
   // respective address.
   // Builder.CreateMemSet(DestPtr, Builder.getInt8(0), SizeVal, false);
-  auto zeroValue = builder.getNullValue(convertType(ty), loc);
+  const mlir::Value zeroValue = builder.getNullValue(convertType(ty), loc);
   builder.createStore(loc, zeroValue, destPtr.getPointer());
 }
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h 
b/clang/lib/CIR/CodeGen/CIRGenModule.h
index 87a9eef16e7f9..6ba1ccc4ddd9f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.h
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -113,9 +113,8 @@ class CIRGenModule : public CIRGenTypeCache {
   void emitGlobalVarDefinition(const clang::VarDecl *vd,
                                bool isTentative = false);
 
-  // Return the result of value-initializing the given type, i.e. a null
-  /// expression of the given type.  This is usually, but not always, an LLVM
-  /// null constant.
+  /// Return the result of value-initializing the given type, i.e. a null
+  /// expression of the given type.
   mlir::Value emitNullConstant(QualType t, mlir::Location loc);
 
   cir::FuncOp
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp 
b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
index 2684fde728fa0..1e47ccc451b86 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
@@ -268,13 +268,16 @@ bool CIRGenTypes::isZeroInitializable(clang::QualType t) {
         return true;
   }
 
-  if (const RecordType *rt = t->getAs<RecordType>()) {
+  if (t->getAs<RecordType>()) {
     cgm.errorNYI(SourceLocation(), "isZeroInitializable for RecordType", t);
+    return false;
   }
 
-  if (const MemberPointerType *mpt = t->getAs<MemberPointerType>())
+  if (t->getAs<MemberPointerType>()) {
     cgm.errorNYI(SourceLocation(), "isZeroInitializable for MemberPointerType",
                  t);
+    return false;
+  }
 
   return true;
 }
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp 
b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 99f9670c02d28..ae0ea967f74fd 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -246,8 +246,8 @@ OpFoldResult cir::ConstantOp::fold(FoldAdaptor /*adaptor*/) 
{
 
//===----------------------------------------------------------------------===//
 
 LogicalResult cir::CastOp::verify() {
-  const auto resType = getResult().getType();
-  const auto srcType = getSrc().getType();
+  const mlir::Type resType = getResult().getType();
+  const mlir::Type srcType = getSrc().getType();
 
   switch (getKind()) {
   case cir::CastKind::int_to_bool: {
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 56b4e2a5ad03d..b547e598dd70f 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -546,8 +546,6 @@ mlir::LogicalResult 
CIRToLLVMPtrStrideOpLowering::matchAndRewrite(
     cir::PtrStrideOp ptrStrideOp, OpAdaptor adaptor,
     mlir::ConversionPatternRewriter &rewriter) const {
 
-  const mlir::DataLayout llvmLayout(
-      ptrStrideOp->getParentOfType<mlir::ModuleOp>());
   const mlir::TypeConverter *tc = getTypeConverter();
   const mlir::Type resultTy = tc->convertType(ptrStrideOp.getType());
 
@@ -566,9 +564,9 @@ mlir::LogicalResult 
CIRToLLVMPtrStrideOpLowering::matchAndRewrite(
   const unsigned width =
       mlir::cast<mlir::IntegerType>(index.getType()).getWidth();
   const std::optional<std::uint64_t> layoutWidth =
-      llvmLayout.getTypeIndexBitwidth(adaptor.getBase().getType());
+      dataLayout.getTypeIndexBitwidth(adaptor.getBase().getType());
 
-  const auto indexOp = index.getDefiningOp();
+  mlir::Operation *indexOp = index.getDefiningOp();
   if (indexOp && layoutWidth && width != *layoutWidth) {
     // If the index comes from a subtraction, make sure the extension happens
     // before it. To achieve that, look at unary minus, which already got
@@ -691,7 +689,7 @@ mlir::Value lowerCirAttrAsValue(mlir::Operation *parentOp,
                                 const mlir::TypeConverter *converter,
                                 mlir::DataLayout const &dataLayout) {
   CIRAttrToValue valueConverter(parentOp, rewriter, converter);
-  auto value = valueConverter.visit(attr);
+  const mlir::Value value = valueConverter.visit(attr);
   if (!value)
     llvm_unreachable("unhandled attribute type");
   return value;
@@ -751,16 +749,16 @@ mlir::LogicalResult 
CIRToLLVMConstantOpLowering::matchAndRewrite(
 
     std::optional<mlir::Attribute> denseAttr;
     if (constArr && hasTrailingZeros(constArr)) {
-      auto newOp = lowerCirAttrAsValue(op, constArr, rewriter,
-                                       getTypeConverter(), dataLayout);
+      const mlir::Value newOp = lowerCirAttrAsValue(
+          op, constArr, rewriter, getTypeConverter(), dataLayout);
       rewriter.replaceOp(op, newOp);
       return mlir::success();
     } else if (constArr &&
                (denseAttr = lowerConstArrayAttr(constArr, typeConverter))) {
       attr = denseAttr.value();
     } else {
-      auto initVal = lowerCirAttrAsValue(op, op.getValue(), rewriter,
-                                         typeConverter, dataLayout);
+      const mlir::Value initVal = lowerCirAttrAsValue(
+          op, op.getValue(), rewriter, typeConverter, dataLayout);
       rewriter.replaceAllUsesWith(op, initVal);
       rewriter.eraseOp(op);
       return mlir::success();
diff --git a/clang/lib/CIR/Lowering/LoweringHelpers.cpp 
b/clang/lib/CIR/Lowering/LoweringHelpers.cpp
index e0635d97fceb5..2c638f0f8c8a7 100644
--- a/clang/lib/CIR/Lowering/LoweringHelpers.cpp
+++ b/clang/lib/CIR/Lowering/LoweringHelpers.cpp
@@ -16,14 +16,12 @@ mlir::DenseElementsAttr
 convertStringAttrToDenseElementsAttr(cir::ConstArrayAttr attr,
                                      mlir::Type type) {
   auto values = llvm::SmallVector<mlir::APInt, 8>{};
-  const auto stringAttr = mlir::dyn_cast<mlir::StringAttr>(attr.getElts());
-  assert(stringAttr && "expected string attribute here");
+  const auto stringAttr = mlir::cast<mlir::StringAttr>(attr.getElts());
 
-  for (auto element : stringAttr)
+  for (const char element : stringAttr)
     values.push_back({8, (uint64_t)element});
 
-  const auto arrayTy = mlir::dyn_cast<cir::ArrayType>(attr.getType());
-  assert(arrayTy && "String attribute must have an array type");
+  const auto arrayTy = mlir::cast<cir::ArrayType>(attr.getType());
   if (arrayTy.getSize() != stringAttr.size())
     llvm_unreachable("array type of the length not equal to that of the string 
"
                      "attribute is not supported yet");
diff --git a/clang/test/CIR/CodeGen/array.cpp b/clang/test/CIR/CodeGen/array.cpp
index 29313e6960896..ece73ac7b555a 100644
--- a/clang/test/CIR/CodeGen/array.cpp
+++ b/clang/test/CIR/CodeGen/array.cpp
@@ -117,10 +117,25 @@ void func6() {
   // CHECK: cir.store %[[V1]], %[[ELE_PTR]] : !s32i, !cir.ptr<!s32i>
 }
 
-void func7(int p[10]) {}
-// CHECK: cir.func @func7(%arg0: !cir.ptr<!s32i>
+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>>>
+}
+
+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]
 
-void func8(int pp[10][5]) {}
-// CHECK: cir.func @func8(%arg0: !cir.ptr<!cir.array<!s32i x 5>>
+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>>>
diff --git a/clang/test/CIR/Lowering/array.cpp 
b/clang/test/CIR/Lowering/array.cpp
index 692f82ddf201a..460e9ce2f8366 100644
--- a/clang/test/CIR/Lowering/array.cpp
+++ b/clang/test/CIR/Lowering/array.cpp
@@ -102,10 +102,23 @@ void func6() {
 // CHECK:  %[[ELE_1:.*]] = getelementptr i32, ptr %[[ELE_0]], i64 1
 // CHECK:  store i32 5, ptr %[[ELE_1]], align 4
 
-void func7(int p[10]) {}
-// CHECK: define void @func7(ptr {{%.*}})
+void func7() {
+  int* arr[1] = {};
+}
+// CHECK: define void @func7()
+// CHECK:  %[[ARR:.*]] = alloca [1 x ptr], i64 1, align 8
+// CHECK:  %[[ALLOCA:.*]] = alloca ptr, i64 1, align 8
+// CHECK:  %[[ELE_PTR:.*]] = getelementptr ptr, ptr %[[ARR]], i32 0
+// CHECK:  store ptr %[[ELE_PTR]], ptr %[[ALLOCA]], align 8
+// CHECK:  %[[TMP:.*]] = load ptr, ptr %[[ALLOCA]], align 8
+// CHECK:  store ptr null, ptr %[[TMP]], align 8
+// CHECK:  %[[ELE:.*]] = getelementptr ptr, ptr %[[TMP]], i64 1
+// CHECK:  store ptr %[[ELE]], ptr %[[ALLOCA]], align 8
+
+void func8(int p[10]) {}
+// CHECK: define void @func8(ptr {{%.*}})
 // CHECK-NEXT: alloca ptr, i64 1, align 8
 
-void func8(int pp[10][5]) {}
-// CHECK: define void @func8(ptr {{%.*}})
+void func9(int pp[10][5]) {}
+// CHECK: define void @func9(ptr {{%.*}})
 // CHECK-NEXT: alloca ptr, i64 1, align 8

>From ed0a86bf05aaf6c2566c4c69270fbc3adccaf489 Mon Sep 17 00:00:00 2001
From: AmrDeveloper <am...@programmer.net>
Date: Wed, 26 Mar 2025 23:33:00 +0100
Subject: [PATCH 5/7] Address code review comments

---
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 21 ++++---------------
 clang/lib/CIR/Lowering/LoweringHelpers.cpp    |  8 +++----
 2 files changed, 7 insertions(+), 22 deletions(-)

diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index b547e598dd70f..24187bc29e088 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -682,19 +682,6 @@ mlir::LogicalResult 
CIRToLLVMStoreOpLowering::matchAndRewrite(
   return mlir::LogicalResult::success();
 }
 
-/// Switches on the type of attribute and calls the appropriate conversion.
-mlir::Value lowerCirAttrAsValue(mlir::Operation *parentOp,
-                                const mlir::Attribute attr,
-                                mlir::ConversionPatternRewriter &rewriter,
-                                const mlir::TypeConverter *converter,
-                                mlir::DataLayout const &dataLayout) {
-  CIRAttrToValue valueConverter(parentOp, rewriter, converter);
-  const mlir::Value value = valueConverter.visit(attr);
-  if (!value)
-    llvm_unreachable("unhandled attribute type");
-  return value;
-}
-
 bool hasTrailingZeros(cir::ConstArrayAttr attr) {
   auto array = mlir::dyn_cast<mlir::ArrayAttr>(attr.getElts());
   return attr.hasTrailingZeros() ||
@@ -749,16 +736,16 @@ mlir::LogicalResult 
CIRToLLVMConstantOpLowering::matchAndRewrite(
 
     std::optional<mlir::Attribute> denseAttr;
     if (constArr && hasTrailingZeros(constArr)) {
-      const mlir::Value newOp = lowerCirAttrAsValue(
-          op, constArr, rewriter, getTypeConverter(), dataLayout);
+      const mlir::Value newOp =
+          lowerCirAttrAsValue(op, constArr, rewriter, getTypeConverter());
       rewriter.replaceOp(op, newOp);
       return mlir::success();
     } else if (constArr &&
                (denseAttr = lowerConstArrayAttr(constArr, typeConverter))) {
       attr = denseAttr.value();
     } else {
-      const mlir::Value initVal = lowerCirAttrAsValue(
-          op, op.getValue(), rewriter, typeConverter, dataLayout);
+      const mlir::Value initVal =
+          lowerCirAttrAsValue(op, op.getValue(), rewriter, typeConverter);
       rewriter.replaceAllUsesWith(op, initVal);
       rewriter.eraseOp(op);
       return mlir::success();
diff --git a/clang/lib/CIR/Lowering/LoweringHelpers.cpp 
b/clang/lib/CIR/Lowering/LoweringHelpers.cpp
index 2c638f0f8c8a7..8c5dac38bf1b9 100644
--- a/clang/lib/CIR/Lowering/LoweringHelpers.cpp
+++ b/clang/lib/CIR/Lowering/LoweringHelpers.cpp
@@ -117,14 +117,11 @@ mlir::DenseElementsAttr convertToDenseElementsAttr(
 std::optional<mlir::Attribute>
 lowerConstArrayAttr(cir::ConstArrayAttr constArr,
                     const mlir::TypeConverter *converter) {
-
   // Ensure ConstArrayAttr has a type.
-  auto typedConstArr = mlir::dyn_cast<mlir::TypedAttr>(constArr);
-  assert(typedConstArr && "cir::ConstArrayAttr is not a mlir::TypedAttr");
+  const auto typedConstArr = mlir::cast<mlir::TypedAttr>(constArr);
 
   // Ensure ConstArrayAttr type is a ArrayType.
-  auto cirArrayType = mlir::dyn_cast<cir::ArrayType>(typedConstArr.getType());
-  assert(cirArrayType && "cir::ConstArrayAttr is not a cir::ArrayType");
+  const auto cirArrayType = 
mlir::cast<cir::ArrayType>(typedConstArr.getType());
 
   // Is a ConstArrayAttr with an cir::ArrayType: fetch element type.
   mlir::Type type = cirArrayType;
@@ -140,6 +137,7 @@ lowerConstArrayAttr(cir::ConstArrayAttr constArr,
   if (mlir::isa<cir::IntType>(type))
     return convertToDenseElementsAttr<cir::IntAttr, mlir::APInt>(
         constArr, dims, type, converter->convertType(type));
+
   if (mlir::isa<cir::CIRFPTypeInterface>(type))
     return convertToDenseElementsAttr<cir::FPAttr, mlir::APFloat>(
         constArr, dims, type, converter->convertType(type));

>From 56ef35e480f3317c58629677cdf6821a0ef4caba Mon Sep 17 00:00:00 2001
From: AmrDeveloper <am...@programmer.net>
Date: Thu, 27 Mar 2025 14:43:03 +0100
Subject: [PATCH 6/7] Add missing features

---
 clang/include/clang/CIR/MissingFeatures.h  | 1 +
 clang/lib/CIR/Lowering/LoweringHelpers.cpp | 4 ++--
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/clang/include/clang/CIR/MissingFeatures.h 
b/clang/include/clang/CIR/MissingFeatures.h
index 3e33e5dc60194..d3dfcb7dfb8ce 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -111,6 +111,7 @@ struct MissingFeatures {
   static bool scalableVectors() { return false; }
   static bool unsizedTypes() { return false; }
   static bool vectorType() { return false; }
+  static bool stringTypeWithDifferentArraySize() { return false; }
 
   // Future CIR operations
   static bool awaitOp() { return false; }
diff --git a/clang/lib/CIR/Lowering/LoweringHelpers.cpp 
b/clang/lib/CIR/Lowering/LoweringHelpers.cpp
index 8c5dac38bf1b9..0320bc40509b0 100644
--- a/clang/lib/CIR/Lowering/LoweringHelpers.cpp
+++ b/clang/lib/CIR/Lowering/LoweringHelpers.cpp
@@ -11,6 +11,7 @@
 
//===----------------------------------------------------------------------===//
 
 #include "clang/CIR/LoweringHelpers.h"
+#include "clang/CIR/MissingFeatures.h"
 
 mlir::DenseElementsAttr
 convertStringAttrToDenseElementsAttr(cir::ConstArrayAttr attr,
@@ -23,8 +24,7 @@ convertStringAttrToDenseElementsAttr(cir::ConstArrayAttr attr,
 
   const auto arrayTy = mlir::cast<cir::ArrayType>(attr.getType());
   if (arrayTy.getSize() != stringAttr.size())
-    llvm_unreachable("array type of the length not equal to that of the string 
"
-                     "attribute is not supported yet");
+    assert(!cir::MissingFeatures::stringTypeWithDifferentArraySize());
 
   return mlir::DenseElementsAttr::get(
       mlir::RankedTensorType::get({(int64_t)values.size()}, type),

>From e814e46d95d36ac2473eaba7802b5531be0c4cf9 Mon Sep 17 00:00:00 2001
From: AmrDeveloper <am...@programmer.net>
Date: Mon, 31 Mar 2025 21:10:35 +0200
Subject: [PATCH 7/7] Fix merge conflict

---
 clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h | 2 +-
 clang/lib/CIR/CodeGen/CIRGenBuilder.h                    | 4 ----
 clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp            | 2 +-
 3 files changed, 2 insertions(+), 6 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h 
b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index 67be5a861053a..cbde73bbba53d 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -76,7 +76,7 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
   cir::ConstantOp getNullValue(mlir::Type ty, mlir::Location loc) {
     return getConstant(loc, getZeroInitAttr(ty));
   }
-  
+
   mlir::TypedAttr getConstNullPtrAttr(mlir::Type t) {
     assert(mlir::isa<cir::PointerType>(t) && "expected cir.ptr");
     return getConstPtrAttr(t, 0);
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h 
b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index 71385a465336e..03fb227a464a1 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -141,10 +141,6 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
   }
   bool isInt(mlir::Type i) { return mlir::isa<cir::IntType>(i); }
 
-  bool isInt8Ty(mlir::Type i) {
-    return i == typeCache.UInt8Ty || i == typeCache.SInt8Ty;
-  }
-
   // Creates constant nullptr for pointer type ty.
   cir::ConstantOp getNullPtr(mlir::Type ty, mlir::Location loc) {
     assert(!cir::MissingFeatures::targetCodeGenInfoGetNullPointer());
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
index cdfb55f5565d9..0c5e31eafdc8d 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
@@ -153,7 +153,7 @@ void AggExprEmitter::emitArrayInit(Address destPtr, 
cir::ArrayType arrayTy,
     // Allocate the temporary variable
     // to store the pointer to first unitialized element
     auto tmpAddr = cgf.createTempAlloca(
-        cirElementPtrType, cgf.getPointerAlign(), loc, "arrayinit.temp");
+        cirElementPtrType, cgf.getPointerAlign(), loc, "arrayinit.temp", 
false);
     LValue tmpLV = LValue::makeAddr(tmpAddr, elementPtrType);
     cgf.emitStoreThroughLValue(RValue::get(element), tmpLV);
 

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

Reply via email to