unify_const_test.cpp 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997
  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 <tuple>
  16. #include <unordered_set>
  17. #include <utility>
  18. #include <vector>
  19. #include "test/opt/assembly_builder.h"
  20. #include "test/opt/pass_fixture.h"
  21. #include "test/opt/pass_utils.h"
  22. namespace spvtools {
  23. namespace opt {
  24. namespace {
  25. // Returns the types defining instructions commonly used in many tests.
  26. std::vector<std::string> CommonTypes() {
  27. return std::vector<std::string>{
  28. // clang-format off
  29. // scalar types
  30. "%bool = OpTypeBool",
  31. "%uint = OpTypeInt 32 0",
  32. "%int = OpTypeInt 32 1",
  33. "%uint64 = OpTypeInt 64 0",
  34. "%int64 = OpTypeInt 64 1",
  35. "%float = OpTypeFloat 32",
  36. "%double = OpTypeFloat 64",
  37. // vector types
  38. "%v2bool = OpTypeVector %bool 2",
  39. "%v2uint = OpTypeVector %uint 2",
  40. "%v2int = OpTypeVector %int 2",
  41. "%v3int = OpTypeVector %int 3",
  42. "%v4int = OpTypeVector %int 4",
  43. "%v2float = OpTypeVector %float 2",
  44. "%v3float = OpTypeVector %float 3",
  45. "%v2double = OpTypeVector %double 2",
  46. // struct types
  47. "%inner_struct = OpTypeStruct %bool %float",
  48. "%outer_struct = OpTypeStruct %inner_struct %int %double",
  49. "%flat_struct = OpTypeStruct %bool %int %float %double",
  50. // variable pointer types
  51. "%_pf_bool = OpTypePointer Function %bool",
  52. "%_pf_uint = OpTypePointer Function %uint",
  53. "%_pf_int = OpTypePointer Function %int",
  54. "%_pf_uint64 = OpTypePointer Function %uint64",
  55. "%_pf_int64 = OpTypePointer Function %int64",
  56. "%_pf_float = OpTypePointer Function %float",
  57. "%_pf_double = OpTypePointer Function %double",
  58. "%_pf_v2int = OpTypePointer Function %v2int",
  59. "%_pf_v3int = OpTypePointer Function %v3int",
  60. "%_pf_v4int = OpTypePointer Function %v4int",
  61. "%_pf_v2float = OpTypePointer Function %v2float",
  62. "%_pf_v3float = OpTypePointer Function %v3float",
  63. "%_pf_v2double = OpTypePointer Function %v2double",
  64. "%_pf_inner_struct = OpTypePointer Function %inner_struct",
  65. "%_pf_outer_struct = OpTypePointer Function %outer_struct",
  66. "%_pf_flat_struct = OpTypePointer Function %flat_struct",
  67. // clang-format on
  68. };
  69. }
  70. // A helper function to strip OpName instructions from the given string of
  71. // disassembly code and put those debug instructions to a set. Returns the
  72. // string with all OpName instruction stripped and a set of OpName
  73. // instructions.
  74. std::tuple<std::string, std::unordered_set<std::string>>
  75. StripOpNameInstructionsToSet(const std::string& str) {
  76. std::stringstream ss(str);
  77. std::ostringstream oss;
  78. std::string inst_str;
  79. std::unordered_set<std::string> opname_instructions;
  80. while (std::getline(ss, inst_str, '\n')) {
  81. if (inst_str.find("OpName %") == std::string::npos) {
  82. oss << inst_str << '\n';
  83. } else {
  84. opname_instructions.insert(inst_str);
  85. }
  86. }
  87. return std::make_tuple(oss.str(), std::move(opname_instructions));
  88. }
  89. // The test fixture for all tests of UnifyConstantPass. This fixture defines
  90. // the rule of checking: all the optimized code should be exactly the same as
  91. // the expected code, except the OpName instructions, which can be different in
  92. // order.
  93. template <typename T>
  94. class UnifyConstantTest : public PassTest<T> {
  95. protected:
  96. // Runs UnifyConstantPass on the code built from the given |test_builder|,
  97. // and checks whether the optimization result matches with the code built
  98. // from |expected_builder|.
  99. void Check(const AssemblyBuilder& expected_builder,
  100. const AssemblyBuilder& test_builder) {
  101. // unoptimized code
  102. const std::string original_before_strip = test_builder.GetCode();
  103. std::string original_without_opnames;
  104. std::unordered_set<std::string> original_opnames;
  105. std::tie(original_without_opnames, original_opnames) =
  106. StripOpNameInstructionsToSet(original_before_strip);
  107. // expected code
  108. std::string expected_without_opnames;
  109. std::unordered_set<std::string> expected_opnames;
  110. std::tie(expected_without_opnames, expected_opnames) =
  111. StripOpNameInstructionsToSet(expected_builder.GetCode());
  112. // optimized code
  113. std::string optimized_before_strip;
  114. auto status = Pass::Status::SuccessWithoutChange;
  115. std::tie(optimized_before_strip, status) =
  116. this->template SinglePassRunAndDisassemble<UnifyConstantPass>(
  117. test_builder.GetCode(),
  118. /* skip_nop = */ true, /* do_validation = */ false);
  119. std::string optimized_without_opnames;
  120. std::unordered_set<std::string> optimized_opnames;
  121. std::tie(optimized_without_opnames, optimized_opnames) =
  122. StripOpNameInstructionsToSet(optimized_before_strip);
  123. // Flag "status" should be returned correctly.
  124. EXPECT_NE(Pass::Status::Failure, status);
  125. EXPECT_EQ(expected_without_opnames == original_without_opnames,
  126. status == Pass::Status::SuccessWithoutChange);
  127. // Code except OpName instructions should be exactly the same.
  128. EXPECT_EQ(expected_without_opnames, optimized_without_opnames);
  129. // OpName instructions can be in different order, but the content must be
  130. // the same.
  131. EXPECT_EQ(expected_opnames, optimized_opnames);
  132. }
  133. };
  134. using UnifyFrontEndConstantSingleTest =
  135. UnifyConstantTest<PassTest<::testing::Test>>;
  136. TEST_F(UnifyFrontEndConstantSingleTest, Basic) {
  137. AssemblyBuilder test_builder;
  138. AssemblyBuilder expected_builder;
  139. test_builder
  140. .AppendTypesConstantsGlobals({
  141. "%uint = OpTypeInt 32 0", "%_pf_uint = OpTypePointer Function %uint",
  142. "%unsigned_1 = OpConstant %uint 1",
  143. "%unsigned_1_duplicate = OpConstant %uint 1", // duplicated constant
  144. })
  145. .AppendInMain({
  146. "%uint_var = OpVariable %_pf_uint Function",
  147. "OpStore %uint_var %unsigned_1_duplicate",
  148. });
  149. expected_builder
  150. .AppendTypesConstantsGlobals({
  151. "%uint = OpTypeInt 32 0",
  152. "%_pf_uint = OpTypePointer Function %uint",
  153. "%unsigned_1 = OpConstant %uint 1",
  154. })
  155. .AppendInMain({
  156. "%uint_var = OpVariable %_pf_uint Function",
  157. "OpStore %uint_var %unsigned_1",
  158. })
  159. .AppendNames({
  160. "OpName %unsigned_1 \"unsigned_1_duplicate\"", // the OpName
  161. // instruction of the
  162. // removed duplicated
  163. // constant won't be
  164. // erased.
  165. });
  166. Check(expected_builder, test_builder);
  167. }
  168. TEST_F(UnifyFrontEndConstantSingleTest, SkipWhenResultIdHasDecorations) {
  169. AssemblyBuilder test_builder;
  170. AssemblyBuilder expected_builder;
  171. test_builder
  172. .AppendAnnotations({
  173. // So far we don't have valid decorations for constants. This is
  174. // preparing for the future updates of SPIR-V.
  175. // TODO(qining): change to a valid decoration once they are available.
  176. "OpDecorate %f_1 RelaxedPrecision",
  177. "OpDecorate %f_2_dup RelaxedPrecision",
  178. })
  179. .AppendTypesConstantsGlobals({
  180. // clang-format off
  181. "%float = OpTypeFloat 32",
  182. "%_pf_float = OpTypePointer Function %float",
  183. "%f_1 = OpConstant %float 1",
  184. // %f_1 has decoration, so %f_1 will not be used to replace %f_1_dup.
  185. "%f_1_dup = OpConstant %float 1",
  186. "%f_2 = OpConstant %float 2",
  187. // %_2_dup has decoration, so %f_2 will not replace %f_2_dup.
  188. "%f_2_dup = OpConstant %float 2",
  189. // no decoration for %f_3 or %f_3_dup, %f_3_dup should be replaced.
  190. "%f_3 = OpConstant %float 3",
  191. "%f_3_dup = OpConstant %float 3",
  192. // clang-format on
  193. })
  194. .AppendInMain({
  195. // clang-format off
  196. "%f_var = OpVariable %_pf_float Function",
  197. "OpStore %f_var %f_1_dup",
  198. "OpStore %f_var %f_2_dup",
  199. "OpStore %f_var %f_3_dup",
  200. // clang-format on
  201. });
  202. expected_builder
  203. .AppendAnnotations({
  204. "OpDecorate %f_1 RelaxedPrecision",
  205. "OpDecorate %f_2_dup RelaxedPrecision",
  206. })
  207. .AppendTypesConstantsGlobals({
  208. // clang-format off
  209. "%float = OpTypeFloat 32",
  210. "%_pf_float = OpTypePointer Function %float",
  211. "%f_1 = OpConstant %float 1",
  212. "%f_1_dup = OpConstant %float 1",
  213. "%f_2 = OpConstant %float 2",
  214. "%f_2_dup = OpConstant %float 2",
  215. "%f_3 = OpConstant %float 3",
  216. // clang-format on
  217. })
  218. .AppendInMain({
  219. // clang-format off
  220. "%f_var = OpVariable %_pf_float Function",
  221. "OpStore %f_var %f_1_dup",
  222. "OpStore %f_var %f_2_dup",
  223. "OpStore %f_var %f_3",
  224. // clang-format on
  225. })
  226. .AppendNames({
  227. "OpName %f_3 \"f_3_dup\"",
  228. });
  229. Check(expected_builder, test_builder);
  230. }
  231. TEST_F(UnifyFrontEndConstantSingleTest, UnifyWithDecorationOnTypes) {
  232. AssemblyBuilder test_builder;
  233. AssemblyBuilder expected_builder;
  234. test_builder
  235. .AppendAnnotations({
  236. "OpMemberDecorate %flat_d 1 RelaxedPrecision",
  237. })
  238. .AppendTypesConstantsGlobals({
  239. // clang-format off
  240. "%int = OpTypeInt 32 1",
  241. "%float = OpTypeFloat 32",
  242. "%flat = OpTypeStruct %int %float",
  243. "%_pf_flat = OpTypePointer Function %flat",
  244. // decorated flat struct
  245. "%flat_d = OpTypeStruct %int %float",
  246. "%_pf_flat_d = OpTypePointer Function %flat_d",
  247. // perserved contants. %flat_1 and %flat_d has same members, but
  248. // their type are different in decorations, so they should not be
  249. // used to replace each other.
  250. "%int_1 = OpConstant %int 1",
  251. "%float_1 = OpConstant %float 1",
  252. "%flat_1 = OpConstantComposite %flat %int_1 %float_1",
  253. "%flat_d_1 = OpConstantComposite %flat_d %int_1 %float_1",
  254. // duplicated constants.
  255. "%flat_1_dup = OpConstantComposite %flat %int_1 %float_1",
  256. "%flat_d_1_dup = OpConstantComposite %flat_d %int_1 %float_1",
  257. // clang-format on
  258. })
  259. .AppendInMain({
  260. "%flat_var = OpVariable %_pf_flat Function",
  261. "OpStore %flat_var %flat_1_dup",
  262. "%flat_d_var = OpVariable %_pf_flat_d Function",
  263. "OpStore %flat_d_var %flat_d_1_dup",
  264. });
  265. expected_builder
  266. .AppendAnnotations({
  267. "OpMemberDecorate %flat_d 1 RelaxedPrecision",
  268. })
  269. .AppendTypesConstantsGlobals({
  270. // clang-format off
  271. "%int = OpTypeInt 32 1",
  272. "%float = OpTypeFloat 32",
  273. "%flat = OpTypeStruct %int %float",
  274. "%_pf_flat = OpTypePointer Function %flat",
  275. // decorated flat struct
  276. "%flat_d = OpTypeStruct %int %float",
  277. "%_pf_flat_d = OpTypePointer Function %flat_d",
  278. "%int_1 = OpConstant %int 1",
  279. "%float_1 = OpConstant %float 1",
  280. "%flat_1 = OpConstantComposite %flat %int_1 %float_1",
  281. "%flat_d_1 = OpConstantComposite %flat_d %int_1 %float_1",
  282. // clang-format on
  283. })
  284. .AppendInMain({
  285. "%flat_var = OpVariable %_pf_flat Function",
  286. "OpStore %flat_var %flat_1",
  287. "%flat_d_var = OpVariable %_pf_flat_d Function",
  288. "OpStore %flat_d_var %flat_d_1",
  289. })
  290. .AppendNames({
  291. "OpName %flat_1 \"flat_1_dup\"",
  292. "OpName %flat_d_1 \"flat_d_1_dup\"",
  293. });
  294. Check(expected_builder, test_builder);
  295. }
  296. struct UnifyConstantTestCase {
  297. // preserved constants.
  298. std::vector<std::string> preserved_consts;
  299. // expected uses of the preserved constants.
  300. std::vector<std::string> use_preserved_consts;
  301. // duplicated constants of the preserved constants.
  302. std::vector<std::string> duplicate_consts;
  303. // uses of the duplicated constants, expected to be updated to use the
  304. // preserved constants.
  305. std::vector<std::string> use_duplicate_consts;
  306. // The updated OpName instructions that originally refer to duplicated
  307. // constants.
  308. std::vector<std::string> remapped_names;
  309. };
  310. using UnifyFrontEndConstantParamTest = UnifyConstantTest<
  311. PassTest<::testing::TestWithParam<UnifyConstantTestCase>>>;
  312. TEST_P(UnifyFrontEndConstantParamTest, TestCase) {
  313. auto& tc = GetParam();
  314. AssemblyBuilder test_builder;
  315. AssemblyBuilder expected_builder;
  316. test_builder.AppendTypesConstantsGlobals(CommonTypes());
  317. expected_builder.AppendTypesConstantsGlobals(CommonTypes());
  318. test_builder.AppendTypesConstantsGlobals(tc.preserved_consts)
  319. .AppendTypesConstantsGlobals(tc.duplicate_consts)
  320. .AppendInMain(tc.use_duplicate_consts);
  321. // Duplicated constants are killed in the expected output, and the debug
  322. // instructions attached to those duplicated instructions will be migrated to
  323. // the corresponding preserved constants.
  324. expected_builder.AppendTypesConstantsGlobals(tc.preserved_consts)
  325. .AppendInMain(tc.use_preserved_consts)
  326. .AppendNames(tc.remapped_names);
  327. Check(expected_builder, test_builder);
  328. }
  329. INSTANTIATE_TEST_SUITE_P(
  330. Case, UnifyFrontEndConstantParamTest,
  331. ::
  332. testing::
  333. ValuesIn(
  334. std::
  335. vector<UnifyConstantTestCase>(
  336. {
  337. // clang-format off
  338. // basic tests for scalar constants
  339. {
  340. // preserved constants
  341. {
  342. "%bool_true = OpConstantTrue %bool",
  343. "%signed_1 = OpConstant %int 1",
  344. "%signed_minus_1 = OpConstant %int64 -1",
  345. "%unsigned_max = OpConstant %uint64 18446744073709551615",
  346. "%float_1 = OpConstant %float 1",
  347. "%double_1 = OpConstant %double 1",
  348. },
  349. // use preserved constants in main
  350. {
  351. "%bool_var = OpVariable %_pf_bool Function",
  352. "OpStore %bool_var %bool_true",
  353. "%int_var = OpVariable %_pf_int Function",
  354. "OpStore %int_var %signed_1",
  355. "%int64_var = OpVariable %_pf_int64 Function",
  356. "OpStore %int64_var %signed_minus_1",
  357. "%uint64_var = OpVariable %_pf_uint64 Function",
  358. "OpStore %uint64_var %unsigned_max",
  359. "%float_var = OpVariable %_pf_float Function",
  360. "OpStore %float_var %float_1",
  361. "%double_var = OpVariable %_pf_double Function",
  362. "OpStore %double_var %double_1",
  363. },
  364. // duplicated constants
  365. {
  366. "%bool_true_duplicate = OpConstantTrue %bool",
  367. "%signed_1_duplicate = OpConstant %int 1",
  368. "%signed_minus_1_duplicate = OpConstant %int64 -1",
  369. "%unsigned_max_duplicate = OpConstant %uint64 18446744073709551615",
  370. "%float_1_duplicate = OpConstant %float 1",
  371. "%double_1_duplicate = OpConstant %double 1",
  372. },
  373. // use duplicated constants in main
  374. {
  375. "%bool_var = OpVariable %_pf_bool Function",
  376. "OpStore %bool_var %bool_true_duplicate",
  377. "%int_var = OpVariable %_pf_int Function",
  378. "OpStore %int_var %signed_1_duplicate",
  379. "%int64_var = OpVariable %_pf_int64 Function",
  380. "OpStore %int64_var %signed_minus_1_duplicate",
  381. "%uint64_var = OpVariable %_pf_uint64 Function",
  382. "OpStore %uint64_var %unsigned_max_duplicate",
  383. "%float_var = OpVariable %_pf_float Function",
  384. "OpStore %float_var %float_1_duplicate",
  385. "%double_var = OpVariable %_pf_double Function",
  386. "OpStore %double_var %double_1_duplicate",
  387. },
  388. // remapped names
  389. {
  390. "OpName %bool_true \"bool_true_duplicate\"",
  391. "OpName %signed_1 \"signed_1_duplicate\"",
  392. "OpName %signed_minus_1 \"signed_minus_1_duplicate\"",
  393. "OpName %unsigned_max \"unsigned_max_duplicate\"",
  394. "OpName %float_1 \"float_1_duplicate\"",
  395. "OpName %double_1 \"double_1_duplicate\"",
  396. },
  397. },
  398. // NaN in different bit patterns should not be unified, but the ones
  399. // using same bit pattern should be unified.
  400. {
  401. // preserved constants
  402. {
  403. "%float_nan_1 = OpConstant %float 0x1.8p+128", // !2143289344, 7FC00000
  404. "%float_nan_2 = OpConstant %float 0x1.800002p+128",// !2143289345 7FC00001
  405. },
  406. // use preserved constants in main
  407. {
  408. "%float_var = OpVariable %_pf_float Function",
  409. "OpStore %float_var %float_nan_1",
  410. "OpStore %float_var %float_nan_2",
  411. },
  412. // duplicated constants
  413. {
  414. "%float_nan_1_duplicate = OpConstant %float 0x1.8p+128", // !2143289344, 7FC00000
  415. "%float_nan_2_duplicate = OpConstant %float 0x1.800002p+128",// !2143289345, 7FC00001
  416. },
  417. // use duplicated constants in main
  418. {
  419. "%float_var = OpVariable %_pf_float Function",
  420. "OpStore %float_var %float_nan_1_duplicate",
  421. "OpStore %float_var %float_nan_2_duplicate",
  422. },
  423. // remapped names
  424. {
  425. "OpName %float_nan_1 \"float_nan_1_duplicate\"",
  426. "OpName %float_nan_2 \"float_nan_2_duplicate\"",
  427. },
  428. },
  429. // null values
  430. {
  431. // preserved constants
  432. {
  433. "%bool_null = OpConstantNull %bool",
  434. "%signed_null = OpConstantNull %int",
  435. "%signed_64_null = OpConstantNull %int64",
  436. "%float_null = OpConstantNull %float",
  437. "%double_null = OpConstantNull %double",
  438. // zero-valued constants will not be unified with the equivalent
  439. // null constants.
  440. "%signed_zero = OpConstant %int 0",
  441. },
  442. // use preserved constants in main
  443. {
  444. "%bool_var = OpVariable %_pf_bool Function",
  445. "OpStore %bool_var %bool_null",
  446. "%int_var = OpVariable %_pf_int Function",
  447. "OpStore %int_var %signed_null",
  448. "%int64_var = OpVariable %_pf_int64 Function",
  449. "OpStore %int64_var %signed_64_null",
  450. "%float_var = OpVariable %_pf_float Function",
  451. "OpStore %float_var %float_null",
  452. "%double_var = OpVariable %_pf_double Function",
  453. "OpStore %double_var %double_null",
  454. },
  455. // duplicated constants
  456. {
  457. "%bool_null_duplicate = OpConstantNull %bool",
  458. "%signed_null_duplicate = OpConstantNull %int",
  459. "%signed_64_null_duplicate = OpConstantNull %int64",
  460. "%float_null_duplicate = OpConstantNull %float",
  461. "%double_null_duplicate = OpConstantNull %double",
  462. },
  463. // use duplicated constants in main
  464. {
  465. "%bool_var = OpVariable %_pf_bool Function",
  466. "OpStore %bool_var %bool_null_duplicate",
  467. "%int_var = OpVariable %_pf_int Function",
  468. "OpStore %int_var %signed_null_duplicate",
  469. "%int64_var = OpVariable %_pf_int64 Function",
  470. "OpStore %int64_var %signed_64_null_duplicate",
  471. "%float_var = OpVariable %_pf_float Function",
  472. "OpStore %float_var %float_null_duplicate",
  473. "%double_var = OpVariable %_pf_double Function",
  474. "OpStore %double_var %double_null_duplicate",
  475. },
  476. // remapped names
  477. {
  478. "OpName %bool_null \"bool_null_duplicate\"",
  479. "OpName %signed_null \"signed_null_duplicate\"",
  480. "OpName %signed_64_null \"signed_64_null_duplicate\"",
  481. "OpName %float_null \"float_null_duplicate\"",
  482. "OpName %double_null \"double_null_duplicate\"",
  483. },
  484. },
  485. // constant sampler
  486. {
  487. // preserved constants
  488. {
  489. "%sampler = OpTypeSampler",
  490. "%_pf_sampler = OpTypePointer Function %sampler",
  491. "%sampler_1 = OpConstantSampler %sampler Repeat 0 Linear",
  492. },
  493. // use preserved constants in main
  494. {
  495. "%sampler_var = OpVariable %_pf_sampler Function",
  496. "OpStore %sampler_var %sampler_1",
  497. },
  498. // duplicated constants
  499. {
  500. "%sampler_1_duplicate = OpConstantSampler %sampler Repeat 0 Linear",
  501. },
  502. // use duplicated constants in main
  503. {
  504. "%sampler_var = OpVariable %_pf_sampler Function",
  505. "OpStore %sampler_var %sampler_1_duplicate",
  506. },
  507. // remapped names
  508. {
  509. "OpName %sampler_1 \"sampler_1_duplicate\"",
  510. },
  511. },
  512. // duplicate vector built from same ids.
  513. {
  514. // preserved constants
  515. {
  516. "%signed_1 = OpConstant %int 1",
  517. "%signed_2 = OpConstant %int 2",
  518. "%signed_3 = OpConstant %int 3",
  519. "%signed_4 = OpConstant %int 4",
  520. "%vec = OpConstantComposite %v4int %signed_1 %signed_2 %signed_3 %signed_4",
  521. },
  522. // use preserved constants in main
  523. {
  524. "%vec_var = OpVariable %_pf_v4int Function",
  525. "OpStore %vec_var %vec",
  526. },
  527. // duplicated constants
  528. {
  529. "%vec_duplicate = OpConstantComposite %v4int %signed_1 %signed_2 %signed_3 %signed_4",
  530. },
  531. // use duplicated constants in main
  532. {
  533. "%vec_var = OpVariable %_pf_v4int Function",
  534. "OpStore %vec_var %vec_duplicate",
  535. },
  536. // remapped names
  537. {
  538. "OpName %vec \"vec_duplicate\"",
  539. }
  540. },
  541. // duplicate vector built from duplicated ids.
  542. {
  543. // preserved constants
  544. {
  545. "%signed_1 = OpConstant %int 1",
  546. "%signed_2 = OpConstant %int 2",
  547. "%signed_3 = OpConstant %int 3",
  548. "%signed_4 = OpConstant %int 4",
  549. "%vec = OpConstantComposite %v4int %signed_1 %signed_2 %signed_3 %signed_4",
  550. },
  551. // use preserved constants in main
  552. {
  553. "%vec_var = OpVariable %_pf_v4int Function",
  554. "OpStore %vec_var %vec",
  555. },
  556. // duplicated constants
  557. {
  558. "%signed_3_duplicate = OpConstant %int 3",
  559. "%signed_4_duplicate = OpConstant %int 4",
  560. "%vec_duplicate = OpConstantComposite %v4int %signed_1 %signed_2 %signed_3_duplicate %signed_4_duplicate",
  561. },
  562. // use duplicated constants in main
  563. {
  564. "%vec_var = OpVariable %_pf_v4int Function",
  565. "OpStore %vec_var %vec_duplicate",
  566. },
  567. // remapped names
  568. {
  569. "OpName %signed_3 \"signed_3_duplicate\"",
  570. "OpName %signed_4 \"signed_4_duplicate\"",
  571. "OpName %vec \"vec_duplicate\"",
  572. },
  573. },
  574. // flat struct
  575. {
  576. // preserved constants
  577. {
  578. "%bool_true = OpConstantTrue %bool",
  579. "%signed_1 = OpConstant %int 1",
  580. "%float_1 = OpConstant %float 1",
  581. "%double_1 = OpConstant %double 1",
  582. "%s = OpConstantComposite %flat_struct %bool_true %signed_1 %float_1 %double_1",
  583. },
  584. // use preserved constants in main
  585. {
  586. "%s_var = OpVariable %_pf_flat_struct Function",
  587. "OpStore %s_var %s",
  588. },
  589. // duplicated constants
  590. {
  591. "%float_1_duplicate = OpConstant %float 1",
  592. "%double_1_duplicate = OpConstant %double 1",
  593. "%s_duplicate = OpConstantComposite %flat_struct %bool_true %signed_1 %float_1_duplicate %double_1_duplicate",
  594. },
  595. // use duplicated constants in main
  596. {
  597. "%s_var = OpVariable %_pf_flat_struct Function",
  598. "OpStore %s_var %s_duplicate",
  599. },
  600. // remapped names
  601. {
  602. "OpName %float_1 \"float_1_duplicate\"",
  603. "OpName %double_1 \"double_1_duplicate\"",
  604. "OpName %s \"s_duplicate\"",
  605. },
  606. },
  607. // nested struct
  608. {
  609. // preserved constants
  610. {
  611. "%bool_true = OpConstantTrue %bool",
  612. "%signed_1 = OpConstant %int 1",
  613. "%float_1 = OpConstant %float 1",
  614. "%double_1 = OpConstant %double 1",
  615. "%inner = OpConstantComposite %inner_struct %bool_true %float_1",
  616. "%outer = OpConstantComposite %outer_struct %inner %signed_1 %double_1",
  617. },
  618. // use preserved constants in main
  619. {
  620. "%outer_var = OpVariable %_pf_outer_struct Function",
  621. "OpStore %outer_var %outer",
  622. },
  623. // duplicated constants
  624. {
  625. "%float_1_duplicate = OpConstant %float 1",
  626. "%double_1_duplicate = OpConstant %double 1",
  627. "%inner_duplicate = OpConstantComposite %inner_struct %bool_true %float_1_duplicate",
  628. "%outer_duplicate = OpConstantComposite %outer_struct %inner_duplicate %signed_1 %double_1_duplicate",
  629. },
  630. // use duplicated constants in main
  631. {
  632. "%outer_var = OpVariable %_pf_outer_struct Function",
  633. "OpStore %outer_var %outer_duplicate",
  634. },
  635. // remapped names
  636. {
  637. "OpName %float_1 \"float_1_duplicate\"",
  638. "OpName %double_1 \"double_1_duplicate\"",
  639. "OpName %inner \"inner_duplicate\"",
  640. "OpName %outer \"outer_duplicate\"",
  641. },
  642. },
  643. // composite type null constants. Null constants and zero-valued
  644. // constants should not be used to replace each other.
  645. {
  646. // preserved constants
  647. {
  648. "%bool_zero = OpConstantFalse %bool",
  649. "%float_zero = OpConstant %float 0",
  650. "%int_null = OpConstantNull %int",
  651. "%double_null = OpConstantNull %double",
  652. // inner_struct type null constant.
  653. "%null_inner = OpConstantNull %inner_struct",
  654. // zero-valued composite constant built from zero-valued constant
  655. // component. inner_zero should not be replace by null_inner.
  656. "%inner_zero = OpConstantComposite %inner_struct %bool_zero %float_zero",
  657. // zero-valued composite contant built from zero-valued constants
  658. // and null constants.
  659. "%outer_zero = OpConstantComposite %outer_struct %inner_zero %int_null %double_null",
  660. // outer_struct type null constant, it should not be replaced by
  661. // outer_zero.
  662. "%null_outer = OpConstantNull %outer_struct",
  663. },
  664. // use preserved constants in main
  665. {
  666. "%inner_var = OpVariable %_pf_inner_struct Function",
  667. "OpStore %inner_var %inner_zero",
  668. "OpStore %inner_var %null_inner",
  669. "%outer_var = OpVariable %_pf_outer_struct Function",
  670. "OpStore %outer_var %outer_zero",
  671. "OpStore %outer_var %null_outer",
  672. },
  673. // duplicated constants
  674. {
  675. "%null_inner_dup = OpConstantNull %inner_struct",
  676. "%null_outer_dup = OpConstantNull %outer_struct",
  677. "%inner_zero_dup = OpConstantComposite %inner_struct %bool_zero %float_zero",
  678. "%outer_zero_dup = OpConstantComposite %outer_struct %inner_zero_dup %int_null %double_null",
  679. },
  680. // use duplicated constants in main
  681. {
  682. "%inner_var = OpVariable %_pf_inner_struct Function",
  683. "OpStore %inner_var %inner_zero_dup",
  684. "OpStore %inner_var %null_inner_dup",
  685. "%outer_var = OpVariable %_pf_outer_struct Function",
  686. "OpStore %outer_var %outer_zero_dup",
  687. "OpStore %outer_var %null_outer_dup",
  688. },
  689. // remapped names
  690. {
  691. "OpName %null_inner \"null_inner_dup\"",
  692. "OpName %null_outer \"null_outer_dup\"",
  693. "OpName %inner_zero \"inner_zero_dup\"",
  694. "OpName %outer_zero \"outer_zero_dup\"",
  695. },
  696. },
  697. // Spec Constants with SpecId decoration should be skipped.
  698. {
  699. // preserved constants
  700. {
  701. // Assembly builder will add OpDecorate SpecId instruction for the
  702. // following spec constant instructions automatically.
  703. "%spec_bool_1 = OpSpecConstantTrue %bool",
  704. "%spec_bool_2 = OpSpecConstantTrue %bool",
  705. "%spec_int_1 = OpSpecConstant %int 1",
  706. "%spec_int_2 = OpSpecConstant %int 1",
  707. },
  708. // use preserved constants in main
  709. {
  710. "%bool_var = OpVariable %_pf_bool Function",
  711. "OpStore %bool_var %spec_bool_1",
  712. "OpStore %bool_var %spec_bool_2",
  713. "%int_var = OpVariable %_pf_int Function",
  714. "OpStore %int_var %spec_int_1",
  715. "OpStore %int_var %spec_int_2",
  716. },
  717. // duplicated constants. No duplicated instruction to remove in this
  718. // case.
  719. {},
  720. // use duplicated constants in main. Same as the above 'use preserved
  721. // constants in main' defined above, as no instruction should be
  722. // removed in this case.
  723. {
  724. "%bool_var = OpVariable %_pf_bool Function",
  725. "OpStore %bool_var %spec_bool_1",
  726. "OpStore %bool_var %spec_bool_2",
  727. "%int_var = OpVariable %_pf_int Function",
  728. "OpStore %int_var %spec_int_1",
  729. "OpStore %int_var %spec_int_2",
  730. },
  731. // remapped names. No duplicated instruction removed, so this is
  732. // empty.
  733. {}
  734. },
  735. // spec constant composite
  736. {
  737. // preserved constants
  738. {
  739. "%spec_bool_true = OpSpecConstantTrue %bool",
  740. "%spec_signed_1 = OpSpecConstant %int 1",
  741. "%float_1 = OpConstant %float 1",
  742. "%double_1 = OpConstant %double 1",
  743. "%spec_inner = OpSpecConstantComposite %inner_struct %spec_bool_true %float_1",
  744. "%spec_outer = OpSpecConstantComposite %outer_struct %spec_inner %spec_signed_1 %double_1",
  745. "%spec_vec2 = OpSpecConstantComposite %v2float %float_1 %float_1",
  746. },
  747. // use preserved constants in main
  748. {
  749. "%outer_var = OpVariable %_pf_outer_struct Function",
  750. "OpStore %outer_var %spec_outer",
  751. "%v2float_var = OpVariable %_pf_v2float Function",
  752. "OpStore %v2float_var %spec_vec2",
  753. },
  754. // duplicated constants
  755. {
  756. "%float_1_duplicate = OpConstant %float 1",
  757. "%double_1_duplicate = OpConstant %double 1",
  758. "%spec_inner_duplicate = OpSpecConstantComposite %inner_struct %spec_bool_true %float_1_duplicate",
  759. "%spec_outer_duplicate = OpSpecConstantComposite %outer_struct %spec_inner_duplicate %spec_signed_1 %double_1_duplicate",
  760. "%spec_vec2_duplicate = OpSpecConstantComposite %v2float %float_1 %float_1_duplicate",
  761. },
  762. // use duplicated constants in main
  763. {
  764. "%outer_var = OpVariable %_pf_outer_struct Function",
  765. "OpStore %outer_var %spec_outer_duplicate",
  766. "%v2float_var = OpVariable %_pf_v2float Function",
  767. "OpStore %v2float_var %spec_vec2_duplicate",
  768. },
  769. // remapped names
  770. {
  771. "OpName %float_1 \"float_1_duplicate\"",
  772. "OpName %double_1 \"double_1_duplicate\"",
  773. "OpName %spec_inner \"spec_inner_duplicate\"",
  774. "OpName %spec_outer \"spec_outer_duplicate\"",
  775. "OpName %spec_vec2 \"spec_vec2_duplicate\"",
  776. },
  777. },
  778. // spec constant op with int scalar
  779. {
  780. // preserved constants
  781. {
  782. "%spec_signed_1 = OpSpecConstant %int 1",
  783. "%spec_signed_2 = OpSpecConstant %int 2",
  784. "%spec_signed_add = OpSpecConstantOp %int IAdd %spec_signed_1 %spec_signed_2",
  785. },
  786. // use preserved constants in main
  787. {
  788. "%int_var = OpVariable %_pf_int Function",
  789. "OpStore %int_var %spec_signed_add",
  790. },
  791. // duplicated constants
  792. {
  793. "%spec_signed_add_duplicate = OpSpecConstantOp %int IAdd %spec_signed_1 %spec_signed_2",
  794. },
  795. // use duplicated contants in main
  796. {
  797. "%int_var = OpVariable %_pf_int Function",
  798. "OpStore %int_var %spec_signed_add_duplicate",
  799. },
  800. // remapped names
  801. {
  802. "OpName %spec_signed_add \"spec_signed_add_duplicate\"",
  803. },
  804. },
  805. // spec constant op composite extract
  806. {
  807. // preserved constants
  808. {
  809. "%float_1 = OpConstant %float 1",
  810. "%spec_vec2 = OpSpecConstantComposite %v2float %float_1 %float_1",
  811. "%spec_extract = OpSpecConstantOp %float CompositeExtract %spec_vec2 1",
  812. },
  813. // use preserved constants in main
  814. {
  815. "%float_var = OpVariable %_pf_float Function",
  816. "OpStore %float_var %spec_extract",
  817. },
  818. // duplicated constants
  819. {
  820. "%spec_extract_duplicate = OpSpecConstantOp %float CompositeExtract %spec_vec2 1",
  821. },
  822. // use duplicated constants in main
  823. {
  824. "%float_var = OpVariable %_pf_float Function",
  825. "OpStore %float_var %spec_extract_duplicate",
  826. },
  827. // remapped names
  828. {
  829. "OpName %spec_extract \"spec_extract_duplicate\"",
  830. },
  831. },
  832. // spec constant op vector shuffle
  833. {
  834. // preserved constants
  835. {
  836. "%float_1 = OpConstant %float 1",
  837. "%float_2 = OpConstant %float 2",
  838. "%spec_vec2_1 = OpSpecConstantComposite %v2float %float_1 %float_1",
  839. "%spec_vec2_2 = OpSpecConstantComposite %v2float %float_2 %float_2",
  840. "%spec_vector_shuffle = OpSpecConstantOp %v2float VectorShuffle %spec_vec2_1 %spec_vec2_2 1 2",
  841. },
  842. // use preserved constants in main
  843. {
  844. "%v2float_var = OpVariable %_pf_v2float Function",
  845. "OpStore %v2float_var %spec_vector_shuffle",
  846. },
  847. // duplicated constants
  848. {
  849. "%spec_vector_shuffle_duplicate = OpSpecConstantOp %v2float VectorShuffle %spec_vec2_1 %spec_vec2_2 1 2",
  850. },
  851. // use duplicated constants in main
  852. {
  853. "%v2float_var = OpVariable %_pf_v2float Function",
  854. "OpStore %v2float_var %spec_vector_shuffle_duplicate",
  855. },
  856. // remapped names
  857. {
  858. "OpName %spec_vector_shuffle \"spec_vector_shuffle_duplicate\"",
  859. },
  860. },
  861. // long dependency chain
  862. {
  863. // preserved constants
  864. {
  865. "%array_size = OpConstant %int 4",
  866. "%type_arr_int_4 = OpTypeArray %int %array_size",
  867. "%signed_0 = OpConstant %int 100",
  868. "%signed_1 = OpConstant %int 1",
  869. "%signed_2 = OpSpecConstantOp %int IAdd %signed_0 %signed_1",
  870. "%signed_3 = OpSpecConstantOp %int ISub %signed_0 %signed_2",
  871. "%signed_4 = OpSpecConstantOp %int IAdd %signed_0 %signed_3",
  872. "%signed_5 = OpSpecConstantOp %int ISub %signed_0 %signed_4",
  873. "%signed_6 = OpSpecConstantOp %int IAdd %signed_0 %signed_5",
  874. "%signed_7 = OpSpecConstantOp %int ISub %signed_0 %signed_6",
  875. "%signed_8 = OpSpecConstantOp %int IAdd %signed_0 %signed_7",
  876. "%signed_9 = OpSpecConstantOp %int ISub %signed_0 %signed_8",
  877. "%signed_10 = OpSpecConstantOp %int IAdd %signed_0 %signed_9",
  878. "%signed_11 = OpSpecConstantOp %int ISub %signed_0 %signed_10",
  879. "%signed_12 = OpSpecConstantOp %int IAdd %signed_0 %signed_11",
  880. "%signed_13 = OpSpecConstantOp %int ISub %signed_0 %signed_12",
  881. "%signed_14 = OpSpecConstantOp %int IAdd %signed_0 %signed_13",
  882. "%signed_15 = OpSpecConstantOp %int ISub %signed_0 %signed_14",
  883. "%signed_16 = OpSpecConstantOp %int ISub %signed_0 %signed_15",
  884. "%signed_17 = OpSpecConstantOp %int IAdd %signed_0 %signed_16",
  885. "%signed_18 = OpSpecConstantOp %int ISub %signed_0 %signed_17",
  886. "%signed_19 = OpSpecConstantOp %int IAdd %signed_0 %signed_18",
  887. "%signed_20 = OpSpecConstantOp %int ISub %signed_0 %signed_19",
  888. "%signed_vec_a = OpSpecConstantComposite %v2int %signed_18 %signed_19",
  889. "%signed_vec_b = OpSpecConstantOp %v2int IMul %signed_vec_a %signed_vec_a",
  890. "%signed_21 = OpSpecConstantOp %int CompositeExtract %signed_vec_b 0",
  891. "%signed_array = OpConstantComposite %type_arr_int_4 %signed_20 %signed_20 %signed_21 %signed_21",
  892. "%signed_22 = OpSpecConstantOp %int CompositeExtract %signed_array 0",
  893. },
  894. // use preserved constants in main
  895. {
  896. "%int_var = OpVariable %_pf_int Function",
  897. "OpStore %int_var %signed_22",
  898. },
  899. // duplicated constants
  900. {
  901. "%signed_0_dup = OpConstant %int 100",
  902. "%signed_1_dup = OpConstant %int 1",
  903. "%signed_2_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_1_dup",
  904. "%signed_3_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_2_dup",
  905. "%signed_4_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_3_dup",
  906. "%signed_5_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_4_dup",
  907. "%signed_6_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_5_dup",
  908. "%signed_7_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_6_dup",
  909. "%signed_8_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_7_dup",
  910. "%signed_9_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_8_dup",
  911. "%signed_10_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_9_dup",
  912. "%signed_11_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_10_dup",
  913. "%signed_12_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_11_dup",
  914. "%signed_13_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_12_dup",
  915. "%signed_14_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_13_dup",
  916. "%signed_15_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_14_dup",
  917. "%signed_16_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_15_dup",
  918. "%signed_17_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_16_dup",
  919. "%signed_18_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_17_dup",
  920. "%signed_19_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_18_dup",
  921. "%signed_20_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_19_dup",
  922. "%signed_vec_a_dup = OpSpecConstantComposite %v2int %signed_18_dup %signed_19_dup",
  923. "%signed_vec_b_dup = OpSpecConstantOp %v2int IMul %signed_vec_a_dup %signed_vec_a_dup",
  924. "%signed_21_dup = OpSpecConstantOp %int CompositeExtract %signed_vec_b_dup 0",
  925. "%signed_array_dup = OpConstantComposite %type_arr_int_4 %signed_20_dup %signed_20_dup %signed_21_dup %signed_21_dup",
  926. "%signed_22_dup = OpSpecConstantOp %int CompositeExtract %signed_array_dup 0",
  927. },
  928. // use duplicated constants in main
  929. {
  930. "%int_var = OpVariable %_pf_int Function",
  931. "OpStore %int_var %signed_22_dup",
  932. },
  933. // remapped names
  934. {
  935. "OpName %signed_0 \"signed_0_dup\"",
  936. "OpName %signed_1 \"signed_1_dup\"",
  937. "OpName %signed_2 \"signed_2_dup\"",
  938. "OpName %signed_3 \"signed_3_dup\"",
  939. "OpName %signed_4 \"signed_4_dup\"",
  940. "OpName %signed_5 \"signed_5_dup\"",
  941. "OpName %signed_6 \"signed_6_dup\"",
  942. "OpName %signed_7 \"signed_7_dup\"",
  943. "OpName %signed_8 \"signed_8_dup\"",
  944. "OpName %signed_9 \"signed_9_dup\"",
  945. "OpName %signed_10 \"signed_10_dup\"",
  946. "OpName %signed_11 \"signed_11_dup\"",
  947. "OpName %signed_12 \"signed_12_dup\"",
  948. "OpName %signed_13 \"signed_13_dup\"",
  949. "OpName %signed_14 \"signed_14_dup\"",
  950. "OpName %signed_15 \"signed_15_dup\"",
  951. "OpName %signed_16 \"signed_16_dup\"",
  952. "OpName %signed_17 \"signed_17_dup\"",
  953. "OpName %signed_18 \"signed_18_dup\"",
  954. "OpName %signed_19 \"signed_19_dup\"",
  955. "OpName %signed_20 \"signed_20_dup\"",
  956. "OpName %signed_vec_a \"signed_vec_a_dup\"",
  957. "OpName %signed_vec_b \"signed_vec_b_dup\"",
  958. "OpName %signed_21 \"signed_21_dup\"",
  959. "OpName %signed_array \"signed_array_dup\"",
  960. "OpName %signed_22 \"signed_22_dup\"",
  961. },
  962. },
  963. // clang-format on
  964. })));
  965. } // namespace
  966. } // namespace opt
  967. } // namespace spvtools