Skip to content

Commit 0d2a01f

Browse files
authored
[CIR] Add support for array new with constructors (#1347)
This adds support for array new expressions on objects with non-trivial constructors.
1 parent 8debbb9 commit 0d2a01f

File tree

5 files changed

+108
-5
lines changed

5 files changed

+108
-5
lines changed

clang/include/clang/CIR/Dialect/IR/CIRTypes.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -587,7 +587,7 @@ def ArrayPtr : Type<
587587
CPred<"::mlir::isa<::cir::PointerType>($_self)">,
588588
CPred<"::mlir::isa<::cir::ArrayType>("
589589
"::mlir::cast<::cir::PointerType>($_self).getPointee())">,
590-
]>, "!cir.ptr<!cir.eh_info>"> {
590+
]>, "!cir.ptr<!cir.array>"> {
591591
}
592592

593593
// Pointer to functions

clang/lib/CIR/CodeGen/CIRGenClass.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1889,10 +1889,10 @@ void CIRGenFunction::emitCXXAggrConstructorCall(
18891889
llvm_unreachable("NYI");
18901890
}
18911891

1892-
// Wmit the constructor call that will execute for every array element.
1892+
// Emit the constructor call that will execute for every array element.
1893+
auto arrayOp = builder.createPtrBitcast(arrayBase.getPointer(), arrayTy);
18931894
builder.create<cir::ArrayCtor>(
1894-
*currSrcLoc, arrayBase.getPointer(),
1895-
[&](mlir::OpBuilder &b, mlir::Location loc) {
1895+
*currSrcLoc, arrayOp, [&](mlir::OpBuilder &b, mlir::Location loc) {
18961896
auto arg = b.getInsertionBlock()->addArgument(ptrToElmType, loc);
18971897
Address curAddr = Address(arg, ptrToElmType, eltAlignment);
18981898
auto currAVS = AggValueSlot::forAddr(

clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1120,7 +1120,22 @@ void CIRGenFunction::emitNewArrayInitializer(
11201120
llvm_unreachable("NYI");
11211121
}
11221122

1123-
llvm_unreachable("NYI");
1123+
// Store the new Cleanup position for irregular Cleanups.
1124+
//
1125+
// FIXME: Share this cleanup with the constructor call emission rather than
1126+
// having it create a cleanup of its own.
1127+
if (EndOfInit.isValid())
1128+
llvm_unreachable("NYI");
1129+
1130+
// Emit a constructor call loop to initialize the remaining elements.
1131+
if (InitListElements)
1132+
llvm_unreachable("NYI");
1133+
auto arrayType = convertType(CCE->getType());
1134+
CurPtr = CurPtr.withElementType(arrayType);
1135+
emitCXXAggrConstructorCall(Ctor, NumElements, CurPtr, CCE,
1136+
/*NewPointerIsChecked*/ true,
1137+
CCE->requiresZeroInitialization());
1138+
return;
11241139
}
11251140

11261141
// If this is value-initialization, we can usually use memset.
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -I%S/../Inputs -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-lowering-prepare %s -o %t.cir 2>&1 | FileCheck -check-prefix=BEFORE %s
2+
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -I%S/../Inputs -fclangir -emit-cir -mmlir --mlir-print-ir-after=cir-lowering-prepare %s -o %t.cir 2>&1 | FileCheck -check-prefix=AFTER %s
3+
4+
class E {
5+
public:
6+
E();
7+
~E();
8+
};
9+
10+
void t_new_constant_size_constructor() {
11+
auto p = new E[3];
12+
}
13+
14+
// BEFORE: cir.func @_Z31t_new_constant_size_constructorv
15+
// BEFORE: %[[NUM_ELEMENTS:.*]] = cir.const #cir.int<3> : !u64i
16+
// BEFORE: %[[SIZE_WITHOUT_COOKIE:.*]] = cir.const #cir.int<3> : !u64i
17+
// BEFORE: %[[ALLOC_SIZE:.*]] = cir.const #cir.int<11> : !u64i
18+
// BEFORE: %[[ALLOC_PTR:.*]] = cir.call @_Znam(%[[ALLOC_SIZE]])
19+
// BEFORE: %[[COOKIE_PTR:.*]] = cir.cast(bitcast, %[[ALLOC_PTR]] : !cir.ptr<!void>), !cir.ptr<!u64i>
20+
// BEFORE: cir.store %[[NUM_ELEMENTS]], %[[COOKIE_PTR]] : !u64i, !cir.ptr<!u64i>
21+
// BEFORE: %[[PTR_AS_U8:.*]] = cir.cast(bitcast, %[[ALLOC_PTR]] : !cir.ptr<!void>), !cir.ptr<!u8i>
22+
// BEFORE: %[[OFFSET:.*]] = cir.const #cir.int<8> : !s32i
23+
// BEFORE: %[[OBJ_PTR:.*]] = cir.ptr_stride(%[[PTR_AS_U8]] : !cir.ptr<!u8i>, %[[OFFSET]] : !s32i), !cir.ptr<!u8i>
24+
// BEFORE: %[[OBJ_ELEM_PTR:.*]] = cir.cast(bitcast, %[[OBJ_PTR]] : !cir.ptr<!u8i>), !cir.ptr<!ty_E>
25+
// BEFORE: %[[OBJ_ARRAY_PTR:.*]] = cir.cast(bitcast, %[[OBJ_ELEM_PTR]] : !cir.ptr<!ty_E>), !cir.ptr<!cir.array<!ty_E x 3>>
26+
// BEFORE: cir.array.ctor(%[[OBJ_ARRAY_PTR]] : !cir.ptr<!cir.array<!ty_E x 3>>) {
27+
// BEFORE: ^bb0(%arg0: !cir.ptr<!ty_E>
28+
// BEFORE: cir.call @_ZN1EC1Ev(%arg0) : (!cir.ptr<!ty_E>) -> ()
29+
// BEFORE: cir.yield
30+
// BEFORE: }
31+
32+
// AFTER: cir.func @_Z31t_new_constant_size_constructorv
33+
// AFTER: %[[NUM_ELEMENTS:.*]] = cir.const #cir.int<3> : !u64i
34+
// AFTER: %[[SIZE_WITHOUT_COOKIE:.*]] = cir.const #cir.int<3> : !u64i
35+
// AFTER: %[[ALLOC_SIZE:.*]] = cir.const #cir.int<11> : !u64i
36+
// AFTER: %[[ALLOC_PTR:.*]] = cir.call @_Znam(%[[ALLOC_SIZE]])
37+
// AFTER: %[[COOKIE_PTR:.*]] = cir.cast(bitcast, %[[ALLOC_PTR]] : !cir.ptr<!void>), !cir.ptr<!u64i>
38+
// AFTER: cir.store %[[NUM_ELEMENTS]], %[[COOKIE_PTR]] : !u64i, !cir.ptr<!u64i>
39+
// AFTER: %[[PTR_AS_U8:.*]] = cir.cast(bitcast, %[[ALLOC_PTR]] : !cir.ptr<!void>), !cir.ptr<!u8i>
40+
// AFTER: %[[OFFSET:.*]] = cir.const #cir.int<8> : !s32i
41+
// AFTER: %[[OBJ_PTR:.*]] = cir.ptr_stride(%[[PTR_AS_U8]] : !cir.ptr<!u8i>, %[[OFFSET]] : !s32i), !cir.ptr<!u8i>
42+
// AFTER: %[[OBJ_ELEM_PTR:.*]] = cir.cast(bitcast, %[[OBJ_PTR]] : !cir.ptr<!u8i>), !cir.ptr<!ty_E>
43+
// AFTER: %[[OBJ_ARRAY_PTR:.*]] = cir.cast(bitcast, %[[OBJ_ELEM_PTR]] : !cir.ptr<!ty_E>), !cir.ptr<!cir.array<!ty_E x 3>>
44+
// AFTER: %[[NUM_ELEMENTS2:.*]] = cir.const #cir.int<3> : !u64i
45+
// AFTER: %[[ELEM_PTR:.*]] = cir.cast(array_to_ptrdecay, %10 : !cir.ptr<!cir.array<!ty_E x 3>>), !cir.ptr<!ty_E>
46+
// AFTER: %[[END_PTR:.*]] = cir.ptr_stride(%[[ELEM_PTR]] : !cir.ptr<!ty_E>, %[[NUM_ELEMENTS2]] : !u64i), !cir.ptr<!ty_E>
47+
// AFTER: %[[CUR_ELEM_ALLOCA:.*]] = cir.alloca !cir.ptr<!ty_E>, !cir.ptr<!cir.ptr<!ty_E>>, ["__array_idx"] {alignment = 1 : i64}
48+
// AFTER: cir.store %[[ELEM_PTR]], %[[CUR_ELEM_ALLOCA]] : !cir.ptr<!ty_E>, !cir.ptr<!cir.ptr<!ty_E>>
49+
// AFTER: cir.do {
50+
// AFTER: %[[CUR_ELEM_PTR:.*]] = cir.load %[[CUR_ELEM_ALLOCA]] : !cir.ptr<!cir.ptr<!ty_E>>, !cir.ptr<!ty_E>
51+
// AFTER: %[[OFFSET:.*]] = cir.const #cir.int<1> : !u64i
52+
// AFTER: cir.call @_ZN1EC1Ev(%[[CUR_ELEM_PTR]]) : (!cir.ptr<!ty_E>) -> ()
53+
// AFTER: %[[NEXT_PTR:.*]] = cir.ptr_stride(%[[CUR_ELEM_PTR]] : !cir.ptr<!ty_E>, %[[OFFSET]] : !u64i), !cir.ptr<!ty_E>
54+
// AFTER: cir.store %[[NEXT_PTR]], %[[CUR_ELEM_ALLOCA]] : !cir.ptr<!ty_E>, !cir.ptr<!cir.ptr<!ty_E>>
55+
// AFTER: cir.yield
56+
// AFTER: } while {
57+
// AFTER: %[[CUR_ELEM_PTR2:.*]] = cir.load %[[CUR_ELEM_ALLOCA]] : !cir.ptr<!cir.ptr<!ty_E>>, !cir.ptr<!ty_E>
58+
// AFTER: %[[END_TEST:.*]] = cir.cmp(eq, %[[CUR_ELEM_PTR2]], %[[END_PTR]]) : !cir.ptr<!ty_E>, !cir.bool
59+
// AFTER: cir.condition(%[[END_TEST]])
60+
// AFTER: }

clang/test/CIR/Lowering/new.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,3 +187,31 @@ void t_new_var_size_nontrivial(size_t n) {
187187
// LLVM: %[[ANY_OVERFLOW:.*]] = or i1 %[[OVERFLOW]], %[[OVERFLOW2]]
188188
// LLVM: %[[ALLOC_SIZE:.*]] = select i1 %[[ANY_OVERFLOW]], i64 -1, i64 %[[SIZE]]
189189
// LLVM: %[[ADDR:.*]] = call ptr @_Znam(i64 %[[ALLOC_SIZE]])
190+
191+
class E {
192+
public:
193+
E();
194+
~E();
195+
};
196+
197+
void t_new_constant_size_constructor() {
198+
auto p = new E[3];
199+
}
200+
201+
// LLVM: @_Z31t_new_constant_size_constructorv
202+
// LLVM: %[[ALLOC_PTR:.*]] = call ptr @_Znam(i64 11)
203+
// LLVM: store i64 3, ptr %[[ALLOC_PTR]], align 8
204+
// LLVM: %[[OBJ_PTR:.*]] = getelementptr i8, ptr %[[ALLOC_PTR]], i64 8
205+
// LLVM: %[[ELEM_PTR:.*]] = getelementptr %class.E, ptr %[[OBJ_PTR]], i32 0
206+
// LLVM: %[[END_PTR:.*]] = getelementptr %class.E, ptr %[[ELEM_PTR]], i64 3
207+
// LLVM: br label %[[INIT_ELEM_BB:.*]]
208+
// LLVM: [[LOOP_INC_BB:.*]]:
209+
// LLVM: %[[NEXT_ELEM_PTR:.*]] = load ptr
210+
// LLVM: %[[END_TEST:.*]] = icmp eq ptr %[[NEXT_ELEM_PTR]], %[[END_PTR]]
211+
// LLVM: br i1 %[[END_TEST]], label %[[INIT_ELEM_BB]], label %[[EXIT_BB:.*]]
212+
// LLVM: [[INIT_ELEM_BB]]:
213+
// LLVM: %[[CUR_ELEM_PTR:.*]] = load ptr
214+
// LLVM: call void @_ZN1EC1Ev(ptr %[[CUR_ELEM_PTR]])
215+
// LLVM: %[[NEXT_PTR:.*]] = getelementptr %class.E, ptr %[[CUR_ELEM_PTR]], i64 1
216+
// LLVM: store ptr %[[NEXT_PTR]]
217+
// LLVM: br label %[[LOOP_INC_BB]]

0 commit comments

Comments
 (0)