xref: /freebsd/contrib/llvm-project/llvm/lib/IR/EHPersonalities.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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/IR/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/IR/Module.h"
16 #include "llvm/Support/Debug.h"
17 #include "llvm/Support/raw_ostream.h"
18 #include "llvm/TargetParser/Triple.h"
19 using namespace llvm;
20 
21 /// See if the given exception handling personality function is one that we
22 /// understand.  If so, return a description of it; otherwise return Unknown.
classifyEHPersonality(const Value * Pers)23 EHPersonality llvm::classifyEHPersonality(const Value *Pers) {
24   const GlobalValue *F =
25       Pers ? dyn_cast<GlobalValue>(Pers->stripPointerCasts()) : nullptr;
26   if (!F || !F->getValueType() || !F->getValueType()->isFunctionTy())
27     return EHPersonality::Unknown;
28 
29   StringRef Name = F->getName();
30   if (F->getParent()->getTargetTriple().isWindowsArm64EC()) {
31     // ARM64EC function symbols are mangled by prefixing them with "#".
32     // Demangle them by skipping this prefix.
33     Name.consume_front("#");
34   }
35 
36   return StringSwitch<EHPersonality>(Name)
37       .Case("__gnat_eh_personality", EHPersonality::GNU_Ada)
38       .Case("__gxx_personality_v0", EHPersonality::GNU_CXX)
39       .Case("__gxx_personality_seh0", EHPersonality::GNU_CXX)
40       .Case("__gxx_personality_sj0", EHPersonality::GNU_CXX_SjLj)
41       .Case("__gcc_personality_v0", EHPersonality::GNU_C)
42       .Case("__gcc_personality_seh0", EHPersonality::GNU_C)
43       .Case("__gcc_personality_sj0", EHPersonality::GNU_C_SjLj)
44       .Case("__objc_personality_v0", EHPersonality::GNU_ObjC)
45       .Case("_except_handler3", EHPersonality::MSVC_X86SEH)
46       .Case("_except_handler4", EHPersonality::MSVC_X86SEH)
47       .Case("__C_specific_handler", EHPersonality::MSVC_TableSEH)
48       .Case("__CxxFrameHandler3", EHPersonality::MSVC_CXX)
49       .Case("ProcessCLRException", EHPersonality::CoreCLR)
50       .Case("rust_eh_personality", EHPersonality::Rust)
51       .Case("__gxx_wasm_personality_v0", EHPersonality::Wasm_CXX)
52       .Case("__xlcxx_personality_v1", EHPersonality::XL_CXX)
53       .Case("__zos_cxx_personality_v2", EHPersonality::ZOS_CXX)
54       .Default(EHPersonality::Unknown);
55 }
56 
getEHPersonalityName(EHPersonality Pers)57 StringRef llvm::getEHPersonalityName(EHPersonality Pers) {
58   switch (Pers) {
59   case EHPersonality::GNU_Ada:
60     return "__gnat_eh_personality";
61   case EHPersonality::GNU_CXX:
62     return "__gxx_personality_v0";
63   case EHPersonality::GNU_CXX_SjLj:
64     return "__gxx_personality_sj0";
65   case EHPersonality::GNU_C:
66     return "__gcc_personality_v0";
67   case EHPersonality::GNU_C_SjLj:
68     return "__gcc_personality_sj0";
69   case EHPersonality::GNU_ObjC:
70     return "__objc_personality_v0";
71   case EHPersonality::MSVC_X86SEH:
72     return "_except_handler3";
73   case EHPersonality::MSVC_TableSEH:
74     return "__C_specific_handler";
75   case EHPersonality::MSVC_CXX:
76     return "__CxxFrameHandler3";
77   case EHPersonality::CoreCLR:
78     return "ProcessCLRException";
79   case EHPersonality::Rust:
80     return "rust_eh_personality";
81   case EHPersonality::Wasm_CXX:
82     return "__gxx_wasm_personality_v0";
83   case EHPersonality::XL_CXX:
84     return "__xlcxx_personality_v1";
85   case EHPersonality::ZOS_CXX:
86     return "__zos_cxx_personality_v2";
87   case EHPersonality::Unknown:
88     llvm_unreachable("Unknown EHPersonality!");
89   }
90 
91   llvm_unreachable("Invalid EHPersonality!");
92 }
93 
getDefaultEHPersonality(const Triple & T)94 EHPersonality llvm::getDefaultEHPersonality(const Triple &T) {
95   if (T.isPS5())
96     return EHPersonality::GNU_CXX;
97   else
98     return EHPersonality::GNU_C;
99 }
100 
canSimplifyInvokeNoUnwind(const Function * F)101 bool llvm::canSimplifyInvokeNoUnwind(const Function *F) {
102   EHPersonality Personality = classifyEHPersonality(F->getPersonalityFn());
103   // We can't simplify any invokes to nounwind functions if the personality
104   // function wants to catch asynch exceptions.  The nounwind attribute only
105   // implies that the function does not throw synchronous exceptions.
106 
107   // Cannot simplify CXX Personality under AsynchEH
108   const llvm::Module *M = (const llvm::Module *)F->getParent();
109   bool EHa = M->getModuleFlag("eh-asynch");
110   return !EHa && !isAsynchronousEHPersonality(Personality);
111 }
112 
colorEHFunclets(Function & F)113 DenseMap<BasicBlock *, ColorVector> llvm::colorEHFunclets(Function &F) {
114   SmallVector<std::pair<BasicBlock *, BasicBlock *>, 16> Worklist;
115   BasicBlock *EntryBlock = &F.getEntryBlock();
116   DenseMap<BasicBlock *, ColorVector> BlockColors;
117 
118   // Build up the color map, which maps each block to its set of 'colors'.
119   // For any block B the "colors" of B are the set of funclets F (possibly
120   // including a root "funclet" representing the main function) such that
121   // F will need to directly contain B or a copy of B (where the term "directly
122   // contain" is used to distinguish from being "transitively contained" in
123   // a nested funclet).
124   //
125   // Note: Despite not being a funclet in the truest sense, a catchswitch is
126   // considered to belong to its own funclet for the purposes of coloring.
127 
128   DEBUG_WITH_TYPE("win-eh-prepare-coloring",
129                   dbgs() << "\nColoring funclets for " << F.getName() << "\n");
130 
131   Worklist.push_back({EntryBlock, EntryBlock});
132 
133   while (!Worklist.empty()) {
134     BasicBlock *Visiting;
135     BasicBlock *Color;
136     std::tie(Visiting, Color) = Worklist.pop_back_val();
137     DEBUG_WITH_TYPE("win-eh-prepare-coloring",
138                     dbgs() << "Visiting " << Visiting->getName() << ", "
139                            << Color->getName() << "\n");
140     BasicBlock::iterator VisitingHead = Visiting->getFirstNonPHIIt();
141     if (VisitingHead->isEHPad()) {
142       // Mark this funclet head as a member of itself.
143       Color = Visiting;
144     }
145     // Note that this is a member of the given color.
146     ColorVector &Colors = BlockColors[Visiting];
147     if (!is_contained(Colors, Color))
148       Colors.push_back(Color);
149     else
150       continue;
151 
152     DEBUG_WITH_TYPE("win-eh-prepare-coloring",
153                     dbgs() << "  Assigned color \'" << Color->getName()
154                            << "\' to block \'" << Visiting->getName()
155                            << "\'.\n");
156 
157     BasicBlock *SuccColor = Color;
158     Instruction *Terminator = Visiting->getTerminator();
159     if (auto *CatchRet = dyn_cast<CatchReturnInst>(Terminator)) {
160       Value *ParentPad = CatchRet->getCatchSwitchParentPad();
161       if (isa<ConstantTokenNone>(ParentPad))
162         SuccColor = EntryBlock;
163       else
164         SuccColor = cast<Instruction>(ParentPad)->getParent();
165     }
166 
167     for (BasicBlock *Succ : successors(Visiting))
168       Worklist.push_back({Succ, SuccColor});
169   }
170   return BlockColors;
171 }
172