Index: include/llvm/Target/TargetLowering.h =================================================================== --- include/llvm/Target/TargetLowering.h +++ include/llvm/Target/TargetLowering.h @@ -2520,7 +2520,10 @@ RetTy = ResultType; IsInReg = Call.paramHasAttr(0, Attribute::InReg); - DoesNotReturn = Call.doesNotReturn(); + DoesNotReturn = + Call.doesNotReturn() || + (!Call.isInvoke() && + isa(Call.getInstruction()->getNextNode())); IsVarArg = FTy->isVarArg(); IsReturnValueUsed = !Call.getInstruction()->use_empty(); RetSExt = Call.paramHasAttr(0, Attribute::SExt); Index: lib/Target/X86/X86ISelLowering.cpp =================================================================== --- lib/Target/X86/X86ISelLowering.cpp +++ lib/Target/X86/X86ISelLowering.cpp @@ -3381,6 +3381,12 @@ else NumBytesForCalleeToPop = 0; // Callee pops nothing. + if (CLI.DoesNotReturn && !getTargetMachine().Options.TrapUnreachable) { + // No need to reset the stack after the call if the call doesn't return. To + // make the MI verify, we'll pretend the callee does it for us. + NumBytesForCalleeToPop = NumBytes; + } + // Returns a flag for retval copy to use. if (!IsSibcall) { Chain = DAG.getCALLSEQ_END(Chain, Index: test/CodeGen/X86/noreturn-call.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/noreturn-call.ll @@ -0,0 +1,48 @@ +; RUN: llc < %s -mtriple=i686-pc-win32 | FileCheck %s + +define void @test1(i32 %c) { +; CHECK-LABEL: test1: +entry: + %0 = alloca i8, i32 %c + %tobool = icmp eq i32 %c, 0 + br i1 %tobool, label %if.end, label %if.then + +if.end: + call void @g(i8* %0) + ret void + +if.then: + call void @crash(i8* %0) + unreachable +; CHECK: calll _crash +; There is no need to adjust the stack after the call, since +; the function is noreturn and that code will therefore never run. +; CHECK-NOT: add +; CHECK-NOT: pop +} + +define void @test2(i32 %c) { +; CHECK-LABEL: test2: +entry: + %0 = alloca i8, i32 %c + %tobool = icmp eq i32 %c, 0 + br i1 %tobool, label %if.end, label %if.then + +if.end: + call void @g(i8* %0) + ret void + +if.then: + call void @crash2(i8* %0) + unreachable +; CHECK: calll _crash2 +; Even though _crash2 is not marked noreturn, it is in practice because +; of the "unreachable" right after it. This happens e.g. when falling off +; a non-void function after a call. +; CHECK-NOT: add +; CHECK-NOT: pop +} + +declare void @crash(i8*) noreturn +declare void @crash2(i8*) +declare void @g(i8*)