xref: /freebsd-src/contrib/llvm-project/llvm/lib/IR/EHPersonalities.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
106c3fb27SDimitry Andric //===- EHPersonalities.cpp - Compute EH-related information ---------------===//
206c3fb27SDimitry Andric //
306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606c3fb27SDimitry Andric //
706c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
806c3fb27SDimitry Andric 
906c3fb27SDimitry Andric #include "llvm/IR/EHPersonalities.h"
1006c3fb27SDimitry Andric #include "llvm/ADT/StringSwitch.h"
1106c3fb27SDimitry Andric #include "llvm/IR/CFG.h"
1206c3fb27SDimitry Andric #include "llvm/IR/Constants.h"
1306c3fb27SDimitry Andric #include "llvm/IR/Function.h"
1406c3fb27SDimitry Andric #include "llvm/IR/Instructions.h"
1506c3fb27SDimitry Andric #include "llvm/IR/Module.h"
1606c3fb27SDimitry Andric #include "llvm/Support/Debug.h"
1706c3fb27SDimitry Andric #include "llvm/Support/raw_ostream.h"
1806c3fb27SDimitry Andric #include "llvm/TargetParser/Triple.h"
1906c3fb27SDimitry Andric using namespace llvm;
2006c3fb27SDimitry Andric 
2106c3fb27SDimitry Andric /// See if the given exception handling personality function is one that we
2206c3fb27SDimitry Andric /// understand.  If so, return a description of it; otherwise return Unknown.
2306c3fb27SDimitry Andric EHPersonality llvm::classifyEHPersonality(const Value *Pers) {
2406c3fb27SDimitry Andric   const GlobalValue *F =
2506c3fb27SDimitry Andric       Pers ? dyn_cast<GlobalValue>(Pers->stripPointerCasts()) : nullptr;
2606c3fb27SDimitry Andric   if (!F || !F->getValueType() || !F->getValueType()->isFunctionTy())
2706c3fb27SDimitry Andric     return EHPersonality::Unknown;
2806c3fb27SDimitry Andric   return StringSwitch<EHPersonality>(F->getName())
2906c3fb27SDimitry Andric       .Case("__gnat_eh_personality", EHPersonality::GNU_Ada)
3006c3fb27SDimitry Andric       .Case("__gxx_personality_v0", EHPersonality::GNU_CXX)
3106c3fb27SDimitry Andric       .Case("__gxx_personality_seh0", EHPersonality::GNU_CXX)
3206c3fb27SDimitry Andric       .Case("__gxx_personality_sj0", EHPersonality::GNU_CXX_SjLj)
3306c3fb27SDimitry Andric       .Case("__gcc_personality_v0", EHPersonality::GNU_C)
3406c3fb27SDimitry Andric       .Case("__gcc_personality_seh0", EHPersonality::GNU_C)
3506c3fb27SDimitry Andric       .Case("__gcc_personality_sj0", EHPersonality::GNU_C_SjLj)
3606c3fb27SDimitry Andric       .Case("__objc_personality_v0", EHPersonality::GNU_ObjC)
3706c3fb27SDimitry Andric       .Case("_except_handler3", EHPersonality::MSVC_X86SEH)
3806c3fb27SDimitry Andric       .Case("_except_handler4", EHPersonality::MSVC_X86SEH)
3906c3fb27SDimitry Andric       .Case("__C_specific_handler", EHPersonality::MSVC_TableSEH)
4006c3fb27SDimitry Andric       .Case("__CxxFrameHandler3", EHPersonality::MSVC_CXX)
4106c3fb27SDimitry Andric       .Case("ProcessCLRException", EHPersonality::CoreCLR)
4206c3fb27SDimitry Andric       .Case("rust_eh_personality", EHPersonality::Rust)
4306c3fb27SDimitry Andric       .Case("__gxx_wasm_personality_v0", EHPersonality::Wasm_CXX)
4406c3fb27SDimitry Andric       .Case("__xlcxx_personality_v1", EHPersonality::XL_CXX)
45*0fca6ea1SDimitry Andric       .Case("__zos_cxx_personality_v2", EHPersonality::ZOS_CXX)
4606c3fb27SDimitry Andric       .Default(EHPersonality::Unknown);
4706c3fb27SDimitry Andric }
4806c3fb27SDimitry Andric 
4906c3fb27SDimitry Andric StringRef llvm::getEHPersonalityName(EHPersonality Pers) {
5006c3fb27SDimitry Andric   switch (Pers) {
5106c3fb27SDimitry Andric   case EHPersonality::GNU_Ada:
5206c3fb27SDimitry Andric     return "__gnat_eh_personality";
5306c3fb27SDimitry Andric   case EHPersonality::GNU_CXX:
5406c3fb27SDimitry Andric     return "__gxx_personality_v0";
5506c3fb27SDimitry Andric   case EHPersonality::GNU_CXX_SjLj:
5606c3fb27SDimitry Andric     return "__gxx_personality_sj0";
5706c3fb27SDimitry Andric   case EHPersonality::GNU_C:
5806c3fb27SDimitry Andric     return "__gcc_personality_v0";
5906c3fb27SDimitry Andric   case EHPersonality::GNU_C_SjLj:
6006c3fb27SDimitry Andric     return "__gcc_personality_sj0";
6106c3fb27SDimitry Andric   case EHPersonality::GNU_ObjC:
6206c3fb27SDimitry Andric     return "__objc_personality_v0";
6306c3fb27SDimitry Andric   case EHPersonality::MSVC_X86SEH:
6406c3fb27SDimitry Andric     return "_except_handler3";
6506c3fb27SDimitry Andric   case EHPersonality::MSVC_TableSEH:
6606c3fb27SDimitry Andric     return "__C_specific_handler";
6706c3fb27SDimitry Andric   case EHPersonality::MSVC_CXX:
6806c3fb27SDimitry Andric     return "__CxxFrameHandler3";
6906c3fb27SDimitry Andric   case EHPersonality::CoreCLR:
7006c3fb27SDimitry Andric     return "ProcessCLRException";
7106c3fb27SDimitry Andric   case EHPersonality::Rust:
7206c3fb27SDimitry Andric     return "rust_eh_personality";
7306c3fb27SDimitry Andric   case EHPersonality::Wasm_CXX:
7406c3fb27SDimitry Andric     return "__gxx_wasm_personality_v0";
7506c3fb27SDimitry Andric   case EHPersonality::XL_CXX:
7606c3fb27SDimitry Andric     return "__xlcxx_personality_v1";
77*0fca6ea1SDimitry Andric   case EHPersonality::ZOS_CXX:
78*0fca6ea1SDimitry Andric     return "__zos_cxx_personality_v2";
7906c3fb27SDimitry Andric   case EHPersonality::Unknown:
8006c3fb27SDimitry Andric     llvm_unreachable("Unknown EHPersonality!");
8106c3fb27SDimitry Andric   }
8206c3fb27SDimitry Andric 
8306c3fb27SDimitry Andric   llvm_unreachable("Invalid EHPersonality!");
8406c3fb27SDimitry Andric }
8506c3fb27SDimitry Andric 
8606c3fb27SDimitry Andric EHPersonality llvm::getDefaultEHPersonality(const Triple &T) {
8706c3fb27SDimitry Andric   if (T.isPS5())
8806c3fb27SDimitry Andric     return EHPersonality::GNU_CXX;
8906c3fb27SDimitry Andric   else
9006c3fb27SDimitry Andric     return EHPersonality::GNU_C;
9106c3fb27SDimitry Andric }
9206c3fb27SDimitry Andric 
9306c3fb27SDimitry Andric bool llvm::canSimplifyInvokeNoUnwind(const Function *F) {
9406c3fb27SDimitry Andric   EHPersonality Personality = classifyEHPersonality(F->getPersonalityFn());
9506c3fb27SDimitry Andric   // We can't simplify any invokes to nounwind functions if the personality
9606c3fb27SDimitry Andric   // function wants to catch asynch exceptions.  The nounwind attribute only
9706c3fb27SDimitry Andric   // implies that the function does not throw synchronous exceptions.
9806c3fb27SDimitry Andric 
9906c3fb27SDimitry Andric   // Cannot simplify CXX Personality under AsynchEH
10006c3fb27SDimitry Andric   const llvm::Module *M = (const llvm::Module *)F->getParent();
10106c3fb27SDimitry Andric   bool EHa = M->getModuleFlag("eh-asynch");
10206c3fb27SDimitry Andric   return !EHa && !isAsynchronousEHPersonality(Personality);
10306c3fb27SDimitry Andric }
10406c3fb27SDimitry Andric 
10506c3fb27SDimitry Andric DenseMap<BasicBlock *, ColorVector> llvm::colorEHFunclets(Function &F) {
10606c3fb27SDimitry Andric   SmallVector<std::pair<BasicBlock *, BasicBlock *>, 16> Worklist;
10706c3fb27SDimitry Andric   BasicBlock *EntryBlock = &F.getEntryBlock();
10806c3fb27SDimitry Andric   DenseMap<BasicBlock *, ColorVector> BlockColors;
10906c3fb27SDimitry Andric 
11006c3fb27SDimitry Andric   // Build up the color map, which maps each block to its set of 'colors'.
11106c3fb27SDimitry Andric   // For any block B the "colors" of B are the set of funclets F (possibly
11206c3fb27SDimitry Andric   // including a root "funclet" representing the main function) such that
11306c3fb27SDimitry Andric   // F will need to directly contain B or a copy of B (where the term "directly
11406c3fb27SDimitry Andric   // contain" is used to distinguish from being "transitively contained" in
11506c3fb27SDimitry Andric   // a nested funclet).
11606c3fb27SDimitry Andric   //
11706c3fb27SDimitry Andric   // Note: Despite not being a funclet in the truest sense, a catchswitch is
11806c3fb27SDimitry Andric   // considered to belong to its own funclet for the purposes of coloring.
11906c3fb27SDimitry Andric 
1205f757f3fSDimitry Andric   DEBUG_WITH_TYPE("win-eh-prepare-coloring",
12106c3fb27SDimitry Andric                   dbgs() << "\nColoring funclets for " << F.getName() << "\n");
12206c3fb27SDimitry Andric 
12306c3fb27SDimitry Andric   Worklist.push_back({EntryBlock, EntryBlock});
12406c3fb27SDimitry Andric 
12506c3fb27SDimitry Andric   while (!Worklist.empty()) {
12606c3fb27SDimitry Andric     BasicBlock *Visiting;
12706c3fb27SDimitry Andric     BasicBlock *Color;
12806c3fb27SDimitry Andric     std::tie(Visiting, Color) = Worklist.pop_back_val();
1295f757f3fSDimitry Andric     DEBUG_WITH_TYPE("win-eh-prepare-coloring",
13006c3fb27SDimitry Andric                     dbgs() << "Visiting " << Visiting->getName() << ", "
13106c3fb27SDimitry Andric                            << Color->getName() << "\n");
13206c3fb27SDimitry Andric     Instruction *VisitingHead = Visiting->getFirstNonPHI();
13306c3fb27SDimitry Andric     if (VisitingHead->isEHPad()) {
13406c3fb27SDimitry Andric       // Mark this funclet head as a member of itself.
13506c3fb27SDimitry Andric       Color = Visiting;
13606c3fb27SDimitry Andric     }
13706c3fb27SDimitry Andric     // Note that this is a member of the given color.
13806c3fb27SDimitry Andric     ColorVector &Colors = BlockColors[Visiting];
13906c3fb27SDimitry Andric     if (!is_contained(Colors, Color))
14006c3fb27SDimitry Andric       Colors.push_back(Color);
14106c3fb27SDimitry Andric     else
14206c3fb27SDimitry Andric       continue;
14306c3fb27SDimitry Andric 
1445f757f3fSDimitry Andric     DEBUG_WITH_TYPE("win-eh-prepare-coloring",
14506c3fb27SDimitry Andric                     dbgs() << "  Assigned color \'" << Color->getName()
14606c3fb27SDimitry Andric                            << "\' to block \'" << Visiting->getName()
14706c3fb27SDimitry Andric                            << "\'.\n");
14806c3fb27SDimitry Andric 
14906c3fb27SDimitry Andric     BasicBlock *SuccColor = Color;
15006c3fb27SDimitry Andric     Instruction *Terminator = Visiting->getTerminator();
15106c3fb27SDimitry Andric     if (auto *CatchRet = dyn_cast<CatchReturnInst>(Terminator)) {
15206c3fb27SDimitry Andric       Value *ParentPad = CatchRet->getCatchSwitchParentPad();
15306c3fb27SDimitry Andric       if (isa<ConstantTokenNone>(ParentPad))
15406c3fb27SDimitry Andric         SuccColor = EntryBlock;
15506c3fb27SDimitry Andric       else
15606c3fb27SDimitry Andric         SuccColor = cast<Instruction>(ParentPad)->getParent();
15706c3fb27SDimitry Andric     }
15806c3fb27SDimitry Andric 
15906c3fb27SDimitry Andric     for (BasicBlock *Succ : successors(Visiting))
16006c3fb27SDimitry Andric       Worklist.push_back({Succ, SuccColor});
16106c3fb27SDimitry Andric   }
16206c3fb27SDimitry Andric   return BlockColors;
16306c3fb27SDimitry Andric }
164