interface_var_sroa_test.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. // Copyright (c) 2022 Google LLC
  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 <iostream>
  15. #include "gmock/gmock.h"
  16. #include "test/opt/assembly_builder.h"
  17. #include "test/opt/pass_fixture.h"
  18. #include "test/opt/pass_utils.h"
  19. namespace spvtools {
  20. namespace opt {
  21. namespace {
  22. using InterfaceVariableScalarReplacementTest = PassTest<::testing::Test>;
  23. TEST_F(InterfaceVariableScalarReplacementTest,
  24. ReplaceInterfaceVarsWithScalars) {
  25. const std::string spirv = R"(
  26. OpCapability Shader
  27. OpCapability Tessellation
  28. OpMemoryModel Logical GLSL450
  29. OpEntryPoint TessellationControl %func "shader" %x %y %z %w %u %v
  30. ; CHECK: OpName [[x:%\w+]] "x"
  31. ; CHECK-NOT: OpName {{%\w+}} "x"
  32. ; CHECK: OpName [[y:%\w+]] "y"
  33. ; CHECK-NOT: OpName {{%\w+}} "y"
  34. ; CHECK: OpName [[z0:%\w+]] "z"
  35. ; CHECK: OpName [[z1:%\w+]] "z"
  36. ; CHECK: OpName [[w0:%\w+]] "w"
  37. ; CHECK: OpName [[w1:%\w+]] "w"
  38. ; CHECK: OpName [[u0:%\w+]] "u"
  39. ; CHECK: OpName [[u1:%\w+]] "u"
  40. ; CHECK: OpName [[v0:%\w+]] "v"
  41. ; CHECK: OpName [[v1:%\w+]] "v"
  42. ; CHECK: OpName [[v2:%\w+]] "v"
  43. ; CHECK: OpName [[v3:%\w+]] "v"
  44. ; CHECK: OpName [[v4:%\w+]] "v"
  45. ; CHECK: OpName [[v5:%\w+]] "v"
  46. OpName %x "x"
  47. OpName %y "y"
  48. OpName %z "z"
  49. OpName %w "w"
  50. OpName %u "u"
  51. OpName %v "v"
  52. ; CHECK-DAG: OpDecorate [[x]] Location 2
  53. ; CHECK-DAG: OpDecorate [[y]] Location 0
  54. ; CHECK-DAG: OpDecorate [[z0]] Location 0
  55. ; CHECK-DAG: OpDecorate [[z0]] Component 0
  56. ; CHECK-DAG: OpDecorate [[z1]] Location 1
  57. ; CHECK-DAG: OpDecorate [[z1]] Component 0
  58. ; CHECK-DAG: OpDecorate [[z0]] Patch
  59. ; CHECK-DAG: OpDecorate [[z1]] Patch
  60. ; CHECK-DAG: OpDecorate [[w0]] Location 2
  61. ; CHECK-DAG: OpDecorate [[w0]] Component 0
  62. ; CHECK-DAG: OpDecorate [[w1]] Location 3
  63. ; CHECK-DAG: OpDecorate [[w1]] Component 0
  64. ; CHECK-DAG: OpDecorate [[w0]] Patch
  65. ; CHECK-DAG: OpDecorate [[w1]] Patch
  66. ; CHECK-DAG: OpDecorate [[u0]] Location 3
  67. ; CHECK-DAG: OpDecorate [[u0]] Component 2
  68. ; CHECK-DAG: OpDecorate [[u1]] Location 4
  69. ; CHECK-DAG: OpDecorate [[u1]] Component 2
  70. ; CHECK-DAG: OpDecorate [[v0]] Location 3
  71. ; CHECK-DAG: OpDecorate [[v0]] Component 3
  72. ; CHECK-DAG: OpDecorate [[v1]] Location 4
  73. ; CHECK-DAG: OpDecorate [[v1]] Component 3
  74. ; CHECK-DAG: OpDecorate [[v2]] Location 5
  75. ; CHECK-DAG: OpDecorate [[v2]] Component 3
  76. ; CHECK-DAG: OpDecorate [[v3]] Location 6
  77. ; CHECK-DAG: OpDecorate [[v3]] Component 3
  78. ; CHECK-DAG: OpDecorate [[v4]] Location 7
  79. ; CHECK-DAG: OpDecorate [[v4]] Component 3
  80. ; CHECK-DAG: OpDecorate [[v5]] Location 8
  81. ; CHECK-DAG: OpDecorate [[v5]] Component 3
  82. OpDecorate %z Patch
  83. OpDecorate %w Patch
  84. OpDecorate %z Location 0
  85. OpDecorate %x Location 2
  86. OpDecorate %v Location 3
  87. OpDecorate %v Component 3
  88. OpDecorate %y Location 0
  89. OpDecorate %w Location 2
  90. OpDecorate %u Location 3
  91. OpDecorate %u Component 2
  92. %uint = OpTypeInt 32 0
  93. %uint_1 = OpConstant %uint 1
  94. %uint_2 = OpConstant %uint 2
  95. %uint_3 = OpConstant %uint 3
  96. %uint_4 = OpConstant %uint 4
  97. %_arr_uint_uint_2 = OpTypeArray %uint %uint_2
  98. %_ptr_Output__arr_uint_uint_2 = OpTypePointer Output %_arr_uint_uint_2
  99. %_ptr_Input__arr_uint_uint_2 = OpTypePointer Input %_arr_uint_uint_2
  100. %_ptr_Input_uint = OpTypePointer Input %uint
  101. %_ptr_Output_uint = OpTypePointer Output %uint
  102. %_arr_arr_uint_uint_2_3 = OpTypeArray %_arr_uint_uint_2 %uint_3
  103. %_ptr_Input__arr_arr_uint_uint_2_3 = OpTypePointer Input %_arr_arr_uint_uint_2_3
  104. %_arr_arr_arr_uint_uint_2_3_4 = OpTypeArray %_arr_arr_uint_uint_2_3 %uint_4
  105. %_ptr_Output__arr_arr_arr_uint_uint_2_3_4 = OpTypePointer Output %_arr_arr_arr_uint_uint_2_3_4
  106. %_ptr_Output__arr_arr_uint_uint_2_3 = OpTypePointer Output %_arr_arr_uint_uint_2_3
  107. %z = OpVariable %_ptr_Output__arr_uint_uint_2 Output
  108. %x = OpVariable %_ptr_Output__arr_uint_uint_2 Output
  109. %y = OpVariable %_ptr_Input__arr_uint_uint_2 Input
  110. %w = OpVariable %_ptr_Input__arr_uint_uint_2 Input
  111. %u = OpVariable %_ptr_Input__arr_arr_uint_uint_2_3 Input
  112. %v = OpVariable %_ptr_Output__arr_arr_arr_uint_uint_2_3_4 Output
  113. ; CHECK-DAG: [[x]] = OpVariable %_ptr_Output__arr_uint_uint_2 Output
  114. ; CHECK-DAG: [[y]] = OpVariable %_ptr_Input__arr_uint_uint_2 Input
  115. ; CHECK-DAG: [[z0]] = OpVariable %_ptr_Output_uint Output
  116. ; CHECK-DAG: [[z1]] = OpVariable %_ptr_Output_uint Output
  117. ; CHECK-DAG: [[w0]] = OpVariable %_ptr_Input_uint Input
  118. ; CHECK-DAG: [[w1]] = OpVariable %_ptr_Input_uint Input
  119. ; CHECK-DAG: [[u0]] = OpVariable %_ptr_Input__arr_uint_uint_3 Input
  120. ; CHECK-DAG: [[u1]] = OpVariable %_ptr_Input__arr_uint_uint_3 Input
  121. ; CHECK-DAG: [[v0]] = OpVariable %_ptr_Output__arr_uint_uint_4 Output
  122. ; CHECK-DAG: [[v1]] = OpVariable %_ptr_Output__arr_uint_uint_4 Output
  123. ; CHECK-DAG: [[v2]] = OpVariable %_ptr_Output__arr_uint_uint_4 Output
  124. ; CHECK-DAG: [[v3]] = OpVariable %_ptr_Output__arr_uint_uint_4 Output
  125. ; CHECK-DAG: [[v4]] = OpVariable %_ptr_Output__arr_uint_uint_4 Output
  126. ; CHECK-DAG: [[v5]] = OpVariable %_ptr_Output__arr_uint_uint_4 Output
  127. %void = OpTypeVoid
  128. %void_f = OpTypeFunction %void
  129. %func = OpFunction %void None %void_f
  130. %label = OpLabel
  131. ; CHECK: [[w0_value:%\w+]] = OpLoad %uint [[w0]]
  132. ; CHECK: [[w1_value:%\w+]] = OpLoad %uint [[w1]]
  133. ; CHECK: [[w_value:%\w+]] = OpCompositeConstruct %_arr_uint_uint_2 [[w0_value]] [[w1_value]]
  134. ; CHECK: [[w0:%\w+]] = OpCompositeExtract %uint [[w_value]] 0
  135. ; CHECK: OpStore [[z0]] [[w0]]
  136. ; CHECK: [[w1:%\w+]] = OpCompositeExtract %uint [[w_value]] 1
  137. ; CHECK: OpStore [[z1]] [[w1]]
  138. %w_value = OpLoad %_arr_uint_uint_2 %w
  139. OpStore %z %w_value
  140. ; CHECK: [[u00_ptr:%\w+]] = OpAccessChain %_ptr_Input_uint [[u0]] %uint_0
  141. ; CHECK: [[u00:%\w+]] = OpLoad %uint [[u00_ptr]]
  142. ; CHECK: [[u10_ptr:%\w+]] = OpAccessChain %_ptr_Input_uint [[u1]] %uint_0
  143. ; CHECK: [[u10:%\w+]] = OpLoad %uint [[u10_ptr]]
  144. ; CHECK: [[u01_ptr:%\w+]] = OpAccessChain %_ptr_Input_uint [[u0]] %uint_1
  145. ; CHECK: [[u01:%\w+]] = OpLoad %uint [[u01_ptr]]
  146. ; CHECK: [[u11_ptr:%\w+]] = OpAccessChain %_ptr_Input_uint [[u1]] %uint_1
  147. ; CHECK: [[u11:%\w+]] = OpLoad %uint [[u11_ptr]]
  148. ; CHECK: [[u02_ptr:%\w+]] = OpAccessChain %_ptr_Input_uint [[u0]] %uint_2
  149. ; CHECK: [[u02:%\w+]] = OpLoad %uint [[u02_ptr]]
  150. ; CHECK: [[u12_ptr:%\w+]] = OpAccessChain %_ptr_Input_uint [[u1]] %uint_2
  151. ; CHECK: [[u12:%\w+]] = OpLoad %uint [[u12_ptr]]
  152. ; CHECK-DAG: [[u0_val:%\w+]] = OpCompositeConstruct %_arr_uint_uint_2 [[u00]] [[u10]]
  153. ; CHECK-DAG: [[u1_val:%\w+]] = OpCompositeConstruct %_arr_uint_uint_2 [[u01]] [[u11]]
  154. ; CHECK-DAG: [[u2_val:%\w+]] = OpCompositeConstruct %_arr_uint_uint_2 [[u02]] [[u12]]
  155. ; CHECK: [[u_val:%\w+]] = OpCompositeConstruct %_arr__arr_uint_uint_2_uint_3 [[u0_val]] [[u1_val]] [[u2_val]]
  156. ; CHECK: [[ptr:%\w+]] = OpAccessChain %_ptr_Output_uint [[v0]] %uint_1
  157. ; CHECK: [[val:%\w+]] = OpCompositeExtract %uint [[u_val]] 0 0
  158. ; CHECK: OpStore [[ptr]] [[val]]
  159. ; CHECK: [[ptr:%\w+]] = OpAccessChain %_ptr_Output_uint [[v1]] %uint_1
  160. ; CHECK: [[val:%\w+]] = OpCompositeExtract %uint [[u_val]] 0 1
  161. ; CHECK: OpStore [[ptr]] [[val]]
  162. ; CHECK: [[ptr:%\w+]] = OpAccessChain %_ptr_Output_uint [[v2]] %uint_1
  163. ; CHECK: [[val:%\w+]] = OpCompositeExtract %uint [[u_val]] 1 0
  164. ; CHECK: OpStore [[ptr]] [[val]]
  165. ; CHECK: [[ptr:%\w+]] = OpAccessChain %_ptr_Output_uint [[v3]] %uint_1
  166. ; CHECK: [[val:%\w+]] = OpCompositeExtract %uint [[u_val]] 1 1
  167. ; CHECK: OpStore [[ptr]] [[val]]
  168. ; CHECK: [[ptr:%\w+]] = OpAccessChain %_ptr_Output_uint [[v4]] %uint_1
  169. ; CHECK: [[val:%\w+]] = OpCompositeExtract %uint [[u_val]] 2 0
  170. ; CHECK: OpStore [[ptr]] [[val]]
  171. ; CHECK: [[ptr:%\w+]] = OpAccessChain %_ptr_Output_uint [[v5]] %uint_1
  172. ; CHECK: [[val:%\w+]] = OpCompositeExtract %uint [[u_val]] 2 1
  173. ; CHECK: OpStore [[ptr]] [[val]]
  174. %v_ptr = OpAccessChain %_ptr_Output__arr_arr_uint_uint_2_3 %v %uint_1
  175. %u_val = OpLoad %_arr_arr_uint_uint_2_3 %u
  176. OpStore %v_ptr %u_val
  177. OpReturn
  178. OpFunctionEnd
  179. )";
  180. SinglePassRunAndMatch<InterfaceVariableScalarReplacement>(spirv, true);
  181. }
  182. TEST_F(InterfaceVariableScalarReplacementTest,
  183. CheckPatchDecorationPreservation) {
  184. // Make sure scalars for the variables with the extra arrayness have the extra
  185. // arrayness after running the pass while others do not have it.
  186. // Only "y" does not have the extra arrayness in the following SPIR-V.
  187. const std::string spirv = R"(
  188. OpCapability Shader
  189. OpCapability Tessellation
  190. OpMemoryModel Logical GLSL450
  191. OpEntryPoint TessellationEvaluation %func "shader" %x %y %z %w
  192. OpDecorate %z Patch
  193. OpDecorate %w Patch
  194. OpDecorate %z Location 0
  195. OpDecorate %x Location 2
  196. OpDecorate %y Location 0
  197. OpDecorate %w Location 1
  198. OpName %x "x"
  199. OpName %y "y"
  200. OpName %z "z"
  201. OpName %w "w"
  202. ; CHECK: OpName [[y:%\w+]] "y"
  203. ; CHECK-NOT: OpName {{%\w+}} "y"
  204. ; CHECK-DAG: OpName [[z0:%\w+]] "z"
  205. ; CHECK-DAG: OpName [[z1:%\w+]] "z"
  206. ; CHECK-DAG: OpName [[w0:%\w+]] "w"
  207. ; CHECK-DAG: OpName [[w1:%\w+]] "w"
  208. ; CHECK-DAG: OpName [[x0:%\w+]] "x"
  209. ; CHECK-DAG: OpName [[x1:%\w+]] "x"
  210. %uint = OpTypeInt 32 0
  211. %uint_2 = OpConstant %uint 2
  212. %_arr_uint_uint_2 = OpTypeArray %uint %uint_2
  213. %_ptr_Output__arr_uint_uint_2 = OpTypePointer Output %_arr_uint_uint_2
  214. %_ptr_Input__arr_uint_uint_2 = OpTypePointer Input %_arr_uint_uint_2
  215. %z = OpVariable %_ptr_Output__arr_uint_uint_2 Output
  216. %x = OpVariable %_ptr_Output__arr_uint_uint_2 Output
  217. %y = OpVariable %_ptr_Input__arr_uint_uint_2 Input
  218. %w = OpVariable %_ptr_Input__arr_uint_uint_2 Input
  219. ; CHECK-DAG: [[y]] = OpVariable %_ptr_Input__arr_uint_uint_2 Input
  220. ; CHECK-DAG: [[z0]] = OpVariable %_ptr_Output_uint Output
  221. ; CHECK-DAG: [[z1]] = OpVariable %_ptr_Output_uint Output
  222. ; CHECK-DAG: [[w0]] = OpVariable %_ptr_Input_uint Input
  223. ; CHECK-DAG: [[w1]] = OpVariable %_ptr_Input_uint Input
  224. ; CHECK-DAG: [[x0]] = OpVariable %_ptr_Output_uint Output
  225. ; CHECK-DAG: [[x1]] = OpVariable %_ptr_Output_uint Output
  226. %void = OpTypeVoid
  227. %void_f = OpTypeFunction %void
  228. %func = OpFunction %void None %void_f
  229. %label = OpLabel
  230. OpReturn
  231. OpFunctionEnd
  232. )";
  233. SinglePassRunAndMatch<InterfaceVariableScalarReplacement>(spirv, true);
  234. }
  235. TEST_F(InterfaceVariableScalarReplacementTest,
  236. CheckEntryPointInterfaceOperands) {
  237. const std::string spirv = R"(
  238. OpCapability Shader
  239. OpCapability Tessellation
  240. OpMemoryModel Logical GLSL450
  241. OpEntryPoint TessellationEvaluation %tess "tess" %x %y
  242. OpEntryPoint Vertex %vert "vert" %w
  243. OpDecorate %z Location 0
  244. OpDecorate %x Location 2
  245. OpDecorate %y Location 0
  246. OpDecorate %w Location 1
  247. OpName %x "x"
  248. OpName %y "y"
  249. OpName %z "z"
  250. OpName %w "w"
  251. ; CHECK: OpName [[y:%\w+]] "y"
  252. ; CHECK-NOT: OpName {{%\w+}} "y"
  253. ; CHECK-DAG: OpName [[x0:%\w+]] "x"
  254. ; CHECK-DAG: OpName [[x1:%\w+]] "x"
  255. ; CHECK-DAG: OpName [[w0:%\w+]] "w"
  256. ; CHECK-DAG: OpName [[w1:%\w+]] "w"
  257. ; CHECK-DAG: OpName [[z:%\w+]] "z"
  258. ; CHECK-NOT: OpName {{%\w+}} "z"
  259. %uint = OpTypeInt 32 0
  260. %uint_2 = OpConstant %uint 2
  261. %_arr_uint_uint_2 = OpTypeArray %uint %uint_2
  262. %_ptr_Output__arr_uint_uint_2 = OpTypePointer Output %_arr_uint_uint_2
  263. %_ptr_Input__arr_uint_uint_2 = OpTypePointer Input %_arr_uint_uint_2
  264. %z = OpVariable %_ptr_Output__arr_uint_uint_2 Output
  265. %x = OpVariable %_ptr_Output__arr_uint_uint_2 Output
  266. %y = OpVariable %_ptr_Input__arr_uint_uint_2 Input
  267. %w = OpVariable %_ptr_Input__arr_uint_uint_2 Input
  268. ; CHECK-DAG: [[y]] = OpVariable %_ptr_Input__arr_uint_uint_2 Input
  269. ; CHECK-DAG: [[z]] = OpVariable %_ptr_Output__arr_uint_uint_2 Output
  270. ; CHECK-DAG: [[w0]] = OpVariable %_ptr_Input_uint Input
  271. ; CHECK-DAG: [[w1]] = OpVariable %_ptr_Input_uint Input
  272. ; CHECK-DAG: [[x0]] = OpVariable %_ptr_Output_uint Output
  273. ; CHECK-DAG: [[x1]] = OpVariable %_ptr_Output_uint Output
  274. %void = OpTypeVoid
  275. %void_f = OpTypeFunction %void
  276. %tess = OpFunction %void None %void_f
  277. %bb0 = OpLabel
  278. OpReturn
  279. OpFunctionEnd
  280. %vert = OpFunction %void None %void_f
  281. %bb1 = OpLabel
  282. OpReturn
  283. OpFunctionEnd
  284. )";
  285. SinglePassRunAndMatch<InterfaceVariableScalarReplacement>(spirv, true);
  286. }
  287. class InterfaceVarSROAErrorTest : public PassTest<::testing::Test> {
  288. public:
  289. InterfaceVarSROAErrorTest()
  290. : consumer_([this](spv_message_level_t level, const char*,
  291. const spv_position_t& position, const char* message) {
  292. if (!error_message_.empty()) error_message_ += "\n";
  293. switch (level) {
  294. case SPV_MSG_FATAL:
  295. case SPV_MSG_INTERNAL_ERROR:
  296. case SPV_MSG_ERROR:
  297. error_message_ += "ERROR";
  298. break;
  299. case SPV_MSG_WARNING:
  300. error_message_ += "WARNING";
  301. break;
  302. case SPV_MSG_INFO:
  303. error_message_ += "INFO";
  304. break;
  305. case SPV_MSG_DEBUG:
  306. error_message_ += "DEBUG";
  307. break;
  308. }
  309. error_message_ +=
  310. ": " + std::to_string(position.index) + ": " + message;
  311. }) {}
  312. Pass::Status RunPass(const std::string& text) {
  313. std::unique_ptr<IRContext> context_ =
  314. spvtools::BuildModule(SPV_ENV_UNIVERSAL_1_2, consumer_, text);
  315. if (!context_.get()) return Pass::Status::Failure;
  316. PassManager manager;
  317. manager.SetMessageConsumer(consumer_);
  318. manager.AddPass<InterfaceVariableScalarReplacement>();
  319. return manager.Run(context_.get());
  320. }
  321. std::string GetErrorMessage() const { return error_message_; }
  322. void TearDown() override { error_message_.clear(); }
  323. private:
  324. spvtools::MessageConsumer consumer_;
  325. std::string error_message_;
  326. };
  327. TEST_F(InterfaceVarSROAErrorTest, CheckConflictOfExtraArraynessBetweenEntries) {
  328. const std::string spirv = R"(
  329. OpCapability Shader
  330. OpCapability Tessellation
  331. OpMemoryModel Logical GLSL450
  332. OpEntryPoint TessellationControl %tess "tess" %x %y %z
  333. OpEntryPoint Vertex %vert "vert" %z %w
  334. OpDecorate %z Location 0
  335. OpDecorate %x Location 2
  336. OpDecorate %y Location 0
  337. OpDecorate %w Location 1
  338. OpName %x "x"
  339. OpName %y "y"
  340. OpName %z "z"
  341. OpName %w "w"
  342. %uint = OpTypeInt 32 0
  343. %uint_2 = OpConstant %uint 2
  344. %_arr_uint_uint_2 = OpTypeArray %uint %uint_2
  345. %_ptr_Output__arr_uint_uint_2 = OpTypePointer Output %_arr_uint_uint_2
  346. %_ptr_Input__arr_uint_uint_2 = OpTypePointer Input %_arr_uint_uint_2
  347. %z = OpVariable %_ptr_Output__arr_uint_uint_2 Output
  348. %x = OpVariable %_ptr_Output__arr_uint_uint_2 Output
  349. %y = OpVariable %_ptr_Input__arr_uint_uint_2 Input
  350. %w = OpVariable %_ptr_Input__arr_uint_uint_2 Input
  351. %void = OpTypeVoid
  352. %void_f = OpTypeFunction %void
  353. %tess = OpFunction %void None %void_f
  354. %bb0 = OpLabel
  355. OpReturn
  356. OpFunctionEnd
  357. %vert = OpFunction %void None %void_f
  358. %bb1 = OpLabel
  359. OpReturn
  360. OpFunctionEnd
  361. )";
  362. EXPECT_EQ(RunPass(spirv), Pass::Status::Failure);
  363. const char expected_error[] =
  364. "ERROR: 0: A variable is arrayed for an entry point but it is not "
  365. "arrayed for another entry point\n"
  366. " %z = OpVariable %_ptr_Output__arr_uint_uint_2 Output";
  367. EXPECT_STREQ(GetErrorMessage().c_str(), expected_error);
  368. }
  369. } // namespace
  370. } // namespace opt
  371. } // namespace spvtools