===================================================================
@@ -185,7 +185,7 @@
A comparison to constant is simple enough to allow, and
is used to convert to bool. */
-static bool
+bool
cilk_ignorable_spawn_rhs_op (tree exp)
{
enum tree_code code = TREE_CODE (exp);
@@ -223,8 +223,8 @@
/* Returns true when EXP is a CALL_EXPR with _Cilk_spawn in front. Unwraps
CILK_SPAWN_STMT wrapper from the CALL_EXPR in *EXP0 statement. */
-static bool
-recognize_spawn (tree exp, tree *exp0)
+bool
+cilk_recognize_spawn (tree exp, tree *exp0)
{
bool spawn_found = false;
if (TREE_CODE (exp) == CILK_SPAWN_STMT)
@@ -292,7 +292,7 @@
/* Now we should have a CALL_EXPR with a CILK_SPAWN_STMT wrapper around
it, or return false. */
- if (recognize_spawn (exp, exp0))
+ if (cilk_recognize_spawn (exp, exp0))
return true;
return false;
}
@@ -1251,6 +1251,21 @@
return;
case AGGR_INIT_EXPR:
+ {
+ int len = 0;
+ int ii = 0;
+ extract_free_variables (TREE_OPERAND (t, 1), wd, ADD_READ);
+ if (TREE_CODE (TREE_OPERAND (t, 0)) == INTEGER_CST)
+ {
+ len = TREE_INT_CST_LOW (TREE_OPERAND (t, 0));
+
+ for (ii = 3; ii < len; ii++)
+ extract_free_variables (TREE_OPERAND (t, ii), wd, ADD_READ);
+ extract_free_variables (TREE_TYPE (t), wd, ADD_READ);
+ }
+ break;
+ }
+
case CALL_EXPR:
{
int len = 0;
===================================================================
@@ -39,6 +39,7 @@
static tree cp_fold_r (tree *, int *, void *);
static void cp_genericize_tree (tree*);
static tree cp_fold (tree);
+bool cilk_cp_detect_spawn_and_unwrap (tree *);
/* Local declarations. */
@@ -619,7 +620,7 @@
case INIT_EXPR:
if (fn_contains_cilk_spawn_p (cfun))
{
- if (cilk_detect_spawn_and_unwrap (expr_p))
+ if (cilk_cp_detect_spawn_and_unwrap (expr_p))
{
cilk_cp_gimplify_call_params_in_spawned_fn (expr_p,
pre_p, post_p);
@@ -637,7 +638,7 @@
modify_expr_case:
{
if (fn_contains_cilk_spawn_p (cfun)
- && cilk_detect_spawn_and_unwrap (expr_p)
+ && cilk_cp_detect_spawn_and_unwrap (expr_p)
&& !seen_error ())
{
cilk_cp_gimplify_call_params_in_spawned_fn (expr_p, pre_p, post_p);
@@ -738,7 +739,7 @@
case CILK_SPAWN_STMT:
gcc_assert(fn_contains_cilk_spawn_p (cfun)
- && cilk_detect_spawn_and_unwrap (expr_p));
+ && cilk_cp_detect_spawn_and_unwrap (expr_p));
if (!seen_error ())
{
@@ -749,7 +750,7 @@
case CALL_EXPR:
if (fn_contains_cilk_spawn_p (cfun)
- && cilk_detect_spawn_and_unwrap (expr_p)
+ && cilk_cp_detect_spawn_and_unwrap (expr_p)
&& !seen_error ())
{
cilk_cp_gimplify_call_params_in_spawned_fn (expr_p, pre_p, post_p);
===================================================================
@@ -27,6 +27,108 @@
#include "tree-iterator.h"
#include "cilk.h"
+bool cilk_ignorable_spawn_rhs_op (tree);
+bool cilk_recognize_spawn (tree, tree *);
+
+/* Return TRUE if T is a FUNCTION_DECL for a type-conversion operator. */
+
+static bool
+is_conversion_operator_function_decl_p (tree t) {
+ if (TREE_CODE (t) != FUNCTION_DECL)
+ return false;
+
+ return DECL_NAME (t) && IDENTIFIER_TYPENAME_P (DECL_NAME (t));
+}
+
+/* Recursively traverse EXP to search for a CILK_SPAWN_STMT subtree. Return the
+ CILK_SPAWN_STMT subtree if found; otherwise, the last subtree searched. */
+
+static tree
+find_spawn (tree exp)
+{
+ /* Happens with C++ TARGET_EXPR. */
+ if (exp == NULL_TREE)
+ return exp;
+
+ if (cilk_ignorable_spawn_rhs_op (exp))
+ return find_spawn (TREE_OPERAND (exp, 0));
+
+ switch (TREE_CODE (exp))
+ {
+ case AGGR_INIT_EXPR:
+ {
+ /* Check for initialization via a constructor call that represents
+ implicit conversion. */
+ if (AGGR_INIT_VIA_CTOR_P (exp) && aggr_init_expr_nargs (exp) == 2)
+ return find_spawn (AGGR_INIT_EXPR_ARG (exp, 1));
+
+ /* Check for initialization via a call to a type-conversion
+ operator. */
+ tree fn = AGGR_INIT_EXPR_FN (exp);
+ if (TREE_CODE (fn) == ADDR_EXPR
+ && is_conversion_operator_function_decl_p (TREE_OPERAND (fn, 0))
+ && aggr_init_expr_nargs (exp) == 1)
+ return find_spawn (AGGR_INIT_EXPR_ARG (exp, 0));
+ }
+ break;
+
+ case CALL_EXPR:
+ {
+ /* Check for a call to a type-conversion operator. */
+ tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
+ if (is_conversion_operator_function_decl_p (fndecl)
+ && call_expr_nargs (exp) == 1)
+ return find_spawn (CALL_EXPR_ARG (exp, 0));
+ }
+ break;
+
+ case TARGET_EXPR:
+ return find_spawn (TARGET_EXPR_INITIAL (exp));
+
+ case CLEANUP_POINT_EXPR:
+ case COMPOUND_EXPR:
+ case EXPR_STMT:
+ return find_spawn (TREE_OPERAND (exp, 0));
+
+ default:
+ break;
+ }
+
+ return exp;
+}
+
+/* Returns true if *EXP0 is a recognized form of spawn. Recognized forms are,
+ after conversion to void, a call expression at outer level or an assignment
+ at outer level with the right hand side being a spawned call.
+ In addition to this, it also unwraps the CILK_SPAWN_STMT cover from the
+ CALL_EXPR that is being spawned.
+ Note that `=' in C++ may turn into a CALL_EXPR rather than a MODIFY_EXPR. */
+
+bool
+cilk_cp_detect_spawn_and_unwrap (tree *exp0)
+{
+ tree exp = *exp0;
+
+ if (!TREE_SIDE_EFFECTS (exp))
+ return false;
+
+ /* Strip off any conversion to void. It does not affect whether spawn
+ is supported here. */
+ if (TREE_CODE (exp) == CONVERT_EXPR && VOID_TYPE_P (TREE_TYPE (exp)))
+ exp = TREE_OPERAND (exp, 0);
+
+ if (TREE_CODE (exp) == MODIFY_EXPR || TREE_CODE (exp) == INIT_EXPR)
+ exp = TREE_OPERAND (exp, 1);
+
+ exp = find_spawn (exp);
+ if (exp == NULL_TREE)
+ return false;
+
+ /* Now we should have a CALL_EXPR with a CILK_SPAWN_STMT wrapper around
+ it, or return false. */
+ return cilk_recognize_spawn (exp, exp0);
+}
+
/* Callback for cp_walk_tree to validate the body of a pragma simd loop
or _cilk_for loop.
===================================================================
@@ -11,7 +11,7 @@
int main()
{
- std::vector<double> x = _Cilk_spawn f(); /* { dg-error "invalid use of" } */
+ std::vector<double> x = _Cilk_spawn f ();
std::vector<double> y = f();
_Cilk_sync;
return 0;
===================================================================
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-fcilkplus" } */
+
+struct A1 {
+};
+
+struct A2 {
+ A2 () {}
+ A2 (const A2&) {}
+};
+
+struct B1 {
+ operator A1 () {
+ return A1 ();
+ }
+};
+
+B1 fb1 () {
+ return B1 ();
+}
+
+struct B2 {
+ operator A2 () {
+ return A2 ();
+ }
+};
+
+B2 fb2 () {
+ return B2 ();
+}
+
+void t1 () {
+ A1 a1 = _Cilk_spawn fb1 ();
+}
+
+void t2 () {
+ A2 a2 = _Cilk_spawn fb2 ();
+}
===================================================================
@@ -0,0 +1,68 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c++11 -fcilkplus" } */
+
+struct A1 {
+ A1 () {}
+ A1 (const A1&) {}
+};
+
+A1 fa1 () {
+ return A1 ();
+}
+
+struct A2 {
+ A2 () {}
+ A2 (A2&&) {}
+};
+
+A2 fa2 () {
+ A2 ();
+}
+
+struct B1 {
+};
+
+B1 fb1 () {
+ return B1 ();
+}
+
+struct A3 {
+ A3 (const B1&) {}
+};
+
+struct A4 {
+ A4 (B1) {}
+};
+
+struct B2 {
+ B2 () {}
+ B2 (const B2&) {}
+};
+
+B2 fb2 () {
+ return B2 ();
+}
+
+struct A5 {
+ A5 (B2) {}
+};
+
+void t1 () {
+ A1 a1 = _Cilk_spawn fa1 ();
+}
+
+void t2 () {
+ A2 a2 = _Cilk_spawn fa2 ();
+}
+
+void t3 () {
+ A3 a3 = _Cilk_spawn fb1 ();
+}
+
+void t4 () {
+ A4 a4 = _Cilk_spawn fb1 ();
+}
+
+void t5 () {
+ A5 a5 = _Cilk_spawn fb2 ();
+}