From b395721a9de9b533d39b34be73adaee0ef50cde9 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Wed, 19 Mar 2025 14:25:16 -0700 Subject: [PATCH] [SelectionDAG] Not issue TRAP node if naked function In [1], Nikita Popov suggested that during lowering 'unreachable' insn should not generate extra code for naked functions, and this applies to all architectures. Note that for naked functions, 'unreachable' insn is necessary in IR since the basic block needs a terminator to end. This patch checked whether a function is naked function or not. If it is a naked function, 'unreachable' insn will not generate ISD::TRAP. [1] https://github.com/llvm/llvm-project/pull/131731 --- llvm/include/llvm/IR/Instructions.h | 3 +++ llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp | 19 +++++------------ llvm/lib/CodeGen/SelectionDAG/FastISel.cpp | 15 +++++-------- .../SelectionDAG/SelectionDAGBuilder.cpp | 13 ++---------- llvm/lib/IR/Instructions.cpp | 21 +++++++++++++++++++ .../naked-fn-with-frame-pointer.ll | 2 -- .../X86/naked-fn-with-unreachable-trap.ll | 11 ++++++++++ 7 files changed, 47 insertions(+), 37 deletions(-) create mode 100644 llvm/test/CodeGen/X86/naked-fn-with-unreachable-trap.ll 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 }