Skip to content

Commit 2cec820

Browse files
authored
[CIR][CIRGen] Support copy constructors with non-record arrays (#1165)
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.
1 parent a18db3c commit 2cec820

File tree

2 files changed

+59
-1
lines changed

2 files changed

+59
-1
lines changed

clang/lib/CIR/CodeGen/CIRGenClass.cpp

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,30 @@ static void emitMemberInitializer(CIRGenFunction &CGF,
252252
CGF.getContext().getAsConstantArrayType(FieldType);
253253
if (Array && Constructor->isDefaulted() &&
254254
Constructor->isCopyOrMoveConstructor()) {
255-
llvm_unreachable("NYI");
255+
QualType baseElementTy = CGF.getContext().getBaseElementType(Array);
256+
// NOTE(cir): CodeGen allows record types to be memcpy'd if applicable,
257+
// whereas ClangIR wants to represent all object construction explicitly.
258+
if (!baseElementTy->isRecordType()) {
259+
unsigned srcArgIndex =
260+
CGF.CGM.getCXXABI().getSrcArgforCopyCtor(Constructor, Args);
261+
cir::LoadOp srcPtr = CGF.getBuilder().createLoad(
262+
CGF.getLoc(MemberInit->getSourceLocation()),
263+
CGF.GetAddrOfLocalVar(Args[srcArgIndex]));
264+
LValue thisRhslv = CGF.MakeNaturalAlignAddrLValue(srcPtr, RecordTy);
265+
LValue src = CGF.emitLValueForFieldInitialization(thisRhslv, Field,
266+
Field->getName());
267+
268+
// Copy the aggregate.
269+
CGF.emitAggregateCopy(LHS, src, FieldType,
270+
CGF.getOverlapForFieldInit(Field),
271+
LHS.isVolatileQualified());
272+
// Ensure that we destroy the objects if an exception is thrown later in
273+
// the constructor.
274+
QualType::DestructionKind dtorKind = FieldType.isDestructedType();
275+
assert(!CGF.needsEHCleanup(dtorKind) &&
276+
"Arrays of non-record types shouldn't need EH cleanup");
277+
return;
278+
}
256279
}
257280

258281
CGF.emitInitializerForField(Field, LHS, MemberInit->getInit());
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
2+
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
3+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll
4+
// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s
5+
6+
struct HasScalarArrayMember {
7+
int arr[2][2];
8+
HasScalarArrayMember(const HasScalarArrayMember &);
9+
};
10+
11+
// CIR-LABEL: cir.func @_ZN20HasScalarArrayMemberC2ERKS_(
12+
// CIR-NEXT: %[[#THIS:]] = cir.alloca !cir.ptr<!ty_HasScalarArrayMember>
13+
// CIR-NEXT: %[[#OTHER:]] = cir.alloca !cir.ptr<!ty_HasScalarArrayMember>
14+
// CIR-NEXT: cir.store %arg0, %[[#THIS]]
15+
// CIR-NEXT: cir.store %arg1, %[[#OTHER]]
16+
// CIR-NEXT: %[[#THIS_LOAD:]] = cir.load %[[#THIS]]
17+
// CIR-NEXT: %[[#THIS_ARR:]] = cir.get_member %[[#THIS_LOAD]][0] {name = "arr"}
18+
// CIR-NEXT: %[[#OTHER_LOAD:]] = cir.load %[[#OTHER]]
19+
// CIR-NEXT: %[[#OTHER_ARR:]] = cir.get_member %[[#OTHER_LOAD]][0] {name = "arr"}
20+
// CIR-NEXT: cir.copy %[[#OTHER_ARR]] to %[[#THIS_ARR]] : !cir.ptr<!cir.array<!cir.array<!s32i x 2> x 2>>
21+
// CIR-NEXT: cir.return
22+
23+
// LLVM-LABEL: define {{.*}} @_ZN20HasScalarArrayMemberC2ERKS_(
24+
// LLVM-SAME: ptr %[[#ARG0:]], ptr %[[#ARG1:]])
25+
// LLVM-NEXT: %[[#THIS:]] = alloca ptr
26+
// LLVM-NEXT: %[[#OTHER:]] = alloca ptr
27+
// LLVM-NEXT: store ptr %[[#ARG0]], ptr %[[#THIS]]
28+
// LLVM-NEXT: store ptr %[[#ARG1]], ptr %[[#OTHER]]
29+
// LLVM-NEXT: %[[#THIS_LOAD:]] = load ptr, ptr %[[#THIS]]
30+
// LLVM-NEXT: %[[#THIS_ARR:]] = getelementptr %struct.HasScalarArrayMember, ptr %[[#THIS_LOAD]], i32 0, i32 0
31+
// LLVM-NEXT: %[[#OTHER_LOAD:]] = load ptr, ptr %[[#OTHER]]
32+
// LLVM-NEXT: %[[#OTHER_ARR:]] = getelementptr %struct.HasScalarArrayMember, ptr %[[#OTHER_LOAD]], i32 0, i32 0
33+
// LLVM-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr %[[#THIS_ARR]], ptr %[[#OTHER_ARR]], i32 16, i1 false)
34+
// LLVM-NEXT: ret void
35+
HasScalarArrayMember::HasScalarArrayMember(const HasScalarArrayMember &) = default;

0 commit comments

Comments
 (0)