Skip to content

Commit

Permalink
[CIR][CIRGen] Add uwtable attribute
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
smeenai committed Dec 11, 2024
1 parent 9a63c50 commit b31c62e
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 2 deletions.
29 changes: 29 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
Original file line number Diff line number Diff line change
Expand Up @@ -1119,6 +1119,35 @@ def ConvergentAttr : CIRUnitAttr<"Convergent", "convergent"> {
let storageType = [{ ConvergentAttr }];
}

def UWTableKindNone
: I32EnumAttrCase<"None", 0, "none">;
def UWTableKindSync
: I32EnumAttrCase<"Sync", 1, "sync">;
def UWTableKindAsync
: I32EnumAttrCase<"Async", 2, "async">;

def UWTableKind : I32EnumAttr<"UWTableKind", "Unwind table kind", [
UWTableKindNone, UWTableKindSync, UWTableKindAsync
]> {
let cppNamespace = "::cir";
let genSpecializedAttr = 0;
}

def UWTableAttr : EnumAttr<CIR_Dialect, UWTableKind, "uwtable"> {
let summary = "Unwind table kind attribute";
let description = [{
The kind of unwind tables to generate for a function. `none` means no unwind
tables are generated; `sync` means synchronous unwind tables (that are only
valid at call boundaries), and `async` means asynchronous unwind tables
(that are valid at all instructions). When applied to a module, this
controls the unwind table generation for any synthesized functions.
}];

let assemblyFormat = [{
`<` $value `>`
}];
}

class CIR_GlobalCtorDtor<string name, string attrMnemonic,
string sum, string desc>
: CIR_Attr<"Global" # name, "global_" # attrMnemonic> {
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/CIR/Dialect/IR/CIRDialect.td
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ def CIR_Dialect : Dialect {
static llvm::StringRef getLangAttrName() { return "cir.lang"; }
static llvm::StringRef getTripleAttrName() { return "cir.triple"; }
static llvm::StringRef getOptInfoAttrName() { return "cir.opt_info"; }
static llvm::StringRef getUWTableAttrName() { return "cir.uwtable"; }

static llvm::StringRef getGlobalCtorsAttrName() { return "cir.global_ctors"; }
static llvm::StringRef getGlobalDtorsAttrName() { return "cir.global_dtors"; }
Expand Down
1 change: 0 additions & 1 deletion clang/include/clang/CIR/MissingFeatures.h
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,6 @@ struct MissingFeatures {
static bool codeModel() { return false; }
static bool largeDataThreshold() { return false; }
static bool directAccessExternalData() { return false; }
static bool setUwtable() { return false; }
static bool setFramePointer() { return false; }
static bool simplifyPersonality() { return false; }
static bool emitVersionIdentMetadata() { return false; }
Expand Down
11 changes: 10 additions & 1 deletion clang/lib/CIR/CodeGen/CIRGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2500,6 +2500,12 @@ void CIRGenModule::setCIRFunctionAttributesForDefinition(const Decl *decl,
FuncOp f) {
mlir::NamedAttrList attrs{f.getExtraAttrs().getElements().getValue()};

if ((!decl || !decl->hasAttr<NoUwtableAttr>()) && codeGenOpts.UnwindTables) {
auto attr = cir::UWTableKindAttr::get(
&getMLIRContext(), cir::UWTableKind(codeGenOpts.UnwindTables));
attrs.set(attr.getMnemonic(), attr);
}

if (!hasUnwindExceptions(getLangOpts())) {
auto attr = cir::NoThrowAttr::get(&getMLIRContext());
attrs.set(attr.getMnemonic(), attr);
Expand Down Expand Up @@ -3258,7 +3264,10 @@ void CIRGenModule::Release() {
llvm_unreachable("NYI");
assert(!MissingFeatures::directAccessExternalData());
if (codeGenOpts.UnwindTables)
assert(!MissingFeatures::setUwtable());
theModule->setAttr(
cir::CIRDialect::getUWTableAttrName(),
cir::UWTableKindAttr::get(&getMLIRContext(),
cir::UWTableKind(codeGenOpts.UnwindTables)));

switch (codeGenOpts.getFramePointer()) {
case CodeGenOptions::FramePointerKind::None:
Expand Down
22 changes: 22 additions & 0 deletions clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVMIR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ class CIRDialectLLVMIRTranslationInterface
oclVerMD->addOperand(llvm::MDNode::get(llvmContext, oclVerElts));
}

if (auto uwTableAttr =
mlir::dyn_cast<cir::UWTableKindAttr>(attribute.getValue()))
llvmModule->setUwtable(convertUWTableKind(uwTableAttr.getValue()));

// Drop ammended CIR attribute from LLVM op.
module->removeAttr(attribute.getName());
}
Expand Down Expand Up @@ -129,6 +133,11 @@ class CIRDialectLLVMIRTranslationInterface
attr.getValue())) {
emitOpenCLKernelArgMetadata(clArgMetadata, func.getNumArguments(),
llvmFunc, moduleTranslation);
} else if (auto uwTableAttr =
mlir::dyn_cast<cir::UWTableKindAttr>(attr.getValue())) {
llvm::AttrBuilder builder(llvmFunc->getContext());
builder.addUWTableAttr(convertUWTableKind(uwTableAttr.getValue()));
llvmFunc->addFnAttrs(builder);
}
}
}
Expand Down Expand Up @@ -261,6 +270,19 @@ class CIRDialectLLVMIRTranslationInterface
llvmFunc->setMetadata("kernel_arg_name",
llvm::MDNode::get(vmCtx, argNames));
}

