Global.h 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // Global.h //
  4. // Copyright (C) Microsoft Corporation. All rights reserved. //
  5. // This file is distributed under the University of Illinois Open Source //
  6. // License. See LICENSE.TXT for details. //
  7. // //
  8. // Provides important declarations global to all DX Compiler code. //
  9. // //
  10. ///////////////////////////////////////////////////////////////////////////////
  11. #pragma once
  12. #ifdef _WIN32
  13. // Redeclare some macros to not depend on winerror.h
  14. #define DXC_FAILED(hr) (((HRESULT)(hr)) < 0)
  15. #ifndef _HRESULT_DEFINED
  16. #define _HRESULT_DEFINED
  17. #ifndef _Return_type_success_
  18. typedef long HRESULT;
  19. #else
  20. typedef _Return_type_success_(return >= 0) long HRESULT;
  21. #endif // _Return_type_success_
  22. #endif // !_HRESULT_DEFINED
  23. #endif // _WIN32
  24. #include <stdarg.h>
  25. #include <system_error>
  26. #include "dxc/Support/exception.h"
  27. #include "dxc/Support/WinAdapter.h"
  28. ///////////////////////////////////////////////////////////////////////////////
  29. // Memory allocation support.
  30. //
  31. // This mechanism ties into the C++ new and delete operators.
  32. //
  33. // Other allocators may be used in specific situations, eg sub-allocators or
  34. // the COM allocator for interop. This is the preferred allocator in general,
  35. // however, as it eventually allows the library user to specify their own.
  36. //
  37. struct IMalloc;
  38. // Used by DllMain to set up and tear down per-thread tracking.
  39. HRESULT DxcInitThreadMalloc() throw();
  40. void DxcCleanupThreadMalloc() throw();
  41. // Used by APIs entry points to set up per-thread/invocation allocator.
  42. // Setting the IMalloc on the thread increases the reference count,
  43. // clearing it decreases it.
  44. void DxcSetThreadMallocToDefault() throw();
  45. void DxcClearThreadMalloc() throw();
  46. // Used to retrieve the current invocation's allocator or perform an alloc/free/realloc.
  47. IMalloc *DxcGetThreadMallocNoRef() throw();
  48. class DxcThreadMalloc {
  49. public:
  50. explicit DxcThreadMalloc(IMalloc *pMallocOrNull) throw();
  51. ~DxcThreadMalloc();
  52. IMalloc *GetInstalledAllocator() const { return p; }
  53. private:
  54. // Copy constructor and assignment are dangerous and should always be
  55. // deleted...
  56. DxcThreadMalloc(const DxcThreadMalloc &) = delete;
  57. DxcThreadMalloc &operator =(const DxcThreadMalloc &) = delete;
  58. // Move constructor and assignment should be OK to be added if needed.
  59. DxcThreadMalloc(DxcThreadMalloc &&) = delete;
  60. DxcThreadMalloc &operator =(DxcThreadMalloc &&) = delete;
  61. IMalloc *p;
  62. IMalloc *pPrior;
  63. };
  64. ///////////////////////////////////////////////////////////////////////////////
  65. // Error handling support.
  66. void CheckLLVMErrorCode(const std::error_code &ec);
  67. /******************************************************************************
  68. Project-wide macros
  69. ******************************************************************************/
  70. #define SAFE_RELEASE(p) { if (p) { (p)->Release(); (p) = nullptr; } }
  71. #define SAFE_ADDREF(p) { if (p) { (p)->AddRef(); } }
  72. #define SAFE_DELETE_ARRAY(p) { delete [](p); p = nullptr; }
  73. #define SAFE_DELETE(p) { delete (p); p = nullptr; }
  74. // VH is used in other DXC projects, but it's also a typedef in llvm.
  75. // Use the IFC (IfFailedCleanup) set of conventions.
  76. #define IFC(x) { hr = (x); if (DXC_FAILED(hr)) goto Cleanup; }
  77. #define IFR(x) { HRESULT __hr = (x); if (DXC_FAILED(__hr)) return __hr; }
  78. #define IFRBOOL(x,y){ if (!(x)) return (y); }
  79. #define IFCBOOL(x,y){ if (!(x)) { hr = (y); goto Cleanup; } }
  80. #define IFCOOM(x) { if (nullptr == (x)) { hr = E_OUTOFMEMORY; goto Cleanup; } }
  81. #define IFROOM(x) { if (nullptr == (x)) { return E_OUTOFMEMORY; } }
  82. #define IFCPTR(x) { if (nullptr == (x)) { hr = E_POINTER; goto Cleanup; }}
  83. #define IFT(x) { HRESULT __hr = (x); if (DXC_FAILED(__hr)) throw ::hlsl::Exception(__hr); }
  84. #define IFTBOOL(x,y){ if (!(x)) throw ::hlsl::Exception(y); }
  85. #define IFTOOM(x) { if (nullptr == (x)) { throw ::hlsl::Exception(E_OUTOFMEMORY); }}
  86. #define IFTPTR(x) { if (nullptr == (x)) { throw ::hlsl::Exception(E_POINTER); }}
  87. #define IFTARG(x) { if (!(x)) { throw ::hlsl::Exception(E_INVALIDARG); }}
  88. #define IFTLLVM(x) { CheckLLVMErrorCode(x); }
  89. #define IFTMSG(x, msg) { HRESULT __hr = (x); if (DXC_FAILED(__hr)) throw ::hlsl::Exception(__hr, msg); }
  90. #define IFTBOOLMSG(x, y, msg) { if (!(x)) throw ::hlsl::Exception(y, msg); }
  91. // Propagate an C++ exception into an HRESULT.
  92. #define CATCH_CPP_ASSIGN_HRESULT() \
  93. catch (std::bad_alloc&) { hr = E_OUTOFMEMORY; } \
  94. catch (hlsl::Exception& _hlsl_exception_) { \
  95. _Analysis_assume_(DXC_FAILED(_hlsl_exception_.hr)); \
  96. hr = _hlsl_exception_.hr; \
  97. } \
  98. catch (...) { hr = E_FAIL; }
  99. #define CATCH_CPP_RETURN_HRESULT() \
  100. catch (std::bad_alloc&) { return E_OUTOFMEMORY; } \
  101. catch (hlsl::Exception& _hlsl_exception_) { \
  102. _Analysis_assume_(DXC_FAILED(_hlsl_exception_.hr)); \
  103. return _hlsl_exception_.hr; \
  104. } \
  105. catch (...) { return E_FAIL; }
  106. template<typename T> T *VerifyNullAndThrow(T *p) {
  107. if (p == nullptr)
  108. throw std::bad_alloc();
  109. return p;
  110. }
  111. #define VNT(__p) VerifyNullAndThrow(__p)
  112. #ifdef _MSC_VER
  113. extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA(_In_opt_ const char *msg);
  114. inline void OutputDebugBytes(const void *ptr, size_t len) {
  115. const char digits[] = "0123456789abcdef";
  116. const unsigned char *pBytes = (const unsigned char *)ptr;
  117. const int bytesPerLine = 16;
  118. char buffer[bytesPerLine * 3 + 2 + 1];
  119. buffer[_countof(buffer) - 3] = '\r';
  120. buffer[_countof(buffer) - 2] = '\n';
  121. buffer[_countof(buffer) - 1] = '\0';
  122. char *pWrite = buffer;
  123. char *pEnd = buffer + _countof(buffer) - 3;
  124. while (len) {
  125. *pWrite++ = digits[(*pBytes & 0xF0) >> 4];
  126. *pWrite++ = digits[*pBytes & 0x0f];
  127. *pWrite++ = ' ';
  128. if (pWrite == pEnd) {
  129. OutputDebugStringA(buffer);
  130. pWrite = buffer;
  131. }
  132. --len;
  133. ++pBytes;
  134. }
  135. if (pWrite != buffer) {
  136. *pWrite = '\0';
  137. OutputDebugStringA(buffer);
  138. OutputDebugStringA("\r\n");
  139. }
  140. }
  141. inline void OutputDebugFormatA(_In_ _Printf_format_string_ _Null_terminated_ const char* pszFormat, ...) {
  142. char buffer[1024];
  143. va_list argList;
  144. va_start(argList, pszFormat);
  145. int count = vsprintf_s(buffer, _countof(buffer), pszFormat, argList);
  146. va_end(argList);
  147. OutputDebugStringA(buffer);
  148. if (count < 0) {
  149. OutputDebugStringA("...\n");
  150. }
  151. }
  152. #endif // _MSC_VER
  153. #ifdef DBG
  154. #ifdef _WIN32
  155. // DXASSERT is used to debug break when 'exp' evaluates to false and is only
  156. // intended for internal developer use. It is compiled out in free
  157. // builds. This means that code that should be in the final exe should
  158. // NOT be inside of of an DXASSERT test.
  159. //
  160. // 'fmt' is a printf-like format string; positional arguments aren't
  161. // supported.
  162. //
  163. // Example: DXASSERT(i > 10, "Hello %s", "World");
  164. // This prints 'Hello World (i > 10)' and breaks in the debugger if the
  165. // assertion doesn't hold.
  166. //
  167. #define DXASSERT_ARGS(exp, fmt, ...)\
  168. do { _Analysis_assume_(exp); if(!(exp)) { \
  169. OutputDebugFormatA("Error: \t%s\nFile:\n%s(%d)\nFunc:\t%s.\n\t" fmt "\n", "!(" #exp ")", __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__); \
  170. __debugbreak();\
  171. } } while(0)
  172. #define DXASSERT(exp, msg) DXASSERT_ARGS(exp, msg)
  173. #define DXASSERT_LOCALVAR(local, exp, msg) DXASSERT(exp, msg)
  174. #define DXASSERT_LOCALVAR_NOMSG(local, exp) DXASSERT_LOCALVAR(local, exp, "")
  175. #define DXASSERT_NOMSG(exp) DXASSERT(exp, "")
  176. #define DXVERIFY_NOMSG(exp) DXASSERT(exp, "")
  177. #else // _WIN32
  178. #include <cassert>
  179. #define DXASSERT_NOMSG assert
  180. #define DXASSERT_LOCALVAR(local, exp, msg) DXASSERT(exp, msg)
  181. #define DXASSERT_LOCALVAR_NOMSG(local, exp) DXASSERT_LOCALVAR(local, exp, "")
  182. #define DXVERIFY_NOMSG assert
  183. #define DXASSERT_ARGS(expr, fmt, ...) do { if (!(expr)) { fprintf(stderr, fmt, __VA_ARGS__); assert(false); } } while (0);
  184. #define DXASSERT(expr, msg) do { if (!(expr)) { fprintf(stderr, msg); assert(false && msg); } } while (0);
  185. #endif // _WIN32
  186. #else // DBG
  187. // DXASSERT_ARGS is disabled in free builds.
  188. #define DXASSERT_ARGS(exp, s, ...) _Analysis_assume_(exp)
  189. // DXASSERT is disabled in free builds.
  190. #define DXASSERT(exp, msg) _Analysis_assume_(exp)
  191. // DXASSERT_LOCALVAR is disabled in free builds, but we keep the local referenced to avoid a warning.
  192. #define DXASSERT_LOCALVAR(local, exp, msg) do { (void)(local); _Analysis_assume_(exp); } while (0)
  193. #define DXASSERT_LOCALVAR_NOMSG(local, exp) DXASSERT_LOCALVAR(local, exp, "")
  194. // DXASSERT_NOMSG is disabled in free builds.
  195. #define DXASSERT_NOMSG(exp) _Analysis_assume_(exp)
  196. // DXVERIFY is patterned after NT_VERIFY and will evaluate the expression
  197. #define DXVERIFY_NOMSG(exp) do { (void)(exp); _Analysis_assume_(exp); } while (0)
  198. #endif // DBG