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 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