private:
static llvm::UWTableKind convertUWTableKind(cir::UWTableKind kind) {
// TODO(cir): Use UWTableKindAttr from the LLVM dialect when available.
switch (kind) {
case cir::UWTableKind::None:
return llvm::UWTableKind::None;
case cir::UWTableKind::Sync:
return llvm::UWTableKind::Sync;
case cir::UWTableKind::Async:
return llvm::UWTableKind::Async;
}
}
};

void registerCIRDialectTranslation(mlir::DialectRegistry &registry) {
Expand Down
56 changes: 56 additions & 0 deletions clang/test/CIR/CodeGen/uwtable.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t-none.cir
// RUN: FileCheck %s --input-file=%t-none.cir --check-prefix=CIR-NONE
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -funwind-tables=0 %s -o %t-none-explicit.cir
// RUN: FileCheck %s --input-file=%t-none-explicit.cir --check-prefix=CIR-NONE
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -funwind-tables=1 %s -o %t-sync.cir
// RUN: FileCheck %s --input-file=%t-sync.cir --check-prefix=CIR-SYNC
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -funwind-tables=2 %s -o %t-async.cir
// RUN: FileCheck %s --input-file=%t-async.cir --check-prefix=CIR-ASYNC

// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-none.ll
// RUN: FileCheck %s --input-file=%t-none.ll --check-prefix=LLVM-NONE
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm -funwind-tables=0 %s -o %t-none-explicit.ll
// RUN: FileCheck %s --input-file=%t-none-explicit.ll --check-prefix=LLVM-NONE
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm -funwind-tables=1 %s -o %t-sync.ll
// RUN: FileCheck %s --input-file=%t-sync.ll --check-prefix=LLVM-SYNC
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm -funwind-tables=2 %s -o %t-async.ll
// RUN: FileCheck %s --input-file=%t-async.ll --check-prefix=LLVM-ASYNC

// CIR-NONE-NOT: #cir.uwtable

// CIR-SYNC-DAG: module {{.*}} attributes {{{.*}}cir.uwtable = #cir.uwtable<sync>
// CIR-SYNC-DAG: cir.func @_Z1fv() extra(#[[f_attr:.*]])
// CIR-SYNC-DAG: cir.func @_Z1gv() extra(#[[g_attr:.*]])
// CIR-SYNC-DAG: #[[f_attr]] = #cir<extra({{{.*}}uwtable = #cir.uwtable<sync>
// CIR-SYNC-DAG: #[[g_attr]] =
// CIR-SYNC-NOT: #cir.uwtable

// CIR-ASYNC-DAG: module {{.*}} attributes {{{.*}}cir.uwtable = #cir.uwtable<async>
// CIR-ASYNC-DAG: cir.func @_Z1fv() extra(#[[f_attr:.*]])
// CIR-ASYNC-DAG: cir.func @_Z1gv() extra(#[[g_attr:.*]])
// CIR-ASYNC-DAG: #[[f_attr]] = #cir<extra({{{.*}}uwtable = #cir.uwtable<async>
// CIR-ASYNC-DAG: #[[g_attr]] =
// CIR-ASYNC-NOT: #cir.uwtable

// Avoid matching "uwtable" in the ModuleID and source_filename comments.
// LLVM-NONE: define {{.*}} @_Z1fv()
// LLVM-NONE-NOT: uwtable

// LLVM-SYNC: define {{.*}} @_Z1fv() #[[#F_ATTRS:]]
// LLVM-SYNC: define {{.*}} @_Z1gv() #[[#G_ATTRS:]]
// LLVM-SYNC: attributes #[[#F_ATTRS]] = {{{.*}}uwtable(sync)
// LLVM-SYNC: attributes #[[#G_ATTRS]] =
// LLVM-SYNC-NOT: uwtable
// LLVM-SYNC-DAG: ![[#METADATA:]] = !{i32 7, !"uwtable", i32 1}
// LLVM-SYNC-DAG: !llvm.module.flags = !{{{.*}}[[#METADATA]]

// LLVM-ASYNC: define {{.*}} @_Z1fv() #[[#ATTRS:]]
// LLVM-ASYNC: define {{.*}} @_Z1gv() #[[#G_ATTRS:]]
// LLVM-ASYNC: attributes #[[#ATTRS]] = {{{.*}}uwtable{{ }}
// LLVM-ASYNC: attributes #[[#G_ATTRS]] =
// LLVM-ASYNC-NOT: uwtable
// LLVM-ASYNC-DAG: ![[#METADATA:]] = !{i32 7, !"uwtable", i32 2}
// LLVM-ASYNC-DAG: !llvm.module.flags = !{{{.*}}[[#METADATA]]
void f() {}

[[clang::nouwtable]] void g() {}

0 comments on commit b31c62e

Please sign in to comment.