blob: a4ec8ccebbd3bd723bc205190c842731402b2aaa [file] [log] [blame]
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// These classes support the generation of CIR for cleanups, initially based
// on LLVM IR cleanup handling, but ought to change as CIR evolves.
//
//===----------------------------------------------------------------------===//
#ifndef CLANG_LIB_CIR_CODEGEN_CIRGENCLEANUP_H
#define CLANG_LIB_CIR_CODEGEN_CIRGENCLEANUP_H
#include "Address.h"
#include "EHScopeStack.h"
#include "mlir/IR/Value.h"
namespace clang::CIRGen {
/// A protected scope for zero-cost EH handling.
class EHScope {
class CommonBitFields {
friend class EHScope;
unsigned kind : 3;
};
enum { NumCommonBits = 3 };
protected:
class CleanupBitFields {
friend class EHCleanupScope;
unsigned : NumCommonBits;
/// Whether this cleanup needs to be run along normal edges.
unsigned isNormalCleanup : 1;
/// Whether this cleanup needs to be run along exception edges.
unsigned isEHCleanup : 1;
/// Whether this cleanup is currently active.
unsigned isActive : 1;
/// Whether this cleanup is a lifetime marker
unsigned isLifetimeMarker : 1;
/// Whether the normal cleanup should test the activation flag.
unsigned testFlagInNormalCleanup : 1;
/// Whether the EH cleanup should test the activation flag.
unsigned testFlagInEHCleanup : 1;
/// The amount of extra storage needed by the Cleanup.
/// Always a multiple of the scope-stack alignment.
unsigned cleanupSize : 12;
};
union {
CommonBitFields commonBits;
CleanupBitFields cleanupBits;
};
public:
enum Kind { Cleanup, Catch, Terminate, Filter };
EHScope(Kind kind) { commonBits.kind = kind; }
Kind getKind() const { return static_cast<Kind>(commonBits.kind); }
};
/// A cleanup scope which generates the cleanup blocks lazily.
class alignas(EHScopeStack::ScopeStackAlignment) EHCleanupScope
: public EHScope {
public:
/// Gets the size required for a lazy cleanup scope with the given
/// cleanup-data requirements.
static size_t getSizeForCleanupSize(size_t size) {
return sizeof(EHCleanupScope) + size;
}
size_t getAllocatedSize() const {
return sizeof(EHCleanupScope) + cleanupBits.cleanupSize;
}
EHCleanupScope(unsigned cleanupSize) : EHScope(EHScope::Cleanup) {
// TODO(cir): When exception handling is upstreamed, isNormalCleanup and
// isEHCleanup will be arguments to the constructor.
cleanupBits.isNormalCleanup = true;
cleanupBits.isEHCleanup = false;
cleanupBits.isActive = true;
cleanupBits.isLifetimeMarker = false;
cleanupBits.testFlagInNormalCleanup = false;
cleanupBits.testFlagInEHCleanup = false;
cleanupBits.cleanupSize = cleanupSize;
assert(cleanupBits.cleanupSize == cleanupSize && "cleanup size overflow");
}
void destroy() {}
// Objects of EHCleanupScope are not destructed. Use destroy().
~EHCleanupScope() = delete;
bool isNormalCleanup() const { return cleanupBits.isNormalCleanup; }
bool isActive() const { return cleanupBits.isActive; }
size_t getCleanupSize() const { return cleanupBits.cleanupSize; }
void *getCleanupBuffer() { return this + 1; }
EHScopeStack::Cleanup *getCleanup() {
return reinterpret_cast<EHScopeStack::Cleanup *>(getCleanupBuffer());
}
static bool classof(const EHScope *scope) {
return (scope->getKind() == Cleanup);
}
void markEmitted() {}
};
/// A non-stable pointer into the scope stack.
class EHScopeStack::iterator {
char *ptr = nullptr;
friend class EHScopeStack;
explicit iterator(char *ptr) : ptr(ptr) {}
public:
iterator() = default;
EHScope *get() const { return reinterpret_cast<EHScope *>(ptr); }
EHScope &operator*() const { return *get(); }
};
inline EHScopeStack::iterator EHScopeStack::begin() const {
return iterator(startOfData);
}
} // namespace clang::CIRGen
#endif // CLANG_LIB_CIR_CODEGEN_CIRGENCLEANUP_H