Skip to content

Commit 032f31b

Browse files
andykayloraokblast
authored andcommitted
[CIR] Handle operator delete with virtual destructors (llvm#165010)
This adds support for emitting operator delete when used with classes that have a virtual destructor.
1 parent 56c3c6c commit 032f31b

File tree

5 files changed

+67
-2
lines changed

5 files changed

+67
-2
lines changed

clang/include/clang/CIR/MissingFeatures.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ struct MissingFeatures {
241241
static bool dataLayoutPtrHandlingBasedOnLangAS() { return false; }
242242
static bool deferredCXXGlobalInit() { return false; }
243243
static bool deleteArray() { return false; }
244+
static bool devirtualizeDestructor() { return false; }
244245
static bool devirtualizeMemberFunction() { return false; }
245246
static bool ehCleanupFlags() { return false; }
246247
static bool ehCleanupHasPrebranchedFallthrough() { return false; }

clang/lib/CIR/CodeGen/CIRGenCXXABI.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,11 @@ class CIRGenCXXABI {
187187
virtual void registerGlobalDtor(const VarDecl *vd, cir::FuncOp dtor,
188188
mlir::Value addr) = 0;
189189

190+
virtual void emitVirtualObjectDelete(CIRGenFunction &cgf,
191+
const CXXDeleteExpr *de, Address ptr,
192+
QualType elementType,
193+
const CXXDestructorDecl *dtor) = 0;
194+
190195
/// Checks if ABI requires extra virtual offset for vtable field.
191196
virtual bool
192197
isVirtualOffsetNeededForVTableField(CIRGenFunction &cgf,

clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -565,8 +565,10 @@ static void emitObjectDelete(CIRGenFunction &cgf, const CXXDeleteExpr *de,
565565
dtor = rd->getDestructor();
566566

567567
if (dtor->isVirtual()) {
568-
cgf.cgm.errorNYI(de->getSourceRange(),
569-
"emitObjectDelete: virtual destructor");
568+
assert(!cir::MissingFeatures::devirtualizeDestructor());
569+
cgf.cgm.getCXXABI().emitVirtualObjectDelete(cgf, de, ptr, elementType,
570+
dtor);
571+
return;
570572
}
571573
}
572574
}

clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI {
7474
QualType thisTy) override;
7575
void registerGlobalDtor(const VarDecl *vd, cir::FuncOp dtor,
7676
mlir::Value addr) override;
77+
void emitVirtualObjectDelete(CIRGenFunction &cgf, const CXXDeleteExpr *de,
78+
Address ptr, QualType elementType,
79+
const CXXDestructorDecl *dtor) override;
7780

7881
void emitRethrow(CIRGenFunction &cgf, bool isNoReturn) override;
7982
void emitThrow(CIRGenFunction &cgf, const CXXThrowExpr *e) override;
@@ -2175,6 +2178,21 @@ mlir::Value CIRGenItaniumCXXABI::emitDynamicCast(CIRGenFunction &cgf,
21752178
isRefCast, castInfo);
21762179
}
21772180

2181+
/// The Itanium ABI always places an offset to the complete object
2182+
/// at entry -2 in the vtable.
2183+
void CIRGenItaniumCXXABI::emitVirtualObjectDelete(
2184+
CIRGenFunction &cgf, const CXXDeleteExpr *delExpr, Address ptr,
2185+
QualType elementType, const CXXDestructorDecl *dtor) {
2186+
bool useGlobalDelete = delExpr->isGlobalDelete();
2187+
if (useGlobalDelete) {
2188+
cgf.cgm.errorNYI(delExpr->getSourceRange(),
2189+
"emitVirtualObjectDelete: global delete");
2190+
}
2191+
2192+
CXXDtorType dtorType = useGlobalDelete ? Dtor_Complete : Dtor_Deleting;
2193+
emitVirtualDestructorCall(cgf, dtor, dtorType, ptr, delExpr);
2194+
}
2195+
21782196
/************************** Array allocation cookies **************************/
21792197

21802198
CharUnits CIRGenItaniumCXXABI::getArrayCookieSizeImpl(QualType elementType) {

clang/test/CIR/CodeGen/delete.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,42 @@ Container::~Container() { delete contents; }
8686
// These functions are declared/defined below the calls in OGCG.
8787
// OGCG: define linkonce_odr void @_ZN8ContentsD2Ev
8888
// OGCG: declare void @_ZdlPvm(ptr noundef, i64 noundef)
89+
90+
struct StructWithVirtualDestructor {
91+
virtual ~StructWithVirtualDestructor();
92+
};
93+
94+
void destroy(StructWithVirtualDestructor *x) {
95+
delete x;
96+
}
97+
98+
// CIR: cir.func {{.*}} @_Z7destroyP27StructWithVirtualDestructor(%[[X_ARG:.*]]: !cir.ptr<!rec_StructWithVirtualDestructor> {{.*}})
99+
// CIR: %[[X_ADDR:.*]] = cir.alloca !cir.ptr<!rec_StructWithVirtualDestructor>
100+
// CIR: cir.store %[[X_ARG]], %[[X_ADDR]]
101+
// CIR: %[[X:.*]] = cir.load{{.*}} %[[X_ADDR]]
102+
// CIR: %[[VTABLE_PTR:.*]] = cir.vtable.get_vptr %[[X]] : !cir.ptr<!rec_StructWithVirtualDestructor> -> !cir.ptr<!cir.vptr>
103+
// CIR: %[[VTABLE:.*]] = cir.load{{.*}} %[[VTABLE_PTR]] : !cir.ptr<!cir.vptr>, !cir.vptr
104+
// CIR: %[[DTOR_FN_ADDR_PTR:.*]] = cir.vtable.get_virtual_fn_addr %[[VTABLE]][1]
105+
// CIR: %[[DTOR_FN_ADDR:.*]] = cir.load{{.*}} %[[DTOR_FN_ADDR_PTR]]
106+
// CIR: cir.call %[[DTOR_FN_ADDR]](%[[X]])
107+
108+
// LLVM: define {{.*}} void @_Z7destroyP27StructWithVirtualDestructor(ptr %[[X_ARG:.*]])
109+
// LLVM: %[[X_ADDR:.*]] = alloca ptr
110+
// LLVM: store ptr %[[X_ARG]], ptr %[[X_ADDR]]
111+
// LLVM: %[[X:.*]] = load ptr, ptr %[[X_ADDR]]
112+
// LLVM: %[[VTABLE:.*]] = load ptr, ptr %[[X]]
113+
// LLVM: %[[DTOR_FN_ADDR_PTR:.*]] = getelementptr inbounds ptr, ptr %[[VTABLE]], i32 1
114+
// LLVM: %[[DTOR_FN_ADDR:.*]] = load ptr, ptr %[[DTOR_FN_ADDR_PTR]]
115+
// LLVM: call void %[[DTOR_FN_ADDR]](ptr %[[X]])
116+
117+
// OGCG: define {{.*}} void @_Z7destroyP27StructWithVirtualDestructor(ptr {{.*}} %[[X_ARG:.*]])
118+
// OGCG: %[[X_ADDR:.*]] = alloca ptr
119+
// OGCG: store ptr %[[X_ARG]], ptr %[[X_ADDR]]
120+
// OGCG: %[[X:.*]] = load ptr, ptr %[[X_ADDR]]
121+
// OGCG: %[[ISNULL:.*]] = icmp eq ptr %[[X]], null
122+
// OGCG: br i1 %[[ISNULL]], label %{{.*}}, label %[[DELETE_NOTNULL:.*]]
123+
// OGCG: [[DELETE_NOTNULL]]:
124+
// OGCG: %[[VTABLE:.*]] = load ptr, ptr %[[X]]
125+
// OGCG: %[[DTOR_FN_ADDR_PTR:.*]] = getelementptr inbounds ptr, ptr %[[VTABLE]], i64 1
126+
// OGCG: %[[DTOR_FN_ADDR:.*]] = load ptr, ptr %[[DTOR_FN_ADDR_PTR]]
127+
// OGCG: call void %[[DTOR_FN_ADDR]](ptr {{.*}} %[[X]])

0 commit comments

Comments
 (0)