diff options
Diffstat (limited to 'llvm/lib/Analysis/EHPersonalities.cpp')
| -rw-r--r-- | llvm/lib/Analysis/EHPersonalities.cpp | 135 | 
1 files changed, 135 insertions, 0 deletions
diff --git a/llvm/lib/Analysis/EHPersonalities.cpp b/llvm/lib/Analysis/EHPersonalities.cpp new file mode 100644 index 0000000000000..2242541696a44 --- /dev/null +++ b/llvm/lib/Analysis/EHPersonalities.cpp @@ -0,0 +1,135 @@ +//===- EHPersonalities.cpp - Compute EH-related information ---------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "llvm/Analysis/EHPersonalities.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/IR/CFG.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +/// See if the given exception handling personality function is one that we +/// understand.  If so, return a description of it; otherwise return Unknown. +EHPersonality llvm::classifyEHPersonality(const Value *Pers) { +  const Function *F = +      Pers ? dyn_cast<Function>(Pers->stripPointerCasts()) : nullptr; +  if (!F) +    return EHPersonality::Unknown; +  return StringSwitch<EHPersonality>(F->getName()) +    .Case("__gnat_eh_personality",     EHPersonality::GNU_Ada) +    .Case("__gxx_personality_v0",      EHPersonality::GNU_CXX) +    .Case("__gxx_personality_seh0",    EHPersonality::GNU_CXX) +    .Case("__gxx_personality_sj0",     EHPersonality::GNU_CXX_SjLj) +    .Case("__gcc_personality_v0",      EHPersonality::GNU_C) +    .Case("__gcc_personality_seh0",    EHPersonality::GNU_C) +    .Case("__gcc_personality_sj0",     EHPersonality::GNU_C_SjLj) +    .Case("__objc_personality_v0",     EHPersonality::GNU_ObjC) +    .Case("_except_handler3",          EHPersonality::MSVC_X86SEH) +    .Case("_except_handler4",          EHPersonality::MSVC_X86SEH) +    .Case("__C_specific_handler",      EHPersonality::MSVC_Win64SEH) +    .Case("__CxxFrameHandler3",        EHPersonality::MSVC_CXX) +    .Case("ProcessCLRException",       EHPersonality::CoreCLR) +    .Case("rust_eh_personality",       EHPersonality::Rust) +    .Case("__gxx_wasm_personality_v0", EHPersonality::Wasm_CXX) +    .Default(EHPersonality::Unknown); +} + +StringRef llvm::getEHPersonalityName(EHPersonality Pers) { +  switch (Pers) { +  case EHPersonality::GNU_Ada:       return "__gnat_eh_personality"; +  case EHPersonality::GNU_CXX:       return "__gxx_personality_v0"; +  case EHPersonality::GNU_CXX_SjLj:  return "__gxx_personality_sj0"; +  case EHPersonality::GNU_C:         return "__gcc_personality_v0"; +  case EHPersonality::GNU_C_SjLj:    return "__gcc_personality_sj0"; +  case EHPersonality::GNU_ObjC:      return "__objc_personality_v0"; +  case EHPersonality::MSVC_X86SEH:   return "_except_handler3"; +  case EHPersonality::MSVC_Win64SEH: return "__C_specific_handler"; +  case EHPersonality::MSVC_CXX:      return "__CxxFrameHandler3"; +  case EHPersonality::CoreCLR:       return "ProcessCLRException"; +  case EHPersonality::Rust:          return "rust_eh_personality"; +  case EHPersonality::Wasm_CXX:      return "__gxx_wasm_personality_v0"; +  case EHPersonality::Unknown:       llvm_unreachable("Unknown EHPersonality!"); +  } + +  llvm_unreachable("Invalid EHPersonality!"); +} + +EHPersonality llvm::getDefaultEHPersonality(const Triple &T) { +  return EHPersonality::GNU_C; +} + +bool llvm::canSimplifyInvokeNoUnwind(const Function *F) { +  EHPersonality Personality = classifyEHPersonality(F->getPersonalityFn()); +  // We can't simplify any invokes to nounwind functions if the personality +  // function wants to catch asynch exceptions.  The nounwind attribute only +  // implies that the function does not throw synchronous exceptions. +  return !isAsynchronousEHPersonality(Personality); +} + +DenseMap<BasicBlock *, ColorVector> llvm::colorEHFunclets(Function &F) { +  SmallVector<std::pair<BasicBlock *, BasicBlock *>, 16> Worklist; +  BasicBlock *EntryBlock = &F.getEntryBlock(); +  DenseMap<BasicBlock *, ColorVector> BlockColors; + +  // Build up the color map, which maps each block to its set of 'colors'. +  // For any block B the "colors" of B are the set of funclets F (possibly +  // including a root "funclet" representing the main function) such that +  // F will need to directly contain B or a copy of B (where the term "directly +  // contain" is used to distinguish from being "transitively contained" in +  // a nested funclet). +  // +  // Note: Despite not being a funclet in the truest sense, a catchswitch is +  // considered to belong to its own funclet for the purposes of coloring. + +  DEBUG_WITH_TYPE("winehprepare-coloring", dbgs() << "\nColoring funclets for " +                                                  << F.getName() << "\n"); + +  Worklist.push_back({EntryBlock, EntryBlock}); + +  while (!Worklist.empty()) { +    BasicBlock *Visiting; +    BasicBlock *Color; +    std::tie(Visiting, Color) = Worklist.pop_back_val(); +    DEBUG_WITH_TYPE("winehprepare-coloring", +                    dbgs() << "Visiting " << Visiting->getName() << ", " +                           << Color->getName() << "\n"); +    Instruction *VisitingHead = Visiting->getFirstNonPHI(); +    if (VisitingHead->isEHPad()) { +      // Mark this funclet head as a member of itself. +      Color = Visiting; +    } +    // Note that this is a member of the given color. +    ColorVector &Colors = BlockColors[Visiting]; +    if (!is_contained(Colors, Color)) +      Colors.push_back(Color); +    else +      continue; + +    DEBUG_WITH_TYPE("winehprepare-coloring", +                    dbgs() << "  Assigned color \'" << Color->getName() +                           << "\' to block \'" << Visiting->getName() +                           << "\'.\n"); + +    BasicBlock *SuccColor = Color; +    Instruction *Terminator = Visiting->getTerminator(); +    if (auto *CatchRet = dyn_cast<CatchReturnInst>(Terminator)) { +      Value *ParentPad = CatchRet->getCatchSwitchParentPad(); +      if (isa<ConstantTokenNone>(ParentPad)) +        SuccColor = EntryBlock; +      else +        SuccColor = cast<Instruction>(ParentPad)->getParent(); +    } + +    for (BasicBlock *Succ : successors(Visiting)) +      Worklist.push_back({Succ, SuccColor}); +  } +  return BlockColors; +}  | 
