name_mapper_test.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  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 <string>
  15. #include <vector>
  16. #include "gmock/gmock.h"
  17. #include "source/name_mapper.h"
  18. #include "test/test_fixture.h"
  19. #include "test/unit_spirv.h"
  20. namespace spvtools {
  21. namespace {
  22. using spvtest::ScopedContext;
  23. using ::testing::Eq;
  24. TEST(TrivialNameTest, Samples) {
  25. auto mapper = GetTrivialNameMapper();
  26. EXPECT_EQ(mapper(1), "1");
  27. EXPECT_EQ(mapper(1999), "1999");
  28. EXPECT_EQ(mapper(1024), "1024");
  29. }
  30. // A test case for the name mappers that actually look at an assembled module.
  31. struct NameIdCase {
  32. std::string assembly; // Input assembly text
  33. uint32_t id;
  34. std::string expected_name;
  35. };
  36. using FriendlyNameTest =
  37. spvtest::TextToBinaryTestBase<::testing::TestWithParam<NameIdCase>>;
  38. TEST_P(FriendlyNameTest, SingleMapping) {
  39. ScopedContext context(SPV_ENV_UNIVERSAL_1_1);
  40. auto words = CompileSuccessfully(GetParam().assembly, SPV_ENV_UNIVERSAL_1_1);
  41. auto friendly_mapper =
  42. FriendlyNameMapper(context.context, words.data(), words.size());
  43. NameMapper mapper = friendly_mapper.GetNameMapper();
  44. EXPECT_THAT(mapper(GetParam().id), Eq(GetParam().expected_name))
  45. << GetParam().assembly << std::endl
  46. << " for id " << GetParam().id;
  47. }
  48. INSTANTIATE_TEST_SUITE_P(ScalarType, FriendlyNameTest,
  49. ::testing::ValuesIn(std::vector<NameIdCase>{
  50. {"%1 = OpTypeVoid", 1, "void"},
  51. {"%1 = OpTypeBool", 1, "bool"},
  52. {"%1 = OpTypeInt 8 0", 1, "uchar"},
  53. {"%1 = OpTypeInt 8 1", 1, "char"},
  54. {"%1 = OpTypeInt 16 0", 1, "ushort"},
  55. {"%1 = OpTypeInt 16 1", 1, "short"},
  56. {"%1 = OpTypeInt 32 0", 1, "uint"},
  57. {"%1 = OpTypeInt 32 1", 1, "int"},
  58. {"%1 = OpTypeInt 64 0", 1, "ulong"},
  59. {"%1 = OpTypeInt 64 1", 1, "long"},
  60. {"%1 = OpTypeInt 1 0", 1, "u1"},
  61. {"%1 = OpTypeInt 1 1", 1, "i1"},
  62. {"%1 = OpTypeInt 33 0", 1, "u33"},
  63. {"%1 = OpTypeInt 33 1", 1, "i33"},
  64. {"%1 = OpTypeFloat 16", 1, "half"},
  65. {"%1 = OpTypeFloat 32", 1, "float"},
  66. {"%1 = OpTypeFloat 64", 1, "double"},
  67. {"%1 = OpTypeFloat 10", 1, "fp10"},
  68. {"%1 = OpTypeFloat 55", 1, "fp55"},
  69. }));
  70. INSTANTIATE_TEST_SUITE_P(
  71. VectorType, FriendlyNameTest,
  72. ::testing::ValuesIn(std::vector<NameIdCase>{
  73. {"%1 = OpTypeBool %2 = OpTypeVector %1 1", 2, "v1bool"},
  74. {"%1 = OpTypeBool %2 = OpTypeVector %1 2", 2, "v2bool"},
  75. {"%1 = OpTypeBool %2 = OpTypeVector %1 3", 2, "v3bool"},
  76. {"%1 = OpTypeBool %2 = OpTypeVector %1 4", 2, "v4bool"},
  77. {"%1 = OpTypeInt 8 0 %2 = OpTypeVector %1 2", 2, "v2uchar"},
  78. {"%1 = OpTypeInt 16 1 %2 = OpTypeVector %1 3", 2, "v3short"},
  79. {"%1 = OpTypeInt 32 0 %2 = OpTypeVector %1 4", 2, "v4uint"},
  80. {"%1 = OpTypeInt 64 1 %2 = OpTypeVector %1 3", 2, "v3long"},
  81. {"%1 = OpTypeInt 20 0 %2 = OpTypeVector %1 4", 2, "v4u20"},
  82. {"%1 = OpTypeInt 21 1 %2 = OpTypeVector %1 3", 2, "v3i21"},
  83. {"%1 = OpTypeFloat 32 %2 = OpTypeVector %1 2", 2, "v2float"},
  84. // OpName overrides the element name.
  85. {"OpName %1 \"time\" %1 = OpTypeFloat 32 %2 = OpTypeVector %1 2", 2,
  86. "v2time"},
  87. }));
  88. INSTANTIATE_TEST_SUITE_P(
  89. MatrixType, FriendlyNameTest,
  90. ::testing::ValuesIn(std::vector<NameIdCase>{
  91. {"%1 = OpTypeBool %2 = OpTypeVector %1 2 %3 = OpTypeMatrix %2 2", 3,
  92. "mat2v2bool"},
  93. {"%1 = OpTypeFloat 32 %2 = OpTypeVector %1 2 %3 = OpTypeMatrix %2 3", 3,
  94. "mat3v2float"},
  95. {"%1 = OpTypeFloat 32 %2 = OpTypeVector %1 2 %3 = OpTypeMatrix %2 4", 3,
  96. "mat4v2float"},
  97. {"OpName %1 \"time\" %1 = OpTypeFloat 32 %2 = OpTypeVector %1 2 %3 = "
  98. "OpTypeMatrix %2 4",
  99. 3, "mat4v2time"},
  100. {"OpName %2 \"lat_long\" %1 = OpTypeFloat 32 %2 = OpTypeVector %1 2 %3 "
  101. "= OpTypeMatrix %2 4",
  102. 3, "mat4lat_long"},
  103. }));
  104. INSTANTIATE_TEST_SUITE_P(
  105. OpName, FriendlyNameTest,
  106. ::testing::ValuesIn(std::vector<NameIdCase>{
  107. {"OpName %1 \"abcdefg\"", 1, "abcdefg"},
  108. {"OpName %1 \"Hello world!\"", 1, "Hello_world_"},
  109. {"OpName %1 \"0123456789\"", 1, "0123456789"},
  110. {"OpName %1 \"_\"", 1, "_"},
  111. // An empty string is not valid for SPIR-V assembly IDs.
  112. {"OpName %1 \"\"", 1, "_"},
  113. // Test uniqueness when presented with things mapping to "_"
  114. {"OpName %1 \"\" OpName %2 \"\"", 1, "_"},
  115. {"OpName %1 \"\" OpName %2 \"\"", 2, "__0"},
  116. {"OpName %1 \"\" OpName %2 \"\" OpName %3 \"_\"", 3, "__1"},
  117. // Test uniqueness of names that are forced to be
  118. // numbers.
  119. {"OpName %1 \"2\" OpName %2 \"2\"", 1, "2"},
  120. {"OpName %1 \"2\" OpName %2 \"2\"", 2, "2_0"},
  121. // Test uniqueness in the face of forward references
  122. // for Ids that don't already have friendly names.
  123. // In particular, the first OpDecorate assigns the name, and
  124. // the second one can't override it.
  125. {"OpDecorate %1 Volatile OpDecorate %1 Restrict", 1, "1"},
  126. // But a forced name can override the name that
  127. // would have been assigned via the OpDecorate
  128. // forward reference.
  129. {"OpName %1 \"mememe\" OpDecorate %1 Volatile OpDecorate %1 Restrict",
  130. 1, "mememe"},
  131. // OpName can override other inferences. We assume valid instruction
  132. // ordering, where OpName precedes type definitions.
  133. {"OpName %1 \"myfloat\" %1 = OpTypeFloat 32", 1, "myfloat"},
  134. }));
  135. INSTANTIATE_TEST_SUITE_P(
  136. UniquenessHeuristic, FriendlyNameTest,
  137. ::testing::ValuesIn(std::vector<NameIdCase>{
  138. {"%1 = OpTypeVoid %2 = OpTypeVoid %3 = OpTypeVoid", 1, "void"},
  139. {"%1 = OpTypeVoid %2 = OpTypeVoid %3 = OpTypeVoid", 2, "void_0"},
  140. {"%1 = OpTypeVoid %2 = OpTypeVoid %3 = OpTypeVoid", 3, "void_1"},
  141. }));
  142. INSTANTIATE_TEST_SUITE_P(Arrays, FriendlyNameTest,
  143. ::testing::ValuesIn(std::vector<NameIdCase>{
  144. {"OpName %2 \"FortyTwo\" %1 = OpTypeFloat 32 "
  145. "%2 = OpConstant %1 42 %3 = OpTypeArray %1 %2",
  146. 3, "_arr_float_FortyTwo"},
  147. {"%1 = OpTypeInt 32 0 "
  148. "%2 = OpTypeRuntimeArray %1",
  149. 2, "_runtimearr_uint"},
  150. }));
  151. INSTANTIATE_TEST_SUITE_P(Structs, FriendlyNameTest,
  152. ::testing::ValuesIn(std::vector<NameIdCase>{
  153. {"%1 = OpTypeBool "
  154. "%2 = OpTypeStruct %1 %1 %1",
  155. 2, "_struct_2"},
  156. {"%1 = OpTypeBool "
  157. "%2 = OpTypeStruct %1 %1 %1 "
  158. "%3 = OpTypeStruct %2 %2",
  159. 3, "_struct_3"},
  160. }));
  161. INSTANTIATE_TEST_SUITE_P(
  162. Pointer, FriendlyNameTest,
  163. ::testing::ValuesIn(std::vector<NameIdCase>{
  164. {"%1 = OpTypeFloat 32 %2 = OpTypePointer Workgroup %1", 2,
  165. "_ptr_Workgroup_float"},
  166. {"%1 = OpTypeBool %2 = OpTypePointer Private %1", 2,
  167. "_ptr_Private_bool"},
  168. // OpTypeForwardPointer doesn't force generation of the name for its
  169. // target type.
  170. {"%1 = OpTypeBool OpTypeForwardPointer %2 Private %2 = OpTypePointer "
  171. "Private %1",
  172. 2, "_ptr_Private_bool"},
  173. }));
  174. INSTANTIATE_TEST_SUITE_P(ExoticTypes, FriendlyNameTest,
  175. ::testing::ValuesIn(std::vector<NameIdCase>{
  176. {"%1 = OpTypeEvent", 1, "Event"},
  177. {"%1 = OpTypeDeviceEvent", 1, "DeviceEvent"},
  178. {"%1 = OpTypeReserveId", 1, "ReserveId"},
  179. {"%1 = OpTypeQueue", 1, "Queue"},
  180. {"%1 = OpTypeOpaque \"hello world!\"", 1,
  181. "Opaque_hello_world_"},
  182. {"%1 = OpTypePipe ReadOnly", 1, "PipeReadOnly"},
  183. {"%1 = OpTypePipe WriteOnly", 1, "PipeWriteOnly"},
  184. {"%1 = OpTypePipe ReadWrite", 1, "PipeReadWrite"},
  185. {"%1 = OpTypePipeStorage", 1, "PipeStorage"},
  186. {"%1 = OpTypeNamedBarrier", 1, "NamedBarrier"},
  187. }));
  188. // Makes a test case for a BuiltIn variable declaration.
  189. NameIdCase BuiltInCase(std::string assembly_name, std::string expected) {
  190. return NameIdCase{std::string("OpDecorate %1 BuiltIn ") + assembly_name +
  191. " %1 = OpVariable %2 Input",
  192. 1, expected};
  193. }
  194. // Makes a test case for a BuiltIn variable declaration. In this overload,
  195. // the expected result is the same as the assembly name.
  196. NameIdCase BuiltInCase(std::string assembly_name) {
  197. return BuiltInCase(assembly_name, assembly_name);
  198. }
  199. // Makes a test case for a BuiltIn variable declaration. In this overload,
  200. // the expected result is the same as the assembly name, but with a "gl_"
  201. // prefix.
  202. NameIdCase BuiltInGLCase(std::string assembly_name) {
  203. return BuiltInCase(assembly_name, std::string("gl_") + assembly_name);
  204. }
  205. INSTANTIATE_TEST_SUITE_P(
  206. BuiltIns, FriendlyNameTest,
  207. ::testing::ValuesIn(std::vector<NameIdCase>{
  208. BuiltInGLCase("Position"),
  209. BuiltInGLCase("PointSize"),
  210. BuiltInGLCase("ClipDistance"),
  211. BuiltInGLCase("CullDistance"),
  212. BuiltInCase("VertexId", "gl_VertexID"),
  213. BuiltInCase("InstanceId", "gl_InstanceID"),
  214. BuiltInCase("PrimitiveId", "gl_PrimitiveID"),
  215. BuiltInCase("InvocationId", "gl_InvocationID"),
  216. BuiltInGLCase("Layer"),
  217. BuiltInGLCase("ViewportIndex"),
  218. BuiltInGLCase("TessLevelOuter"),
  219. BuiltInGLCase("TessLevelInner"),
  220. BuiltInGLCase("TessCoord"),
  221. BuiltInGLCase("PatchVertices"),
  222. BuiltInGLCase("FragCoord"),
  223. BuiltInGLCase("PointCoord"),
  224. BuiltInGLCase("FrontFacing"),
  225. BuiltInCase("SampleId", "gl_SampleID"),
  226. BuiltInGLCase("SamplePosition"),
  227. BuiltInGLCase("SampleMask"),
  228. BuiltInGLCase("FragDepth"),
  229. BuiltInGLCase("HelperInvocation"),
  230. BuiltInCase("NumWorkgroups", "gl_NumWorkGroups"),
  231. BuiltInCase("WorkgroupSize", "gl_WorkGroupSize"),
  232. BuiltInCase("WorkgroupId", "gl_WorkGroupID"),
  233. BuiltInCase("LocalInvocationId", "gl_LocalInvocationID"),
  234. BuiltInCase("GlobalInvocationId", "gl_GlobalInvocationID"),
  235. BuiltInGLCase("LocalInvocationIndex"),
  236. BuiltInCase("WorkDim"),
  237. BuiltInCase("GlobalSize"),
  238. BuiltInCase("EnqueuedWorkgroupSize"),
  239. BuiltInCase("GlobalOffset"),
  240. BuiltInCase("GlobalLinearId"),
  241. BuiltInCase("SubgroupSize"),
  242. BuiltInCase("SubgroupMaxSize"),
  243. BuiltInCase("NumSubgroups"),
  244. BuiltInCase("NumEnqueuedSubgroups"),
  245. BuiltInCase("SubgroupId"),
  246. BuiltInCase("SubgroupLocalInvocationId"),
  247. BuiltInGLCase("VertexIndex"),
  248. BuiltInGLCase("InstanceIndex"),
  249. BuiltInCase("SubgroupEqMaskKHR"),
  250. BuiltInCase("SubgroupGeMaskKHR"),
  251. BuiltInCase("SubgroupGtMaskKHR"),
  252. BuiltInCase("SubgroupLeMaskKHR"),
  253. BuiltInCase("SubgroupLtMaskKHR"),
  254. }));
  255. INSTANTIATE_TEST_SUITE_P(DebugNameOverridesBuiltin, FriendlyNameTest,
  256. ::testing::ValuesIn(std::vector<NameIdCase>{
  257. {"OpName %1 \"foo\" OpDecorate %1 BuiltIn WorkDim "
  258. "%1 = OpVariable %2 Input",
  259. 1, "foo"}}));
  260. INSTANTIATE_TEST_SUITE_P(
  261. SimpleIntegralConstants, FriendlyNameTest,
  262. ::testing::ValuesIn(std::vector<NameIdCase>{
  263. {"%1 = OpTypeInt 32 0 %2 = OpConstant %1 0", 2, "uint_0"},
  264. {"%1 = OpTypeInt 32 0 %2 = OpConstant %1 1", 2, "uint_1"},
  265. {"%1 = OpTypeInt 32 0 %2 = OpConstant %1 2", 2, "uint_2"},
  266. {"%1 = OpTypeInt 32 0 %2 = OpConstant %1 9", 2, "uint_9"},
  267. {"%1 = OpTypeInt 32 0 %2 = OpConstant %1 42", 2, "uint_42"},
  268. {"%1 = OpTypeInt 32 1 %2 = OpConstant %1 0", 2, "int_0"},
  269. {"%1 = OpTypeInt 32 1 %2 = OpConstant %1 1", 2, "int_1"},
  270. {"%1 = OpTypeInt 32 1 %2 = OpConstant %1 2", 2, "int_2"},
  271. {"%1 = OpTypeInt 32 1 %2 = OpConstant %1 9", 2, "int_9"},
  272. {"%1 = OpTypeInt 32 1 %2 = OpConstant %1 42", 2, "int_42"},
  273. {"%1 = OpTypeInt 32 1 %2 = OpConstant %1 -42", 2, "int_n42"},
  274. // Exotic bit widths
  275. {"%1 = OpTypeInt 33 0 %2 = OpConstant %1 0", 2, "u33_0"},
  276. {"%1 = OpTypeInt 33 1 %2 = OpConstant %1 10", 2, "i33_10"},
  277. {"%1 = OpTypeInt 33 1 %2 = OpConstant %1 -19", 2, "i33_n19"},
  278. }));
  279. INSTANTIATE_TEST_SUITE_P(
  280. SimpleFloatConstants, FriendlyNameTest,
  281. ::testing::ValuesIn(std::vector<NameIdCase>{
  282. {"%1 = OpTypeFloat 16\n%2 = OpConstant %1 0x1.ff4p+16", 2,
  283. "half_0x1_ff4p_16"},
  284. {"%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x1.d2cp-10", 2,
  285. "half_n0x1_d2cpn10"},
  286. // 32-bit floats
  287. {"%1 = OpTypeFloat 32\n%2 = OpConstant %1 -3.125", 2, "float_n3_125"},
  288. {"%1 = OpTypeFloat 32\n%2 = OpConstant %1 0x1.8p+128", 2,
  289. "float_0x1_8p_128"}, // NaN
  290. {"%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0x1.0002p+128", 2,
  291. "float_n0x1_0002p_128"}, // NaN
  292. {"%1 = OpTypeFloat 32\n%2 = OpConstant %1 0x1p+128", 2,
  293. "float_0x1p_128"}, // Inf
  294. {"%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0x1p+128", 2,
  295. "float_n0x1p_128"}, // -Inf
  296. // 64-bit floats
  297. {"%1 = OpTypeFloat 64\n%2 = OpConstant %1 -3.125", 2, "double_n3_125"},
  298. {"%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1.ffffffffffffap-1023", 2,
  299. "double_0x1_ffffffffffffapn1023"}, // small normal
  300. {"%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1.ffffffffffffap-1023", 2,
  301. "double_n0x1_ffffffffffffapn1023"},
  302. {"%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1.8p+1024", 2,
  303. "double_0x1_8p_1024"}, // NaN
  304. {"%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1.0002p+1024", 2,
  305. "double_n0x1_0002p_1024"}, // NaN
  306. {"%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1p+1024", 2,
  307. "double_0x1p_1024"}, // Inf
  308. {"%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1p+1024", 2,
  309. "double_n0x1p_1024"}, // -Inf
  310. }));
  311. INSTANTIATE_TEST_SUITE_P(
  312. BooleanConstants, FriendlyNameTest,
  313. ::testing::ValuesIn(std::vector<NameIdCase>{
  314. {"%1 = OpTypeBool\n%2 = OpConstantTrue %1", 2, "true"},
  315. {"%1 = OpTypeBool\n%2 = OpConstantFalse %1", 2, "false"},
  316. }));
  317. } // namespace
  318. } // namespace spvtools