1283a215cSJonathan Peyton // RUN: %libomp-compile-and-run
2*93e17cfeSJonathan Peyton // RUN: %libomp-compile && env KMP_TASKLOOP_MIN_TASKS=1 %libomp-run
3283a215cSJonathan Peyton #include <stdio.h>
4283a215cSJonathan Peyton #include <omp.h>
5283a215cSJonathan Peyton #include "omp_my_sleep.h"
6283a215cSJonathan Peyton
7283a215cSJonathan Peyton #define N 4
8283a215cSJonathan Peyton #define GRAIN 10
9283a215cSJonathan Peyton #define STRIDE 3
10283a215cSJonathan Peyton
11283a215cSJonathan Peyton // globals
12283a215cSJonathan Peyton int th_counter[N];
13283a215cSJonathan Peyton int counter;
14283a215cSJonathan Peyton
15283a215cSJonathan Peyton
16283a215cSJonathan Peyton // Compiler-generated code (emulation)
17283a215cSJonathan Peyton typedef struct ident {
18283a215cSJonathan Peyton void* dummy;
19283a215cSJonathan Peyton } ident_t;
20283a215cSJonathan Peyton
21283a215cSJonathan Peyton typedef struct shar {
22283a215cSJonathan Peyton int(*pth_counter)[N];
23283a215cSJonathan Peyton int *pcounter;
24283a215cSJonathan Peyton int *pj;
25283a215cSJonathan Peyton } *pshareds;
26283a215cSJonathan Peyton
27283a215cSJonathan Peyton typedef struct task {
28283a215cSJonathan Peyton pshareds shareds;
29283a215cSJonathan Peyton int(* routine)(int,struct task*);
30283a215cSJonathan Peyton int part_id;
31283a215cSJonathan Peyton // privates:
32283a215cSJonathan Peyton unsigned long long lb; // library always uses ULONG
33283a215cSJonathan Peyton unsigned long long ub;
34283a215cSJonathan Peyton int st;
35283a215cSJonathan Peyton int last;
36283a215cSJonathan Peyton int i;
37283a215cSJonathan Peyton int j;
38283a215cSJonathan Peyton int th;
39283a215cSJonathan Peyton } *ptask, kmp_task_t;
40283a215cSJonathan Peyton
41283a215cSJonathan Peyton typedef int(* task_entry_t)( int, ptask );
42283a215cSJonathan Peyton
43283a215cSJonathan Peyton void
__task_dup_entry(ptask task_dst,ptask task_src,int lastpriv)44283a215cSJonathan Peyton __task_dup_entry(ptask task_dst, ptask task_src, int lastpriv)
45283a215cSJonathan Peyton {
46283a215cSJonathan Peyton // setup lastprivate flag
47283a215cSJonathan Peyton task_dst->last = lastpriv;
48283a215cSJonathan Peyton // could be constructor calls here...
49283a215cSJonathan Peyton }
50283a215cSJonathan Peyton
51283a215cSJonathan Peyton
52283a215cSJonathan Peyton // OpenMP RTL interfaces
53283a215cSJonathan Peyton typedef unsigned long long kmp_uint64;
54283a215cSJonathan Peyton typedef long long kmp_int64;
55283a215cSJonathan Peyton
56283a215cSJonathan Peyton #ifdef __cplusplus
57283a215cSJonathan Peyton extern "C" {
58283a215cSJonathan Peyton #endif
59283a215cSJonathan Peyton void
60283a215cSJonathan Peyton __kmpc_taskloop(ident_t *loc, int gtid, kmp_task_t *task, int if_val,
61283a215cSJonathan Peyton kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st,
62283a215cSJonathan Peyton int nogroup, int sched, kmp_int64 grainsize, void *task_dup );
63283a215cSJonathan Peyton ptask
64283a215cSJonathan Peyton __kmpc_omp_task_alloc( ident_t *loc, int gtid, int flags,
65283a215cSJonathan Peyton size_t sizeof_kmp_task_t, size_t sizeof_shareds,
66283a215cSJonathan Peyton task_entry_t task_entry );
67283a215cSJonathan Peyton void __kmpc_atomic_fixed4_add(void *id_ref, int gtid, int * lhs, int rhs);
68283a215cSJonathan Peyton int __kmpc_global_thread_num(void *id_ref);
69283a215cSJonathan Peyton #ifdef __cplusplus
70283a215cSJonathan Peyton }
71283a215cSJonathan Peyton #endif
72283a215cSJonathan Peyton
73283a215cSJonathan Peyton
74283a215cSJonathan Peyton // User's code
task_entry(int gtid,ptask task)75283a215cSJonathan Peyton int task_entry(int gtid, ptask task)
76283a215cSJonathan Peyton {
77283a215cSJonathan Peyton pshareds pshar = task->shareds;
78283a215cSJonathan Peyton for( task->i = task->lb; task->i <= (int)task->ub; task->i += task->st ) {
79283a215cSJonathan Peyton task->th = omp_get_thread_num();
80283a215cSJonathan Peyton __kmpc_atomic_fixed4_add(NULL,gtid,pshar->pcounter,1);
81283a215cSJonathan Peyton __kmpc_atomic_fixed4_add(NULL,gtid,&((*pshar->pth_counter)[task->th]),1);
82283a215cSJonathan Peyton task->j = task->i;
83283a215cSJonathan Peyton }
84283a215cSJonathan Peyton my_sleep( 0.1 ); // sleep 100 ms in order to allow other threads to steal tasks
85283a215cSJonathan Peyton if( task->last ) {
86283a215cSJonathan Peyton *(pshar->pj) = task->j; // lastprivate
87283a215cSJonathan Peyton }
88283a215cSJonathan Peyton return 0;
89283a215cSJonathan Peyton }
90283a215cSJonathan Peyton
main()91283a215cSJonathan Peyton int main()
92283a215cSJonathan Peyton {
93283a215cSJonathan Peyton int i, j, gtid = __kmpc_global_thread_num(NULL);
94283a215cSJonathan Peyton ptask task;
95283a215cSJonathan Peyton pshareds psh;
96283a215cSJonathan Peyton omp_set_dynamic(0);
97283a215cSJonathan Peyton counter = 0;
98283a215cSJonathan Peyton for( i=0; i<N; ++i )
99283a215cSJonathan Peyton th_counter[i] = 0;
100283a215cSJonathan Peyton #pragma omp parallel num_threads(N)
101283a215cSJonathan Peyton {
102283a215cSJonathan Peyton #pragma omp master
103283a215cSJonathan Peyton {
104283a215cSJonathan Peyton int gtid = __kmpc_global_thread_num(NULL);
105283a215cSJonathan Peyton /*
106283a215cSJonathan Peyton * This is what the OpenMP runtime calls correspond to:
107283a215cSJonathan Peyton #pragma omp taskloop num_tasks(N) lastprivate(j)
108283a215cSJonathan Peyton for( i=0; i<N*GRAIN*STRIDE-1; i+=STRIDE )
109283a215cSJonathan Peyton {
110283a215cSJonathan Peyton int th = omp_get_thread_num();
111283a215cSJonathan Peyton #pragma omp atomic
112283a215cSJonathan Peyton counter++;
113283a215cSJonathan Peyton #pragma omp atomic
114283a215cSJonathan Peyton th_counter[th]++;
115283a215cSJonathan Peyton j = i;
116283a215cSJonathan Peyton }
117283a215cSJonathan Peyton */
118283a215cSJonathan Peyton task = __kmpc_omp_task_alloc(NULL,gtid,1,sizeof(struct task),sizeof(struct shar),&task_entry);
119283a215cSJonathan Peyton psh = task->shareds;
120283a215cSJonathan Peyton psh->pth_counter = &th_counter;
121283a215cSJonathan Peyton psh->pcounter = &counter;
122283a215cSJonathan Peyton psh->pj = &j;
123283a215cSJonathan Peyton task->lb = 0;
124283a215cSJonathan Peyton task->ub = N*GRAIN*STRIDE-2;
125283a215cSJonathan Peyton task->st = STRIDE;
126283a215cSJonathan Peyton
127283a215cSJonathan Peyton __kmpc_taskloop(
128283a215cSJonathan Peyton NULL, // location
129283a215cSJonathan Peyton gtid, // gtid
130283a215cSJonathan Peyton task, // task structure
131283a215cSJonathan Peyton 1, // if clause value
132283a215cSJonathan Peyton &task->lb, // lower bound
133283a215cSJonathan Peyton &task->ub, // upper bound
134283a215cSJonathan Peyton STRIDE, // loop increment
135283a215cSJonathan Peyton 0, // 1 if nogroup specified
136283a215cSJonathan Peyton 2, // schedule type: 0-none, 1-grainsize, 2-num_tasks
137283a215cSJonathan Peyton N, // schedule value (ignored for type 0)
138283a215cSJonathan Peyton (void*)&__task_dup_entry // tasks duplication routine
139283a215cSJonathan Peyton );
140283a215cSJonathan Peyton } // end master
141283a215cSJonathan Peyton } // end parallel
142283a215cSJonathan Peyton // check results
143283a215cSJonathan Peyton if( j != N*GRAIN*STRIDE-STRIDE ) {
144283a215cSJonathan Peyton printf("Error in lastprivate, %d != %d\n",j,N*GRAIN*STRIDE-STRIDE);
145283a215cSJonathan Peyton return 1;
146283a215cSJonathan Peyton }
147283a215cSJonathan Peyton if( counter != N*GRAIN ) {
148283a215cSJonathan Peyton printf("Error, counter %d != %d\n",counter,N*GRAIN);
149283a215cSJonathan Peyton return 1;
150283a215cSJonathan Peyton }
151283a215cSJonathan Peyton for( i=0; i<N; ++i ) {
152283a215cSJonathan Peyton if( th_counter[i] % GRAIN ) {
153283a215cSJonathan Peyton printf("Error, th_counter[%d] = %d\n",i,th_counter[i]);
154283a215cSJonathan Peyton return 1;
155283a215cSJonathan Peyton }
156283a215cSJonathan Peyton }
157283a215cSJonathan Peyton printf("passed\n");
158283a215cSJonathan Peyton return 0;
159283a215cSJonathan Peyton }
160