Skip to content

Commit fcd1b68

Browse files
authored
[CIR][CIRGen] Introduce cir.delete.array op (#1172)
I am working on a clangir based solution to improve C++'s safety (https://discourse.llvm.org/t/rfc-a-clangir-based-safe-c/83245). This is similar with the previous analysis only approach I proposed, where we may not care about the lowered code. And this is what I described as layering problems in https://discourse.llvm.org/t/rfc-a-clangir-based-safe-c/83245 This is similar with the other issue proposed #1128. We'd better to emit the higher level operations and lowering/optimizing it later. This is also inspired our handling method for VAArg, where we use ABI information to lower things during the passes. It gives me more confidence that I am doing things right.
1 parent a989ecb commit fcd1b68

File tree

7 files changed

+68
-4
lines changed

7 files changed

+68
-4
lines changed

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3555,6 +3555,21 @@ def LLVMIntrinsicCallOp : CIR_Op<"llvm.intrinsic"> {
35553555

35563556
}
35573557

3558+
//===----------------------------------------------------------------------===//
3559+
// DeleteArrayOp
3560+
//===----------------------------------------------------------------------===//
3561+
3562+
def DeleteArrayOp : CIR_Op<"delete.array">,
3563+
Arguments<(ins CIR_PointerType:$address)> {
3564+
let summary = "Delete address representing an array";
3565+
let description = [{
3566+
`cir.delete.array` operation deletes an array. For example, `delete[] ptr;`
3567+
will be translated to `cir.delete.array %ptr`.
3568+
}];
3569+
let assemblyFormat = "$address `:` type($address) attr-dict";
3570+
let hasVerifier = 0;
3571+
}
3572+
35583573
//===----------------------------------------------------------------------===//
35593574
// CallOp and TryCallOp
35603575
//===----------------------------------------------------------------------===//

clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -901,17 +901,23 @@ void CIRGenFunction::emitCXXDeleteExpr(const CXXDeleteExpr *E) {
901901
return;
902902
}
903903

904+
// In CodeGen:
904905
// We might be deleting a pointer to array. If so, GEP down to the
905906
// first non-array element.
906907
// (this assumes that A(*)[3][7] is converted to [3 x [7 x %A]]*)
908+
// In CIRGen: we handle this differently because the deallocation of
909+
// array highly relates to the array cookies, which is ABI sensitive,
910+
// we plan to handle it in LoweringPreparePass and the corresponding
911+
// ABI part.
907912
if (DeleteTy->isConstantArrayType()) {
908-
llvm_unreachable("NYI");
913+
Ptr = Ptr;
909914
}
910915

911916
assert(convertTypeForMem(DeleteTy) == Ptr.getElementType());
912917

913918
if (E->isArrayForm()) {
914-
llvm_unreachable("NYI");
919+
builder.create<cir::DeleteArrayOp>(Ptr.getPointer().getLoc(),
920+
Ptr.getPointer());
915921
} else {
916922
(void)EmitObjectDelete(*this, E, Ptr, DeleteTy);
917923
}

clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> {
7777
void lowerComplexBinOp(ComplexBinOp op);
7878
void lowerThreeWayCmpOp(CmpThreeWayOp op);
7979
void lowerVAArgOp(VAArgOp op);
80+
void lowerDeleteArrayOp(DeleteArrayOp op);
8081
void lowerGlobalOp(GlobalOp op);
8182
void lowerDynamicCastOp(DynamicCastOp op);
8283
void lowerStdFindOp(StdFindOp op);
@@ -157,6 +158,8 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> {
157158
/// Tracks current module.
158159
ModuleOp theModule;
159160

161+
std::optional<cir::CIRDataLayout> datalayout;
162+
160163
/// Tracks existing dynamic initializers.
161164
llvm::StringMap<uint32_t> dynamicInitializerNames;
162165
llvm::SmallVector<FuncOp, 4> dynamicInitializers;
@@ -344,16 +347,26 @@ static void canonicalizeIntrinsicThreeWayCmp(CIRBaseBuilderTy &builder,
344347
void LoweringPreparePass::lowerVAArgOp(VAArgOp op) {
345348
CIRBaseBuilderTy builder(getContext());
346349
builder.setInsertionPoint(op);
347-
cir::CIRDataLayout datalayout(theModule);
348350

349-
auto res = cxxABI->lowerVAArg(builder, op, datalayout);
351+
auto res = cxxABI->lowerVAArg(builder, op, *datalayout);
350352
if (res) {
351353
op.replaceAllUsesWith(res);
352354
op.erase();
353355
}
354356
return;
355357
}
356358

359+
void LoweringPreparePass::lowerDeleteArrayOp(DeleteArrayOp op) {
360+
CIRBaseBuilderTy builder(getContext());
361+
builder.setInsertionPoint(op);
362+
363+
cxxABI->lowerDeleteArray(builder, op, *datalayout);
364+
// DeleteArrayOp won't have a result, so we don't need to replace
365+
// the uses.
366+
op.erase();
367+
return;
368+
}
369+
357370
void LoweringPreparePass::lowerUnaryOp(UnaryOp op) {
358371
auto ty = op.getType();
359372
if (!mlir::isa<cir::ComplexType>(ty))
@@ -1154,6 +1167,8 @@ void LoweringPreparePass::runOnOp(Operation *op) {
11541167
lowerThreeWayCmpOp(threeWayCmp);
11551168
} else if (auto vaArgOp = dyn_cast<VAArgOp>(op)) {
11561169
lowerVAArgOp(vaArgOp);
1170+
} else if (auto deleteArrayOp = dyn_cast<DeleteArrayOp>(op)) {
1171+
lowerDeleteArrayOp(deleteArrayOp);
11571172
} else if (auto getGlobal = dyn_cast<GlobalOp>(op)) {
11581173
lowerGlobalOp(getGlobal);
11591174
} else if (auto dynamicCast = dyn_cast<DynamicCastOp>(op)) {
@@ -1188,6 +1203,7 @@ void LoweringPreparePass::runOnOperation() {
11881203
auto *op = getOperation();
11891204
if (isa<::mlir::ModuleOp>(op)) {
11901205
theModule = cast<::mlir::ModuleOp>(op);
1206+
datalayout.emplace(theModule);
11911207
}
11921208

11931209
llvm::SmallVector<Operation *> opsToTransform;

clang/lib/CIR/Dialect/Transforms/LoweringPrepareCXXABI.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ class LoweringPrepareCXXABI {
3232

3333
virtual mlir::Value lowerVAArg(CIRBaseBuilderTy &builder, cir::VAArgOp op,
3434
const cir::CIRDataLayout &datalayout) = 0;
35+
36+
virtual mlir::Value
37+
lowerDeleteArray(cir::CIRBaseBuilderTy &builder, cir::DeleteArrayOp op,
38+
const cir::CIRDataLayout &datalayout) = 0;
3539
virtual ~LoweringPrepareCXXABI() {}
3640

3741
virtual mlir::Value lowerDynamicCast(CIRBaseBuilderTy &builder,

clang/lib/CIR/Dialect/Transforms/LoweringPrepareItaniumCXXABI.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,16 @@ class LoweringPrepareItaniumCXXABI : public cir::LoweringPrepareCXXABI {
2121
cir::DynamicCastOp op) override;
2222
mlir::Value lowerVAArg(cir::CIRBaseBuilderTy &builder, cir::VAArgOp op,
2323
const cir::CIRDataLayout &datalayout) override;
24+
25+
mlir::Value lowerDeleteArray(cir::CIRBaseBuilderTy &builder,
26+
cir::DeleteArrayOp op,
27+
const cir::CIRDataLayout &datalayout) override {
28+
// Note: look at `CIRGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *)`
29+
// in CIRGenExprCXX.cpp.
30+
// In traditional code gen, we need handle ABI related array cookie to
31+
// generate codes to handle the expression to delete array. We need similar
32+
// mechanism here for ItaniumCXXABI.
33+
llvm_unreachable("NYI && Delete Array is not supported to be lowered in "
34+
"Itanium CXX ABI");
35+
}
2436
};

clang/lib/CIR/Dialect/Transforms/TargetLowering/ItaniumCXXABI.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,4 +210,7 @@ class LoweringPrepareItaniumCXXABI : public cir::LoweringPrepareCXXABI {
210210
cir::DynamicCastOp op) override;
211211
mlir::Value lowerVAArg(cir::CIRBaseBuilderTy &builder, cir::VAArgOp op,
212212
const cir::CIRDataLayout &datalayout) override;
213+
mlir::Value lowerDeleteArray(cir::CIRBaseBuilderTy &builder,
214+
cir::DeleteArrayOp op,
215+
const cir::CIRDataLayout &datalayout) override;
213216
};
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -fclangir -emit-cir %s -o %t.cir
2+
// RUN: FileCheck --input-file=%t.cir %s
3+
4+
void test_delete_array(int *ptr) {
5+
delete[] ptr;
6+
}
7+
8+
// CHECK: cir.delete.array

0 commit comments

Comments
 (0)