From bd3009cdf637a7ad9f8373ff58baebe8cb6f5e80 Mon Sep 17 00:00:00 2001
From: Dan Kegel <dank@kegel.com>
Date: Sat, 29 Sep 2012 10:19:52 -0700
Subject: [PATCH 10/14] vcomp: better stubs for _vcomp_for_dynamic_init,
 _vcomp_for_dynamic_next

---
 dlls/vcomp/tests/main.c    |   64 ++++++++++++++++++++++++++++++++++++++++++++
 dlls/vcomp/vcomp.spec      |    4 +--
 dlls/vcomp/vcomp_private.h |   11 ++++++++
 dlls/vcomp/work.c          |   41 ++++++++++++++++++++++++++++
 4 files changed, 118 insertions(+), 2 deletions(-)

diff --git a/dlls/vcomp/tests/main.c b/dlls/vcomp/tests/main.c
index 96cfe4f..06cb43c 100644
--- a/dlls/vcomp/tests/main.c
+++ b/dlls/vcomp/tests/main.c
@@ -20,10 +20,15 @@
 
 #include "wine/test.h"
 
+/* Must match definition in ../vcomp_private.h */
+#define VCOMP_DYNAMIC_FOR_FLAGS_UP 0x40
+
 static int CDECL (*pomp_get_num_threads)(void);
 static int CDECL (*pomp_in_parallel)(void);
 static void CDECL (*pomp_set_num_threads)(int);
 static void WINAPIV (*p_vcomp_fork)(DWORD parallel, int nargs, void *helper, ...);
+static void CDECL (*p_vcomp_for_dynamic_init)(int flags, int first, int last, int mystep, int chunksize);
+static int CDECL (*p_vcomp_for_dynamic_next)(int *pcounter, int *pchunklimit);
 static void CDECL (*p_vcomp_for_static_end)(void);
 static void CDECL (*p_vcomp_for_static_simple_init)(int first, int last, int mystep, int step, int *pfirst, int *plast);
 
@@ -41,6 +46,8 @@ static BOOL init(void)
     GETFUNC(omp_in_parallel);
     GETFUNC(omp_set_num_threads);
     GETFUNC(_vcomp_fork);
+    GETFUNC(_vcomp_for_dynamic_init);
+    GETFUNC(_vcomp_for_dynamic_next);
     GETFUNC(_vcomp_for_static_end);
     GETFUNC(_vcomp_for_static_simple_init);
 
@@ -123,8 +130,64 @@ static void test_omp_in_parallel(void)
     pomp_set_num_threads(old_nt);
 }
 
+static LONG volatile ncalls;
 static LONG volatile nsum;
 
+static void __cdecl _test_vcomp_dynamic_for_worker_up(void)
+{
+    int i, limit;
+
+    InterlockedIncrement(&ncalls);
+
+    /* pragma omp schedule(dynamic,16) */
+    /* for (i=0; i<=17; i++) */
+    p_vcomp_for_dynamic_init(VCOMP_DYNAMIC_FOR_FLAGS_UP, 0, 17, 1, 16);
+    while (p_vcomp_for_dynamic_next(&i, &limit)) {
+        for (; i<=limit; i++) {
+            int j;
+            for (j=0; j<i; j++) {
+                InterlockedIncrement(&nsum);
+            }
+        }
+    }
+}
+
+static void __cdecl _test_vcomp_dynamic_for_worker_down(void)
+{
+    int i, limit;
+
+    InterlockedIncrement(&ncalls);
+
+    /* pragma omp schedule(dynamic,16) */
+    /* for (i=17; i>=0; i--) */
+    p_vcomp_for_dynamic_init(0, 17, 0, 1, 16);
+    while (p_vcomp_for_dynamic_next(&i, &limit)) {
+        for (; i>=limit; i--) {
+            int j;
+            for (j=0; j<i; j++) {
+                InterlockedIncrement(&nsum);
+            }
+        }
+    }
+}
+
+static void test_vcomp_dynamic_for(void)
+{
+    /* for (i=0; i<=17; i++) nsum += i; */
+    ncalls = 0;
+    nsum = 0;
+    p_vcomp_fork(1, 0, _test_vcomp_dynamic_for_worker_up);
+    ok(ncalls >= 1, "expected >= 1 call, got %d\n", ncalls);
+    ok(nsum == 9*17, "expected sum 9*17, got %d\n", nsum);
+
+    /* for (i=17; i>=0; i--) nsum += i; */
+    ncalls = 0;
+    nsum = 0;
+    p_vcomp_fork(1, 0, _test_vcomp_dynamic_for_worker_down);
+    ok(ncalls >= 1, "expected >= 1 call, got %d\n", ncalls);
+    ok(nsum == 9*17, "expected sum 9*17, got %d\n", nsum);
+}
+
 static void __cdecl _test_vcomp_for_static_simple_init_worker(void)
 {
     int i, my_limit;
@@ -160,5 +223,6 @@ START_TEST(main)
 
     test_vcomp_fork();
     test_omp_in_parallel();
+    test_vcomp_dynamic_for();
     test_vcomp_for_static_simple_init();
 }
