name_mapper.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. // Copyright (c) 2016 Google Inc.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "source/name_mapper.h"
  15. #include <algorithm>
  16. #include <cassert>
  17. #include <iterator>
  18. #include <sstream>
  19. #include <string>
  20. #include <unordered_map>
  21. #include <unordered_set>
  22. #include "spirv-tools/libspirv.h"
  23. #include "source/latest_version_spirv_header.h"
  24. #include "source/parsed_operand.h"
  25. namespace spvtools {
  26. namespace {
  27. // Converts a uint32_t to its string decimal representation.
  28. std::string to_string(uint32_t id) {
  29. // Use stringstream, since some versions of Android compilers lack
  30. // std::to_string.
  31. std::stringstream os;
  32. os << id;
  33. return os.str();
  34. }
  35. } // anonymous namespace
  36. NameMapper GetTrivialNameMapper() { return to_string; }
  37. FriendlyNameMapper::FriendlyNameMapper(const spv_const_context context,
  38. const uint32_t* code,
  39. const size_t wordCount)
  40. : grammar_(AssemblyGrammar(context)) {
  41. spv_diagnostic diag = nullptr;
  42. // We don't care if the parse fails.
  43. spvBinaryParse(context, this, code, wordCount, nullptr,
  44. ParseInstructionForwarder, &diag);
  45. spvDiagnosticDestroy(diag);
  46. }
  47. std::string FriendlyNameMapper::NameForId(uint32_t id) {
  48. auto iter = name_for_id_.find(id);
  49. if (iter == name_for_id_.end()) {
  50. // It must have been an invalid module, so just return a trivial mapping.
  51. // We don't care about uniqueness.
  52. return to_string(id);
  53. } else {
  54. return iter->second;
  55. }
  56. }
  57. std::string FriendlyNameMapper::Sanitize(const std::string& suggested_name) {
  58. if (suggested_name.empty()) return "_";
  59. // Otherwise, replace invalid characters by '_'.
  60. std::string result;
  61. std::string valid =
  62. "abcdefghijklmnopqrstuvwxyz"
  63. "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  64. "_0123456789";
  65. std::transform(suggested_name.begin(), suggested_name.end(),
  66. std::back_inserter(result), [&valid](const char c) {
  67. return (std::string::npos == valid.find(c)) ? '_' : c;
  68. });
  69. return result;
  70. }
  71. void FriendlyNameMapper::SaveName(uint32_t id,
  72. const std::string& suggested_name) {
  73. if (name_for_id_.find(id) != name_for_id_.end()) return;
  74. const std::string sanitized_suggested_name = Sanitize(suggested_name);
  75. std::string name = sanitized_suggested_name;
  76. auto inserted = used_names_.insert(name);
  77. if (!inserted.second) {
  78. const std::string base_name = sanitized_suggested_name + "_";
  79. for (uint32_t index = 0; !inserted.second; ++index) {
  80. name = base_name + to_string(index);
  81. inserted = used_names_.insert(name);
  82. }
  83. }
  84. name_for_id_[id] = name;
  85. }
  86. void FriendlyNameMapper::SaveBuiltInName(uint32_t target_id,
  87. uint32_t built_in) {
  88. #define GLCASE(name) \
  89. case SpvBuiltIn##name: \
  90. SaveName(target_id, "gl_" #name); \
  91. return;
  92. #define GLCASE2(name, suggested) \
  93. case SpvBuiltIn##name: \
  94. SaveName(target_id, "gl_" #suggested); \
  95. return;
  96. #define CASE(name) \
  97. case SpvBuiltIn##name: \
  98. SaveName(target_id, #name); \
  99. return;
  100. switch (built_in) {
  101. GLCASE(Position)
  102. GLCASE(PointSize)
  103. GLCASE(ClipDistance)
  104. GLCASE(CullDistance)
  105. GLCASE2(VertexId, VertexID)
  106. GLCASE2(InstanceId, InstanceID)
  107. GLCASE2(PrimitiveId, PrimitiveID)
  108. GLCASE2(InvocationId, InvocationID)
  109. GLCASE(Layer)
  110. GLCASE(ViewportIndex)
  111. GLCASE(TessLevelOuter)
  112. GLCASE(TessLevelInner)
  113. GLCASE(TessCoord)
  114. GLCASE(PatchVertices)
  115. GLCASE(FragCoord)
  116. GLCASE(PointCoord)
  117. GLCASE(FrontFacing)
  118. GLCASE2(SampleId, SampleID)
  119. GLCASE(SamplePosition)
  120. GLCASE(SampleMask)
  121. GLCASE(FragDepth)
  122. GLCASE(HelperInvocation)
  123. GLCASE2(NumWorkgroups, NumWorkGroups)
  124. GLCASE2(WorkgroupSize, WorkGroupSize)
  125. GLCASE2(WorkgroupId, WorkGroupID)
  126. GLCASE2(LocalInvocationId, LocalInvocationID)
  127. GLCASE2(GlobalInvocationId, GlobalInvocationID)
  128. GLCASE(LocalInvocationIndex)
  129. CASE(WorkDim)
  130. CASE(GlobalSize)
  131. CASE(EnqueuedWorkgroupSize)
  132. CASE(GlobalOffset)
  133. CASE(GlobalLinearId)
  134. CASE(SubgroupSize)
  135. CASE(SubgroupMaxSize)
  136. CASE(NumSubgroups)
  137. CASE(NumEnqueuedSubgroups)
  138. CASE(SubgroupId)
  139. CASE(SubgroupLocalInvocationId)
  140. GLCASE(VertexIndex)
  141. GLCASE(InstanceIndex)
  142. GLCASE(BaseInstance)
  143. CASE(SubgroupEqMaskKHR)
  144. CASE(SubgroupGeMaskKHR)
  145. CASE(SubgroupGtMaskKHR)
  146. CASE(SubgroupLeMaskKHR)
  147. CASE(SubgroupLtMaskKHR)
  148. default:
  149. break;
  150. }
  151. #undef GLCASE
  152. #undef GLCASE2
  153. #undef CASE
  154. }
  155. spv_result_t FriendlyNameMapper::ParseInstruction(
  156. const spv_parsed_instruction_t& inst) {
  157. const auto result_id = inst.result_id;
  158. switch (inst.opcode) {
  159. case SpvOpName:
  160. SaveName(inst.words[1], reinterpret_cast<const char*>(inst.words + 2));
  161. break;
  162. case SpvOpDecorate:
  163. // Decorations come after OpName. So OpName will take precedence over
  164. // decorations.
  165. //
  166. // In theory, we should also handle OpGroupDecorate. But that's unlikely
  167. // to occur.
  168. if (inst.words[2] == SpvDecorationBuiltIn) {
  169. assert(inst.num_words > 3);
  170. SaveBuiltInName(inst.words[1], inst.words[3]);
  171. }
  172. break;
  173. case SpvOpTypeVoid:
  174. SaveName(result_id, "void");
  175. break;
  176. case SpvOpTypeBool:
  177. SaveName(result_id, "bool");
  178. break;
  179. case SpvOpTypeInt: {
  180. std::string signedness;
  181. std::string root;
  182. const auto bit_width = inst.words[2];
  183. switch (bit_width) {
  184. case 8:
  185. root = "char";
  186. break;
  187. case 16:
  188. root = "short";
  189. break;
  190. case 32:
  191. root = "int";
  192. break;
  193. case 64:
  194. root = "long";
  195. break;
  196. default:
  197. root = to_string(bit_width);
  198. signedness = "i";
  199. break;
  200. }
  201. if (0 == inst.words[3]) signedness = "u";
  202. SaveName(result_id, signedness + root);
  203. } break;
  204. case SpvOpTypeFloat: {
  205. const auto bit_width = inst.words[2];
  206. switch (bit_width) {
  207. case 16:
  208. SaveName(result_id, "half");
  209. break;
  210. case 32:
  211. SaveName(result_id, "float");
  212. break;
  213. case 64:
  214. SaveName(result_id, "double");
  215. break;
  216. default:
  217. SaveName(result_id, std::string("fp") + to_string(bit_width));
  218. break;
  219. }
  220. } break;
  221. case SpvOpTypeVector:
  222. SaveName(result_id, std::string("v") + to_string(inst.words[3]) +
  223. NameForId(inst.words[2]));
  224. break;
  225. case SpvOpTypeMatrix:
  226. SaveName(result_id, std::string("mat") + to_string(inst.words[3]) +
  227. NameForId(inst.words[2]));
  228. break;
  229. case SpvOpTypeArray:
  230. SaveName(result_id, std::string("_arr_") + NameForId(inst.words[2]) +
  231. "_" + NameForId(inst.words[3]));
  232. break;
  233. case SpvOpTypeRuntimeArray:
  234. SaveName(result_id,
  235. std::string("_runtimearr_") + NameForId(inst.words[2]));
  236. break;
  237. case SpvOpTypePointer:
  238. SaveName(result_id, std::string("_ptr_") +
  239. NameForEnumOperand(SPV_OPERAND_TYPE_STORAGE_CLASS,
  240. inst.words[2]) +
  241. "_" + NameForId(inst.words[3]));
  242. break;
  243. case SpvOpTypePipe:
  244. SaveName(result_id,
  245. std::string("Pipe") +
  246. NameForEnumOperand(SPV_OPERAND_TYPE_ACCESS_QUALIFIER,
  247. inst.words[2]));
  248. break;
  249. case SpvOpTypeEvent:
  250. SaveName(result_id, "Event");
  251. break;
  252. case SpvOpTypeDeviceEvent:
  253. SaveName(result_id, "DeviceEvent");
  254. break;
  255. case SpvOpTypeReserveId:
  256. SaveName(result_id, "ReserveId");
  257. break;
  258. case SpvOpTypeQueue:
  259. SaveName(result_id, "Queue");
  260. break;
  261. case SpvOpTypeOpaque:
  262. SaveName(result_id,
  263. std::string("Opaque_") +
  264. Sanitize(reinterpret_cast<const char*>(inst.words + 2)));
  265. break;
  266. case SpvOpTypePipeStorage:
  267. SaveName(result_id, "PipeStorage");
  268. break;
  269. case SpvOpTypeNamedBarrier:
  270. SaveName(result_id, "NamedBarrier");
  271. break;
  272. case SpvOpTypeStruct:
  273. // Structs are mapped rather simplisitically. Just indicate that they
  274. // are a struct and then give the raw Id number.
  275. SaveName(result_id, std::string("_struct_") + to_string(result_id));
  276. break;
  277. case SpvOpConstantTrue:
  278. SaveName(result_id, "true");
  279. break;
  280. case SpvOpConstantFalse:
  281. SaveName(result_id, "false");
  282. break;
  283. case SpvOpConstant: {
  284. std::ostringstream value;
  285. EmitNumericLiteral(&value, inst, inst.operands[2]);
  286. auto value_str = value.str();
  287. // Use 'n' to signify negative. Other invalid characters will be mapped
  288. // to underscore.
  289. for (auto& c : value_str)
  290. if (c == '-') c = 'n';
  291. SaveName(result_id, NameForId(inst.type_id) + "_" + value_str);
  292. } break;
  293. default:
  294. // If this instruction otherwise defines an Id, then save a mapping for
  295. // it. This is needed to ensure uniqueness in there is an OpName with
  296. // string something like "1" that might collide with this result_id.
  297. // We should only do this if a name hasn't already been registered by some
  298. // previous forward reference.
  299. if (result_id && name_for_id_.find(result_id) == name_for_id_.end())
  300. SaveName(result_id, to_string(result_id));
  301. break;
  302. }
  303. return SPV_SUCCESS;
  304. }
  305. std::string FriendlyNameMapper::NameForEnumOperand(spv_operand_type_t type,
  306. uint32_t word) {
  307. spv_operand_desc desc = nullptr;
  308. if (SPV_SUCCESS == grammar_.lookupOperand(type, word, &desc)) {
  309. return desc->name;
  310. } else {
  311. // Invalid input. Just give something.
  312. return std::string("StorageClass") + to_string(word);
  313. }
  314. }
  315. } // namespace spvtools