diff --git a/include/llvm/Target/TargetOptions.h b/include/llvm/Target/TargetOptions.h index 70fac7833f3..ae206ed90fe 100644 --- a/include/llvm/Target/TargetOptions.h +++ b/include/llvm/Target/TargetOptions.h @@ -107,7 +107,9 @@ namespace llvm { EnableFastISel(false), UseInitArray(false), DisableIntegratedAS(false), RelaxELFRelocations(false), FunctionSections(false), DataSections(false), - UniqueSectionNames(true), TrapUnreachable(false), EmulatedTLS(false), + UniqueSectionNames(true), TrapUnreachable(false), + NoTrapAfterNoreturn(false), + EmulatedTLS(false), EnableIPRA(false), EmitStackSizeSection(false) {} /// PrintMachineCode - This flag is enabled when the -print-machineinstrs @@ -209,6 +211,10 @@ namespace llvm { /// Emit target-specific trap instruction for 'unreachable' IR instructions. unsigned TrapUnreachable : 1; + /// Do not emit a trap instruction for 'unreachable' IR instructions behind + /// noreturn calls, even if TrapUnreachable is true. + unsigned NoTrapAfterNoreturn : 1; + /// EmulatedTLS - This flag enables emulated TLS model, using emutls /// function in the runtime library.. unsigned EmulatedTLS : 1; diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index 263d2ec2a12..d8708ecf186 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -2584,9 +2584,23 @@ void SelectionDAGBuilder::visitIndirectBr(const IndirectBrInst &I) { } void SelectionDAGBuilder::visitUnreachable(const UnreachableInst &I) { - if (DAG.getTarget().Options.TrapUnreachable) - DAG.setRoot( - DAG.getNode(ISD::TRAP, getCurSDLoc(), MVT::Other, DAG.getRoot())); + if (!DAG.getTarget().Options.TrapUnreachable) + return; + + // We may be able to ignore unreachable behind a noreturn call. + if (DAG.getTarget().Options.NoTrapAfterNoreturn) { + const BasicBlock &BB = *I.getParent(); + if (&I != &BB.front()) { + BasicBlock::const_iterator PredI = + std::prev(BasicBlock::const_iterator(&I)); + if (const CallInst *Call = dyn_cast(&*PredI)) { + if (Call->doesNotReturn()) + return; + } + } + } + + DAG.setRoot(DAG.getNode(ISD::TRAP, getCurSDLoc(), MVT::Other, DAG.getRoot())); } void SelectionDAGBuilder::visitFSub(const User &I) { diff --git a/lib/Target/AArch64/AArch64TargetMachine.cpp b/lib/Target/AArch64/AArch64TargetMachine.cpp index 1ebc1748369..6fef33e2a6e 100644 --- a/lib/Target/AArch64/AArch64TargetMachine.cpp +++ b/lib/Target/AArch64/AArch64TargetMachine.cpp @@ -244,8 +244,10 @@ AArch64TargetMachine::AArch64TargetMachine(const Target &T, const Triple &TT, TLOF(createTLOF(getTargetTriple())), isLittle(LittleEndian) { initAsmInfo(); - if (TT.isOSBinFormatMachO()) + if (TT.isOSBinFormatMachO()) { this->Options.TrapUnreachable = true; + this->Options.NoTrapAfterNoreturn = true; + } } AArch64TargetMachine::~AArch64TargetMachine() = default; diff --git a/lib/Target/ARM/ARMTargetMachine.cpp b/lib/Target/ARM/ARMTargetMachine.cpp index e768cc87940..204adff04a3 100644 --- a/lib/Target/ARM/ARMTargetMachine.cpp +++ b/lib/Target/ARM/ARMTargetMachine.cpp @@ -238,8 +238,10 @@ ARMBaseTargetMachine::ARMBaseTargetMachine(const Target &T, const Triple &TT, this->Options.EABIVersion = EABI::EABI5; } - if (TT.isOSBinFormatMachO()) + if (TT.isOSBinFormatMachO()) { this->Options.TrapUnreachable = true; + this->Options.NoTrapAfterNoreturn = true; + } initAsmInfo(); } diff --git a/lib/Target/X86/X86TargetMachine.cpp b/lib/Target/X86/X86TargetMachine.cpp index ee6efc09cb8..d0941e3d109 100644 --- a/lib/Target/X86/X86TargetMachine.cpp +++ b/lib/Target/X86/X86TargetMachine.cpp @@ -221,8 +221,10 @@ X86TargetMachine::X86TargetMachine(const Target &T, const Triple &TT, // to ever want to mix 32 and 64-bit windows code in a single module // this should be fine. if ((TT.isOSWindows() && TT.getArch() == Triple::x86_64) || TT.isPS4() || - TT.isOSBinFormatMachO()) + TT.isOSBinFormatMachO()) { this->Options.TrapUnreachable = true; + this->Options.NoTrapAfterNoreturn = TT.isOSBinFormatMachO(); + } initAsmInfo(); } diff --git a/test/CodeGen/X86/unreachable-trap.ll b/test/CodeGen/X86/unreachable-trap.ll new file mode 100644 index 00000000000..8de0510ed38 --- /dev/null +++ b/test/CodeGen/X86/unreachable-trap.ll @@ -0,0 +1,29 @@ +; RUN: llc -o - %s -mtriple=x86_64-windows-msvc | FileCheck %s --check-prefixes=CHECK,TRAP_AFTER_NORETURN +; RUN: llc -o - %s -mtriple=x86_64-apple-darwin | FileCheck %s --check-prefixes=CHECK,NO_TRAP_AFTER_NORETURN + +; CHECK-LABEL: call_exit: +; CHECK: callq {{_?}}exit +; TRAP_AFTER_NORETURN: ud2 +; NO_TRAP_AFTER_NORETURN-NOT: ud2 +define i32 @call_exit() noreturn nounwind { + tail call void @exit(i32 0) + unreachable +} + +; CHECK-LABEL: trap: +; CHECK: ud2 +; TRAP_AFTER_NORETURN: ud2 +; NO_TRAP_AFTER_NORETURN-NOT: ud2 +define i32 @trap() noreturn nounwind { + tail call void @llvm.trap() + unreachable +} + +; CHECK-LABEL: unreachable: +; CHECK: ud2 +define i32 @unreachable() noreturn nounwind { + unreachable +} + +declare void @llvm.trap() nounwind noreturn +declare void @exit(i32 %rc) nounwind noreturn