[clang] [CIR] Emit copy for aggregate initialization (PR #155697)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Aug 27 14:15:07 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clangir
Author: Andy Kaylor (andykaylor)
<details>
<summary>Changes</summary>
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.
---
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:
- (modified) clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h (+5)
- (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+45)
- (modified) clang/include/clang/CIR/MissingFeatures.h (+1)
- (modified) clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp (+94-12)
- (modified) clang/lib/CIR/CodeGen/CIRGenFunction.h (+10)
- (modified) clang/lib/CIR/CodeGen/CIRGenValue.h (+2)
- (modified) clang/lib/CIR/Dialect/IR/CIRDialect.cpp (+15)
- (modified) clang/lib/CIR/Dialect/IR/CIRMemorySlot.cpp (+38)
- (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+12)
- (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h (+9)
- (modified) clang/test/CIR/CodeGen/statement-exprs.c (+2-3)
- (modified) clang/test/CIR/CodeGen/variable-decomposition.cpp (+11-1)
- (modified) clang/test/CIR/CodeGenOpenACC/compute-firstprivate-clause.c (+22-6)
- (added) clang/test/CIR/IR/copy.cir (+10)
- (added) clang/test/CIR/IR/invalid-copy.cir (+21)
``````````diff
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]
``````````
</details>
https://github.com/llvm/llvm-project/pull/155697
More information about the cfe-commits
mailing list