https://github.com/erichkeane created https://github.com/llvm/llvm-project/pull/177978
This mirrors what LLVM does, and requires propagating into the LLVM dialect: When the user specifies 'noreturn' we propagate this down throughout the stack. Note the similar 'willreturn' is too strong of a guarantee (in that they are not opposites of each other, as there is a 'unknown' implied by all others), so we cannot use that on non-noreturn functions. >From e923db15e33e28a80a19270a868e4e73bcf3d7ef Mon Sep 17 00:00:00 2001 From: erichkeane <[email protected]> Date: Tue, 20 Jan 2026 08:31:54 -0800 Subject: [PATCH] [CIR] Implement 'noreturn' attribute for functions/calls. This mirrors what LLVM does, and requires propagating into the LLVM dialect: When the user specifies 'noreturn' we propagate this down throughout the stack. Note the similar 'willreturn' is too strong of a guarantee (in that they are not opposites of each other, as there is a 'unknown' implied by all others), so we cannot use that on non-noreturn functions. --- .../clang/CIR/Dialect/IR/CIRDialect.td | 1 + clang/lib/CIR/CodeGen/CIRGenCall.cpp | 48 +++++++++++++++--- clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h | 26 ++++++++-- clang/lib/CIR/CodeGen/CIRGenTypes.cpp | 11 ++--- clang/lib/CIR/CodeGen/CIRGenTypes.h | 2 +- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 13 ++++- clang/test/CIR/CodeGen/noreturn.cpp | 49 +++++++++++++++++++ .../test/CIR/CodeGenBuiltins/builtin_call.cpp | 2 +- mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td | 2 + mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp | 4 ++ .../LLVMIR/LLVMToLLVMIRTranslation.cpp | 2 + mlir/lib/Target/LLVMIR/ModuleImport.cpp | 1 + mlir/lib/Target/LLVMIR/ModuleTranslation.cpp | 2 + 13 files changed, 141 insertions(+), 22 deletions(-) create mode 100644 clang/test/CIR/CodeGen/noreturn.cpp diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td index 7c38492544b39..058f096bfae3b 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td @@ -39,6 +39,7 @@ def CIR_Dialect : Dialect { static llvm::StringRef getOptInfoAttrName() { return "cir.opt_info"; } static llvm::StringRef getCalleeAttrName() { return "callee"; } static llvm::StringRef getNoThrowAttrName() { return "nothrow"; } + static llvm::StringRef getNoReturnAttrName() { return "no_return"; } static llvm::StringRef getSideEffectAttrName() { return "side_effect"; } static llvm::StringRef getModuleLevelAsmAttrName() { return "cir.module_asm"; } static llvm::StringRef getGlobalCtorsAttrName() { return "cir.global_ctors"; } diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp index 5fd11c6d97c07..628f39ae2cfba 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp @@ -21,7 +21,7 @@ using namespace clang; using namespace clang::CIRGen; CIRGenFunctionInfo * -CIRGenFunctionInfo::create(CanQualType resultType, +CIRGenFunctionInfo::create(FunctionType::ExtInfo info, CanQualType resultType, llvm::ArrayRef<CanQualType> argTypes, RequiredArgs required) { // The first slot allocated for arg type slot is for the return value. @@ -32,6 +32,8 @@ CIRGenFunctionInfo::create(CanQualType resultType, CIRGenFunctionInfo *fi = new (buffer) CIRGenFunctionInfo(); + fi->noReturn = info.getNoReturn(); + fi->required = required; fi->numArgs = argTypes.size(); @@ -120,6 +122,11 @@ void CIRGenModule::constructAttributeList(llvm::StringRef name, assert(!cir::MissingFeatures::opCallCallConv()); sideEffect = cir::SideEffect::All; + if (info.isNoReturn()) + attrs.set(cir::CIRDialect::getNoReturnAttrName(), + mlir::UnitAttr::get(&getMLIRContext())); + // TODO(cir): Check/add cmse_nonsecure_call attribute here. + addAttributesFromFunctionProtoType(getBuilder(), attrs, calleeInfo.getCalleeFunctionProtoType()); @@ -129,11 +136,30 @@ void CIRGenModule::constructAttributeList(llvm::StringRef name, if (targetDecl->hasAttr<NoThrowAttr>()) attrs.set(cir::CIRDialect::getNoThrowAttrName(), mlir::UnitAttr::get(&getMLIRContext())); + // TODO(cir): This is actually only possible if targetDecl isn't a + // declarator, which ObjCMethodDecl seems to be the only way to get this to + // happen. We're including it here for completeness, but we should add a + // test for this when we start generating ObjectiveC. + if (targetDecl->hasAttr<NoReturnAttr>()) + attrs.set(cir::CIRDialect::getNoReturnAttrName(), + mlir::UnitAttr::get(&getMLIRContext())); if (const FunctionDecl *func = dyn_cast<FunctionDecl>(targetDecl)) { addAttributesFromFunctionProtoType( getBuilder(), attrs, func->getType()->getAs<FunctionProtoType>()); assert(!cir::MissingFeatures::opCallAttrs()); + + const CXXMethodDecl *md = dyn_cast<CXXMethodDecl>(func); + bool isVirtualCall = md && md->isVirtual(); + + // Don't use [[noreturn]], _Noreturn or [[no_builtin]] for a call to a + // virtual function. These attributes are not inherited by overloads. + if (!(attrOnCallSite && isVirtualCall)) { + if (func->isNoReturn()) + attrs.set(cir::CIRDialect::getNoReturnAttrName(), + mlir::UnitAttr::get(&getMLIRContext())); + // TODO(cir): Set NoBuiltinAttr here. + } } assert(!cir::MissingFeatures::opCallAttrs()); @@ -222,7 +248,8 @@ CIRGenTypes::arrangeCXXStructorDeclaration(GlobalDecl gd) { assert(!cir::MissingFeatures::opCallCIRGenFuncInfoExtParamInfo()); assert(!cir::MissingFeatures::opCallFnInfoOpts()); - return arrangeCIRFunctionInfo(resultType, argTypes, required); + return arrangeCIRFunctionInfo(fpt->getExtInfo(), resultType, argTypes, + required); } /// Derives the 'this' type for CIRGen purposes, i.e. ignoring method CVR @@ -259,7 +286,8 @@ arrangeCIRFunctionInfo(CIRGenTypes &cgt, SmallVectorImpl<CanQualType> &prefix, assert(!cir::MissingFeatures::opCallExtParameterInfo()); appendParameterTypes(cgt, prefix, fpt); CanQualType resultType = fpt->getReturnType().getUnqualifiedType(); - return cgt.arrangeCIRFunctionInfo(resultType, prefix, required); + return cgt.arrangeCIRFunctionInfo(fpt->getExtInfo(), resultType, prefix, + required); } void CIRGenFunction::emitDelegateCallArg(CallArgList &args, @@ -325,7 +353,8 @@ arrangeFreeFunctionLikeCall(CIRGenTypes &cgt, CIRGenModule &cgm, CanQualType retType = fnType->getReturnType()->getCanonicalTypeUnqualified(); assert(!cir::MissingFeatures::opCallFnInfoOpts()); - return cgt.arrangeCIRFunctionInfo(retType, argTypes, required); + return cgt.arrangeCIRFunctionInfo(fnType->getExtInfo(), retType, argTypes, + required); } /// Arrange a call to a C++ method, passing the given arguments. @@ -364,7 +393,8 @@ const CIRGenFunctionInfo &CIRGenTypes::arrangeCXXConstructorCall( assert(!cir::MissingFeatures::opCallFnInfoOpts()); assert(!cir::MissingFeatures::opCallCIRGenFuncInfoExtParamInfo()); - return arrangeCIRFunctionInfo(resultType, argTypes, required); + return arrangeCIRFunctionInfo(fpt->getExtInfo(), resultType, argTypes, + required); } /// Arrange a call to a C++ method, passing the given arguments. @@ -385,6 +415,7 @@ const CIRGenFunctionInfo &CIRGenTypes::arrangeCXXMethodCall( assert(!cir::MissingFeatures::opCallFnInfoOpts()); return arrangeCIRFunctionInfo( + proto->getExtInfo(), proto->getReturnType()->getCanonicalTypeUnqualified(), argTypes, required); } @@ -456,8 +487,8 @@ CIRGenTypes::arrangeFunctionDeclaration(const FunctionDecl *fd) { funcTy.getAs<FunctionNoProtoType>()) { assert(!cir::MissingFeatures::opCallCIRGenFuncInfoExtParamInfo()); assert(!cir::MissingFeatures::opCallFnInfoOpts()); - return arrangeCIRFunctionInfo(noProto->getReturnType(), {}, - RequiredArgs::All); + return arrangeCIRFunctionInfo( + noProto->getExtInfo(), noProto->getReturnType(), {}, RequiredArgs::All); } return arrangeFreeFunctionType(funcTy.castAs<FunctionProtoType>()); @@ -535,7 +566,8 @@ const CIRGenFunctionInfo & CIRGenTypes::arrangeFreeFunctionType(CanQual<FunctionNoProtoType> fnpt) { CanQualType resultType = fnpt->getReturnType().getUnqualifiedType(); assert(!cir::MissingFeatures::opCallFnInfoOpts()); - return arrangeCIRFunctionInfo(resultType, {}, RequiredArgs(0)); + return arrangeCIRFunctionInfo(fnpt->getExtInfo(), resultType, {}, + RequiredArgs(0)); } RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo, diff --git a/clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h b/clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h index 4f5754cb43986..fb7da9e414139 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h @@ -72,6 +72,10 @@ class RequiredArgs { class CIRGenFunctionInfo final : public llvm::FoldingSetNode, private llvm::TrailingObjects<CIRGenFunctionInfo, CanQualType> { + // Whether this function has noreturn. + LLVM_PREFERRED_TYPE(bool) + unsigned noReturn : 1; + RequiredArgs required; unsigned numArgs; @@ -81,8 +85,19 @@ class CIRGenFunctionInfo final CIRGenFunctionInfo() : required(RequiredArgs::All) {} + FunctionType::ExtInfo getExtInfo() const { + // TODO(cir): as we add this information to this type, we need to add calls + // here instead of explicit false/0. + return FunctionType::ExtInfo( + isNoReturn(), /*getHasRegParm=*/false, /*getRegParm=*/false, + /*getASTCallingConvention=*/CallingConv(0), /*isReturnsRetained=*/false, + /*isNoCallerSavedRegs=*/false, /*isNoCfCheck=*/false, + /*isCmseNSCall=*/false); + } + public: - static CIRGenFunctionInfo *create(CanQualType resultType, + static CIRGenFunctionInfo *create(FunctionType::ExtInfo info, + CanQualType resultType, llvm::ArrayRef<CanQualType> argTypes, RequiredArgs required); @@ -97,9 +112,10 @@ class CIRGenFunctionInfo final // This function has to be CamelCase because llvm::FoldingSet requires so. // NOLINTNEXTLINE(readability-identifier-naming) - static void Profile(llvm::FoldingSetNodeID &id, RequiredArgs required, - CanQualType resultType, + static void Profile(llvm::FoldingSetNodeID &id, FunctionType::ExtInfo info, + RequiredArgs required, CanQualType resultType, llvm::ArrayRef<CanQualType> argTypes) { + id.AddBoolean(info.getNoReturn()); id.AddBoolean(required.getOpaqueData()); resultType.Profile(id); for (const CanQualType &arg : argTypes) @@ -111,7 +127,7 @@ class CIRGenFunctionInfo final // If the Profile functions get out of sync, we can end up with incorrect // function signatures, so we call the static Profile function here rather // than duplicating the logic. - Profile(id, required, getReturnType(), arguments()); + Profile(id, getExtInfo(), required, getReturnType(), arguments()); } llvm::ArrayRef<CanQualType> arguments() const { @@ -144,6 +160,8 @@ class CIRGenFunctionInfo final return isVariadic() ? getRequiredArgs().getNumRequiredArgs() : argTypeSize(); } + + bool isNoReturn() const { return noReturn; } }; } // namespace clang::CIRGen diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp index 610ee2ceb1da4..1b0aad37569c4 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp @@ -662,15 +662,14 @@ bool CIRGenTypes::isZeroInitializable(const RecordDecl *rd) { return getCIRGenRecordLayout(rd).isZeroInitializable(); } -const CIRGenFunctionInfo & -CIRGenTypes::arrangeCIRFunctionInfo(CanQualType returnType, - llvm::ArrayRef<CanQualType> argTypes, - RequiredArgs required) { +const CIRGenFunctionInfo &CIRGenTypes::arrangeCIRFunctionInfo( + FunctionType::ExtInfo info, CanQualType returnType, + llvm::ArrayRef<CanQualType> argTypes, RequiredArgs required) { assert(llvm::all_of(argTypes, [](CanQualType t) { return t.isCanonicalAsParam(); })); // Lookup or create unique function info. llvm::FoldingSetNodeID id; - CIRGenFunctionInfo::Profile(id, required, returnType, argTypes); + CIRGenFunctionInfo::Profile(id, info, required, returnType, argTypes); void *insertPos = nullptr; CIRGenFunctionInfo *fi = functionInfos.FindNodeOrInsertPos(id, insertPos); @@ -687,7 +686,7 @@ CIRGenTypes::arrangeCIRFunctionInfo(CanQualType returnType, assert(!cir::MissingFeatures::opCallCallConv()); // Construction the function info. We co-allocate the ArgInfos. - fi = CIRGenFunctionInfo::create(returnType, argTypes, required); + fi = CIRGenFunctionInfo::create(info, returnType, argTypes, required); functionInfos.InsertNode(fi, insertPos); return *fi; diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.h b/clang/lib/CIR/CodeGen/CIRGenTypes.h index e79cdfc9f8224..bbc594c8656da 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTypes.h +++ b/clang/lib/CIR/CodeGen/CIRGenTypes.h @@ -197,7 +197,7 @@ class CIRGenTypes { const FunctionType *fnType); const CIRGenFunctionInfo & - arrangeCIRFunctionInfo(CanQualType returnType, + arrangeCIRFunctionInfo(FunctionType::ExtInfo info, CanQualType returnType, llvm::ArrayRef<CanQualType> argTypes, RequiredArgs required); diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 4877508b1c3da..20bfb6c3153e1 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -310,7 +310,8 @@ mlir::Value lowerCirAttrAsValue(mlir::Operation *parentOp, void convertSideEffectForCall(mlir::Operation *callOp, bool isNothrow, cir::SideEffect sideEffect, mlir::LLVM::MemoryEffectsAttr &memoryEffect, - bool &noUnwind, bool &willReturn) { + bool &noUnwind, bool &willReturn, + bool &noReturn) { using mlir::LLVM::ModRefInfo; switch (sideEffect) { @@ -344,6 +345,8 @@ void convertSideEffectForCall(mlir::Operation *callOp, bool isNothrow, willReturn = true; break; } + + noReturn = callOp->hasAttr(CIRDialect::getNoReturnAttrName()); } static mlir::LLVM::CallIntrinsicOp @@ -1620,8 +1623,9 @@ rewriteCallOrInvoke(mlir::Operation *op, mlir::ValueRange callOperands, mlir::LLVM::MemoryEffectsAttr memoryEffects; bool noUnwind = false; bool willReturn = false; + bool noReturn = false; convertSideEffectForCall(op, call.getNothrow(), call.getSideEffect(), - memoryEffects, noUnwind, willReturn); + memoryEffects, noUnwind, willReturn, noReturn); mlir::LLVM::LLVMFunctionType llvmFnTy; @@ -1684,6 +1688,7 @@ rewriteCallOrInvoke(mlir::Operation *op, mlir::ValueRange callOperands, newOp.setMemoryEffectsAttr(memoryEffects); newOp.setNoUnwind(noUnwind); newOp.setWillReturn(willReturn); + newOp.setNoReturn(noReturn); return mlir::success(); } @@ -2036,6 +2041,7 @@ void CIRToLLVMFuncOpLowering::lowerFuncAttributes( attr.getName() == func.getDsoLocalAttrName() || attr.getName() == func.getInlineKindAttrName() || attr.getName() == func.getSideEffectAttrName() || + attr.getName() == CIRDialect::getNoReturnAttrName() || (filterArgAndResAttrs && (attr.getName() == func.getArgAttrsAttrName() || attr.getName() == func.getResAttrsAttrName()))) @@ -2151,6 +2157,9 @@ mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewrite( } } + if (op->hasAttr(CIRDialect::getNoReturnAttrName())) + fn.setNoReturn(true); + if (std::optional<cir::InlineKind> inlineKind = op.getInlineKind()) { fn.setNoInline(*inlineKind == cir::InlineKind::NoInline); fn.setInlineHint(*inlineKind == cir::InlineKind::InlineHint); diff --git a/clang/test/CIR/CodeGen/noreturn.cpp b/clang/test/CIR/CodeGen/noreturn.cpp new file mode 100644 index 0000000000000..ddb9e25802ddb --- /dev/null +++ b/clang/test/CIR/CodeGen/noreturn.cpp @@ -0,0 +1,49 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG + +extern "C" { +// CIR: cir.func {{.*}} @bar() -> !s32i attributes {no_return} { +// LLVM: Function Attrs:{{.*}} noreturn +// LLVM-NEXT: define {{.*}} i32 @bar() #[[BAR_FOO_ATTR:.*]] { +// OGCG: Function Attrs:{{.*}} noreturn +// OGCG-NEXT: define {{.*}} i32 @bar() #[[BAR_FOO_ATTR:.*]] { +__attribute((noreturn)) +int bar() { } + +// Note: Classic codegen puts this here, so we need this to make sure the +// FunctionAttrs from `trap` doesn't interfere with 'foo'. However, CIR->LLVM +// lowering puts the trap decl at the end, so it isn't here to worry about. +// OGCG: declare void @llvm.trap + +// CIR: cir.func {{.*}} @foo() -> !s32i attributes {no_return} { +// LLVM: Function Attrs:{{.*}} noreturn +// LLVM-NEXT: define {{.*}} i32 @foo() #[[BAR_FOO_ATTR:.*]] { +// OGCG: Function Attrs:{{.*}} noreturn +// OGCG-NEXT: define {{.*}} i32 @foo() #[[BAR_FOO_ATTR:.*]] { +[[noreturn]] +int foo() { } + +void caller() { + // CIR: cir.call @bar() {no_return} : () -> !s32i + // LLVM: call i32 @bar() #[[CALL_ATTR:.*]] + // OGCG: call i32 @bar() #[[CALL_ATTR:.*]] + bar(); +} + +void caller2() { + // CIR: cir.call @foo() {no_return} : () -> !s32i + // LLVM: call i32 @foo() #[[CALL_ATTR:.*]] + // OGCG: call i32 @foo() #[[CALL_ATTR:.*]] + foo(); +} + +// LLVM: attributes #[[BAR_FOO_ATTR]] = {{.*}}noreturn +// OGCG: attributes #[[BAR_FOO_ATTR]] = {{.*}}noreturn +// LLVM: attributes #[[CALL_ATTR]] = {{.*}}noreturn +// OGCG: attributes #[[CALL_ATTR]] = {{.*}}noreturn + +} diff --git a/clang/test/CIR/CodeGenBuiltins/builtin_call.cpp b/clang/test/CIR/CodeGenBuiltins/builtin_call.cpp index a08a784951247..fc9e89b0ac486 100644 --- a/clang/test/CIR/CodeGenBuiltins/builtin_call.cpp +++ b/clang/test/CIR/CodeGenBuiltins/builtin_call.cpp @@ -85,7 +85,7 @@ void library_builtins() { // CIR: cir.func{{.*}} @_Z16library_builtinsv() // CIR: %[[NULL:.+]] = cir.const #cir.ptr<null> : !cir.ptr<!s8i> // CIR: cir.call @printf(%[[NULL]]) nothrow : (!cir.ptr<!s8i>) -> !s32i -// CIR: cir.call @abort() nothrow : () -> () +// CIR: cir.call @abort() nothrow {no_return} : () -> () // LLVM: define{{.*}} void @_Z16library_builtinsv() // LLVM: call i32 (ptr, ...) @printf(ptr null) diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td index 6789ca22c3d5f..b8b31680df824 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td @@ -795,6 +795,7 @@ def LLVM_CallOp DefaultValuedAttr<TailCallKind, "TailCallKind::None">:$TailCallKind, OptionalAttr<LLVM_MemoryEffectsAttr>:$memory_effects, UnitAttr:$convergent, UnitAttr:$no_unwind, UnitAttr:$will_return, + UnitAttr:$no_return, VariadicOfVariadic<LLVM_Type, "op_bundle_sizes">:$op_bundle_operands, DenseI32ArrayAttr:$op_bundle_sizes, OptionalAttr<ArrayAttr>:$op_bundle_tags, @@ -1992,6 +1993,7 @@ def LLVM_LLVMFuncOp : LLVM_Op<"func", [ OptionalAttr<UnitAttr>:$inline_hint, OptionalAttr<UnitAttr>:$no_unwind, OptionalAttr<UnitAttr>:$will_return, + OptionalAttr<UnitAttr>:$no_return, OptionalAttr<UnitAttr>:$optimize_none, OptionalAttr<LLVM_VecTypeHintAttr>:$vec_type_hint, OptionalAttr<DenseI32ArrayAttr>:$work_group_size_hint, diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp index 91fbc53c5eb32..e0b751fc55664 100644 --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp @@ -995,6 +995,7 @@ void CallOp::build(OpBuilder &builder, OperationState &state, TypeRange results, /*CConv=*/nullptr, /*TailCallKind=*/nullptr, /*memory_effects=*/nullptr, /*convergent=*/nullptr, /*no_unwind=*/nullptr, /*will_return=*/nullptr, + /*no_return=*/nullptr, /*op_bundle_operands=*/{}, /*op_bundle_tags=*/{}, /*arg_attrs=*/nullptr, /*res_attrs=*/nullptr, /*access_groups=*/nullptr, /*alias_scopes=*/nullptr, @@ -1025,6 +1026,7 @@ void CallOp::build(OpBuilder &builder, OperationState &state, /*TailCallKind=*/nullptr, /*memory_effects=*/nullptr, /*convergent=*/nullptr, /*no_unwind=*/nullptr, /*will_return=*/nullptr, + /*no_return=*/nullptr, /*op_bundle_operands=*/{}, /*op_bundle_tags=*/{}, /*arg_attrs=*/nullptr, /*res_attrs=*/nullptr, /*access_groups=*/nullptr, @@ -1041,6 +1043,7 @@ void CallOp::build(OpBuilder &builder, OperationState &state, /*fastmathFlags=*/nullptr, /*CConv=*/nullptr, /*TailCallKind=*/nullptr, /*memory_effects=*/nullptr, /*convergent=*/nullptr, /*no_unwind=*/nullptr, /*will_return=*/nullptr, + /*no_return=*/nullptr, /*op_bundle_operands=*/{}, /*op_bundle_tags=*/{}, /*arg_attrs=*/nullptr, /*res_attrs=*/nullptr, /*access_groups=*/nullptr, /*alias_scopes=*/nullptr, @@ -1057,6 +1060,7 @@ void CallOp::build(OpBuilder &builder, OperationState &state, LLVMFuncOp func, /*fastmathFlags=*/nullptr, /*CConv=*/nullptr, /*TailCallKind=*/nullptr, /*memory_effects=*/nullptr, /*convergent=*/nullptr, /*no_unwind=*/nullptr, /*will_return=*/nullptr, + /*no_return=*/nullptr, /*op_bundle_operands=*/{}, /*op_bundle_tags=*/{}, /*access_groups=*/nullptr, /*alias_scopes=*/nullptr, /*arg_attrs=*/nullptr, /*res_attrs=*/nullptr, diff --git a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp index b6ea4ba6e4921..1f53cfe8ece27 100644 --- a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp @@ -421,6 +421,8 @@ convertOperationImpl(Operation &opInst, llvm::IRBuilderBase &builder, call->addFnAttr(llvm::Attribute::NoUnwind); if (callOp.getWillReturnAttr()) call->addFnAttr(llvm::Attribute::WillReturn); + if (callOp.getNoReturnAttr()) + call->addFnAttr(llvm::Attribute::NoReturn); if (callOp.getNoInlineAttr()) call->addFnAttr(llvm::Attribute::NoInline); if (callOp.getAlwaysInlineAttr()) diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp index cec968c02078d..dca3a36133748 100644 --- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp @@ -2673,6 +2673,7 @@ static constexpr std::array kExplicitLLVMFuncOpAttributes{ StringLiteral("uwtable"), StringLiteral("vscale_range"), StringLiteral("willreturn"), + StringLiteral("noreturn"), }; /// Converts LLVM attributes from `func` into MLIR attributes and adds them diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp index fad9bd6b78018..50beb1a2ec410 100644 --- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp @@ -1676,6 +1676,8 @@ static void convertFunctionAttributes(LLVMFuncOp func, llvmFunc->addFnAttr(llvm::Attribute::NoUnwind); if (func.getWillReturnAttr()) llvmFunc->addFnAttr(llvm::Attribute::WillReturn); + if (func.getNoReturnAttr()) + llvmFunc->addFnAttr(llvm::Attribute::NoReturn); if (TargetFeaturesAttr targetFeatAttr = func.getTargetFeaturesAttr()) llvmFunc->addFnAttr("target-features", targetFeatAttr.getFeaturesString()); if (FramePointerKindAttr fpAttr = func.getFramePointerAttr()) _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
