Author: Andy Kaylor Date: 2025-08-13T16:14:32-07:00 New Revision: f2d76b58f8f7b96bb8227fa55ea0ad53e53368bc
URL: https://github.com/llvm/llvm-project/commit/f2d76b58f8f7b96bb8227fa55ea0ad53e53368bc DIFF: https://github.com/llvm/llvm-project/commit/f2d76b58f8f7b96bb8227fa55ea0ad53e53368bc.diff LOG: [CIR] Use a loop for array initialization (#153499) This updates the array initialization loop to use a do..while loop rather than a fully serialized initialization. It also allows the initialization of destructed objects when exception handling is not enabled. Array initialization when exception handling is enabled remains unimplemented, but more precise messages are now emitted. Added: Modified: clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp clang/test/CIR/CodeGen/array.cpp clang/test/CIR/CodeGen/destructors.cpp clang/test/CIR/Lowering/array.cpp Removed: ################################################################################ diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp index 1fda8487796a9..6b6ac701e6867 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp @@ -124,8 +124,8 @@ void AggExprEmitter::emitArrayInit(Address destPtr, cir::ArrayType arrayTy, const QualType elementType = cgf.getContext().getAsArrayType(arrayQTy)->getElementType(); - if (elementType.isDestructedType()) { - cgf.cgm.errorNYI(loc, "dtorKind NYI"); + if (elementType.isDestructedType() && cgf.cgm.getLangOpts().Exceptions) { + cgf.cgm.errorNYI(loc, "initialized array requires destruction"); return; } @@ -135,9 +135,9 @@ void AggExprEmitter::emitArrayInit(Address destPtr, cir::ArrayType arrayTy, const cir::PointerType cirElementPtrType = builder.getPointerTo(cirElementType); - auto begin = builder.create<cir::CastOp>(loc, cirElementPtrType, - cir::CastKind::array_to_ptrdecay, - destPtr.getPointer()); + auto begin = cir::CastOp::create(builder, loc, cirElementPtrType, + cir::CastKind::array_to_ptrdecay, + destPtr.getPointer()); const CharUnits elementSize = cgf.getContext().getTypeSizeInChars(elementType); @@ -182,8 +182,8 @@ void AggExprEmitter::emitArrayInit(Address destPtr, cir::ArrayType arrayTy, // Advance to the start of the rest of the array. if (numInitElements) { one = builder.getConstantInt(loc, cgf.PtrDiffTy, 1); - element = builder.create<cir::PtrStrideOp>(loc, cirElementPtrType, - element, one); + element = cir::PtrStrideOp::create(builder, loc, cirElementPtrType, + element, one); } // Allocate the temporary variable @@ -193,25 +193,52 @@ void AggExprEmitter::emitArrayInit(Address destPtr, cir::ArrayType arrayTy, LValue tmpLV = cgf.makeAddrLValue(tmpAddr, elementPtrType); cgf.emitStoreThroughLValue(RValue::get(element), tmpLV); - // TODO(CIR): Replace this part later with cir::DoWhileOp - for (unsigned i = numInitElements; i != numArrayElements; ++i) { - cir::LoadOp currentElement = builder.createLoad(loc, tmpAddr); - - // Emit the actual filler expression. - const LValue elementLV = cgf.makeAddrLValue( - Address(currentElement, cirElementType, elementAlign), elementType); - - if (arrayFiller) - emitInitializationToLValue(arrayFiller, elementLV); - else - emitNullInitializationToLValue(loc, elementLV); - - // Advance pointer and store them to temporary variable - one = builder.getConstantInt(loc, cgf.PtrDiffTy, 1); - cir::PtrStrideOp nextElement = - builder.createPtrStride(loc, currentElement, one); - cgf.emitStoreThroughLValue(RValue::get(nextElement), tmpLV); - } + // Compute the end of array + cir::ConstantOp numArrayElementsConst = builder.getConstInt( + loc, mlir::cast<cir::IntType>(cgf.PtrDiffTy), numArrayElements); + mlir::Value end = cir::PtrStrideOp::create(builder, loc, cirElementPtrType, + begin, numArrayElementsConst); + + builder.createDoWhile( + loc, + /*condBuilder=*/ + [&](mlir::OpBuilder &b, mlir::Location loc) { + cir::LoadOp currentElement = builder.createLoad(loc, tmpAddr); + mlir::Type boolTy = cgf.convertType(cgf.getContext().BoolTy); + cir::CmpOp cmp = cir::CmpOp::create( + builder, loc, boolTy, cir::CmpOpKind::ne, currentElement, end); + builder.createCondition(cmp); + }, + /*bodyBuilder=*/ + [&](mlir::OpBuilder &b, mlir::Location loc) { + cir::LoadOp currentElement = builder.createLoad(loc, tmpAddr); + + assert(!cir::MissingFeatures::requiresCleanups()); + + // Emit the actual filler expression. + LValue elementLV = cgf.makeAddrLValue( + Address(currentElement, cirElementType, elementAlign), + elementType); + if (arrayFiller) + emitInitializationToLValue(arrayFiller, elementLV); + else + emitNullInitializationToLValue(loc, elementLV); + + // Tell the EH cleanup that we finished with the last element. + if (cgf.cgm.getLangOpts().Exceptions) { + cgf.cgm.errorNYI(loc, "update destructed array element for EH"); + return; + } + + // Advance pointer and store them to temporary variable + cir::ConstantOp one = builder.getConstInt( + loc, mlir::cast<cir::IntType>(cgf.PtrDiffTy), 1); + auto nextElement = cir::PtrStrideOp::create( + builder, loc, cirElementPtrType, currentElement, one); + cgf.emitStoreThroughLValue(RValue::get(nextElement), tmpLV); + + builder.createYield(loc); + }); } } diff --git a/clang/test/CIR/CodeGen/array.cpp b/clang/test/CIR/CodeGen/array.cpp index 141b67e0e63c7..60028af4b3161 100644 --- a/clang/test/CIR/CodeGen/array.cpp +++ b/clang/test/CIR/CodeGen/array.cpp @@ -129,31 +129,50 @@ void func2() { } // CIR: %[[ARR2:.*]] = cir.alloca !cir.array<!s32i x 2>, !cir.ptr<!cir.array<!s32i x 2>>, ["arr", init] -// CIR: %[[ELE_ALLOCA:.*]] = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["arrayinit.temp", init] -// CIR: %[[ARR_2_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR2]] : !cir.ptr<!cir.array<!s32i x 2>>), !cir.ptr<!s32i> -// CIR: %[[V1:.*]] = cir.const #cir.int<5> : !s32i -// CIR: cir.store{{.*}} %[[V1]], %[[ARR_2_PTR]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[ARR_PTR:.*]] = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["arrayinit.temp", init] +// CIR: %[[ARR_0:.*]] = cir.cast(array_to_ptrdecay, %[[ARR2]] : !cir.ptr<!cir.array<!s32i x 2>>), !cir.ptr<!s32i> +// CIR: %[[FIVE:.*]] = cir.const #cir.int<5> : !s32i +// CIR: cir.store{{.*}} %[[FIVE]], %[[ARR_0]] : !s32i, !cir.ptr<!s32i> // CIR: %[[OFFSET_0:.*]] = cir.const #cir.int<1> : !s64i -// CIR: %[[ELE_PTR:.*]] = cir.ptr_stride(%[[ARR_2_PTR]] : !cir.ptr<!s32i>, %[[OFFSET_0]] : !s64i), !cir.ptr<!s32i> -// CIR: cir.store{{.*}} %[[ELE_PTR]], %[[ELE_ALLOCA]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>> -// CIR: %[[LOAD_1:.*]] = cir.load{{.*}} %[[ELE_ALLOCA]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i> -// CIR: %[[V2:.*]] = cir.const #cir.int<0> : !s32i -// CIR: cir.store{{.*}} %[[V2]], %[[LOAD_1]] : !s32i, !cir.ptr<!s32i> -// CIR: %[[OFFSET_1:.*]] = cir.const #cir.int<1> : !s64i -// CIR: %[[ELE_1_PTR:.*]] = cir.ptr_stride(%[[LOAD_1]] : !cir.ptr<!s32i>, %[[OFFSET_1]] : !s64i), !cir.ptr<!s32i> -// CIR: cir.store{{.*}} %[[ELE_1_PTR]], %[[ELE_ALLOCA]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>> +// CIR: %[[ELE_PTR:.*]] = cir.ptr_stride(%[[ARR_0]] : !cir.ptr<!s32i>, %[[OFFSET_0]] : !s64i), !cir.ptr<!s32i> +// CIR: cir.store{{.*}} %[[ELE_PTR]], %[[ARR_PTR]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>> +// CIR: %[[TWO:.*]] = cir.const #cir.int<2> : !s64i +// CIR: %[[ARR_END:.*]] = cir.ptr_stride(%[[ARR_0]] : !cir.ptr<!s32i>, %[[TWO]] : !s64i), !cir.ptr<!s32i> +// CIR: cir.do { +// CIR: %[[ARR_CUR:.*]] = cir.load{{.*}} %[[ARR_PTR]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i> +// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i +// CIR: cir.store{{.*}} %[[ZERO]], %[[ARR_CUR]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s64i +// CIR: %[[ARR_NEXT:.*]] = cir.ptr_stride(%[[ARR_CUR]] : !cir.ptr<!s32i>, %[[ONE]] : !s64i), !cir.ptr<!s32i> +// CIR: cir.store{{.*}} %[[ARR_NEXT]], %[[ARR_PTR]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>> +// CIR: cir.yield +// CIR: } while { +// CIR: %[[ARR_CUR:.*]] = cir.load{{.*}} %[[ARR_PTR]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i> +// CIR: %[[CMP:.*]] = cir.cmp(ne, %[[ARR_CUR]], %[[ARR_END]]) : !cir.ptr<!s32i>, !cir.bool +// CIR: cir.condition(%[[CMP]]) +// CIR: } // LLVM: define{{.*}} void @_Z5func2v() -// LLVM: %[[ARR:.*]] = alloca [2 x i32], i64 1, align 4 -// LLVM: %[[TMP:.*]] = alloca ptr, i64 1, align 8 -// LLVM: %[[ARR_PTR:.*]] = getelementptr i32, ptr %[[ARR]], i32 0 -// LLVM: store i32 5, ptr %[[ARR_PTR]], align 4 -// LLVM: %[[ELE_1_PTR:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i64 1 -// LLVM: store ptr %[[ELE_1_PTR]], ptr %[[TMP]], align 8 -// LLVM: %[[TMP2:.*]] = load ptr, ptr %[[TMP]], align 8 -// LLVM: store i32 0, ptr %[[TMP2]], align 4 -// LLVM: %[[ELE_1:.*]] = getelementptr i32, ptr %[[TMP2]], i64 1 -// LLVM: store ptr %[[ELE_1]], ptr %[[TMP]], align 8 +// LLVM: %[[ARR:.*]] = alloca [2 x i32], i64 1, align 4 +// LLVM: %[[TMP:.*]] = alloca ptr, i64 1, align 8 +// LLVM: %[[ARR_PTR:.*]] = getelementptr i32, ptr %[[ARR]], i32 0 +// LLVM: store i32 5, ptr %[[ARR_PTR]], align 4 +// LLVM: %[[ELE_1_PTR:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i64 1 +// LLVM: store ptr %[[ELE_1_PTR]], ptr %[[TMP]], align 8 +// LLVM: %[[END_PTR:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i64 2 +// LLVM: br label %[[LOOP_BODY:.*]] +// LLVM: [[LOOP_NEXT:.*]]: +// LLVM: %[[CUR:.*]] = load ptr, ptr %[[TMP]], align 8 +// LLVM: %[[CMP:.*]] = icmp ne ptr %[[CUR]], %[[END_PTR]] +// LLVM: br i1 %[[CMP]], label %[[LOOP_BODY]], label %[[LOOP_END:.*]] +// LLVM: [[LOOP_BODY]]: +// LLVM: %[[CUR:.*]] = load ptr, ptr %[[TMP]], align 8 +// LLVM: store i32 0, ptr %[[CUR]], align 4 +// LLVM: %[[NEXT:.*]] = getelementptr i32, ptr %[[CUR]], i64 1 +// LLVM: store ptr %[[NEXT]], ptr %[[TMP]], align 8 +// LLVM: br label %[[LOOP_NEXT:.*]] +// LLVM: [[LOOP_END]]: +// LLVM: ret void // OGCG: %[[ARR:.*]] = alloca [2 x i32], align 4 // OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[ARR]], ptr align 4 @[[FUN2_ARR]], i64 8, i1 false) @@ -270,27 +289,46 @@ void func5() { // CIR: %[[V_0_0:.*]] = cir.const #cir.int<5> : !s32i // CIR: cir.store{{.*}} %[[V_0_0]], %[[ARR_0_PTR]] : !s32i, !cir.ptr<!s32i> // CIR: %[[OFFSET:.*]] = cir.const #cir.int<1> : !s64i -// CIR: %6 = cir.ptr_stride(%[[ARR_0]] : !cir.ptr<!cir.array<!s32i x 1>>, %[[OFFSET]] : !s64i), !cir.ptr<!cir.array<!s32i x 1>> -// CIR: cir.store{{.*}} %6, %[[ARR_PTR]] : !cir.ptr<!cir.array<!s32i x 1>>, !cir.ptr<!cir.ptr<!cir.array<!s32i x 1>>> -// CIR: %7 = cir.load{{.*}} %[[ARR_PTR]] : !cir.ptr<!cir.ptr<!cir.array<!s32i x 1>>>, !cir.ptr<!cir.array<!s32i x 1>> -// CIR: %8 = cir.const #cir.zero : !cir.array<!s32i x 1> -// CIR: cir.store{{.*}} %8, %7 : !cir.array<!s32i x 1>, !cir.ptr<!cir.array<!s32i x 1>> -// CIR: %[[OFFSET_1:.*]] = cir.const #cir.int<1> : !s64i -// CIR: %10 = cir.ptr_stride(%7 : !cir.ptr<!cir.array<!s32i x 1>>, %[[OFFSET_1]] : !s64i), !cir.ptr<!cir.array<!s32i x 1>> -// CIR: cir.store{{.*}} %10, %[[ARR_PTR]] : !cir.ptr<!cir.array<!s32i x 1>>, !cir.ptr<!cir.ptr<!cir.array<!s32i x 1>>> +// CIR: %[[ARR_1:.*]] = cir.ptr_stride(%[[ARR_0]] : !cir.ptr<!cir.array<!s32i x 1>>, %[[OFFSET]] : !s64i), !cir.ptr<!cir.array<!s32i x 1>> +// CIR: cir.store{{.*}} %[[ARR_1]], %[[ARR_PTR]] : !cir.ptr<!cir.array<!s32i x 1>>, !cir.ptr<!cir.ptr<!cir.array<!s32i x 1>>> +// CIR: %[[TWO:.*]] = cir.const #cir.int<2> : !s64i +// CIR: %[[ARR_END:.*]] = cir.ptr_stride(%[[ARR_0]] : !cir.ptr<!cir.array<!s32i x 1>>, %[[TWO]] : !s64i), !cir.ptr<!cir.array<!s32i x 1>> +// CIR: cir.do { +// CIR: %[[ARR_CUR:.*]] = cir.load{{.*}} %[[ARR_PTR]] : !cir.ptr<!cir.ptr<!cir.array<!s32i x 1>>>, !cir.ptr<!cir.array<!s32i x 1>> +// CIR: %[[ZERO:.*]] = cir.const #cir.zero : !cir.array<!s32i x 1> +// CIR: cir.store{{.*}} %[[ZERO]], %[[ARR_CUR]] : !cir.array<!s32i x 1>, !cir.ptr<!cir.array<!s32i x 1>> +// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s64i +// CIR: %[[ARR_NEXT:.*]] = cir.ptr_stride(%[[ARR_CUR]] : !cir.ptr<!cir.array<!s32i x 1>>, %[[ONE]] : !s64i), !cir.ptr<!cir.array<!s32i x 1>> +// CIR: cir.store{{.*}} %[[ARR_NEXT]], %[[ARR_PTR]] : !cir.ptr<!cir.array<!s32i x 1>>, !cir.ptr<!cir.ptr<!cir.array<!s32i x 1>>> +// CIR: cir.yield +// CIR: } while { +// CIR: %[[ARR_CUR:.*]] = cir.load{{.*}} %[[ARR_PTR]] : !cir.ptr<!cir.ptr<!cir.array<!s32i x 1>>>, !cir.ptr<!cir.array<!s32i x 1>> +// CIR: %[[CMP:.*]] = cir.cmp(ne, %[[ARR_CUR]], %[[ARR_END]]) : !cir.ptr<!cir.array<!s32i x 1>>, !cir.bool +// CIR: cir.condition(%[[CMP]]) +// CIR: } // LLVM: define{{.*}} void @_Z5func5v() -// LLVM: %[[ARR:.*]] = alloca [2 x [1 x i32]], i64 1, align 4 -// LLVM: %[[TMP:.*]] = alloca ptr, i64 1, align 8 -// LLVM: %[[ARR_PTR:.*]] = getelementptr [1 x i32], ptr %[[ARR]], i32 0 -// LLVM: %[[ARR_0:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i32 0 -// LLVM: store i32 5, ptr %[[ARR_0]], align 4 -// LLVM: %[[ARR_1:.*]] = getelementptr [1 x i32], ptr %[[ARR_PTR]], i64 1 -// LLVM: store ptr %[[ARR_1]], ptr %[[TMP]], align 8 -// LLVM: %[[ARR_1_VAL:.*]] = load ptr, ptr %[[TMP]], align 8 -// LLVM: store [1 x i32] zeroinitializer, ptr %[[ARR_1_VAL]], align 4 -// LLVM: %[[ARR_1_PTR:.*]] = getelementptr [1 x i32], ptr %[[ARR_1_VAL]], i64 1 -// LLVM: store ptr %[[ARR_1_PTR]], ptr %[[TMP]], align 8 +// LLVM: %[[ARR:.*]] = alloca [2 x [1 x i32]], i64 1, align 4 +// LLVM: %[[TMP:.*]] = alloca ptr, i64 1, align 8 +// LLVM: %[[ARR_PTR:.*]] = getelementptr [1 x i32], ptr %[[ARR]], i32 0 +// LLVM: %[[ARR_0:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i32 0 +// LLVM: store i32 5, ptr %[[ARR_0]], align 4 +// LLVM: %[[ARR_1:.*]] = getelementptr [1 x i32], ptr %[[ARR_PTR]], i64 1 +// LLVM: store ptr %[[ARR_1]], ptr %[[TMP]], align 8 +// LLVM: %[[END_PTR:.*]] = getelementptr [1 x i32], ptr %[[ARR_PTR]], i64 2 +// LLVM: br label %[[LOOP_BODY:.*]] +// LLVM: [[LOOP_NEXT:.*]]: +// LLVM: %[[CUR:.*]] = load ptr, ptr %[[TMP]], align 8 +// LLVM: %[[CMP:.*]] = icmp ne ptr %[[CUR]], %[[END_PTR]] +// LLVM: br i1 %[[CMP]], label %[[LOOP_BODY]], label %[[LOOP_END:.*]] +// LLVM: [[LOOP_BODY]]: +// LLVM: %[[CUR:.*]] = load ptr, ptr %[[TMP]], align 8 +// LLVM: store [1 x i32] zeroinitializer, ptr %[[CUR]], align 4 +// LLVM: %[[NEXT:.*]] = getelementptr [1 x i32], ptr %[[CUR]], i64 1 +// LLVM: store ptr %[[NEXT]], ptr %[[TMP]], align 8 +// LLVM: br label %[[LOOP_NEXT:.*]] +// LLVM: [[LOOP_END]]: +// LLVM: ret void // ORGC: %[[ARR:.*]] = alloca [2 x [1 x i32]], align 4 // ORGC: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[ARR]], ptr align 4 @[[FUN5_ARR]], i64 8, i1 false) @@ -335,25 +373,44 @@ void func7() { } // CIR: %[[ARR:.*]] = cir.alloca !cir.array<!cir.ptr<!s32i> x 1>, !cir.ptr<!cir.array<!cir.ptr<!s32i> x 1>>, ["arr", init] -// CIR: %[[ARR_TMP:.*]] = cir.alloca !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>>, ["arrayinit.temp", init] -// CIR: %[[ARR_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR]] : !cir.ptr<!cir.array<!cir.ptr<!s32i> x 1>>), !cir.ptr<!cir.ptr<!s32i>> -// CIR: cir.store{{.*}} %[[ARR_PTR]], %[[ARR_TMP]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> -// CIR: %[[TMP:.*]] = cir.load{{.*}} %[[ARR_TMP]] : !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>>, !cir.ptr<!cir.ptr<!s32i>> -// CIR: %[[NULL_PTR:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!s32i> -// CIR: cir.store{{.*}} %[[NULL_PTR]], %[[TMP]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>> -// CIR: %[[OFFSET:.*]] = cir.const #cir.int<1> : !s64i -// CIR: %[[ELE_PTR:.*]] = cir.ptr_stride(%[[TMP]] : !cir.ptr<!cir.ptr<!s32i>>, %[[OFFSET]] : !s64i), !cir.ptr<!cir.ptr<!s32i>> -// CIR: cir.store{{.*}} %[[ELE_PTR]], %[[ARR_TMP]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> +// CIR: %[[ARR_PTR:.*]] = cir.alloca !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>>, ["arrayinit.temp", init] +// CIR: %[[ARR_0:.*]] = cir.cast(array_to_ptrdecay, %[[ARR]] : !cir.ptr<!cir.array<!cir.ptr<!s32i> x 1>>), !cir.ptr<!cir.ptr<!s32i>> +// CIR: cir.store{{.*}} %[[ARR_0]], %[[ARR_PTR]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> +// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s64i +// CIR: %[[ARR_END:.*]] = cir.ptr_stride(%[[ARR_0]] : !cir.ptr<!cir.ptr<!s32i>>, %[[ONE]] : !s64i), !cir.ptr<!cir.ptr<!s32i>> +// CIR: cir.do { +// CIR: %[[ARR_CUR:.*]] = cir.load{{.*}} %[[ARR_PTR]] : !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>>, !cir.ptr<!cir.ptr<!s32i>> +// CIR: %[[NULL_PTR:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!s32i> +// CIR: cir.store{{.*}} %[[NULL_PTR]], %[[ARR_CUR]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>> +// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s64i +// CIR: %[[ARR_NEXT:.*]] = cir.ptr_stride(%[[ARR_CUR]] : !cir.ptr<!cir.ptr<!s32i>>, %[[ONE]] : !s64i), !cir.ptr<!cir.ptr<!s32i>> +// CIR: cir.store{{.*}} %[[ARR_NEXT]], %[[ARR_PTR]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> +// CIR: cir.yield +// CIR: } while { +// CIR: %[[ARR_CUR:.*]] = cir.load{{.*}} %[[ARR_PTR]] : !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>>, !cir.ptr<!cir.ptr<!s32i>> +// CIR: %[[CMP:.*]] = cir.cmp(ne, %[[ARR_CUR]], %[[ARR_END]]) : !cir.ptr<!cir.ptr<!s32i>>, !cir.bool +// CIR: cir.condition(%[[CMP]]) +// CIR: } // LLVM: define{{.*}} void @_Z5func7v() -// LLVM: %[[ARR:.*]] = alloca [1 x ptr], i64 1, align 8 -// LLVM: %[[ALLOCA:.*]] = alloca ptr, i64 1, align 8 -// LLVM: %[[ELE_PTR:.*]] = getelementptr ptr, ptr %[[ARR]], i32 0 -// LLVM: store ptr %[[ELE_PTR]], ptr %[[ALLOCA]], align 8 -// LLVM: %[[TMP:.*]] = load ptr, ptr %[[ALLOCA]], align 8 -// LLVM: store ptr null, ptr %[[TMP]], align 8 -// LLVM: %[[ELE:.*]] = getelementptr ptr, ptr %[[TMP]], i64 1 -// LLVM: store ptr %[[ELE]], ptr %[[ALLOCA]], align 8 +// LLVM: %[[ARR:.*]] = alloca [1 x ptr], i64 1, align 8 +// LLVM: %[[TMP:.*]] = alloca ptr, i64 1, align 8 +// LLVM: %[[ARR_PTR:.*]] = getelementptr ptr, ptr %[[ARR]], i32 0 +// LLVM: store ptr %[[ARR_PTR]], ptr %[[TMP]], align 8 +// LLVM: %[[END_PTR:.*]] = getelementptr ptr, ptr %[[ARR_PTR]], i64 1 +// LLVM: br label %[[LOOP_BODY:.*]] +// LLVM: [[LOOP_NEXT:.*]]: +// LLVM: %[[CUR:.*]] = load ptr, ptr %[[TMP]], align 8 +// LLVM: %[[CMP:.*]] = icmp ne ptr %[[CUR]], %[[END_PTR]] +// LLVM: br i1 %[[CMP]], label %[[LOOP_BODY]], label %[[LOOP_END:.*]] +// LLVM: [[LOOP_BODY]]: +// LLVM: %[[CUR:.*]] = load ptr, ptr %[[TMP]], align 8 +// LLVM: store ptr null, ptr %[[CUR]], align 8 +// LLVM: %[[NEXT:.*]] = getelementptr ptr, ptr %[[CUR]], i64 1 +// LLVM: store ptr %[[NEXT]], ptr %[[TMP]], align 8 +// LLVM: br label %[[LOOP_NEXT:.*]] +// LLVM: [[LOOP_END]]: +// LLVM: ret void // OGCG: %[[ARR:.*]] = alloca [1 x ptr], align 8 // OGCG: call void @llvm.memset.p0.i64(ptr align 8 %[[ARR]], i8 0, i64 8, i1 false) diff --git a/clang/test/CIR/CodeGen/destructors.cpp b/clang/test/CIR/CodeGen/destructors.cpp index de7718f0998fc..fde0732a4352f 100644 --- a/clang/test/CIR/CodeGen/destructors.cpp +++ b/clang/test/CIR/CodeGen/destructors.cpp @@ -55,3 +55,102 @@ struct inline_destructor { // CIR-NOT: cir.func {{.*}}inline_destructor{{.*}} // LLVM-NOT: define {{.*}}inline_destructor{{.*}} // OGCG-NOT: define {{.*}}inline_destructor{{.*}} + +struct array_element {~array_element();}; +void test_array_destructor() { + array_element arr[5]{}; +} + +// CIR: cir.func dso_local @_Z21test_array_destructorv() +// CIR: %[[ARR:.*]] = cir.alloca !cir.array<!rec_array_element x 5>, !cir.ptr<!cir.array<!rec_array_element x 5>>, ["arr", init] +// CIR: %[[ARR_PTR:.*]] = cir.alloca !cir.ptr<!rec_array_element>, !cir.ptr<!cir.ptr<!rec_array_element>>, ["arrayinit.temp", init] +// CIR: %[[BEGIN:.*]] = cir.cast(array_to_ptrdecay, %[[ARR]] : !cir.ptr<!cir.array<!rec_array_element x 5>>) +// CIR: cir.store{{.*}} %[[BEGIN]], %[[ARR_PTR]] +// CIR: %[[FIVE:.*]] = cir.const #cir.int<5> : !s64i +// CIR: %[[ARR_END:.*]] = cir.ptr_stride(%[[BEGIN]] : !cir.ptr<!rec_array_element>, %[[FIVE]] : !s64i) +// CIR: cir.do { +// CIR: %[[ARR_CUR:.*]] = cir.load{{.*}} %[[ARR_PTR]] +// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s64i +// CIR: %[[ARR_NEXT:.*]] = cir.ptr_stride(%[[ARR_CUR]] : !cir.ptr<!rec_array_element>, %[[ONE]] : !s64i) +// CIR: cir.store{{.*}} %[[ARR_NEXT]], %[[ARR_PTR]] : !cir.ptr<!rec_array_element>, !cir.ptr<!cir.ptr<!rec_array_element>> +// CIR: cir.yield +// CIR: } while { +// CIR: %[[ARR_CUR:.*]] = cir.load{{.*}} %[[ARR_PTR]] +// CIR: %[[CMP:.*]] = cir.cmp(ne, %[[ARR_CUR]], %[[ARR_END]]) +// CIR: cir.condition(%[[CMP]]) +// CIR: } +// CIR: %[[FOUR:.*]] = cir.const #cir.int<4> : !u64i +// CIR: %[[BEGIN:.*]] = cir.cast(array_to_ptrdecay, %[[ARR]] : !cir.ptr<!cir.array<!rec_array_element x 5>>) +// CIR: %[[END:.*]] = cir.ptr_stride(%[[BEGIN]] : !cir.ptr<!rec_array_element>, %[[FOUR]] : !u64i) +// CIR: %[[ARR_PTR:.*]] = cir.alloca !cir.ptr<!rec_array_element>, !cir.ptr<!cir.ptr<!rec_array_element>>, ["__array_idx"] +// CIR: cir.store %[[END]], %[[ARR_PTR]] +// CIR: cir.do { +// CIR: %[[ARR_CUR:.*]] = cir.load{{.*}} %[[ARR_PTR]] +// CIR: cir.call @_ZN13array_elementD1Ev(%[[ARR_CUR]]) nothrow : (!cir.ptr<!rec_array_element>) -> () +// CIR: %[[NEG_ONE:.*]] = cir.const #cir.int<-1> : !s64i +// CIR: %[[ARR_NEXT:.*]] = cir.ptr_stride(%[[ARR_CUR]] : !cir.ptr<!rec_array_element>, %[[NEG_ONE]] : !s64i) +// CIR: cir.store %[[ARR_NEXT]], %[[ARR_PTR]] +// CIR: cir.yield +// CIR: } while { +// CIR: %[[ARR_CUR:.*]] = cir.load{{.*}} %[[ARR_PTR]] +// CIR: %[[CMP:.*]] = cir.cmp(ne, %[[ARR_CUR]], %[[BEGIN]]) +// CIR: cir.condition(%[[CMP]]) +// CIR: } + +// LLVM: define{{.*}} void @_Z21test_array_destructorv() +// LLVM: %[[ARR:.*]] = alloca [5 x %struct.array_element] +// LLVM: %[[TMP:.*]] = alloca ptr +// LLVM: %[[ARR_PTR:.*]] = getelementptr %struct.array_element, ptr %[[ARR]], i32 0 +// LLVM: store ptr %[[ARR_PTR]], ptr %[[TMP]] +// LLVM: %[[END_PTR:.*]] = getelementptr %struct.array_element, ptr %[[ARR_PTR]], i64 5 +// LLVM: br label %[[INIT_LOOP_BODY:.*]] +// LLVM: [[INIT_LOOP_NEXT:.*]]: +// LLVM: %[[CUR:.*]] = load ptr, ptr %[[TMP]] +// LLVM: %[[CMP:.*]] = icmp ne ptr %[[CUR]], %[[END_PTR]] +// LLVM: br i1 %[[CMP]], label %[[INIT_LOOP_BODY]], label %[[INIT_LOOP_END:.*]] +// LLVM: [[INIT_LOOP_BODY]]: +// LLVM: %[[CUR:.*]] = load ptr, ptr %[[TMP]] +// LLVM: %[[NEXT:.*]] = getelementptr %struct.array_element, ptr %[[CUR]], i64 1 +// LLVM: store ptr %[[NEXT]], ptr %[[TMP]] +// LLVM: br label %[[INIT_LOOP_NEXT:.*]] +// LLVM: [[INIT_LOOP_END]]: +// LLVM: %[[ARR_BEGIN:.*]] = getelementptr %struct.array_element, ptr %[[ARR]], i32 0 +// LLVM: %[[ARR_END:.*]] = getelementptr %struct.array_element, ptr %[[ARR_BEGIN]], i64 4 +// LLVM: %[[ARR_CUR:.*]] = alloca ptr +// LLVM: store ptr %[[ARR_END]], ptr %[[ARR_CUR]] +// LLVM: br label %[[DESTROY_LOOP_BODY:.*]] +// LLVM: [[DESTROY_LOOP_NEXT:.*]]: +// LLVM: %[[CUR:.*]] = load ptr, ptr %[[ARR_CUR]] +// LLVM: %[[CMP:.*]] = icmp ne ptr %[[CUR]], %[[ARR_BEGIN]] +// LLVM: br i1 %[[CMP]], label %[[DESTROY_LOOP_BODY]], label %[[DESTROY_LOOP_END:.*]] +// LLVM: [[DESTROY_LOOP_BODY]]: +// LLVM: %[[CUR:.*]] = load ptr, ptr %[[ARR_CUR]] +// LLVM: call void @_ZN13array_elementD1Ev(ptr %[[CUR]]) +// LLVM: %[[PREV:.*]] = getelementptr %struct.array_element, ptr %[[CUR]], i64 -1 +// LLVM: store ptr %[[PREV]], ptr %[[ARR_CUR]] +// LLVM: br label %[[DESTROY_LOOP_NEXT]] +// LLVM: [[DESTROY_LOOP_END]]: +// LLVM: ret void + +// OGCG: define{{.*}} void @_Z21test_array_destructorv() +// OGCG: entry: +// OGCG: %[[ARR:.*]] = alloca [5 x %struct.array_element] +// OGCG: %[[ARRAYINIT_END:.*]] = getelementptr inbounds %struct.array_element, ptr %[[ARR]], i64 5 +// OGCG: br label %[[INIT_LOOP_BODY:.*]] +// OGCG: [[INIT_LOOP_BODY]]: +// OGCG: %[[CUR:.*]] = phi ptr [ %[[ARR]], %entry ], [ %[[NEXT:.*]], %[[INIT_LOOP_BODY]] ] +// OGCG: %[[NEXT]] = getelementptr inbounds %struct.array_element, ptr %[[CUR]], i64 1 +// OGCG: %[[CMP:.*]] = icmp eq ptr %[[NEXT]], %[[ARRAYINIT_END]] +// OGCG: br i1 %[[CMP]], label %[[INIT_LOOP_END:.*]], label %[[INIT_LOOP_BODY]] +// OGCG: [[INIT_LOOP_END:.*]]: +// OGCG: %[[BEGIN:.*]] = getelementptr inbounds [5 x %struct.array_element], ptr %[[ARR]], i32 0, i32 0 +// OGCG: %[[END:.*]] = getelementptr inbounds %struct.array_element, ptr %[[BEGIN]], i64 5 +// OGCG: br label %[[DESTROY_LOOP_BODY:.*]] +// OGCG: [[DESTROY_LOOP_BODY:.*]]: +// OGCG: %[[CUR:.*]] = phi ptr [ %[[END]], %[[INIT_LOOP_END]] ], [ %[[PREV:.*]], %[[DESTROY_LOOP_BODY]] ] +// OGCG: %[[PREV]] = getelementptr inbounds %struct.array_element, ptr %[[CUR]], i64 -1 +// OGCG: call void @_ZN13array_elementD1Ev(ptr {{.*}} %[[PREV]]) +// OGCG: %[[CMP:.*]] = icmp eq ptr %[[PREV]], %[[BEGIN]] +// OGCG: br i1 %[[CMP]], label %[[DESTROY_LOOP_END:.*]], label %[[DESTROY_LOOP_BODY]] +// OGCG: [[DESTROY_LOOP_END:.*]]: +// OGCG: ret void diff --git a/clang/test/CIR/Lowering/array.cpp b/clang/test/CIR/Lowering/array.cpp index 438d41e2c2c2f..82d803a6b5aa2 100644 --- a/clang/test/CIR/Lowering/array.cpp +++ b/clang/test/CIR/Lowering/array.cpp @@ -57,17 +57,28 @@ void func() { void func2() { int arr[2] = {5}; } + // CHECK: define{{.*}} void @_Z5func2v() -// CHECK: %[[ARR_ALLOCA:.*]] = alloca [2 x i32], i64 1, align 4 -// CHECK: %[[TMP:.*]] = alloca ptr, i64 1, align 8 -// CHECK: %[[ARR_PTR:.*]] = getelementptr i32, ptr %[[ARR_ALLOCA]], i32 0 -// CHECK: store i32 5, ptr %[[ARR_PTR]], align 4 -// CHECK: %[[ELE_1_PTR:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i64 1 -// CHECK: store ptr %[[ELE_1_PTR]], ptr %[[TMP]], align 8 -// CHECK: %[[TMP2:.*]] = load ptr, ptr %[[TMP]], align 8 -// CHECK: store i32 0, ptr %[[TMP2]], align 4 -// CHECK: %[[ELE_1:.*]] = getelementptr i32, ptr %[[TMP2]], i64 1 -// CHECK: store ptr %[[ELE_1]], ptr %[[TMP]], align 8 +// CHECK: %[[ARR:.*]] = alloca [2 x i32], i64 1, align 4 +// CHECK: %[[TMP:.*]] = alloca ptr, i64 1, align 8 +// CHECK: %[[ARR_PTR:.*]] = getelementptr i32, ptr %[[ARR]], i32 0 +// CHECK: store i32 5, ptr %[[ARR_PTR]], align 4 +// CHECK: %[[ELE_1_PTR:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i64 1 +// CHECK: store ptr %[[ELE_1_PTR]], ptr %[[TMP]], align 8 +// CHECK: %[[END_PTR:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i64 2 +// CHECK: br label %[[LOOP_BODY:.*]] +// CHECK: [[LOOP_NEXT:.*]]: +// CHECK: %[[CUR:.*]] = load ptr, ptr %[[TMP]], align 8 +// CHECK: %[[CMP:.*]] = icmp ne ptr %[[CUR]], %[[END_PTR]] +// CHECK: br i1 %[[CMP]], label %[[LOOP_BODY]], label %[[LOOP_END:.*]] +// CHECK: [[LOOP_BODY]]: +// CHECK: %[[CUR:.*]] = load ptr, ptr %[[TMP]], align 8 +// CHECK: store i32 0, ptr %[[CUR]], align 4 +// CHECK: %[[NEXT:.*]] = getelementptr i32, ptr %[[CUR]], i64 1 +// CHECK: store ptr %[[NEXT]], ptr %[[TMP]], align 8 +// CHECK: br label %[[LOOP_NEXT:.*]] +// CHECK: [[LOOP_END]]: +// CHECK: ret void void func3() { int arr3[2] = {5, 6}; @@ -103,17 +114,27 @@ void func5() { int arr[2][1] = {{5}}; } // CHECK: define{{.*}} void @_Z5func5v() -// CHECK: %[[ARR_ALLOCA:.*]] = alloca [2 x [1 x i32]], i64 1, align 4 -// CHECK: %[[TMP:.*]] = alloca ptr, i64 1, align 8 -// CHECK: %[[ARR_PTR:.*]] = getelementptr [1 x i32], ptr %[[ARR_ALLOCA]], i32 0 -// CHECK: %[[ARR_0:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i32 0 -// CHECK: store i32 5, ptr %[[ARR_0]], align 4 -// CHECK: %[[ARR_1:.*]] = getelementptr [1 x i32], ptr %[[ARR_PTR]], i64 1 -// CHECK: store ptr %[[ARR_1]], ptr %[[TMP]], align 8 -// CHECK: %[[ARR_1_VAL:.*]] = load ptr, ptr %[[TMP]], align 8 -// CHECK: store [1 x i32] zeroinitializer, ptr %[[ARR_1_VAL]], align 4 -// CHECK: %[[ARR_1_PTR:.*]] = getelementptr [1 x i32], ptr %[[ARR_1_VAL]], i64 1 -// CHECK: store ptr %[[ARR_1_PTR]], ptr %[[TMP]], align 8 +// CHECK: %[[ARR:.*]] = alloca [2 x [1 x i32]], i64 1, align 4 +// CHECK: %[[TMP:.*]] = alloca ptr, i64 1, align 8 +// CHECK: %[[ARR_PTR:.*]] = getelementptr [1 x i32], ptr %[[ARR]], i32 0 +// CHECK: %[[ARR_0:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i32 0 +// CHECK: store i32 5, ptr %[[ARR_0]], align 4 +// CHECK: %[[ARR_1:.*]] = getelementptr [1 x i32], ptr %[[ARR_PTR]], i64 1 +// CHECK: store ptr %[[ARR_1]], ptr %[[TMP]], align 8 +// CHECK: %[[END_PTR:.*]] = getelementptr [1 x i32], ptr %[[ARR_PTR]], i64 2 +// CHECK: br label %[[LOOP_BODY:.*]] +// CHECK: [[LOOP_NEXT:.*]]: +// CHECK: %[[CUR:.*]] = load ptr, ptr %[[TMP]], align 8 +// CHECK: %[[CMP:.*]] = icmp ne ptr %[[CUR]], %[[END_PTR]] +// CHECK: br i1 %[[CMP]], label %[[LOOP_BODY]], label %[[LOOP_END:.*]] +// CHECK: [[LOOP_BODY]]: +// CHECK: %[[CUR:.*]] = load ptr, ptr %[[TMP]], align 8 +// CHECK: store [1 x i32] zeroinitializer, ptr %[[CUR]], align 4 +// CHECK: %[[NEXT:.*]] = getelementptr [1 x i32], ptr %[[CUR]], i64 1 +// CHECK: store ptr %[[NEXT]], ptr %[[TMP]], align 8 +// CHECK: br label %[[LOOP_NEXT:.*]] +// CHECK: [[LOOP_END]]: +// CHECK: ret void void func6() { int x = 4; @@ -133,14 +154,24 @@ void func7() { int* arr[1] = {}; } // CHECK: define{{.*}} void @_Z5func7v() -// CHECK: %[[ARR:.*]] = alloca [1 x ptr], i64 1, align 8 -// CHECK: %[[ALLOCA:.*]] = alloca ptr, i64 1, align 8 -// CHECK: %[[ELE_PTR:.*]] = getelementptr ptr, ptr %[[ARR]], i32 0 -// CHECK: store ptr %[[ELE_PTR]], ptr %[[ALLOCA]], align 8 -// CHECK: %[[TMP:.*]] = load ptr, ptr %[[ALLOCA]], align 8 -// CHECK: store ptr null, ptr %[[TMP]], align 8 -// CHECK: %[[ELE:.*]] = getelementptr ptr, ptr %[[TMP]], i64 1 -// CHECK: store ptr %[[ELE]], ptr %[[ALLOCA]], align 8 +// CHECK: %[[ARR:.*]] = alloca [1 x ptr], i64 1, align 8 +// CHECK: %[[TMP:.*]] = alloca ptr, i64 1, align 8 +// CHECK: %[[ARR_PTR:.*]] = getelementptr ptr, ptr %[[ARR]], i32 0 +// CHECK: store ptr %[[ARR_PTR]], ptr %[[TMP]], align 8 +// CHECK: %[[END_PTR:.*]] = getelementptr ptr, ptr %[[ARR_PTR]], i64 1 +// CHECK: br label %[[LOOP_BODY:.*]] +// CHECK: [[LOOP_NEXT:.*]]: +// CHECK: %[[CUR:.*]] = load ptr, ptr %[[TMP]], align 8 +// CHECK: %[[CMP:.*]] = icmp ne ptr %[[CUR]], %[[END_PTR]] +// CHECK: br i1 %[[CMP]], label %[[LOOP_BODY]], label %[[LOOP_END:.*]] +// CHECK: [[LOOP_BODY]]: +// CHECK: %[[CUR:.*]] = load ptr, ptr %[[TMP]], align 8 +// CHECK: store ptr null, ptr %[[CUR]], align 8 +// CHECK: %[[NEXT:.*]] = getelementptr ptr, ptr %[[CUR]], i64 1 +// CHECK: store ptr %[[NEXT]], ptr %[[TMP]], align 8 +// CHECK: br label %[[LOOP_NEXT:.*]] +// CHECK: [[LOOP_END]]: +// CHECK: ret void void func8(int p[10]) {} // CHECK: define{{.*}} void @_Z5func8Pi(ptr {{%.*}}) _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits