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