DxcLangExtensionsCommonHelper.h 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // DxcLangExtensionsCommonHelper.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 a helper class to implement language extensions to HLSL. //
  9. // //
  10. ///////////////////////////////////////////////////////////////////////////////
  11. #pragma once
  12. #include "dxc/Support/Unicode.h"
  13. #include "dxc/Support/FileIOHelper.h"
  14. #include "dxc/dxcapi.internal.h"
  15. #include <vector>
  16. namespace llvm {
  17. class raw_string_ostream;
  18. class CallInst;
  19. class Value;
  20. }
  21. namespace hlsl {
  22. class DxcLangExtensionsCommonHelper {
  23. private:
  24. llvm::SmallVector<std::string, 2> m_semanticDefines;
  25. llvm::SmallVector<std::string, 2> m_semanticDefineExclusions;
  26. llvm::SmallVector<std::string, 2> m_defines;
  27. llvm::SmallVector<CComPtr<IDxcIntrinsicTable>, 2> m_intrinsicTables;
  28. CComPtr<IDxcSemanticDefineValidator> m_semanticDefineValidator;
  29. std::string m_semanticDefineMetaDataName;
  30. std::string m_targetTriple;
  31. HRESULT STDMETHODCALLTYPE RegisterIntoVector(LPCWSTR name, llvm::SmallVector<std::string, 2>& here)
  32. {
  33. try {
  34. IFTPTR(name);
  35. std::string s;
  36. if (!Unicode::UTF16ToUTF8String(name, &s)) {
  37. throw ::hlsl::Exception(E_INVALIDARG);
  38. }
  39. here.push_back(s);
  40. return S_OK;
  41. }
  42. CATCH_CPP_RETURN_HRESULT();
  43. }
  44. public:
  45. const llvm::SmallVector<std::string, 2>& GetSemanticDefines() const { return m_semanticDefines; }
  46. const llvm::SmallVector<std::string, 2>& GetSemanticDefineExclusions() const { return m_semanticDefineExclusions; }
  47. const llvm::SmallVector<std::string, 2>& GetDefines() const { return m_defines; }
  48. llvm::SmallVector<CComPtr<IDxcIntrinsicTable>, 2>& GetIntrinsicTables(){ return m_intrinsicTables; }
  49. const std::string &GetSemanticDefineMetadataName() { return m_semanticDefineMetaDataName; }
  50. const std::string &GetTargetTriple() { return m_targetTriple; }
  51. HRESULT STDMETHODCALLTYPE RegisterSemanticDefine(LPCWSTR name)
  52. {
  53. return RegisterIntoVector(name, m_semanticDefines);
  54. }
  55. HRESULT STDMETHODCALLTYPE RegisterSemanticDefineExclusion(LPCWSTR name)
  56. {
  57. return RegisterIntoVector(name, m_semanticDefineExclusions);
  58. }
  59. HRESULT STDMETHODCALLTYPE RegisterDefine(LPCWSTR name)
  60. {
  61. return RegisterIntoVector(name, m_defines);
  62. }
  63. HRESULT STDMETHODCALLTYPE RegisterIntrinsicTable(_In_ IDxcIntrinsicTable* pTable)
  64. {
  65. try {
  66. IFTPTR(pTable);
  67. LPCSTR tableName = nullptr;
  68. IFT(pTable->GetTableName(&tableName));
  69. IFTPTR(tableName);
  70. IFTARG(strcmp(tableName, "op") != 0); // "op" is reserved for builtin intrinsics
  71. for (auto &&table : m_intrinsicTables) {
  72. LPCSTR otherTableName = nullptr;
  73. IFT(table->GetTableName(&otherTableName));
  74. IFTPTR(otherTableName);
  75. IFTARG(strcmp(tableName, otherTableName) != 0); // Added a duplicate table name
  76. }
  77. m_intrinsicTables.push_back(pTable);
  78. return S_OK;
  79. }
  80. CATCH_CPP_RETURN_HRESULT();
  81. }
  82. // Set the validator used to validate semantic defines.
  83. // Only one validator stored and used to run validation.
  84. HRESULT STDMETHODCALLTYPE SetSemanticDefineValidator(_In_ IDxcSemanticDefineValidator* pValidator) {
  85. if (pValidator == nullptr)
  86. return E_POINTER;
  87. m_semanticDefineValidator = pValidator;
  88. return S_OK;
  89. }
  90. HRESULT STDMETHODCALLTYPE SetSemanticDefineMetaDataName(LPCSTR name) {
  91. try {
  92. m_semanticDefineMetaDataName = name;
  93. return S_OK;
  94. }
  95. CATCH_CPP_RETURN_HRESULT();
  96. }
  97. HRESULT STDMETHODCALLTYPE SetTargetTriple(LPCSTR triple) {
  98. try {
  99. m_targetTriple = triple;
  100. return S_OK;
  101. }
  102. CATCH_CPP_RETURN_HRESULT();
  103. }
  104. // Get the name of the dxil intrinsic function.
  105. std::string GetIntrinsicName(UINT opcode) {
  106. LPCSTR pName = "";
  107. for (IDxcIntrinsicTable *table : m_intrinsicTables) {
  108. if (SUCCEEDED(table->GetIntrinsicName(opcode, &pName))) {
  109. return pName;
  110. }
  111. }
  112. return "";
  113. }
  114. // Get the dxil opcode for the extension opcode if one exists.
  115. // Return true if the opcode was mapped successfully.
  116. bool GetDxilOpCode(UINT opcode, UINT &dxilOpcode) {
  117. for (IDxcIntrinsicTable *table : m_intrinsicTables) {
  118. if (SUCCEEDED(table->GetDxilOpCode(opcode, &dxilOpcode))) {
  119. return true;
  120. }
  121. }
  122. return false;
  123. }
  124. // Result of validating a semantic define.
  125. // Stores any warning or error messages produced by the validator.
  126. // Successful validation means that there are no warning or error messages.
  127. struct SemanticDefineValidationResult {
  128. std::string Warning;
  129. std::string Error;
  130. bool HasError() { return Error.size() > 0; }
  131. bool HasWarning() { return Warning.size() > 0; }
  132. static SemanticDefineValidationResult Success() {
  133. return SemanticDefineValidationResult();
  134. }
  135. };
  136. // Use the contained semantice define validator to validate the given semantic define.
  137. SemanticDefineValidationResult ValidateSemanticDefine(const std::string &name, const std::string &value) {
  138. if (!m_semanticDefineValidator)
  139. return SemanticDefineValidationResult::Success();
  140. // Blobs for getting restul from validator. Strings for returning results to caller.
  141. CComPtr<IDxcBlobEncoding> pError;
  142. CComPtr<IDxcBlobEncoding> pWarning;
  143. std::string error;
  144. std::string warning;
  145. // Run semantic define validator.
  146. HRESULT result = m_semanticDefineValidator->GetSemanticDefineWarningsAndErrors(name.c_str(), value.c_str(), &pWarning, &pError);
  147. if (FAILED(result)) {
  148. // Failure indicates it was not able to even run validation so
  149. // we cannot say whether the define is invalid or not. Return a
  150. // generic error message about failure to run the valiadator.
  151. error = "failed to run semantic define validator for: ";
  152. error.append(name); error.append("="); error.append(value);
  153. return SemanticDefineValidationResult{ warning, error };
  154. }
  155. // Define a little function to convert encoded blob into a string.
  156. auto GetErrorAsString = [&name](const CComPtr<IDxcBlobEncoding> &pBlobString) -> std::string {
  157. CComPtr<IDxcBlobUtf8> pUTF8BlobStr;
  158. if (SUCCEEDED(hlsl::DxcGetBlobAsUtf8(pBlobString, DxcGetThreadMallocNoRef(), &pUTF8BlobStr)))
  159. return std::string(pUTF8BlobStr->GetStringPointer(), pUTF8BlobStr->GetStringLength());
  160. else
  161. return std::string("invalid semantic define " + name);
  162. };
  163. // Check to see if any warnings or errors were produced.
  164. if (pError && pError->GetBufferSize()) {
  165. error = GetErrorAsString(pError);
  166. }
  167. if (pWarning && pWarning->GetBufferSize()) {
  168. warning = GetErrorAsString(pWarning);
  169. }
  170. return SemanticDefineValidationResult{ warning, error };
  171. }
  172. DxcLangExtensionsCommonHelper()
  173. : m_semanticDefineMetaDataName("hlsl.semdefs"),
  174. m_targetTriple("dxil-ms-dx") {}
  175. };
  176. // Use this macro to embed an implementation that will delegate to a field.
  177. // Note that QueryInterface still needs to return the vtable.
  178. #define DXC_LANGEXTENSIONS_HELPER_IMPL(_helper_field_) \
  179. HRESULT STDMETHODCALLTYPE RegisterIntrinsicTable(_In_ IDxcIntrinsicTable *pTable) override { \
  180. DxcThreadMalloc TM(m_pMalloc); \
  181. return (_helper_field_).RegisterIntrinsicTable(pTable); \
  182. } \
  183. HRESULT STDMETHODCALLTYPE RegisterSemanticDefine(LPCWSTR name) override { \
  184. DxcThreadMalloc TM(m_pMalloc); \
  185. return (_helper_field_).RegisterSemanticDefine(name); \
  186. } \
  187. HRESULT STDMETHODCALLTYPE RegisterSemanticDefineExclusion(LPCWSTR name) override { \
  188. DxcThreadMalloc TM(m_pMalloc); \
  189. return (_helper_field_).RegisterSemanticDefineExclusion(name); \
  190. } \
  191. HRESULT STDMETHODCALLTYPE RegisterDefine(LPCWSTR name) override { \
  192. DxcThreadMalloc TM(m_pMalloc); \
  193. return (_helper_field_).RegisterDefine(name); \
  194. } \
  195. HRESULT STDMETHODCALLTYPE SetSemanticDefineValidator(_In_ IDxcSemanticDefineValidator* pValidator) override { \
  196. DxcThreadMalloc TM(m_pMalloc); \
  197. return (_helper_field_).SetSemanticDefineValidator(pValidator); \
  198. } \
  199. HRESULT STDMETHODCALLTYPE SetSemanticDefineMetaDataName(LPCSTR name) override { \
  200. DxcThreadMalloc TM(m_pMalloc); \
  201. return (_helper_field_).SetSemanticDefineMetaDataName(name); \
  202. } \
  203. HRESULT STDMETHODCALLTYPE SetTargetTriple(LPCSTR name) override { \
  204. DxcThreadMalloc TM(m_pMalloc); \
  205. return (_helper_field_).SetTargetTriple(name); \
  206. } \
  207. } // namespace hlsl