https://github.com/Andres-Salamanca updated https://github.com/llvm/llvm-project/pull/220466
>From 9d20cb13fec7b761e98c8aa28ee07e871348ae2a Mon Sep 17 00:00:00 2001 From: Andres Salamanca <[email protected]> Date: Tue, 1 Sep 2026 22:01:28 -0500 Subject: [PATCH 1/5] [CIR] Add support for coroutine allocation failure --- clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp | 25 +++++- .../test/CIR/CodeGenCoroutines/coro-alloc.cpp | 78 +++++++++++++++++++ 2 files changed, 99 insertions(+), 4 deletions(-) create mode 100644 clang/test/CIR/CodeGenCoroutines/coro-alloc.cpp diff --git a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp index 7bcaa43bae765..13e06c2b580ab 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp @@ -15,6 +15,7 @@ #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtVisitor.h" #include "clang/Basic/TargetInfo.h" +#include "clang/CIR/Dialect/IR/CIRDialect.h" #include "clang/CIR/Dialect/IR/CIRTypes.h" #include "clang/CIR/MissingFeatures.h" @@ -370,16 +371,32 @@ CIRGenFunction::emitCoroutineBody(const CoroutineBodyStmt &s) { loc, emitScalarExpr(s.getAllocate()), storeAddr); cir::YieldOp::create(builder, loc); }); + + // Handle allocation failure if 'ReturnStmtOnAllocFailure' was provided. + if (Stmt *retOnAllocFailure = s.getReturnStmtOnAllocFailure()) { + + mlir::LogicalResult res = mlir::success(); + mlir::Value isPtrNull = builder.createPtrIsNull(storeAddr); + + assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic()); + + cir::IfOp::create( + builder, openCurlyLoc, isPtrNull, /*withElseRegion=*/false, + [&](mlir::OpBuilder &b, mlir::Location loc) { + res = emitStmt(retOnAllocFailure, /*useCurrentScope=*/true); + cir::TrapOp::create(builder, openCurlyLoc); + }); + + if (res.failed()) + return res; + } + curCoro.data->coroBegin = cir::CoroBeginOp::create( cgm.getBuilder(), openCurlyLoc, mlir::ValueRange{ curCoro.data->coroId.getResult(), cir::LoadOp::create(builder, openCurlyLoc, allocaTy, storeAddr)}); - // Handle allocation failure if 'ReturnStmtOnAllocFailure' was provided. - if (s.getReturnStmtOnAllocFailure()) - cgm.errorNYI("handle coroutine return alloc failure"); - { assert(!cir::MissingFeatures::generateDebugInfo()); ParamReferenceReplacerRAII paramReplacer(localDeclMap); diff --git a/clang/test/CIR/CodeGenCoroutines/coro-alloc.cpp b/clang/test/CIR/CodeGenCoroutines/coro-alloc.cpp new file mode 100644 index 0000000000000..02684a1dbfebf --- /dev/null +++ b/clang/test/CIR/CodeGenCoroutines/coro-alloc.cpp @@ -0,0 +1,78 @@ +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -fno-clangir-call-conv-lowering -Wno-coroutine-missing-unhandled-exception -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -emit-llvm -disable-llvm-passes -Wno-coroutine-missing-unhandled-exception %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=OGCG +#include "Inputs/coroutine.h" +namespace std { + +struct nothrow_t {}; +constexpr nothrow_t nothrow = {}; + +} // end namespace std + +// Required when get_return_object_on_allocation_failure() is defined by +// the promise. The nothrow overload prevents allocation failure from +// throwing std::bad_alloc. +using SizeT = decltype(sizeof(int)); +void* operator new(SizeT __sz, const std::nothrow_t&) noexcept; +void operator delete(void* __p, const std::nothrow_t&) noexcept; + +struct promise_on_alloc_failure_tag {}; + +template <> +struct std::coroutine_traits<int, promise_on_alloc_failure_tag> { + struct promise_type { + int get_return_object() { return 0; } + suspend_always initial_suspend() { return {}; } + suspend_always final_suspend() noexcept { return {}; } + void return_void() {} + static int get_return_object_on_allocation_failure() { return -1; } + }; +}; + +int f4(promise_on_alloc_failure_tag) { + + co_return; +} + +// CIR-LABEL: @_Z2f428promise_on_alloc_failure_tag( +// CIR: %[[RetVal:.*]] = cir.alloca "__retval" +// CIR: %[[SavedFrameAddr:.*]] = cir.alloca "__coro_frame_addr" +// CIR: %[[CORO_ID:.*]] = cir.coro.intrinsic.id( +// CIR: %[[ShouldAlloc:.*]] = cir.coro.intrinsic.alloc(%[[CORO_ID]]) +// CIR: cir.if %[[ShouldAlloc]] { +// CIR: %[[CORO_SIZE:.*]] = cir.coro.intrinsic.size() +// CIR: %[[STD_NOTHROW:.*]] = cir.get_global @_ZStL7nothrow +// CIR: %[[ALLOC_ADDR:.*]] = cir.call @_ZnwmRKSt9nothrow_t(%[[CORO_SIZE]], %[[STD_NOTHROW]]) +// CIR: cir.store %[[ALLOC_ADDR]], %[[SavedFrameAddr]] +// CIR: } +// CIR: %[[NULL_PTR:.*]] = cir.const #cir.ptr<null> +// CIR: %[[IS_NULL_PTR:.*]] = cir.cmp eq %[[SavedFrameAddr]], %[[NULL_PTR:.*]] +// CIR: cir.if %[[IS_NULL_PTR]] { +// CIR: %[[FailRet:.*]] = cir.call @_ZNSt16coroutine_traitsIiJ28promise_on_alloc_failure_tagEE12promise_type39get_return_object_on_allocation_failureEv +// CIR: cir.store %[[FailRet]], %[[RetVal]] : !s32i +// CIR: %[[RET:.*]] = cir.load %[[RetVal]] : !cir.ptr<!s32i> +// CIR: cir.return %[[RET]] : !s32i +// CIR: ^[[UNREACHABLE:.*]]: +// CIR: cir.trap +// CIR: } + +// OGCG-LABEL: @_Z2f428promise_on_alloc_failure_tag( +// OGCG: %[[RetVal:.*]] = alloca i32 +// OGCG: %[[ID:.*]] = call token @llvm.coro.id(i32 16 +// OGCG: %[[SIZE:.*]] = call i64 @llvm.coro.size.i64() +// OGCG: %[[MEM:.*]] = call noalias noundef ptr @_ZnwmRKSt9nothrow_t(i64 noundef %[[SIZE]], ptr noundef nonnull align 1 dereferenceable(1) @_ZStL7nothrow) +// OGCG: %[[OK:.*]] = icmp ne ptr %[[MEM]], null +// OGCG: br i1 %[[OK]], label %[[OKBB:.*]], label %[[ERRBB:.*]] + +// OGCG: [[ERRBB]]: +// OGCG: %[[FailRet:.*]] = call noundef i32 @_ZNSt16coroutine_traitsIiJ28promise_on_alloc_failure_tagEE12promise_type39get_return_object_on_allocation_failureEv() +// OGCG: store i32 %[[FailRet]], ptr %[[RetVal]] +// OGCG: br label %[[RetBB:.*]] + +// OGCG: [[OKBB]]: +// OGCG: %[[OkRet:.*]] = call noundef i32 @_ZNSt16coroutine_traitsIiJ28promise_on_alloc_failure_tagEE12promise_type17get_return_objectEv({{.*}} + +// OGCG: [[RetBB]]: +// OGCG: %[[LoadRet:.*]] = load i32, ptr %[[RetVal]], align 4 +// OGCG: ret i32 %[[LoadRet]] >From 3988e6aff6b84f60cc0befd12260194de445a0a5 Mon Sep 17 00:00:00 2001 From: Andres Salamanca <[email protected]> Date: Tue, 1 Sep 2026 23:39:13 -0500 Subject: [PATCH 2/5] Address review comments --- clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp | 36 +++++++++---------- .../test/CIR/CodeGenCoroutines/coro-alloc.cpp | 26 +++++++------- 2 files changed, 30 insertions(+), 32 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp index 13e06c2b580ab..4fbede0f88ad4 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp @@ -363,33 +363,29 @@ CIRGenFunction::emitCoroutineBody(const CoroutineBodyStmt &s) { mlir::Value storeAddr = coroFrame.getPointer(); builder.CIRBaseBuilderTy::createStore(openCurlyLoc, nullPtrCst, storeAddr); + mlir::LogicalResult res = mlir::success(); cir::IfOp::create( builder, openCurlyLoc, coroAlloc.getResult(), /*withElseRegion=*/false, /*thenBuilder=*/[&](mlir::OpBuilder &b, mlir::Location loc) { - builder.CIRBaseBuilderTy::createStore( - loc, emitScalarExpr(s.getAllocate()), storeAddr); + mlir::Value allocatedPtr = emitScalarExpr(s.getAllocate()); + builder.CIRBaseBuilderTy::createStore(loc, allocatedPtr, storeAddr); + // Handle allocation failure if 'ReturnStmtOnAllocFailure' was provided. + if (Stmt *retOnAllocFailure = s.getReturnStmtOnAllocFailure()) { + mlir::Value isPtrNull = builder.createPtrIsNull(allocatedPtr); + assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic()); + cir::IfOp::create(builder, loc, isPtrNull, /*withElseRegion=*/false, + [&](mlir::OpBuilder &b, mlir::Location loc) { + res = emitStmt(retOnAllocFailure, + /*useCurrentScope=*/true); + cir::UnreachableOp::create(builder, loc); + }); + } cir::YieldOp::create(builder, loc); }); - // Handle allocation failure if 'ReturnStmtOnAllocFailure' was provided. - if (Stmt *retOnAllocFailure = s.getReturnStmtOnAllocFailure()) { - - mlir::LogicalResult res = mlir::success(); - mlir::Value isPtrNull = builder.createPtrIsNull(storeAddr); - - assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic()); - - cir::IfOp::create( - builder, openCurlyLoc, isPtrNull, /*withElseRegion=*/false, - [&](mlir::OpBuilder &b, mlir::Location loc) { - res = emitStmt(retOnAllocFailure, /*useCurrentScope=*/true); - cir::TrapOp::create(builder, openCurlyLoc); - }); - - if (res.failed()) - return res; - } + if (res.failed()) + return res; curCoro.data->coroBegin = cir::CoroBeginOp::create( cgm.getBuilder(), openCurlyLoc, diff --git a/clang/test/CIR/CodeGenCoroutines/coro-alloc.cpp b/clang/test/CIR/CodeGenCoroutines/coro-alloc.cpp index 02684a1dbfebf..1c7bc9b4797c9 100644 --- a/clang/test/CIR/CodeGenCoroutines/coro-alloc.cpp +++ b/clang/test/CIR/CodeGenCoroutines/coro-alloc.cpp @@ -37,24 +37,26 @@ int f4(promise_on_alloc_failure_tag) { // CIR-LABEL: @_Z2f428promise_on_alloc_failure_tag( // CIR: %[[RetVal:.*]] = cir.alloca "__retval" -// CIR: %[[SavedFrameAddr:.*]] = cir.alloca "__coro_frame_addr" +// CIR: %[[FrameAddr:.*]] = cir.alloca "__coro_frame_addr" +// CIR: %[[NULL_INIT:.*]] = cir.const #cir.ptr<null> // CIR: %[[CORO_ID:.*]] = cir.coro.intrinsic.id( // CIR: %[[ShouldAlloc:.*]] = cir.coro.intrinsic.alloc(%[[CORO_ID]]) +// CIR: cir.store %[[NULL_INIT]], %[[FrameAddr]] // CIR: cir.if %[[ShouldAlloc]] { // CIR: %[[CORO_SIZE:.*]] = cir.coro.intrinsic.size() // CIR: %[[STD_NOTHROW:.*]] = cir.get_global @_ZStL7nothrow // CIR: %[[ALLOC_ADDR:.*]] = cir.call @_ZnwmRKSt9nothrow_t(%[[CORO_SIZE]], %[[STD_NOTHROW]]) -// CIR: cir.store %[[ALLOC_ADDR]], %[[SavedFrameAddr]] -// CIR: } -// CIR: %[[NULL_PTR:.*]] = cir.const #cir.ptr<null> -// CIR: %[[IS_NULL_PTR:.*]] = cir.cmp eq %[[SavedFrameAddr]], %[[NULL_PTR:.*]] -// CIR: cir.if %[[IS_NULL_PTR]] { -// CIR: %[[FailRet:.*]] = cir.call @_ZNSt16coroutine_traitsIiJ28promise_on_alloc_failure_tagEE12promise_type39get_return_object_on_allocation_failureEv -// CIR: cir.store %[[FailRet]], %[[RetVal]] : !s32i -// CIR: %[[RET:.*]] = cir.load %[[RetVal]] : !cir.ptr<!s32i> -// CIR: cir.return %[[RET]] : !s32i -// CIR: ^[[UNREACHABLE:.*]]: -// CIR: cir.trap +// CIR: cir.store %[[ALLOC_ADDR]], %[[FrameAddr]] +// CIR: %[[NULL_PTR:.*]] = cir.const #cir.ptr<null> +// CIR: %[[IS_NULL_PTR:.*]] = cir.cmp eq %[[ALLOC_ADDR]], %[[NULL_PTR]] +// CIR: cir.if %[[IS_NULL_PTR]] { +// CIR: %[[FailRet:.*]] = cir.call @_ZNSt16coroutine_traitsIiJ28promise_on_alloc_failure_tagEE12promise_type39get_return_object_on_allocation_failureEv +// CIR: cir.store %[[FailRet]], %[[RetVal]] : !s32i +// CIR: %[[RET:.*]] = cir.load %[[RetVal]] : !cir.ptr<!s32i> +// CIR: cir.return %[[RET]] : !s32i +// CIR: ^[[UNREACHABLE:.*]]: +// CIR: cir.unreachable +// CIR: } // CIR: } // OGCG-LABEL: @_Z2f428promise_on_alloc_failure_tag( >From 2dc20e008926f54914bb84c8b3d681cca76620a2 Mon Sep 17 00:00:00 2001 From: Andres Salamanca <[email protected]> Date: Wed, 2 Sep 2026 16:58:59 -0500 Subject: [PATCH 3/5] Address review comments --- clang/test/CIR/CodeGenCoroutines/coro-alloc.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/test/CIR/CodeGenCoroutines/coro-alloc.cpp b/clang/test/CIR/CodeGenCoroutines/coro-alloc.cpp index 1c7bc9b4797c9..bb0d27af57271 100644 --- a/clang/test/CIR/CodeGenCoroutines/coro-alloc.cpp +++ b/clang/test/CIR/CodeGenCoroutines/coro-alloc.cpp @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -fno-clangir-call-conv-lowering -Wno-coroutine-missing-unhandled-exception -emit-cir %s -o %t.cir +// TODO(cir): drop -fno-clangir-call-conv-lowering once CallConvLowering +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -Wno-coroutine-missing-unhandled-exception -emit-cir %s -o %t.cir // RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -emit-llvm -disable-llvm-passes -Wno-coroutine-missing-unhandled-exception %s -o %t-cir.ll // RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=OGCG >From bc25b172ff22688103ff603db0fd093fa83f24c9 Mon Sep 17 00:00:00 2001 From: Andres Salamanca <[email protected]> Date: Wed, 2 Sep 2026 22:03:49 -0500 Subject: [PATCH 4/5] Address review comments --- .../test/CIR/CodeGenCoroutines/coro-alloc.cpp | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/clang/test/CIR/CodeGenCoroutines/coro-alloc.cpp b/clang/test/CIR/CodeGenCoroutines/coro-alloc.cpp index bb0d27af57271..50adb1db53012 100644 --- a/clang/test/CIR/CodeGenCoroutines/coro-alloc.cpp +++ b/clang/test/CIR/CodeGenCoroutines/coro-alloc.cpp @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -Wno-coroutine-missing-unhandled-exception -emit-cir %s -o %t.cir // RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -emit-llvm -disable-llvm-passes -Wno-coroutine-missing-unhandled-exception %s -o %t-cir.ll -// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=OGCG +// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM #include "Inputs/coroutine.h" namespace std { @@ -60,22 +60,22 @@ int f4(promise_on_alloc_failure_tag) { // CIR: } // CIR: } -// OGCG-LABEL: @_Z2f428promise_on_alloc_failure_tag( -// OGCG: %[[RetVal:.*]] = alloca i32 -// OGCG: %[[ID:.*]] = call token @llvm.coro.id(i32 16 -// OGCG: %[[SIZE:.*]] = call i64 @llvm.coro.size.i64() -// OGCG: %[[MEM:.*]] = call noalias noundef ptr @_ZnwmRKSt9nothrow_t(i64 noundef %[[SIZE]], ptr noundef nonnull align 1 dereferenceable(1) @_ZStL7nothrow) -// OGCG: %[[OK:.*]] = icmp ne ptr %[[MEM]], null -// OGCG: br i1 %[[OK]], label %[[OKBB:.*]], label %[[ERRBB:.*]] +// LLVM-LABEL: @_Z2f428promise_on_alloc_failure_tag( +// LLVM: %[[RetVal:.*]] = alloca i32 +// LLVM: %[[ID:.*]] = call token @llvm.coro.id(i32 16 +// LLVM: %[[SIZE:.*]] = call i64 @llvm.coro.size.i64() +// LLVM: %[[MEM:.*]] = call noalias noundef ptr @_ZnwmRKSt9nothrow_t(i64 noundef %[[SIZE]], ptr noundef nonnull align 1 dereferenceable(1) @_ZStL7nothrow) +// LLVM: %[[OK:.*]] = icmp ne ptr %[[MEM]], null +// LLVM: br i1 %[[OK]], label %[[OKBB:.*]], label %[[ERRBB:.*]] -// OGCG: [[ERRBB]]: -// OGCG: %[[FailRet:.*]] = call noundef i32 @_ZNSt16coroutine_traitsIiJ28promise_on_alloc_failure_tagEE12promise_type39get_return_object_on_allocation_failureEv() -// OGCG: store i32 %[[FailRet]], ptr %[[RetVal]] -// OGCG: br label %[[RetBB:.*]] +// LLVM: [[ERRBB]]: +// LLVM: %[[FailRet:.*]] = call noundef i32 @_ZNSt16coroutine_traitsIiJ28promise_on_alloc_failure_tagEE12promise_type39get_return_object_on_allocation_failureEv() +// LLVM: store i32 %[[FailRet]], ptr %[[RetVal]] +// LLVM: br label %[[RetBB:.*]] -// OGCG: [[OKBB]]: -// OGCG: %[[OkRet:.*]] = call noundef i32 @_ZNSt16coroutine_traitsIiJ28promise_on_alloc_failure_tagEE12promise_type17get_return_objectEv({{.*}} +// LLVM: [[OKBB]]: +// LLVM: %[[OkRet:.*]] = call noundef i32 @_ZNSt16coroutine_traitsIiJ28promise_on_alloc_failure_tagEE12promise_type17get_return_objectEv({{.*}} -// OGCG: [[RetBB]]: -// OGCG: %[[LoadRet:.*]] = load i32, ptr %[[RetVal]], align 4 -// OGCG: ret i32 %[[LoadRet]] +// LLVM: [[RetBB]]: +// LLVM: %[[LoadRet:.*]] = load i32, ptr %[[RetVal]], align 4 +// LLVM: ret i32 %[[LoadRet]] >From 9d3b0395e8422d610f66672868000136d4fc665e Mon Sep 17 00:00:00 2001 From: Andres Salamanca <[email protected]> Date: Thu, 3 Sep 2026 11:05:54 -0500 Subject: [PATCH 5/5] remove comment --- clang/test/CIR/CodeGenCoroutines/coro-alloc.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/clang/test/CIR/CodeGenCoroutines/coro-alloc.cpp b/clang/test/CIR/CodeGenCoroutines/coro-alloc.cpp index 50adb1db53012..fc766cc54d7a0 100644 --- a/clang/test/CIR/CodeGenCoroutines/coro-alloc.cpp +++ b/clang/test/CIR/CodeGenCoroutines/coro-alloc.cpp @@ -1,4 +1,3 @@ -// TODO(cir): drop -fno-clangir-call-conv-lowering once CallConvLowering // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -Wno-coroutine-missing-unhandled-exception -emit-cir %s -o %t.cir // RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -emit-llvm -disable-llvm-passes -Wno-coroutine-missing-unhandled-exception %s -o %t-cir.ll _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
