Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions llvm/include/llvm/IR/Instructions.h
Original file line number Diff line number Diff line change
Expand Up @@ -4497,6 +4497,9 @@ class UnreachableInst : public Instruction {
return isa<Instruction>(V) && classof(cast<Instruction>(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!");
Expand Down
19 changes: 5 additions & 14 deletions llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<UnreachableInst>(U);

// We may be able to ignore unreachable behind a noreturn call.
if (const CallInst *Call = dyn_cast_or_null<CallInst>(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;
Expand Down
15 changes: 5 additions & 10 deletions llvm/lib/CodeGen/SelectionDAG/FastISel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<CallInst>(cast<Instruction>(I)->getPrevNode());
if (Call && Call->doesNotReturn())
return true;
}
auto UI = cast<UnreachableInst>(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:
Expand Down
13 changes: 2 additions & 11 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<CallInst>(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()));
}

Expand Down
21 changes: 21 additions & 0 deletions llvm/lib/IR/Instructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<CallInst>(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));
}
2 changes: 0 additions & 2 deletions llvm/test/CodeGen/WebAssembly/naked-fn-with-frame-pointer.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
11 changes: 11 additions & 0 deletions llvm/test/CodeGen/X86/naked-fn-with-unreachable-trap.ll
Original file line number Diff line number Diff line change
@@ -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 }