[clang] 49a8f37 - [CIR] Preserve attributes when converting call to try_call (#185782)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Mar 11 15:56:23 PDT 2026
Author: Andy Kaylor
Date: 2026-03-11T15:56:19-07:00
New Revision: 49a8f37e4b39bf82ca0424e040a10e8fbfcc5571
URL: https://github.com/llvm/llvm-project/commit/49a8f37e4b39bf82ca0424e040a10e8fbfcc5571
DIFF: https://github.com/llvm/llvm-project/commit/49a8f37e4b39bf82ca0424e040a10e8fbfcc5571.diff
LOG: [CIR] Preserve attributes when converting call to try_call (#185782)
This adds code to preserve any attributes, including parameter and
return value attributes, that were present on a call operation that is
being replaced with a try_call operation.
Added:
clang/test/CIR/CodeGen/invoke-attrs.cpp
clang/test/CIR/Transforms/flatten-preserve-attrs.cir
Modified:
clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp
clang/test/CIR/CodeGen/new-delete.cpp
clang/test/CIR/CodeGen/try-catch.cpp
clang/test/CIR/CodeGen/virtual-fn-calls-eh.cpp
Removed:
################################################################################
diff --git a/clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp b/clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp
index 49a9f85418055..50e8baba94a98 100644
--- a/clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp
@@ -647,7 +647,6 @@ static void replaceCallWithTryCall(cir::CallOp callOp, mlir::Block *unwindDest,
rewriter.splitBlock(callBlock, std::next(callOp->getIterator()));
// Build the try_call to replace the original call.
- // TODO(cir): Preserve function and argument attributes.
rewriter.setInsertionPoint(callOp);
cir::TryCallOp tryCallOp;
if (callOp.isIndirect()) {
@@ -666,6 +665,28 @@ static void replaceCallWithTryCall(cir::CallOp callOp, mlir::Block *unwindDest,
normalDest, unwindDest, callOp.getArgOperands());
}
+ // Copy all attributes from the original call except those already set by
+ // TryCallOp::create or that are operation-specific and should not be copied.
+ llvm::StringRef excludedAttrs[] = {
+ CIRDialect::getCalleeAttrName(), // Set by create()
+ CIRDialect::getOperandSegmentSizesAttrName(),
+ };
+#ifndef NDEBUG
+ // We don't expect to ever see any of these attributes on a call that we
+ // converted to a try_call.
+ llvm::StringRef unexpectedAttrs[] = {
+ CIRDialect::getNoThrowAttrName(),
+ CIRDialect::getNoUnwindAttrName(),
+ };
+#endif
+ for (mlir::NamedAttribute attr : callOp->getAttrs()) {
+ if (llvm::is_contained(excludedAttrs, attr.getName()))
+ continue;
+ assert(!llvm::is_contained(unexpectedAttrs, attr.getName()) &&
+ "unexpected attribute on converted call");
+ tryCallOp->setAttr(attr.getName(), attr.getValue());
+ }
+
// Replace uses of the call result with the try_call result.
if (callOp->getNumResults() > 0)
callOp->getResult(0).replaceAllUsesWith(tryCallOp.getResult());
diff --git a/clang/test/CIR/CodeGen/invoke-attrs.cpp b/clang/test/CIR/CodeGen/invoke-attrs.cpp
new file mode 100644
index 0000000000000..bc58d2193c267
--- /dev/null
+++ b/clang/test/CIR/CodeGen/invoke-attrs.cpp
@@ -0,0 +1,77 @@
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fcxx-exceptions -fexceptions -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
+// RUN: cir-opt --cir-flatten-cfg %t.cir -o %t-flat.cir
+// RUN: FileCheck --input-file=%t-flat.cir %s --check-prefix=CIR-FLAT
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fcxx-exceptions -fexceptions -fclangir -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fcxx-exceptions -fexceptions -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
+
+struct S {
+ int data[5];
+ void method();
+ int &ref_return();
+ void ref_param(int &i);
+};
+
+// Test that 'this' pointer attributes (nonnull, noundef, align,
+// dereferenceable) are preserved on invoke instructions lowered from
+// calls inside try blocks.
+void test_this_ptr_attrs(S &s) {
+ try {
+ s.method();
+ } catch (...) {}
+}
+
+// CIR-LABEL: cir.func {{.*}}@_Z19test_this_ptr_attrsR1S
+// CIR: cir.call @_ZN1S6methodEv({{%.*}}) : (!cir.ptr<!rec_S> {llvm.align = 4 : i64, llvm.dereferenceable = 20 : i64, llvm.nonnull, llvm.noundef}) -> ()
+
+// CIR-FLAT-LABEL: cir.func {{.*}}@_Z19test_this_ptr_attrsR1S
+// CIR-FLAT: cir.try_call @_ZN1S6methodEv({{%.*}}) ^{{bb[0-9]+}}, ^{{bb[0-9]+}} : (!cir.ptr<!rec_S> {llvm.align = 4 : i64, llvm.dereferenceable = 20 : i64, llvm.nonnull, llvm.noundef}) -> ()
+
+// LLVM-LABEL: define {{.*}} void @_Z19test_this_ptr_attrsR1S
+// LLVM: invoke void @_ZN1S6methodEv(ptr noundef nonnull align 4 dereferenceable(20) {{%.*}})
+
+// OGCG-LABEL: define {{.*}} void @_Z19test_this_ptr_attrsR1S
+// OGCG: invoke void @_ZN1S6methodEv(ptr noundef nonnull align 4 dereferenceable(20) {{%.*}})
+
+// Test that both 'this' and reference parameter attributes are preserved
+// on invoke instructions.
+void test_ref_param_attrs(S &s, int &i) {
+ try {
+ s.ref_param(i);
+ } catch (...) {}
+}
+
+// CIR-LABEL: cir.func {{.*}}@_Z20test_ref_param_attrsR1SRi
+// CIR: cir.call @_ZN1S9ref_paramERi({{%.*}}, {{%.*}}) : (!cir.ptr<!rec_S> {llvm.align = 4 : i64, llvm.dereferenceable = 20 : i64, llvm.nonnull, llvm.noundef}, !cir.ptr<!s32i> {llvm.align = 8 : i64, llvm.dereferenceable = 4 : i64, llvm.nonnull, llvm.noundef}) -> ()
+
+// CIR-FLAT-LABEL: cir.func {{.*}}@_Z20test_ref_param_attrsR1SRi
+// CIR-FLAT: cir.try_call @_ZN1S9ref_paramERi({{%.*}}, {{%.*}}) ^{{bb[0-9]+}}, ^{{bb[0-9]+}} : (!cir.ptr<!rec_S> {llvm.align = 4 : i64, llvm.dereferenceable = 20 : i64, llvm.nonnull, llvm.noundef}, !cir.ptr<!s32i> {llvm.align = 8 : i64, llvm.dereferenceable = 4 : i64, llvm.nonnull, llvm.noundef}) -> ()
+
+// LLVM-LABEL: define {{.*}} void @_Z20test_ref_param_attrsR1SRi
+// LLVM: invoke void @_ZN1S9ref_paramERi(ptr noundef nonnull align 4 dereferenceable(20) {{%.*}}, ptr noundef nonnull align 8 dereferenceable(4) {{%.*}})
+
+// OGCG-LABEL: define {{.*}} void @_Z20test_ref_param_attrsR1SRi
+// OGCG: invoke void @_ZN1S9ref_paramERi(ptr noundef nonnull align 4 dereferenceable(20) {{%.*}}, ptr noundef nonnull align 4 dereferenceable(4) {{%.*}})
+
+// Test that return attributes (nonnull, noundef, align, dereferenceable)
+// and parameter attributes are preserved on invoke instructions that
+// return a value.
+void test_ref_return_attrs(S &s) {
+ try {
+ int &r = s.ref_return();
+ } catch (...) {}
+}
+
+// CIR-LABEL: cir.func {{.*}}@_Z21test_ref_return_attrsR1S
+// CIR: cir.call @_ZN1S10ref_returnEv({{%.*}}) : (!cir.ptr<!rec_S> {llvm.align = 4 : i64, llvm.dereferenceable = 20 : i64, llvm.nonnull, llvm.noundef}) -> (!cir.ptr<!s32i> {llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nonnull, llvm.noundef})
+
+// CIR-FLAT-LABEL: cir.func {{.*}}@_Z21test_ref_return_attrsR1S
+// CIR-FLAT: cir.try_call @_ZN1S10ref_returnEv({{%.*}}) ^{{bb[0-9]+}}, ^{{bb[0-9]+}} : (!cir.ptr<!rec_S> {llvm.align = 4 : i64, llvm.dereferenceable = 20 : i64, llvm.nonnull, llvm.noundef}) -> (!cir.ptr<!s32i> {llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nonnull, llvm.noundef})
+
+// LLVM-LABEL: define {{.*}} void @_Z21test_ref_return_attrsR1S
+// LLVM: {{%.*}} = invoke noundef nonnull align 4 dereferenceable(4) ptr @_ZN1S10ref_returnEv(ptr noundef nonnull align 4 dereferenceable(20) {{%.*}})
+
+// OGCG-LABEL: define {{.*}} void @_Z21test_ref_return_attrsR1S
+// OGCG: {{%.*}} = invoke noundef nonnull align 4 dereferenceable(4) ptr @_ZN1S10ref_returnEv(ptr noundef nonnull align 4 dereferenceable(20) {{%.*}})
diff --git a/clang/test/CIR/CodeGen/new-delete.cpp b/clang/test/CIR/CodeGen/new-delete.cpp
index ca0c9152c40ad..d0c8c7d851c70 100644
--- a/clang/test/CIR/CodeGen/new-delete.cpp
+++ b/clang/test/CIR/CodeGen/new-delete.cpp
@@ -35,7 +35,7 @@ A *a() {
// LLVM: br label %[[EH_SCOPE:.*]]
// LLVM: [[EH_SCOPE]]:
// LLVM: store ptr %[[PTR]], ptr %[[NEW_RESULT]]
-// LLVM: invoke void @_ZN1AC1Ei(ptr %[[PTR]], i32 5)
+// LLVM: invoke void @_ZN1AC1Ei(ptr {{.*}} %[[PTR]], i32 5)
// LLVM: to label %[[INVOKE_CONT:.*]] unwind label %[[UNWIND:.*]]
// LLVM: [[INVOKE_CONT]]:
// LLVM: br label %[[EH_SCOPE_END:.*]]
@@ -113,7 +113,7 @@ A *b() {
// LLVM: %[[FOO:.*]] = invoke i32 @_Z3foov()
// LLVM: to label %[[INVOKE_CONT:.*]] unwind label %[[UNWIND:.*]]
// LLVM: [[INVOKE_CONT]]:
-// LLVM: invoke void @_ZN1AC1Ei(ptr %[[PTR]], i32 %[[FOO]])
+// LLVM: invoke void @_ZN1AC1Ei(ptr {{.*}} %[[PTR]], i32 %[[FOO]])
// LLVM: to label %[[INVOKE_CONT_2:.*]] unwind label %[[UNWIND:.*]]
// LLVM: [[INVOKE_CONT_2]]:
// LLVM: br label %[[EH_SCOPE_END:.*]]
@@ -200,7 +200,7 @@ B *c() {
// LLVM: br label %[[EH_SCOPE:.*]]
// LLVM: [[EH_SCOPE]]:
// LLVM: store ptr %[[PTR]], ptr %[[NEW_RESULT]]
-// LLVM: invoke void @_ZN1BC1Ei(ptr %[[PTR]], i32 5)
+// LLVM: invoke void @_ZN1BC1Ei(ptr {{.*}} %[[PTR]], i32 5)
// LLVM: to label %[[INVOKE_CONT:.*]] unwind label %[[UNWIND:.*]]
// LLVM: [[INVOKE_CONT]]:
// LLVM: br label %[[EH_SCOPE_END:.*]]
diff --git a/clang/test/CIR/CodeGen/try-catch.cpp b/clang/test/CIR/CodeGen/try-catch.cpp
index a9ad38a56715d..4883e37fc9d6d 100644
--- a/clang/test/CIR/CodeGen/try-catch.cpp
+++ b/clang/test/CIR/CodeGen/try-catch.cpp
@@ -226,7 +226,7 @@ void call_function_inside_try_catch_all() {
// LLVM: [[TRY_SCOPE]]:
// LLVM: br label %[[TRY_BEGIN:.*]]
// LLVM: [[TRY_BEGIN]]:
-// LLVM: %[[CALL:.*]] = invoke i32 @_Z8divisionv()
+// LLVM: %[[CALL:.*]] = invoke noundef i32 @_Z8divisionv()
// LLVM: to label %[[INVOKE_CONT:.*]] unwind label %[[LANDING_PAD:.*]]
// LLVM: [[INVOKE_CONT]]:
// LLVM: br label %[[TRY_CONT:.*]]
@@ -316,7 +316,7 @@ void call_function_inside_try_catch_with_exception_type() {
// LLVM: [[TRY_SCOPE]]:
// LLVM: br label %[[TRY_BEGIN:.*]]
// LLVM: [[TRY_BEGIN]]:
-// LLVM: %[[CALL:.*]] = invoke i32 @_Z8divisionv()
+// LLVM: %[[CALL:.*]] = invoke noundef i32 @_Z8divisionv()
// LLVM: to label %[[INVOKE_CONT:.*]] unwind label %[[LANDING_PAD:.*]]
// LLVM: [[INVOKE_CONT]]:
// LLVM: br label %[[TRY_CONT:.*]]
@@ -433,7 +433,7 @@ void call_function_inside_try_catch_with_ref_exception_type() {
// LLVM: [[TRY_SCOPE]]:
// LLVM: br label %[[TRY_BEGIN:.*]]
// LLVM: [[TRY_BEGIN]]:
-// LLVM: invoke i32 @_Z8divisionv()
+// LLVM: invoke noundef i32 @_Z8divisionv()
// LLVM: to label %[[INVOKE_CONT:.*]] unwind label %[[LANDING_PAD:.*]]
// LLVM: [[INVOKE_CONT:.*]]:
// LLVM: br label %[[TRY_CONT:.*]]
@@ -549,7 +549,7 @@ void call_function_inside_try_catch_with_complex_exception_type() {
// LLVM: [[TRY_SCOPE]]:
// LLVM: br label %[[TRY_BEGIN:.*]]
// LLVM: [[TRY_BEGIN]]:
-// LLVM: %[[CALL:.*]] = invoke i32 @_Z8divisionv()
+// LLVM: %[[CALL:.*]] = invoke noundef i32 @_Z8divisionv()
// LLVM: to label %[[INVOKE_CONT:.*]] unwind label %[[LANDING_PAD:.*]]
// LLVM: [[INVOKE_CONT]]:
// LLVM: br label %[[TRY_CONT:.*]]
@@ -672,7 +672,7 @@ void call_function_inside_try_catch_with_array_exception_type() {
// LLVM: [[TRY_SCOPE]]:
// LLVM: br label %[[TRY_BEGIN:.*]]
// LLVM: [[TRY_BEGIN]]:
-// LLVM: %[[CALL:.*]] = invoke i32 @_Z8divisionv()
+// LLVM: %[[CALL:.*]] = invoke noundef i32 @_Z8divisionv()
// LLVM: to label %[[INVOKE_CONT:.*]] unwind label %[[LANDING_PAD:.*]]
// LLVM: [[INVOKE_CONT]]:
// LLVM: br label %[[TRY_CONT:.*]]
@@ -796,7 +796,7 @@ void call_function_inside_try_catch_with_exception_type_and_catch_all() {
// LLVM: [[TRY_SCOPE]]:
// LLVM: br label %[[TRY_BEGIN:.*]]
// LLVM: [[TRY_BEGIN]]:
-// LLVM: %[[CALL:.*]] = invoke i32 @_Z8divisionv()
+// LLVM: %[[CALL:.*]] = invoke noundef i32 @_Z8divisionv()
// LLVM: to label %[[INVOKE_CONT:.*]] unwind label %[[LANDING_PAD:.*]]
// LLVM: [[INVOKE_CONT]]:
// LLVM: br label %[[TRY_CONT:.*]]
@@ -930,7 +930,7 @@ void cleanup_inside_try_body() {
// LLVM: [[TRY_BEGIN]]:
// LLVM: br label %[[CLEANUP_SCOPE:.*]]
// LLVM: [[CLEANUP_SCOPE]]:
-// LLVM: %[[CALL:.*]] = invoke i32 @_Z8divisionv()
+// LLVM: %[[CALL:.*]] = invoke noundef i32 @_Z8divisionv()
// LLVM: to label %[[INVOKE_CONT:.*]] unwind label %[[LANDING_PAD:.*]]
// LLVM: [[INVOKE_CONT]]:
// LLVM: br label %[[CLEANUP:.*]]
@@ -977,7 +977,7 @@ void cleanup_inside_try_body() {
// OGCG: %[[S:.*]] = alloca %struct.S
// OGCG: %[[EXN_SLOT:.*]] = alloca ptr
// OGCG: %[[EHSELECTOR_SLOT:.*]] = alloca i32
-// OGCG: %[[CALL:.*]] = invoke {{.*}} i32 @_Z8divisionv()
+// OGCG: %[[CALL:.*]] = invoke noundef i32 @_Z8divisionv()
// OGCG: to label %[[INVOKE_CONT:.*]] unwind label %[[LANDING_PAD:.*]]
// OGCG: [[INVOKE_CONT]]:
// OGCG: call void @_ZN1SD1Ev(ptr noundef nonnull align 1 dereferenceable(1) %[[S]])
diff --git a/clang/test/CIR/CodeGen/virtual-fn-calls-eh.cpp b/clang/test/CIR/CodeGen/virtual-fn-calls-eh.cpp
index b72e54de8005a..5ae1b5745d711 100644
--- a/clang/test/CIR/CodeGen/virtual-fn-calls-eh.cpp
+++ b/clang/test/CIR/CodeGen/virtual-fn-calls-eh.cpp
@@ -43,7 +43,7 @@ void call_virtual_fn_in_cleanup_scope() {
// CIR-FLAT: %[[VPTR:.*]] = cir.load{{.*}} %[[VPTR_ADDR]]
// CIR-FLAT: %[[FN_PTR_ADDR:.*]] = cir.vtable.get_virtual_fn_addr %[[VPTR]][0] : !cir.vptr -> !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!rec_B>, !s8i)>>>
// CIR-FLAT: %[[FN_PTR:.*]] = cir.load{{.*}} %[[FN_PTR_ADDR:.*]] : !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!rec_B>, !s8i)>>>, !cir.ptr<!cir.func<(!cir.ptr<!rec_B>, !s8i)>>
-// CIR-FLAT: cir.try_call %[[FN_PTR]](%[[B]], %[[C_LITERAL]]) ^[[NORMAL:bb[0-9]+]], ^[[UNWIND:bb[0-9]+]] : (!cir.ptr<!cir.func<(!cir.ptr<!rec_B>, !s8i)>>, !cir.ptr<!rec_B>, !s8i) -> ()
+// CIR-FLAT: cir.try_call %[[FN_PTR]](%[[B]], %[[C_LITERAL]]) ^[[NORMAL:bb[0-9]+]], ^[[UNWIND:bb[0-9]+]] : (!cir.ptr<!cir.func<(!cir.ptr<!rec_B>, !s8i)>>, !cir.ptr<!rec_B> {{.*}}, !s8i {{.*}}) -> ()
// CIR-FLAT: ^[[NORMAL]]: // pred: ^bb1
// CIR-FLAT: cir.br ^[[NORMAL_CLEANUP:bb[0-9]+]]
// CIR-FLAT: ^[[NORMAL_CLEANUP]]:
@@ -70,7 +70,7 @@ void call_virtual_fn_in_cleanup_scope() {
// LLVM: %[[B_VPTR:.*]] = load ptr, ptr %[[B]]
// LLVM: %[[FN_PTR_ADDR:.*]] = getelementptr inbounds ptr, ptr %[[B_VPTR]], i32 0
// LLVM: %[[FN_PTR:.*]] = load ptr, ptr %[[FN_PTR_ADDR]]
-// LLVM: invoke void %[[FN_PTR]](ptr %[[B]], i8 99)
+// LLVM: invoke void %[[FN_PTR]](ptr {{.*}} %[[B]], i8 {{.*}} 99)
// LLVM: to label %[[NORMAL_CONTINUE:.*]] unwind label %[[UNWIND:.*]]
// LLVM: [[NORMAL_CONTINUE]]
// LLVM: br label %[[NORMAL_CLEANUP:.*]]
diff --git a/clang/test/CIR/Transforms/flatten-preserve-attrs.cir b/clang/test/CIR/Transforms/flatten-preserve-attrs.cir
new file mode 100644
index 0000000000000..cc906b03beb99
--- /dev/null
+++ b/clang/test/CIR/Transforms/flatten-preserve-attrs.cir
@@ -0,0 +1,129 @@
+// RUN: cir-opt %s -cir-flatten-cfg -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s
+
+!s32i = !cir.int<s, 32>
+!rec_SomeClass = !cir.record<struct "SomeClass" {!s32i}>
+
+// Test that argument attributes on a cir.call are preserved on the resulting
+// cir.try_call after flattening.
+cir.func @test_preserve_arg_attrs(%arg0 : !cir.ptr<!s32i>) {
+ cir.scope {
+ cir.try {
+ cir.call @takesPtr(%arg0) : (!cir.ptr<!s32i> {llvm.nonnull, llvm.noundef}) -> ()
+ cir.yield
+ } catch all (%eh_token : !cir.eh_token) {
+ %catch_token, %exn_ptr = cir.begin_catch %eh_token : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!cir.void>)
+ cir.end_catch %catch_token : !cir.catch_token
+ cir.yield
+ }
+ }
+ cir.return
+}
+
+// CHECK-LABEL: cir.func @test_preserve_arg_attrs
+// CHECK-SAME: (%[[ARG0:.*]]: !cir.ptr<!s32i>)
+// CHECK: cir.try_call @takesPtr(%[[ARG0]]) ^{{.*}}, ^{{.*}} : (!cir.ptr<!s32i> {llvm.nonnull, llvm.noundef}) -> ()
+
+// Test that result attributes on a cir.call are preserved on the resulting
+// cir.try_call after flattening.
+cir.func @test_preserve_res_attrs() {
+ cir.scope {
+ cir.try {
+ %0 = cir.call @returnsPtr() : () -> (!cir.ptr<!s32i> {llvm.nonnull})
+ cir.yield
+ } catch all (%eh_token : !cir.eh_token) {
+ %catch_token, %exn_ptr = cir.begin_catch %eh_token : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!cir.void>)
+ cir.end_catch %catch_token : !cir.catch_token
+ cir.yield
+ }
+ }
+ cir.return
+}
+
+// CHECK-LABEL: cir.func @test_preserve_res_attrs()
+// CHECK: cir.try_call @returnsPtr() ^{{.*}}, ^{{.*}} : () -> (!cir.ptr<!s32i> {llvm.nonnull})
+
+// Test that the side_effect attribute on a cir.call is preserved on the
+// resulting cir.try_call after flattening.
+cir.func @test_preserve_side_effect() {
+ cir.scope {
+ cir.try {
+ %0 = cir.call @pureFunc() side_effect(pure) : () -> !s32i
+ cir.yield
+ } catch all (%eh_token : !cir.eh_token) {
+ %catch_token, %exn_ptr = cir.begin_catch %eh_token : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!cir.void>)
+ cir.end_catch %catch_token : !cir.catch_token
+ cir.yield
+ }
+ }
+ cir.return
+}
+
+// CHECK-LABEL: cir.func @test_preserve_side_effect()
+// CHECK: cir.try_call @pureFunc() ^{{.*}}, ^{{.*}} side_effect(pure) : () -> !s32i
+
+// Test that argument attributes on an indirect cir.call are preserved on the
+// resulting indirect cir.try_call after flattening.
+cir.func @test_preserve_indirect_call_attrs(
+ %fptr : !cir.ptr<!cir.func<(!cir.ptr<!rec_SomeClass>) -> !s32i>>,
+ %obj : !cir.ptr<!rec_SomeClass>) {
+ cir.scope {
+ cir.try {
+ %0 = cir.call %fptr(%obj) : (!cir.ptr<!cir.func<(!cir.ptr<!rec_SomeClass>) -> !s32i>>, !cir.ptr<!rec_SomeClass> {llvm.nonnull}) -> !s32i
+ cir.yield
+ } catch all (%eh_token : !cir.eh_token) {
+ %catch_token, %exn_ptr = cir.begin_catch %eh_token : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!cir.void>)
+ cir.end_catch %catch_token : !cir.catch_token
+ cir.yield
+ }
+ }
+ cir.return
+}
+
+// CHECK-LABEL: cir.func @test_preserve_indirect_call_attrs
+// CHECK: cir.try_call %{{.*}}(%{{.*}}) ^{{.*}}, ^{{.*}} : (!cir.ptr<!cir.func<(!cir.ptr<!rec_SomeClass>) -> !s32i>>, !cir.ptr<!rec_SomeClass> {llvm.nonnull}) -> !s32i
+
+// Test that all attribute types are preserved.
+cir.func @test_preserve_all_attrs(%arg0 : !cir.ptr<!s32i>) {
+ cir.scope {
+ cir.try {
+ %0 = cir.call @generalFunc(%arg0) side_effect(const) : (!cir.ptr<!s32i> {llvm.nonnull, llvm.noundef}) -> (!cir.ptr<!s32i> {llvm.nonnull})
+ cir.yield
+ } catch all (%eh_token : !cir.eh_token) {
+ %catch_token, %exn_ptr = cir.begin_catch %eh_token : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!cir.void>)
+ cir.end_catch %catch_token : !cir.catch_token
+ cir.yield
+ }
+ }
+ cir.return
+}
+
+// CHECK-LABEL: cir.func @test_preserve_all_attrs(%arg0: !cir.ptr<!s32i>)
+// CHECK: cir.try_call @generalFunc(%arg0) ^{{bb[0-9]+}}, ^{{bb[0-9]+}} side_effect(const) : (!cir.ptr<!s32i> {llvm.nonnull, llvm.noundef}) -> (!cir.ptr<!s32i> {llvm.nonnull})
+
+// Test that all attribute types are preserved with indirect calls.
+cir.func @test_preserve_all_attrs_indirect(
+ %fptr : !cir.ptr<!cir.func<(!cir.ptr<!rec_SomeClass>) -> !s32i>>,
+ %obj : !cir.ptr<!rec_SomeClass>) {
+ cir.scope {
+ cir.try {
+ %0 = cir.call %fptr(%obj) side_effect(const) : (!cir.ptr<!cir.func<(!cir.ptr<!rec_SomeClass>) -> !s32i>>, !cir.ptr<!rec_SomeClass> {llvm.nonnull}) -> (!s32i {llvm.nonnull})
+ cir.yield
+ } catch all (%eh_token : !cir.eh_token) {
+ %catch_token, %exn_ptr = cir.begin_catch %eh_token : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!cir.void>)
+ cir.end_catch %catch_token : !cir.catch_token
+ cir.yield
+ }
+ }
+ cir.return
+}
+
+// CHECK-LABEL: cir.func @test_preserve_all_attrs_indirect
+// CHECK: %[[FN_PTR:.*]]: !cir.ptr<!cir.func<(!cir.ptr<!rec_SomeClass>) -> !s32i>>,
+// CHECK-SAME: %[[OBJ:.*]]: !cir.ptr<!rec_SomeClass>
+// CHECK: cir.try_call %[[FN_PTR]](%[[OBJ]]) ^{{bb[0-9]+}}, ^{{bb[0-9]+}} side_effect(const) : (!cir.ptr<!cir.func<(!cir.ptr<!rec_SomeClass>) -> !s32i>>, !cir.ptr<!rec_SomeClass> {llvm.nonnull}) -> (!s32i {llvm.nonnull})
+
+cir.func private @generalFunc(!cir.ptr<!s32i>) -> !cir.ptr<!s32i>
+cir.func private @takesPtr(!cir.ptr<!s32i>)
+cir.func private @returnsPtr() -> !cir.ptr<!s32i>
+cir.func private @pureFunc() -> !s32i
More information about the cfe-commits
mailing list