summaryrefslogtreecommitdiffstats
path: root/gnu/llvm/tools/clang/lib/CodeGen/CGCleanup.h
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/llvm/tools/clang/lib/CodeGen/CGCleanup.h')
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGCleanup.h650
1 files changed, 0 insertions, 650 deletions
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGCleanup.h b/gnu/llvm/tools/clang/lib/CodeGen/CGCleanup.h
deleted file mode 100644
index 15d6f46dcb5..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGCleanup.h
+++ /dev/null
@@ -1,650 +0,0 @@
-//===-- CGCleanup.h - Classes for cleanups IR generation --------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// These classes support the generation of LLVM IR for cleanups.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_CODEGEN_CGCLEANUP_H
-#define LLVM_CLANG_LIB_CODEGEN_CGCLEANUP_H
-
-#include "EHScopeStack.h"
-
-#include "Address.h"
-#include "llvm/ADT/SmallPtrSet.h"
-#include "llvm/ADT/SmallVector.h"
-
-namespace llvm {
-class BasicBlock;
-class Value;
-class ConstantInt;
-class AllocaInst;
-}
-
-namespace clang {
-class FunctionDecl;
-namespace CodeGen {
-class CodeGenModule;
-class CodeGenFunction;
-
-/// 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 {
- llvm::Constant *RTTI;
- unsigned Flags;
-};
-
-/// A protected scope for zero-cost EH handling.
-class EHScope {
- llvm::BasicBlock *CachedLandingPad;
- llvm::BasicBlock *CachedEHDispatchBlock;
-
- EHScopeStack::stable_iterator EnclosingEHScope;
-
- class CommonBitFields {
- friend class EHScope;
- unsigned Kind : 3;
- };
- enum { NumCommonBits = 3 };
-
-protected:
- class CatchBitFields {
- friend class EHCatchScope;
- unsigned : NumCommonBits;
-
- unsigned NumHandlers : 32 - NumCommonBits;
- };
-
- 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;
- };
-
- class FilterBitFields {
- friend class EHFilterScope;
- unsigned : NumCommonBits;
-
- unsigned NumFilters : 32 - NumCommonBits;
- };
-
- union {
- CommonBitFields CommonBits;
- CatchBitFields CatchBits;
- CleanupBitFields CleanupBits;
- FilterBitFields FilterBits;
- };
-
-public:
- enum Kind { Cleanup, Catch, Terminate, Filter, PadEnd };
-
- EHScope(Kind kind, EHScopeStack::stable_iterator enclosingEHScope)
- : CachedLandingPad(nullptr), CachedEHDispatchBlock(nullptr),
- EnclosingEHScope(enclosingEHScope) {
- CommonBits.Kind = kind;
- }
-
- Kind getKind() const { return static_cast<Kind>(CommonBits.Kind); }
-
- llvm::BasicBlock *getCachedLandingPad() const {
- return CachedLandingPad;
- }
-
- void setCachedLandingPad(llvm::BasicBlock *block) {
- CachedLandingPad = block;
- }
-
- llvm::BasicBlock *getCachedEHDispatchBlock() const {
- return CachedEHDispatchBlock;
- }
-
- void setCachedEHDispatchBlock(llvm::BasicBlock *block) {
- CachedEHDispatchBlock = block;
- }
-
- bool hasEHBranches() const {
- if (llvm::BasicBlock *block = getCachedEHDispatchBlock())
- return !block->use_empty();
- return false;
- }
-
- EHScopeStack::stable_iterator getEnclosingEHScope() const {
- return EnclosingEHScope;
- }
-};
-
-/// 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 (C++ null, not an LLVM null pointer)
- /// for a catch-all.
- CatchTypeInfo Type;
-
- /// The catch handler for this type.
- llvm::BasicBlock *Block;
-
- bool isCatchAll() const { return Type.RTTI == nullptr; }
- };
-
-private:
- friend class EHScopeStack;
-
- Handler *getHandlers() {
- return reinterpret_cast<Handler*>(this+1);
- }
-
- const Handler *getHandlers() const {
- return reinterpret_cast<const Handler*>(this+1);
- }
-
-public:
- static size_t getSizeForNumHandlers(unsigned N) {
- return sizeof(EHCatchScope) + N * sizeof(Handler);
- }
-
- EHCatchScope(unsigned numHandlers,
- EHScopeStack::stable_iterator enclosingEHScope)
- : EHScope(Catch, enclosingEHScope) {
- CatchBits.NumHandlers = numHandlers;
- assert(CatchBits.NumHandlers == numHandlers && "NumHandlers overflow?");
- }
-
- unsigned getNumHandlers() const {
- return CatchBits.NumHandlers;
- }
-
- void setCatchAllHandler(unsigned I, llvm::BasicBlock *Block) {
- setHandler(I, CatchTypeInfo{nullptr, 0}, Block);
- }
-
- void setHandler(unsigned I, llvm::Constant *Type, llvm::BasicBlock *Block) {
- assert(I < getNumHandlers());
- getHandlers()[I].Type = CatchTypeInfo{Type, 0};
- getHandlers()[I].Block = Block;
- }
-
- void setHandler(unsigned I, CatchTypeInfo Type, llvm::BasicBlock *Block) {
- assert(I < getNumHandlers());
- getHandlers()[I].Type = Type;
- getHandlers()[I].Block = Block;
- }
-
- const Handler &getHandler(unsigned I) const {
- assert(I < getNumHandlers());
- return getHandlers()[I];
- }
-
- // 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() {
- for (unsigned I = 0, N = getNumHandlers(); I != N; ++I)
- delete getHandler(I).Block;
- }
-
- typedef const Handler *iterator;
- iterator begin() const { return getHandlers(); }
- iterator end() const { return getHandlers() + getNumHandlers(); }
-
- static bool classof(const EHScope *Scope) {
- return Scope->getKind() == Catch;
- }
-};
-
-/// A cleanup scope which generates the cleanup blocks lazily.
-class alignas(8) EHCleanupScope : public EHScope {
- /// The nearest normal cleanup scope enclosing this one.
- EHScopeStack::stable_iterator EnclosingNormal;
-
- /// The nearest EH scope enclosing this one.
- EHScopeStack::stable_iterator EnclosingEH;
-
- /// The dual entry/exit block along the normal edge. This is lazily
- /// created if needed before the cleanup is popped.
- llvm::BasicBlock *NormalBlock;
-
- /// An optional i1 variable indicating whether this cleanup has been
- /// activated yet.
- llvm::AllocaInst *ActiveFlag;
-
- /// Extra information required for cleanups that have resolved
- /// branches through them. This has to be allocated on the side
- /// because everything on the cleanup stack has be trivially
- /// movable.
- struct ExtInfo {
- /// The destinations of normal branch-afters and branch-throughs.
- llvm::SmallPtrSet<llvm::BasicBlock*, 4> Branches;
-
- /// Normal branch-afters.
- SmallVector<std::pair<llvm::BasicBlock*,llvm::ConstantInt*>, 4>
- BranchAfters;
- };
- mutable struct ExtInfo *ExtInfo;
-
- /// 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;
-
- struct ExtInfo &getExtInfo() {
- if (!ExtInfo) ExtInfo = new struct ExtInfo();
- return *ExtInfo;
- }
-
- const struct ExtInfo &getExtInfo() const {
- if (!ExtInfo) ExtInfo = new struct ExtInfo();
- return *ExtInfo;
- }
-
-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(bool isNormal, bool isEH, bool isActive,
- unsigned cleanupSize, unsigned fixupDepth,
- EHScopeStack::stable_iterator enclosingNormal,
- EHScopeStack::stable_iterator enclosingEH)
- : EHScope(EHScope::Cleanup, enclosingEH),
- EnclosingNormal(enclosingNormal), NormalBlock(nullptr),
- ActiveFlag(nullptr), ExtInfo(nullptr), FixupDepth(fixupDepth) {
- CleanupBits.IsNormalCleanup = isNormal;
- CleanupBits.IsEHCleanup = isEH;
- CleanupBits.IsActive = isActive;
- CleanupBits.IsLifetimeMarker = false;
- CleanupBits.TestFlagInNormalCleanup = false;
- CleanupBits.TestFlagInEHCleanup = false;
- CleanupBits.CleanupSize = cleanupSize;
-
- assert(CleanupBits.CleanupSize == cleanupSize && "cleanup size overflow");
- }
-
- void Destroy() {
- delete ExtInfo;
- }
- // Objects of EHCleanupScope are not destructed. Use Destroy().
- ~EHCleanupScope() = delete;
-
- bool isNormalCleanup() const { return CleanupBits.IsNormalCleanup; }
- llvm::BasicBlock *getNormalBlock() const { return NormalBlock; }
- void setNormalBlock(llvm::BasicBlock *BB) { NormalBlock = BB; }
-
- bool isEHCleanup() const { return CleanupBits.IsEHCleanup; }
-
- bool isActive() const { return CleanupBits.IsActive; }
- void setActive(bool A) { CleanupBits.IsActive = A; }
-
- bool isLifetimeMarker() const { return CleanupBits.IsLifetimeMarker; }
- void setLifetimeMarker() { CleanupBits.IsLifetimeMarker = true; }
-
- bool hasActiveFlag() const { return ActiveFlag != nullptr; }
- Address getActiveFlag() const {
- return Address(ActiveFlag, CharUnits::One());
- }
- void setActiveFlag(Address Var) {
- assert(Var.getAlignment().isOne());
- ActiveFlag = cast<llvm::AllocaInst>(Var.getPointer());
- }
-
- void setTestFlagInNormalCleanup() {
- CleanupBits.TestFlagInNormalCleanup = true;
- }
- bool shouldTestFlagInNormalCleanup() const {
- return CleanupBits.TestFlagInNormalCleanup;
- }
-
- void setTestFlagInEHCleanup() {
- CleanupBits.TestFlagInEHCleanup = true;
- }
- bool shouldTestFlagInEHCleanup() const {
- return CleanupBits.TestFlagInEHCleanup;
- }
-
- unsigned getFixupDepth() const { return FixupDepth; }
- EHScopeStack::stable_iterator getEnclosingNormalCleanup() const {
- return EnclosingNormal;
- }
-
- size_t getCleanupSize() const { return CleanupBits.CleanupSize; }
- void *getCleanupBuffer() { return this + 1; }
-
- EHScopeStack::Cleanup *getCleanup() {
- return reinterpret_cast<EHScopeStack::Cleanup*>(getCleanupBuffer());
- }
-
- /// True if this cleanup scope has any branch-afters or branch-throughs.
- bool hasBranches() const { return ExtInfo && !ExtInfo->Branches.empty(); }
-
- /// Add a branch-after to this cleanup scope. A branch-after is a
- /// branch from a point protected by this (normal) cleanup to a
- /// point in the normal cleanup scope immediately containing it.
- /// For example,
- /// for (;;) { A a; break; }
- /// contains a branch-after.
- ///
- /// Branch-afters each have their own destination out of the
- /// cleanup, guaranteed distinct from anything else threaded through
- /// it. Therefore branch-afters usually force a switch after the
- /// cleanup.
- void addBranchAfter(llvm::ConstantInt *Index,
- llvm::BasicBlock *Block) {
- struct ExtInfo &ExtInfo = getExtInfo();
- if (ExtInfo.Branches.insert(Block).second)
- ExtInfo.BranchAfters.push_back(std::make_pair(Block, Index));
- }
-
- /// Return the number of unique branch-afters on this scope.
- unsigned getNumBranchAfters() const {
- return ExtInfo ? ExtInfo->BranchAfters.size() : 0;
- }
-
- llvm::BasicBlock *getBranchAfterBlock(unsigned I) const {
- assert(I < getNumBranchAfters());
- return ExtInfo->BranchAfters[I].first;
- }
-
- llvm::ConstantInt *getBranchAfterIndex(unsigned I) const {
- assert(I < getNumBranchAfters());
- return ExtInfo->BranchAfters[I].second;
- }
-
- /// Add a branch-through to this cleanup scope. A branch-through is
- /// a branch from a scope protected by this (normal) cleanup to an
- /// enclosing scope other than the immediately-enclosing normal
- /// cleanup scope.
- ///
- /// In the following example, the branch through B's scope is a
- /// branch-through, while the branch through A's scope is a
- /// branch-after:
- /// for (;;) { A a; B b; break; }
- ///
- /// All branch-throughs have a common destination out of the
- /// cleanup, one possibly shared with the fall-through. Therefore
- /// branch-throughs usually don't force a switch after the cleanup.
- ///
- /// \return true if the branch-through was new to this scope
- bool addBranchThrough(llvm::BasicBlock *Block) {
- return getExtInfo().Branches.insert(Block).second;
- }
-
- /// Determines if this cleanup scope has any branch throughs.
- bool hasBranchThroughs() const {
- if (!ExtInfo) return false;
- return (ExtInfo->BranchAfters.size() != ExtInfo->Branches.size());
- }
-
- static bool classof(const EHScope *Scope) {
- return (Scope->getKind() == Cleanup);
- }
-};
-// NOTE: there's a bunch of different data classes tacked on after an
-// EHCleanupScope. It is asserted (in EHScopeStack::pushCleanup*) that
-// they don't require greater alignment than ScopeStackAlignment. So,
-// EHCleanupScope ought to have alignment equal to that -- not more
-// (would be misaligned by the stack allocator), and not less (would
-// break the appended classes).
-static_assert(alignof(EHCleanupScope) == EHScopeStack::ScopeStackAlignment,
- "EHCleanupScope expected alignment");
-
-/// An exceptions scope which filters exceptions thrown through it.
-/// Only exceptions matching the filter types will be permitted to be
-/// thrown.
-///
-/// This is used to implement C++ exception specifications.
-class EHFilterScope : public EHScope {
- // Essentially ends in a flexible array member:
- // llvm::Value *FilterTypes[0];
-
- llvm::Value **getFilters() {
- return reinterpret_cast<llvm::Value**>(this+1);
- }
-
- llvm::Value * const *getFilters() const {
- return reinterpret_cast<llvm::Value* const *>(this+1);
- }
-
-public:
- EHFilterScope(unsigned numFilters)
- : EHScope(Filter, EHScopeStack::stable_end()) {
- FilterBits.NumFilters = numFilters;
- assert(FilterBits.NumFilters == numFilters && "NumFilters overflow");
- }
-
- static size_t getSizeForNumFilters(unsigned numFilters) {
- return sizeof(EHFilterScope) + numFilters * sizeof(llvm::Value*);
- }
-
- unsigned getNumFilters() const { return FilterBits.NumFilters; }
-
- void setFilter(unsigned i, llvm::Value *filterValue) {
- assert(i < getNumFilters());
- getFilters()[i] = filterValue;
- }
-
- llvm::Value *getFilter(unsigned i) const {
- assert(i < getNumFilters());
- return getFilters()[i];
- }
-
- static bool classof(const EHScope *scope) {
- return scope->getKind() == Filter;
- }
-};
-
-/// An exceptions scope which calls std::terminate if any exception
-/// reaches it.
-class EHTerminateScope : public EHScope {
-public:
- EHTerminateScope(EHScopeStack::stable_iterator enclosingEHScope)
- : EHScope(Terminate, enclosingEHScope) {}
- static size_t getSize() { return sizeof(EHTerminateScope); }
-
- static bool classof(const EHScope *scope) {
- return scope->getKind() == Terminate;
- }
-};
-
-class EHPadEndScope : public EHScope {
-public:
- EHPadEndScope(EHScopeStack::stable_iterator enclosingEHScope)
- : EHScope(PadEnd, enclosingEHScope) {}
- static size_t getSize() { return sizeof(EHPadEndScope); }
-
- static bool classof(const EHScope *scope) {
- return scope->getKind() == PadEnd;
- }
-};
-
-/// A non-stable pointer into the scope stack.
-class EHScopeStack::iterator {
- char *Ptr;
-
- friend class EHScopeStack;
- explicit iterator(char *Ptr) : Ptr(Ptr) {}
-
-public:
- iterator() : Ptr(nullptr) {}
-
- EHScope *get() const {
- return reinterpret_cast<EHScope*>(Ptr);
- }
-
- EHScope *operator->() const { return get(); }
- EHScope &operator*() const { return *get(); }
-
- iterator &operator++() {
- size_t Size;
- switch (get()->getKind()) {
- case EHScope::Catch:
- Size = EHCatchScope::getSizeForNumHandlers(
- static_cast<const EHCatchScope *>(get())->getNumHandlers());
- break;
-
- case EHScope::Filter:
- Size = EHFilterScope::getSizeForNumFilters(
- static_cast<const EHFilterScope *>(get())->getNumFilters());
- break;
-
- case EHScope::Cleanup:
- Size = static_cast<const EHCleanupScope *>(get())->getAllocatedSize();
- break;
-
- case EHScope::Terminate:
- Size = EHTerminateScope::getSize();
- break;
-
- case EHScope::PadEnd:
- Size = EHPadEndScope::getSize();
- break;
- }
- Ptr += llvm::alignTo(Size, ScopeStackAlignment);
- return *this;
- }
-
- iterator next() {
- iterator copy = *this;
- ++copy;
- return copy;
- }
-
- iterator operator++(int) {
- iterator copy = *this;
- operator++();
- return copy;
- }
-
- bool encloses(iterator other) const { return Ptr >= other.Ptr; }
- bool strictlyEncloses(iterator other) const { return Ptr > other.Ptr; }
-
- bool operator==(iterator other) const { return Ptr == other.Ptr; }
- bool operator!=(iterator other) const { return Ptr != other.Ptr; }
-};
-
-inline EHScopeStack::iterator EHScopeStack::begin() const {
- return iterator(StartOfData);
-}
-
-inline EHScopeStack::iterator EHScopeStack::end() const {
- return iterator(EndOfBuffer);
-}
-
-inline void EHScopeStack::popCatch() {
- assert(!empty() && "popping exception stack when not empty");
-
- EHCatchScope &scope = cast<EHCatchScope>(*begin());
- InnermostEHScope = scope.getEnclosingEHScope();
- deallocate(EHCatchScope::getSizeForNumHandlers(scope.getNumHandlers()));
-}
-
-inline void EHScopeStack::popTerminate() {
- assert(!empty() && "popping exception stack when not empty");
-
- EHTerminateScope &scope = cast<EHTerminateScope>(*begin());
- InnermostEHScope = scope.getEnclosingEHScope();
- deallocate(EHTerminateScope::getSize());
-}
-
-inline EHScopeStack::iterator EHScopeStack::find(stable_iterator sp) const {
- assert(sp.isValid() && "finding invalid savepoint");
- assert(sp.Size <= stable_begin().Size && "finding savepoint after pop");
- return iterator(EndOfBuffer - sp.Size);
-}
-
-inline EHScopeStack::stable_iterator
-EHScopeStack::stabilize(iterator ir) const {
- assert(StartOfData <= ir.Ptr && ir.Ptr <= EndOfBuffer);
- return stable_iterator(EndOfBuffer - ir.Ptr);
-}
-
-/// The exceptions personality for a function.
-struct EHPersonality {
- const char *PersonalityFn;
-
- // If this is non-null, this personality requires a non-standard
- // function for rethrowing an exception after a catchall cleanup.
- // This function must have prototype void(void*).
- const char *CatchallRethrowFn;
-
- static const EHPersonality &get(CodeGenModule &CGM, const FunctionDecl *FD);
- static const EHPersonality &get(CodeGenFunction &CGF);
-
- static const EHPersonality GNU_C;
- static const EHPersonality GNU_C_SJLJ;
- static const EHPersonality GNU_C_SEH;
- static const EHPersonality GNU_ObjC;
- static const EHPersonality GNU_ObjC_SJLJ;
- static const EHPersonality GNU_ObjC_SEH;
- static const EHPersonality GNUstep_ObjC;
- static const EHPersonality GNU_ObjCXX;
- static const EHPersonality NeXT_ObjC;
- static const EHPersonality GNU_CPlusPlus;
- static const EHPersonality GNU_CPlusPlus_SJLJ;
- static const EHPersonality GNU_CPlusPlus_SEH;
- static const EHPersonality MSVC_except_handler;
- static const EHPersonality MSVC_C_specific_handler;
- static const EHPersonality MSVC_CxxFrameHandler3;
- static const EHPersonality GNU_Wasm_CPlusPlus;
-
- /// Does this personality use landingpads or the family of pad instructions
- /// designed to form funclets?
- bool usesFuncletPads() const {
- return isMSVCPersonality() || isWasmPersonality();
- }
-
- bool isMSVCPersonality() const {
- return this == &MSVC_except_handler || this == &MSVC_C_specific_handler ||
- this == &MSVC_CxxFrameHandler3;
- }
-
- bool isWasmPersonality() const { return this == &GNU_Wasm_CPlusPlus; }
-
- bool isMSVCXXPersonality() const { return this == &MSVC_CxxFrameHandler3; }
-};
-}
-}
-
-#endif