xref: /freebsd-src/contrib/llvm-project/llvm/lib/IR/EHPersonalities.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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)
4506c3fb27SDimitry Andric       .Default(EHPersonality::Unknown);
4606c3fb27SDimitry Andric }
4706c3fb27SDimitry Andric 
4806c3fb27SDimitry Andric StringRef llvm::getEHPersonalityName(EHPersonality Pers) {
4906c3fb27SDimitry Andric   switch (Pers) {
5006c3fb27SDimitry Andric   case EHPersonality::GNU_Ada:
5106c3fb27SDimitry Andric     return "__gnat_eh_personality";
5206c3fb27SDimitry Andric   case EHPersonality::GNU_CXX:
5306c3fb27SDimitry Andric     return "__gxx_personality_v0";
5406c3fb27SDimitry Andric   case EHPersonality::GNU_CXX_SjLj:
5506c3fb27SDimitry Andric     return "__gxx_personality_sj0";
5606c3fb27SDimitry Andric   case EHPersonality::GNU_C:
5706c3fb27SDimitry Andric     return "__gcc_personality_v0";
5806c3fb27SDimitry Andric   case EHPersonality::GNU_C_SjLj:
5906c3fb27SDimitry Andric     return "__gcc_personality_sj0";
6006c3fb27SDimitry Andric   case EHPersonality::GNU_ObjC:
6106c3fb27SDimitry Andric     return "__objc_personality_v0";
6206c3fb27SDimitry Andric   case EHPersonality::MSVC_X86SEH:
6306c3fb27SDimitry Andric     return "_except_handler3";
6406c3fb27SDimitry Andric   case EHPersonality::MSVC_TableSEH:
6506c3fb27SDimitry Andric     return "__C_specific_handler";
6606c3fb27SDimitry Andric   case EHPersonality::MSVC_CXX:
6706c3fb27SDimitry Andric     return "__CxxFrameHandler3";
6806c3fb27SDimitry Andric   case EHPersonality::CoreCLR:
6906c3fb27SDimitry Andric     return "ProcessCLRException";
7006c3fb27SDimitry Andric   case EHPersonality::Rust:
7106c3fb27SDimitry Andric     return "rust_eh_personality";
7206c3fb27SDimitry Andric   case EHPersonality::Wasm_CXX:
7306c3fb27SDimitry Andric     return "__gxx_wasm_personality_v0";
7406c3fb27SDimitry Andric   case EHPersonality::XL_CXX:
7506c3fb27SDimitry Andric     return "__xlcxx_personality_v1";
7606c3fb27SDimitry Andric   case EHPersonality::Unknown:
7706c3fb27SDimitry Andric     llvm_unreachable("Unknown EHPersonality!");
7806c3fb27SDimitry Andric   }
7906c3fb27SDimitry Andric 
8006c3fb27SDimitry Andric   llvm_unreachable("Invalid EHPersonality!");
8106c3fb27SDimitry Andric }
8206c3fb27SDimitry Andric 
8306c3fb27SDimitry Andric EHPersonality llvm::getDefaultEHPersonality(const Triple &T) {
8406c3fb27SDimitry Andric   if (T.isPS5())
8506c3fb27SDimitry Andric     return EHPersonality::GNU_CXX;
8606c3fb27SDimitry Andric   else
8706c3fb27SDimitry Andric     return EHPersonality::GNU_C;
8806c3fb27SDimitry Andric }
8906c3fb27SDimitry Andric 
9006c3fb27SDimitry Andric bool llvm::canSimplifyInvokeNoUnwind(const Function *F) {
9106c3fb27SDimitry Andric   EHPersonality Personality = classifyEHPersonality(F->getPersonalityFn());
9206c3fb27SDimitry Andric   // We can't simplify any invokes to nounwind functions if the personality
9306c3fb27SDimitry Andric   // function wants to catch asynch exceptions.  The nounwind attribute only
9406c3fb27SDimitry Andric   // implies that the function does not throw synchronous exceptions.
9506c3fb27SDimitry Andric 
9606c3fb27SDimitry Andric   // Cannot simplify CXX Personality under AsynchEH
9706c3fb27SDimitry Andric   const llvm::Module *M = (const llvm::Module *)F->getParent();
9806c3fb27SDimitry Andric   bool EHa = M->getModuleFlag("eh-asynch");
9906c3fb27SDimitry Andric   return !EHa && !isAsynchronousEHPersonality(Personality);
10006c3fb27SDimitry Andric }
10106c3fb27SDimitry Andric 
10206c3fb27SDimitry Andric DenseMap<BasicBlock *, ColorVector> llvm::colorEHFunclets(Function &F) {
10306c3fb27SDimitry Andric   SmallVector<std::pair<BasicBlock *, BasicBlock *>, 16> Worklist;
10406c3fb27SDimitry Andric   BasicBlock *EntryBlock = &F.getEntryBlock();
10506c3fb27SDimitry Andric   DenseMap<BasicBlock *, ColorVector> BlockColors;
10606c3fb27SDimitry Andric 
10706c3fb27SDimitry Andric   // Build up the color map, which maps each block to its set of 'colors'.
10806c3fb27SDimitry Andric   // For any block B the "colors" of B are the set of funclets F (possibly
10906c3fb27SDimitry Andric   // including a root "funclet" representing the main function) such that
11006c3fb27SDimitry Andric   // F will need to directly contain B or a copy of B (where the term "directly
11106c3fb27SDimitry Andric   // contain" is used to distinguish from being "transitively contained" in
11206c3fb27SDimitry Andric   // a nested funclet).
11306c3fb27SDimitry Andric   //
11406c3fb27SDimitry Andric   // Note: Despite not being a funclet in the truest sense, a catchswitch is
11506c3fb27SDimitry Andric   // considered to belong to its own funclet for the purposes of coloring.
11606c3fb27SDimitry Andric 
117*5f757f3fSDimitry Andric   DEBUG_WITH_TYPE("win-eh-prepare-coloring",
11806c3fb27SDimitry Andric                   dbgs() << "\nColoring funclets for " << F.getName() << "\n");
11906c3fb27SDimitry Andric 
12006c3fb27SDimitry Andric   Worklist.push_back({EntryBlock, EntryBlock});
12106c3fb27SDimitry Andric 
12206c3fb27SDimitry Andric   while (!Worklist.empty()) {
12306c3fb27SDimitry Andric     BasicBlock *Visiting;
12406c3fb27SDimitry Andric     BasicBlock *Color;
12506c3fb27SDimitry Andric     std::tie(Visiting, Color) = Worklist.pop_back_val();
126*5f757f3fSDimitry Andric     DEBUG_WITH_TYPE("win-eh-prepare-coloring",
12706c3fb27SDimitry Andric                     dbgs() << "Visiting " << Visiting->getName() << ", "
12806c3fb27SDimitry Andric                            << Color->getName() << "\n");
12906c3fb27SDimitry Andric     Instruction *VisitingHead = Visiting->getFirstNonPHI();
13006c3fb27SDimitry Andric     if (VisitingHead->isEHPad()) {
13106c3fb27SDimitry Andric       // Mark this funclet head as a member of itself.
13206c3fb27SDimitry Andric       Color = Visiting;
13306c3fb27SDimitry Andric     }
13406c3fb27SDimitry Andric     // Note that this is a member of the given color.
13506c3fb27SDimitry Andric     ColorVector &Colors = BlockColors[Visiting];
13606c3fb27SDimitry Andric     if (!is_contained(Colors, Color))
13706c3fb27SDimitry Andric       Colors.push_back(Color);
13806c3fb27SDimitry Andric     else
13906c3fb27SDimitry Andric       continue;
14006c3fb27SDimitry Andric 
141*5f757f3fSDimitry Andric     DEBUG_WITH_TYPE("win-eh-prepare-coloring",
14206c3fb27SDimitry Andric                     dbgs() << "  Assigned color \'" << Color->getName()
14306c3fb27SDimitry Andric                            << "\' to block \'" << Visiting->getName()
14406c3fb27SDimitry Andric                            << "\'.\n");
14506c3fb27SDimitry Andric 
14606c3fb27SDimitry Andric     BasicBlock *SuccColor = Color;
14706c3fb27SDimitry Andric     Instruction *Terminator = Visiting->getTerminator();
14806c3fb27SDimitry Andric     if (auto *CatchRet = dyn_cast<CatchReturnInst>(Terminator)) {
14906c3fb27SDimitry Andric       Value *ParentPad = CatchRet->getCatchSwitchParentPad();
15006c3fb27SDimitry Andric       if (isa<ConstantTokenNone>(ParentPad))
15106c3fb27SDimitry Andric         SuccColor = EntryBlock;
15206c3fb27SDimitry Andric       else
15306c3fb27SDimitry Andric         SuccColor = cast<Instruction>(ParentPad)->getParent();
15406c3fb27SDimitry Andric     }
15506c3fb27SDimitry Andric 
15606c3fb27SDimitry Andric     for (BasicBlock *Succ : successors(Visiting))
15706c3fb27SDimitry Andric       Worklist.push_back({Succ, SuccColor});
15806c3fb27SDimitry Andric   }
15906c3fb27SDimitry Andric   return BlockColors;
16006c3fb27SDimitry Andric }
161