diff --git a/llvm/include/llvm/IR/Instructions.h b/llvm/include/llvm/IR/Instructions.h index a1f964352207f..9a4fb2985264b 100644 --- a/llvm/include/llvm/IR/Instructions.h +++ b/llvm/include/llvm/IR/Instructions.h @@ -4497,6 +4497,9 @@ class UnreachableInst : public Instruction { return isa(V) && classof(cast(V)); } + // Whether to do target lowering in SelectionDAG. + bool shouldLowerToTrap(bool TrapUnreachable, bool NoTrapAfterNoreturn) const; + private: BasicBlock *getSuccessor(unsigned idx) const { llvm_unreachable("UnreachableInst has no successors!"); diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp index 6014f57d439f0..f8afb42bf5535 100644 --- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp +++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -3143,21 +3143,12 @@ bool IRTranslator::translateVAArg(const User &U, MachineIRBuilder &MIRBuilder) { return true; } -bool IRTranslator::translateUnreachable(const User &U, MachineIRBuilder &MIRBuilder) { - if (!MF->getTarget().Options.TrapUnreachable) - return true; - +bool IRTranslator::translateUnreachable(const User &U, + MachineIRBuilder &MIRBuilder) { auto &UI = cast(U); - - // We may be able to ignore unreachable behind a noreturn call. - if (const CallInst *Call = dyn_cast_or_null(UI.getPrevNode()); - Call && Call->doesNotReturn()) { - if (MF->getTarget().Options.NoTrapAfterNoreturn) - return true; - // Do not emit an additional trap instruction. - if (Call->isNonContinuableTrap()) - return true; - } + if (!UI.shouldLowerToTrap(MF->getTarget().Options.TrapUnreachable, + MF->getTarget().Options.NoTrapAfterNoreturn)) + return true; MIRBuilder.buildTrap(); return true; diff --git a/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp b/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp index 33dd039c4ab2a..fbc0264961bc7 100644 --- a/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp @@ -1854,17 +1854,12 @@ bool FastISel::selectOperator(const User *I, unsigned Opcode) { } case Instruction::Unreachable: { - if (TM.Options.TrapUnreachable) { - if (TM.Options.NoTrapAfterNoreturn) { - const auto *Call = - dyn_cast_or_null(cast(I)->getPrevNode()); - if (Call && Call->doesNotReturn()) - return true; - } + auto UI = cast(I); + if (!UI->shouldLowerToTrap(TM.Options.TrapUnreachable, + TM.Options.NoTrapAfterNoreturn)) + return true; - return fastEmit_(MVT::Other, MVT::Other, ISD::TRAP) != 0; - } - return true; + return fastEmit_(MVT::Other, MVT::Other, ISD::TRAP) != 0; } case Instruction::Alloca: diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index 14bb1d943d2d6..d076bc85f48d1 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -3501,19 +3501,10 @@ void SelectionDAGBuilder::visitIndirectBr(const IndirectBrInst &I) { } void SelectionDAGBuilder::visitUnreachable(const UnreachableInst &I) { - if (!DAG.getTarget().Options.TrapUnreachable) + if (!I.shouldLowerToTrap(DAG.getTarget().Options.TrapUnreachable, + DAG.getTarget().Options.NoTrapAfterNoreturn)) return; - // We may be able to ignore unreachable behind a noreturn call. - if (const CallInst *Call = dyn_cast_or_null(I.getPrevNode()); - Call && Call->doesNotReturn()) { - if (DAG.getTarget().Options.NoTrapAfterNoreturn) - return; - // Do not emit an additional trap instruction. - if (Call->isNonContinuableTrap()) - return; - } - DAG.setRoot(DAG.getNode(ISD::TRAP, getCurSDLoc(), MVT::Other, DAG.getRoot())); } diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp index d2cf0ae2c1778..18109bf107858 100644 --- a/llvm/lib/IR/Instructions.cpp +++ b/llvm/lib/IR/Instructions.cpp @@ -4529,6 +4529,27 @@ UnreachableInst *UnreachableInst::cloneImpl() const { return new UnreachableInst(Context); } +bool UnreachableInst::shouldLowerToTrap(bool TrapUnreachable, + bool NoTrapAfterNoreturn) const { + if (!TrapUnreachable) + return false; + + // We may be able to ignore unreachable behind a noreturn call. + if (const CallInst *Call = dyn_cast_or_null(getPrevNode()); + Call && Call->doesNotReturn()) { + if (NoTrapAfterNoreturn) + return false; + // Do not emit an additional trap instruction. + if (Call->isNonContinuableTrap()) + return false; + } + + if (getFunction()->hasFnAttribute(Attribute::Naked)) + return false; + + return true; +} + FreezeInst *FreezeInst::cloneImpl() const { return new FreezeInst(getOperand(0)); } diff --git a/llvm/test/CodeGen/WebAssembly/naked-fn-with-frame-pointer.ll b/llvm/test/CodeGen/WebAssembly/naked-fn-with-frame-pointer.ll index fcd42e8cbfb9f..d50cf0b201229 100644 --- a/llvm/test/CodeGen/WebAssembly/naked-fn-with-frame-pointer.ll +++ b/llvm/test/CodeGen/WebAssembly/naked-fn-with-frame-pointer.ll @@ -9,13 +9,11 @@ define dso_local void @naked() naked "frame-pointer"="all" { ; CHECK-32: .functype naked () -> () ; CHECK-32-NEXT: # %bb.0: ; CHECK-32-NEXT: call main -; CHECK-32-NEXT: unreachable ; ; CHECK-64-LABEL: naked: ; CHECK-64: .functype naked () -> () ; CHECK-64-NEXT: # %bb.0: ; CHECK-64-NEXT: call main -; CHECK-64-NEXT: unreachable call void @main() unreachable } diff --git a/llvm/test/CodeGen/X86/naked-fn-with-unreachable-trap.ll b/llvm/test/CodeGen/X86/naked-fn-with-unreachable-trap.ll new file mode 100644 index 0000000000000..94274fcb1c160 --- /dev/null +++ b/llvm/test/CodeGen/X86/naked-fn-with-unreachable-trap.ll @@ -0,0 +1,11 @@ +; RUN: llc -o - %s -mtriple=x86_64-linux-gnu -trap-unreachable | FileCheck %s +; RUN: llc -o - %s -mtriple=x86_64-linux-gnu -trap-unreachable -fast-isel | FileCheck %s + +define dso_local void @foo() #0 { +entry: + tail call void asm sideeffect "movl 3,%eax", "~{dirflag},~{fpsr},~{flags}"() + unreachable +} +; CHECK-NOT: ud2 + +attributes #0 = { naked }