Skip to content

Commit 8b74dc0

Browse files
authored
[CIR][CIRGen] Add uwtable attribute (#1226)
The module-level uwtable attribute controls the unwind tables for any synthesized functions, and the function-level attribute controls them for those functions. I'll add support for this attribute to the LLVM dialect as well, but translate it from CIR directly for now to avoid waiting on the MLIR addition and a subsequent rebase.
1 parent 1e344e0 commit 8b74dc0

File tree

6 files changed

+119
-2
lines changed

6 files changed

+119
-2
lines changed

clang/include/clang/CIR/Dialect/IR/CIRAttrs.td

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1134,6 +1134,36 @@ def ConvergentAttr : CIRUnitAttr<"Convergent", "convergent"> {
11341134
let storageType = [{ ConvergentAttr }];
11351135
}
11361136

1137+
def UWTableKindNone
1138+
: I32EnumAttrCase<"None", 0, "none">;
1139+
def UWTableKindSync
1140+
: I32EnumAttrCase<"Sync", 1, "sync">;
1141+
def UWTableKindAsync
1142+
: I32EnumAttrCase<"Async", 2, "async">;
1143+
1144+
def UWTableKind : I32EnumAttr<"UWTableKind", "Unwind table kind", [
1145+
UWTableKindNone, UWTableKindSync, UWTableKindAsync
1146+
]> {
1147+
let cppNamespace = "::cir";
1148+
let genSpecializedAttr = 0;
1149+
}
1150+
1151+
def UWTableAttr : EnumAttr<CIR_Dialect, UWTableKind, "uwtable"> {
1152+
let summary = "Unwind table kind attribute";
1153+
let description = [{
1154+
The kind of unwind tables to generate for a function. `none` means no unwind
1155+
tables are generated; `sync` means synchronous unwind tables (that are only
1156+
valid at call boundaries), and `async` means asynchronous unwind tables
1157+
(that are valid at all instructions). When applied to a module, this
1158+
controls the unwind table generation for any synthesized functions.
1159+
}];
1160+
1161+
let cppClassName = "UWTableAttr";
1162+
let assemblyFormat = [{
1163+
`<` $value `>`
1164+
}];
1165+
}
1166+
11371167
class CIR_GlobalCtorDtor<string name, string attrMnemonic,
11381168
string sum, string desc>
11391169
: CIR_Attr<"Global" # name, "global_" # attrMnemonic> {

clang/include/clang/CIR/Dialect/IR/CIRDialect.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ def CIR_Dialect : Dialect {
3838
static llvm::StringRef getLangAttrName() { return "cir.lang"; }
3939
static llvm::StringRef getTripleAttrName() { return "cir.triple"; }
4040
static llvm::StringRef getOptInfoAttrName() { return "cir.opt_info"; }
41+
static llvm::StringRef getUWTableAttrName() { return "cir.uwtable"; }
4142

4243
static llvm::StringRef getGlobalCtorsAttrName() { return "cir.global_ctors"; }
4344
static llvm::StringRef getGlobalDtorsAttrName() { return "cir.global_dtors"; }

clang/include/clang/CIR/MissingFeatures.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,6 @@ struct MissingFeatures {
361361
static bool codeModel() { return false; }
362362
static bool largeDataThreshold() { return false; }
363363
static bool directAccessExternalData() { return false; }
364-
static bool setUwtable() { return false; }
365364
static bool setFramePointer() { return false; }
366365
static bool simplifyPersonality() { return false; }
367366
static bool emitVersionIdentMetadata() { return false; }

clang/lib/CIR/CodeGen/CIRGenModule.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2500,6 +2500,12 @@ void CIRGenModule::setCIRFunctionAttributesForDefinition(const Decl *decl,
25002500
FuncOp f) {
25012501
mlir::NamedAttrList attrs{f.getExtraAttrs().getElements().getValue()};
25022502

2503+
if ((!decl || !decl->hasAttr<NoUwtableAttr>()) && codeGenOpts.UnwindTables) {
2504+
auto attr = cir::UWTableAttr::get(
2505+
&getMLIRContext(), cir::UWTableKind(codeGenOpts.UnwindTables));
2506+
attrs.set(attr.getMnemonic(), attr);
2507+
}
2508+
25032509
if (!hasUnwindExceptions(getLangOpts())) {
25042510
auto attr = cir::NoThrowAttr::get(&getMLIRContext());
25052511
attrs.set(attr.getMnemonic(), attr);
@@ -3258,7 +3264,10 @@ void CIRGenModule::Release() {
32583264
llvm_unreachable("NYI");
32593265
assert(!MissingFeatures::directAccessExternalData());
32603266
if (codeGenOpts.UnwindTables)
3261-
assert(!MissingFeatures::setUwtable());
3267+
theModule->setAttr(
3268+
cir::CIRDialect::getUWTableAttrName(),
3269+
cir::UWTableAttr::get(&getMLIRContext(),
3270+
cir::UWTableKind(codeGenOpts.UnwindTables)));
32623271

32633272
switch (codeGenOpts.getFramePointer()) {
32643273
case CodeGenOptions::FramePointerKind::None:

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVMIR.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ class CIRDialectLLVMIRTranslationInterface
8181
oclVerMD->addOperand(llvm::MDNode::get(llvmContext, oclVerElts));
8282
}
8383

84+
if (auto uwTableAttr =
85+
mlir::dyn_cast<cir::UWTableAttr>(attribute.getValue()))
86+
llvmModule->setUwtable(convertUWTableKind(uwTableAttr.getValue()));
87+
8488
// Drop ammended CIR attribute from LLVM op.
8589
module->removeAttr(attribute.getName());
8690
}
@@ -129,6 +133,11 @@ class CIRDialectLLVMIRTranslationInterface
129133
attr.getValue())) {
130134
emitOpenCLKernelArgMetadata(clArgMetadata, func.getNumArguments(),
131135
llvmFunc, moduleTranslation);
136+
} else if (auto uwTableAttr =
137+
mlir::dyn_cast<cir::UWTableAttr>(attr.getValue())) {
138+
llvm::AttrBuilder builder(llvmFunc->getContext());
139+
builder.addUWTableAttr(convertUWTableKind(uwTableAttr.getValue()));
140+
llvmFunc->addFnAttrs(builder);
132141
}
133142
}
134143
}
@@ -261,6 +270,19 @@ class CIRDialectLLVMIRTranslationInterface
261270
llvmFunc->setMetadata("kernel_arg_name",
262271
llvm::MDNode::get(vmCtx, argNames));
263272
}
273+
274+
private:
275+
static llvm::UWTableKind convertUWTableKind(cir::UWTableKind kind) {
276+
// TODO(cir): Use UWTableKindAttr from the LLVM dialect when available.
277+
switch (kind) {
278+
case cir::UWTableKind::None:
279+
return llvm::UWTableKind::None;
280+
case cir::UWTableKind::Sync:
281+
return llvm::UWTableKind::Sync;
282+
case cir::UWTableKind::Async:
283+
return llvm::UWTableKind::Async;
284+
}
285+
}
264286
};
265287

