val_adjacency_test.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707
  1. // Copyright (c) 2018 LunarG 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 <sstream>
  15. #include <string>
  16. #include "gmock/gmock.h"
  17. #include "test/unit_spirv.h"
  18. #include "test/val/val_fixtures.h"
  19. namespace spvtools {
  20. namespace val {
  21. namespace {
  22. using ::testing::HasSubstr;
  23. using ::testing::Not;
  24. using ValidateAdjacency = spvtest::ValidateBase<bool>;
  25. TEST_F(ValidateAdjacency, OpPhiBeginsModuleFail) {
  26. const std::string module = R"(
  27. %result = OpPhi %bool %true %true_label %false %false_label
  28. OpCapability Shader
  29. OpMemoryModel Logical GLSL450
  30. OpEntryPoint Fragment %main "main"
  31. OpExecutionMode %main OriginUpperLeft
  32. %void = OpTypeVoid
  33. %bool = OpTypeBool
  34. %true = OpConstantTrue %bool
  35. %false = OpConstantFalse %bool
  36. %func = OpTypeFunction %void
  37. %main = OpFunction %void None %func
  38. %main_entry = OpLabel
  39. OpBranch %true_label
  40. %true_label = OpLabel
  41. OpBranch %false_label
  42. %false_label = OpLabel
  43. OpBranch %end_label
  44. OpReturn
  45. OpFunctionEnd
  46. )";
  47. CompileSuccessfully(module);
  48. EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  49. EXPECT_THAT(getDiagnosticString(),
  50. HasSubstr("ID '1[%bool]' has not been defined"));
  51. }
  52. TEST_F(ValidateAdjacency, OpLoopMergeEndsModuleFail) {
  53. const std::string module = R"(
  54. OpCapability Shader
  55. OpMemoryModel Logical GLSL450
  56. OpEntryPoint Fragment %main "main"
  57. OpExecutionMode %main OriginUpperLeft
  58. %void = OpTypeVoid
  59. %func = OpTypeFunction %void
  60. %main = OpFunction %void None %func
  61. %main_entry = OpLabel
  62. OpBranch %loop
  63. %loop = OpLabel
  64. OpLoopMerge %end %loop None
  65. )";
  66. CompileSuccessfully(module);
  67. EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions());
  68. EXPECT_THAT(getDiagnosticString(),
  69. HasSubstr("Missing OpFunctionEnd at end of module"));
  70. }
  71. TEST_F(ValidateAdjacency, OpSelectionMergeEndsModuleFail) {
  72. const std::string module = R"(
  73. OpCapability Shader
  74. OpMemoryModel Logical GLSL450
  75. OpEntryPoint Fragment %main "main"
  76. OpExecutionMode %main OriginUpperLeft
  77. %void = OpTypeVoid
  78. %func = OpTypeFunction %void
  79. %main = OpFunction %void None %func
  80. %main_entry = OpLabel
  81. OpBranch %merge
  82. %merge = OpLabel
  83. OpSelectionMerge %merge None
  84. )";
  85. CompileSuccessfully(module);
  86. EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions());
  87. EXPECT_THAT(getDiagnosticString(),
  88. HasSubstr("Missing OpFunctionEnd at end of module"));
  89. }
  90. std::string GenerateShaderCode(
  91. const std::string& body,
  92. const std::string& capabilities_and_extensions = "OpCapability Shader",
  93. const std::string& execution_model = "Fragment") {
  94. std::ostringstream ss;
  95. ss << capabilities_and_extensions << "\n";
  96. ss << "OpMemoryModel Logical GLSL450\n";
  97. ss << "OpEntryPoint " << execution_model << " %main \"main\"\n";
  98. if (execution_model == "Fragment") {
  99. ss << "OpExecutionMode %main OriginUpperLeft\n";
  100. }
  101. ss << R"(
  102. %string = OpString ""
  103. %void = OpTypeVoid
  104. %bool = OpTypeBool
  105. %int = OpTypeInt 32 0
  106. %true = OpConstantTrue %bool
  107. %false = OpConstantFalse %bool
  108. %zero = OpConstant %int 0
  109. %int_1 = OpConstant %int 1
  110. %func = OpTypeFunction %void
  111. %func_int = OpTypePointer Function %int
  112. %main = OpFunction %void None %func
  113. %main_entry = OpLabel
  114. )";
  115. ss << body;
  116. ss << R"(
  117. OpReturn
  118. OpFunctionEnd)";
  119. return ss.str();
  120. }
  121. TEST_F(ValidateAdjacency, OpPhiPreceededByOpLabelSuccess) {
  122. const std::string body = R"(
  123. OpSelectionMerge %end_label None
  124. OpBranchConditional %true %true_label %false_label
  125. %true_label = OpLabel
  126. OpBranch %end_label
  127. %false_label = OpLabel
  128. OpBranch %end_label
  129. %end_label = OpLabel
  130. OpLine %string 0 0
  131. %result = OpPhi %bool %true %true_label %false %false_label
  132. )";
  133. CompileSuccessfully(GenerateShaderCode(body));
  134. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  135. }
  136. TEST_F(ValidateAdjacency, OpPhiPreceededByOpPhiSuccess) {
  137. const std::string body = R"(
  138. OpSelectionMerge %end_label None
  139. OpBranchConditional %true %true_label %false_label
  140. %true_label = OpLabel
  141. OpBranch %end_label
  142. %false_label = OpLabel
  143. OpBranch %end_label
  144. %end_label = OpLabel
  145. %1 = OpPhi %bool %true %true_label %false %false_label
  146. %2 = OpPhi %bool %true %true_label %false %false_label
  147. )";
  148. CompileSuccessfully(GenerateShaderCode(body));
  149. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  150. }
  151. TEST_F(ValidateAdjacency, OpPhiPreceededByOpLineSuccess) {
  152. const std::string body = R"(
  153. OpSelectionMerge %end_label None
  154. OpBranchConditional %true %true_label %false_label
  155. %true_label = OpLabel
  156. OpBranch %end_label
  157. %false_label = OpLabel
  158. OpBranch %end_label
  159. %end_label = OpLabel
  160. OpLine %string 0 0
  161. %result = OpPhi %bool %true %true_label %false %false_label
  162. )";
  163. CompileSuccessfully(GenerateShaderCode(body));
  164. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  165. }
  166. TEST_F(ValidateAdjacency, OpPhiPreceededByBadOpFail) {
  167. const std::string body = R"(
  168. OpSelectionMerge %end_label None
  169. OpBranchConditional %true %true_label %false_label
  170. %true_label = OpLabel
  171. OpBranch %end_label
  172. %false_label = OpLabel
  173. OpBranch %end_label
  174. %end_label = OpLabel
  175. OpNop
  176. %result = OpPhi %bool %true %true_label %false %false_label
  177. )";
  178. CompileSuccessfully(GenerateShaderCode(body));
  179. EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
  180. EXPECT_THAT(getDiagnosticString(),
  181. HasSubstr("OpPhi must appear within a non-entry block before all "
  182. "non-OpPhi instructions"));
  183. }
  184. TEST_F(ValidateAdjacency, OpPhiPreceededByOpLineAndBadOpFail) {
  185. const std::string body = R"(
  186. OpSelectionMerge %end_label None
  187. OpBranchConditional %true %true_label %false_label
  188. %true_label = OpLabel
  189. OpBranch %end_label
  190. %false_label = OpLabel
  191. OpBranch %end_label
  192. %end_label = OpLabel
  193. OpNop
  194. OpLine %string 1 1
  195. %result = OpPhi %bool %true %true_label %false %false_label
  196. )";
  197. CompileSuccessfully(GenerateShaderCode(body));
  198. EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
  199. EXPECT_THAT(getDiagnosticString(),
  200. HasSubstr("OpPhi must appear within a non-entry block before all "
  201. "non-OpPhi instructions"));
  202. }
  203. TEST_F(ValidateAdjacency, OpPhiFollowedByOpLineGood) {
  204. const std::string body = R"(
  205. OpSelectionMerge %end_label None
  206. OpBranchConditional %true %true_label %false_label
  207. %true_label = OpLabel
  208. OpBranch %end_label
  209. %false_label = OpLabel
  210. OpBranch %end_label
  211. %end_label = OpLabel
  212. %result = OpPhi %bool %true %true_label %false %false_label
  213. OpLine %string 1 1
  214. OpNop
  215. OpNop
  216. OpLine %string 2 1
  217. OpNop
  218. OpLine %string 3 1
  219. )";
  220. CompileSuccessfully(GenerateShaderCode(body));
  221. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  222. }
  223. TEST_F(ValidateAdjacency, OpPhiMultipleOpLineAndOpPhiFail) {
  224. const std::string body = R"(
  225. OpSelectionMerge %end_label None
  226. OpBranchConditional %true %true_label %false_label
  227. %true_label = OpLabel
  228. OpBranch %end_label
  229. %false_label = OpLabel
  230. OpBranch %end_label
  231. %end_label = OpLabel
  232. OpLine %string 1 1
  233. %value = OpPhi %int %zero %true_label %int_1 %false_label
  234. OpNop
  235. OpLine %string 2 1
  236. OpNop
  237. OpLine %string 3 1
  238. %result = OpPhi %bool %true %true_label %false %false_label
  239. )";
  240. CompileSuccessfully(GenerateShaderCode(body));
  241. EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
  242. EXPECT_THAT(getDiagnosticString(),
  243. HasSubstr("OpPhi must appear within a non-entry block before all "
  244. "non-OpPhi instructions"));
  245. }
  246. TEST_F(ValidateAdjacency, OpPhiMultipleOpLineAndOpPhiGood) {
  247. const std::string body = R"(
  248. OpSelectionMerge %end_label None
  249. OpBranchConditional %true %true_label %false_label
  250. %true_label = OpLabel
  251. OpBranch %end_label
  252. %false_label = OpLabel
  253. OpBranch %end_label
  254. %end_label = OpLabel
  255. OpLine %string 1 1
  256. %value = OpPhi %int %zero %true_label %int_1 %false_label
  257. OpLine %string 2 1
  258. %result = OpPhi %bool %true %true_label %false %false_label
  259. OpLine %string 3 1
  260. OpNop
  261. OpNop
  262. OpLine %string 4 1
  263. OpNop
  264. )";
  265. CompileSuccessfully(GenerateShaderCode(body));
  266. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  267. }
  268. TEST_F(ValidateAdjacency, OpPhiInEntryBlockBad) {
  269. const std::string body = R"(
  270. OpLine %string 1 1
  271. %value = OpPhi %int
  272. OpLine %string 2 1
  273. OpNop
  274. OpLine %string 3 1
  275. OpNop
  276. )";
  277. CompileSuccessfully(GenerateShaderCode(body));
  278. EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
  279. EXPECT_THAT(getDiagnosticString(),
  280. HasSubstr("OpPhi must appear within a non-entry block before all "
  281. "non-OpPhi instructions"));
  282. }
  283. TEST_F(ValidateAdjacency, NonSemanticBeforeOpPhiBad) {
  284. const std::string body = R"(
  285. OpSelectionMerge %end_label None
  286. OpBranchConditional %true %true_label %false_label
  287. %true_label = OpLabel
  288. OpBranch %end_label
  289. %false_label = OpLabel
  290. OpBranch %end_label
  291. %end_label = OpLabel
  292. %placeholder = OpExtInst %void %extinst 123 %int_1
  293. %result = OpPhi %bool %true %true_label %false %false_label
  294. )";
  295. const std::string extra = R"(OpCapability Shader
  296. OpExtension "SPV_KHR_non_semantic_info"
  297. %extinst = OpExtInstImport "NonSemantic.Testing.Set"
  298. )";
  299. CompileSuccessfully(GenerateShaderCode(body, extra));
  300. EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
  301. EXPECT_THAT(getDiagnosticString(),
  302. HasSubstr("OpPhi must appear within a non-entry block before all "
  303. "non-OpPhi instructions"));
  304. }
  305. TEST_F(ValidateAdjacency, NonSemanticBetweenOpPhiBad) {
  306. const std::string body = R"(
  307. OpSelectionMerge %end_label None
  308. OpBranchConditional %true %true_label %false_label
  309. %true_label = OpLabel
  310. OpBranch %end_label
  311. %false_label = OpLabel
  312. OpBranch %end_label
  313. %end_label = OpLabel
  314. %result1 = OpPhi %bool %true %true_label %false %false_label
  315. %placeholder = OpExtInst %void %extinst 123 %int_1
  316. %result2 = OpPhi %bool %true %true_label %false %false_label
  317. )";
  318. const std::string extra = R"(OpCapability Shader
  319. OpExtension "SPV_KHR_non_semantic_info"
  320. %extinst = OpExtInstImport "NonSemantic.Testing.Set"
  321. )";
  322. CompileSuccessfully(GenerateShaderCode(body, extra));
  323. EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
  324. EXPECT_THAT(getDiagnosticString(),
  325. HasSubstr("OpPhi must appear within a non-entry block before all "
  326. "non-OpPhi instructions"));
  327. }
  328. TEST_F(ValidateAdjacency, NonSemanticAfterOpPhiGood) {
  329. const std::string body = R"(
  330. OpSelectionMerge %end_label None
  331. OpBranchConditional %true %true_label %false_label
  332. %true_label = OpLabel
  333. OpBranch %end_label
  334. %false_label = OpLabel
  335. OpBranch %end_label
  336. %end_label = OpLabel
  337. OpLine %string 0 0
  338. %result = OpPhi %bool %true %true_label %false %false_label
  339. %placeholder = OpExtInst %void %extinst 123 %int_1
  340. )";
  341. const std::string extra = R"(OpCapability Shader
  342. OpExtension "SPV_KHR_non_semantic_info"
  343. %extinst = OpExtInstImport "NonSemantic.Testing.Set"
  344. )";
  345. CompileSuccessfully(GenerateShaderCode(body, extra));
  346. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  347. }
  348. TEST_F(ValidateAdjacency, NonSemanticBeforeOpFunctionParameterBad) {
  349. const std::string body = R"(
  350. OpCapability Shader
  351. OpExtension "SPV_KHR_non_semantic_info"
  352. %extinst = OpExtInstImport "NonSemantic.Testing.Set"
  353. OpMemoryModel Logical GLSL450
  354. OpEntryPoint Fragment %main "main"
  355. OpExecutionMode %main OriginUpperLeft
  356. %string = OpString ""
  357. %void = OpTypeVoid
  358. %bool = OpTypeBool
  359. %int = OpTypeInt 32 0
  360. %true = OpConstantTrue %bool
  361. %false = OpConstantFalse %bool
  362. %zero = OpConstant %int 0
  363. %int_1 = OpConstant %int 1
  364. %func = OpTypeFunction %void
  365. %func_int = OpTypePointer Function %int
  366. %paramfunc_type = OpTypeFunction %void %int %int
  367. %paramfunc = OpFunction %void None %paramfunc_type
  368. %placeholder = OpExtInst %void %extinst 123 %int_1
  369. %a = OpFunctionParameter %int
  370. %b = OpFunctionParameter %int
  371. %paramfunc_entry = OpLabel
  372. OpReturn
  373. OpFunctionEnd
  374. %main = OpFunction %void None %func
  375. %main_entry = OpLabel
  376. OpReturn
  377. OpFunctionEnd
  378. )";
  379. CompileSuccessfully(body);
  380. EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions());
  381. EXPECT_THAT(getDiagnosticString(),
  382. HasSubstr("Non-semantic OpExtInst within function definition "
  383. "must appear in a block"));
  384. }
  385. TEST_F(ValidateAdjacency, NonSemanticBetweenOpFunctionParameterBad) {
  386. const std::string body = R"(
  387. OpCapability Shader
  388. OpExtension "SPV_KHR_non_semantic_info"
  389. %extinst = OpExtInstImport "NonSemantic.Testing.Set"
  390. OpMemoryModel Logical GLSL450
  391. OpEntryPoint Fragment %main "main"
  392. OpExecutionMode %main OriginUpperLeft
  393. %string = OpString ""
  394. %void = OpTypeVoid
  395. %bool = OpTypeBool
  396. %int = OpTypeInt 32 0
  397. %true = OpConstantTrue %bool
  398. %false = OpConstantFalse %bool
  399. %zero = OpConstant %int 0
  400. %int_1 = OpConstant %int 1
  401. %func = OpTypeFunction %void
  402. %func_int = OpTypePointer Function %int
  403. %paramfunc_type = OpTypeFunction %void %int %int
  404. %paramfunc = OpFunction %void None %paramfunc_type
  405. %a = OpFunctionParameter %int
  406. %placeholder = OpExtInst %void %extinst 123 %int_1
  407. %b = OpFunctionParameter %int
  408. %paramfunc_entry = OpLabel
  409. OpReturn
  410. OpFunctionEnd
  411. %main = OpFunction %void None %func
  412. %main_entry = OpLabel
  413. OpReturn
  414. OpFunctionEnd
  415. )";
  416. CompileSuccessfully(body);
  417. EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions());
  418. EXPECT_THAT(getDiagnosticString(),
  419. HasSubstr("Non-semantic OpExtInst within function definition "
  420. "must appear in a block"));
  421. }
  422. TEST_F(ValidateAdjacency, NonSemanticAfterOpFunctionParameterGood) {
  423. const std::string body = R"(
  424. OpCapability Shader
  425. OpExtension "SPV_KHR_non_semantic_info"
  426. %extinst = OpExtInstImport "NonSemantic.Testing.Set"
  427. OpMemoryModel Logical GLSL450
  428. OpEntryPoint Fragment %main "main"
  429. OpExecutionMode %main OriginUpperLeft
  430. %string = OpString ""
  431. %void = OpTypeVoid
  432. %bool = OpTypeBool
  433. %int = OpTypeInt 32 0
  434. %true = OpConstantTrue %bool
  435. %false = OpConstantFalse %bool
  436. %zero = OpConstant %int 0
  437. %int_1 = OpConstant %int 1
  438. %func = OpTypeFunction %void
  439. %func_int = OpTypePointer Function %int
  440. %paramfunc_type = OpTypeFunction %void %int %int
  441. %paramfunc = OpFunction %void None %paramfunc_type
  442. %a = OpFunctionParameter %int
  443. %b = OpFunctionParameter %int
  444. %paramfunc_entry = OpLabel
  445. %placeholder = OpExtInst %void %extinst 123 %int_1
  446. OpReturn
  447. OpFunctionEnd
  448. %main = OpFunction %void None %func
  449. %main_entry = OpLabel
  450. OpReturn
  451. OpFunctionEnd
  452. )";
  453. CompileSuccessfully(body);
  454. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  455. }
  456. TEST_F(ValidateAdjacency, NonSemanticBetweenFunctionsGood) {
  457. const std::string body = R"(
  458. OpCapability Shader
  459. OpExtension "SPV_KHR_non_semantic_info"
  460. %extinst = OpExtInstImport "NonSemantic.Testing.Set"
  461. OpMemoryModel Logical GLSL450
  462. OpEntryPoint Fragment %main "main"
  463. OpExecutionMode %main OriginUpperLeft
  464. %string = OpString ""
  465. %void = OpTypeVoid
  466. %bool = OpTypeBool
  467. %int = OpTypeInt 32 0
  468. %true = OpConstantTrue %bool
  469. %false = OpConstantFalse %bool
  470. %zero = OpConstant %int 0
  471. %int_1 = OpConstant %int 1
  472. %func = OpTypeFunction %void
  473. %func_int = OpTypePointer Function %int
  474. %paramfunc_type = OpTypeFunction %void %int %int
  475. %paramfunc = OpFunction %void None %paramfunc_type
  476. %a = OpFunctionParameter %int
  477. %b = OpFunctionParameter %int
  478. %paramfunc_entry = OpLabel
  479. OpReturn
  480. OpFunctionEnd
  481. %placeholder = OpExtInst %void %extinst 123 %int_1
  482. %main = OpFunction %void None %func
  483. %main_entry = OpLabel
  484. OpReturn
  485. OpFunctionEnd
  486. )";
  487. CompileSuccessfully(body);
  488. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  489. }
  490. TEST_F(ValidateAdjacency, OpVariableInFunctionGood) {
  491. const std::string body = R"(
  492. OpLine %string 1 1
  493. %var = OpVariable %func_int Function
  494. OpLine %string 2 1
  495. OpNop
  496. OpLine %string 3 1
  497. OpNop
  498. )";
  499. CompileSuccessfully(GenerateShaderCode(body));
  500. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  501. }
  502. TEST_F(ValidateAdjacency, OpVariableInFunctionMultipleGood) {
  503. const std::string body = R"(
  504. OpLine %string 1 1
  505. %1 = OpVariable %func_int Function
  506. OpLine %string 2 1
  507. %2 = OpVariable %func_int Function
  508. %3 = OpVariable %func_int Function
  509. OpNop
  510. OpLine %string 3 1
  511. OpNop
  512. )";
  513. CompileSuccessfully(GenerateShaderCode(body));
  514. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  515. }
  516. TEST_F(ValidateAdjacency, OpVariableInFunctionBad) {
  517. const std::string body = R"(
  518. %1 = OpUndef %int
  519. %2 = OpVariable %func_int Function
  520. )";
  521. CompileSuccessfully(GenerateShaderCode(body));
  522. EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
  523. EXPECT_THAT(getDiagnosticString(),
  524. HasSubstr("All OpVariable instructions in a function must be the "
  525. "first instructions"));
  526. }
  527. TEST_F(ValidateAdjacency, OpVariableInFunctionMultipleBad) {
  528. const std::string body = R"(
  529. OpNop
  530. %1 = OpVariable %func_int Function
  531. OpLine %string 1 1
  532. %2 = OpVariable %func_int Function
  533. OpNop
  534. OpNop
  535. OpLine %string 2 1
  536. %3 = OpVariable %func_int Function
  537. )";
  538. CompileSuccessfully(GenerateShaderCode(body));
  539. EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
  540. EXPECT_THAT(getDiagnosticString(),
  541. HasSubstr("All OpVariable instructions in a function must be the "
  542. "first instructions"));
  543. }
  544. TEST_F(ValidateAdjacency, OpLoopMergePreceedsOpBranchSuccess) {
  545. const std::string body = R"(
  546. OpBranch %loop
  547. %loop = OpLabel
  548. OpLoopMerge %end %loop None
  549. OpBranch %loop
  550. %end = OpLabel
  551. )";
  552. CompileSuccessfully(GenerateShaderCode(body));
  553. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  554. }
  555. TEST_F(ValidateAdjacency, OpLoopMergePreceedsOpBranchConditionalSuccess) {
  556. const std::string body = R"(
  557. OpBranch %loop
  558. %loop = OpLabel
  559. OpLoopMerge %end %loop None
  560. OpBranchConditional %true %loop %end
  561. %end = OpLabel
  562. )";
  563. CompileSuccessfully(GenerateShaderCode(body));
  564. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  565. }
  566. TEST_F(ValidateAdjacency, OpLoopMergePreceedsBadOpFail) {
  567. const std::string body = R"(
  568. OpBranch %loop
  569. %loop = OpLabel
  570. OpLoopMerge %end %loop None
  571. OpNop
  572. OpBranchConditional %true %loop %end
  573. %end = OpLabel
  574. )";
  575. CompileSuccessfully(GenerateShaderCode(body));
  576. EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
  577. EXPECT_THAT(getDiagnosticString(),
  578. HasSubstr("OpLoopMerge must immediately precede either an "
  579. "OpBranch or OpBranchConditional instruction."));
  580. }
  581. TEST_F(ValidateAdjacency, OpSelectionMergePreceedsOpBranchConditionalSuccess) {
  582. const std::string body = R"(
  583. OpSelectionMerge %end_label None
  584. OpBranchConditional %true %true_label %false_label
  585. %true_label = OpLabel
  586. OpBranch %end_label
  587. %false_label = OpLabel
  588. OpBranch %end_label
  589. %end_label = OpLabel
  590. )";
  591. CompileSuccessfully(GenerateShaderCode(body));
  592. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  593. }
  594. TEST_F(ValidateAdjacency, OpSelectionMergePreceedsOpSwitchSuccess) {
  595. const std::string body = R"(
  596. OpSelectionMerge %merge None
  597. OpSwitch %zero %merge 0 %label
  598. %label = OpLabel
  599. OpBranch %merge
  600. %merge = OpLabel
  601. )";
  602. CompileSuccessfully(GenerateShaderCode(body));
  603. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  604. }
  605. TEST_F(ValidateAdjacency, OpSelectionMergePreceedsBadOpFail) {
  606. const std::string body = R"(
  607. OpSelectionMerge %merge None
  608. OpNop
  609. OpSwitch %zero %merge 0 %label
  610. %label = OpLabel
  611. OpBranch %merge
  612. %merge = OpLabel
  613. )";
  614. CompileSuccessfully(GenerateShaderCode(body));
  615. EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
  616. EXPECT_THAT(getDiagnosticString(),
  617. HasSubstr("OpSelectionMerge must immediately precede either an "
  618. "OpBranchConditional or OpSwitch instruction"));
  619. }
  620. } // namespace
  621. } // namespace val
  622. } // namespace spvtools