diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td index 0a74a217a5f01..5e4ee4276aa97 100644 --- a/llvm/include/llvm/IR/Intrinsics.td +++ b/llvm/include/llvm/IR/Intrinsics.td @@ -1405,8 +1405,8 @@ let IntrProperties = [IntrNoMem, IntrSpeculatable, IntrWillReturn] in { // given function it is 'const' and may be CSE'd etc. def int_eh_typeid_for : Intrinsic<[llvm_i32_ty], [llvm_anyptr_ty], [IntrNoMem]>; -def int_eh_return_i32 : Intrinsic<[], [llvm_i32_ty, llvm_ptr_ty]>; -def int_eh_return_i64 : Intrinsic<[], [llvm_i64_ty, llvm_ptr_ty]>; +def int_eh_return_i32 : Intrinsic<[], [llvm_i32_ty, llvm_ptr_ty], [IntrNoReturn]>; +def int_eh_return_i64 : Intrinsic<[], [llvm_i64_ty, llvm_ptr_ty], [IntrNoReturn]>; // eh.exceptionpointer returns the pointer to the exception caught by // the given `catchpad`. diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp index 8e860a1f74029..7cf6e4d55c24a 100644 --- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp +++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -3125,6 +3125,14 @@ bool IRTranslator::translateUnreachable(const User &U, MachineIRBuilder &MIRBuil // Do not emit an additional trap instruction. if (Call->isNonContinuableTrap()) return true; + // Do not emit trap instructions after EH_RETURN intrinsics. + // This can cause problems later down the line when other machine passes + // attempt to use the last instruction in a BB to determine terminator behavior. + if (const auto *II = dyn_cast(Call)) { + const auto IID = II->getIntrinsicID(); + if (IID == Intrinsic::eh_return_i32 || IID == Intrinsic::eh_return_i64) + return true; + } } MIRBuilder.buildTrap(); diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index 25213f587116d..8ca1aa0278f12 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -3553,6 +3553,14 @@ void SelectionDAGBuilder::visitUnreachable(const UnreachableInst &I) { // Do not emit an additional trap instruction. if (Call->isNonContinuableTrap()) return; + // Do not emit trap instructions after EH_RETURN intrinsics. + // This can cause problems later down the line when other machine passes + // attempt to use the last instruction in a BB to determine terminator behavior. + if (const auto *II = dyn_cast(Call)) { + const auto IID = II->getIntrinsicID(); + if (IID == Intrinsic::eh_return_i32 || IID == Intrinsic::eh_return_i64) + return; + } } DAG.setRoot(DAG.getNode(ISD::TRAP, getCurSDLoc(), MVT::Other, DAG.getRoot())); diff --git a/llvm/test/CodeGen/X86/eh-trap-unreachable-x86.ll b/llvm/test/CodeGen/X86/eh-trap-unreachable-x86.ll new file mode 100644 index 0000000000000..1101a89f68b0b --- /dev/null +++ b/llvm/test/CodeGen/X86/eh-trap-unreachable-x86.ll @@ -0,0 +1,15 @@ +; RUN: llc < %s -mtriple=i386-unknown-unknown -trap-unreachable -no-trap-after-noreturn=false -verify-machineinstrs | FileCheck %s + +;; Ensure we restore caller-saved registers before EH_RETURN, even with trap-unreachable enabled. +;; For now, we deliberately avoid generating traps altogether. + +; CHECK-LABEL: test32 +; CHECK: pushl +; CHECK: popl +; CHECK: eh_return +; CHECK-NOT: ud2 +define void @test32(i32 %offset, ptr %handler) { + call void @llvm.eh.unwind.init() + call void @llvm.eh.return.i32(i32 %offset, ptr %handler) + unreachable +} diff --git a/llvm/test/CodeGen/X86/eh-trap-unreachable-x86_64.ll b/llvm/test/CodeGen/X86/eh-trap-unreachable-x86_64.ll new file mode 100644 index 0000000000000..d95bd610b5622 --- /dev/null +++ b/llvm/test/CodeGen/X86/eh-trap-unreachable-x86_64.ll @@ -0,0 +1,15 @@ +; RUN: llc < %s -mtriple=x86_64-unknown-unknown -trap-unreachable -no-trap-after-noreturn=false -verify-machineinstrs | FileCheck %s + +;; Ensure we restore caller-saved registers before EH_RETURN, even with trap-unreachable enabled. +;; For now, we deliberately avoid generating traps altogether. + +; CHECK-LABEL: test64 +; CHECK: pushq +; CHECK: popq +; CHECK: eh_return +; CHECK-NOT: ud2 +define void @test64(i64 %offset, ptr %handler) { + call void @llvm.eh.unwind.init() + call void @llvm.eh.return.i64(i64 %offset, ptr %handler) + unreachable +}