-
Notifications
You must be signed in to change notification settings - Fork 13.3k
[CIR][Upstream] Local initialization for ArrayType #132974
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[CIR][Upstream] Local initialization for ArrayType #132974
Conversation
@llvm/pr-subscribers-clang Author: Amr Hesham (AmrDeveloper) ChangesThis change adds local initialization for ArrayType Issue #130197 Patch is 59.03 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/132974.diff 25 Files Affected:
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().convertTypeForM...
[truncated]
|
@llvm/pr-subscribers-clangir Author: Amr Hesham (AmrDeveloper) ChangesThis change adds local initialization for ArrayType Issue #130197 Patch is 59.03 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/132974.diff 25 Files Affected:
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().convertTypeForM...
[truncated]
|
// respective address. | ||
// Builder.CreateMemSet(DestPtr, Builder.getInt8(0), SizeVal, false); | ||
auto zeroAttr = cir::ZeroAttr::get(builder.getContext(), convertType(ty)); | ||
auto zeroValue = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use builder.getNullValue
instead explicit operation creation and duplicit type conversion.
// SameFirstOperandAndResultType already checks all we need. | ||
let hasVerifier = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need for it as it is 0
by default.
// SameFirstOperandAndResultType already checks all we need. | |
let hasVerifier = 0; |
for (uint64_t i = 0; i != numInitElements; ++i) { | ||
// Advance to the next element. | ||
if (i > 0) { | ||
one = builder.create<cir::ConstantOp>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use builder.getConstant
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe worth adding builder.getConstantInt
method as this repeats a lot
cgf.getTypes().isZeroInitializable(elementType))) { | ||
// Advance to the start of the rest of the array. | ||
if (numInitElements) { | ||
one = builder.create<cir::ConstantOp>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use builder.getConstant
emitNullInitializationToLValue(loc, elementLV); | ||
|
||
// Advance pointer and store them to temporary variable | ||
one = builder.create<cir::ConstantOp>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use getConstant
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have only minor inline comments, good direction.
The PR is a bit big but I can see this requires touching everywhere in CIRGen and also LLVM lowering support, which is good end-to-end testing.
If there are things there are not needed right now, it'd be better to remove it for extra clarity. Have you checked that?
I already removed some parts like TypeSizeInfoAttr and AddrSpace before creating the PR for that reason, I will double check again if I can remove anything else |
return; | ||
} | ||
|
||
llvm_unreachable("emitStoreThroughBitfieldLValue NYI"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
llvm_unreachable("emitStoreThroughBitfieldLValue NYI"); | |
cgf.cgm.errorNYI("emitStoreThroughBitfieldLValue"); |
|
||
void AggExprEmitter::VisitInitListExpr(InitListExpr *e) { | ||
if (e->hadArrayRangeDesignator()) | ||
llvm_unreachable("GNU array range designator extension"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
errorNYI
return; | ||
} | ||
|
||
llvm_unreachable("NYI"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
errorNYI with more detail
if (getTypes().isZeroInitializable(t)) | ||
return builder.getNullValue(getTypes().convertTypeForMem(t), loc); | ||
|
||
if (const ConstantArrayType *cat = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove the unused variable here to avoid introducing a warning.
|
||
if (const ConstantArrayType *cat = | ||
getASTContext().getAsConstantArrayType(t)) { | ||
llvm_unreachable("NYI"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
erroNYI with more detail
|
||
// TODO:Replace this part later with cir::DoWhileOp | ||
for (unsigned i = numInitElements; i != numArrayElements; ++i) { | ||
auto currentElement = builder.createLoad(loc, tmpAddr.getPointer()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No auto here
const QualType type = lv.getType(); | ||
|
||
if (isa<ImplicitValueInitExpr, CXXScalarValueInitExpr>(e)) { | ||
const auto loc = e->getSourceRange().isValid() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No auto
return; | ||
|
||
if (type->isReferenceType()) { | ||
llvm_unreachable("NTI"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
errorNYI
|
||
switch (cgf.getEvaluationKind(type)) { | ||
case cir::TEK_Complex: | ||
llvm_unreachable("TEK_Complex NYI"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
errorNYI
I'm not sure it's worth splitting up now, but you probably could have implemented the zero-initialization case by itself as a preliminary patch. |
@@ -620,6 +682,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, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was already a definition of this function. What you're adding here only differs in that it adds a dataLayout argument which isn't used.
std::optional<mlir::Attribute> denseAttr; | ||
if (constArr && hasTrailingZeros(constArr)) { | ||
const mlir::Value newOp = lowerCirAttrAsValue( | ||
op, constArr, rewriter, getTypeConverter(), dataLayout); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
op, constArr, rewriter, getTypeConverter(), dataLayout); | |
op, constArr, rewriter, getTypeConverter()); |
attr = denseAttr.value(); | ||
} else { | ||
const mlir::Value initVal = lowerCirAttrAsValue( | ||
op, op.getValue(), rewriter, typeConverter, dataLayout); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
op, op.getValue(), rewriter, typeConverter, dataLayout); | |
op, op.getValue(), rewriter, typeConverter); |
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 " |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not suggesting errorNYI
. I'm suggesting op.emitError()
. We can't do that here either, but maybe we could do it in the function from which this is called?
✅ With the latest revision this PR passed the C/C++ code formatter. |
a7f3849
to
ed0a86b
Compare
I think it's easier to keep it as assert, llvm_unreachable or a missing features as the error message mention, because otherwise we will modify the function to return nullptr to flag this case and also to modify the caller to catch it and report, also we don't have Operator to use it to emitError, what do you think? @andykaylor |
I suppose MissingFeatures would be fine. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have anything else to add, LGTM!
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)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let merge the zero-init change first and rebase this one to get the changes there.
@@ -327,4 +337,4 @@ class CIRBaseBuilderTy : public mlir::OpBuilder { | |||
|
|||
} // namespace cir | |||
|
|||
#endif | |||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This indicates that you (or some tool you're using) removed the newline character at the end of the file. It's a good practice to configure your editor to automatically add a newline at the end if it's missing. If you use the VSCode editor, the text editor has a setting called "Insert Final Newline" that does this.
AggValueSlot ensureSlot(mlir::Location loc, QualType t) { | ||
if (!dest.isIgnored()) | ||
return dest; | ||
llvm_unreachable("Slot for ignored address NTI"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
llvm_unreachable("Slot for ignored address NTI"); | |
cgf.cgm.errorNYI(loc, "Slot for ignored address"); |
cgf.getContext().getAsArrayType(arrayQTy)->getElementType(); | ||
|
||
if (elementType.isDestructedType()) { | ||
llvm_unreachable("dtorKind NYI"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
errorNYI
if (i > 0) { | ||
one = builder.getConstantInt(loc, cgf.PtrDiffTy, i); | ||
element = | ||
builder.create<cir::PtrStrideOp>(loc, cirElementPtrType, begin, one); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer createPtrStride()
added in the base builder class.
// Allocate the temporary variable | ||
// to store the pointer to first unitialized element | ||
auto tmpAddr = cgf.createTempAlloca( | ||
cirElementPtrType, cgf.getPointerAlign(), loc, "arrayinit.temp", false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cirElementPtrType, cgf.getPointerAlign(), loc, "arrayinit.temp", false); | |
cirElementPtrType, cgf.getPointerAlign(), loc, "arrayinit.temp", | |
/*insertIntoFnEntryBlock=*/false); |
|
||
// Allocate the temporary variable | ||
// to store the pointer to first unitialized element | ||
auto tmpAddr = cgf.createTempAlloca( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't use auto here.
|
||
// Advance pointer and store them to temporary variable | ||
one = builder.getConstantInt(loc, cgf.PtrDiffTy, 1); | ||
auto nextElement = builder.create<cir::PtrStrideOp>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As above, I'd prefer createPtrStride()
and that will mean you shouldn't use auto
.
|
||
if (cgf.hasScalarEvaluationKind(type)) { | ||
// For non-aggregates, we can store the appropriate null constant. | ||
auto null = cgf.cgm.emitNullConstant(type, loc); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No auto
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have comments here other than what Andy suggested, so get those fixed/make him happy, and I'm happy when he is.
7d486df
to
9a9e494
Compare
I addressed all comments, CI is red because unrelated reason. |
@@ -110,6 +110,10 @@ class CIRGenFunction : public CIRGenTypeCache { | |||
public: | |||
mlir::Value createDummyValue(mlir::Location loc, clang::QualType qt); | |||
|
|||
void emitAggExpr(const clang::Expr *e, AggValueSlot slot); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These should be moved to the place where other emit*
functions are declared and inserted in alphabetical order.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, thanks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks ready.
@@ -110,6 +110,8 @@ class CIRGenFunction : public CIRGenTypeCache { | |||
public: | |||
mlir::Value createDummyValue(mlir::Location loc, clang::QualType qt); | |||
|
|||
void emitNullInitialization(mlir::Location loc, Address destPtr, QualType ty); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The two emit functions you've added are still not in the correct place, but that's fine. Some others have gotten out of order too, so I'll make another reordering patch after this is merged.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you, Currently I have time if you prefer, I can handle it
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/17/builds/7001 Here is the relevant piece of the build log for the reference
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/201/builds/3938 Here is the relevant piece of the build log for the reference
|
This change adds local initialization for ArrayType
Issue #130197