tentzen created this revision. tentzen added reviewers: rnk, eli.friedman, JosephTremoulet, asmith. Herald added a project: clang. Herald added a subscriber: cfe-commits.
Per Windows SEH Spec, except _leave, all other early exits of a _try (goto/return/continue/break) are considered abnormal exits. In those cases, the first parameter passes to its _finally funclet should be TRUE to indicate an abnormal-termination. One way to implement abnormal exits in _try is to invoke Windows runtime _local_unwind() (MSVC approach) that will invoke _dtor funclet where abnormal-termination flag is always TRUE when calling _finally. Obviously this approach is less optimal and is complicated to implement in Clang. Clang today has a NormalCleanupDestSlot mechanism to dispatch multiple exits at the end of _try. Since _leave (or try-end fall-through) is always Indexed with 0 in that NormalCleanupDestSlot, this fix takes the advantage of that mechanism and just passes NormalCleanupDest ID as 1st Arg to _finally. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D77936 Files: clang/lib/CodeGen/CGCleanup.cpp clang/lib/CodeGen/CGException.cpp clang/lib/CodeGen/EHScopeStack.h Index: clang/lib/CodeGen/EHScopeStack.h =================================================================== --- clang/lib/CodeGen/EHScopeStack.h +++ clang/lib/CodeGen/EHScopeStack.h @@ -160,7 +160,8 @@ enum { F_IsForEH = 0x1, F_IsNormalCleanupKind = 0x2, - F_IsEHCleanupKind = 0x4 + F_IsEHCleanupKind = 0x4, + F_HasSehAbnormalExits = 0x8 }; unsigned flags; @@ -179,6 +180,9 @@ /// cleanup. bool isEHCleanupKind() const { return flags & F_IsEHCleanupKind; } void setIsEHCleanupKind() { flags |= F_IsEHCleanupKind; } + + bool hasSehAbnormalExits() const { return flags & F_HasSehAbnormalExits; } + void setHasSehAbnormalExits() { flags |= F_HasSehAbnormalExits; } }; Index: clang/lib/CodeGen/CGException.cpp =================================================================== --- clang/lib/CodeGen/CGException.cpp +++ clang/lib/CodeGen/CGException.cpp @@ -1639,6 +1639,18 @@ llvm::Value *IsForEH = llvm::ConstantInt::get(CGF.ConvertType(ArgTys[0]), F.isForEHCleanup()); + + // Except _leave and fall-through at the end, all other exits in a _try + // (return/goto/continue/break) are considered as abnormal terminations + // since _leave/fall-through is always Indexed 0, + // just use NormalCleanupDestSlot (>= 1 for goto/return/..), + // as 1st Arg to indicate abnormal termination + if (!F.isForEHCleanup() && F.hasSehAbnormalExits()) { + Address Addr = CGF.getNormalCleanupDestSlot(); + llvm::Value* Load = CGF.Builder.CreateLoad(Addr, "cleanup.dest"); + IsForEH = CGF.Builder.CreateTrunc(Load, CGM.Int8Ty); + } + Args.add(RValue::get(IsForEH), ArgTys[0]); Args.add(RValue::get(FP), ArgTys[1]); Index: clang/lib/CodeGen/CGCleanup.cpp =================================================================== --- clang/lib/CodeGen/CGCleanup.cpp +++ clang/lib/CodeGen/CGCleanup.cpp @@ -860,6 +860,9 @@ // TODO: base this on the number of branch-afters and fixups const unsigned SwitchCapacity = 10; + // pass the abnormal exit flag to Fn (SEH cleanup) + cleanupFlags.setHasSehAbnormalExits(); + llvm::LoadInst *Load = createLoadInstBefore(getNormalCleanupDestSlot(), "cleanup.dest", nullptr);
Index: clang/lib/CodeGen/EHScopeStack.h =================================================================== --- clang/lib/CodeGen/EHScopeStack.h +++ clang/lib/CodeGen/EHScopeStack.h @@ -160,7 +160,8 @@ enum { F_IsForEH = 0x1, F_IsNormalCleanupKind = 0x2, - F_IsEHCleanupKind = 0x4 + F_IsEHCleanupKind = 0x4, + F_HasSehAbnormalExits = 0x8 }; unsigned flags; @@ -179,6 +180,9 @@ /// cleanup. bool isEHCleanupKind() const { return flags & F_IsEHCleanupKind; } void setIsEHCleanupKind() { flags |= F_IsEHCleanupKind; } + + bool hasSehAbnormalExits() const { return flags & F_HasSehAbnormalExits; } + void setHasSehAbnormalExits() { flags |= F_HasSehAbnormalExits; } }; Index: clang/lib/CodeGen/CGException.cpp =================================================================== --- clang/lib/CodeGen/CGException.cpp +++ clang/lib/CodeGen/CGException.cpp @@ -1639,6 +1639,18 @@ llvm::Value *IsForEH = llvm::ConstantInt::get(CGF.ConvertType(ArgTys[0]), F.isForEHCleanup()); + + // Except _leave and fall-through at the end, all other exits in a _try + // (return/goto/continue/break) are considered as abnormal terminations + // since _leave/fall-through is always Indexed 0, + // just use NormalCleanupDestSlot (>= 1 for goto/return/..), + // as 1st Arg to indicate abnormal termination + if (!F.isForEHCleanup() && F.hasSehAbnormalExits()) { + Address Addr = CGF.getNormalCleanupDestSlot(); + llvm::Value* Load = CGF.Builder.CreateLoad(Addr, "cleanup.dest"); + IsForEH = CGF.Builder.CreateTrunc(Load, CGM.Int8Ty); + } + Args.add(RValue::get(IsForEH), ArgTys[0]); Args.add(RValue::get(FP), ArgTys[1]); Index: clang/lib/CodeGen/CGCleanup.cpp =================================================================== --- clang/lib/CodeGen/CGCleanup.cpp +++ clang/lib/CodeGen/CGCleanup.cpp @@ -860,6 +860,9 @@ // TODO: base this on the number of branch-afters and fixups const unsigned SwitchCapacity = 10; + // pass the abnormal exit flag to Fn (SEH cleanup) + cleanupFlags.setHasSehAbnormalExits(); + llvm::LoadInst *Load = createLoadInstBefore(getNormalCleanupDestSlot(), "cleanup.dest", nullptr);
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits