On 11/21/2013 05:40 PM, Iyer, Balaji V wrote:
+/* Returns a TRY_CATCH_EXPR that will encapsulate BODY, EXCEPT_DATA and
+ EXCEPT_FLAG. */
+
+tree
+create_cilk_try_catch (tree except_flag, tree except_data, tree body)
+{
+ tree catch_list = alloc_stmt_list ();
+ append_to_statement_list (except_flag, &catch_list);
+ append_to_statement_list (except_data, &catch_list);
+ append_to_statement_list (do_begin_catch (), &catch_list);
+ append_to_statement_list (build_throw (NULL_TREE), &catch_list);
+ tree catch_tf_expr = build_stmt (EXPR_LOCATION (body), TRY_FINALLY_EXPR,
+ catch_list, do_end_catch (NULL_TREE));
+ catch_list = build2 (CATCH_EXPR, void_type_node, NULL_TREE,
+ catch_tf_expr);
+ tree try_catch_expr = build_stmt (EXPR_LOCATION (body), TRY_CATCH_EXPR,
+ body, catch_list);
+ return try_catch_expr;
+}
I had in mind something less cilk-specific: a function that takes two
tree operands, one for the body and one for the throwing path.
Basically, make catch_list a parameter and move the first two appends
back into the calling function.
The reason is that, when you have something like this:
_Cilk_spawn [=] { <body> } ();
I need to capture the function call (which in this case is the whole function)
and throw it into a nested function. The nested function implementation is
shared with C. If the function is stored in a variable then I can just send
that out to the nested function. I have added another constraint to make sure
the function is a spawning function, this way we can reduce more cases were
they are stored to a variable. The reason why I added this check in
finish_call_expr is that it seemed to be most straight-forward for me and only
place where I could do with least disruption (code-changes).
It looks like you're transforming any
[...] {...} (...);
into
auto lambda = [...]{...};
lambda(...);
which has significantly different semantics, particularly in terms of
the lifetime of the lambda object. In some of the Cilk online
documentation, I see:
When spawning named lambda functions, be careful that the lifespan of the
lambda extends at least until the next sync, or else the destructor for the
lambda will race with the spawned call. For example:
double i = g();
if (some condition) {
// named lambda with value capture of i
auto f = [=i]() { double d = sin(i); f(d); };
cilk_spawn f();
} // Ouch! destructor for f is in parallel with spawned call.
This would seem to apply even more to unnamed lambda functions, since
normally they would be destroyed at the end of the full-expression,
which must always be before the sync. Does the Intel compiler
implicitly extend the lifetime of a lambda called by cilk spawn? In any
case, we really don't want to do this for all calls to unnamed lambdas
just because we turned on cilk mode.
Jason