Skip to content

Commit c3152ff

Browse files
smeenailanza
authored andcommitted
[CIR][CIRGen] Add uwtable attribute (llvm#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 a51fcba commit c3152ff

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
@@ -2499,6 +2499,12 @@ void CIRGenModule::setCIRFunctionAttributesForDefinition(const Decl *decl,
24992499
FuncOp f) {
25002500
mlir::NamedAttrList attrs{f.getExtraAttrs().getElements().getValue()};
25012501

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

32623271
switch (codeGenOpts.getFramePointer()) {
32633272
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
@@ -82,6 +82,10 @@ class CIRDialectLLVMIRTranslationInterface
8282
oclVerMD->addOperand(llvm::MDNode::get(llvmContext, oclVerElts));
8383
}
8484

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

267289
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)