#include "llvm/Target/TargetSelectionDAGInfo.h"
#include "llvm/Target/TargetSubtargetInfo.h"
#include <algorithm>
+#include <utility>
using namespace llvm;
#define DEBUG_TYPE "isel"
/// destination, but in the machine CFG, we enumerate all the possible blocks.
/// This function skips over imaginary basic blocks that hold catchpad,
/// terminatepad, or catchendpad instructions, and finds all the "real" machine
-/// basic block destinations.
-static void
-findUnwindDestinations(FunctionLoweringInfo &FuncInfo,
- const BasicBlock *EHPadBB,
- SmallVectorImpl<MachineBasicBlock *> &UnwindDests) {
+/// basic block destinations. As those destinations may not be successors of
+/// EHPadBB, here we also calculate the edge weight to those destinations. The
+/// passed-in Weight is the edge weight to EHPadBB.
+static void findUnwindDestinations(
+ FunctionLoweringInfo &FuncInfo, const BasicBlock *EHPadBB, uint32_t Weight,
+ SmallVectorImpl<std::pair<MachineBasicBlock *, uint32_t>> &UnwindDests) {
EHPersonality Personality =
classifyEHPersonality(FuncInfo.Fn->getPersonalityFn());
bool IsMSVCCXX = Personality == EHPersonality::MSVC_CXX;
bool IsCoreCLR = Personality == EHPersonality::CoreCLR;
+
while (EHPadBB) {
const Instruction *Pad = EHPadBB->getFirstNonPHI();
+ BasicBlock *NewEHPadBB = nullptr;
if (isa<LandingPadInst>(Pad)) {
// Stop on landingpads. They are not funclets.
- UnwindDests.push_back(FuncInfo.MBBMap[EHPadBB]);
+ UnwindDests.emplace_back(FuncInfo.MBBMap[EHPadBB], Weight);
break;
} else if (isa<CleanupPadInst>(Pad)) {
// Stop on cleanup pads. Cleanups are always funclet entries for all known
// personalities.
- UnwindDests.push_back(FuncInfo.MBBMap[EHPadBB]);
- UnwindDests.back()->setIsEHFuncletEntry();
+ UnwindDests.emplace_back(FuncInfo.MBBMap[EHPadBB], Weight);
+ UnwindDests.back().first->setIsEHFuncletEntry();
break;
} else if (const auto *CPI = dyn_cast<CatchPadInst>(Pad)) {
// Add the catchpad handler to the possible destinations.
- UnwindDests.push_back(FuncInfo.MBBMap[EHPadBB]);
+ UnwindDests.emplace_back(FuncInfo.MBBMap[EHPadBB], Weight);
// In MSVC C++, catchblocks are funclets and need prologues.
if (IsMSVCCXX || IsCoreCLR)
- UnwindDests.back()->setIsEHFuncletEntry();
- EHPadBB = CPI->getUnwindDest();
- } else if (const auto *CEPI = dyn_cast<CatchEndPadInst>(Pad)) {
- EHPadBB = CEPI->getUnwindDest();
- } else if (const auto *CEPI = dyn_cast<CleanupEndPadInst>(Pad)) {
- EHPadBB = CEPI->getUnwindDest();
+ UnwindDests.back().first->setIsEHFuncletEntry();
+ NewEHPadBB = CPI->getUnwindDest();
+ } else if (const auto *CEPI = dyn_cast<CatchEndPadInst>(Pad))
+ NewEHPadBB = CEPI->getUnwindDest();
+ else if (const auto *CEPI = dyn_cast<CleanupEndPadInst>(Pad))
+ NewEHPadBB = CEPI->getUnwindDest();
+ else
+ continue;
+
+ BranchProbabilityInfo *BPI = FuncInfo.BPI;
+ if (BPI && NewEHPadBB) {
+ // When BPI is available, the calculated weight cannot be zero as zero
+ // will be turned to a default weight in MachineBlockFrequencyInfo.
+ Weight = std::max<uint32_t>(
+ BPI->getEdgeProbability(EHPadBB, NewEHPadBB).scale(Weight), 1);
}
+ EHPadBB = NewEHPadBB;
}
}
void SelectionDAGBuilder::visitCleanupRet(const CleanupReturnInst &I) {
// Update successor info.
- // FIXME: The weights for catchpads will be wrong.
- SmallVector<MachineBasicBlock *, 1> UnwindDests;
- findUnwindDestinations(FuncInfo, I.getUnwindDest(), UnwindDests);
- for (MachineBasicBlock *UnwindDest : UnwindDests) {
- UnwindDest->setIsEHPad();
- addSuccessorWithWeight(FuncInfo.MBB, UnwindDest);
+ SmallVector<std::pair<MachineBasicBlock *, uint32_t>, 1> UnwindDests;
+ auto UnwindDest = I.getUnwindDest();
+ BranchProbabilityInfo *BPI = FuncInfo.BPI;
+ uint32_t UnwindDestWeight =
+ BPI ? BPI->getEdgeWeight(FuncInfo.MBB->getBasicBlock(), UnwindDest) : 0;
+ findUnwindDestinations(FuncInfo, UnwindDest, UnwindDestWeight, UnwindDests);
+ for (auto &UnwindDest : UnwindDests) {
+ UnwindDest.first->setIsEHPad();
+ addSuccessorWithWeight(FuncInfo.MBB, UnwindDest.first, UnwindDest.second);
}
// Create the terminator node.
CopyToExportRegsIfNeeded(&I);
}
- SmallVector<MachineBasicBlock *, 1> UnwindDests;
- findUnwindDestinations(FuncInfo, EHPadBB, UnwindDests);
+ SmallVector<std::pair<MachineBasicBlock *, uint32_t>, 1> UnwindDests;
+ BranchProbabilityInfo *BPI = FuncInfo.BPI;
+ uint32_t EHPadBBWeight =
+ BPI ? BPI->getEdgeWeight(InvokeMBB->getBasicBlock(), EHPadBB) : 0;
+ findUnwindDestinations(FuncInfo, EHPadBB, EHPadBBWeight, UnwindDests);
// Update successor info.
- // FIXME: The weights for catchpads will be wrong.
addSuccessorWithWeight(InvokeMBB, Return);
- for (MachineBasicBlock *UnwindDest : UnwindDests) {
- UnwindDest->setIsEHPad();
- addSuccessorWithWeight(InvokeMBB, UnwindDest);
+ for (auto &UnwindDest : UnwindDests) {
+ UnwindDest.first->setIsEHPad();
+ addSuccessorWithWeight(InvokeMBB, UnwindDest.first, UnwindDest.second);
}
// Drop into normal successor.
--- /dev/null
+; RUN: llc -march=x86-64 -print-machineinstrs=expand-isel-pseudos %s -o /dev/null 2>&1 | FileCheck %s
+
+; Check if the edge weight to the catchpad is calculated correctly.
+
+; CHECK: Successors according to CFG: BB#3(1048575) BB#1(1) BB#4(1) BB#6(1) BB#8(1)
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64--windows-msvc18.0.0"
+
+%rtti.TypeDescriptor7 = type { i8**, i8*, [8 x i8] }
+%struct.HasDtor = type { i8 }
+
+$"\01??_R0?AUA@@@8" = comdat any
+
+$"\01??_R0?AUB@@@8" = comdat any
+
+$"\01??_R0?AUC@@@8" = comdat any
+
+@"\01??_7type_info@@6B@" = external constant i8*
+@"\01??_R0?AUA@@@8" = linkonce_odr global %rtti.TypeDescriptor7 { i8** @"\01??_7type_info@@6B@", i8* null, [8 x i8] c".?AUA@@\00" }, comdat
+@"\01??_R0?AUB@@@8" = linkonce_odr global %rtti.TypeDescriptor7 { i8** @"\01??_7type_info@@6B@", i8* null, [8 x i8] c".?AUB@@\00" }, comdat
+@"\01??_R0?AUC@@@8" = linkonce_odr global %rtti.TypeDescriptor7 { i8** @"\01??_7type_info@@6B@", i8* null, [8 x i8] c".?AUC@@\00" }, comdat
+
+; Function Attrs: uwtable
+define i32 @main() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
+entry:
+ %o = alloca %struct.HasDtor, align 1
+ %0 = getelementptr inbounds %struct.HasDtor, %struct.HasDtor* %o, i64 0, i32 0
+ call void @llvm.lifetime.start(i64 1, i8* %0) #4
+ invoke void @"\01?may_throw@@YAXXZ"()
+ to label %try.cont unwind label %catch.dispatch
+
+catch.dispatch: ; preds = %entry
+ %1 = catchpad [%rtti.TypeDescriptor7* @"\01??_R0?AUA@@@8", i32 0, i8* null]
+ to label %catch.5 unwind label %catch.dispatch.1
+
+catch.5: ; preds = %catch.dispatch
+ catchret %1 to label %try.cont
+
+try.cont: ; preds = %entry, %catch, %catch.3, %catch.5
+ call void @"\01??1HasDtor@@QEAA@XZ"(%struct.HasDtor* nonnull %o) #4
+ call void @llvm.lifetime.end(i64 1, i8* %0) #4
+ ret i32 0
+
+catch.dispatch.1: ; preds = %catch.dispatch
+ %2 = catchpad [%rtti.TypeDescriptor7* @"\01??_R0?AUB@@@8", i32 0, i8* null]
+ to label %catch.3 unwind label %catch.dispatch.2
+
+catch.3: ; preds = %catch.dispatch.1
+ catchret %2 to label %try.cont
+
+catch.dispatch.2: ; preds = %catch.dispatch.1
+ %3 = catchpad [%rtti.TypeDescriptor7* @"\01??_R0?AUC@@@8", i32 0, i8* null]
+ to label %catch unwind label %catchendblock
+
+catch: ; preds = %catch.dispatch.2
+ catchret %3 to label %try.cont
+
+catchendblock: ; preds = %catch.dispatch.2
+ catchendpad unwind label %ehcleanup
+
+ehcleanup: ; preds = %catchendblock
+ %4 = cleanuppad []
+ call void @"\01??1HasDtor@@QEAA@XZ"(%struct.HasDtor* nonnull %o) #4
+ cleanupret %4 unwind to caller
+}
+
+; Function Attrs: nounwind argmemonly
+declare void @llvm.lifetime.start(i64, i8* nocapture) #1
+
+declare void @"\01?may_throw@@YAXXZ"() #2
+
+declare i32 @__CxxFrameHandler3(...)
+
+; Function Attrs: nounwind
+declare void @"\01??1HasDtor@@QEAA@XZ"(%struct.HasDtor*) #3
+
+; Function Attrs: nounwind argmemonly
+declare void @llvm.lifetime.end(i64, i8* nocapture) #1
+
+attributes #0 = { uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind argmemonly }
+attributes #2 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #3 = { nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #4 = { nounwind }