266288
void registerCIRDialectTranslation(mlir::DialectRegistry &registry) {

clang/test/CIR/CodeGen/uwtable.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t-none.cir
2+
// RUN: FileCheck %s --input-file=%t-none.cir --check-prefix=CIR-NONE
3+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -funwind-tables=0 %s -o %t-none-explicit.cir
4+
// RUN: FileCheck %s --input-file=%t-none-explicit.cir --check-prefix=CIR-NONE
5+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -funwind-tables=1 %s -o %t-sync.cir
6+
// RUN: FileCheck %s --input-file=%t-sync.cir --check-prefix=CIR-SYNC
7+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -funwind-tables=2 %s -o %t-async.cir
8+
// RUN: FileCheck %s --input-file=%t-async.cir --check-prefix=CIR-ASYNC
9+
10+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-none.ll
11+
// RUN: FileCheck %s --input-file=%t-none.ll --check-prefix=LLVM-NONE
12+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm -funwind-tables=0 %s -o %t-none-explicit.ll
13+
// RUN: FileCheck %s --input-file=%t-none-explicit.ll --check-prefix=LLVM-NONE
14+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm -funwind-tables=1 %s -o %t-sync.ll
15+
// RUN: FileCheck %s --input-file=%t-sync.ll --check-prefix=LLVM-SYNC
16+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm -funwind-tables=2 %s -o %t-async.ll
17+
// RUN: FileCheck %s --input-file=%t-async.ll --check-prefix=LLVM-ASYNC
18+
19+
// CIR-NONE-NOT: #cir.uwtable
20+
21+
// CIR-SYNC-DAG: module {{.*}} attributes {{{.*}}cir.uwtable = #cir.uwtable<sync>
22+
// CIR-SYNC-DAG: cir.func @_Z1fv() extra(#[[f_attr:.*]])
23+
// CIR-SYNC-DAG: cir.func @_Z1gv() extra(#[[g_attr:.*]])
24+
// CIR-SYNC-DAG: #[[f_attr]] = #cir<extra({{{.*}}uwtable = #cir.uwtable<sync>
25+
// CIR-SYNC-DAG: #[[g_attr]] =
26+
// CIR-SYNC-NOT: #cir.uwtable
27+
28+
// CIR-ASYNC-DAG: module {{.*}} attributes {{{.*}}cir.uwtable = #cir.uwtable<async>
29+
// CIR-ASYNC-DAG: cir.func @_Z1fv() extra(#[[f_attr:.*]])
30+
// CIR-ASYNC-DAG: cir.func @_Z1gv() extra(#[[g_attr:.*]])
31+
// CIR-ASYNC-DAG: #[[f_attr]] = #cir<extra({{{.*}}uwtable = #cir.uwtable<async>
32+
// CIR-ASYNC-DAG: #[[g_attr]] =
33+
// CIR-ASYNC-NOT: #cir.uwtable
34+
35+
// Avoid matching "uwtable" in the ModuleID and source_filename comments.
36+
// LLVM-NONE: define {{.*}} @_Z1fv()
37+
// LLVM-NONE-NOT: uwtable
38+
39+
// LLVM-SYNC: define {{.*}} @_Z1fv() #[[#F_ATTRS:]]
40+
// LLVM-SYNC: define {{.*}} @_Z1gv() #[[#G_ATTRS:]]
41+
// LLVM-SYNC: attributes #[[#F_ATTRS]] = {{{.*}}uwtable(sync)
42+
// LLVM-SYNC: attributes #[[#G_ATTRS]] =
43+
// LLVM-SYNC-NOT: uwtable
44+
// LLVM-SYNC-DAG: ![[#METADATA:]] = !{i32 7, !"uwtable", i32 1}
45+
// LLVM-SYNC-DAG: !llvm.module.flags = !{{{.*}}[[#METADATA]]
46+
47+
// LLVM-ASYNC: define {{.*}} @_Z1fv() #[[#ATTRS:]]
48+
// LLVM-ASYNC: define {{.*}} @_Z1gv() #[[#G_ATTRS:]]
49+
// LLVM-ASYNC: attributes #[[#ATTRS]] = {{{.*}}uwtable{{ }}
50+
// LLVM-ASYNC: attributes #[[#G_ATTRS]] =
51+
// LLVM-ASYNC-NOT: uwtable
52+
// LLVM-ASYNC-DAG: ![[#METADATA:]] = !{i32 7, !"uwtable", i32 2}
53+
// LLVM-ASYNC-DAG: !llvm.module.flags = !{{{.*}}[[#METADATA]]
54+
void f() {}
55+
56+
[[clang::nouwtable]] void g() {}

0 commit comments

Comments
 (0)