diff --git a/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp b/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp --- a/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp +++ b/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp @@ -472,6 +472,9 @@ if (isKernelFunction(*F)) emitKernelFunctionDirectives(*F, O); + if (shouldEmitPTXNoReturn(F, TM)) + O << ".noreturn"; + OutStreamer->emitRawText(O.str()); VRegMapping.clear(); @@ -615,6 +618,8 @@ getSymbol(F)->print(O, MAI); O << "\n"; emitFunctionParamList(F, O); + if (shouldEmitPTXNoReturn(F, TM)) + O << ".noreturn"; O << ";\n"; } diff --git a/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp b/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp --- a/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp +++ b/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp @@ -1430,7 +1430,10 @@ if (VAInfo) O << (first ? "" : ",") << " .param .align " << VAInfo->second << " .b8 _[]\n"; - O << ");"; + O << ")"; + if (shouldEmitPTXNoReturn(&CB, *nvTM)) + O << " .noreturn"; + O << ";"; return Prototype; } diff --git a/llvm/lib/Target/NVPTX/NVPTXSubtarget.h b/llvm/lib/Target/NVPTX/NVPTXSubtarget.h --- a/llvm/lib/Target/NVPTX/NVPTXSubtarget.h +++ b/llvm/lib/Target/NVPTX/NVPTXSubtarget.h @@ -78,6 +78,7 @@ bool hasFP16Math() const { return SmVersion >= 53; } bool allowFP16Math() const; bool hasMaskOperator() const { return PTXVersion >= 71; } + bool hasNoReturn() const { return SmVersion >= 30 && PTXVersion >= 64; } unsigned int getSmVersion() const { return SmVersion; } std::string getTargetName() const { return TargetName; } diff --git a/llvm/lib/Target/NVPTX/NVPTXUtilities.h b/llvm/lib/Target/NVPTX/NVPTXUtilities.h --- a/llvm/lib/Target/NVPTX/NVPTXUtilities.h +++ b/llvm/lib/Target/NVPTX/NVPTXUtilities.h @@ -24,6 +24,8 @@ namespace llvm { +class TargetMachine; + void clearAnnotationCache(const Module *); bool findOneNVVMAnnotation(const GlobalValue *, const std::string &, @@ -70,6 +72,8 @@ else return size; } + +bool shouldEmitPTXNoReturn(const Value *V, const TargetMachine &TM); } #endif diff --git a/llvm/lib/Target/NVPTX/NVPTXUtilities.cpp b/llvm/lib/Target/NVPTX/NVPTXUtilities.cpp --- a/llvm/lib/Target/NVPTX/NVPTXUtilities.cpp +++ b/llvm/lib/Target/NVPTX/NVPTXUtilities.cpp @@ -12,6 +12,7 @@ #include "NVPTXUtilities.h" #include "NVPTX.h" +#include "NVPTXTargetMachine.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalVariable.h" @@ -328,4 +329,23 @@ return dyn_cast(CB->getCalledOperand()->stripPointerCasts()); } +bool shouldEmitPTXNoReturn(const Value *V, const TargetMachine &TM) { + const auto &ST = + *static_cast(TM).getSubtargetImpl(); + if (!ST.hasNoReturn()) + return false; + + assert((isa(V) || isa(V)) && + "Expect either a call instruction or a function"); + + if (const CallInst *CallI = dyn_cast(V)) + return CallI->doesNotReturn() && + CallI->getFunctionType()->getReturnType()->isVoidTy(); + + const Function *F = cast(V); + return F->doesNotReturn() && + F->getFunctionType()->getReturnType()->isVoidTy() && + !isKernelFunction(*F); +} + } // namespace llvm diff --git a/llvm/test/CodeGen/NVPTX/noreturn.ll b/llvm/test/CodeGen/NVPTX/noreturn.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/NVPTX/noreturn.ll @@ -0,0 +1,51 @@ +; RUN: llc < %s -march=nvptx64 -mattr=+ptx64 -mcpu=sm_30 | FileCheck %s +; RUN: %if ptxas %{llc < %s -march=nvptx64 -mattr=+ptx60 -mcpu=sm_30 | %ptxas-verify %} + +@function_pointer = addrspace(1) global void (i32)* null + +; CHECK: .func trap_wrapper +; CHECK-NEXT: () +; CHECK-NEXT: .noreturn; + +declare void @trap_wrapper() #0 + +; CHECK: .func {{.*}} non_void_noreturn() +; CHECK-NOT: .noreturn + +define i32 @non_void_noreturn() #0 { + ret i32 54 +} + +; CHECK: .func true_noreturn0() +; CHECK-NEXT: .noreturn + +define void @true_noreturn0() #0 { + call void @trap_wrapper() + ret void +} + +; CHECK: .entry ignore_kernel_noreturn() +; CHECK-NOT: .noreturn + +define void @ignore_kernel_noreturn() #0 { + unreachable +} + +; CHECK-LABEL: .entry callprototype_noreturn( +; CHECK: prototype_{{[0-9]+}} : .callprototype ()_ (.param .b32 _) .noreturn; +; CHECK: prototype_{{[0-9]+}} : .callprototype (.param .b32 _) _ (.param .b32 _); + +define void @callprototype_noreturn(i32) { + %fn = load void (i32)*, void (i32)* addrspace(1)* @function_pointer + call void %fn(i32 %0) #0 + %non_void = bitcast void (i32)* %fn to i32 (i32)* + %2 = call i32 %non_void(i32 %0) #0 + ret void +} + +attributes #0 = { noreturn } + +!nvvm.annotations = !{!0, !1} + +!0 = !{void ()* @ignore_kernel_noreturn, !"kernel", i32 1} +!1 = !{void (i32)* @callprototype_noreturn, !"kernel", i32 1}