[clang] [CIR] Implement mustprogress/uwtable attributes (PR #228093)
Erich Keane via cfe-commits
cfe-commits at lists.llvm.org
Thu Oct 1 11:54:22 PDT 2026
https://github.com/erichkeane updated https://github.com/llvm/llvm-project/pull/228093
>From 2e8c34a4596f9fbf93330c00c52f6e0eba6e4889 Mon Sep 17 00:00:00 2001
From: erichkeane <ekeane at nvidia.com>
Date: Wed, 30 Sep 2026 21:06:06 -0700
Subject: [PATCH 1/2] [CIR] Implement mustprogress/uwtable attributes
These are effectively on-by-default attributes for nearly every function
in the program, and allows LLVM to make better optimization decisions.
'mustprogress' is added any time we have forward progress guaranteeds by
language (C++11 and not finite-loops disabled via command line option).
`uwtable` forwards the 'unwind table' codegen opt to functions that
don't opt out of it (via attribute), and clarifies whether the function
has an entry in the unwind table. In some programs this can be
time-consuming, so they disable them.
Both of these showed up as a defficiency in a test suite, and resulted
in certain programs taking a huge amount of time to properly compile.
This patch adds both as the 'extended attributes' printing location to
functions.
---
.../include/clang/CIR/Dialect/IR/CIRAttrs.td | 21 ++++++++
.../clang/CIR/Dialect/IR/CIRDialect.td | 1 +
clang/include/clang/CIR/Dialect/IR/CIROps.td | 3 +-
clang/include/clang/CIR/MissingFeatures.h | 1 -
clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 4 ++
clang/lib/CIR/CodeGen/CIRGenModule.cpp | 5 +-
clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 22 +++++---
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 21 ++++++++
clang/test/CIR/CodeGen/misc-attrs.cpp | 8 +--
clang/test/CIR/CodeGen/mustprogress.cpp | 20 +++++++
clang/test/CIR/CodeGen/uwtable.cpp | 53 +++++++++++++++++++
clang/test/CIR/IR/func-attrs.cir | 51 ++++++++++++++++++
clang/test/CIR/IR/invalid-func-attr.cir | 30 ++++++++++-
13 files changed, 226 insertions(+), 14 deletions(-)
create mode 100644 clang/test/CIR/CodeGen/mustprogress.cpp
create mode 100644 clang/test/CIR/CodeGen/uwtable.cpp
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 358412b75fc05..f614f37c795e9 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -1425,6 +1425,27 @@ def CIR_VisibilityKind : CIR_I32Enum<"VisibilityKind", "C/C++ visibility", [
I32EnumCase<"Protected", 2, "protected">
]>;
+//===----------------------------------------------------------------------===//
+// UnwindTableKind
+//===----------------------------------------------------------------------===//
+def CIR_UnwindTableKind : CIR_I32Enum<"UnwindTableKind", "Unwind Table Kind", [
+ I32EnumCase<"None", 0, "none">,
+ I32EnumCase<"Sync", 1, "sync">,
+ I32EnumCase<"Async", 2, "async">
+]>;
+
+def CIR_UnwindTableKindAttr : CIR_EnumAttr<CIR_UnwindTableKind, "uwtable"> {
+ let summary = "Encodes the unwind table kind for a function.";
+
+ let description = [{
+ This mirrors the UWTableKindEnum in The LLVM dialect,
+ and is passed through to the llvm dialect.According to the LLVM
+ documentation:
+ The ‘uwtable’ attribute is about the ABI or the user mandating an /
+ entry in the unwind table.
+ }];
+}
+
//===----------------------------------------------------------------------===//
// GloblCtorAttr
//===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
index d4ec063d8db0f..67a30b2c2b0dd 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
@@ -50,6 +50,7 @@ def CIR_Dialect : Dialect {
static llvm::StringRef getNoThrowAttrName() { return "nothrow"; }
static llvm::StringRef getNoReturnAttrName() { return "noreturn"; }
static llvm::StringRef getMemoryEffectsAttrName() { return "memory_effects"; }
+ static llvm::StringRef getUwtableAttrName() { return "uwtable"; }
static llvm::StringRef getReturnsTwiceAttrName() { return "returns_twice"; }
static llvm::StringRef getColdAttrName() { return "cold"; }
static llvm::StringRef getHotAttrName() { return "hot"; }
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index bc9af2210a048..2fa6ef2d0a837 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4358,7 +4358,8 @@ def CIR_FuncOp : CIR_Op<"func", [
CIR_OptionalPriorityAttr:$global_ctor_priority,
CIR_OptionalPriorityAttr:$global_dtor_priority,
OptionalAttr<CIR_FuncInfoAttr>:$func_info,
- OptionalAttr<CIR_AnnotationArrayAttr>:$annotations
+ OptionalAttr<CIR_AnnotationArrayAttr>:$annotations,
+ OptionalAttr<CIR_UnwindTableKindAttr>:$uwtable
);
let regions = (region AnyRegion:$body);
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index 9a866b62849ef..a9729ae9835a1 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -80,7 +80,6 @@ struct MissingFeatures {
static bool opFuncOptNoneAttr() { return false; }
static bool opFuncParameterAttributes() { return false; }
static bool opFuncReadOnly() { return false; }
- static bool opFuncUnwindTablesAttr() { return false; }
static bool opFuncWillReturn() { return false; }
static bool opFuncPreferredAlignment() { return false; }
static bool setLLVMFunctionFEnvAttributes() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index 823ccbe1d2e82..41dea08f7d535 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -779,6 +779,10 @@ cir::FuncOp CIRGenFunction::generateCode(clang::GlobalDecl gd, cir::FuncOp fn,
if (body && isa_and_nonnull<CoroutineBodyStmt>(body))
llvm::append_range(fnArgs, funcDecl->parameters());
+ if (checkIfFunctionMustProgress())
+ fn->setAttr(cir::CIRDialect::getMustProgressAttrName(),
+ mlir::UnitAttr::get(&getMLIRContext()));
+
if (shouldEmitLifetimeMarkers)
fnHasBypassStmt = functionMightHaveBypass(body);
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index cc0f36a0e7992..1db2bdc356a2d 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -3255,7 +3255,10 @@ void CIRGenModule::setFunctionAttributes(GlobalDecl globalDecl,
void CIRGenModule::setCIRFunctionAttributesForDefinition(
const clang::FunctionDecl *decl, cir::FuncOp f) {
- assert(!cir::MissingFeatures::opFuncUnwindTablesAttr());
+
+ if ((!decl || !decl->hasAttr<NoUwtableAttr>()) && codeGenOpts.UnwindTables)
+ f.setUwtable(static_cast<cir::UnwindTableKind>(codeGenOpts.UnwindTables));
+
assert(!cir::MissingFeatures::stackProtector());
if (!CodeGenUtils::hasUnwindExceptions(langOpts))
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 4b9e0c7f0f544..9903347ef1e36 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -1336,8 +1336,15 @@ static ParseResult checkEffectAttrKinds(mlir::OpAsmParser &parser,
<< CIRDialect::getMemoryEffectsAttrName()
<< "' must be a #cir.memory_effects attribute";
+ if (mlir::Attribute uwtable = attrs.get(CIRDialect::getUwtableAttrName()))
+ if (!mlir::isa<cir::UnwindTableKindAttr>(uwtable))
+ return parser.emitError(loc, "attribute '")
+ << CIRDialect::getUwtableAttrName()
+ << "' must be a #cir.uwtable attribute";
+
for (llvm::StringRef name :
- {CIRDialect::getNoUnwindAttrName(), CIRDialect::getWillReturnAttrName()})
+ {CIRDialect::getNoUnwindAttrName(), CIRDialect::getWillReturnAttrName(),
+ CIRDialect::getMustProgressAttrName()})
if (mlir::Attribute flag = attrs.get(name))
if (!mlir::isa<mlir::UnitAttr>(flag))
return parser.emitError(loc, "attribute '")
@@ -2958,10 +2965,11 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) {
return failure();
// Every other declared attribute has dedicated syntax above, so
- // memory_effects is the only one the explicit list may carry. Without the
- // exception cir.func could not parse back what it prints.
+ // memory_effects and uwtable is the only one the explicit list may carry.
+ // Without the exception cir.func could not parse back what it prints.
for (StringRef disallowed : cir::FuncOp::getAttributeNames()) {
- if (disallowed == CIRDialect::getMemoryEffectsAttrName())
+ if (disallowed == CIRDialect::getMemoryEffectsAttrName() ||
+ disallowed == CIRDialect::getUwtableAttrName())
continue;
if (parsedAttrs.get(disallowed))
return parser.emitError(loc, "attribute '")
@@ -3152,10 +3160,12 @@ void cir::FuncOp::print(OpAsmPrinter &p) {
}
// Every declared attribute is printed by the syntax above, except
- // memory_effects, which has none and so must reach the dictionary.
+ // memory_effects and uwtable, which have none and so must reach the
+ // dictionary.
llvm::SmallVector<llvm::StringRef> elidedAttrs;
for (llvm::StringRef name : cir::FuncOp::getAttributeNames())
- if (name != CIRDialect::getMemoryEffectsAttrName())
+ if (name != CIRDialect::getMemoryEffectsAttrName() &&
+ name != CIRDialect::getUwtableAttrName())
elidedAttrs.push_back(name);
function_interface_impl::printFunctionAttributes(p, *this, elidedAttrs);
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index d3a1b3fb1a02c..405b91e7f3ecf 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -20,6 +20,7 @@
#include "mlir/Conversion/OpenMPToLLVM/ConvertOpenMPToLLVM.h"
#include "mlir/Dialect/DLTI/DLTI.h"
#include "mlir/Dialect/Func/IR/FuncOps.h"
+#include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
#include "mlir/Dialect/LLVMIR/LLVMTypes.h"
#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
@@ -288,6 +289,22 @@ static mlir::LLVM::CConv convertCallingConv(cir::CallingConv callingConv) {
llvm_unreachable("Unknown calling convention");
}
+static mlir::LLVM::uwtable::UWTableKind
+convertUWTableKind(cir::UnwindTableKind kind) {
+ using CIR = cir::UnwindTableKind;
+ using LLVM = mlir::LLVM::uwtable::UWTableKind;
+
+ switch (kind) {
+ case CIR::None:
+ return LLVM::None;
+ case CIR::Sync:
+ return LLVM::Sync;
+ case CIR::Async:
+ return LLVM::Async;
+ }
+ llvm_unreachable("Unknown CIR unwind table kind");
+}
+
mlir::LogicalResult CIRToLLVMCopyOpLowering::matchAndRewrite(
cir::CopyOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
@@ -2891,6 +2908,10 @@ mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewrite(
if (op->hasAttr(CIRDialect::getNoReturnAttrName()))
fn.setNoreturn(true);
+ if (std::optional<cir::UnwindTableKind> uwtableKind = op.getUwtable())
+ fn.setUwtableKindAttr(mlir::LLVM::UWTableKindAttr::get(
+ fn.getContext(), convertUWTableKind(*uwtableKind)));
+
// Function attributes with no dedicated field on the LLVM dialect's
// LLVMFuncOp are routed through the `passthrough` array. The MLIR LLVM IR
// translator forwards `passthrough` entries to LLVM IR as function
diff --git a/clang/test/CIR/CodeGen/misc-attrs.cpp b/clang/test/CIR/CodeGen/misc-attrs.cpp
index d9e7ad261dd96..379025d20174e 100644
--- a/clang/test/CIR/CodeGen/misc-attrs.cpp
+++ b/clang/test/CIR/CodeGen/misc-attrs.cpp
@@ -11,12 +11,12 @@ extern "C" {
// LLVM-NEXT: define{{.*}}@returns_twice() #[[RT_ATTR:.*]] {
__attribute__((returns_twice))
void returns_twice() {}
- // CIR: cir.func{{.*}}@cold() attributes {{{.*}}cold, nothrow} {
+ // CIR: cir.func{{.*}}@cold() attributes {{{.*}}cold,{{.*}}nothrow} {
// LLVM: Function Attrs:{{.*}}cold
// LLVM-NEXT: define{{.*}}@cold() #[[COLD_ATTR:.*]] {
__attribute__((cold))
void cold() {}
- // CIR: cir.func{{.*}}@hot() attributes {{{.*}}hot, nothrow} {
+ // CIR: cir.func{{.*}}@hot() attributes {{{.*}}hot, {{.*}}nothrow} {
// LLVM: Function Attrs:{{.*}}hot
// LLVM-NEXT: define{{.*}}@hot() #[[HOT_ATTR:.*]] {
__attribute__((hot))
@@ -26,7 +26,7 @@ extern "C" {
// LLVM-NEXT: define{{.*}}@nodupes() #[[ND_ATTR:.*]] {
__attribute__((noduplicate))
void nodupes() {}
- // CIR: cir.func{{.*}}@convergent() attributes {{{.*}}convergent, nothrow} {
+ // CIR: cir.func{{.*}}@convergent() attributes {{{.*}}convergent, {{.*}}nothrow} {
// LLVM: Function Attrs:{{.*}}convergent
// LLVM-NEXT: define{{.*}}@convergent() #[[CONV_ATTR:.*]] {
__attribute__((convergent))
@@ -46,7 +46,7 @@ extern "C" {
__attribute__((leaf))
void leaf() {}
- // CIR: cir.func{{.*}}@modular_format({{.*}}) attributes {{{.*}}modular_format = "kprintf,1,2,someIdent,someStr,aspect,aspect2", nothrow} {
+ // CIR: cir.func{{.*}}@modular_format({{.*}}) attributes {{{.*}}modular_format = "kprintf,1,2,someIdent,someStr,aspect,aspect2", {{.*}}nothrow} {
// LLVM: Function Attrs:
// LLVM-NOT:modular_format
// LLVM-NEXT: define{{.*}}@modular_format({{.*}}) #[[MOD_FORMAT_ATTR:.*]] {
diff --git a/clang/test/CIR/CodeGen/mustprogress.cpp b/clang/test/CIR/CodeGen/mustprogress.cpp
new file mode 100644
index 0000000000000..de3cbd767ec8b
--- /dev/null
+++ b/clang/test/CIR/CodeGen/mustprogress.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -std=c++17 -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 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -fno-finite-loops -emit-llvm %s -o %t-nomp.ll
+// RUN: FileCheck --input-file=%t-nomp.ll %s -check-prefix=LLVM-NOMP
+
+void foo() {}
+
+// CIR: cir.func {{.*}}@_Z3foov{{.*}}attributes {{.*}}mustprogress
+
+// LLVM: define {{.*}} void @_Z3foov(){{.*}} #[[LATTR:[0-9]+]]
+// LLVM: attributes #[[LATTR]] = {{[{].*}}mustprogress{{.*}}}
+
+// With -fno-finite-loops, checkIfFunctionMustProgress() is false, so no
+// function should carry 'mustprogress' at all.
+// LLVM-NOMP: define {{.*}} void @_Z3foov()
+// LLVM-NOMP-NOT: mustprogress
diff --git a/clang/test/CIR/CodeGen/uwtable.cpp b/clang/test/CIR/CodeGen/uwtable.cpp
new file mode 100644
index 0000000000000..95f8493581967
--- /dev/null
+++ b/clang/test/CIR/CodeGen/uwtable.cpp
@@ -0,0 +1,53 @@
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -funwind-tables=2 -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR-ASYNC
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -funwind-tables=2 -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM-ASYNC
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -funwind-tables=2 -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM-ASYNC
+
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -funwind-tables=1 -emit-cir %s -o %t-sync.cir
+// RUN: FileCheck --input-file=%t-sync.cir %s -check-prefix=CIR-SYNC
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -funwind-tables=1 -emit-llvm %s -o %t-sync.ll
+// RUN: FileCheck --input-file=%t-sync.ll %s -check-prefix=LLVM-SYNC
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -funwind-tables=1 -emit-llvm %s -o %t-sync-ogcg.ll
+// RUN: FileCheck --input-file=%t-sync-ogcg.ll %s -check-prefix=LLVM-SYNC
+//
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -funwind-tables=0 -emit-cir %s -o %t-none.cir
+// RUN: FileCheck --input-file=%t-none.cir %s -check-prefix=CIR-NONE
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -funwind-tables=0 -emit-llvm %s -o %t-none.ll
+// RUN: FileCheck --input-file=%t-none.ll %s -check-prefix=LLVM-NONE
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -funwind-tables=0 -emit-llvm %s -o %t-none-ogcg.ll
+// RUN: FileCheck --input-file=%t-none-ogcg.ll %s -check-prefix=LLVM-NONE
+
+void normal() {}
+// CIR-ASYNC: cir.func{{.*}}@_Z6normalv() attributes {{.*}}uwtable = #cir.uwtable<async>
+// LLVM-ASYNC: define {{.*}}@_Z6normalv(){{.*}}#[[NORM_ATTR:[0-9]+]]
+
+// CIR-SYNC: cir.func{{.*}}@_Z6normalv() attributes {{.*}}uwtable = #cir.uwtable<sync>
+// LLVM-SYNC: define {{.*}}@_Z6normalv(){{.*}}#[[NORM_ATTR:[0-9]+]]
+
+// CIR-NONE: cir.func{{.*}}@_Z6normalv()
+// CIR-NONE-NOT: attributes {{.*}}uwtable =
+// LLVM-NONE: define {{.*}}@_Z6normalv(){{.*}}#[[NORM_ATTR:[0-9]+]]
+
+[[clang::nouwtable]] void suppressed() {}
+// CIR-ASYNC: cir.func{{.*}}@_Z10suppressedv()
+// CIR-ASYNC-NOT: attributes {{.*}}uwtable =
+// LLVM-ASYNC: define{{.*}}@_Z10suppressedv(){{.*}} #[[SUPP_ATTR:[0-9]+]]
+
+// CIR-SYNC: cir.func{{.*}}@_Z10suppressedv()
+// CIR-SYNC-NOT: attributes {{.*}}uwtable =
+// LLVM-SYNC: define{{.*}}@_Z10suppressedv(){{.*}} #[[SUPP_ATTR:[0-9]+]]
+
+// CIR-NONE: cir.func{{.*}}@_Z10suppressedv()
+// CIR-NONE-NOT: attributes {{.*}}uwtable =
+// LLVM-NONE: define{{.*}}@_Z10suppressedv(){{.*}} #[[SUPP_ATTR:[0-9]+]]
+
+// LLVM-ASYNC: attributes #[[NORM_ATTR]] ={{.*}}uwtable
+// LLVM-ASYNC-NOT: attributes #[[SUPP_ATTR]] ={{.*}}uwtable
+
+// LLVM-SYNC: attributes #[[NORM_ATTR]] ={{.*}}uwtable(sync)
+// LLVM-SYNC-NOT: attributes #[[SUPP_ATTR]] ={{.*}}uwtable
+
+// LLVM-SYNC-NOT: attributes #[[NORM_ATTR]] ={{.*}}uwtable
+// LLVM-SYNC-NOT: attributes #[[SUPP_ATTR]] ={{.*}}uwtable
diff --git a/clang/test/CIR/IR/func-attrs.cir b/clang/test/CIR/IR/func-attrs.cir
index 17a5ae905e5fe..fd51e1cee6f4a 100644
--- a/clang/test/CIR/IR/func-attrs.cir
+++ b/clang/test/CIR/IR/func-attrs.cir
@@ -75,3 +75,54 @@ cir.func @make_calls() {
cir.return
}
+
+cir.func @mustProgressFn() attributes {mustprogress} {
+ cir.return
+}
+// CHECK: cir.func @mustProgressFn() attributes {mustprogress} {
+// CHECK: cir.return
+// CHECK: }
+
+cir.func @noMustProgressFn() {
+ cir.return
+}
+// CHECK: cir.func @noMustProgressFn() {
+// CHECK-NOT: mustprogress
+// CHECK: cir.return
+// CHECK: }
+
+cir.func no_inline dso_local @mustProgressWithOthers() attributes {mustprogress} {
+ cir.return
+}
+// CHECK: cir.func no_inline dso_local @mustProgressWithOthers() attributes {mustprogress} {
+// CHECK: cir.return
+// CHECK: }
+
+cir.func @asyncUwtable() attributes {uwtable = #cir.uwtable<async>} {
+ cir.return
+}
+// CHECK: cir.func @asyncUwtable() attributes {uwtable = #cir.uwtable<async>} {
+// CHECK: cir.return
+// CHECK: }
+
+cir.func @syncUwtable() attributes {uwtable = #cir.uwtable<sync>} {
+ cir.return
+}
+// CHECK: cir.func @syncUwtable() attributes {uwtable = #cir.uwtable<sync>} {
+// CHECK: cir.return
+// CHECK: }
+
+cir.func @noUwtable() {
+ cir.return
+}
+// CHECK: cir.func @noUwtable() {
+// CHECK-NOT: uwtable
+// CHECK: cir.return
+// CHECK: }
+
+cir.func no_inline dso_local @uwtableWithOthers() attributes {mustprogress, uwtable = #cir.uwtable<async>} {
+ cir.return
+}
+// CHECK: cir.func no_inline dso_local @uwtableWithOthers() attributes {mustprogress, uwtable = #cir.uwtable<async>} {
+// CHECK: cir.return
+// CHECK: }
diff --git a/clang/test/CIR/IR/invalid-func-attr.cir b/clang/test/CIR/IR/invalid-func-attr.cir
index aaaaba7a7bf6f..81054bda03db9 100644
--- a/clang/test/CIR/IR/invalid-func-attr.cir
+++ b/clang/test/CIR/IR/invalid-func-attr.cir
@@ -1,4 +1,4 @@
-// RUN: cir-opt %s -verify-diagnostics
+// RUN: cir-opt %s -verify-diagnostics -split-input-file
module {
cir.func @l0() {
@@ -9,3 +9,31 @@ module {
cir.return
}
}
+
+// -----
+
+module {
+ // expected-error at +1 {{attribute 'mustprogress' must be a unit attribute}}
+ cir.func @badMustProgressKind() attributes {mustprogress = 1 : i32} {
+ cir.return
+ }
+}
+
+// -----
+
+module {
+ // expected-error at +1 {{attribute 'uwtable' must be a #cir.uwtable attribute}}
+ cir.func @badUwtableKind() attributes {uwtable = 1 : i32} {
+ cir.return
+ }
+}
+
+// -----
+
+module {
+ // expected-error at +2 {{expected one of [none, sync, async] for Unwind Table Kind, got: bogus}}
+ // expected-error at +1 {{failed to parse CIR_UnwindTableKindAttr parameter 'value' which is to be a `::cir::UnwindTableKind`}}
+ cir.func @badUwtableSpelling() attributes {uwtable = #cir.uwtable<bogus>} {
+ cir.return
+ }
+}
>From 825f870503ca2b1701771196ce84a9c8ba10f617 Mon Sep 17 00:00:00 2001
From: erichkeane <ekeane at nvidia.com>
Date: Thu, 1 Oct 2026 11:54:03 -0700
Subject: [PATCH 2/2] fixup review comments
---
clang/include/clang/CIR/Dialect/IR/CIRAttrs.td | 2 +-
clang/test/CIR/CodeGen/uwtable.cpp | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index f614f37c795e9..f6aaac5ab4cab 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -1439,7 +1439,7 @@ def CIR_UnwindTableKindAttr : CIR_EnumAttr<CIR_UnwindTableKind, "uwtable"> {
let description = [{
This mirrors the UWTableKindEnum in The LLVM dialect,
- and is passed through to the llvm dialect.According to the LLVM
+ and is passed through to the llvm dialect. According to the LLVM
documentation:
The ‘uwtable’ attribute is about the ABI or the user mandating an /
entry in the unwind table.
diff --git a/clang/test/CIR/CodeGen/uwtable.cpp b/clang/test/CIR/CodeGen/uwtable.cpp
index 95f8493581967..dd0bff00a57ca 100644
--- a/clang/test/CIR/CodeGen/uwtable.cpp
+++ b/clang/test/CIR/CodeGen/uwtable.cpp
@@ -49,5 +49,5 @@ void normal() {}
// LLVM-SYNC: attributes #[[NORM_ATTR]] ={{.*}}uwtable(sync)
// LLVM-SYNC-NOT: attributes #[[SUPP_ATTR]] ={{.*}}uwtable
-// LLVM-SYNC-NOT: attributes #[[NORM_ATTR]] ={{.*}}uwtable
-// LLVM-SYNC-NOT: attributes #[[SUPP_ATTR]] ={{.*}}uwtable
+// LLVM-NONE-NOT: attributes #[[NORM_ATTR]] ={{.*}}uwtable
+// LLVM-NONE-NOT: attributes #[[SUPP_ATTR]] ={{.*}}uwtable
More information about the cfe-commits
mailing list