DxilExportMap.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // DxilExportMap.cpp //
  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. // dxilutil::ExportMap for handling -exports option. //
  9. // //
  10. ///////////////////////////////////////////////////////////////////////////////
  11. #include "dxc/Support/Global.h"
  12. #include "dxc/DXIL/DxilUtil.h"
  13. #include "dxc/HLSL/DxilExportMap.h"
  14. #include "dxc/DXIL/DxilTypeSystem.h"
  15. #include "llvm/Support/raw_ostream.h"
  16. #include "llvm/ADT/StringRef.h"
  17. #include "llvm/ADT/StringSet.h"
  18. #include "llvm/ADT/SmallVector.h"
  19. #include "llvm/ADT/DenseSet.h"
  20. #include "llvm/ADT/DenseMap.h"
  21. #include "llvm/IR/Function.h"
  22. #include <string>
  23. #include <vector>
  24. #include <set>
  25. using namespace llvm;
  26. using namespace hlsl;
  27. namespace hlsl {
  28. namespace dxilutil {
  29. void ExportMap::clear() {
  30. m_ExportMap.clear();
  31. }
  32. bool ExportMap::empty() const {
  33. return m_ExportMap.empty();
  34. }
  35. bool ExportMap::ParseExports(const std::vector<std::string> &exportOpts, llvm::raw_ostream &errors) {
  36. for (auto &str : exportOpts) {
  37. llvm::StringRef exports = StoreString(str);
  38. size_t start = 0;
  39. size_t end = llvm::StringRef::npos;
  40. // def1;def2;...
  41. while (true) {
  42. end = exports.find_first_of(';', start);
  43. llvm::StringRef exportDef = exports.slice(start, end);
  44. // def: export1[[,export2,...]=internal]
  45. llvm::StringRef internalName = exportDef;
  46. size_t equals = exportDef.find_first_of('=');
  47. if (equals != llvm::StringRef::npos) {
  48. internalName = exportDef.substr(equals + 1);
  49. size_t exportStart = 0;
  50. while (true) {
  51. size_t comma = exportDef.find_first_of(',', exportStart);
  52. if (comma == llvm::StringRef::npos || comma > equals)
  53. break;
  54. if (exportStart < comma)
  55. Add(exportDef.slice(exportStart, comma), internalName);
  56. exportStart = comma + 1;
  57. }
  58. if (exportStart < equals)
  59. Add(exportDef.slice(exportStart, equals), internalName);
  60. } else {
  61. Add(internalName);
  62. }
  63. if (equals == 0 || internalName.empty()) {
  64. errors << "Invalid syntax for -exports: '" << exportDef
  65. << "'. Syntax is: export1[[,export2,...]=internal][;...]";
  66. return false;
  67. }
  68. if (end == llvm::StringRef::npos)
  69. break;
  70. start = end + 1;
  71. }
  72. }
  73. return true;
  74. }
  75. void ExportMap::Add(llvm::StringRef exportName, llvm::StringRef internalName) {
  76. // Incoming strings may be escaped (because they originally come from arguments)
  77. // Unescape them here, if necessary
  78. if (exportName.startswith("\\")) {
  79. std::string str;
  80. llvm::raw_string_ostream os(str);
  81. PrintUnescapedString(exportName, os);
  82. exportName = StoreString(os.str());
  83. }
  84. if (internalName.startswith("\\")) {
  85. std::string str;
  86. llvm::raw_string_ostream os(str);
  87. PrintUnescapedString(internalName, os);
  88. internalName = StoreString(os.str());
  89. }
  90. if (internalName.empty())
  91. internalName = exportName;
  92. exportName = DemangleFunctionName(exportName);
  93. m_ExportMap[internalName].insert(exportName);
  94. }
  95. ExportMap::const_iterator ExportMap::GetExportsByName(llvm::StringRef Name) const {
  96. ExportMap::const_iterator it = m_ExportMap.find(Name);
  97. StringRef unmangled = DemangleFunctionName(Name);
  98. if (it == end()) {
  99. if (Name.startswith(ManglingPrefix)) {
  100. it = m_ExportMap.find(unmangled);
  101. }
  102. else if (Name.startswith(EntryPrefix)) {
  103. it = m_ExportMap.find(Name.substr(strlen(EntryPrefix)));
  104. }
  105. }
  106. return it;
  107. }
  108. bool ExportMap::IsExported(llvm::StringRef original) const {
  109. if (m_ExportMap.empty())
  110. return true;
  111. return GetExportsByName(original) != end();
  112. }
  113. void ExportMap::BeginProcessing() {
  114. m_ExportNames.clear();
  115. m_NameCollisions.clear();
  116. m_UnusedExports.clear();
  117. for (auto &it : m_ExportMap) {
  118. m_UnusedExports.emplace(it.getKey());
  119. }
  120. }
  121. bool ExportMap::ProcessFunction(llvm::Function *F, bool collisionAvoidanceRenaming) {
  122. // Skip if already added. This can happen due to patch constant functions.
  123. if (m_RenameMap.find(F) != m_RenameMap.end())
  124. return true;
  125. StringRef originalName = F->getName();
  126. StringRef unmangled = DemangleFunctionName(originalName);
  127. auto it = GetExportsByName(F->getName());
  128. // Early out if not exported, and do optional collision avoidance
  129. if (it == end()) {
  130. F->setLinkage(GlobalValue::LinkageTypes::InternalLinkage);
  131. if (collisionAvoidanceRenaming) {
  132. std::string internalName = (Twine("internal.") + unmangled).str();
  133. internalName = dxilutil::ReplaceFunctionName(originalName, internalName);
  134. F->setName(internalName);
  135. }
  136. return false;
  137. }
  138. F->setLinkage(GlobalValue::LinkageTypes::ExternalLinkage);
  139. // Add entry to m_RenameMap:
  140. auto &renames = m_RenameMap[F];
  141. const llvm::StringSet<> &exportRenames = it->getValue();
  142. llvm::StringRef internalName = it->getKey();
  143. // mark export used
  144. UseExport(internalName);
  145. // Add identity first
  146. auto itIdentity = exportRenames.find(unmangled);
  147. if (exportRenames.empty() || itIdentity != exportRenames.end()) {
  148. if (exportRenames.size() > 1)
  149. renames.insert(originalName);
  150. ExportName(originalName);
  151. } else if (collisionAvoidanceRenaming) {
  152. // do optional collision avoidance for exports being renamed
  153. std::string tempName = (Twine("temp.") + unmangled).str();
  154. tempName = dxilutil::ReplaceFunctionName(originalName, tempName);
  155. F->setName(tempName);
  156. }
  157. for (auto itName = exportRenames.begin(); itName != exportRenames.end(); itName++) {
  158. // Now add actual renames
  159. if (itName != itIdentity) {
  160. StringRef newName = StoreString(dxilutil::ReplaceFunctionName(F->getName(), itName->getKey()));
  161. renames.insert(newName);
  162. ExportName(newName);
  163. }
  164. }
  165. return true;
  166. }
  167. void ExportMap::RegisterExportedFunction(llvm::Function *F) {
  168. // Skip if already added
  169. if (m_RenameMap.find(F) != m_RenameMap.end())
  170. return;
  171. F->setLinkage(GlobalValue::LinkageTypes::ExternalLinkage);
  172. NameSet &renames = m_RenameMap[F];
  173. (void)(renames); // Don't actually add anything
  174. ExportName(F->getName());
  175. }
  176. void ExportMap::UseExport(llvm::StringRef internalName) {
  177. auto it = m_UnusedExports.find(internalName);
  178. if (it != m_UnusedExports.end())
  179. m_UnusedExports.erase(it);
  180. }
  181. void ExportMap::ExportName(llvm::StringRef exportName) {
  182. auto result = m_ExportNames.insert(exportName);
  183. if (!result.second) {
  184. // Already present, report collision
  185. m_NameCollisions.insert(exportName);
  186. }
  187. }
  188. bool ExportMap::EndProcessing() const {
  189. return m_UnusedExports.empty() && m_NameCollisions.empty();
  190. }
  191. llvm::StringRef ExportMap::StoreString(llvm::StringRef str) {
  192. return *m_StringStorage.insert(str).first;
  193. }
  194. } // dxilutil
  195. } // hlsl