-
Notifications
You must be signed in to change notification settings - Fork 15.4k
[CIR] Implement NRVO variable cleanup #170774
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
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 code for that case is trivial.
|
@llvm/pr-subscribers-clang @llvm/pr-subscribers-clangir Author: Andy Kaylor (andykaylor) ChangesThis 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. Full diff: https://github.com/llvm/llvm-project/pull/170774.diff 4 Files Affected:
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..3431761abcd92 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);
+ mlir::Location loc = addr.getPointer().getLoc();
+ if (nrvo) {
+ // If we exited via NRVO, we skip the destructor call.
+ 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]]
|
| cir::ConstantOp falseNVRO = builder.getFalse(loc); | ||
| Address nrvoFlag = createTempAlloca(falseNVRO.getType(), | ||
| CharUnits::One(), loc, "nrvo", | ||
| /*arraySize=*/nullptr, &address); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was wrong. It was overwriting the Address in this function that is tracking the variable we're emitting. The incubator passes a separate allocaAddr argument here, which is also wrong but that variable isn't used in the incubator so it doesn't cause problems. Classic codegen has an AllocaAddr variable, but it doesn't pass it to CreateTempAlloca in this part of the code.
AmrDeveloper
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with nit
clang/lib/CIR/CodeGen/CIRGenDecl.cpp
Outdated
|
|
||
| CIRGenBuilderTy &builder = cgf.getBuilder(); | ||
| mlir::OpBuilder::InsertionGuard guard(builder); | ||
| mlir::Location loc = addr.getPointer().getLoc(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If loc will be used only inside the if block, should we move it inside it 🤔
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/190/builds/32291 Here is the relevant piece of the build log for the reference |
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.
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.