[clang] dedcf88 - [CIR] Implement NRVO variable cleanup (#170774)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Dec 5 15:59:18 PST 2025
Author: Andy Kaylor
Date: 2025-12-05T23:59:14Z
New Revision: dedcf88569c4b45b1ab78d05304045326336de0c
URL: https://github.com/llvm/llvm-project/commit/dedcf88569c4b45b1ab78d05304045326336de0c
DIFF: https://github.com/llvm/llvm-project/commit/dedcf88569c4b45b1ab78d05304045326336de0c.diff
LOG: [CIR] Implement NRVO variable cleanup (#170774)
This implements the cleanup handling for C++ NRVO variables. Because
exception handling is still incomplete, this doesn't behave any
differently with exceptions enabled yet, but the NRVO-specific code for
that case is trivial.
Added:
Modified:
clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
clang/include/clang/CIR/MissingFeatures.h
clang/lib/CIR/CodeGen/CIRGenDecl.cpp
clang/test/CIR/CodeGen/nrvo.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index c2598a1bc9f7b..aa47c4bce189b 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -331,6 +331,14 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
return cir::StoreOp::create(*this, loc, val, dst, isVolatile, align, order);
}
+ /// Emit a load from an boolean flag variable.
+ cir::LoadOp createFlagLoad(mlir::Location loc, mlir::Value addr) {
+ mlir::Type boolTy = getBoolTy();
+ if (boolTy != mlir::cast<cir::PointerType>(addr.getType()).getPointee())
+ addr = createPtrBitcast(addr, boolTy);
+ return createLoad(loc, addr, /*isVolatile=*/false, /*alignment=*/1);
+ }
+
cir::StoreOp createFlagStore(mlir::Location loc, bool val, mlir::Value dst) {
mlir::Value flag = getBool(val, loc);
return CIRBaseBuilderTy::createStore(loc, flag, dst);
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index b8df0528ea18d..826a4b13f5c0c 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -227,7 +227,6 @@ struct MissingFeatures {
static bool countedBySize() { return false; }
static bool cgFPOptionsRAII() { return false; }
static bool checkBitfieldClipping() { return false; }
- static bool cleanupDestroyNRVOVariable() { return false; }
static bool cirgenABIInfo() { return false; }
static bool cleanupAfterErrorDiags() { return false; }
static bool cleanupAppendInsts() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
index e93ddd9b8a32d..948245ceab2cd 100644
--- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
@@ -106,7 +106,7 @@ CIRGenFunction::emitAutoVarAlloca(const VarDecl &d,
cir::ConstantOp falseNVRO = builder.getFalse(loc);
Address nrvoFlag = createTempAlloca(falseNVRO.getType(),
CharUnits::One(), loc, "nrvo",
- /*arraySize=*/nullptr, &address);
+ /*arraySize=*/nullptr);
assert(builder.getInsertionBlock());
builder.createStore(loc, falseNVRO, nrvoFlag);
@@ -835,7 +835,24 @@ template <class Derived> struct DestroyNRVOVariable : EHScopeStack::Cleanup {
QualType ty;
void emit(CIRGenFunction &cgf, Flags flags) override {
- assert(!cir::MissingFeatures::cleanupDestroyNRVOVariable());
+ // Along the exceptions path we always execute the dtor.
+ bool nrvo = flags.isForNormalCleanup() && nrvoFlag;
+
+ CIRGenBuilderTy &builder = cgf.getBuilder();
+ mlir::OpBuilder::InsertionGuard guard(builder);
+ if (nrvo) {
+ // If we exited via NRVO, we skip the destructor call.
+ mlir::Location loc = addr.getPointer().getLoc();
+ mlir::Value didNRVO = builder.createFlagLoad(loc, nrvoFlag);
+ mlir::Value notNRVO = builder.createNot(didNRVO);
+ cir::IfOp::create(builder, loc, notNRVO, /*withElseRegion=*/false,
+ [&](mlir::OpBuilder &b, mlir::Location) {
+ static_cast<Derived *>(this)->emitDestructorCall(cgf);
+ builder.createYield(loc);
+ });
+ } else {
+ static_cast<Derived *>(this)->emitDestructorCall(cgf);
+ }
}
virtual ~DestroyNRVOVariable() = default;
@@ -851,7 +868,9 @@ struct DestroyNRVOVariableCXX final
const CXXDestructorDecl *dtor;
void emitDestructorCall(CIRGenFunction &cgf) {
- assert(!cir::MissingFeatures::cleanupDestroyNRVOVariable());
+ cgf.emitCXXDestructorCall(dtor, Dtor_Complete,
+ /*forVirtualBase=*/false,
+ /*delegating=*/false, addr, ty);
}
};
diff --git a/clang/test/CIR/CodeGen/nrvo.cpp b/clang/test/CIR/CodeGen/nrvo.cpp
index 05cd79ea1caf9..0fc9b9ba54012 100644
--- a/clang/test/CIR/CodeGen/nrvo.cpp
+++ b/clang/test/CIR/CodeGen/nrvo.cpp
@@ -72,6 +72,11 @@ NonTrivial test_nrvo() {
// CIR: cir.call @_Z10maybeThrowv() : () -> ()
// CIR: %[[TRUE:.*]] = cir.const #true
// CIR: cir.store{{.*}} %[[TRUE]], %[[NRVO_FLAG]]
+// CIR: %[[NRVO_FLAG_VAL:.*]] = cir.load{{.*}} %[[NRVO_FLAG]]
+// CIR: %[[NOT_NRVO_VAL:.*]] = cir.unary(not, %[[NRVO_FLAG_VAL]])
+// CIR: cir.if %[[NOT_NRVO_VAL]] {
+// CIR: cir.call @_ZN10NonTrivialD1Ev(%[[RESULT]])
+// CIR: }
// CIR: %[[RET:.*]] = cir.load %[[RESULT]]
// CIR: cir.return %[[RET]]
@@ -81,6 +86,14 @@ NonTrivial test_nrvo() {
// LLVM: store i8 0, ptr %[[NRVO_FLAG]]
// LLVM: call void @_Z10maybeThrowv()
// LLVM: store i8 1, ptr %[[NRVO_FLAG]]
+// LLVM: %[[NRVO_VAL:.*]] = load i8, ptr %[[NRVO_FLAG]]
+// LLVM: %[[NRVO_VAL_TRUNC:.*]] = trunc i8 %[[NRVO_VAL]] to i1
+// LLVM: %[[NOT_NRVO_VAL:.*]] = xor i1 %[[NRVO_VAL_TRUNC]], true
+// LLVM: br i1 %[[NOT_NRVO_VAL]], label %[[NRVO_UNUSED:.*]], label %[[NRVO_USED:.*]]
+// LLVM: [[NRVO_UNUSED]]:
+// LLVM: call void @_ZN10NonTrivialD1Ev(ptr %[[RESULT]])
+// LLVM: br label %[[NRVO_USED]]
+// LLVM: [[NRVO_USED]]:
// LLVM: %[[RET:.*]] = load %struct.NonTrivial, ptr %[[RESULT]]
// LLVM: ret %struct.NonTrivial %[[RET]]
More information about the cfe-commits
mailing list