On 19 Aug 13:55, Bernd Schmidt wrote:
> On 08/19/2014 12:41 PM, Ilya Verbin wrote:
> >For the functions it's not so easy to identify which of them to add into the
> >table, e.g.:
> > #pragma omp target
> > #pragma omp parallel
> > x++;
> >Here 2 functions with "omp declare target" attribute are created. But only
> >the outer must be added to the table.
> >So I believe that expand_omp_target is better place for the functions.
>
> Hmm, ok. Can you elaborate how this happens and why only one must be
> added to the table?
Here is gimple for this testcase:
foo ()
{
/* prepare data */
__builtin_GOMP_target (-1, foo._omp_fn.0, /* data */);
}
foo._omp_fn.0 (struct .omp_data_t.0 * .omp_data_i)
{
/* prepare data */
__builtin_GOMP_parallel (foo._omp_fn.1, /* data */);
}
foo._omp_fn.1 (struct .omp_data_s.1 * .omp_data_i)
{
_3 = .omp_data_i_2(D)->x;
_4 = _3 + 1;
.omp_data_i_2(D)->x = _4;
}
Both fn.0 and fn.1 can be executed on host and on target, therefore they have
"omp declare target" attribute. And there are 2 alternatives during runtime:
1. GOMP_target calls fn.0 on host, which calls fn.1 on host.
2. GOMP_target offloads fn.0 and fn.1, and runs fn.0 on target, which calls
fn.1.
So, there is only one "entry point" for GOMP_target - fn.0, and GOMP_target
can't run fn.1 on target directly, that's why only fn.0 must be added to the
table.
-- Ilya