Index: lib/CodeGen/WinEHPrepare.cpp =================================================================== --- lib/CodeGen/WinEHPrepare.cpp +++ lib/CodeGen/WinEHPrepare.cpp @@ -455,7 +455,7 @@ std::tie(Pad, ParentState) = Worklist.pop_back_val(); Value *OuterScope; - int PredState; + int SelfState; if (const CleanupPadInst *Cleanup = dyn_cast(Pad)) { // A cleanup can have multiple exits; don't re-process after the first. if (FuncInfo.EHPadStateMap.count(Cleanup)) @@ -463,50 +463,41 @@ // CoreCLR personality uses arity to distinguish faults from finallies. const BasicBlock *PadBlock = Cleanup->getParent(); ClrHandlerType HandlerType = - (Cleanup->getNumOperands() ? ClrHandlerType::Fault - : ClrHandlerType::Finally); - int NewState = + (Cleanup->getNumArgOperands() ? ClrHandlerType::Fault + : ClrHandlerType::Finally); + SelfState = addClrEHHandler(FuncInfo, ParentState, HandlerType, 0, PadBlock); - FuncInfo.EHPadStateMap[Cleanup] = NewState; - // Propagate the new state to all preds of the cleanup OuterScope = Cleanup->getOuterScope(); - PredState = NewState; } else if (const auto *CatchSwitch = dyn_cast(Pad)) { - SmallVector Handlers; - for (const Use &U : CatchSwitch->handlers()) { - const auto *Catch = - cast(cast(U)->getFirstNonPHI()); - Handlers.push_back(Catch); - } - FuncInfo.EHPadStateMap[CatchSwitch] = ParentState; + // Walk the catchpads in reverse order since the early ones are reported + // like descendants of the later ones in the EH tables. int NewState = ParentState; - for (auto HandlerI = Handlers.rbegin(), HandlerE = Handlers.rend(); - HandlerI != HandlerE; ++HandlerI) { - const CatchPadInst *Catch = *HandlerI; - const BasicBlock *PadBlock = Catch->getParent(); + SmallVector CatchBlocks(CatchSwitch->handlers()); + for (auto CBI = CatchBlocks.rbegin(), CBE = CatchBlocks.rend(); + CBI != CBE; ++CBI) { + const BasicBlock *CatchBlock = cast(*CBI); + const auto *Catch = cast(CatchBlock->getFirstNonPHI()); uint32_t TypeToken = static_cast( cast(Catch->getArgOperand(0))->getZExtValue()); NewState = addClrEHHandler(FuncInfo, NewState, ClrHandlerType::Catch, - TypeToken, PadBlock); + TypeToken, CatchBlock); FuncInfo.EHPadStateMap[Catch] = NewState; } - for (const auto *CatchPad : Handlers) { - for (const User *U : CatchPad->users()) { - const auto *UserI = cast(U); - if (UserI->isEHPad()) - Worklist.emplace_back(UserI, ParentState); - } - } - PredState = NewState; + // The catchswitch uses the same state number as the first catch (or, if + // we ever see an empty catchswitch, the state number of its successor). + SelfState = NewState; OuterScope = CatchSwitch->getOuterScope(); } else { llvm_unreachable("Unexpected EH pad"); } + // Record this pad's state. + FuncInfo.EHPadStateMap[Pad] = SelfState; + // Queue all predecessors with the given state for (const BasicBlock *Pred : predecessors(Pad->getParent())) { if ((Pred = getEHPadFromPredecessor(Pred, OuterScope))) - Worklist.emplace_back(Pred->getFirstNonPHI(), PredState); + Worklist.emplace_back(Pred->getFirstNonPHI(), SelfState); } } Index: test/CodeGen/X86/wineh-coreclr.ll =================================================================== --- test/CodeGen/X86/wineh-coreclr.ll +++ test/CodeGen/X86/wineh-coreclr.ll @@ -146,122 +146,120 @@ ; CHECK: [[L_end:.*func_end.*]]: } -; FIXME: Verify that the new clauses are correct and re-enable these checks. - ; Now check for EH table in xdata (following standard xdata) -; CHECKX-LABEL: .section .xdata +; CHECK-LABEL: .section .xdata ; standard xdata comes here -; CHECKX: .long 4{{$}} +; CHECK: .long 4{{$}} ; ^ number of funclets -; CHECKX-NEXT: .long [[L_catch1]]-[[L_begin]] +; CHECK-NEXT: .long [[L_catch1]]-[[L_begin]] ; ^ offset from L_begin to start of 1st funclet -; CHECKX-NEXT: .long [[L_catch2]]-[[L_begin]] +; CHECK-NEXT: .long [[L_catch2]]-[[L_begin]] ; ^ offset from L_begin to start of 2nd funclet -; CHECKX-NEXT: .long [[L_fault]]-[[L_begin]] +; CHECK-NEXT: .long [[L_fault]]-[[L_begin]] ; ^ offset from L_begin to start of 3rd funclet -; CHECKX-NEXT: .long [[L_finally]]-[[L_begin]] +; CHECK-NEXT: .long [[L_finally]]-[[L_begin]] ; ^ offset from L_begin to start of 4th funclet -; CHECKX-NEXT: .long [[L_end]]-[[L_begin]] +; CHECK-NEXT: .long [[L_end]]-[[L_begin]] ; ^ offset from L_begin to end of last funclet -; CHECKX-NEXT: .long 7 +; CHECK-NEXT: .long 7 ; ^ number of EH clauses ; Clause 1: call f(2) is guarded by catch1 -; CHECKX-NEXT: .long 0 +; CHECK-NEXT: .long 0 ; ^ flags (0 => catch handler) -; CHECKX-NEXT: .long ([[L_before_f2]]-[[L_begin]])+1 +; CHECK-NEXT: .long ([[L_before_f2]]-[[L_begin]])+1 ; ^ offset of start of clause -; CHECKX-NEXT: .long ([[L_after_f2]]-[[L_begin]])+1 +; CHECK-NEXT: .long ([[L_after_f2]]-[[L_begin]])+1 ; ^ offset of end of clause -; CHECKX-NEXT: .long [[L_catch1]]-[[L_begin]] +; CHECK-NEXT: .long [[L_catch1]]-[[L_begin]] ; ^ offset of start of handler -; CHECKX-NEXT: .long [[L_catch2]]-[[L_begin]] +; CHECK-NEXT: .long [[L_catch2]]-[[L_begin]] ; ^ offset of end of handler -; CHECKX-NEXT: .long 1 +; CHECK-NEXT: .long 1 ; ^ type token of catch (from catchpad) ; Clause 2: call f(2) is also guarded by catch2 -; CHECKX-NEXT: .long 0 +; CHECK-NEXT: .long 0 ; ^ flags (0 => catch handler) -; CHECKX-NEXT: .long ([[L_before_f2]]-[[L_begin]])+1 +; CHECK-NEXT: .long ([[L_before_f2]]-[[L_begin]])+1 ; ^ offset of start of clause -; CHECKX-NEXT: .long ([[L_after_f2]]-[[L_begin]])+1 +; CHECK-NEXT: .long ([[L_after_f2]]-[[L_begin]])+1 ; ^ offset of end of clause -; CHECKX-NEXT: .long [[L_catch2]]-[[L_begin]] +; CHECK-NEXT: .long [[L_catch2]]-[[L_begin]] ; ^ offset of start of handler -; CHECKX-NEXT: .long [[L_fault]]-[[L_begin]] +; CHECK-NEXT: .long [[L_fault]]-[[L_begin]] ; ^ offset of end of handler -; CHECKX-NEXT: .long 2 +; CHECK-NEXT: .long 2 ; ^ type token of catch (from catchpad) ; Clause 3: calls f(1) and f(2) are guarded by finally -; CHECKX-NEXT: .long 2 +; CHECK-NEXT: .long 2 ; ^ flags (2 => finally handler) -; CHECKX-NEXT: .long ([[L_before_f1]]-[[L_begin]])+1 +; CHECK-NEXT: .long ([[L_before_f1]]-[[L_begin]])+1 ; ^ offset of start of clause -; CHECKX-NEXT: .long ([[L_after_f2]]-[[L_begin]])+1 +; CHECK-NEXT: .long ([[L_after_f2]]-[[L_begin]])+1 ; ^ offset of end of clause -; CHECKX-NEXT: .long [[L_finally]]-[[L_begin]] +; CHECK-NEXT: .long [[L_finally]]-[[L_begin]] ; ^ offset of start of handler -; CHECKX-NEXT: .long [[L_end]]-[[L_begin]] +; CHECK-NEXT: .long [[L_end]]-[[L_begin]] ; ^ offset of end of handler -; CHECKX-NEXT: .long 0 +; CHECK-NEXT: .long 0 ; ^ type token slot (null for finally) ; Clause 4: call f(3) is guarded by finally ; This is a "duplicate" because the protected range (f(3)) ; is in funclet catch1 but the finally's immediate parent ; is the main function, not that funclet. -; CHECKX-NEXT: .long 10 +; CHECK-NEXT: .long 10 ; ^ flags (2 => finally handler | 8 => duplicate) -; CHECKX-NEXT: .long ([[L_before_f3]]-[[L_begin]])+1 +; CHECK-NEXT: .long ([[L_before_f3]]-[[L_begin]])+1 ; ^ offset of start of clause -; CHECKX-NEXT: .long ([[L_after_f3]]-[[L_begin]])+1 +; CHECK-NEXT: .long ([[L_after_f3]]-[[L_begin]])+1 ; ^ offset of end of clause -; CHECKX-NEXT: .long [[L_finally]]-[[L_begin]] +; CHECK-NEXT: .long [[L_finally]]-[[L_begin]] ; ^ offset of start of handler -; CHECKX-NEXT: .long [[L_end]]-[[L_begin]] +; CHECK-NEXT: .long [[L_end]]-[[L_begin]] ; ^ offset of end of handler -; CHECKX-NEXT: .long 0 +; CHECK-NEXT: .long 0 ; ^ type token slot (null for finally) ; Clause 5: call f(5) is guarded by fault -; CHECKX-NEXT: .long 4 +; CHECK-NEXT: .long 4 ; ^ flags (4 => fault handler) -; CHECKX-NEXT: .long ([[L_before_f5]]-[[L_begin]])+1 +; CHECK-NEXT: .long ([[L_before_f5]]-[[L_begin]])+1 ; ^ offset of start of clause -; CHECKX-NEXT: .long ([[L_after_f5]]-[[L_begin]])+1 +; CHECK-NEXT: .long ([[L_after_f5]]-[[L_begin]])+1 ; ^ offset of end of clause -; CHECKX-NEXT: .long [[L_fault]]-[[L_begin]] +; CHECK-NEXT: .long [[L_fault]]-[[L_begin]] ; ^ offset of start of handler -; CHECKX-NEXT: .long [[L_finally]]-[[L_begin]] +; CHECK-NEXT: .long [[L_finally]]-[[L_begin]] ; ^ offset of end of handler -; CHECKX-NEXT: .long 0 +; CHECK-NEXT: .long 0 ; ^ type token slot (null for fault) ; Clause 6: calls f(4) and f(5) are guarded by finally ; This is a "duplicate" because the protected range (f(4)-f(5)) ; is in funclet catch2 but the finally's immediate parent ; is the main function, not that funclet. -; CHECKX-NEXT: .long 10 +; CHECK-NEXT: .long 10 ; ^ flags (2 => finally handler | 8 => duplicate) -; CHECKX-NEXT: .long ([[L_before_f4]]-[[L_begin]])+1 +; CHECK-NEXT: .long ([[L_before_f4]]-[[L_begin]])+1 ; ^ offset of start of clause -; CHECKX-NEXT: .long ([[L_after_f5]]-[[L_begin]])+1 +; CHECK-NEXT: .long ([[L_after_f5]]-[[L_begin]])+1 ; ^ offset of end of clause -; CHECKX-NEXT: .long [[L_finally]]-[[L_begin]] +; CHECK-NEXT: .long [[L_finally]]-[[L_begin]] ; ^ offset of start of handler -; CHECKX-NEXT: .long [[L_end]]-[[L_begin]] +; CHECK-NEXT: .long [[L_end]]-[[L_begin]] ; ^ offset of end of handler -; CHECKX-NEXT: .long 0 +; CHECK-NEXT: .long 0 ; ^ type token slot (null for finally) ; Clause 7: call f(6) is guarded by finally ; This is a "duplicate" because the protected range (f(3)) ; is in funclet catch1 but the finally's immediate parent ; is the main function, not that funclet. -; CHECKX-NEXT: .long 10 +; CHECK-NEXT: .long 10 ; ^ flags (2 => finally handler | 8 => duplicate) -; CHECKX-NEXT: .long ([[L_before_f6]]-[[L_begin]])+1 +; CHECK-NEXT: .long ([[L_before_f6]]-[[L_begin]])+1 ; ^ offset of start of clause -; CHECKX-NEXT: .long ([[L_after_f6]]-[[L_begin]])+1 +; CHECK-NEXT: .long ([[L_after_f6]]-[[L_begin]])+1 ; ^ offset of end of clause -; CHECKX-NEXT: .long [[L_finally]]-[[L_begin]] +; CHECK-NEXT: .long [[L_finally]]-[[L_begin]] ; ^ offset of start of handler -; CHECKX-NEXT: .long [[L_end]]-[[L_begin]] +; CHECK-NEXT: .long [[L_end]]-[[L_begin]] ; ^ offset of end of handler -; CHECKX-NEXT: .long 0 +; CHECK-NEXT: .long 0 ; ^ type token slot (null for finally)