teak-llvm/clang/test/CodeGenCoroutines/coro-gro-nrvo.cpp
Brian Gesiak 986062219f [Coroutines] Use allocator overload when available
Summary:
Depends on https://reviews.llvm.org/D42605.

An implementation of the behavior described in `[dcl.fct.def.coroutine]/7`:
when a promise type overloads `operator new` using a "placement new"
that takes the same argument types as the coroutine function, that
overload is used when allocating the coroutine frame.

Simply passing references to the coroutine function parameters directly
to `operator new` results in invariant violations in LLVM's coroutine
splitting pass, so this implementation modifies Clang codegen to
produce allocator-specific alloc/store/loads for each parameter being
forwarded to the allocator.

Test Plan: `check-clang`

Reviewers: rsmith, GorNishanov, eric_niebler

Reviewed By: GorNishanov

Subscribers: lewissbaker, EricWF, cfe-commits

Differential Revision: https://reviews.llvm.org/D42606

llvm-svn: 325291
2018-02-15 20:37:22 +00:00

88 lines
2.5 KiB
C++

// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s
#include "Inputs/coroutine.h"
using namespace std::experimental;
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.
void* operator new(__SIZE_TYPE__ __sz, const std::nothrow_t&) noexcept;
void operator delete(void* __p, const std::nothrow_t&) noexcept;
template <class RetObject>
struct promise_type {
RetObject get_return_object();
suspend_always initial_suspend();
suspend_never final_suspend();
void return_void();
static void unhandled_exception();
};
struct coro {
using promise_type = promise_type<coro>;
coro(coro const&);
struct Impl;
Impl *impl;
};
// Verify that the NRVO is applied to the Gro object.
// CHECK-LABEL: define void @_Z1fi(%struct.coro* noalias sret %agg.result, i32)
coro f(int) {
// CHECK: %call = call i8* @_Znwm(
// CHECK-NEXT: br label %[[CoroInit:.*]]
// CHECK: {{.*}}[[CoroInit]]:
// CHECK: store i1 false, i1* %gro.active
// CHECK: call void @{{.*get_return_objectEv}}(%struct.coro* sret %agg.result
// CHECK-NEXT: store i1 true, i1* %gro.active
co_return;
}
template <class RetObject>
struct promise_type_with_on_alloc_failure {
static RetObject get_return_object_on_allocation_failure();
RetObject get_return_object();
suspend_always initial_suspend();
suspend_never final_suspend();
void return_void();
static void unhandled_exception();
};
struct coro_two {
using promise_type = promise_type_with_on_alloc_failure<coro_two>;
coro_two(coro_two const&);
struct Impl;
Impl *impl;
};
// Verify that the NRVO is applied to the Gro object.
// CHECK-LABEL: define void @_Z1hi(%struct.coro_two* noalias sret %agg.result, i32)
coro_two h(int) {
// CHECK: %call = call i8* @_ZnwmRKSt9nothrow_t
// CHECK-NEXT: %[[CheckNull:.*]] = icmp ne i8* %call, null
// CHECK-NEXT: br i1 %[[CheckNull]], label %[[InitOnSuccess:.*]], label %[[InitOnFailure:.*]]
// CHECK: {{.*}}[[InitOnFailure]]:
// CHECK-NEXT: call void @{{.*get_return_object_on_allocation_failureEv}}(%struct.coro_two* sret %agg.result
// CHECK-NEXT: br label %[[RetLabel:.*]]
// CHECK: {{.*}}[[InitOnSuccess]]:
// CHECK: store i1 false, i1* %gro.active
// CHECK: call void @{{.*get_return_objectEv}}(%struct.coro_two* sret %agg.result
// CHECK-NEXT: store i1 true, i1* %gro.active
// CHECK: [[RetLabel]]:
// CHECK-NEXT: ret void
co_return;
}