From eacaf5a58cb586d448b574ffd3109aac2dab4ca8 Mon Sep 17 00:00:00 2001 From: Greg Roth Date: Wed, 27 Jun 2018 11:42:23 -0600 Subject: [PATCH] [macos-port] Allow dxc and tests to run on mac (#1383) The REGEX_H define prevented the inclusion of an Apple system header. Not coincidentally, the same header regex_impl.h was derived from. Prevent Apple warning by splitting macro args with an #else. Add HLSL change comments too which were missing from the start. Search for libdxcompiler.dylib instead of .so on Apple. MacOS resolves symbols differently from Linux. Linux takes the first valid resolution and then uses it wherever it is referenced. MacOS more similar to Windows, favors symbols that are local to the compilation unit. This comes into play where functions set static globals such as the malloc tls and the IMalloc contained there. The dxc binary initializes these. For Linux, that's enough because all calls resolve to the ones from this binary because they are encountered first. MacOS calls that originate from within the dynamic library resolve to the local functions, which don't have their globals initialized. To initialize them, we need to do what is done in DLLMain in DXCompiler.cpp. Performing these calls results in duplicate initializations on Linux unless the calls in question are given visibility hidden. This is the default on Windows, but not on Unix OSes. --- include/dxc/Support/Global.h | 2 -- lib/DxcSupport/HLSLOptions.cpp | 8 ++++++++ lib/DxcSupport/dxcmem.cpp | 20 +++++++------------- lib/Support/regerror.c | 5 ++++- lib/Support/regex_impl.h | 6 +++--- tools/clang/tools/dxcompiler/DXCompiler.cpp | 18 ++++++++++++++++++ 6 files changed, 40 insertions(+), 19 deletions(-) diff --git a/include/dxc/Support/Global.h b/include/dxc/Support/Global.h index 47c68b028..b18cdf35d 100644 --- a/include/dxc/Support/Global.h +++ b/include/dxc/Support/Global.h @@ -60,8 +60,6 @@ IMalloc *DxcSwapThreadMallocOrDefault(IMalloc *pMalloc, IMalloc **ppPrior) throw // Used to retrieve the current invocation's allocator or perform an alloc/free/realloc. IMalloc *DxcGetThreadMallocNoRef() throw(); -_Ret_maybenull_ _Post_writable_byte_size_(nBytes) void *DxcThreadAlloc(size_t nBytes) throw(); -void DxcThreadFree(void *) throw(); struct DxcThreadMalloc { DxcThreadMalloc(IMalloc *pMallocOrNull) throw() { diff --git a/lib/DxcSupport/HLSLOptions.cpp b/lib/DxcSupport/HLSLOptions.cpp index d1adbe16b..4d1943a5e 100644 --- a/lib/DxcSupport/HLSLOptions.cpp +++ b/lib/DxcSupport/HLSLOptions.cpp @@ -49,6 +49,10 @@ namespace { static HlslOptTable *g_HlslOptTable; +#ifndef _WIN32 +#pragma GCC visibility push(hidden) +#endif + std::error_code hlsl::options::initHlslOptTable() { DXASSERT(g_HlslOptTable == nullptr, "else double-init"); g_HlslOptTable = new (std::nothrow) HlslOptTable(); @@ -66,6 +70,10 @@ const OptTable * hlsl::options::getHlslOptTable() { return g_HlslOptTable; } +#ifndef _WIN32 +#pragma GCC visibility pop +#endif + void DxcDefines::push_back(llvm::StringRef value) { // Skip empty defines. if (value.size() > 0) { diff --git a/lib/DxcSupport/dxcmem.cpp b/lib/DxcSupport/dxcmem.cpp index ae9331ab2..3bef28f06 100644 --- a/lib/DxcSupport/dxcmem.cpp +++ b/lib/DxcSupport/dxcmem.cpp @@ -21,19 +21,9 @@ static llvm::sys::ThreadLocal *g_ThreadMallocTls; static IMalloc *g_pDefaultMalloc; -// Used by DllMain to set up and tear down per-thread tracking. -HRESULT DxcInitThreadMalloc() throw(); -void DxcCleanupThreadMalloc() throw(); - -// Used by APIs that are entry points to set up per-thread/invocation allocator. -void DxcSetThreadMalloc(IMalloc *pMalloc) throw(); -void DxcSetThreadMallocOrDefault(IMalloc *pMalloc) throw(); -void DxcClearThreadMalloc() throw(); - -// Used to retrieve the current invocation's allocator or perform an alloc/free/realloc. -IMalloc *DxcGetThreadMallocNoRef() throw(); -_Ret_maybenull_ _Post_writable_byte_size_(nBytes) void *DxcThreadAlloc(size_t nBytes) throw(); -void DxcThreadFree(void *) throw(); +#ifndef _WIN32 +#pragma GCC visibility push(hidden) +#endif HRESULT DxcInitThreadMalloc() throw() { DXASSERT(g_pDefaultMalloc == nullptr, "else InitThreadMalloc already called"); @@ -96,3 +86,7 @@ IMalloc *DxcSwapThreadMalloc(IMalloc *pMalloc, IMalloc **ppPrior) throw() { IMalloc *DxcSwapThreadMallocOrDefault(IMalloc *pMallocOrNull, IMalloc **ppPrior) throw() { return DxcSwapThreadMalloc(pMallocOrNull ? pMallocOrNull : g_pDefaultMalloc, ppPrior); } + +#ifndef _WIN32 +#pragma GCC visibility pop +#endif diff --git a/lib/Support/regerror.c b/lib/Support/regerror.c index 9c7e0a6a0..95b3ae89c 100644 --- a/lib/Support/regerror.c +++ b/lib/Support/regerror.c @@ -108,12 +108,15 @@ llvm_regerror(int errcode, const llvm_regex_t *preg, _Out_writes_all_(errbuf_siz assert(strlen(r->name) < sizeof(convbuf)); (void) llvm_strlcpy(convbuf, r->name, sizeof convbuf); } else + // Begin HLSL Change #ifdef _WIN32 (void)_snprintf_s(convbuf, _countof(convbuf), _countof(convbuf), + "REG_0x%x", target); #else (void)snprintf(convbuf, sizeof convbuf, -#endif // WIN32 "REG_0x%x", target); +#endif // WIN32 + // End HLSL Change s = convbuf; } else s = r->explain; diff --git a/lib/Support/regex_impl.h b/lib/Support/regex_impl.h index 4340bbf03..bbf64cfb2 100644 --- a/lib/Support/regex_impl.h +++ b/lib/Support/regex_impl.h @@ -35,8 +35,8 @@ * @(#)regex.h 8.1 (Berkeley) 6/2/93 */ -#ifndef _REGEX_H_ -#define _REGEX_H_ +#ifndef _REGEX_IMPL_H_ // HLSL Change +#define _REGEX_IMPL_H_ // HLSL Change #include "dxc/Support/WinAdapter.h" // HLSL Change #include @@ -119,4 +119,4 @@ size_t llvm_strlcpy( } #endif -#endif /* !_REGEX_H_ */ +#endif /* !_REGEX_IMPL_H_ */ // HLSL Change diff --git a/tools/clang/tools/dxcompiler/DXCompiler.cpp b/tools/clang/tools/dxcompiler/DXCompiler.cpp index 894f2ea6d..77a6a9fcf 100644 --- a/tools/clang/tools/dxcompiler/DXCompiler.cpp +++ b/tools/clang/tools/dxcompiler/DXCompiler.cpp @@ -14,7 +14,9 @@ #include "dxc/Support/Global.h" #include "dxc/Support/WinIncludes.h" #include "dxc/Support/HLSLOptions.h" +#ifdef LLVM_ON_WIN32 #include "dxcetw.h" +#endif #include "dxillib.h" namespace hlsl { HRESULT SetupRegistryPassForHLSL(); } @@ -22,6 +24,7 @@ namespace hlsl { HRESULT SetupRegistryPassForHLSL(); } // C++ exception specification ignored except to indicate a function is not __declspec(nothrow) #pragma warning( disable : 4290 ) +#ifdef LLVM_ON_WIN32 // operator new and friends. void * __CRTDECL operator new(std::size_t size) throw(std::bad_alloc) { void * ptr = DxcGetThreadMallocNoRef()->Alloc(size); @@ -39,6 +42,7 @@ void __CRTDECL operator delete (void* ptr) throw() { void __CRTDECL operator delete (void* ptr, const std::nothrow_t& nothrow_constant) throw() { DxcGetThreadMallocNoRef()->Free(ptr); } +#endif static HRESULT InitMaybeFail() throw() { HRESULT hr; @@ -72,7 +76,20 @@ Cleanup: } return hr; } +#if defined(LLVM_ON_UNIX) +HRESULT __attribute__ ((constructor)) DllMain() { + return InitMaybeFail(); +} +void __attribute__ ((destructor)) DllShutdown() { + DxcSetThreadMallocOrDefault(nullptr); + ::hlsl::options::cleanupHlslOptTable(); + ::llvm::sys::fs::CleanupPerThreadFileSystem(); + ::llvm::llvm_shutdown(); + DxcClearThreadMalloc(); + DxcCleanupThreadMalloc(); +} +#else // LLVM_ON_UNIX BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD Reason, LPVOID reserved) { BOOL result = TRUE; if (Reason == DLL_PROCESS_ATTACH) { @@ -102,3 +119,4 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD Reason, LPVOID reserved) { return result; } +#endif // LLVM_ON_UNIX