1292915Sdim//===- EHPersonalities.cpp - Compute EH-related information ---------------===//
2292915Sdim//
3292915Sdim//                     The LLVM Compiler Infrastructure
4292915Sdim//
5292915Sdim// This file is distributed under the University of Illinois Open Source
6292915Sdim// License. See LICENSE.TXT for details.
7292915Sdim//
8292915Sdim//===----------------------------------------------------------------------===//
9292915Sdim
10292915Sdim#include "llvm/Analysis/EHPersonalities.h"
11292915Sdim#include "llvm/ADT/StringSwitch.h"
12292915Sdim#include "llvm/IR/CFG.h"
13292915Sdim#include "llvm/IR/Constants.h"
14292915Sdim#include "llvm/IR/Function.h"
15292915Sdim#include "llvm/IR/Instructions.h"
16292915Sdim#include "llvm/Support/Debug.h"
17292915Sdim#include "llvm/Support/raw_ostream.h"
18292915Sdimusing namespace llvm;
19292915Sdim
20292915Sdim/// See if the given exception handling personality function is one that we
21292915Sdim/// understand.  If so, return a description of it; otherwise return Unknown.
22292915SdimEHPersonality llvm::classifyEHPersonality(const Value *Pers) {
23292915Sdim  const Function *F =
24292915Sdim      Pers ? dyn_cast<Function>(Pers->stripPointerCasts()) : nullptr;
25292915Sdim  if (!F)
26292915Sdim    return EHPersonality::Unknown;
27292915Sdim  return StringSwitch<EHPersonality>(F->getName())
28292915Sdim    .Case("__gnat_eh_personality", EHPersonality::GNU_Ada)
29292915Sdim    .Case("__gxx_personality_v0",  EHPersonality::GNU_CXX)
30292915Sdim    .Case("__gcc_personality_v0",  EHPersonality::GNU_C)
31292915Sdim    .Case("__objc_personality_v0", EHPersonality::GNU_ObjC)
32292915Sdim    .Case("_except_handler3",      EHPersonality::MSVC_X86SEH)
33292915Sdim    .Case("_except_handler4",      EHPersonality::MSVC_X86SEH)
34292915Sdim    .Case("__C_specific_handler",  EHPersonality::MSVC_Win64SEH)
35292915Sdim    .Case("__CxxFrameHandler3",    EHPersonality::MSVC_CXX)
36292915Sdim    .Case("ProcessCLRException",   EHPersonality::CoreCLR)
37292915Sdim    .Default(EHPersonality::Unknown);
38292915Sdim}
39292915Sdim
40292915Sdimbool llvm::canSimplifyInvokeNoUnwind(const Function *F) {
41292915Sdim  EHPersonality Personality = classifyEHPersonality(F->getPersonalityFn());
42292915Sdim  // We can't simplify any invokes to nounwind functions if the personality
43292915Sdim  // function wants to catch asynch exceptions.  The nounwind attribute only
44292915Sdim  // implies that the function does not throw synchronous exceptions.
45292915Sdim  return !isAsynchronousEHPersonality(Personality);
46292915Sdim}
47292915Sdim
48292915SdimDenseMap<BasicBlock *, ColorVector> llvm::colorEHFunclets(Function &F) {
49292915Sdim  SmallVector<std::pair<BasicBlock *, BasicBlock *>, 16> Worklist;
50292915Sdim  BasicBlock *EntryBlock = &F.getEntryBlock();
51292915Sdim  DenseMap<BasicBlock *, ColorVector> BlockColors;
52292915Sdim
53292915Sdim  // Build up the color map, which maps each block to its set of 'colors'.
54292915Sdim  // For any block B the "colors" of B are the set of funclets F (possibly
55292915Sdim  // including a root "funclet" representing the main function) such that
56292915Sdim  // F will need to directly contain B or a copy of B (where the term "directly
57292915Sdim  // contain" is used to distinguish from being "transitively contained" in
58292915Sdim  // a nested funclet).
59292915Sdim  //
60292915Sdim  // Note: Despite not being a funclet in the truest sense, a catchswitch is
61292915Sdim  // considered to belong to its own funclet for the purposes of coloring.
62292915Sdim
63292915Sdim  DEBUG_WITH_TYPE("winehprepare-coloring", dbgs() << "\nColoring funclets for "
64292915Sdim                                                  << F.getName() << "\n");
65292915Sdim
66292915Sdim  Worklist.push_back({EntryBlock, EntryBlock});
67292915Sdim
68292915Sdim  while (!Worklist.empty()) {
69292915Sdim    BasicBlock *Visiting;
70292915Sdim    BasicBlock *Color;
71292915Sdim    std::tie(Visiting, Color) = Worklist.pop_back_val();
72292915Sdim    DEBUG_WITH_TYPE("winehprepare-coloring",
73292915Sdim                    dbgs() << "Visiting " << Visiting->getName() << ", "
74292915Sdim                           << Color->getName() << "\n");
75292915Sdim    Instruction *VisitingHead = Visiting->getFirstNonPHI();
76292915Sdim    if (VisitingHead->isEHPad()) {
77292915Sdim      // Mark this funclet head as a member of itself.
78292915Sdim      Color = Visiting;
79292915Sdim    }
80292915Sdim    // Note that this is a member of the given color.
81292915Sdim    ColorVector &Colors = BlockColors[Visiting];
82292915Sdim    if (std::find(Colors.begin(), Colors.end(), Color) == Colors.end())
83292915Sdim      Colors.push_back(Color);
84292915Sdim    else
85292915Sdim      continue;
86292915Sdim
87292915Sdim    DEBUG_WITH_TYPE("winehprepare-coloring",
88292915Sdim                    dbgs() << "  Assigned color \'" << Color->getName()
89292915Sdim                           << "\' to block \'" << Visiting->getName()
90292915Sdim                           << "\'.\n");
91292915Sdim
92292915Sdim    BasicBlock *SuccColor = Color;
93292915Sdim    TerminatorInst *Terminator = Visiting->getTerminator();
94292915Sdim    if (auto *CatchRet = dyn_cast<CatchReturnInst>(Terminator)) {
95292915Sdim      Value *ParentPad = CatchRet->getParentPad();
96292915Sdim      if (isa<ConstantTokenNone>(ParentPad))
97292915Sdim        SuccColor = EntryBlock;
98292915Sdim      else
99292915Sdim        SuccColor = cast<Instruction>(ParentPad)->getParent();
100292915Sdim    }
101292915Sdim
102292915Sdim    for (BasicBlock *Succ : successors(Visiting))
103292915Sdim      Worklist.push_back({Succ, SuccColor});
104292915Sdim  }
105292915Sdim  return BlockColors;
106292915Sdim}
107