graphics_robust_access_test.cpp 66 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659
  1. // Copyright (c) 2019 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 <sstream>
  15. #include <string>
  16. #include <vector>
  17. #include "pass_fixture.h"
  18. #include "pass_utils.h"
  19. #include "source/opt/graphics_robust_access_pass.h"
  20. namespace {
  21. using namespace spvtools;
  22. using opt::GraphicsRobustAccessPass;
  23. using GraphicsRobustAccessTest = opt::PassTest<::testing::Test>;
  24. // Test incompatible module, determined at module-level.
  25. TEST_F(GraphicsRobustAccessTest, FailNotShader) {
  26. const std::string text = R"(
  27. ; CHECK: Can only process Shader modules
  28. OpCapability Kernel
  29. )";
  30. SinglePassRunAndFail<GraphicsRobustAccessPass>(text);
  31. }
  32. TEST_F(GraphicsRobustAccessTest, FailCantProcessVariablePointers) {
  33. const std::string text = R"(
  34. ; CHECK: Can't process modules with VariablePointers capability
  35. OpCapability VariablePointers
  36. )";
  37. SinglePassRunAndFail<GraphicsRobustAccessPass>(text);
  38. }
  39. TEST_F(GraphicsRobustAccessTest, FailCantProcessVariablePointersStorageBuffer) {
  40. const std::string text = R"(
  41. ; CHECK: Can't process modules with VariablePointersStorageBuffer capability
  42. OpCapability VariablePointersStorageBuffer
  43. )";
  44. SinglePassRunAndFail<GraphicsRobustAccessPass>(text);
  45. }
  46. TEST_F(GraphicsRobustAccessTest, FailCantProcessRuntimeDescriptorArrayEXT) {
  47. const std::string text = R"(
  48. ; CHECK: Can't process modules with RuntimeDescriptorArrayEXT capability
  49. OpCapability RuntimeDescriptorArrayEXT
  50. )";
  51. SinglePassRunAndFail<GraphicsRobustAccessPass>(text);
  52. }
  53. TEST_F(GraphicsRobustAccessTest, FailCantProcessPhysical32AddressingModel) {
  54. const std::string text = R"(
  55. ; CHECK: Addressing model must be Logical. Found OpMemoryModel Physical32 OpenCL
  56. OpCapability Shader
  57. OpMemoryModel Physical32 OpenCL
  58. )";
  59. SinglePassRunAndFail<GraphicsRobustAccessPass>(text);
  60. }
  61. TEST_F(GraphicsRobustAccessTest, FailCantProcessPhysical64AddressingModel) {
  62. const std::string text = R"(
  63. ; CHECK: Addressing model must be Logical. Found OpMemoryModel Physical64 OpenCL
  64. OpCapability Shader
  65. OpMemoryModel Physical64 OpenCL
  66. )";
  67. SinglePassRunAndFail<GraphicsRobustAccessPass>(text);
  68. }
  69. TEST_F(GraphicsRobustAccessTest,
  70. FailCantProcessPhysicalStorageBuffer64EXTAddressingModel) {
  71. const std::string text = R"(
  72. ; CHECK: Addressing model must be Logical. Found OpMemoryModel PhysicalStorageBuffer64 GLSL450
  73. OpCapability Shader
  74. OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
  75. )";
  76. SinglePassRunAndFail<GraphicsRobustAccessPass>(text);
  77. }
  78. // Test access chains
  79. // Returns the names of access chain instructions handled by the pass.
  80. // For the purposes of this pass, regular and in-bounds access chains are the
  81. // same.)
  82. std::vector<const char*> AccessChains() {
  83. return {"OpAccessChain", "OpInBoundsAccessChain"};
  84. }
  85. std::string ShaderPreamble() {
  86. return R"(
  87. OpCapability Shader
  88. OpMemoryModel Logical Simple
  89. OpEntryPoint GLCompute %main "main"
  90. )";
  91. }
  92. std::string ShaderPreamble(const std::vector<std::string>& names) {
  93. std::ostringstream os;
  94. os << ShaderPreamble();
  95. for (auto& name : names) {
  96. os << " OpName %" << name << " \"" << name << "\"\n";
  97. }
  98. return os.str();
  99. }
  100. std::string ShaderPreambleAC() {
  101. return ShaderPreamble({"ac", "ptr_ty", "var"});
  102. }
  103. std::string ShaderPreambleAC(const std::vector<std::string>& names) {
  104. auto names2 = names;
  105. names2.push_back("ac");
  106. names2.push_back("ptr_ty");
  107. names2.push_back("var");
  108. return ShaderPreamble(names2);
  109. }
  110. std::string DecoSSBO() {
  111. return R"(
  112. OpDecorate %ssbo_s BufferBlock
  113. OpMemberDecorate %ssbo_s 0 Offset 0
  114. OpMemberDecorate %ssbo_s 1 Offset 4
  115. OpMemberDecorate %ssbo_s 2 Offset 16
  116. OpDecorate %var DescriptorSet 0
  117. OpDecorate %var Binding 0
  118. )";
  119. }
  120. std::string TypesVoid() {
  121. return R"(
  122. %void = OpTypeVoid
  123. %void_fn = OpTypeFunction %void
  124. )";
  125. }
  126. std::string TypesInt() {
  127. return R"(
  128. %uint = OpTypeInt 32 0
  129. %int = OpTypeInt 32 1
  130. )";
  131. }
  132. std::string TypesFloat() {
  133. return R"(
  134. %float = OpTypeFloat 32
  135. )";
  136. }
  137. std::string TypesShort() {
  138. return R"(
  139. %ushort = OpTypeInt 16 0
  140. %short = OpTypeInt 16 1
  141. )";
  142. }
  143. std::string TypesLong() {
  144. return R"(
  145. %ulong = OpTypeInt 64 0
  146. %long = OpTypeInt 64 1
  147. )";
  148. }
  149. std::string MainPrefix() {
  150. return R"(
  151. %main = OpFunction %void None %void_fn
  152. %entry = OpLabel
  153. )";
  154. }
  155. std::string MainSuffix() {
  156. return R"(
  157. OpReturn
  158. OpFunctionEnd
  159. )";
  160. }
  161. std::string ACCheck(const std::string& access_chain_inst,
  162. const std::string& original,
  163. const std::string& transformed) {
  164. return "\n ; CHECK: %ac = " + access_chain_inst + " %ptr_ty %var" +
  165. (transformed.empty() ? "" : " ") + transformed +
  166. "\n ; CHECK-NOT: " + access_chain_inst +
  167. "\n ; CHECK-NEXT: OpReturn"
  168. "\n %ac = " +
  169. access_chain_inst + " %ptr_ty %var " + (original.empty() ? "" : " ") +
  170. original + "\n";
  171. }
  172. std::string ACCheckFail(const std::string& access_chain_inst,
  173. const std::string& original,
  174. const std::string& transformed) {
  175. return "\n ; CHECK: %ac = " + access_chain_inst + " %ptr_ty %var" +
  176. (transformed.empty() ? "" : " ") + transformed +
  177. "\n ; CHECK-NOT: " + access_chain_inst +
  178. "\n ; CHECK-NOT: OpReturn"
  179. "\n %ac = " +
  180. access_chain_inst + " %ptr_ty %var " + (original.empty() ? "" : " ") +
  181. original + "\n";
  182. }
  183. // Access chain into:
  184. // Vector
  185. // Vector sizes 2, 3, 4
  186. // Matrix
  187. // Matrix columns 2, 4
  188. // Component is vector 2, 4
  189. // Array
  190. // Struct
  191. // TODO(dneto): RuntimeArray
  192. TEST_F(GraphicsRobustAccessTest, ACVectorLeastInboundConstantUntouched) {
  193. for (auto* ac : AccessChains()) {
  194. std::ostringstream shaders;
  195. shaders << ShaderPreambleAC() << TypesVoid() << TypesInt() << R"(
  196. %uvec2 = OpTypeVector %uint 2
  197. %var_ty = OpTypePointer Function %uvec2
  198. %ptr_ty = OpTypePointer Function %uint
  199. %uint_0 = OpConstant %uint 0
  200. )"
  201. << MainPrefix() << R"(
  202. %var = OpVariable %var_ty Function)" << ACCheck(ac, "%uint_0", "%uint_0")
  203. << MainSuffix();
  204. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  205. }
  206. }
  207. TEST_F(GraphicsRobustAccessTest, ACVectorMostInboundConstantUntouched) {
  208. for (auto* ac : AccessChains()) {
  209. std::ostringstream shaders;
  210. shaders << ShaderPreambleAC() << TypesVoid() << TypesInt() << R"(
  211. %v4uint = OpTypeVector %uint 4
  212. %var_ty = OpTypePointer Function %v4uint
  213. %ptr_ty = OpTypePointer Function %uint
  214. %uint_3 = OpConstant %uint 3
  215. )"
  216. << MainPrefix() << R"(
  217. %var = OpVariable %var_ty Function)" << ACCheck(ac, "%uint_3", "%uint_3")
  218. << MainSuffix();
  219. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  220. }
  221. }
  222. TEST_F(GraphicsRobustAccessTest, ACVectorExcessConstantClamped) {
  223. for (auto* ac : AccessChains()) {
  224. std::ostringstream shaders;
  225. shaders << ShaderPreambleAC() << TypesVoid() << TypesInt() << R"(
  226. %v4uint = OpTypeVector %uint 4
  227. %var_ty = OpTypePointer Function %v4uint
  228. %ptr_ty = OpTypePointer Function %uint
  229. %uint_4 = OpConstant %uint 4
  230. )"
  231. << MainPrefix() << R"(
  232. %var = OpVariable %var_ty Function)" << ACCheck(ac, "%uint_4", "%int_3")
  233. << MainSuffix();
  234. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  235. }
  236. }
  237. TEST_F(GraphicsRobustAccessTest, ACVectorNegativeConstantClamped) {
  238. for (auto* ac : AccessChains()) {
  239. std::ostringstream shaders;
  240. shaders << ShaderPreambleAC() << TypesVoid() << TypesInt() << R"(
  241. %v4uint = OpTypeVector %uint 4
  242. %var_ty = OpTypePointer Function %v4uint
  243. %ptr_ty = OpTypePointer Function %uint
  244. %int_n1 = OpConstant %int -1
  245. )"
  246. << MainPrefix() << R"(
  247. ; CHECK: %int_0 = OpConstant %int 0
  248. %var = OpVariable %var_ty Function)" << ACCheck(ac, "%int_n1", "%int_0")
  249. << MainSuffix();
  250. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  251. }
  252. }
  253. // Like the previous test, but ensures the pass knows how to modify an index
  254. // which does not come first in the access chain.
  255. TEST_F(GraphicsRobustAccessTest, ACVectorInArrayNegativeConstantClamped) {
  256. for (auto* ac : AccessChains()) {
  257. std::ostringstream shaders;
  258. shaders << ShaderPreambleAC() << TypesVoid() << TypesInt() << R"(
  259. %v4uint = OpTypeVector %uint 4
  260. %uint_1 = OpConstant %uint 1
  261. %uint_2 = OpConstant %uint 2
  262. %arr = OpTypeArray %v4uint %uint_2
  263. %var_ty = OpTypePointer Function %arr
  264. %ptr_ty = OpTypePointer Function %uint
  265. %int_n1 = OpConstant %int -1
  266. )"
  267. << MainPrefix() << R"(
  268. ; CHECK: %int_0 = OpConstant %int 0
  269. %var = OpVariable %var_ty Function)"
  270. << ACCheck(ac, "%uint_1 %int_n1", "%uint_1 %int_0") << MainSuffix();
  271. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  272. }
  273. }
  274. TEST_F(GraphicsRobustAccessTest, ACVectorGeneralClamped) {
  275. for (auto* ac : AccessChains()) {
  276. std::ostringstream shaders;
  277. shaders << ShaderPreambleAC({"i"}) << TypesVoid() << TypesInt() << R"(
  278. %v4uint = OpTypeVector %uint 4
  279. %var_ty = OpTypePointer Function %v4uint
  280. %ptr_ty = OpTypePointer Function %uint
  281. %i = OpUndef %int)"
  282. << MainPrefix() << R"(
  283. ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450"
  284. ; CHECK-DAG: %int_0 = OpConstant %int 0
  285. ; CHECK-DAG: %int_3 = OpConstant %int 3
  286. ; CHECK: OpLabel
  287. ; CHECK: %[[clamp:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %i %int_0 %int_3
  288. %var = OpVariable %var_ty Function)" << ACCheck(ac, "%i", "%[[clamp]]")
  289. << MainSuffix();
  290. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  291. }
  292. }
  293. TEST_F(GraphicsRobustAccessTest, ACVectorGeneralShortClamped) {
  294. // Show that signed 16 bit integers are clamped as well.
  295. for (auto* ac : AccessChains()) {
  296. std::ostringstream shaders;
  297. shaders << "OpCapability Int16\n"
  298. << ShaderPreambleAC({"i"}) << TypesVoid() << TypesShort() <<
  299. R"(
  300. %v4short = OpTypeVector %short 4
  301. %var_ty = OpTypePointer Function %v4short
  302. %ptr_ty = OpTypePointer Function %short
  303. %i = OpUndef %short)"
  304. << MainPrefix() << R"(
  305. ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450"
  306. ; CHECK-NOT: = OpTypeInt 32
  307. ; CHECK-DAG: %short_0 = OpConstant %short 0
  308. ; CHECK-DAG: %short_3 = OpConstant %short 3
  309. ; CHECK-NOT: = OpTypeInt 32
  310. ; CHECK: OpLabel
  311. ; CHECK: %[[clamp:\w+]] = OpExtInst %short %[[GLSLSTD450]] SClamp %i %short_0 %short_3
  312. %var = OpVariable %var_ty Function)" << ACCheck(ac, "%i", "%[[clamp]]")
  313. << MainSuffix();
  314. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  315. }
  316. }
  317. TEST_F(GraphicsRobustAccessTest, ACVectorGeneralUShortClamped) {
  318. // Show that unsigned 16 bit integers are clamped as well.
  319. for (auto* ac : AccessChains()) {
  320. std::ostringstream shaders;
  321. shaders << "OpCapability Int16\n"
  322. << ShaderPreambleAC({"i"}) << TypesVoid() << TypesShort() <<
  323. R"(
  324. %v4ushort = OpTypeVector %ushort 4
  325. %var_ty = OpTypePointer Function %v4ushort
  326. %ptr_ty = OpTypePointer Function %ushort
  327. %i = OpUndef %ushort)"
  328. << MainPrefix() << R"(
  329. ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450"
  330. ; CHECK-NOT: = OpTypeInt 32
  331. ; CHECK-DAG: %short_0 = OpConstant %short 0
  332. ; CHECK-DAG: %short_3 = OpConstant %short 3
  333. ; CHECK-NOT: = OpTypeInt 32
  334. ; CHECK: OpLabel
  335. ; CHECK: %[[clamp:\w+]] = OpExtInst %ushort %[[GLSLSTD450]] SClamp %i %short_0 %short_3
  336. %var = OpVariable %var_ty Function)" << ACCheck(ac, "%i", "%[[clamp]]")
  337. << MainSuffix();
  338. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  339. }
  340. }
  341. TEST_F(GraphicsRobustAccessTest, ACVectorGeneralLongClamped) {
  342. // Show that signed 64 bit integers are clamped as well.
  343. for (auto* ac : AccessChains()) {
  344. std::ostringstream shaders;
  345. shaders << "OpCapability Int64\n"
  346. << ShaderPreambleAC({"i"}) << TypesVoid() << TypesLong() <<
  347. R"(
  348. %v4long = OpTypeVector %long 4
  349. %var_ty = OpTypePointer Function %v4long
  350. %ptr_ty = OpTypePointer Function %long
  351. %i = OpUndef %long)"
  352. << MainPrefix() << R"(
  353. ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450"
  354. ; CHECK-NOT: = OpTypeInt 32
  355. ; CHECK-DAG: %long_0 = OpConstant %long 0
  356. ; CHECK-DAG: %long_3 = OpConstant %long 3
  357. ; CHECK-NOT: = OpTypeInt 32
  358. ; CHECK: OpLabel
  359. ; CHECK: %[[clamp:\w+]] = OpExtInst %long %[[GLSLSTD450]] SClamp %i %long_0 %long_3
  360. %var = OpVariable %var_ty Function)" << ACCheck(ac, "%i", "%[[clamp]]")
  361. << MainSuffix();
  362. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  363. }
  364. }
  365. TEST_F(GraphicsRobustAccessTest, ACVectorGeneralULongClamped) {
  366. // Show that unsigned 64 bit integers are clamped as well.
  367. for (auto* ac : AccessChains()) {
  368. std::ostringstream shaders;
  369. shaders << "OpCapability Int64\n"
  370. << ShaderPreambleAC({"i"}) << TypesVoid() << TypesLong() <<
  371. R"(
  372. %v4ulong = OpTypeVector %ulong 4
  373. %var_ty = OpTypePointer Function %v4ulong
  374. %ptr_ty = OpTypePointer Function %ulong
  375. %i = OpUndef %ulong)"
  376. << MainPrefix() << R"(
  377. ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450"
  378. ; CHECK-NOT: = OpTypeInt 32
  379. ; CHECK-DAG: %long_0 = OpConstant %long 0
  380. ; CHECK-DAG: %long_3 = OpConstant %long 3
  381. ; CHECK-NOT: = OpTypeInt 32
  382. ; CHECK: OpLabel
  383. ; CHECK: %[[clamp:\w+]] = OpExtInst %ulong %[[GLSLSTD450]] SClamp %i %long_0 %long_3
  384. %var = OpVariable %var_ty Function)" << ACCheck(ac, "%i", "%[[clamp]]")
  385. << MainSuffix();
  386. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  387. }
  388. }
  389. TEST_F(GraphicsRobustAccessTest, ACMatrixLeastInboundConstantUntouched) {
  390. for (auto* ac : AccessChains()) {
  391. std::ostringstream shaders;
  392. shaders << ShaderPreambleAC() << TypesVoid() << TypesInt()
  393. << TypesFloat() << R"(
  394. %v2float = OpTypeVector %float 2
  395. %mat4v2float = OpTypeMatrix %v2float 4
  396. %var_ty = OpTypePointer Function %mat4v2float
  397. %ptr_ty = OpTypePointer Function %float
  398. %uint_0 = OpConstant %uint 0
  399. %uint_1 = OpConstant %uint 1
  400. )" << MainPrefix() << R"(
  401. %var = OpVariable %var_ty Function)"
  402. << ACCheck(ac, "%uint_0 %uint_1", "%uint_0 %uint_1")
  403. << MainSuffix();
  404. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  405. }
  406. }
  407. TEST_F(GraphicsRobustAccessTest, ACMatrixMostInboundConstantUntouched) {
  408. for (auto* ac : AccessChains()) {
  409. std::ostringstream shaders;
  410. shaders << ShaderPreambleAC() << TypesVoid() << TypesInt()
  411. << TypesFloat() << R"(
  412. %v2float = OpTypeVector %float 2
  413. %mat4v2float = OpTypeMatrix %v2float 4
  414. %var_ty = OpTypePointer Function %mat4v2float
  415. %ptr_ty = OpTypePointer Function %float
  416. %uint_1 = OpConstant %uint 1
  417. %uint_3 = OpConstant %uint 3
  418. )" << MainPrefix() << R"(
  419. %var = OpVariable %var_ty Function)"
  420. << ACCheck(ac, "%uint_3 %uint_1", "%uint_3 %uint_1")
  421. << MainSuffix();
  422. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  423. }
  424. }
  425. TEST_F(GraphicsRobustAccessTest, ACMatrixExcessConstantClamped) {
  426. for (auto* ac : AccessChains()) {
  427. std::ostringstream shaders;
  428. shaders << ShaderPreambleAC() << TypesVoid() << TypesInt()
  429. << TypesFloat() << R"(
  430. %v2float = OpTypeVector %float 2
  431. %mat4v2float = OpTypeMatrix %v2float 4
  432. %var_ty = OpTypePointer Function %mat4v2float
  433. %ptr_ty = OpTypePointer Function %float
  434. %uint_1 = OpConstant %uint 1
  435. %uint_4 = OpConstant %uint 4
  436. )" << MainPrefix() << R"(
  437. ; CHECK: %int_3 = OpConstant %int 3
  438. %var = OpVariable %var_ty Function)"
  439. << ACCheck(ac, "%uint_4 %uint_1", "%int_3 %uint_1") << MainSuffix();
  440. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  441. }
  442. }
  443. TEST_F(GraphicsRobustAccessTest, ACMatrixNegativeConstantClamped) {
  444. for (auto* ac : AccessChains()) {
  445. std::ostringstream shaders;
  446. shaders << ShaderPreambleAC() << TypesVoid() << TypesInt()
  447. << TypesFloat() << R"(
  448. %v2float = OpTypeVector %float 2
  449. %mat4v2float = OpTypeMatrix %v2float 4
  450. %var_ty = OpTypePointer Function %mat4v2float
  451. %ptr_ty = OpTypePointer Function %float
  452. %uint_1 = OpConstant %uint 1
  453. %int_n1 = OpConstant %int -1
  454. )" << MainPrefix() << R"(
  455. ; CHECK: %int_0 = OpConstant %int 0
  456. %var = OpVariable %var_ty Function)"
  457. << ACCheck(ac, "%int_n1 %uint_1", "%int_0 %uint_1") << MainSuffix();
  458. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  459. }
  460. }
  461. TEST_F(GraphicsRobustAccessTest, ACMatrixGeneralClamped) {
  462. for (auto* ac : AccessChains()) {
  463. std::ostringstream shaders;
  464. shaders << ShaderPreambleAC({"i"}) << TypesVoid() << TypesInt()
  465. << TypesFloat() << R"(
  466. %v2float = OpTypeVector %float 2
  467. %mat4v2float = OpTypeMatrix %v2float 4
  468. %var_ty = OpTypePointer Function %mat4v2float
  469. %ptr_ty = OpTypePointer Function %float
  470. %uint_1 = OpConstant %uint 1
  471. %i = OpUndef %int
  472. )" << MainPrefix() << R"(
  473. ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450"
  474. ; CHECK-DAG: %int_0 = OpConstant %int 0
  475. ; CHECK-DAG: %int_3 = OpConstant %int 3
  476. ; CHECK: OpLabel
  477. ; CHECK: %[[clamp:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %i %int_0 %int_3
  478. %var = OpVariable %var_ty Function)"
  479. << ACCheck(ac, "%i %uint_1", "%[[clamp]] %uint_1") << MainSuffix();
  480. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  481. }
  482. }
  483. TEST_F(GraphicsRobustAccessTest, ACArrayLeastInboundConstantUntouched) {
  484. for (auto* ac : AccessChains()) {
  485. std::ostringstream shaders;
  486. shaders << ShaderPreambleAC() << TypesVoid() << TypesInt()
  487. << TypesFloat() << R"(
  488. %uint_200 = OpConstant %uint 200
  489. %arr = OpTypeArray %float %uint_200
  490. %var_ty = OpTypePointer Function %arr
  491. %ptr_ty = OpTypePointer Function %float
  492. %int_0 = OpConstant %int 0
  493. )" << MainPrefix() << R"(
  494. %var = OpVariable %var_ty Function)"
  495. << ACCheck(ac, "%int_0", "%int_0") << MainSuffix();
  496. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  497. }
  498. }
  499. TEST_F(GraphicsRobustAccessTest, ACArrayMostInboundConstantUntouched) {
  500. for (auto* ac : AccessChains()) {
  501. std::ostringstream shaders;
  502. shaders << ShaderPreambleAC() << TypesVoid() << TypesInt()
  503. << TypesFloat() << R"(
  504. %uint_200 = OpConstant %uint 200
  505. %arr = OpTypeArray %float %uint_200
  506. %var_ty = OpTypePointer Function %arr
  507. %ptr_ty = OpTypePointer Function %float
  508. %int_199 = OpConstant %int 199
  509. )" << MainPrefix() << R"(
  510. %var = OpVariable %var_ty Function)"
  511. << ACCheck(ac, "%int_199", "%int_199") << MainSuffix();
  512. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  513. }
  514. }
  515. TEST_F(GraphicsRobustAccessTest, ACArrayGeneralClamped) {
  516. for (auto* ac : AccessChains()) {
  517. std::ostringstream shaders;
  518. shaders << ShaderPreambleAC({"i"}) << TypesVoid() << TypesInt()
  519. << TypesFloat() << R"(
  520. %uint_200 = OpConstant %uint 200
  521. %arr = OpTypeArray %float %uint_200
  522. %var_ty = OpTypePointer Function %arr
  523. %ptr_ty = OpTypePointer Function %float
  524. %i = OpUndef %int
  525. )" << MainPrefix() << R"(
  526. ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450"
  527. ; CHECK-DAG: %int_0 = OpConstant %int 0
  528. ; CHECK-DAG: %int_199 = OpConstant %int 199
  529. ; CHECK: OpLabel
  530. ; CHECK: %[[clamp:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %i %int_0 %int_199
  531. %var = OpVariable %var_ty Function)"
  532. << ACCheck(ac, "%i", "%[[clamp]]") << MainSuffix();
  533. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  534. }
  535. }
  536. TEST_F(GraphicsRobustAccessTest, ACArrayGeneralShortIndexUIntBoundsClamped) {
  537. // Index is signed short, array bounds overflows the index type.
  538. for (auto* ac : AccessChains()) {
  539. std::ostringstream shaders;
  540. shaders << "OpCapability Int16\n"
  541. << ShaderPreambleAC({"i"}) << TypesVoid() << TypesInt()
  542. << TypesShort() << TypesFloat() << R"(
  543. %uint_70000 = OpConstant %uint 70000 ; overflows 16bits
  544. %arr = OpTypeArray %float %uint_70000
  545. %var_ty = OpTypePointer Function %arr
  546. %ptr_ty = OpTypePointer Function %float
  547. %i = OpUndef %short
  548. )" << MainPrefix() << R"(
  549. ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450"
  550. ; CHECK-DAG: %int_0 = OpConstant %int 0
  551. ; CHECK-DAG: %int_69999 = OpConstant %int 69999
  552. ; CHECK: OpLabel
  553. ; CHECK: %[[i_ext:\w+]] = OpSConvert %uint %i
  554. ; CHECK: %[[clamp:\w+]] = OpExtInst %uint %[[GLSLSTD450]] SClamp %[[i_ext]] %int_0 %int_69999
  555. %var = OpVariable %var_ty Function)"
  556. << ACCheck(ac, "%i", "%[[clamp]]") << MainSuffix();
  557. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  558. }
  559. }
  560. TEST_F(GraphicsRobustAccessTest, ACArrayGeneralUShortIndexIntBoundsClamped) {
  561. // Index is unsigned short, array bounds overflows the index type.
  562. for (auto* ac : AccessChains()) {
  563. std::ostringstream shaders;
  564. shaders << "OpCapability Int16\n"
  565. << ShaderPreambleAC({"i"}) << TypesVoid() << TypesInt()
  566. << TypesShort() << TypesFloat() << R"(
  567. %int_70000 = OpConstant %int 70000 ; overflows 16bits
  568. %arr = OpTypeArray %float %int_70000
  569. %var_ty = OpTypePointer Function %arr
  570. %ptr_ty = OpTypePointer Function %float
  571. %i = OpUndef %ushort
  572. )" << MainPrefix() << R"(
  573. ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450"
  574. ; CHECK-DAG: %int_0 = OpConstant %int 0
  575. ; CHECK-DAG: %int_69999 = OpConstant %int 69999
  576. ; CHECK: OpLabel
  577. ; CHECK: %[[i_ext:\w+]] = OpUConvert %uint %i
  578. ; CHECK: %[[clamp:\w+]] = OpExtInst %uint %[[GLSLSTD450]] SClamp %[[i_ext]] %int_0 %int_69999
  579. %var = OpVariable %var_ty Function)"
  580. << ACCheck(ac, "%i", "%[[clamp]]") << MainSuffix();
  581. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  582. }
  583. }
  584. TEST_F(GraphicsRobustAccessTest, ACArrayGeneralUIntIndexShortBoundsClamped) {
  585. // Signed int index i is wider than the array bounds type.
  586. for (auto* ac : AccessChains()) {
  587. std::ostringstream shaders;
  588. shaders << "OpCapability Int16\n"
  589. << ShaderPreambleAC({"i"}) << TypesVoid() << TypesInt()
  590. << TypesShort() << TypesFloat() << R"(
  591. %short_200 = OpConstant %short 200
  592. %arr = OpTypeArray %float %short_200
  593. %var_ty = OpTypePointer Function %arr
  594. %ptr_ty = OpTypePointer Function %float
  595. %i = OpUndef %uint
  596. )" << MainPrefix() << R"(
  597. ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450"
  598. ; CHECK-DAG: %int_0 = OpConstant %int 0
  599. ; CHECK-DAG: %int_199 = OpConstant %int 199
  600. ; CHECK: OpLabel
  601. ; CHECK: %[[clamp:\w+]] = OpExtInst %uint %[[GLSLSTD450]] SClamp %i %int_0 %int_199
  602. %var = OpVariable %var_ty Function)"
  603. << ACCheck(ac, "%i", "%[[clamp]]") << MainSuffix();
  604. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  605. }
  606. }
  607. TEST_F(GraphicsRobustAccessTest, ACArrayGeneralIntIndexUShortBoundsClamped) {
  608. // Unsigned int index i is wider than the array bounds type.
  609. for (auto* ac : AccessChains()) {
  610. std::ostringstream shaders;
  611. shaders << "OpCapability Int16\n"
  612. << ShaderPreambleAC({"i"}) << TypesVoid() << TypesInt()
  613. << TypesShort() << TypesFloat() << R"(
  614. %ushort_200 = OpConstant %ushort 200
  615. %arr = OpTypeArray %float %ushort_200
  616. %var_ty = OpTypePointer Function %arr
  617. %ptr_ty = OpTypePointer Function %float
  618. %i = OpUndef %int
  619. )" << MainPrefix() << R"(
  620. ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450"
  621. ; CHECK-DAG: %int_0 = OpConstant %int 0
  622. ; CHECK-DAG: %int_199 = OpConstant %int 199
  623. ; CHECK: OpLabel
  624. ; CHECK: %[[clamp:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %i %int_0 %int_199
  625. %var = OpVariable %var_ty Function)"
  626. << ACCheck(ac, "%i", "%[[clamp]]") << MainSuffix();
  627. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  628. }
  629. }
  630. TEST_F(GraphicsRobustAccessTest, ACArrayGeneralLongIndexUIntBoundsClamped) {
  631. // Signed long index i is wider than the array bounds type.
  632. for (auto* ac : AccessChains()) {
  633. std::ostringstream shaders;
  634. shaders << "OpCapability Int64\n"
  635. << ShaderPreambleAC({"i"}) << TypesVoid() << TypesInt()
  636. << TypesLong() << TypesFloat() << R"(
  637. %uint_200 = OpConstant %uint 200
  638. %arr = OpTypeArray %float %uint_200
  639. %var_ty = OpTypePointer Function %arr
  640. %ptr_ty = OpTypePointer Function %float
  641. %i = OpUndef %long
  642. )" << MainPrefix() << R"(
  643. ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450"
  644. ; CHECK-DAG: %long_0 = OpConstant %long 0
  645. ; CHECK-DAG: %long_199 = OpConstant %long 199
  646. ; CHECK: OpLabel
  647. ; CHECK: %[[clamp:\w+]] = OpExtInst %long %[[GLSLSTD450]] SClamp %i %long_0 %long_199
  648. %var = OpVariable %var_ty Function)"
  649. << ACCheck(ac, "%i", "%[[clamp]]") << MainSuffix();
  650. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  651. }
  652. }
  653. TEST_F(GraphicsRobustAccessTest, ACArrayGeneralULongIndexIntBoundsClamped) {
  654. // Unsigned long index i is wider than the array bounds type.
  655. for (auto* ac : AccessChains()) {
  656. std::ostringstream shaders;
  657. shaders << "OpCapability Int64\n"
  658. << ShaderPreambleAC({"i"}) << TypesVoid() << TypesInt()
  659. << TypesLong() << TypesFloat() << R"(
  660. %int_200 = OpConstant %int 200
  661. %arr = OpTypeArray %float %int_200
  662. %var_ty = OpTypePointer Function %arr
  663. %ptr_ty = OpTypePointer Function %float
  664. %i = OpUndef %ulong
  665. )" << MainPrefix() << R"(
  666. ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450"
  667. ; CHECK-DAG: %long_0 = OpConstant %long 0
  668. ; CHECK-DAG: %long_199 = OpConstant %long 199
  669. ; CHECK: OpLabel
  670. ; CHECK: %[[clamp:\w+]] = OpExtInst %ulong %[[GLSLSTD450]] SClamp %i %long_0 %long_199
  671. %var = OpVariable %var_ty Function)"
  672. << ACCheck(ac, "%i", "%[[clamp]]") << MainSuffix();
  673. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  674. }
  675. }
  676. TEST_F(GraphicsRobustAccessTest,
  677. ACArrayGeneralShortIndeArrayBiggerThanShortMaxClipsToShortIntMax) {
  678. for (auto* ac : AccessChains()) {
  679. std::ostringstream shaders;
  680. shaders << "OpCapability Int16\n"
  681. << ShaderPreambleAC({"i"}) << TypesVoid() << TypesShort()
  682. << TypesInt() << TypesFloat() << R"(
  683. %uint_50000 = OpConstant %uint 50000
  684. %arr = OpTypeArray %float %uint_50000
  685. %var_ty = OpTypePointer Function %arr
  686. %ptr_ty = OpTypePointer Function %float
  687. %i = OpUndef %ushort
  688. )" << MainPrefix() << R"(
  689. ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450"
  690. ; CHECK-DAG: %short_0 = OpConstant %short 0
  691. ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %short 32767
  692. ; CHECK: OpLabel
  693. ; CHECK: %[[clamp:\w+]] = OpExtInst %ushort %[[GLSLSTD450]] SClamp %i %short_0 %[[intmax]]
  694. %var = OpVariable %var_ty Function)"
  695. << ACCheck(ac, "%i", "%[[clamp]]") << MainSuffix();
  696. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  697. }
  698. }
  699. TEST_F(GraphicsRobustAccessTest,
  700. ACArrayGeneralIntIndexArrayBiggerThanIntMaxClipsToSignedIntMax) {
  701. for (auto* ac : AccessChains()) {
  702. std::ostringstream shaders;
  703. shaders << ShaderPreambleAC({"i"}) << TypesVoid() << TypesInt()
  704. << TypesFloat() << R"(
  705. %uint_3000000000 = OpConstant %uint 3000000000
  706. %arr = OpTypeArray %float %uint_3000000000
  707. %var_ty = OpTypePointer Function %arr
  708. %ptr_ty = OpTypePointer Function %float
  709. %i = OpUndef %uint
  710. )" << MainPrefix() << R"(
  711. ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450"
  712. ; CHECK-DAG: %int_0 = OpConstant %int 0
  713. ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %int 2147483647
  714. ; CHECK: OpLabel
  715. ; CHECK: %[[clamp:\w+]] = OpExtInst %uint %[[GLSLSTD450]] SClamp %i %int_0 %[[intmax]]
  716. %var = OpVariable %var_ty Function)"
  717. << ACCheck(ac, "%i", "%[[clamp]]") << MainSuffix();
  718. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  719. }
  720. }
  721. TEST_F(GraphicsRobustAccessTest,
  722. ACArrayGeneralLongIndexArrayBiggerThanLongMaxClipsToSignedLongMax) {
  723. for (auto* ac : AccessChains()) {
  724. std::ostringstream shaders;
  725. shaders << "OpCapability Int64\n"
  726. << ShaderPreambleAC({"i"}) << TypesVoid() << TypesInt()
  727. << TypesLong()
  728. << TypesFloat()
  729. // 2^63 == 9,223,372,036,854,775,807
  730. << R"(
  731. %ulong_9223372036854775999 = OpConstant %ulong 9223372036854775999
  732. %arr = OpTypeArray %float %ulong_9223372036854775999
  733. %var_ty = OpTypePointer Function %arr
  734. %ptr_ty = OpTypePointer Function %float
  735. %i = OpUndef %ulong
  736. )"
  737. << MainPrefix() << R"(
  738. ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450"
  739. ; CHECK-DAG: %long_0 = OpConstant %long 0
  740. ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %long 9223372036854775807
  741. ; CHECK: OpLabel
  742. ; CHECK: %[[clamp:\w+]] = OpExtInst %ulong %[[GLSLSTD450]] SClamp %i %long_0 %[[intmax]]
  743. %var = OpVariable %var_ty Function)" << ACCheck(ac, "%i", "%[[clamp]]")
  744. << MainSuffix();
  745. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  746. }
  747. }
  748. TEST_F(GraphicsRobustAccessTest, ACArraySpecIdSizedAlwaysClamped) {
  749. for (auto* ac : AccessChains()) {
  750. std::ostringstream shaders;
  751. shaders << ShaderPreambleAC({"spec200"}) << R"(
  752. OpDecorate %spec200 SpecId 0 )" << TypesVoid() << TypesInt()
  753. << TypesFloat() << R"(
  754. %spec200 = OpSpecConstant %int 200
  755. %arr = OpTypeArray %float %spec200
  756. %var_ty = OpTypePointer Function %arr
  757. %ptr_ty = OpTypePointer Function %float
  758. %uint_5 = OpConstant %uint 5
  759. )" << MainPrefix() << R"(
  760. ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450"
  761. ; CHECK-DAG: %uint_0 = OpConstant %uint 0
  762. ; CHECK-DAG: %uint_1 = OpConstant %uint 1
  763. ; CHECK-DAG: %[[uint_intmax:\w+]] = OpConstant %uint 2147483647
  764. ; CHECK: OpLabel
  765. ; CHECK: %[[max:\w+]] = OpISub %uint %spec200 %uint_1
  766. ; CHECK: %[[smin:\w+]] = OpExtInst %uint %[[GLSLSTD450]] UMin %[[max]] %[[uint_intmax]]
  767. ; CHECK: %[[clamp:\w+]] = OpExtInst %uint %[[GLSLSTD450]] SClamp %uint_5 %uint_0 %[[smin]]
  768. %var = OpVariable %var_ty Function)"
  769. << ACCheck(ac, "%uint_5", "%[[clamp]]") << MainSuffix();
  770. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  771. }
  772. }
  773. TEST_F(GraphicsRobustAccessTest, ACStructLeastUntouched) {
  774. for (auto* ac : AccessChains()) {
  775. std::ostringstream shaders;
  776. shaders << ShaderPreambleAC() << TypesVoid() << TypesInt()
  777. << TypesFloat() << R"(
  778. %struct = OpTypeStruct %float %float %float
  779. %var_ty = OpTypePointer Function %struct
  780. %ptr_ty = OpTypePointer Function %float
  781. %int_0 = OpConstant %int 0
  782. )" << MainPrefix() << R"(
  783. %var = OpVariable %var_ty Function)"
  784. << ACCheck(ac, "%int_0", "%int_0") << MainSuffix();
  785. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  786. }
  787. }
  788. TEST_F(GraphicsRobustAccessTest, ACStructMostUntouched) {
  789. for (auto* ac : AccessChains()) {
  790. std::ostringstream shaders;
  791. shaders << ShaderPreambleAC() << TypesVoid() << TypesInt()
  792. << TypesFloat() << R"(
  793. %struct = OpTypeStruct %float %float %float
  794. %var_ty = OpTypePointer Function %struct
  795. %ptr_ty = OpTypePointer Function %float
  796. %int_2 = OpConstant %int 2
  797. )" << MainPrefix() << R"(
  798. %var = OpVariable %var_ty Function)"
  799. << ACCheck(ac, "%int_2", "%int_2") << MainSuffix();
  800. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  801. }
  802. }
  803. TEST_F(GraphicsRobustAccessTest, ACStructSpecConstantFail) {
  804. for (auto* ac : AccessChains()) {
  805. std::ostringstream shaders;
  806. shaders << ShaderPreambleAC({"struct", "spec200"})
  807. << "OpDecorate %spec200 SpecId 0\n"
  808. <<
  809. TypesVoid() << TypesInt() << TypesFloat() << R"(
  810. %spec200 = OpSpecConstant %int 200
  811. %struct = OpTypeStruct %float %float %float
  812. %var_ty = OpTypePointer Function %struct
  813. %ptr_ty = OpTypePointer Function %float
  814. )" << MainPrefix() << R"(
  815. %var = OpVariable %var_ty Function
  816. ; CHECK: Member index into struct is not a constant integer
  817. ; CHECK-SAME: %spec200 = OpSpecConstant %int 200
  818. )"
  819. << ACCheckFail(ac, "%spec200", "%spec200") << MainSuffix();
  820. SinglePassRunAndFail<GraphicsRobustAccessPass>(shaders.str());
  821. }
  822. }
  823. TEST_F(GraphicsRobustAccessTest, ACStructFloatConstantFail) {
  824. for (auto* ac : AccessChains()) {
  825. std::ostringstream shaders;
  826. shaders << ShaderPreambleAC({"struct"}) <<
  827. TypesVoid() << TypesInt() << TypesFloat() << R"(
  828. %float_2 = OpConstant %float 2
  829. %struct = OpTypeStruct %float %float %float
  830. %var_ty = OpTypePointer Function %struct
  831. %ptr_ty = OpTypePointer Function %float
  832. )" << MainPrefix() << R"(
  833. %var = OpVariable %var_ty Function
  834. ; CHECK: Member index into struct is not a constant integer
  835. ; CHECK-SAME: %float_2 = OpConstant %float 2
  836. )"
  837. << ACCheckFail(ac, "%float_2", "%float_2") << MainSuffix();
  838. SinglePassRunAndFail<GraphicsRobustAccessPass>(shaders.str());
  839. }
  840. }
  841. TEST_F(GraphicsRobustAccessTest, ACStructNonConstantFail) {
  842. for (auto* ac : AccessChains()) {
  843. std::ostringstream shaders;
  844. shaders << ShaderPreambleAC({"struct", "i"}) <<
  845. TypesVoid() << TypesInt() << TypesFloat() << R"(
  846. %float_2 = OpConstant %float 2
  847. %struct = OpTypeStruct %float %float %float
  848. %var_ty = OpTypePointer Function %struct
  849. %ptr_ty = OpTypePointer Function %float
  850. %i = OpUndef %int
  851. )" << MainPrefix() << R"(
  852. %var = OpVariable %var_ty Function
  853. ; CHECK: Member index into struct is not a constant integer
  854. ; CHECK-SAME: %i = OpUndef %int
  855. )"
  856. << ACCheckFail(ac, "%i", "%i") << MainSuffix();
  857. SinglePassRunAndFail<GraphicsRobustAccessPass>(shaders.str());
  858. }
  859. }
  860. TEST_F(GraphicsRobustAccessTest, ACStructExcessFail) {
  861. for (auto* ac : AccessChains()) {
  862. std::ostringstream shaders;
  863. shaders << ShaderPreambleAC({"struct", "i"}) << TypesVoid() << TypesInt()
  864. << TypesFloat() << R"(
  865. %struct = OpTypeStruct %float %float %float
  866. %var_ty = OpTypePointer Function %struct
  867. %ptr_ty = OpTypePointer Function %float
  868. %i = OpConstant %int 4
  869. )" << MainPrefix() << R"(
  870. %var = OpVariable %var_ty Function
  871. ; CHECK: Member index 4 is out of bounds for struct type:
  872. ; CHECK-SAME: %struct = OpTypeStruct %float %float %float
  873. )"
  874. << ACCheckFail(ac, "%i", "%i") << MainSuffix();
  875. SinglePassRunAndFail<GraphicsRobustAccessPass>(shaders.str());
  876. }
  877. }
  878. TEST_F(GraphicsRobustAccessTest, ACStructNegativeFail) {
  879. for (auto* ac : AccessChains()) {
  880. std::ostringstream shaders;
  881. shaders << ShaderPreambleAC({"struct", "i"}) << TypesVoid() << TypesInt()
  882. << TypesFloat() << R"(
  883. %struct = OpTypeStruct %float %float %float
  884. %var_ty = OpTypePointer Function %struct
  885. %ptr_ty = OpTypePointer Function %float
  886. %i = OpConstant %int -1
  887. )" << MainPrefix() << R"(
  888. %var = OpVariable %var_ty Function
  889. ; CHECK: Member index -1 is out of bounds for struct type:
  890. ; CHECK-SAME: %struct = OpTypeStruct %float %float %float
  891. )"
  892. << ACCheckFail(ac, "%i", "%i") << MainSuffix();
  893. SinglePassRunAndFail<GraphicsRobustAccessPass>(shaders.str());
  894. }
  895. }
  896. TEST_F(GraphicsRobustAccessTest, ACRTArrayLeastInboundClamped) {
  897. for (auto* ac : AccessChains()) {
  898. std::ostringstream shaders;
  899. shaders << ShaderPreambleAC() << "OpDecorate %rtarr ArrayStride 4 "
  900. << DecoSSBO() << TypesVoid() << TypesInt() << TypesFloat() << R"(
  901. %rtarr = OpTypeRuntimeArray %float
  902. %ssbo_s = OpTypeStruct %uint %uint %rtarr
  903. %var_ty = OpTypePointer Uniform %ssbo_s
  904. %ptr_ty = OpTypePointer Uniform %float
  905. %var = OpVariable %var_ty Uniform
  906. %int_0 = OpConstant %int 0
  907. %int_2 = OpConstant %int 2
  908. ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450"
  909. ; CHECK-DAG: %int_1 = OpConstant %int 1
  910. ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %int 2147483647
  911. ; CHECK: OpLabel
  912. ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %var 2
  913. ; CHECK: %[[max:\w+]] = OpISub %int %[[arrlen]] %int_1
  914. ; CHECK: %[[smin:\w+]] = OpExtInst %int %[[GLSLSTD450]] UMin %[[max]] %[[intmax]]
  915. ; CHECK: %[[clamp:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %int_0 %int_0 %[[smin]]
  916. )"
  917. << MainPrefix() << ACCheck(ac, "%int_2 %int_0", "%int_2 %[[clamp]]")
  918. << MainSuffix();
  919. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  920. }
  921. }
  922. TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralShortIndexClamped) {
  923. for (auto* ac : AccessChains()) {
  924. std::ostringstream shaders;
  925. shaders << "OpCapability Int16\n"
  926. << ShaderPreambleAC({"i"}) << "OpDecorate %rtarr ArrayStride 4 "
  927. << DecoSSBO() << TypesVoid() << TypesShort() << TypesFloat() << R"(
  928. %rtarr = OpTypeRuntimeArray %float
  929. %ssbo_s = OpTypeStruct %short %short %rtarr
  930. %var_ty = OpTypePointer Uniform %ssbo_s
  931. %ptr_ty = OpTypePointer Uniform %float
  932. %var = OpVariable %var_ty Uniform
  933. %short_2 = OpConstant %short 2
  934. %i = OpUndef %short
  935. ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450"
  936. ; CHECK: %uint = OpTypeInt 32 0
  937. ; CHECK-DAG: %uint_1 = OpConstant %uint 1
  938. ; CHECK-DAG: %uint_0 = OpConstant %uint 0
  939. ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %uint 2147483647
  940. ; CHECK: OpLabel
  941. ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %var 2
  942. ; CHECK-DAG: %[[max:\w+]] = OpISub %uint %[[arrlen]] %uint_1
  943. ; CHECK-DAG: %[[i_ext:\w+]] = OpSConvert %uint %i
  944. ; CHECK: %[[smin:\w+]] = OpExtInst %uint %[[GLSLSTD450]] UMin %[[max]] %[[intmax]]
  945. ; CHECK: %[[clamp:\w+]] = OpExtInst %uint %[[GLSLSTD450]] SClamp %[[i_ext]] %uint_0 %[[smin]]
  946. )"
  947. << MainPrefix() << ACCheck(ac, "%short_2 %i", "%short_2 %[[clamp]]")
  948. << MainSuffix();
  949. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  950. }
  951. }
  952. TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralUShortIndexClamped) {
  953. for (auto* ac : AccessChains()) {
  954. std::ostringstream shaders;
  955. shaders << "OpCapability Int16\n"
  956. << ShaderPreambleAC({"i"}) << "OpDecorate %rtarr ArrayStride 4 "
  957. << DecoSSBO() << TypesVoid() << TypesShort() << TypesFloat() << R"(
  958. %rtarr = OpTypeRuntimeArray %float
  959. %ssbo_s = OpTypeStruct %short %short %rtarr
  960. %var_ty = OpTypePointer Uniform %ssbo_s
  961. %ptr_ty = OpTypePointer Uniform %float
  962. %var = OpVariable %var_ty Uniform
  963. %short_2 = OpConstant %short 2
  964. %i = OpUndef %ushort
  965. ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450"
  966. ; CHECK: %uint = OpTypeInt 32 0
  967. ; CHECK-DAG: %uint_1 = OpConstant %uint 1
  968. ; CHECK-DAG: %uint_0 = OpConstant %uint 0
  969. ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %uint 2147483647
  970. ; CHECK: OpLabel
  971. ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %var 2
  972. ; CHECK-DAG: %[[max:\w+]] = OpISub %uint %[[arrlen]] %uint_1
  973. ; CHECK-DAG: %[[i_ext:\w+]] = OpSConvert %uint %i
  974. ; CHECK: %[[smin:\w+]] = OpExtInst %uint %[[GLSLSTD450]] UMin %[[max]] %[[intmax]]
  975. ; CHECK: %[[clamp:\w+]] = OpExtInst %uint %[[GLSLSTD450]] SClamp %[[i_ext]] %uint_0 %[[smin]]
  976. )"
  977. << MainPrefix() << ACCheck(ac, "%short_2 %i", "%short_2 %[[clamp]]")
  978. << MainSuffix();
  979. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  980. }
  981. }
  982. TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralIntIndexClamped) {
  983. for (auto* ac : AccessChains()) {
  984. std::ostringstream shaders;
  985. shaders << ShaderPreambleAC({"i"}) << "OpDecorate %rtarr ArrayStride 4 "
  986. << DecoSSBO() << TypesVoid() << TypesInt() << TypesFloat() << R"(
  987. %rtarr = OpTypeRuntimeArray %float
  988. %ssbo_s = OpTypeStruct %int %int %rtarr
  989. %var_ty = OpTypePointer Uniform %ssbo_s
  990. %ptr_ty = OpTypePointer Uniform %float
  991. %var = OpVariable %var_ty Uniform
  992. %int_2 = OpConstant %int 2
  993. %i = OpUndef %int
  994. ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450"
  995. ; CHECK-DAG: %int_1 = OpConstant %int 1
  996. ; CHECK-DAG: %int_0 = OpConstant %int 0
  997. ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %int 2147483647
  998. ; CHECK: OpLabel
  999. ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %var 2
  1000. ; CHECK: %[[max:\w+]] = OpISub %int %[[arrlen]] %int_1
  1001. ; CHECK: %[[smin:\w+]] = OpExtInst %int %[[GLSLSTD450]] UMin %[[max]] %[[intmax]]
  1002. ; CHECK: %[[clamp:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %i %int_0 %[[smin]]
  1003. )"
  1004. << MainPrefix() << ACCheck(ac, "%int_2 %i", "%int_2 %[[clamp]]")
  1005. << MainSuffix();
  1006. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  1007. }
  1008. }
  1009. TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralUIntIndexClamped) {
  1010. for (auto* ac : AccessChains()) {
  1011. std::ostringstream shaders;
  1012. shaders << ShaderPreambleAC({"i"}) << "OpDecorate %rtarr ArrayStride 4 "
  1013. << DecoSSBO() << TypesVoid() << TypesInt() << TypesFloat() << R"(
  1014. %rtarr = OpTypeRuntimeArray %float
  1015. %ssbo_s = OpTypeStruct %int %int %rtarr
  1016. %var_ty = OpTypePointer Uniform %ssbo_s
  1017. %ptr_ty = OpTypePointer Uniform %float
  1018. %var = OpVariable %var_ty Uniform
  1019. %int_2 = OpConstant %int 2
  1020. %i = OpUndef %uint
  1021. ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450"
  1022. ; CHECK-DAG: %uint_1 = OpConstant %uint 1
  1023. ; CHECK-DAG: %uint_0 = OpConstant %uint 0
  1024. ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %uint 2147483647
  1025. ; CHECK: OpLabel
  1026. ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %var 2
  1027. ; CHECK: %[[max:\w+]] = OpISub %uint %[[arrlen]] %uint_1
  1028. ; CHECK: %[[smin:\w+]] = OpExtInst %uint %[[GLSLSTD450]] UMin %[[max]] %[[intmax]]
  1029. ; CHECK: %[[clamp:\w+]] = OpExtInst %uint %[[GLSLSTD450]] SClamp %i %uint_0 %[[smin]]
  1030. )"
  1031. << MainPrefix() << ACCheck(ac, "%int_2 %i", "%int_2 %[[clamp]]")
  1032. << MainSuffix();
  1033. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  1034. }
  1035. }
  1036. TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralLongIndexClamped) {
  1037. for (auto* ac : AccessChains()) {
  1038. std::ostringstream shaders;
  1039. shaders << "OpCapability Int64" << ShaderPreambleAC({"i"})
  1040. << "OpDecorate %rtarr ArrayStride 4 " << DecoSSBO() << TypesVoid()
  1041. << TypesInt() << TypesLong() << TypesFloat() << R"(
  1042. %rtarr = OpTypeRuntimeArray %float
  1043. %ssbo_s = OpTypeStruct %int %int %rtarr
  1044. %var_ty = OpTypePointer Uniform %ssbo_s
  1045. %ptr_ty = OpTypePointer Uniform %float
  1046. %var = OpVariable %var_ty Uniform
  1047. %int_2 = OpConstant %int 2
  1048. %i = OpUndef %long
  1049. ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450"
  1050. ; CHECK-DAG: %long_0 = OpConstant %long 0
  1051. ; CHECK-DAG: %long_1 = OpConstant %long 1
  1052. ; CHECK-DAG: %[[longmax:\w+]] = OpConstant %long 9223372036854775807
  1053. ; CHECK: OpLabel
  1054. ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %var 2
  1055. ; CHECK: %[[arrlen_ext:\w+]] = OpUConvert %ulong %[[arrlen]]
  1056. ; CHECK: %[[max:\w+]] = OpISub %long %[[arrlen_ext]] %long_1
  1057. ; CHECK: %[[smin:\w+]] = OpExtInst %long %[[GLSLSTD450]] UMin %[[max]] %[[longmax]]
  1058. ; CHECK: %[[clamp:\w+]] = OpExtInst %long %[[GLSLSTD450]] SClamp %i %long_0 %[[smin]]
  1059. )" << MainPrefix()
  1060. << ACCheck(ac, "%int_2 %i", "%int_2 %[[clamp]]") << MainSuffix();
  1061. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  1062. }
  1063. }
  1064. TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralULongIndexClamped) {
  1065. for (auto* ac : AccessChains()) {
  1066. std::ostringstream shaders;
  1067. shaders << "OpCapability Int64" << ShaderPreambleAC({"i"})
  1068. << "OpDecorate %rtarr ArrayStride 4 " << DecoSSBO() << TypesVoid()
  1069. << TypesInt() << TypesLong() << TypesFloat() << R"(
  1070. %rtarr = OpTypeRuntimeArray %float
  1071. %ssbo_s = OpTypeStruct %int %int %rtarr
  1072. %var_ty = OpTypePointer Uniform %ssbo_s
  1073. %ptr_ty = OpTypePointer Uniform %float
  1074. %var = OpVariable %var_ty Uniform
  1075. %int_2 = OpConstant %int 2
  1076. %i = OpUndef %ulong
  1077. ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450"
  1078. ; CHECK-DAG: %ulong_0 = OpConstant %ulong 0
  1079. ; CHECK-DAG: %ulong_1 = OpConstant %ulong 1
  1080. ; CHECK-DAG: %[[longmax:\w+]] = OpConstant %ulong 9223372036854775807
  1081. ; CHECK: OpLabel
  1082. ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %var 2
  1083. ; CHECK: %[[arrlen_ext:\w+]] = OpUConvert %ulong %[[arrlen]]
  1084. ; CHECK: %[[max:\w+]] = OpISub %ulong %[[arrlen_ext]] %ulong_1
  1085. ; CHECK: %[[smin:\w+]] = OpExtInst %ulong %[[GLSLSTD450]] UMin %[[max]] %[[longmax]]
  1086. ; CHECK: %[[clamp:\w+]] = OpExtInst %ulong %[[GLSLSTD450]] SClamp %i %ulong_0 %[[smin]]
  1087. )" << MainPrefix()
  1088. << ACCheck(ac, "%int_2 %i", "%int_2 %[[clamp]]") << MainSuffix();
  1089. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  1090. }
  1091. }
  1092. TEST_F(GraphicsRobustAccessTest, ACRTArrayStructVectorElem) {
  1093. // The point of this test is that the access chain can have indices past the
  1094. // index into the runtime array. For good measure, the index into the final
  1095. // struct is out of bounds. We have to clamp that index too.
  1096. for (auto* ac : AccessChains()) {
  1097. std::ostringstream shaders;
  1098. shaders << ShaderPreambleAC({"i", "j"})
  1099. << "OpDecorate %rtarr ArrayStride 32\n"
  1100. << DecoSSBO() << "OpMemberDecorate %rtelem 0 Offset 0\n"
  1101. << "OpMemberDecorate %rtelem 1 Offset 16\n"
  1102. << TypesVoid() << TypesInt() << TypesFloat() << R"(
  1103. %v4float = OpTypeVector %float 4
  1104. %rtelem = OpTypeStruct %v4float %v4float
  1105. %rtarr = OpTypeRuntimeArray %rtelem
  1106. %ssbo_s = OpTypeStruct %int %int %rtarr
  1107. %var_ty = OpTypePointer Uniform %ssbo_s
  1108. %ptr_ty = OpTypePointer Uniform %float
  1109. %var = OpVariable %var_ty Uniform
  1110. %int_1 = OpConstant %int 1
  1111. %int_2 = OpConstant %int 2
  1112. %i = OpUndef %int
  1113. %j = OpUndef %int
  1114. ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450"
  1115. ; CHECK-DAG: %int_0 = OpConstant %int 0
  1116. ; CHECK-DAG: %int_3 = OpConstant %int 3
  1117. ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %int 2147483647
  1118. ; CHECK: OpLabel
  1119. ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %var 2
  1120. ; CHECK: %[[max:\w+]] = OpISub %int %[[arrlen]] %int_1
  1121. ; CHECK: %[[smin:\w+]] = OpExtInst %int %[[GLSLSTD450]] UMin %[[max]] %[[intmax]]
  1122. ; CHECK: %[[clamp_i:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %i %int_0 %[[smin]]
  1123. ; CHECK: %[[clamp_j:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %j %int_0 %int_3
  1124. )" << MainPrefix()
  1125. << ACCheck(ac, "%int_2 %i %int_1 %j",
  1126. "%int_2 %[[clamp_i]] %int_1 %[[clamp_j]]")
  1127. << MainSuffix();
  1128. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  1129. }
  1130. }
  1131. TEST_F(GraphicsRobustAccessTest, ACArrayRTArrayStructVectorElem) {
  1132. // Now add an additional level of arrays around the Block-decorated struct.
  1133. for (auto* ac : AccessChains()) {
  1134. std::ostringstream shaders;
  1135. shaders << ShaderPreambleAC({"i", "ssbo_s"})
  1136. << "OpDecorate %rtarr ArrayStride 32\n"
  1137. << DecoSSBO() << "OpMemberDecorate %rtelem 0 Offset 0\n"
  1138. << "OpMemberDecorate %rtelem 1 Offset 16\n"
  1139. << TypesVoid() << TypesInt() << TypesFloat() << R"(
  1140. %v4float = OpTypeVector %float 4
  1141. %rtelem = OpTypeStruct %v4float %v4float
  1142. %rtarr = OpTypeRuntimeArray %rtelem
  1143. %ssbo_s = OpTypeStruct %int %int %rtarr
  1144. %arr_size = OpConstant %int 10
  1145. %arr_ssbo = OpTypeArray %ssbo_s %arr_size
  1146. %var_ty = OpTypePointer Uniform %arr_ssbo
  1147. %ptr_ty = OpTypePointer Uniform %float
  1148. %var = OpVariable %var_ty Uniform
  1149. %int_1 = OpConstant %int 1
  1150. %int_2 = OpConstant %int 2
  1151. %int_17 = OpConstant %int 17
  1152. %i = OpUndef %int
  1153. ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450"
  1154. ; CHECK-DAG: %[[ssbo_p:\w+]] = OpTypePointer Uniform %ssbo_s
  1155. ; CHECK-DAG: %int_0 = OpConstant %int 0
  1156. ; CHECK-DAG: %int_9 = OpConstant %int 9
  1157. ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %int 2147483647
  1158. ; CHECK: OpLabel
  1159. ; This access chain is manufactured only so we can compute the array length.
  1160. ; Note that the %int_9 is already clamped
  1161. ; CHECK: %[[ssbo_base:\w+]] = )" << ac
  1162. << R"( %[[ssbo_p]] %var %int_9
  1163. ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %[[ssbo_base]] 2
  1164. ; CHECK: %[[max:\w+]] = OpISub %int %[[arrlen]] %int_1
  1165. ; CHECK: %[[smin:\w+]] = OpExtInst %int %[[GLSLSTD450]] UMin %[[max]] %[[intmax]]
  1166. ; CHECK: %[[clamp_i:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %i %int_0 %[[smin]]
  1167. )" << MainPrefix()
  1168. << ACCheck(ac, "%int_17 %int_2 %i %int_1 %int_2",
  1169. "%int_9 %int_2 %[[clamp_i]] %int_1 %int_2")
  1170. << MainSuffix();
  1171. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  1172. }
  1173. }
  1174. TEST_F(GraphicsRobustAccessTest, ACSplitACArrayRTArrayStructVectorElem) {
  1175. // Split the address calculation across two access chains. Force
  1176. // the transform to walk up the access chains to find the base variable.
  1177. for (auto* ac : AccessChains()) {
  1178. std::ostringstream shaders;
  1179. shaders << ShaderPreambleAC({"i", "j", "k", "ssbo_s", "ssbo_pty",
  1180. "rtarr_pty", "ac_ssbo", "ac_rtarr"})
  1181. << "OpDecorate %rtarr ArrayStride 32\n"
  1182. << DecoSSBO() << "OpMemberDecorate %rtelem 0 Offset 0\n"
  1183. << "OpMemberDecorate %rtelem 1 Offset 16\n"
  1184. << TypesVoid() << TypesInt() << TypesFloat() << R"(
  1185. %v4float = OpTypeVector %float 4
  1186. %rtelem = OpTypeStruct %v4float %v4float
  1187. %rtarr = OpTypeRuntimeArray %rtelem
  1188. %ssbo_s = OpTypeStruct %int %int %rtarr
  1189. %arr_size = OpConstant %int 10
  1190. %arr_ssbo = OpTypeArray %ssbo_s %arr_size
  1191. %var_ty = OpTypePointer Uniform %arr_ssbo
  1192. %ssbo_pty = OpTypePointer Uniform %ssbo_s
  1193. %rtarr_pty = OpTypePointer Uniform %rtarr
  1194. %ptr_ty = OpTypePointer Uniform %float
  1195. %var = OpVariable %var_ty Uniform
  1196. %int_1 = OpConstant %int 1
  1197. %int_2 = OpConstant %int 2
  1198. %i = OpUndef %int
  1199. %j = OpUndef %int
  1200. %k = OpUndef %int
  1201. ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450"
  1202. ; CHECK-DAG: %int_0 = OpConstant %int 0
  1203. ; CHECK-DAG: %int_9 = OpConstant %int 9
  1204. ; CHECK-DAG: %int_3 = OpConstant %int 3
  1205. ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %int 2147483647
  1206. ; CHECK: OpLabel
  1207. ; CHECK: %[[clamp_i:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %i %int_0 %int_9
  1208. ; CHECK: %ac_ssbo = )" << ac
  1209. << R"( %ssbo_pty %var %[[clamp_i]]
  1210. ; CHECK: %ac_rtarr = )"
  1211. << ac << R"( %rtarr_pty %ac_ssbo %int_2
  1212. ; This is the interesting bit. This array length is needed for an OpAccessChain
  1213. ; computing %ac, but the algorithm had to track back through %ac_rtarr's
  1214. ; definition to find the base pointer %ac_ssbo.
  1215. ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %ac_ssbo 2
  1216. ; CHECK: %[[max:\w+]] = OpISub %int %[[arrlen]] %int_1
  1217. ; CHECK: %[[smin:\w+]] = OpExtInst %int %[[GLSLSTD450]] UMin %[[max]] %[[intmax]]
  1218. ; CHECK: %[[clamp_j:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %j %int_0 %[[smin]]
  1219. ; CHECK: %[[clamp_k:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %k %int_0 %int_3
  1220. ; CHECK: %ac = )" << ac
  1221. << R"( %ptr_ty %ac_rtarr %[[clamp_j]] %int_1 %[[clamp_k]]
  1222. ; CHECK-NOT: AccessChain
  1223. )" << MainPrefix()
  1224. << "%ac_ssbo = " << ac << " %ssbo_pty %var %i\n"
  1225. << "%ac_rtarr = " << ac << " %rtarr_pty %ac_ssbo %int_2\n"
  1226. << "%ac = " << ac << " %ptr_ty %ac_rtarr %j %int_1 %k\n"
  1227. << MainSuffix();
  1228. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  1229. }
  1230. }
  1231. TEST_F(GraphicsRobustAccessTest,
  1232. ACSplitACArrayRTArrayStructVectorElemAcrossBasicBlocks) {
  1233. // Split the address calculation across two access chains. Force
  1234. // the transform to walk up the access chains to find the base variable.
  1235. // This time, put the different access chains in different basic blocks.
  1236. // This is an integrity check to ensure that we keep the instruction-to-block
  1237. // mapping consistent.
  1238. for (auto* ac : AccessChains()) {
  1239. std::ostringstream shaders;
  1240. shaders << ShaderPreambleAC({"i", "j", "k", "bb1", "bb2", "ssbo_s",
  1241. "ssbo_pty", "rtarr_pty", "ac_ssbo",
  1242. "ac_rtarr"})
  1243. << "OpDecorate %rtarr ArrayStride 32\n"
  1244. << DecoSSBO() << "OpMemberDecorate %rtelem 0 Offset 0\n"
  1245. << "OpMemberDecorate %rtelem 1 Offset 16\n"
  1246. << TypesVoid() << TypesInt() << TypesFloat() << R"(
  1247. %v4float = OpTypeVector %float 4
  1248. %rtelem = OpTypeStruct %v4float %v4float
  1249. %rtarr = OpTypeRuntimeArray %rtelem
  1250. %ssbo_s = OpTypeStruct %int %int %rtarr
  1251. %arr_size = OpConstant %int 10
  1252. %arr_ssbo = OpTypeArray %ssbo_s %arr_size
  1253. %var_ty = OpTypePointer Uniform %arr_ssbo
  1254. %ssbo_pty = OpTypePointer Uniform %ssbo_s
  1255. %rtarr_pty = OpTypePointer Uniform %rtarr
  1256. %ptr_ty = OpTypePointer Uniform %float
  1257. %var = OpVariable %var_ty Uniform
  1258. %int_1 = OpConstant %int 1
  1259. %int_2 = OpConstant %int 2
  1260. %i = OpUndef %int
  1261. %j = OpUndef %int
  1262. %k = OpUndef %int
  1263. ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450"
  1264. ; CHECK-DAG: %int_0 = OpConstant %int 0
  1265. ; CHECK-DAG: %int_9 = OpConstant %int 9
  1266. ; CHECK-DAG: %int_3 = OpConstant %int 3
  1267. ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %int 2147483647
  1268. ; CHECK: OpLabel
  1269. ; CHECK: %[[clamp_i:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %i %int_0 %int_9
  1270. ; CHECK: %ac_ssbo = )" << ac
  1271. << R"( %ssbo_pty %var %[[clamp_i]]
  1272. ; CHECK: %bb1 = OpLabel
  1273. ; CHECK: %ac_rtarr = )"
  1274. << ac << R"( %rtarr_pty %ac_ssbo %int_2
  1275. ; CHECK: %bb2 = OpLabel
  1276. ; This is the interesting bit. This array length is needed for an OpAccessChain
  1277. ; computing %ac, but the algorithm had to track back through %ac_rtarr's
  1278. ; definition to find the base pointer %ac_ssbo.
  1279. ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %ac_ssbo 2
  1280. ; CHECK: %[[max:\w+]] = OpISub %int %[[arrlen]] %int_1
  1281. ; CHECK: %[[smin:\w+]] = OpExtInst %int %[[GLSLSTD450]] UMin %[[max]] %[[intmax]]
  1282. ; CHECK: %[[clamp_j:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %j %int_0 %[[smin]]
  1283. ; CHECK: %[[clamp_k:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %k %int_0 %int_3
  1284. ; CHECK: %ac = )" << ac
  1285. << R"( %ptr_ty %ac_rtarr %[[clamp_j]] %int_1 %[[clamp_k]]
  1286. ; CHECK-NOT: AccessChain
  1287. )" << MainPrefix()
  1288. << "%ac_ssbo = " << ac << " %ssbo_pty %var %i\n"
  1289. << "OpBranch %bb1\n%bb1 = OpLabel\n"
  1290. << "%ac_rtarr = " << ac << " %rtarr_pty %ac_ssbo %int_2\n"
  1291. << "OpBranch %bb2\n%bb2 = OpLabel\n"
  1292. << "%ac = " << ac << " %ptr_ty %ac_rtarr %j %int_1 %k\n"
  1293. << MainSuffix();
  1294. SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
  1295. }
  1296. }
  1297. TEST_F(GraphicsRobustAccessTest, bug3813) {
  1298. // This shader comes from Dawn's
  1299. // TextureViewSamplingTest.TextureCubeMapOnWholeTexture, converted from GLSL
  1300. // by glslang.
  1301. // The pass was inserting a signed 32-bit int type, but not correctly marking
  1302. // the shader as changed.
  1303. std::string shader = R"(
  1304. ; SPIR-V
  1305. ; Version: 1.0
  1306. ; Generator: Google Shaderc over Glslang; 10
  1307. ; Bound: 46
  1308. ; Schema: 0
  1309. OpCapability Shader
  1310. %1 = OpExtInstImport "GLSL.std.450"
  1311. OpMemoryModel Logical GLSL450
  1312. OpEntryPoint Fragment %4 "main" %12 %29
  1313. OpExecutionMode %4 OriginUpperLeft
  1314. OpSource GLSL 450
  1315. OpSourceExtension "GL_GOOGLE_cpp_style_line_directive"
  1316. OpSourceExtension "GL_GOOGLE_include_directive"
  1317. OpName %4 "main"
  1318. OpName %8 "sc"
  1319. OpName %12 "texCoord"
  1320. OpName %21 "tc"
  1321. OpName %29 "fragColor"
  1322. OpName %32 "texture0"
  1323. OpName %36 "sampler0"
  1324. OpDecorate %12 Location 0
  1325. OpDecorate %29 Location 0
  1326. OpDecorate %32 DescriptorSet 0
  1327. OpDecorate %32 Binding 1
  1328. OpDecorate %36 DescriptorSet 0
  1329. OpDecorate %36 Binding 0
  1330. %2 = OpTypeVoid
  1331. %3 = OpTypeFunction %2
  1332. %6 = OpTypeFloat 32
  1333. %7 = OpTypePointer Function %6
  1334. %9 = OpConstant %6 2
  1335. %10 = OpTypeVector %6 2
  1336. %11 = OpTypePointer Input %10
  1337. %12 = OpVariable %11 Input
  1338. %13 = OpTypeInt 32 0
  1339. %14 = OpConstant %13 0
  1340. %15 = OpTypePointer Input %6
  1341. %19 = OpConstant %6 1
  1342. %22 = OpConstant %13 1
  1343. %27 = OpTypeVector %6 4
  1344. %28 = OpTypePointer Output %27
  1345. %29 = OpVariable %28 Output
  1346. %30 = OpTypeImage %6 Cube 0 0 0 1 Unknown
  1347. %31 = OpTypePointer UniformConstant %30
  1348. %32 = OpVariable %31 UniformConstant
  1349. %34 = OpTypeSampler
  1350. %35 = OpTypePointer UniformConstant %34
  1351. %36 = OpVariable %35 UniformConstant
  1352. %38 = OpTypeSampledImage %30
  1353. %43 = OpTypeVector %6 3
  1354. %4 = OpFunction %2 None %3
  1355. %5 = OpLabel
  1356. %8 = OpVariable %7 Function
  1357. %21 = OpVariable %7 Function
  1358. %16 = OpAccessChain %15 %12 %14
  1359. %17 = OpLoad %6 %16
  1360. %18 = OpFMul %6 %9 %17
  1361. %20 = OpFSub %6 %18 %19
  1362. OpStore %8 %20
  1363. %23 = OpAccessChain %15 %12 %22
  1364. %24 = OpLoad %6 %23
  1365. %25 = OpFMul %6 %9 %24
  1366. %26 = OpFSub %6 %25 %19
  1367. OpStore %21 %26
  1368. %33 = OpLoad %30 %32
  1369. %37 = OpLoad %34 %36
  1370. %39 = OpSampledImage %38 %33 %37
  1371. %40 = OpLoad %6 %21
  1372. %41 = OpLoad %6 %8
  1373. %42 = OpFNegate %6 %41
  1374. %44 = OpCompositeConstruct %43 %19 %40 %42
  1375. %45 = OpImageSampleImplicitLod %27 %39 %44
  1376. OpStore %29 %45
  1377. OpReturn
  1378. OpFunctionEnd
  1379. )";
  1380. std::string expected = R"(OpCapability Shader
  1381. %1 = OpExtInstImport "GLSL.std.450"
  1382. OpMemoryModel Logical GLSL450
  1383. OpEntryPoint Fragment %main "main" %texCoord %fragColor
  1384. OpExecutionMode %main OriginUpperLeft
  1385. OpSource GLSL 450
  1386. OpSourceExtension "GL_GOOGLE_cpp_style_line_directive"
  1387. OpSourceExtension "GL_GOOGLE_include_directive"
  1388. OpName %main "main"
  1389. OpName %sc "sc"
  1390. OpName %texCoord "texCoord"
  1391. OpName %tc "tc"
  1392. OpName %fragColor "fragColor"
  1393. OpName %texture0 "texture0"
  1394. OpName %sampler0 "sampler0"
  1395. OpDecorate %texCoord Location 0
  1396. OpDecorate %fragColor Location 0
  1397. OpDecorate %texture0 DescriptorSet 0
  1398. OpDecorate %texture0 Binding 1
  1399. OpDecorate %sampler0 DescriptorSet 0
  1400. OpDecorate %sampler0 Binding 0
  1401. %void = OpTypeVoid
  1402. %10 = OpTypeFunction %void
  1403. %float = OpTypeFloat 32
  1404. %_ptr_Function_float = OpTypePointer Function %float
  1405. %float_2 = OpConstant %float 2
  1406. %v2float = OpTypeVector %float 2
  1407. %_ptr_Input_v2float = OpTypePointer Input %v2float
  1408. %texCoord = OpVariable %_ptr_Input_v2float Input
  1409. %uint = OpTypeInt 32 0
  1410. %uint_0 = OpConstant %uint 0
  1411. %_ptr_Input_float = OpTypePointer Input %float
  1412. %float_1 = OpConstant %float 1
  1413. %uint_1 = OpConstant %uint 1
  1414. %v4float = OpTypeVector %float 4
  1415. %_ptr_Output_v4float = OpTypePointer Output %v4float
  1416. %fragColor = OpVariable %_ptr_Output_v4float Output
  1417. %23 = OpTypeImage %float Cube 0 0 0 1 Unknown
  1418. %_ptr_UniformConstant_23 = OpTypePointer UniformConstant %23
  1419. %texture0 = OpVariable %_ptr_UniformConstant_23 UniformConstant
  1420. %25 = OpTypeSampler
  1421. %_ptr_UniformConstant_25 = OpTypePointer UniformConstant %25
  1422. %sampler0 = OpVariable %_ptr_UniformConstant_25 UniformConstant
  1423. %27 = OpTypeSampledImage %23
  1424. %v3float = OpTypeVector %float 3
  1425. %int = OpTypeInt 32 1
  1426. %main = OpFunction %void None %10
  1427. %29 = OpLabel
  1428. %sc = OpVariable %_ptr_Function_float Function
  1429. %tc = OpVariable %_ptr_Function_float Function
  1430. %30 = OpAccessChain %_ptr_Input_float %texCoord %uint_0
  1431. %31 = OpLoad %float %30
  1432. %32 = OpFMul %float %float_2 %31
  1433. %33 = OpFSub %float %32 %float_1
  1434. OpStore %sc %33
  1435. %34 = OpAccessChain %_ptr_Input_float %texCoord %uint_1
  1436. %35 = OpLoad %float %34
  1437. %36 = OpFMul %float %float_2 %35
  1438. %37 = OpFSub %float %36 %float_1
  1439. OpStore %tc %37
  1440. %38 = OpLoad %23 %texture0
  1441. %39 = OpLoad %25 %sampler0
  1442. %40 = OpSampledImage %27 %38 %39
  1443. %41 = OpLoad %float %tc
  1444. %42 = OpLoad %float %sc
  1445. %43 = OpFNegate %float %42
  1446. %44 = OpCompositeConstruct %v3float %float_1 %41 %43
  1447. %45 = OpImageSampleImplicitLod %v4float %40 %44
  1448. OpStore %fragColor %45
  1449. OpReturn
  1450. OpFunctionEnd
  1451. )";
  1452. SinglePassRunAndCheck<GraphicsRobustAccessPass>(shader, expected, false,
  1453. true);
  1454. }
  1455. TEST_F(GraphicsRobustAccessTest, ReplaceIndexReportsChanged) {
  1456. // A ClusterFuzz generated shader that triggered a
  1457. // "Binary size unexpectedly changed despite the optimizer saying there was no
  1458. // change" assertion.
  1459. // See https://github.com/KhronosGroup/SPIRV-Tools/issues/4166.
  1460. std::string shader = R"(
  1461. ; SPIR-V
  1462. ; Version: 1.0
  1463. ; Generator: Google Shaderc over Glslang; 245
  1464. ; Bound: 41
  1465. ; Schema: 0
  1466. OpCapability Shader
  1467. %1 = OpExtInstImport "GLSL.std.450"
  1468. OpMemoryModel Logical GLSL450
  1469. OpEntryPoint GLCompute %main "else" %gl_GlobalInvocationID
  1470. OpExecutionMode %main LocalSize 1 1 3338665985
  1471. OpSource GLSL 450
  1472. OpSourceExtension "GL_GOOGLE_cpp_style_line_directive"
  1473. OpSourceExtension "GL_GOOGLE_include_directive"
  1474. OpName %main "main"
  1475. OpName %index "index"
  1476. OpName %gl_GlobalInvocationID "gl_GlobalInvocationID"
  1477. OpName %S "S"
  1478. OpMemberName %_struct_24 0 ""
  1479. OpMemberName %_struct_24 1 ""
  1480. OpName %Dst "Dst"
  1481. OpMemberName %Dst 0 "s"
  1482. OpName %dst "dst"
  1483. OpName %Src "Src"
  1484. OpMemberName %Src 0 "s"
  1485. OpName %src "src"
  1486. OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
  1487. OpMemberDecorate %_struct_24 0 Offset 64
  1488. OpMemberDecorate %_struct_24 1 Offset 8
  1489. OpDecorate %_arr__struct_24_uint_1 ArrayStride 16
  1490. OpMemberDecorate %Dst 0 Offset 0
  1491. OpDecorate %Dst BufferBlock
  1492. OpDecorate %dst DescriptorSet 0
  1493. OpDecorate %dst Binding 1
  1494. OpDecorate %_arr__struct_24_uint_1_0 ArrayStride 16
  1495. OpMemberDecorate %Src 0 Offset 0
  1496. OpDecorate %Src Block
  1497. OpDecorate %src DescriptorSet 0
  1498. OpDecorate %src Binding 0
  1499. %void = OpTypeVoid
  1500. %3 = OpTypeFunction %void
  1501. %uint = OpTypeInt 32 0
  1502. %_ptr_Function_uint = OpTypePointer Function %uint
  1503. %v3uint = OpTypeVector %uint 3
  1504. %_ptr_Input_v3uint = OpTypePointer Input %v3uint
  1505. %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
  1506. %uint_4864 = OpConstant %uint 4864
  1507. %_ptr_Input_uint = OpTypePointer Input %uint
  1508. %uint_1 = OpConstant %uint 1
  1509. %bool = OpTypeBool
  1510. %v2uint = OpTypeVector %uint 2
  1511. %_struct_24 = OpTypeStruct %_ptr_Input_uint %v2uint
  1512. %_arr__struct_24_uint_1 = OpTypeArray %_struct_24 %uint_1
  1513. %Dst = OpTypeStruct %_arr__struct_24_uint_1
  1514. %_ptr_Uniform_Dst = OpTypePointer Uniform %Dst
  1515. %dst = OpVariable %_ptr_Uniform_Dst Uniform
  1516. %int = OpTypeInt 32 1
  1517. %int_0 = OpConstant %int 0
  1518. %_arr__struct_24_uint_1_0 = OpTypeArray %_struct_24 %uint_1
  1519. %Src = OpTypeStruct %_arr__struct_24_uint_1_0
  1520. %_ptr_Uniform_Src = OpTypePointer Uniform %Src
  1521. %src = OpVariable %_ptr_Uniform_Src Uniform
  1522. %_ptr_Uniform__struct_24 = OpTypePointer Uniform %_struct_24
  1523. %main = OpFunction %void None %3
  1524. %5 = OpLabel
  1525. %index = OpVariable %_ptr_Function_uint Function
  1526. %14 = OpAccessChain %_ptr_Input_uint %gl_GlobalInvocationID %uint_4864
  1527. %15 = OpLoad %uint %14
  1528. OpStore %index %15
  1529. %16 = OpLoad %uint %index
  1530. %S = OpUGreaterThanEqual %bool %16 %uint_1
  1531. OpSelectionMerge %21 None
  1532. OpBranchConditional %S %20 %21
  1533. %20 = OpLabel
  1534. OpReturn
  1535. %21 = OpLabel
  1536. %31 = OpLoad %uint %index
  1537. %36 = OpLoad %uint %index
  1538. %38 = OpAccessChain %_ptr_Uniform__struct_24 %src %int_0 %36
  1539. %39 = OpLoad %_struct_24 %38
  1540. %40 = OpAccessChain %_ptr_Uniform__struct_24 %dst %int_0 %31
  1541. OpStore %40 %39
  1542. OpReturn
  1543. OpFunctionEnd
  1544. )";
  1545. std::vector<uint32_t> optimized_bin;
  1546. auto status = spvtools::opt::Pass::Status::Failure;
  1547. std::tie(optimized_bin, status) =
  1548. SinglePassRunToBinary<GraphicsRobustAccessPass>(shader, false);
  1549. // Check whether the pass returns the correct modification indication.
  1550. EXPECT_EQ(status, spvtools::opt::Pass::Status::SuccessWithChange);
  1551. }
  1552. // TODO(dneto): Test access chain index wider than 64 bits?
  1553. // TODO(dneto): Test struct access chain index wider than 64 bits?
  1554. // TODO(dneto): OpImageTexelPointer
  1555. // - all Dim types: 1D 2D Cube 3D Rect Buffer
  1556. // - all Dim types that can be arrayed: 1D 2D 3D
  1557. // - sample index: set to 0 if not multisampled
  1558. // - Dim (2D, Cube Rect} with multisampling
  1559. // -1 0 max excess
  1560. // TODO(dneto): Test OpImageTexelPointer with coordinate component index other
  1561. // than 32 bits.
  1562. } // namespace