174 lines · cpp
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-exception6//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"19using namespace llvm;20 21/// See if the given exception handling personality function is one that we22/// understand. If so, return a description of it; otherwise return Unknown.23EHPersonality 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 // Rust mangles its personality function, so we can't test exact equality.51 .EndsWith("rust_eh_personality", EHPersonality::Rust)52 .Case("__gxx_wasm_personality_v0", EHPersonality::Wasm_CXX)53 .Case("__xlcxx_personality_v1", EHPersonality::XL_CXX)54 .Case("__zos_cxx_personality_v2", EHPersonality::ZOS_CXX)55 .Default(EHPersonality::Unknown);56}57 58StringRef llvm::getEHPersonalityName(EHPersonality Pers) {59 switch (Pers) {60 case EHPersonality::GNU_Ada:61 return "__gnat_eh_personality";62 case EHPersonality::GNU_CXX:63 return "__gxx_personality_v0";64 case EHPersonality::GNU_CXX_SjLj:65 return "__gxx_personality_sj0";66 case EHPersonality::GNU_C:67 return "__gcc_personality_v0";68 case EHPersonality::GNU_C_SjLj:69 return "__gcc_personality_sj0";70 case EHPersonality::GNU_ObjC:71 return "__objc_personality_v0";72 case EHPersonality::MSVC_X86SEH:73 return "_except_handler3";74 case EHPersonality::MSVC_TableSEH:75 return "__C_specific_handler";76 case EHPersonality::MSVC_CXX:77 return "__CxxFrameHandler3";78 case EHPersonality::CoreCLR:79 return "ProcessCLRException";80 case EHPersonality::Rust:81 llvm_unreachable(82 "Cannot get personality name of Rust personality, since it is mangled");83 case EHPersonality::Wasm_CXX:84 return "__gxx_wasm_personality_v0";85 case EHPersonality::XL_CXX:86 return "__xlcxx_personality_v1";87 case EHPersonality::ZOS_CXX:88 return "__zos_cxx_personality_v2";89 case EHPersonality::Unknown:90 llvm_unreachable("Unknown EHPersonality!");91 }92 93 llvm_unreachable("Invalid EHPersonality!");94}95 96EHPersonality llvm::getDefaultEHPersonality(const Triple &T) {97 if (T.isPS5())98 return EHPersonality::GNU_CXX;99 else100 return EHPersonality::GNU_C;101}102 103bool llvm::canSimplifyInvokeNoUnwind(const Function *F) {104 EHPersonality Personality = classifyEHPersonality(F->getPersonalityFn());105 // We can't simplify any invokes to nounwind functions if the personality106 // function wants to catch asynch exceptions. The nounwind attribute only107 // implies that the function does not throw synchronous exceptions.108 109 // Cannot simplify CXX Personality under AsynchEH110 const llvm::Module *M = (const llvm::Module *)F->getParent();111 bool EHa = M->getModuleFlag("eh-asynch");112 return !EHa && !isAsynchronousEHPersonality(Personality);113}114 115DenseMap<BasicBlock *, ColorVector> llvm::colorEHFunclets(Function &F) {116 SmallVector<std::pair<BasicBlock *, BasicBlock *>, 16> Worklist;117 BasicBlock *EntryBlock = &F.getEntryBlock();118 DenseMap<BasicBlock *, ColorVector> BlockColors;119 120 // Build up the color map, which maps each block to its set of 'colors'.121 // For any block B the "colors" of B are the set of funclets F (possibly122 // including a root "funclet" representing the main function) such that123 // F will need to directly contain B or a copy of B (where the term "directly124 // contain" is used to distinguish from being "transitively contained" in125 // a nested funclet).126 //127 // Note: Despite not being a funclet in the truest sense, a catchswitch is128 // considered to belong to its own funclet for the purposes of coloring.129 130 DEBUG_WITH_TYPE("win-eh-prepare-coloring",131 dbgs() << "\nColoring funclets for " << F.getName() << "\n");132 133 Worklist.push_back({EntryBlock, EntryBlock});134 135 while (!Worklist.empty()) {136 BasicBlock *Visiting;137 BasicBlock *Color;138 std::tie(Visiting, Color) = Worklist.pop_back_val();139 DEBUG_WITH_TYPE("win-eh-prepare-coloring",140 dbgs() << "Visiting " << Visiting->getName() << ", "141 << Color->getName() << "\n");142 BasicBlock::iterator VisitingHead = Visiting->getFirstNonPHIIt();143 if (VisitingHead->isEHPad()) {144 // Mark this funclet head as a member of itself.145 Color = Visiting;146 }147 // Note that this is a member of the given color.148 ColorVector &Colors = BlockColors[Visiting];149 if (!is_contained(Colors, Color))150 Colors.push_back(Color);151 else152 continue;153 154 DEBUG_WITH_TYPE("win-eh-prepare-coloring",155 dbgs() << " Assigned color \'" << Color->getName()156 << "\' to block \'" << Visiting->getName()157 << "\'.\n");158 159 BasicBlock *SuccColor = Color;160 Instruction *Terminator = Visiting->getTerminator();161 if (auto *CatchRet = dyn_cast<CatchReturnInst>(Terminator)) {162 Value *ParentPad = CatchRet->getCatchSwitchParentPad();163 if (isa<ConstantTokenNone>(ParentPad))164 SuccColor = EntryBlock;165 else166 SuccColor = cast<Instruction>(ParentPad)->getParent();167 }168 169 for (BasicBlock *Succ : successors(Visiting))170 Worklist.push_back({Succ, SuccColor});171 }172 return BlockColors;173}174