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

Reply via email to