From aa282a92d63fdc8bc81bc6a4b3846b4d3e946d6b Mon Sep 17 00:00:00 2001 From: Bruno Cardoso Lopes Date: Wed, 28 Aug 2024 19:27:25 -0700 Subject: [PATCH] [CIR][CIRGen] Handle paren list init and get dtors right --- clang/include/clang/CIR/MissingFeatures.h | 1 + clang/lib/CIR/CodeGen/CIRGenClass.cpp | 29 ++++++++++++++-- clang/lib/CIR/CodeGen/CIRGenDecl.cpp | 19 +++++++++++ clang/lib/CIR/CodeGen/CIRGenExprAgg.cpp | 15 +++++++-- clang/lib/CIR/CodeGen/CIRGenFunction.h | 19 +++++++++++ clang/test/CIR/CodeGen/paren-list-init.cpp | 39 ++++++++++++++++++++++ 6 files changed, 118 insertions(+), 4 deletions(-) create mode 100644 clang/test/CIR/CodeGen/paren-list-init.cpp diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index bdfffd4788c1..665f5e5baf62 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -184,6 +184,7 @@ struct MissingFeatures { static bool deferredReplacements() { return false; } static bool shouldInstrumentFunction() { return false; } static bool xray() { return false; } + static bool flagLoad() { return false; } // Inline assembly static bool asmGoto() { return false; } diff --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp b/clang/lib/CIR/CodeGen/CIRGenClass.cpp index 50476594005e..ca2a5bc22936 100644 --- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp @@ -1236,6 +1236,30 @@ struct CallDtorDelete final : EHScopeStack::Cleanup { }; } // namespace +class DestroyField final : public EHScopeStack::Cleanup { + const FieldDecl *field; + CIRGenFunction::Destroyer *destroyer; + bool useEHCleanupForArray; + +public: + DestroyField(const FieldDecl *field, CIRGenFunction::Destroyer *destroyer, + bool useEHCleanupForArray) + : field(field), destroyer(destroyer), + useEHCleanupForArray(useEHCleanupForArray) {} + + void Emit(CIRGenFunction &CGF, Flags flags) override { + // Find the address of the field. + Address thisValue = CGF.LoadCXXThisAddress(); + QualType RecordTy = CGF.getContext().getTagDeclType(field->getParent()); + LValue ThisLV = CGF.makeAddrLValue(thisValue, RecordTy); + LValue LV = CGF.buildLValueForField(ThisLV, field); + assert(LV.isSimple()); + + CGF.emitDestroy(LV.getAddress(), field->getType(), destroyer, + flags.isForNormalCleanup() && useEHCleanupForArray); + } +}; + /// Emit all code that comes at the end of class's destructor. This is to call /// destructors on members and base classes in reverse order of their /// construction. @@ -1346,8 +1370,9 @@ void CIRGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD, if (RT && RT->getDecl()->isAnonymousStructOrUnion()) continue; - [[maybe_unused]] CleanupKind cleanupKind = getCleanupKind(dtorKind); - llvm_unreachable("EHStack.pushCleanup(...) NYI"); + CleanupKind cleanupKind = getCleanupKind(dtorKind); + EHStack.pushCleanup( + cleanupKind, Field, getDestroyer(dtorKind), cleanupKind & EHCleanup); } if (SanitizeFields) diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp index 9a08ccd0d1ff..6ae30a141433 100644 --- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp @@ -1247,3 +1247,22 @@ void CIRGenFunction::pushEHDestroy(QualType::DestructionKind dtorKind, pushDestroy(EHCleanup, addr, type, getDestroyer(dtorKind), true); } + +// Pushes a destroy and defers its deactivation until its +// CleanupDeactivationScope is exited. +void CIRGenFunction::pushDestroyAndDeferDeactivation( + QualType::DestructionKind dtorKind, Address addr, QualType type) { + assert(dtorKind && "cannot push destructor for trivial type"); + + CleanupKind cleanupKind = getCleanupKind(dtorKind); + pushDestroyAndDeferDeactivation( + cleanupKind, addr, type, getDestroyer(dtorKind), cleanupKind & EHCleanup); +} + +void CIRGenFunction::pushDestroyAndDeferDeactivation( + CleanupKind cleanupKind, Address addr, QualType type, Destroyer *destroyer, + bool useEHCleanupForArray) { + assert(!MissingFeatures::flagLoad()); + pushDestroy(cleanupKind, addr, type, destroyer, useEHCleanupForArray); + DeferredDeactivationCleanupStack.push_back({EHStack.stable_begin(), nullptr}); +} diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAgg.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAgg.cpp index c403de3c51da..22a0418e031c 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprAgg.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprAgg.cpp @@ -274,6 +274,7 @@ class AggExprEmitter : public StmtVisitor { void VisitAbstractConditionalOperator(const AbstractConditionalOperator *E); void VisitChooseExpr(const ChooseExpr *E) { llvm_unreachable("NYI"); } void VisitInitListExpr(InitListExpr *E); + void VisitCXXParenListInitExpr(CXXParenListInitExpr *E); void VisitCXXParenListOrInitListExpr(Expr *ExprToVisit, ArrayRef Args, FieldDecl *InitializedFieldInUnion, Expr *ArrayFiller); @@ -1194,6 +1195,12 @@ void AggExprEmitter::VisitBinCmp(const BinaryOperator *E) { // All done! The result is in the Dest slot. } +void AggExprEmitter::VisitCXXParenListInitExpr(CXXParenListInitExpr *E) { + VisitCXXParenListOrInitListExpr(E, E->getInitExprs(), + E->getInitializedFieldInUnion(), + E->getArrayFiller()); +} + void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { // TODO(cir): use something like CGF.ErrorUnsupported if (E->hadArrayRangeDesignator()) @@ -1350,10 +1357,14 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr( // Push a destructor if necessary. // FIXME: if we have an array of structures, all explicitly // initialized, we can end up pushing a linear number of cleanups. - [[maybe_unused]] bool pushedCleanup = false; if (QualType::DestructionKind dtorKind = field->getType().isDestructedType()) { - llvm_unreachable("NYI"); + assert(LV.isSimple()); + if (dtorKind) { + CGF.pushDestroyAndDeferDeactivation(NormalAndEHCleanup, LV.getAddress(), + field->getType(), + CGF.getDestroyer(dtorKind), false); + } } // From LLVM codegen, maybe not useful for CIR: diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index a2bd5f47894f..b6ecf78c62dc 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -375,6 +375,20 @@ class CIRGenFunction : public CIRGenTypeCache { EHScopeStack EHStack; llvm::SmallVector LifetimeExtendedCleanupStack; + // A stack of cleanups which were added to EHStack but have to be deactivated + // later before being popped or emitted. These are usually deactivated on + // exiting a `CleanupDeactivationScope` scope. For instance, after a + // full-expr. + // + // These are specially useful for correctly emitting cleanups while + // encountering branches out of expression (through stmt-expr or coroutine + // suspensions). + struct DeferredDeactivateCleanup { + EHScopeStack::stable_iterator Cleanup; + mlir::Operation *DominatingIP; + }; + llvm::SmallVector DeferredDeactivationCleanupStack; + /// A mapping from NRVO variables to the flags used to indicate /// when the NRVO has been applied to this variable. llvm::DenseMap NRVOFlags; @@ -1811,6 +1825,11 @@ class CIRGenFunction : public CIRGenTypeCache { QualType elementType, CharUnits elementAlign, Destroyer *destroyer); + void pushDestroyAndDeferDeactivation(QualType::DestructionKind dtorKind, + Address addr, QualType type); + void pushDestroyAndDeferDeactivation(CleanupKind cleanupKind, Address addr, + QualType type, Destroyer *destroyer, + bool useEHCleanupForArray); void buildArrayDestroy(mlir::Value begin, mlir::Value end, QualType elementType, CharUnits elementAlign, Destroyer *destroyer, bool checkZeroLength, diff --git a/clang/test/CIR/CodeGen/paren-list-init.cpp b/clang/test/CIR/CodeGen/paren-list-init.cpp new file mode 100644 index 000000000000..f20c932f69f9 --- /dev/null +++ b/clang/test/CIR/CodeGen/paren-list-init.cpp @@ -0,0 +1,39 @@ +// RUN: %clang_cc1 -std=c++20 -triple aarch64-none-linux-android21 -Wno-unused-value -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s + +struct Vec { + Vec(); + Vec(Vec&&); + ~Vec(); +}; + +struct S1 { + Vec v; +}; + +// CIR-DAG: ![[VecType:.*]] = !cir.struct}> +// CIR-DAG: ![[S1:.*]] = !cir.struct}>}> + +template +void make1() { + Vec v; + S1((Vec&&) v); +// CIR: cir.func linkonce_odr @_Z5make1ILi0EEvv() +// CIR: %[[VEC:.*]] = cir.alloca ![[VecType]], !cir.ptr +// CIR: cir.call @_ZN3VecC1Ev(%[[VEC]]) : (!cir.ptr) +// CIR: cir.scope { +// CIR: %[[AGG_TMP:.*]] = cir.alloca ![[S1]], !cir.ptr, ["agg.tmp.ensured"] +// CIR: %[[FIELD:.*]] = cir.get_member %[[AGG_TMP]][0] {name = "v"} : !cir.ptr -> !cir.ptr +// CIR: cir.call @_ZN3VecC1EOS_(%[[FIELD]], %[[VEC]]) : (!cir.ptr, !cir.ptr) -> () +// CIR: cir.call @_ZN2S1D1Ev(%[[AGG_TMP]]) : (!cir.ptr) -> () +// CIR: cir.call @_ZN3VecD1Ev(%[[FIELD]]) : (!cir.ptr) -> () +// CIR: } + +// FIXME: implement MissingFeatures::flagLoad(), do not emit this a second time. +// CIR: cir.call @_ZN3VecD1Ev(%[[VEC]]) : (!cir.ptr) -> () +// CIR: cir.return +} + +void foo() { + make1<0>(); +} \ No newline at end of file