-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[CIR] Emit copy for aggregate initialization #155697
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
Conversation
@llvm/pr-subscribers-clang @llvm/pr-subscribers-clangir Author: Andy Kaylor (andykaylor) ChangesThis adds the implementation of aggEmitFinalDestCopy for the case where the destination value is not ignored. This requires adding the cir.copy operation and associated interface code. Patch is 26.46 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/155697.diff 15 Files Affected:
diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index d29e5687d2544..fd77db2680903 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -247,6 +247,11 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
return createGetGlobal(global.getLoc(), global);
}
+ /// Create a copy with inferred length.
+ cir::CopyOp createCopy(mlir::Value dst, mlir::Value src) {
+ return cir::CopyOp::create(*this, dst.getLoc(), dst, src);
+ }
+
cir::StoreOp createStore(mlir::Location loc, mlir::Value val, mlir::Value dst,
bool isVolatile = false,
mlir::IntegerAttr align = {},
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 2b7a709b80c26..40a297cb7a807 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2431,6 +2431,51 @@ def CIR_CallOp : CIR_CallOpBase<"call", [NoRegionArguments]> {
];
}
+//===----------------------------------------------------------------------===//
+// CopyOp
+//===----------------------------------------------------------------------===//
+
+def CIR_CopyOp : CIR_Op<"copy",[
+ SameTypeOperands,
+ DeclareOpInterfaceMethods<PromotableMemOpInterface>
+]> {
+ let arguments = (ins
+ Arg<CIR_PointerType, "", [MemWrite]>:$dst,
+ Arg<CIR_PointerType, "", [MemRead]>:$src
+ );
+ let summary = "Copies contents from a CIR pointer to another";
+ let description = [{
+ Given two CIR pointers, `src` and `dst`, `cir.copy` will copy the memory
+ pointed by `src` to the memory pointed by `dst`.
+
+ The number of bytes copied is inferred from the pointee type. The pointee
+ type of `src` and `dst` must match and both must implement the
+ `DataLayoutTypeInterface`.
+
+ Examples:
+
+ ```mlir
+ // Copying contents from one record to another:
+ cir.copy %0 to %1 : !cir.ptr<!record_ty>
+ ```
+ }];
+
+ let assemblyFormat = [{$src `to` $dst
+ attr-dict `:` qualified(type($dst))
+ }];
+ let hasVerifier = 1;
+
+ let extraClassDeclaration = [{
+ /// Returns the pointer type being copied.
+ cir::PointerType getType() { return getSrc().getType(); }
+
+ /// Returns the number of bytes to be copied.
+ unsigned getLength() {
+ return mlir::DataLayout::closest(*this).getTypeSize(getType().getPointee());
+ }
+ }];
+}
+
//===----------------------------------------------------------------------===//
// ReturnAddrOp and FrameAddrOp
//===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index a8be2a2374d6e..8a49ee4bc9c71 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -168,6 +168,7 @@ struct MissingFeatures {
// Misc
static bool abiArgInfo() { return false; }
static bool addHeapAllocSiteMetadata() { return false; }
+ static bool aggEmitFinalDestCopyRValue() { return false; }
static bool aggValueSlot() { return false; }
static bool aggValueSlotAlias() { return false; }
static bool aggValueSlotDestructedFlag() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
index 113f9961d2b48..07a2e39dc924c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
@@ -62,12 +62,19 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
/// Perform the final copy to DestPtr, if desired.
void emitFinalDestCopy(QualType type, const LValue &src);
+ void emitCopy(QualType type, const AggValueSlot &dest,
+ const AggValueSlot &src);
+
void emitInitializationToLValue(Expr *e, LValue lv);
void emitNullInitializationToLValue(mlir::Location loc, LValue lv);
void Visit(Expr *e) { StmtVisitor<AggExprEmitter>::Visit(e); }
+ void VisitArraySubscriptExpr(ArraySubscriptExpr *e) {
+ emitAggLoadOfLValue(e);
+ }
+
void VisitCallExpr(const CallExpr *e);
void VisitStmtExpr(const StmtExpr *e) {
CIRGenFunction::StmtExprEvaluation eval(cgf);
@@ -91,13 +98,6 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
}
// Stubs -- These should be moved up when they are implemented.
- void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *e) {
- // We shouldn't really get here, but we do because of missing handling for
- // emitting constant aggregate initializers. If we just ignore this, a
- // fallback handler will do the right thing.
- assert(!cir::MissingFeatures::constEmitterAggILE());
- return;
- }
void VisitCastExpr(CastExpr *e) {
switch (e->getCastKind()) {
case CK_LValueToRValue:
@@ -163,10 +163,6 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
cgf.cgm.errorNYI(e->getSourceRange(),
"AggExprEmitter: VisitCompoundLiteralExpr");
}
- void VisitArraySubscriptExpr(ArraySubscriptExpr *e) {
- cgf.cgm.errorNYI(e->getSourceRange(),
- "AggExprEmitter: VisitArraySubscriptExpr");
- }
void VisitPredefinedExpr(const PredefinedExpr *e) {
cgf.cgm.errorNYI(e->getSourceRange(),
"AggExprEmitter: VisitPredefinedExpr");
@@ -456,7 +452,31 @@ void AggExprEmitter::emitFinalDestCopy(QualType type, const LValue &src) {
if (dest.isIgnored())
return;
- cgf.cgm.errorNYI("emitFinalDestCopy: non-ignored dest is NYI");
+ assert(!cir::MissingFeatures::aggValueSlotVolatile());
+ assert(!cir::MissingFeatures::aggEmitFinalDestCopyRValue());
+ assert(!cir::MissingFeatures::aggValueSlotGC());
+
+ AggValueSlot srcAgg = AggValueSlot::forLValue(src, AggValueSlot::IsDestructed,
+ AggValueSlot::IsAliased,
+ AggValueSlot::MayOverlap);
+ emitCopy(type, dest, srcAgg);
+}
+
+/// Perform a copy from the source into the destination.
+///
+/// \param type - the type of the aggregate being copied; qualifiers are
+/// ignored
+void AggExprEmitter::emitCopy(QualType type, const AggValueSlot &dest,
+ const AggValueSlot &src) {
+ assert(!cir::MissingFeatures::aggValueSlotGC());
+
+ // If the result of the assignment is used, copy the LHS there also.
+ // It's volatile if either side is. Use the minimum alignment of
+ // the two sides.
+ LValue destLV = cgf.makeAddrLValue(dest.getAddress(), type);
+ LValue srcLV = cgf.makeAddrLValue(src.getAddress(), type);
+ assert(!cir::MissingFeatures::aggValueSlotVolatile());
+ cgf.emitAggregateCopy(destLV, srcLV, type, dest.mayOverlap());
}
void AggExprEmitter::emitInitializationToLValue(Expr *e, LValue lv) {
@@ -708,6 +728,68 @@ void CIRGenFunction::emitAggExpr(const Expr *e, AggValueSlot slot) {
AggExprEmitter(*this, slot).Visit(const_cast<Expr *>(e));
}
+void CIRGenFunction::emitAggregateCopy(LValue dest, LValue src, QualType ty,
+ AggValueSlot::Overlap_t mayOverlap) {
+ // TODO(cir): this function needs improvements, commented code for now since
+ // this will be touched again soon.
+ assert(!ty->isAnyComplexType() && "Unexpected copy of complex");
+
+ Address destPtr = dest.getAddress();
+ Address srcPtr = src.getAddress();
+
+ if (getLangOpts().CPlusPlus) {
+ if (auto *record = ty->getAsCXXRecordDecl()) {
+ assert((record->hasTrivialCopyConstructor() ||
+ record->hasTrivialCopyAssignment() ||
+ record->hasTrivialMoveConstructor() ||
+ record->hasTrivialMoveAssignment() ||
+ record->hasAttr<TrivialABIAttr>() || record->isUnion()) &&
+ "Trying to aggregate-copy a type without a trivial copy/move "
+ "constructor or assignment operator");
+ // Ignore empty classes in C++.
+ if (record->isEmpty())
+ return;
+ }
+ }
+
+ assert(!cir::MissingFeatures::cudaSupport());
+
+ // Aggregate assignment turns into llvm.memcpy. This is almost valid per
+ // C99 6.5.16.1p3, which states "If the value being stored in an object is
+ // read from another object that overlaps in anyway the storage of the first
+ // object, then the overlap shall be exact and the two objects shall have
+ // qualified or unqualified versions of a compatible type."
+ //
+ // memcpy is not defined if the source and destination pointers are exactly
+ // equal, but other compilers do this optimization, and almost every memcpy
+ // implementation handles this case safely. If there is a libc that does not
+ // safely handle this, we can add a target hook.
+
+ // Get data size info for this aggregate. Don't copy the tail padding if this
+ // might be a potentially-overlapping subobject, since the tail padding might
+ // be occupied by a different object. Otherwise, copying it is fine.
+ TypeInfoChars typeInfo;
+ if (mayOverlap)
+ typeInfo = getContext().getTypeInfoDataSizeInChars(ty);
+ else
+ typeInfo = getContext().getTypeInfoInChars(ty);
+
+ assert(!cir::MissingFeatures::aggValueSlotVolatile());
+
+ // NOTE(cir): original codegen would normally convert destPtr and srcPtr to
+ // i8* since memcpy operates on bytes. We don't need that in CIR because
+ // cir.copy will operate on any CIR pointer that points to a sized type.
+
+ // Don't do any of the memmove_collectable tests if GC isn't set.
+ if (cgm.getLangOpts().getGC() != LangOptions::NonGC)
+ cgm.errorNYI("emitAggregateCopy: GC");
+
+ [[maybe_unused]] cir::CopyOp copyOp =
+ builder.createCopy(destPtr.getPointer(), srcPtr.getPointer());
+
+ assert(!cir::MissingFeatures::opTBAA());
+}
+
LValue CIRGenFunction::emitAggExprToLValue(const Expr *e) {
assert(hasAggregateEvaluationKind(e->getType()) && "Invalid argument!");
Address temp = createMemTemp(e->getType(), getLoc(e->getSourceRange()));
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index c799ecdc27538..6802d6ee85c72 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -965,6 +965,16 @@ class CIRGenFunction : public CIRGenTypeCache {
LValue emitAggExprToLValue(const Expr *e);
+ /// Emit an aggregate copy.
+ ///
+ /// \param isVolatile \c true iff either the source or the destination is
+ /// volatile.
+ /// \param MayOverlap Whether the tail padding of the destination might be
+ /// occupied by some other object. More efficient code can often be
+ /// generated if not.
+ void emitAggregateCopy(LValue dest, LValue src, QualType eltTy,
+ AggValueSlot::Overlap_t mayOverlap);
+
/// Emit code to compute the specified expression which can have any type. The
/// result is returned as an RValue struct. If this is an aggregate
/// expression, the aggloc/agglocvolatile arguments indicate where the result
diff --git a/clang/lib/CIR/CodeGen/CIRGenValue.h b/clang/lib/CIR/CodeGen/CIRGenValue.h
index ac7e1cc1a1db6..ea8625a0fbee5 100644
--- a/clang/lib/CIR/CodeGen/CIRGenValue.h
+++ b/clang/lib/CIR/CodeGen/CIRGenValue.h
@@ -379,6 +379,8 @@ class AggValueSlot {
mlir::Value getPointer() const { return addr.getPointer(); }
+ Overlap_t mayOverlap() const { return Overlap_t(overlapFlag); }
+
IsZeroed_t isZeroed() const { return IsZeroed_t(zeroedFlag); }
RValue asRValue() const {
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 83fff09d4fab3..d4f975234e3b0 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -1919,6 +1919,21 @@ OpFoldResult cir::UnaryOp::fold(FoldAdaptor adaptor) {
return {};
}
+//===----------------------------------------------------------------------===//
+// CopyOp Definitions
+//===----------------------------------------------------------------------===//
+
+LogicalResult cir::CopyOp::verify() {
+ // A data layout is required for us to know the number of bytes to be copied.
+ if (!getType().getPointee().hasTrait<DataLayoutTypeInterface::Trait>())
+ return emitError() << "missing data layout for pointee type";
+
+ if (getSrc() == getDst())
+ return emitError() << "source and destination are the same";
+
+ return mlir::success();
+}
+
//===----------------------------------------------------------------------===//
// GetMemberOp Definitions
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Dialect/IR/CIRMemorySlot.cpp b/clang/lib/CIR/Dialect/IR/CIRMemorySlot.cpp
index 2550c369a9277..7c341ee589e61 100644
--- a/clang/lib/CIR/Dialect/IR/CIRMemorySlot.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRMemorySlot.cpp
@@ -118,6 +118,44 @@ DeletionKind cir::StoreOp::removeBlockingUses(
return DeletionKind::Delete;
}
+//===----------------------------------------------------------------------===//
+// Interfaces for CopyOp
+//===----------------------------------------------------------------------===//
+
+bool cir::CopyOp::loadsFrom(const MemorySlot &slot) {
+ return getSrc() == slot.ptr;
+}
+
+bool cir::CopyOp::storesTo(const MemorySlot &slot) {
+ return getDst() == slot.ptr;
+}
+
+Value cir::CopyOp::getStored(const MemorySlot &slot, OpBuilder &builder,
+ Value reachingDef, const DataLayout &dataLayout) {
+ return cir::LoadOp::create(builder, getLoc(), slot.elemType, getSrc());
+}
+
+DeletionKind cir::CopyOp::removeBlockingUses(
+ const MemorySlot &slot, const SmallPtrSetImpl<OpOperand *> &blockingUses,
+ OpBuilder &builder, mlir::Value reachingDefinition,
+ const DataLayout &dataLayout) {
+ if (loadsFrom(slot))
+ cir::StoreOp::create(builder, getLoc(), reachingDefinition, getDst(),
+ /*alignment=*/mlir::IntegerAttr{},
+ /*mem-order=*/cir::MemOrderAttr());
+ return DeletionKind::Delete;
+}
+
+bool cir::CopyOp::canUsesBeRemoved(
+ const MemorySlot &slot, const SmallPtrSetImpl<OpOperand *> &blockingUses,
+ SmallVectorImpl<OpOperand *> &newBlockingUses,
+ const DataLayout &dataLayout) {
+ if (getDst() == getSrc())
+ return false;
+
+ return getLength() == dataLayout.getTypeSize(slot.elemType);
+}
+
//===----------------------------------------------------------------------===//
// Interfaces for CastOp
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 03955dc737828..efe249c2bbca3 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -173,6 +173,17 @@ mlir::LLVM::Linkage convertLinkage(cir::GlobalLinkageKind linkage) {
llvm_unreachable("Unknown CIR linkage type");
}
+mlir::LogicalResult CIRToLLVMCopyOpLowering::matchAndRewrite(
+ cir::CopyOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ const mlir::Value length = mlir::LLVM::ConstantOp::create(
+ rewriter, op.getLoc(), rewriter.getI32Type(), op.getLength());
+ assert(!cir::MissingFeatures::aggValueSlotVolatile());
+ rewriter.replaceOpWithNewOp<mlir::LLVM::MemcpyOp>(
+ op, adaptor.getDst(), adaptor.getSrc(), length, /*isVolatile=*/false);
+ return mlir::success();
+}
+
static mlir::Value getLLVMIntCast(mlir::ConversionPatternRewriter &rewriter,
mlir::Value llvmSrc, mlir::Type llvmDstIntTy,
bool isUnsigned, uint64_t cirSrcWidth,
@@ -2419,6 +2430,7 @@ void ConvertCIRToLLVMPass::runOnOperation() {
CIRToLLVMComplexRealOpLowering,
CIRToLLVMComplexRealPtrOpLowering,
CIRToLLVMComplexSubOpLowering,
+ CIRToLLVMCopyOpLowering,
CIRToLLVMConstantOpLowering,
CIRToLLVMExpectOpLowering,
CIRToLLVMFAbsOpLowering,
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
index 513ad37839f1b..c1228c1961c7e 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
@@ -170,6 +170,15 @@ class CIRToLLVMCastOpLowering : public mlir::OpConversionPattern<cir::CastOp> {
mlir::ConversionPatternRewriter &) const override;
};
+class CIRToLLVMCopyOpLowering : public mlir::OpConversionPattern<cir::CopyOp> {
+public:
+ using mlir::OpConversionPattern<cir::CopyOp>::OpConversionPattern;
+
+ mlir::LogicalResult
+ matchAndRewrite(cir::CopyOp op, OpAdaptor,
+ mlir::ConversionPatternRewriter &) const override;
+};
+
class CIRToLLVMExpectOpLowering
: public mlir::OpConversionPattern<cir::ExpectOp> {
public:
diff --git a/clang/test/CIR/CodeGen/statement-exprs.c b/clang/test/CIR/CodeGen/statement-exprs.c
index 1b54edfe7ec30..f6ec9ecd1b67e 100644
--- a/clang/test/CIR/CodeGen/statement-exprs.c
+++ b/clang/test/CIR/CodeGen/statement-exprs.c
@@ -5,9 +5,6 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
-// This fails because of a non-ignored copy of an aggregate in test3.
-// XFAIL: *
-
int f19(void) {
return ({ 3;;4;; });
}
@@ -229,6 +226,7 @@ int test3() { return ({ struct S s = {1}; s; }).x; }
// CIR: %[[GEP_X_S:.+]] = cir.get_member %[[S]][0] {name = "x"} : !cir.ptr<!rec_S> -> !cir.ptr<!s32i>
// CIR: %[[C1:.+]] = cir.const #cir.int<1> : !s32i
// CIR: cir.store {{.*}} %[[C1]], %[[GEP_X_S]] : !s32i, !cir.ptr<!s32i>
+// CIR: cir.copy %[[S]] to %[[REF_TMP0]] : !cir.ptr<!rec_S>
// CIR: }
// CIR: %[[GEP_X_TMP:.+]] = cir.get_member %[[REF_TMP0]][0] {name = "x"} : !cir.ptr<!rec_S> -> !cir.ptr<!s32i>
// CIR: %[[XVAL:.+]] = cir.load {{.*}} %[[GEP_X_TMP]] : !cir.ptr<!s32i>, !s32i
@@ -249,6 +247,7 @@ int test3() { return ({ struct S s = {1}; s; }).x; }
// LLVM: [[LBL6]]:
// LLVM: %[[GEP_S:.+]] = getelementptr %struct.S, ptr %[[VAR3]], i32 0, i32 0
// LLVM: store i32 1, ptr %[[GEP_S]]
+// LLVM: call void @llvm.memcpy.p0.p0.i32(ptr %[[VAR1]], ptr %[[VAR3]], i32 4, i1 false)
// LLVM: br label %[[LBL8:.+]]
// LLVM: [[LBL8]]:
// LLVM: %[[GEP_VAR1:.+]] = getelementptr %struct.S, ptr %[[VAR1]], i32 0, i32 0
diff --git a/clang/test/CIR/CodeGen/variable-decomposition.cpp b/clang/test/CIR/CodeGen/variable-decomposition.cpp
index 022d06a97e369..40dfe73c411c9 100644
--- a/clang/test/CIR/CodeGen/variable-decomposition.cpp
+++ b/clang/test/CIR/CodeGen/variable-decomposition.cpp
@@ -18,7 +18,13 @@ float function() {
// CIR-LABEL: cir.func dso_local @_Z8functionv() -> !cir.float
// CIR: %[[RETVAL:.+]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["__retval"]
-// CIR: %[[STRUCT:.+]] = cir.alloca !rec_some_struct, !cir.ptr<!rec_some_struct>, [""]
+// CIR: %[[STRUCT:.+]] = cir.alloca !rec_some_struct, !cir.ptr<!rec_some_struct>, ["", init]
+// CIR: %[[MEMBER_A:.+]] = cir.get_member %[[STRUCT]][0] {name = "a"} : !cir.ptr<!rec_some_struct> -> !cir.ptr<!s32i>
+// CIR: %[[CONST_1:.+]] = cir.const #cir.int<1> : !s32i
+// CIR: cir.store{{.*}} %[[CONST_1]], %[[MEMBER_A]]
+// CIR: %[[MEMBER_B:.+]] = cir.get_member %[[STRUCT]][1] {name = "b"} : !cir.ptr<!rec_some_struct> -> !cir.ptr<!cir.float>
+// CIR: %[[TWO_FP:.+]] = cir.const #cir.fp<2.000000e+00> : !cir.float
+// CIR: cir.store{{.*}} %[[TWO_FP]], %[[MEMBER_B]]
// CIR: %[[MEMBER_A:.+]] = cir.get_member %[[STRUCT]][0] {name = "a"} : !cir.ptr<!rec_some_struct> -> !cir.ptr<!s32i>
// CIR: %[[LOAD_A:.+]] = cir.load align(4) %[[MEMBER_A]] : !cir.ptr<!s32i>, !s32i
// CIR: %[[CAST_A:.+]] = cir.cast(int_to_float, %[[LOAD_A]] : !s32i), !cir.float
@@ -33,6 +39,10 @@ float function() {
// LLVM: %[[RETVAL:.+]] = alloca float, i64 1
// LLVM: %[[STRUCT:.+]] = alloca %struct.some_struct, i64 1
// LLVM: %[[GEP_A:.+]] = getelementptr %struct.some_struct, ptr %[[STRUCT]], i32 0, i32 0
+// LLVM: store i32 1, ptr %[[GEP_A]]
+// LLVM: %[[GEP_B:.+]] = getelementptr %struct.some_struct, ptr %[[STRUCT]], i32 0, i32 1
+// LLVM: ...
[truncated]
|
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.
Awesome, LGTM
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.
lgtm, with minor nits
let arguments = (ins | ||
Arg<CIR_PointerType, "", [MemWrite]>:$dst, | ||
Arg<CIR_PointerType, "", [MemRead]>:$src | ||
); |
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.
Move below summary and description to keep the common layout.
unsigned getLength() { | ||
return mlir::DataLayout::closest(*this).getTypeSize(getType().getPointee()); | ||
} |
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 is potentially expensive operation due to linear lookup of datalayout, we should probably support and encourage:
unsigned getLength(mlir::DataLayout &dt) {
return dt.getTypeSize(getType().getPointee());
}
if (getDst() == getSrc()) | ||
return false; | ||
|
||
return getLength() == dataLayout.getTypeSize(slot.elemType); |
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.
For instance here the getLength
can use already present dataLayout
.
This adds the implementation of aggEmitFinalDestCopy for the case where the destination value is not ignored. This requires adding the cir.copy operation and associated interface code.
8004849
to
d7f139e
Compare
This adds the implementation of aggEmitFinalDestCopy for the case where the destination value is not ignored. This requires adding the cir.copy operation and associated interface code.