diff --git a/dlls/vcomp/vcomp.spec b/dlls/vcomp/vcomp.spec
index 7d79259..383ae22 100644
--- a/dlls/vcomp/vcomp.spec
+++ b/dlls/vcomp/vcomp.spec
@@ -55,9 +55,9 @@
 @ stub _vcomp_copyprivate_receive
 @ stub _vcomp_enter_critsect
 @ stub _vcomp_flush
-@ stub _vcomp_for_dynamic_init
+@ cdecl _vcomp_for_dynamic_init(long long long long long)
 @ stub _vcomp_for_dynamic_init_i8
-@ stub _vcomp_for_dynamic_next
+@ cdecl _vcomp_for_dynamic_next(ptr)
 @ stub _vcomp_for_dynamic_next_i8
 @ cdecl _vcomp_for_static_end()
 @ stub _vcomp_for_static_init
diff --git a/dlls/vcomp/vcomp_private.h b/dlls/vcomp/vcomp_private.h
index f71b55e..999089f 100644
--- a/dlls/vcomp/vcomp_private.h
+++ b/dlls/vcomp/vcomp_private.h
@@ -23,6 +23,15 @@
 
 struct vcomp_team {
     struct vcomp_team *parent;
+    union {
+        struct {
+            int counter;
+            int step;
+            int iterations_remaining;
+            int chunksize;
+            int flags;
+        } dyn_for;
+    } work;
 };
 
 extern DWORD vcomp_context_tls_idx;
@@ -31,4 +40,6 @@ static inline struct vcomp_team *vcomp_get_team(void)
     return (struct vcomp_team *)TlsGetValue(vcomp_context_tls_idx);
 }
 
+#define VCOMP_DYNAMIC_FOR_FLAGS_UP 0x40
+
 #endif
diff --git a/dlls/vcomp/work.c b/dlls/vcomp/work.c
index 0f9ff78..5cd2fb1 100644
--- a/dlls/vcomp/work.c
+++ b/dlls/vcomp/work.c
@@ -25,9 +25,50 @@
 #include "windef.h"
 #include "winbase.h"
 #include "wine/debug.h"
+#include "vcomp_private.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(vcomp);
 
+void CDECL _vcomp_for_dynamic_init(int flags, int first, int last, int mystep, int chunksize)
+{
+    struct vcomp_team *pt = vcomp_get_team();
+
+    TRACE("(%d, %d, %d, %d, %d): stub\n", flags, first, last, mystep, chunksize);
+    pt->work.dyn_for.counter = first;
+    pt->work.dyn_for.chunksize = chunksize;
+    pt->work.dyn_for.flags = flags;
+    pt->work.dyn_for.step = mystep;
+    if (flags & VCOMP_DYNAMIC_FOR_FLAGS_UP) {
+        pt->work.dyn_for.iterations_remaining = 1 + (last - first) / mystep;
+    } else {
+        pt->work.dyn_for.iterations_remaining = 1 + (first - last) / mystep;
+    }
+}
+
+int CDECL _vcomp_for_dynamic_next(int *pcounter, int *pchunklimit)
+{
+    int n;
+    struct vcomp_team *pt = vcomp_get_team();
+
+    TRACE("(%p, %p): stub.\n", pcounter, pchunklimit);
+    n = pt->work.dyn_for.chunksize;
+    if (n > pt->work.dyn_for.iterations_remaining)
+        n = pt->work.dyn_for.iterations_remaining;
+    *pcounter = pt->work.dyn_for.counter;
+    if (pt->work.dyn_for.flags & VCOMP_DYNAMIC_FOR_FLAGS_UP) {
+        pt->work.dyn_for.counter += pt->work.dyn_for.step * n;
+        *pchunklimit = pt->work.dyn_for.counter - 1;
+    } else {
+        pt->work.dyn_for.counter -= pt->work.dyn_for.step * n;
+        *pchunklimit = pt->work.dyn_for.counter + 1;
+    }
+    pt->work.dyn_for.iterations_remaining -= n;
+
+    TRACE("counter %d, iterations_remaining %d, n %d, returning %d\n",
+       pt->work.dyn_for.counter, pt->work.dyn_for.iterations_remaining, n, (n > 0));
+    return (n > 0);
+}
+
 void CDECL _vcomp_for_static_simple_init(int first, int last, int mystep, int step, int *pfirst, int *plast)
 {
     TRACE("(%d, %d, %d, %d, %p, %p): stub\n", first, last, mystep, step, pfirst, plast);
-- 
1.7.9.5

