Skip to content

Commit

Permalink
[CIR][CIRGen] Handle paren list init and get dtors right
Browse files Browse the repository at this point in the history
  • Loading branch information
bcardosolopes committed Aug 29, 2024
1 parent 27849d7 commit aa282a9
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 4 deletions.
1 change: 1 addition & 0 deletions clang/include/clang/CIR/MissingFeatures.h
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand Down
29 changes: 27 additions & 2 deletions clang/lib/CIR/CodeGen/CIRGenClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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<DestroyField>(...) NYI");
CleanupKind cleanupKind = getCleanupKind(dtorKind);
EHStack.pushCleanup<DestroyField>(
cleanupKind, Field, getDestroyer(dtorKind), cleanupKind & EHCleanup);
}

if (SanitizeFields)
Expand Down
19 changes: 19 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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});
}
15 changes: 13 additions & 2 deletions clang/lib/CIR/CodeGen/CIRGenExprAgg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
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<Expr *> Args,
FieldDecl *InitializedFieldInUnion,
Expr *ArrayFiller);
Expand Down Expand Up @@ -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())
Expand Down Expand Up @@ -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:
Expand Down
19 changes: 19 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,20 @@ class CIRGenFunction : public CIRGenTypeCache {
EHScopeStack EHStack;
llvm::SmallVector<char, 256> 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<DeferredDeactivateCleanup> DeferredDeactivationCleanupStack;

/// A mapping from NRVO variables to the flags used to indicate
/// when the NRVO has been applied to this variable.
llvm::DenseMap<const VarDecl *, mlir::Value> NRVOFlags;
Expand Down Expand Up @@ -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,
Expand Down
39 changes: 39 additions & 0 deletions clang/test/CIR/CodeGen/paren-list-init.cpp
Original file line number Diff line number Diff line change
@@ -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<struct "Vec" {!cir.int<u, 8>}>
// CIR-DAG: ![[S1:.*]] = !cir.struct<struct "S1" {!cir.struct<struct "Vec" {!cir.int<u, 8>}>}>

template <int I>
void make1() {
Vec v;
S1((Vec&&) v);
// CIR: cir.func linkonce_odr @_Z5make1ILi0EEvv()
// CIR: %[[VEC:.*]] = cir.alloca ![[VecType]], !cir.ptr<![[VecType]]>
// CIR: cir.call @_ZN3VecC1Ev(%[[VEC]]) : (!cir.ptr<![[VecType]]>)
// CIR: cir.scope {
// CIR: %[[AGG_TMP:.*]] = cir.alloca ![[S1]], !cir.ptr<![[S1]]>, ["agg.tmp.ensured"]
// CIR: %[[FIELD:.*]] = cir.get_member %[[AGG_TMP]][0] {name = "v"} : !cir.ptr<![[S1]]> -> !cir.ptr<![[VecType]]>
// CIR: cir.call @_ZN3VecC1EOS_(%[[FIELD]], %[[VEC]]) : (!cir.ptr<![[VecType]]>, !cir.ptr<![[VecType]]>) -> ()
// CIR: cir.call @_ZN2S1D1Ev(%[[AGG_TMP]]) : (!cir.ptr<![[S1]]>) -> ()
// CIR: cir.call @_ZN3VecD1Ev(%[[FIELD]]) : (!cir.ptr<![[VecType]]>) -> ()
// CIR: }

// FIXME: implement MissingFeatures::flagLoad(), do not emit this a second time.
// CIR: cir.call @_ZN3VecD1Ev(%[[VEC]]) : (!cir.ptr<![[VecType]]>) -> ()
// CIR: cir.return
}

void foo() {
make1<0>();
}

0 comments on commit aa282a9

Please sign in to comment.