Home | History | Annotate | Line # | Download | only in Analysis
      1 //===- EHPersonalities.cpp - Compute EH-related information ---------------===//
      2 //
      3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4 // See https://llvm.org/LICENSE.txt for license information.
      5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 
      9 #include "llvm/Analysis/EHPersonalities.h"
     10 #include "llvm/ADT/StringSwitch.h"
     11 #include "llvm/IR/CFG.h"
     12 #include "llvm/IR/Constants.h"
     13 #include "llvm/IR/Function.h"
     14 #include "llvm/IR/Instructions.h"
     15 #include "llvm/Support/Debug.h"
     16 #include "llvm/Support/raw_ostream.h"
     17 using namespace llvm;
     18 
     19 /// See if the given exception handling personality function is one that we
     20 /// understand.  If so, return a description of it; otherwise return Unknown.
     21 EHPersonality llvm::classifyEHPersonality(const Value *Pers) {
     22   const GlobalValue *F =
     23       Pers ? dyn_cast<GlobalValue>(Pers->stripPointerCasts()) : nullptr;
     24   if (!F || !F->getValueType() || !F->getValueType()->isFunctionTy())
     25     return EHPersonality::Unknown;
     26   return StringSwitch<EHPersonality>(F->getName())
     27       .Case("__gnat_eh_personality", EHPersonality::GNU_Ada)
     28       .Case("__gxx_personality_v0", EHPersonality::GNU_CXX)
     29       .Case("__gxx_personality_seh0", EHPersonality::GNU_CXX)
     30       .Case("__gxx_personality_sj0", EHPersonality::GNU_CXX_SjLj)
     31       .Case("__gcc_personality_v0", EHPersonality::GNU_C)
     32       .Case("__gcc_personality_seh0", EHPersonality::GNU_C)
     33       .Case("__gcc_personality_sj0", EHPersonality::GNU_C_SjLj)
     34       .Case("__objc_personality_v0", EHPersonality::GNU_ObjC)
     35       .Case("_except_handler3", EHPersonality::MSVC_X86SEH)
     36       .Case("_except_handler4", EHPersonality::MSVC_X86SEH)
     37       .Case("__C_specific_handler", EHPersonality::MSVC_TableSEH)
     38       .Case("__CxxFrameHandler3", EHPersonality::MSVC_CXX)
     39       .Case("ProcessCLRException", EHPersonality::CoreCLR)
     40       .Case("rust_eh_personality", EHPersonality::Rust)
     41       .Case("__gxx_wasm_personality_v0", EHPersonality::Wasm_CXX)
     42       .Case("__xlcxx_personality_v1", EHPersonality::XL_CXX)
     43       .Default(EHPersonality::Unknown);
     44 }
     45 
     46 StringRef llvm::getEHPersonalityName(EHPersonality Pers) {
     47   switch (Pers) {
     48   case EHPersonality::GNU_Ada:       return "__gnat_eh_personality";
     49   case EHPersonality::GNU_CXX:       return "__gxx_personality_v0";
     50   case EHPersonality::GNU_CXX_SjLj:  return "__gxx_personality_sj0";
     51   case EHPersonality::GNU_C:         return "__gcc_personality_v0";
     52   case EHPersonality::GNU_C_SjLj:    return "__gcc_personality_sj0";
     53   case EHPersonality::GNU_ObjC:      return "__objc_personality_v0";
     54   case EHPersonality::MSVC_X86SEH:   return "_except_handler3";
     55   case EHPersonality::MSVC_TableSEH:
     56     return "__C_specific_handler";
     57   case EHPersonality::MSVC_CXX:      return "__CxxFrameHandler3";
     58   case EHPersonality::CoreCLR:       return "ProcessCLRException";
     59   case EHPersonality::Rust:          return "rust_eh_personality";
     60   case EHPersonality::Wasm_CXX:      return "__gxx_wasm_personality_v0";
     61   case EHPersonality::XL_CXX:
     62     return "__xlcxx_personality_v1";
     63   case EHPersonality::Unknown:       llvm_unreachable("Unknown EHPersonality!");
     64   }
     65 
     66   llvm_unreachable("Invalid EHPersonality!");
     67 }
     68 
     69 EHPersonality llvm::getDefaultEHPersonality(const Triple &T) {
     70   return EHPersonality::GNU_C;
     71 }
     72 
     73 bool llvm::canSimplifyInvokeNoUnwind(const Function *F) {
     74   EHPersonality Personality = classifyEHPersonality(F->getPersonalityFn());
     75   // We can't simplify any invokes to nounwind functions if the personality
     76   // function wants to catch asynch exceptions.  The nounwind attribute only
     77   // implies that the function does not throw synchronous exceptions.
     78   return !isAsynchronousEHPersonality(Personality);
     79 }
     80 
     81 DenseMap<BasicBlock *, ColorVector> llvm::colorEHFunclets(Function &F) {
     82   SmallVector<std::pair<BasicBlock *, BasicBlock *>, 16> Worklist;
     83   BasicBlock *EntryBlock = &F.getEntryBlock();
     84   DenseMap<BasicBlock *, ColorVector> BlockColors;
     85 
     86   // Build up the color map, which maps each block to its set of 'colors'.
     87   // For any block B the "colors" of B are the set of funclets F (possibly
     88   // including a root "funclet" representing the main function) such that
     89   // F will need to directly contain B or a copy of B (where the term "directly
     90   // contain" is used to distinguish from being "transitively contained" in
     91   // a nested funclet).
     92   //
     93   // Note: Despite not being a funclet in the truest sense, a catchswitch is
     94   // considered to belong to its own funclet for the purposes of coloring.
     95 
     96   DEBUG_WITH_TYPE("winehprepare-coloring", dbgs() << "\nColoring funclets for "
     97                                                   << F.getName() << "\n");
     98 
     99   Worklist.push_back({EntryBlock, EntryBlock});
    100 
    101   while (!Worklist.empty()) {
    102     BasicBlock *Visiting;
    103     BasicBlock *Color;
    104     std::tie(Visiting, Color) = Worklist.pop_back_val();
    105     DEBUG_WITH_TYPE("winehprepare-coloring",
    106                     dbgs() << "Visiting " << Visiting->getName() << ", "
    107                            << Color->getName() << "\n");
    108     Instruction *VisitingHead = Visiting->getFirstNonPHI();
    109     if (VisitingHead->isEHPad()) {
    110       // Mark this funclet head as a member of itself.
    111       Color = Visiting;
    112     }
    113     // Note that this is a member of the given color.
    114     ColorVector &Colors = BlockColors[Visiting];
    115     if (!is_contained(Colors, Color))
    116       Colors.push_back(Color);
    117     else
    118       continue;
    119 
    120     DEBUG_WITH_TYPE("winehprepare-coloring",
    121                     dbgs() << "  Assigned color \'" << Color->getName()
    122                            << "\' to block \'" << Visiting->getName()
    123                            << "\'.\n");
    124 
    125     BasicBlock *SuccColor = Color;
    126     Instruction *Terminator = Visiting->getTerminator();
    127     if (auto *CatchRet = dyn_cast<CatchReturnInst>(Terminator)) {
    128       Value *ParentPad = CatchRet->getCatchSwitchParentPad();
    129       if (isa<ConstantTokenNone>(ParentPad))
    130         SuccColor = EntryBlock;
    131       else
    132         SuccColor = cast<Instruction>(ParentPad)->getParent();
    133     }
    134 
    135     for (BasicBlock *Succ : successors(Visiting))
    136       Worklist.push_back({Succ, SuccColor});
    137   }
    138   return BlockColors;
    139 }
    140