Skip to content

Commit

Permalink
[CIR][CIRGen] Support copy constructors with non-record arrays (#1165)
Browse files Browse the repository at this point in the history
If a record type contains an array of non-record types, we can generate
a copy for it inside the copy constructor, as CodeGen does. CodeGen does
so for arrays of record types where applicable as well, but we'll want
to represent the construction of those explicitly, as outlined in
#1055.
  • Loading branch information
smeenai authored Nov 26, 2024
1 parent a18db3c commit 2cec820
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 1 deletion.
25 changes: 24 additions & 1 deletion clang/lib/CIR/CodeGen/CIRGenClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,30 @@ static void emitMemberInitializer(CIRGenFunction &CGF,
CGF.getContext().getAsConstantArrayType(FieldType);
if (Array && Constructor->isDefaulted() &&
Constructor->isCopyOrMoveConstructor()) {
llvm_unreachable("NYI");
QualType baseElementTy = CGF.getContext().getBaseElementType(Array);
// NOTE(cir): CodeGen allows record types to be memcpy'd if applicable,
// whereas ClangIR wants to represent all object construction explicitly.
if (!baseElementTy->isRecordType()) {
unsigned srcArgIndex =
CGF.CGM.getCXXABI().getSrcArgforCopyCtor(Constructor, Args);
cir::LoadOp srcPtr = CGF.getBuilder().createLoad(
CGF.getLoc(MemberInit->getSourceLocation()),
CGF.GetAddrOfLocalVar(Args[srcArgIndex]));
LValue thisRhslv = CGF.MakeNaturalAlignAddrLValue(srcPtr, RecordTy);
LValue src = CGF.emitLValueForFieldInitialization(thisRhslv, Field,
Field->getName());

// Copy the aggregate.
CGF.emitAggregateCopy(LHS, src, FieldType,
CGF.getOverlapForFieldInit(Field),
LHS.isVolatileQualified());
// Ensure that we destroy the objects if an exception is thrown later in
// the constructor.
QualType::DestructionKind dtorKind = FieldType.isDestructedType();
assert(!CGF.needsEHCleanup(dtorKind) &&
"Arrays of non-record types shouldn't need EH cleanup");
return;
}
}

CGF.emitInitializerForField(Field, LHS, MemberInit->getInit());
Expand Down
35 changes: 35 additions & 0 deletions clang/test/CIR/CodeGen/copy-constructor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll
// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s

struct HasScalarArrayMember {
int arr[2][2];
HasScalarArrayMember(const HasScalarArrayMember &);
};

// CIR-LABEL: cir.func @_ZN20HasScalarArrayMemberC2ERKS_(
// CIR-NEXT: %[[#THIS:]] = cir.alloca !cir.ptr<!ty_HasScalarArrayMember>
// CIR-NEXT: %[[#OTHER:]] = cir.alloca !cir.ptr<!ty_HasScalarArrayMember>
// CIR-NEXT: cir.store %arg0, %[[#THIS]]
// CIR-NEXT: cir.store %arg1, %[[#OTHER]]
// CIR-NEXT: %[[#THIS_LOAD:]] = cir.load %[[#THIS]]
// CIR-NEXT: %[[#THIS_ARR:]] = cir.get_member %[[#THIS_LOAD]][0] {name = "arr"}
// CIR-NEXT: %[[#OTHER_LOAD:]] = cir.load %[[#OTHER]]
// CIR-NEXT: %[[#OTHER_ARR:]] = cir.get_member %[[#OTHER_LOAD]][0] {name = "arr"}
// CIR-NEXT: cir.copy %[[#OTHER_ARR]] to %[[#THIS_ARR]] : !cir.ptr<!cir.array<!cir.array<!s32i x 2> x 2>>
// CIR-NEXT: cir.return

// LLVM-LABEL: define {{.*}} @_ZN20HasScalarArrayMemberC2ERKS_(
// LLVM-SAME: ptr %[[#ARG0:]], ptr %[[#ARG1:]])
// LLVM-NEXT: %[[#THIS:]] = alloca ptr
// LLVM-NEXT: %[[#OTHER:]] = alloca ptr
// LLVM-NEXT: store ptr %[[#ARG0]], ptr %[[#THIS]]
// LLVM-NEXT: store ptr %[[#ARG1]], ptr %[[#OTHER]]
// LLVM-NEXT: %[[#THIS_LOAD:]] = load ptr, ptr %[[#THIS]]
// LLVM-NEXT: %[[#THIS_ARR:]] = getelementptr %struct.HasScalarArrayMember, ptr %[[#THIS_LOAD]], i32 0, i32 0
// LLVM-NEXT: %[[#OTHER_LOAD:]] = load ptr, ptr %[[#OTHER]]
// LLVM-NEXT: %[[#OTHER_ARR:]] = getelementptr %struct.HasScalarArrayMember, ptr %[[#OTHER_LOAD]], i32 0, i32 0
// LLVM-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr %[[#THIS_ARR]], ptr %[[#OTHER_ARR]], i32 16, i1 false)
// LLVM-NEXT: ret void
HasScalarArrayMember::HasScalarArrayMember(const HasScalarArrayMember &) = default;

0 comments on commit 2cec820

Please sign in to comment.