[clang] [mlir] [CIR] Implement returns_twice, cold, hot, noduplicate, convergent fun… (PR #178289)
Erich Keane via cfe-commits
cfe-commits at lists.llvm.org
Tue Jan 27 12:16:04 PST 2026
https://github.com/erichkeane created https://github.com/llvm/llvm-project/pull/178289
…c attrs
Continuing my quest to get most of the attributes completed, this patch implements 5 attributes for CIR/Clang CIR codegen.
4 of the 5 are also implemented in LLVM-MLIR, since 'convergent' was already there.
As a part of this, we also had to make sure that attributes were handled properly for Call operation lowering, like we do for function attributes.
>From 9a5c5cd4ee8d9e15422b15e32d3db1c956657e36 Mon Sep 17 00:00:00 2001
From: erichkeane <ekeane at nvidia.com>
Date: Fri, 23 Jan 2026 07:09:14 -0800
Subject: [PATCH] [CIR] Implement returns_twice, cold, hot, noduplicate,
convergent func attrs
Continuing my quest to get most of the attributes completed, this patch
implements 5 attributes for CIR/Clang CIR codegen.
4 of the 5 are also implemented in LLVM-MLIR, since 'convergent' was
already there.
As a part of this, we also had to make sure that attributes were handled
properly for Call operation lowering, like we do for function attributes.
---
.../clang/CIR/Dialect/IR/CIRDialect.td | 6 ++
clang/lib/CIR/CodeGen/CIRGenCall.cpp | 24 +++++--
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 20 ++++++
clang/test/CIR/CodeGen/misc-attrs.cpp | 63 +++++++++++++++++++
mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td | 7 ++-
mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp | 9 ++-
.../LLVMIR/LLVMToLLVMIRTranslation.cpp | 8 +++
mlir/lib/Target/LLVMIR/ModuleImport.cpp | 18 ++++++
mlir/lib/Target/LLVMIR/ModuleTranslation.cpp | 8 +++
mlir/test/Dialect/LLVMIR/func.mlir | 24 +++++++
mlir/test/Dialect/LLVMIR/roundtrip.mlir | 12 ++++
.../LLVMIR/Import/function-attributes.ll | 24 +++++++
.../test/Target/LLVMIR/Import/instructions.ll | 48 ++++++++++++++
mlir/test/Target/LLVMIR/llvmir.mlir | 44 +++++++++++++
14 files changed, 307 insertions(+), 8 deletions(-)
create mode 100644 clang/test/CIR/CodeGen/misc-attrs.cpp
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
index 47ca625c34816..31cebdde1aa64 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
@@ -41,6 +41,12 @@ def CIR_Dialect : Dialect {
static llvm::StringRef getNoThrowAttrName() { return "nothrow"; }
static llvm::StringRef getNoReturnAttrName() { return "noreturn"; }
static llvm::StringRef getSideEffectAttrName() { return "side_effect"; }
+ static llvm::StringRef getReturnsTwiceAttrName() { return "returns_twice"; }
+ static llvm::StringRef getColdAttrName() { return "cold"; }
+ static llvm::StringRef getHotAttrName() { return "hot"; }
+ static llvm::StringRef getNoDuplicatesAttrName() { return "noduplicate"; }
+ static llvm::StringRef getConvergentAttrName() { return "convergent"; }
+ static llvm::StringRef getNoUnwindAttrName() { return "nounwind"; }
static llvm::StringRef getModuleLevelAsmAttrName() { return "cir.module_asm"; }
static llvm::StringRef getGlobalCtorsAttrName() { return "cir.global_ctors"; }
static llvm::StringRef getGlobalDtorsAttrName() { return "cir.global_dtors"; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index a7680d3b9e823..83b1c4e78c4d6 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -122,9 +122,13 @@ void CIRGenModule::constructAttributeList(llvm::StringRef name,
assert(!cir::MissingFeatures::opCallCallConv());
sideEffect = cir::SideEffect::All;
+ auto addUnitAttr = [&](llvm::StringRef name) {
+ attrs.set(name, mlir::UnitAttr::get(&getMLIRContext()));
+ };
+
if (info.isNoReturn())
- attrs.set(cir::CIRDialect::getNoReturnAttrName(),
- mlir::UnitAttr::get(&getMLIRContext()));
+ addUnitAttr(cir::CIRDialect::getNoReturnAttrName());
+
// TODO(cir): Check/add cmse_nonsecure_call attribute here.
addAttributesFromFunctionProtoType(getBuilder(), attrs,
@@ -134,15 +138,23 @@ void CIRGenModule::constructAttributeList(llvm::StringRef name,
if (targetDecl) {
if (targetDecl->hasAttr<NoThrowAttr>())
- attrs.set(cir::CIRDialect::getNoThrowAttrName(),
- mlir::UnitAttr::get(&getMLIRContext()));
+ addUnitAttr(cir::CIRDialect::getNoThrowAttrName());
// 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()));
+ addUnitAttr(cir::CIRDialect::getNoReturnAttrName());
+ if (targetDecl->hasAttr<ReturnsTwiceAttr>())
+ addUnitAttr(cir::CIRDialect::getReturnsTwiceAttrName());
+ if (targetDecl->hasAttr<ColdAttr>())
+ addUnitAttr(cir::CIRDialect::getColdAttrName());
+ if (targetDecl->hasAttr<HotAttr>())
+ addUnitAttr(cir::CIRDialect::getHotAttrName());
+ if (targetDecl->hasAttr<NoDuplicateAttr>())
+ addUnitAttr(cir::CIRDialect::getNoDuplicatesAttrName());
+ if (targetDecl->hasAttr<ConvergentAttr>())
+ addUnitAttr(cir::CIRDialect::getConvergentAttrName());
if (const FunctionDecl *func = dyn_cast<FunctionDecl>(targetDecl)) {
addAttributesFromFunctionProtoType(
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 1894e92a485cd..091489c404642 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -1606,6 +1606,22 @@ mlir::LogicalResult CIRToLLVMRotateOpLowering::matchAndRewrite(
return mlir::LogicalResult::success();
}
+static void lowerCallAttributes(cir::CIRCallOpInterface op,
+ SmallVectorImpl<mlir::NamedAttribute> &result) {
+ for (mlir::NamedAttribute attr : op->getAttrs()) {
+ assert(!cir::MissingFeatures::opFuncCallingConv());
+ if (attr.getName() == CIRDialect::getCalleeAttrName() ||
+ attr.getName() == CIRDialect::getSideEffectAttrName() ||
+ attr.getName() == CIRDialect::getNoThrowAttrName() ||
+ attr.getName() == CIRDialect::getNoUnwindAttrName() ||
+ attr.getName() == CIRDialect::getNoReturnAttrName())
+ continue;
+
+ assert(!cir::MissingFeatures::opFuncExtraAttrs());
+ result.push_back(attr);
+ }
+}
+
static mlir::LogicalResult
rewriteCallOrInvoke(mlir::Operation *op, mlir::ValueRange callOperands,
mlir::ConversionPatternRewriter &rewriter,
@@ -1627,6 +1643,9 @@ rewriteCallOrInvoke(mlir::Operation *op, mlir::ValueRange callOperands,
convertSideEffectForCall(op, call.getNothrow(), call.getSideEffect(),
memoryEffects, noUnwind, willReturn, noReturn);
+ SmallVector<mlir::NamedAttribute, 4> attributes;
+ lowerCallAttributes(call, attributes);
+
mlir::LLVM::LLVMFunctionType llvmFnTy;
// Temporary to handle the case where we need to prepend an operand if the
@@ -1684,6 +1703,7 @@ rewriteCallOrInvoke(mlir::Operation *op, mlir::ValueRange callOperands,
auto newOp = rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
op, llvmFnTy, calleeAttr, callOperands);
+ newOp->setAttrs(attributes);
if (memoryEffects)
newOp.setMemoryEffectsAttr(memoryEffects);
newOp.setNoUnwind(noUnwind);
diff --git a/clang/test/CIR/CodeGen/misc-attrs.cpp b/clang/test/CIR/CodeGen/misc-attrs.cpp
new file mode 100644
index 0000000000000..837f99275c70d
--- /dev/null
+++ b/clang/test/CIR/CodeGen/misc-attrs.cpp
@@ -0,0 +1,63 @@
+// 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=LLVM
+
+extern "C" {
+ // CIR: cir.func{{.*}}@returns_twice() attributes {returns_twice} {
+ // LLVM: Function Attrs:{{.*}}returns_twice
+ // LLVM-NEXT: define{{.*}}@returns_twice() #[[RT_ATTR:.*]] {
+ __attribute__((returns_twice))
+ void returns_twice() {}
+ // CIR: cir.func{{.*}}@cold() attributes {cold} {
+ // LLVM: Function Attrs:{{.*}}cold
+ // LLVM-NEXT: define{{.*}}@cold() #[[COLD_ATTR:.*]] {
+ __attribute__((cold))
+ void cold() {}
+ // CIR: cir.func{{.*}}@hot() attributes {hot} {
+ // LLVM: Function Attrs:{{.*}}hot
+ // LLVM-NEXT: define{{.*}}@hot() #[[HOT_ATTR:.*]] {
+ __attribute__((hot))
+ void hot() {}
+ // CIR: cir.func{{.*}}@nodupes() attributes {noduplicate} {
+ // LLVM: Function Attrs:{{.*}}noduplicate
+ // LLVM-NEXT: define{{.*}}@nodupes() #[[ND_ATTR:.*]] {
+ __attribute__((noduplicate))
+ void nodupes() {}
+ // CIR: cir.func{{.*}}@convergent() attributes {convergent} {
+ // LLVM: Function Attrs:{{.*}}convergent
+ // LLVM-NEXT: define{{.*}}@convergent() #[[CONV_ATTR:.*]] {
+ __attribute__((convergent))
+ void convergent() {}
+
+ void caller() {
+ // CIR: cir.call @returns_twice() {returns_twice} : () -> ()
+ // LLVM: call void @returns_twice() #[[RT_CALL_ATTR:.*]]
+ returns_twice();
+ // CIR: cir.call @cold() {cold} : () -> ()
+ // LLVM: call void @cold() #[[COLD_CALL_ATTR:.*]]
+ cold();
+ // CIR: cir.call @hot() {hot} : () -> ()
+ // LLVM: call void @hot() #[[HOT_CALL_ATTR:.*]]
+ hot();
+ // CIR: cir.call @nodupes() {noduplicate} : () -> ()
+ // LLVM: call void @nodupes() #[[ND_CALL_ATTR:.*]]
+ nodupes();
+ // CIR: cir.call @convergent() {convergent} : () -> ()
+ // LLVM: call void @convergent() #[[CONV_CALL_ATTR:.*]]
+ convergent();
+ }
+}
+
+// LLVM: attributes #[[RT_ATTR]] = {{.*}}returns_twice
+// LLVM: attributes #[[COLD_ATTR]] = {{.*}}cold
+// LLVM: attributes #[[HOT_ATTR]] = {{.*}}hot
+// LLVM: attributes #[[ND_ATTR]] = {{.*}}noduplicate
+// LLVM: attributes #[[CONV_ATTR]] = {{.*}}convergent
+// LLVM: attributes #[[RT_CALL_ATTR]] = {{.*}}returns_twice
+// LLVM: attributes #[[COLD_CALL_ATTR]] = {{.*}}cold
+// LLVM: attributes #[[HOT_CALL_ATTR]] = {{.*}}hot
+// LLVM: attributes #[[ND_CALL_ATTR]] = {{.*}}noduplicate
+// LLVM: attributes #[[CONV_CALL_ATTR]] = {{.*}}convergent
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
index 390d5a1ea7dfe..f6f1c90b481c5 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
@@ -795,7 +795,8 @@ def LLVM_CallOp
DefaultValuedAttr<TailCallKind, "TailCallKind::None">:$TailCallKind,
OptionalAttr<LLVM_MemoryEffectsAttr>:$memory_effects,
UnitAttr:$convergent, UnitAttr:$no_unwind, UnitAttr:$will_return,
- UnitAttr:$noreturn,
+ UnitAttr:$noreturn, UnitAttr:$returns_twice, UnitAttr:$hot,
+ UnitAttr:$cold, UnitAttr:$noduplicate,
VariadicOfVariadic<LLVM_Type, "op_bundle_sizes">:$op_bundle_operands,
DenseI32ArrayAttr:$op_bundle_sizes,
OptionalAttr<ArrayAttr>:$op_bundle_tags,
@@ -1995,6 +1996,10 @@ def LLVM_LLVMFuncOp : LLVM_Op<"func", [
OptionalAttr<UnitAttr>:$will_return,
OptionalAttr<UnitAttr>:$noreturn,
OptionalAttr<UnitAttr>:$optimize_none,
+ OptionalAttr<UnitAttr>:$returns_twice,
+ OptionalAttr<UnitAttr>:$hot,
+ OptionalAttr<UnitAttr>:$cold,
+ OptionalAttr<UnitAttr>:$noduplicate,
OptionalAttr<LLVM_VecTypeHintAttr>:$vec_type_hint,
OptionalAttr<DenseI32ArrayAttr>:$work_group_size_hint,
OptionalAttr<DenseI32ArrayAttr>:$reqd_work_group_size,
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index d1c45bcb1656b..27d6355c9e221 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
@@ -995,7 +995,8 @@ void CallOp::build(OpBuilder &builder, OperationState &state, TypeRange results,
/*CConv=*/nullptr, /*TailCallKind=*/nullptr,
/*memory_effects=*/nullptr,
/*convergent=*/nullptr, /*no_unwind=*/nullptr, /*will_return=*/nullptr,
- /*noreturn=*/nullptr,
+ /*noreturn=*/nullptr, /*returns_twice=*/nullptr, /*hot=*/nullptr,
+ /*cold=*/nullptr, /*noduplicate=*/nullptr,
/*op_bundle_operands=*/{}, /*op_bundle_tags=*/{},
/*arg_attrs=*/nullptr, /*res_attrs=*/nullptr,
/*access_groups=*/nullptr, /*alias_scopes=*/nullptr,
@@ -1027,6 +1028,8 @@ void CallOp::build(OpBuilder &builder, OperationState &state,
/*convergent=*/nullptr,
/*no_unwind=*/nullptr, /*will_return=*/nullptr,
/*noreturn=*/nullptr,
+ /*returns_twice=*/nullptr, /*hot=*/nullptr,
+ /*cold=*/nullptr, /*noduplicate=*/nullptr,
/*op_bundle_operands=*/{}, /*op_bundle_tags=*/{},
/*arg_attrs=*/nullptr, /*res_attrs=*/nullptr,
/*access_groups=*/nullptr,
@@ -1044,6 +1047,8 @@ void CallOp::build(OpBuilder &builder, OperationState &state,
/*CConv=*/nullptr, /*TailCallKind=*/nullptr, /*memory_effects=*/nullptr,
/*convergent=*/nullptr, /*no_unwind=*/nullptr, /*will_return=*/nullptr,
/*noreturn=*/nullptr,
+ /*returns_twice=*/nullptr, /*hot=*/nullptr,
+ /*cold=*/nullptr, /*noduplicate=*/nullptr,
/*op_bundle_operands=*/{}, /*op_bundle_tags=*/{},
/*arg_attrs=*/nullptr, /*res_attrs=*/nullptr,
/*access_groups=*/nullptr, /*alias_scopes=*/nullptr,
@@ -1061,6 +1066,8 @@ void CallOp::build(OpBuilder &builder, OperationState &state, LLVMFuncOp func,
/*CConv=*/nullptr, /*TailCallKind=*/nullptr, /*memory_effects=*/nullptr,
/*convergent=*/nullptr, /*no_unwind=*/nullptr, /*will_return=*/nullptr,
/*noreturn=*/nullptr,
+ /*returns_twice=*/nullptr, /*hot=*/nullptr,
+ /*cold=*/nullptr, /*noduplicate=*/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 b1d7f3ab7b777..31636abfff27f 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
@@ -423,6 +423,14 @@ convertOperationImpl(Operation &opInst, llvm::IRBuilderBase &builder,
call->addFnAttr(llvm::Attribute::WillReturn);
if (callOp.getNoreturnAttr())
call->addFnAttr(llvm::Attribute::NoReturn);
+ if (callOp.getReturnsTwiceAttr())
+ call->addFnAttr(llvm::Attribute::ReturnsTwice);
+ if (callOp.getColdAttr())
+ call->addFnAttr(llvm::Attribute::Cold);
+ if (callOp.getHotAttr())
+ call->addFnAttr(llvm::Attribute::Hot);
+ if (callOp.getNoduplicateAttr())
+ call->addFnAttr(llvm::Attribute::NoDuplicate);
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 555e72bd77358..928e7a57ae24f 100644
--- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
@@ -2653,11 +2653,13 @@ static constexpr std::array kExplicitLLVMFuncOpAttributes{
StringLiteral("aarch64_pstate_sm_compatible"),
StringLiteral("aarch64_pstate_sm_enabled"),
StringLiteral("alwaysinline"),
+ StringLiteral("cold"),
StringLiteral("convergent"),
StringLiteral("denormal-fp-math"),
StringLiteral("denormal-fp-math-f32"),
StringLiteral("fp-contract"),
StringLiteral("frame-pointer"),
+ StringLiteral("hot"),
StringLiteral("inlinehint"),
StringLiteral("instrument-function-entry"),
StringLiteral("instrument-function-exit"),
@@ -2665,10 +2667,12 @@ static constexpr std::array kExplicitLLVMFuncOpAttributes{
StringLiteral("no-infs-fp-math"),
StringLiteral("no-nans-fp-math"),
StringLiteral("no-signed-zeros-fp-math"),
+ StringLiteral("noduplicate"),
StringLiteral("noinline"),
StringLiteral("noreturn"),
StringLiteral("nounwind"),
StringLiteral("optnone"),
+ StringLiteral("returns_twice"),
StringLiteral("target-features"),
StringLiteral("tune-cpu"),
StringLiteral("uwtable"),
@@ -2710,6 +2714,14 @@ void ModuleImport::processFunctionAttributes(llvm::Function *func,
funcOp.setWillReturn(true);
if (func->hasFnAttribute(llvm::Attribute::NoReturn))
funcOp.setNoreturn(true);
+ if (func->hasFnAttribute(llvm::Attribute::ReturnsTwice))
+ funcOp.setReturnsTwice(true);
+ if (func->hasFnAttribute(llvm::Attribute::Cold))
+ funcOp.setCold(true);
+ if (func->hasFnAttribute(llvm::Attribute::Hot))
+ funcOp.setHot(true);
+ if (func->hasFnAttribute(llvm::Attribute::NoDuplicate))
+ funcOp.setNoduplicate(true);
if (func->hasFnAttribute("aarch64_pstate_sm_enabled"))
funcOp.setArmStreaming(true);
@@ -2931,6 +2943,12 @@ LogicalResult ModuleImport::convertCallAttributes(llvm::CallInst *inst,
op.setNoUnwind(callAttrs.getFnAttr(llvm::Attribute::NoUnwind).isValid());
op.setWillReturn(callAttrs.getFnAttr(llvm::Attribute::WillReturn).isValid());
op.setNoreturn(callAttrs.getFnAttr(llvm::Attribute::NoReturn).isValid());
+ op.setReturnsTwice(
+ callAttrs.getFnAttr(llvm::Attribute::ReturnsTwice).isValid());
+ op.setHot(callAttrs.getFnAttr(llvm::Attribute::Hot).isValid());
+ op.setCold(callAttrs.getFnAttr(llvm::Attribute::Cold).isValid());
+ op.setNoduplicate(
+ callAttrs.getFnAttr(llvm::Attribute::NoDuplicate).isValid());
op.setNoInline(callAttrs.getFnAttr(llvm::Attribute::NoInline).isValid());
op.setAlwaysInline(
callAttrs.getFnAttr(llvm::Attribute::AlwaysInline).isValid());
diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
index 46a0b97f1edbd..79d65ffe4e551 100644
--- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
@@ -1670,6 +1670,14 @@ static void convertFunctionAttributes(LLVMFuncOp func,
llvmFunc->addFnAttr(llvm::Attribute::InlineHint);
if (func.getOptimizeNoneAttr())
llvmFunc->addFnAttr(llvm::Attribute::OptimizeNone);
+ if (func.getReturnsTwiceAttr())
+ llvmFunc->addFnAttr(llvm::Attribute::ReturnsTwice);
+ if (func.getColdAttr())
+ llvmFunc->addFnAttr(llvm::Attribute::Cold);
+ if (func.getHotAttr())
+ llvmFunc->addFnAttr(llvm::Attribute::Hot);
+ if (func.getNoduplicateAttr())
+ llvmFunc->addFnAttr(llvm::Attribute::NoDuplicate);
if (func.getConvergentAttr())
llvmFunc->addFnAttr(llvm::Attribute::Convergent);
if (func.getNoUnwindAttr())
diff --git a/mlir/test/Dialect/LLVMIR/func.mlir b/mlir/test/Dialect/LLVMIR/func.mlir
index 936260f862a98..a66087e431eee 100644
--- a/mlir/test/Dialect/LLVMIR/func.mlir
+++ b/mlir/test/Dialect/LLVMIR/func.mlir
@@ -330,6 +330,30 @@ module {
llvm.return
}
+ llvm.func @returnstwice_function() attributes {returnstwice} {
+ // CHECK: @returnstwice_function
+ // CHECK-SAME: attributes {returnstwice}
+ llvm.return
+ }
+
+ llvm.func @hot_function() attributes {hot} {
+ // CHECK: @hot_function
+ // CHECK-SAME: attributes {hot}
+ llvm.return
+ }
+
+ llvm.func @cold_function() attributes {cold} {
+ // CHECK: @cold_function
+ // CHECK-SAME: attributes {cold}
+ llvm.return
+ }
+
+ llvm.func @noduplicate_function() attributes {noduplicate} {
+ // CHECK: @noduplicate_function
+ // CHECK-SAME: attributes {noduplicate}
+ llvm.return
+ }
+
}
// -----
diff --git a/mlir/test/Dialect/LLVMIR/roundtrip.mlir b/mlir/test/Dialect/LLVMIR/roundtrip.mlir
index fc2456b350a56..9ce45afd96c25 100644
--- a/mlir/test/Dialect/LLVMIR/roundtrip.mlir
+++ b/mlir/test/Dialect/LLVMIR/roundtrip.mlir
@@ -125,6 +125,18 @@ func.func @ops(%arg0: i32, %arg1: f32,
// CHECK: llvm.call @baz() {noreturn} : () -> ()
llvm.call @baz() {noreturn} : () -> ()
+// CHECK: llvm.call @baz() {returns_twice} : () -> ()
+ llvm.call @baz() {returns_twice} : () -> ()
+
+// CHECK: llvm.call @baz() {hot} : () -> ()
+ llvm.call @baz() {hot} : () -> ()
+
+// CHECK: llvm.call @baz() {cold} : () -> ()
+ llvm.call @baz() {cold} : () -> ()
+
+// CHECK: llvm.call @baz() {noduplicate} : () -> ()
+ llvm.call @baz() {noduplicate} : () -> ()
+
// CHECK: llvm.call @baz() {memory = #llvm.memory_effects<other = none, argMem = read, inaccessibleMem = write, errnoMem = none, targetMem0 = none, targetMem1 = none>} : () -> ()
llvm.call @baz() {memory = #llvm.memory_effects<other = none, argMem = read, inaccessibleMem = write, errnoMem = none, targetMem0 = none, targetMem1 = none>} : () -> ()
diff --git a/mlir/test/Target/LLVMIR/Import/function-attributes.ll b/mlir/test/Target/LLVMIR/Import/function-attributes.ll
index 69e18e1c5bbff..1002ad03c227c 100644
--- a/mlir/test/Target/LLVMIR/Import/function-attributes.ll
+++ b/mlir/test/Target/LLVMIR/Import/function-attributes.ll
@@ -417,5 +417,29 @@ declare void @noreturn_attribute() noreturn
// -----
+; CHECK-LABEL: @returnstwice_attribute
+; CHECK-SAME: attributes {returns_twice}
+declare void @returnstwice_attribute() returns_twice
+
+// -----
+
+; CHECK-LABEL: @hot_attribute
+; CHECK-SAME: attributes {hot}
+declare void @hot_attribute() hot
+
+// -----
+
+; CHECK-LABEL: @cold_attribute
+; CHECK-SAME: attributes {cold}
+declare void @cold_attribute() cold
+
+// -----
+
+; CHECK-LABEL: @noduplicate_attribute
+; CHECK-SAME: attributes {noduplicate}
+declare void @noduplicate_attribute() noduplicate
+
+// -----
+
; expected-warning @unknown {{'preallocated' attribute is invalid on current operation, skipping it}}
declare void @test() preallocated(i32)
diff --git a/mlir/test/Target/LLVMIR/Import/instructions.ll b/mlir/test/Target/LLVMIR/Import/instructions.ll
index 766f19ce386f8..11ebd70def8ce 100644
--- a/mlir/test/Target/LLVMIR/Import/instructions.ll
+++ b/mlir/test/Target/LLVMIR/Import/instructions.ll
@@ -713,6 +713,54 @@ define void @call_noreturn() {
; CHECK: llvm.func @f()
declare void @f()
+; CHECK-LABEL: @call_returnstwice
+define void @call_returnstwice() {
+; CHECK: llvm.call @f() {returns_twice}
+ call void @f() returns_twice
+ ret void
+}
+
+; // -----
+
+; CHECK: llvm.func @f()
+declare void @f()
+
+; CHECK-LABEL: @call_hot
+define void @call_hot() {
+; CHECK: llvm.call @f() {hot}
+ call void @f() hot
+ ret void
+}
+
+; // -----
+
+; CHECK: llvm.func @f()
+declare void @f()
+
+; CHECK-LABEL: @call_cold
+define void @call_cold() {
+; CHECK: llvm.call @f() {cold}
+ call void @f() cold
+ ret void
+}
+
+; // -----
+
+; CHECK: llvm.func @f()
+declare void @f()
+
+; CHECK-LABEL: @call_noduplicate
+define void @call_noduplicate() {
+; CHECK: llvm.call @f() {noduplicate}
+ call void @f() noduplicate
+ ret void
+}
+
+; // -----
+
+; CHECK: llvm.func @f()
+declare void @f()
+
; CHECK-LABEL: @call_memory_effects
define void @call_memory_effects() {
; CHECK: llvm.call @f() {memory_effects = #llvm.memory_effects<other = none, argMem = none, inaccessibleMem = none, errnoMem = none, targetMem0 = none, targetMem1 = none>}
diff --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir
index 12d73b429b3ce..8adf305805b0e 100644
--- a/mlir/test/Target/LLVMIR/llvmir.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir.mlir
@@ -2642,6 +2642,50 @@ llvm.func @noreturn() attributes { noreturn } {
// -----
+// CHECK-LABEL: @returnstwice
+// CHECK-SAME: #[[ATTRS:[0-9]+]]
+llvm.func @returnstwice() attributes { returns_twice } {
+ llvm.return
+}
+
+// CHECK: #[[ATTRS]]
+// CHECK-SAME: returns_twice
+
+// -----
+
+// CHECK-LABEL: @hot
+// CHECK-SAME: #[[ATTRS:[0-9]+]]
+llvm.func @hot() attributes { hot } {
+ llvm.return
+}
+
+// CHECK: #[[ATTRS]]
+// CHECK-SAME: hot
+
+// -----
+
+// CHECK-LABEL: @cold
+// CHECK-SAME: #[[ATTRS:[0-9]+]]
+llvm.func @cold() attributes { cold } {
+ llvm.return
+}
+
+// CHECK: #[[ATTRS]]
+// CHECK-SAME:cold
+
+// -----
+
+// CHECK-LABEL: @noduplicate
+// CHECK-SAME: #[[ATTRS:[0-9]+]]
+llvm.func @noduplicate() attributes { noduplicate } {
+ llvm.return
+}
+
+// CHECK: #[[ATTRS]]
+// CHECK-SAME: noduplicate
+
+// -----
+
llvm.func @f()
// CHECK-LABEL: @convergent_call
More information about the cfe-commits
mailing list