aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/CIR/CodeGen/CIRGenCleanup.h
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/CIR/CodeGen/CIRGenCleanup.h')
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenCleanup.h112
1 files changed, 111 insertions, 1 deletions
diff --git a/clang/lib/CIR/CodeGen/CIRGenCleanup.h b/clang/lib/CIR/CodeGen/CIRGenCleanup.h
index 30f5607..9acf8b1 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCleanup.h
+++ b/clang/lib/CIR/CodeGen/CIRGenCleanup.h
@@ -20,6 +20,13 @@
namespace clang::CIRGen {
+/// The MS C++ ABI needs a pointer to RTTI data plus some flags to describe the
+/// type of a catch handler, so we use this wrapper.
+struct CatchTypeInfo {
+ mlir::TypedAttr rtti;
+ unsigned flags;
+};
+
/// A protected scope for zero-cost EH handling.
class EHScope {
class CommonBitFields {
@@ -29,6 +36,12 @@ class EHScope {
enum { NumCommonBits = 3 };
protected:
+ class CatchBitFields {
+ friend class EHCatchScope;
+ unsigned : NumCommonBits;
+ unsigned numHandlers : 32 - NumCommonBits;
+ };
+
class CleanupBitFields {
friend class EHCleanupScope;
unsigned : NumCommonBits;
@@ -58,6 +71,7 @@ protected:
union {
CommonBitFields commonBits;
+ CatchBitFields catchBits;
CleanupBitFields cleanupBits;
};
@@ -67,11 +81,88 @@ public:
EHScope(Kind kind) { commonBits.kind = kind; }
Kind getKind() const { return static_cast<Kind>(commonBits.kind); }
+
+ bool mayThrow() const {
+ // Traditional LLVM codegen also checks for `!block->use_empty()`, but
+ // in CIRGen the block content is not important, just used as a way to
+ // signal `hasEHBranches`.
+ assert(!cir::MissingFeatures::ehstackBranches());
+ return false;
+ }
+};
+
+/// A scope which attempts to handle some, possibly all, types of
+/// exceptions.
+///
+/// Objective C \@finally blocks are represented using a cleanup scope
+/// after the catch scope.
+
+class EHCatchScope : public EHScope {
+ // In effect, we have a flexible array member
+ // Handler Handlers[0];
+ // But that's only standard in C99, not C++, so we have to do
+ // annoying pointer arithmetic instead.
+
+public:
+ struct Handler {
+ /// A type info value, or null MLIR attribute for a catch-all
+ CatchTypeInfo type;
+
+ /// The catch handler for this type.
+ mlir::Region *region;
+ };
+
+private:
+ friend class EHScopeStack;
+
+ Handler *getHandlers() { return reinterpret_cast<Handler *>(this + 1); }
+
+public:
+ static size_t getSizeForNumHandlers(unsigned n) {
+ return sizeof(EHCatchScope) + n * sizeof(Handler);
+ }
+
+ EHCatchScope(unsigned numHandlers) : EHScope(Catch) {
+ catchBits.numHandlers = numHandlers;
+ assert(catchBits.numHandlers == numHandlers && "NumHandlers overflow?");
+ }
+
+ unsigned getNumHandlers() const { return catchBits.numHandlers; }
+
+ void setHandler(unsigned i, CatchTypeInfo type, mlir::Region *region) {
+ assert(i < getNumHandlers());
+ getHandlers()[i].type = type;
+ getHandlers()[i].region = region;
+ }
+
+ // Clear all handler blocks.
+ // FIXME: it's better to always call clearHandlerBlocks in DTOR and have a
+ // 'takeHandler' or some such function which removes ownership from the
+ // EHCatchScope object if the handlers should live longer than EHCatchScope.
+ void clearHandlerBlocks() {
+ // The blocks are owned by TryOp, nothing to delete.
+ }
+
+ static bool classof(const EHScope *scope) {
+ return scope->getKind() == Catch;
+ }
};
/// A cleanup scope which generates the cleanup blocks lazily.
class alignas(EHScopeStack::ScopeStackAlignment) EHCleanupScope
: public EHScope {
+ /// The nearest normal cleanup scope enclosing this one.
+ EHScopeStack::stable_iterator enclosingNormal;
+
+ /// The dual entry/exit block along the normal edge. This is lazily
+ /// created if needed before the cleanup is popped.
+ mlir::Block *normalBlock = nullptr;
+
+ /// The number of fixups required by enclosing scopes (not including
+ /// this one). If this is the top cleanup scope, all the fixups
+ /// from this index onwards belong to this scope.
+ unsigned fixupDepth = 0;
+
public:
/// Gets the size required for a lazy cleanup scope with the given
/// cleanup-data requirements.
@@ -83,7 +174,10 @@ public:
return sizeof(EHCleanupScope) + cleanupBits.cleanupSize;
}
- EHCleanupScope(unsigned cleanupSize) : EHScope(EHScope::Cleanup) {
+ EHCleanupScope(unsigned cleanupSize, unsigned fixupDepth,
+ EHScopeStack::stable_iterator enclosingNormal)
+ : EHScope(EHScope::Cleanup), enclosingNormal(enclosingNormal),
+ fixupDepth(fixupDepth) {
// TODO(cir): When exception handling is upstreamed, isNormalCleanup and
// isEHCleanup will be arguments to the constructor.
cleanupBits.isNormalCleanup = true;
@@ -101,11 +195,19 @@ public:
// Objects of EHCleanupScope are not destructed. Use destroy().
~EHCleanupScope() = delete;
+ mlir::Block *getNormalBlock() const { return normalBlock; }
+ void setNormalBlock(mlir::Block *bb) { normalBlock = bb; }
+
bool isNormalCleanup() const { return cleanupBits.isNormalCleanup; }
bool isActive() const { return cleanupBits.isActive; }
void setActive(bool isActive) { cleanupBits.isActive = isActive; }
+ unsigned getFixupDepth() const { return fixupDepth; }
+ EHScopeStack::stable_iterator getEnclosingNormalCleanup() const {
+ return enclosingNormal;
+ }
+
size_t getCleanupSize() const { return cleanupBits.cleanupSize; }
void *getCleanupBuffer() { return this + 1; }
@@ -147,5 +249,13 @@ EHScopeStack::find(stable_iterator savePoint) const {
return iterator(endOfBuffer - savePoint.size);
}
+inline void EHScopeStack::popCatch() {
+ assert(!empty() && "popping exception stack when not empty");
+
+ EHCatchScope &scope = llvm::cast<EHCatchScope>(*begin());
+ assert(!cir::MissingFeatures::innermostEHScope());
+ deallocate(EHCatchScope::getSizeForNumHandlers(scope.getNumHandlers()));
+}
+
} // namespace clang::CIRGen
#endif // CLANG_LIB_CIR_CODEGEN_CIRGENCLEANUP_H