[OpenMP][libomp] Implement KMP_DLSYM_NEXT on Windows

The interop API routines try to invoke external entries, but we did
not have support for KMP_DLSYM_NEXT on Windows. Also added proper
guards for STUB build.

Differential Revision: https://reviews.llvm.org/D149892

GitOrigin-RevId: 2f6eba7516b267bf3bbfee840fd61f7fb8cde1c3
diff --git a/runtime/src/kmp_ftn_entry.h b/runtime/src/kmp_ftn_entry.h
index bfd582a..038bccf 100644
--- a/runtime/src/kmp_ftn_entry.h
+++ b/runtime/src/kmp_ftn_entry.h
@@ -1549,14 +1549,14 @@
 
 // libomptarget, if loaded, provides this function
 int FTN_STDCALL FTN_GET_NUM_INTEROP_PROPERTIES(const omp_interop_t interop) {
-#if KMP_MIC || KMP_OS_DARWIN || defined(KMP_STUB)
+#if KMP_OS_DARWIN || defined(KMP_STUB)
   return 0;
 #else
   int (*fptr)(const omp_interop_t);
   if ((*(void **)(&fptr) = KMP_DLSYM_NEXT("omp_get_num_interop_properties")))
     return (*fptr)(interop);
   return 0;
-#endif // KMP_MIC || KMP_OS_DARWIN || KMP_OS_WINDOWS || defined(KMP_STUB)
+#endif
 }
 
 /// TODO Convert FTN_GET_INTEROP_XXX functions into a macro like interop.cpp
@@ -1564,57 +1564,81 @@
 intptr_t FTN_STDCALL FTN_GET_INTEROP_INT(const omp_interop_t interop,
                                          omp_interop_property_t property_id,
                                          int *err) {
+#if KMP_OS_DARWIN || defined(KMP_STUB)
+  return 0;
+#else
   intptr_t (*fptr)(const omp_interop_t, omp_interop_property_t, int *);
   if ((*(void **)(&fptr) = KMP_DLSYM_NEXT("omp_get_interop_int")))
     return (*fptr)(interop, property_id, err);
   return 0;
+#endif
 }
 
 // libomptarget, if loaded, provides this function
 void *FTN_STDCALL FTN_GET_INTEROP_PTR(const omp_interop_t interop,
                                       omp_interop_property_t property_id,
                                       int *err) {
+#if KMP_OS_DARWIN || defined(KMP_STUB)
+  return nullptr;
+#else
   void *(*fptr)(const omp_interop_t, omp_interop_property_t, int *);
   if ((*(void **)(&fptr) = KMP_DLSYM_NEXT("omp_get_interop_ptr")))
     return (*fptr)(interop, property_id, err);
   return nullptr;
+#endif
 }
 
 // libomptarget, if loaded, provides this function
 const char *FTN_STDCALL FTN_GET_INTEROP_STR(const omp_interop_t interop,
                                             omp_interop_property_t property_id,
                                             int *err) {
+#if KMP_OS_DARWIN || defined(KMP_STUB)
+  return nullptr;
+#else
   const char *(*fptr)(const omp_interop_t, omp_interop_property_t, int *);
   if ((*(void **)(&fptr) = KMP_DLSYM_NEXT("omp_get_interop_str")))
     return (*fptr)(interop, property_id, err);
   return nullptr;
+#endif
 }
 
 // libomptarget, if loaded, provides this function
 const char *FTN_STDCALL FTN_GET_INTEROP_NAME(
     const omp_interop_t interop, omp_interop_property_t property_id) {
+#if KMP_OS_DARWIN || defined(KMP_STUB)
+  return nullptr;
+#else
   const char *(*fptr)(const omp_interop_t, omp_interop_property_t);
   if ((*(void **)(&fptr) = KMP_DLSYM_NEXT("omp_get_interop_name")))
     return (*fptr)(interop, property_id);
   return nullptr;
+#endif
 }
 
 // libomptarget, if loaded, provides this function
 const char *FTN_STDCALL FTN_GET_INTEROP_TYPE_DESC(
     const omp_interop_t interop, omp_interop_property_t property_id) {
+#if KMP_OS_DARWIN || defined(KMP_STUB)
+  return nullptr;
+#else
   const char *(*fptr)(const omp_interop_t, omp_interop_property_t);
   if ((*(void **)(&fptr) = KMP_DLSYM_NEXT("omp_get_interop_type_desc")))
     return (*fptr)(interop, property_id);
   return nullptr;
+#endif
 }
 
 // libomptarget, if loaded, provides this function
 const char *FTN_STDCALL FTN_GET_INTEROP_RC_DESC(
     const omp_interop_t interop, omp_interop_property_t property_id) {
+#if KMP_OS_DARWIN || defined(KMP_STUB)
+  return nullptr;
+#else
   const char *(*fptr)(const omp_interop_t, omp_interop_property_t);
   if ((*(void **)(&fptr) = KMP_DLSYM_NEXT("omp_get_interop_rec_desc")))
     return (*fptr)(interop, property_id);
   return nullptr;
+#endif
 }
 
 // display environment variables when requested
diff --git a/runtime/src/kmp_os.h b/runtime/src/kmp_os.h
index c78f3ee..fec589a 100644
--- a/runtime/src/kmp_os.h
+++ b/runtime/src/kmp_os.h
@@ -1282,9 +1282,9 @@
 
 // Symbol lookup on Linux/Windows
 #if KMP_OS_WINDOWS
-extern void *__kmp_lookup_symbol(const char *name);
+extern void *__kmp_lookup_symbol(const char *name, bool next = false);
 #define KMP_DLSYM(name) __kmp_lookup_symbol(name)
-#define KMP_DLSYM_NEXT(name) nullptr
+#define KMP_DLSYM_NEXT(name) __kmp_lookup_symbol(name, true)
 #else
 #define KMP_DLSYM(name) dlsym(RTLD_DEFAULT, name)
 #define KMP_DLSYM_NEXT(name) dlsym(RTLD_NEXT, name)
diff --git a/runtime/src/z_Windows_NT_util.cpp b/runtime/src/z_Windows_NT_util.cpp
index ed62bc3..eb18efc 100644
--- a/runtime/src/z_Windows_NT_util.cpp
+++ b/runtime/src/z_Windows_NT_util.cpp
@@ -1669,7 +1669,7 @@
 } //__kmp_get_load_balance()
 
 // Find symbol from the loaded modules
-void *__kmp_lookup_symbol(const char *name) {
+void *__kmp_lookup_symbol(const char *name, bool next) {
   HANDLE process = GetCurrentProcess();
   DWORD needed;
   HMODULE *modules = nullptr;
@@ -1681,8 +1681,19 @@
     free(modules);
     return nullptr;
   }
+  HMODULE curr_module = nullptr;
+  if (next) {
+    // Current module needs to be skipped if next flag is true
+    if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+                           (LPCTSTR)&__kmp_lookup_symbol, &curr_module)) {
+      free(modules);
+      return nullptr;
+    }
+  }
   void *proc = nullptr;
   for (uint32_t i = 0; i < num_modules; i++) {
+    if (next && modules[i] == curr_module)
+      continue;
     proc = (void *)GetProcAddress(modules[i], name);
     if (proc)
       break;