val_layout_test.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755
  1. // Copyright (c) 2015-2016 The Khronos Group Inc.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // Validation tests for Logical Layout
  15. #include <functional>
  16. #include <string>
  17. #include <tuple>
  18. #include <utility>
  19. #include <vector>
  20. #include "gmock/gmock.h"
  21. #include "source/diagnostic.h"
  22. #include "test/unit_spirv.h"
  23. #include "test/val/val_fixtures.h"
  24. namespace spvtools {
  25. namespace val {
  26. namespace {
  27. using ::testing::Eq;
  28. using ::testing::HasSubstr;
  29. using ::testing::StrEq;
  30. using pred_type = std::function<spv_result_t(int)>;
  31. using ValidateLayout = spvtest::ValidateBase<
  32. std::tuple<int, std::tuple<std::string, pred_type, pred_type>>>;
  33. // returns true if order is equal to VAL
  34. template <int VAL, spv_result_t RET = SPV_ERROR_INVALID_LAYOUT>
  35. spv_result_t Equals(int order) {
  36. return order == VAL ? SPV_SUCCESS : RET;
  37. }
  38. // returns true if order is between MIN and MAX(inclusive)
  39. template <int MIN, int MAX, spv_result_t RET = SPV_ERROR_INVALID_LAYOUT>
  40. struct Range {
  41. explicit Range(bool inverse = false) : inverse_(inverse) {}
  42. spv_result_t operator()(int order) {
  43. return (inverse_ ^ (order >= MIN && order <= MAX)) ? SPV_SUCCESS : RET;
  44. }
  45. private:
  46. bool inverse_;
  47. };
  48. // SPIRV source used to test the logical layout
  49. const std::vector<std::string>& getInstructions() {
  50. // clang-format off
  51. static const std::vector<std::string> instructions = {
  52. "OpCapability Shader",
  53. "OpExtension \"TestExtension\"",
  54. "%inst = OpExtInstImport \"GLSL.std.450\"",
  55. "OpMemoryModel Logical GLSL450",
  56. "OpEntryPoint GLCompute %func \"\"",
  57. "OpExecutionMode %func LocalSize 1 1 1",
  58. "OpExecutionModeId %func LocalSizeId %one %one %one",
  59. "%str = OpString \"Test String\"",
  60. "%str2 = OpString \"blabla\"",
  61. "OpSource GLSL 450 %str \"uniform vec3 var = vec3(4.0);\"",
  62. "OpSourceContinued \"void main(){return;}\"",
  63. "OpSourceExtension \"Test extension\"",
  64. "OpName %func \"MyFunction\"",
  65. "OpMemberName %struct 1 \"my_member\"",
  66. "OpDecorate %dgrp RowMajor",
  67. "OpMemberDecorate %struct 1 RowMajor",
  68. "%dgrp = OpDecorationGroup",
  69. "OpGroupDecorate %dgrp %mat33 %mat44",
  70. "%intt = OpTypeInt 32 1",
  71. "%floatt = OpTypeFloat 32",
  72. "%voidt = OpTypeVoid",
  73. "%boolt = OpTypeBool",
  74. "%vec4 = OpTypeVector %floatt 4",
  75. "%vec3 = OpTypeVector %floatt 3",
  76. "%mat33 = OpTypeMatrix %vec3 3",
  77. "%mat44 = OpTypeMatrix %vec4 4",
  78. "%struct = OpTypeStruct %intt %mat33",
  79. "%vfunct = OpTypeFunction %voidt",
  80. "%viifunct = OpTypeFunction %voidt %intt %intt",
  81. "%one = OpConstant %intt 1",
  82. // TODO(umar): OpConstant fails because the type is not defined
  83. // TODO(umar): OpGroupMemberDecorate
  84. "OpLine %str 3 4",
  85. "OpNoLine",
  86. "%func = OpFunction %voidt None %vfunct",
  87. "%l = OpLabel",
  88. "OpReturn ; %func return",
  89. "OpFunctionEnd ; %func end",
  90. "%func2 = OpFunction %voidt None %viifunct",
  91. "%funcp1 = OpFunctionParameter %intt",
  92. "%funcp2 = OpFunctionParameter %intt",
  93. "%fLabel = OpLabel",
  94. "OpNop",
  95. "OpReturn ; %func2 return",
  96. "OpFunctionEnd"
  97. };
  98. return instructions;
  99. }
  100. static const int kRangeEnd = 1000;
  101. pred_type All = Range<0, kRangeEnd>();
  102. INSTANTIATE_TEST_SUITE_P(InstructionsOrder,
  103. ValidateLayout,
  104. ::testing::Combine(::testing::Range((int)0, (int)getInstructions().size()),
  105. // Note: Because of ID dependencies between instructions, some instructions
  106. // are not free to be placed anywhere without triggering an non-layout
  107. // validation error. Therefore, "Lines to compile" for some instructions
  108. // are not "All" in the below.
  109. //
  110. // | Instruction | Line(s) valid | Lines to compile
  111. ::testing::Values(std::make_tuple(std::string("OpCapability") , Equals<0> , Range<0, 2>())
  112. , std::make_tuple(std::string("OpExtension") , Equals<1> , All)
  113. , std::make_tuple(std::string("OpExtInstImport") , Equals<2> , All)
  114. , std::make_tuple(std::string("OpMemoryModel") , Equals<3> , Range<1, kRangeEnd>())
  115. , std::make_tuple(std::string("OpEntryPoint") , Equals<4> , All)
  116. , std::make_tuple(std::string("OpExecutionMode ") , Range<5, 6>() , All)
  117. , std::make_tuple(std::string("OpExecutionModeId") , Range<5, 6>() , All)
  118. , std::make_tuple(std::string("OpSource ") , Range<7, 11>() , Range<8, kRangeEnd>())
  119. , std::make_tuple(std::string("OpSourceContinued ") , Range<7, 11>() , All)
  120. , std::make_tuple(std::string("OpSourceExtension ") , Range<7, 11>() , All)
  121. , std::make_tuple(std::string("%str2 = OpString ") , Range<7, 11>() , All)
  122. , std::make_tuple(std::string("OpName ") , Range<12, 13>() , All)
  123. , std::make_tuple(std::string("OpMemberName ") , Range<12, 13>() , All)
  124. , std::make_tuple(std::string("OpDecorate ") , Range<14, 17>() , All)
  125. , std::make_tuple(std::string("OpMemberDecorate ") , Range<14, 17>() , All)
  126. , std::make_tuple(std::string("OpGroupDecorate ") , Range<14, 17>() , Range<17, kRangeEnd>())
  127. , std::make_tuple(std::string("OpDecorationGroup") , Range<14, 17>() , Range<0, 16>())
  128. , std::make_tuple(std::string("OpTypeBool") , Range<18, 31>() , All)
  129. , std::make_tuple(std::string("OpTypeVoid") , Range<18, 31>() , Range<0, 26>())
  130. , std::make_tuple(std::string("OpTypeFloat") , Range<18, 31>() , Range<0,21>())
  131. , std::make_tuple(std::string("OpTypeInt") , Range<18, 31>() , Range<0, 21>())
  132. , std::make_tuple(std::string("OpTypeVector %floatt 4") , Range<18, 31>() , Range<20, 24>())
  133. , std::make_tuple(std::string("OpTypeMatrix %vec4 4") , Range<18, 31>() , Range<23, kRangeEnd>())
  134. , std::make_tuple(std::string("OpTypeStruct") , Range<18, 31>() , Range<25, kRangeEnd>())
  135. , std::make_tuple(std::string("%vfunct = OpTypeFunction"), Range<18, 31>() , Range<21, 31>())
  136. , std::make_tuple(std::string("OpConstant") , Range<18, 31>() , Range<21, kRangeEnd>())
  137. , std::make_tuple(std::string("OpLine ") , Range<18, kRangeEnd>() , Range<8, kRangeEnd>())
  138. , std::make_tuple(std::string("OpNoLine") , Range<18, kRangeEnd>() , All)
  139. , std::make_tuple(std::string("%fLabel = OpLabel") , Equals<39> , All)
  140. , std::make_tuple(std::string("OpNop") , Equals<40> , Range<40,kRangeEnd>())
  141. , std::make_tuple(std::string("OpReturn ; %func2 return") , Equals<41> , All)
  142. )));
  143. // clang-format on
  144. // Creates a new vector which removes the string if the substr is found in the
  145. // instructions vector and reinserts it in the location specified by order.
  146. // NOTE: This will not work correctly if there are two instances of substr in
  147. // instructions
  148. std::vector<std::string> GenerateCode(std::string substr, int order) {
  149. std::vector<std::string> code(getInstructions().size());
  150. std::vector<std::string> inst(1);
  151. partition_copy(std::begin(getInstructions()), std::end(getInstructions()),
  152. std::begin(code), std::begin(inst),
  153. [=](const std::string& str) {
  154. return std::string::npos == str.find(substr);
  155. });
  156. code.insert(std::begin(code) + order, inst.front());
  157. return code;
  158. }
  159. // This test will check the logical layout of a binary by removing each
  160. // instruction in the pair of the INSTANTIATE_TEST_SUITE_P call and moving it in
  161. // the SPIRV source formed by combining the vector "instructions".
  162. TEST_P(ValidateLayout, Layout) {
  163. int order;
  164. std::string instruction;
  165. pred_type pred;
  166. pred_type test_pred; // Predicate to determine if the test should be build
  167. std::tuple<std::string, pred_type, pred_type> testCase;
  168. std::tie(order, testCase) = GetParam();
  169. std::tie(instruction, pred, test_pred) = testCase;
  170. // Skip test which break the code generation
  171. if (test_pred(order)) return;
  172. std::vector<std::string> code = GenerateCode(instruction, order);
  173. std::stringstream ss;
  174. std::copy(std::begin(code), std::end(code),
  175. std::ostream_iterator<std::string>(ss, "\n"));
  176. const auto env = SPV_ENV_UNIVERSAL_1_3;
  177. // printf("code: \n%s\n", ss.str().c_str());
  178. CompileSuccessfully(ss.str(), env);
  179. spv_result_t result;
  180. // clang-format off
  181. ASSERT_EQ(pred(order), result = ValidateInstructions(env))
  182. << "Actual: " << spvResultToString(result)
  183. << "\nExpected: " << spvResultToString(pred(order))
  184. << "\nOrder: " << order
  185. << "\nInstruction: " << instruction
  186. << "\nCode: \n" << ss.str();
  187. // clang-format on
  188. }
  189. TEST_F(ValidateLayout, MemoryModelMissingBeforeEntryPoint) {
  190. std::string str = R"(
  191. OpCapability Matrix
  192. OpExtension "TestExtension"
  193. %inst = OpExtInstImport "GLSL.std.450"
  194. OpEntryPoint GLCompute %func ""
  195. OpExecutionMode %func LocalSize 1 1 1
  196. )";
  197. CompileSuccessfully(str);
  198. ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions());
  199. EXPECT_THAT(
  200. getDiagnosticString(),
  201. HasSubstr(
  202. "EntryPoint cannot appear before the memory model instruction"));
  203. }
  204. TEST_F(ValidateLayout, MemoryModelMissing) {
  205. char str[] = R"(OpCapability Linkage)";
  206. CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1);
  207. ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT,
  208. ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
  209. EXPECT_THAT(getDiagnosticString(),
  210. HasSubstr("Missing required OpMemoryModel instruction"));
  211. }
  212. TEST_F(ValidateLayout, MemoryModelSpecifiedTwice) {
  213. char str[] = R"(
  214. OpCapability Linkage
  215. OpCapability Shader
  216. OpMemoryModel Logical Simple
  217. OpMemoryModel Logical Simple
  218. )";
  219. CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1);
  220. ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT,
  221. ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
  222. EXPECT_THAT(getDiagnosticString(),
  223. HasSubstr("OpMemoryModel should only be provided once"));
  224. }
  225. TEST_F(ValidateLayout, FunctionDefinitionBeforeDeclarationBad) {
  226. char str[] = R"(
  227. OpCapability Shader
  228. OpMemoryModel Logical GLSL450
  229. OpDecorate %var Restrict
  230. %intt = OpTypeInt 32 1
  231. %voidt = OpTypeVoid
  232. %vfunct = OpTypeFunction %voidt
  233. %vifunct = OpTypeFunction %voidt %intt
  234. %ptrt = OpTypePointer Function %intt
  235. %func = OpFunction %voidt None %vfunct
  236. %funcl = OpLabel
  237. OpNop
  238. OpReturn
  239. OpFunctionEnd
  240. %func2 = OpFunction %voidt None %vifunct ; must appear before definition
  241. %func2p = OpFunctionParameter %intt
  242. OpFunctionEnd
  243. )";
  244. CompileSuccessfully(str);
  245. ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions());
  246. EXPECT_THAT(
  247. getDiagnosticString(),
  248. HasSubstr(
  249. "Function declarations must appear before function definitions."));
  250. }
  251. // TODO(umar): Passes but gives incorrect error message. Should be fixed after
  252. // type checking
  253. TEST_F(ValidateLayout, LabelBeforeFunctionParameterBad) {
  254. char str[] = R"(
  255. OpCapability Shader
  256. OpMemoryModel Logical GLSL450
  257. OpDecorate %var Restrict
  258. %intt = OpTypeInt 32 1
  259. %voidt = OpTypeVoid
  260. %vfunct = OpTypeFunction %voidt
  261. %vifunct = OpTypeFunction %voidt %intt
  262. %ptrt = OpTypePointer Function %intt
  263. %func = OpFunction %voidt None %vifunct
  264. %funcl = OpLabel ; Label appears before function parameter
  265. %func2p = OpFunctionParameter %intt
  266. OpNop
  267. OpReturn
  268. OpFunctionEnd
  269. )";
  270. CompileSuccessfully(str);
  271. ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions());
  272. EXPECT_THAT(getDiagnosticString(),
  273. HasSubstr("Function parameters must only appear immediately "
  274. "after the function definition"));
  275. }
  276. TEST_F(ValidateLayout, FuncParameterNotImmediatlyAfterFuncBad) {
  277. char str[] = R"(
  278. OpCapability Shader
  279. OpMemoryModel Logical GLSL450
  280. OpDecorate %var Restrict
  281. %intt = OpTypeInt 32 1
  282. %voidt = OpTypeVoid
  283. %vfunct = OpTypeFunction %voidt
  284. %vifunct = OpTypeFunction %voidt %intt
  285. %ptrt = OpTypePointer Function %intt
  286. %func = OpFunction %voidt None %vifunct
  287. %funcl = OpLabel
  288. OpNop
  289. OpBranch %next
  290. %func2p = OpFunctionParameter %intt ;FunctionParameter appears in a function but not immediately afterwards
  291. %next = OpLabel
  292. OpNop
  293. OpReturn
  294. OpFunctionEnd
  295. )";
  296. CompileSuccessfully(str);
  297. ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions());
  298. EXPECT_THAT(getDiagnosticString(),
  299. HasSubstr("Function parameters must only appear immediately "
  300. "after the function definition"));
  301. }
  302. TEST_F(ValidateLayout, OpUndefCanAppearInTypeDeclarationSection) {
  303. std::string str = R"(
  304. OpCapability Kernel
  305. OpCapability Linkage
  306. OpMemoryModel Logical OpenCL
  307. %voidt = OpTypeVoid
  308. %uintt = OpTypeInt 32 0
  309. %funct = OpTypeFunction %voidt
  310. %udef = OpUndef %uintt
  311. %func = OpFunction %voidt None %funct
  312. %entry = OpLabel
  313. OpReturn
  314. OpFunctionEnd
  315. )";
  316. CompileSuccessfully(str);
  317. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  318. }
  319. TEST_F(ValidateLayout, OpUndefCanAppearInBlock) {
  320. std::string str = R"(
  321. OpCapability Kernel
  322. OpCapability Linkage
  323. OpMemoryModel Logical OpenCL
  324. %voidt = OpTypeVoid
  325. %uintt = OpTypeInt 32 0
  326. %funct = OpTypeFunction %voidt
  327. %func = OpFunction %voidt None %funct
  328. %entry = OpLabel
  329. %udef = OpUndef %uintt
  330. OpReturn
  331. OpFunctionEnd
  332. )";
  333. CompileSuccessfully(str);
  334. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  335. }
  336. TEST_F(ValidateLayout, MissingFunctionEndForFunctionWithBody) {
  337. const auto s = R"(
  338. OpCapability Shader
  339. OpCapability Linkage
  340. OpMemoryModel Logical GLSL450
  341. %void = OpTypeVoid
  342. %tf = OpTypeFunction %void
  343. %f = OpFunction %void None %tf
  344. %l = OpLabel
  345. OpReturn
  346. )";
  347. CompileSuccessfully(s);
  348. ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions());
  349. EXPECT_THAT(getDiagnosticString(),
  350. StrEq("Missing OpFunctionEnd at end of module."));
  351. }
  352. TEST_F(ValidateLayout, MissingFunctionEndForFunctionPrototype) {
  353. const auto s = R"(
  354. OpCapability Shader
  355. OpCapability Linkage
  356. OpMemoryModel Logical GLSL450
  357. %void = OpTypeVoid
  358. %tf = OpTypeFunction %void
  359. %f = OpFunction %void None %tf
  360. )";
  361. CompileSuccessfully(s);
  362. ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions());
  363. EXPECT_THAT(getDiagnosticString(),
  364. StrEq("Missing OpFunctionEnd at end of module."));
  365. }
  366. using ValidateOpFunctionParameter = spvtest::ValidateBase<int>;
  367. TEST_F(ValidateOpFunctionParameter, OpLineBetweenParameters) {
  368. const auto s = R"(
  369. OpCapability Shader
  370. OpCapability Linkage
  371. OpMemoryModel Logical GLSL450
  372. %foo_frag = OpString "foo.frag"
  373. %i32 = OpTypeInt 32 1
  374. %tf = OpTypeFunction %i32 %i32 %i32
  375. %c = OpConstant %i32 123
  376. %f = OpFunction %i32 None %tf
  377. OpLine %foo_frag 1 1
  378. %p1 = OpFunctionParameter %i32
  379. OpNoLine
  380. %p2 = OpFunctionParameter %i32
  381. %l = OpLabel
  382. OpReturnValue %c
  383. OpFunctionEnd
  384. )";
  385. CompileSuccessfully(s);
  386. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  387. }
  388. TEST_F(ValidateOpFunctionParameter, TooManyParameters) {
  389. const auto s = R"(
  390. OpCapability Shader
  391. OpCapability Linkage
  392. OpMemoryModel Logical GLSL450
  393. %i32 = OpTypeInt 32 1
  394. %tf = OpTypeFunction %i32 %i32 %i32
  395. %c = OpConstant %i32 123
  396. %f = OpFunction %i32 None %tf
  397. %p1 = OpFunctionParameter %i32
  398. %p2 = OpFunctionParameter %i32
  399. %xp3 = OpFunctionParameter %i32
  400. %xp4 = OpFunctionParameter %i32
  401. %xp5 = OpFunctionParameter %i32
  402. %xp6 = OpFunctionParameter %i32
  403. %xp7 = OpFunctionParameter %i32
  404. %l = OpLabel
  405. OpReturnValue %c
  406. OpFunctionEnd
  407. )";
  408. CompileSuccessfully(s);
  409. ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  410. }
  411. using ValidateEntryPoint = spvtest::ValidateBase<bool>;
  412. // Tests that not having OpEntryPoint causes an error.
  413. TEST_F(ValidateEntryPoint, NoEntryPointBad) {
  414. std::string spirv = R"(
  415. OpCapability Shader
  416. OpMemoryModel Logical GLSL450)";
  417. CompileSuccessfully(spirv);
  418. EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
  419. EXPECT_THAT(getDiagnosticString(),
  420. HasSubstr("No OpEntryPoint instruction was found. This is only "
  421. "allowed if the Linkage capability is being used."));
  422. }
  423. // Invalid. A function may not be a target of both OpEntryPoint and
  424. // OpFunctionCall.
  425. TEST_F(ValidateEntryPoint, FunctionIsTargetOfEntryPointAndFunctionCallBad) {
  426. std::string spirv = R"(
  427. OpCapability Shader
  428. OpMemoryModel Logical GLSL450
  429. OpEntryPoint Fragment %foo "foo"
  430. OpExecutionMode %foo OriginUpperLeft
  431. %voidt = OpTypeVoid
  432. %funct = OpTypeFunction %voidt
  433. %foo = OpFunction %voidt None %funct
  434. %entry = OpLabel
  435. %recurse = OpFunctionCall %voidt %foo
  436. OpReturn
  437. OpFunctionEnd
  438. )";
  439. CompileSuccessfully(spirv);
  440. EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
  441. EXPECT_THAT(
  442. getDiagnosticString(),
  443. HasSubstr("A function (1) may not be targeted by both an OpEntryPoint "
  444. "instruction and an OpFunctionCall instruction."));
  445. }
  446. // Invalid. Must be within a function to make a function call.
  447. TEST_F(ValidateEntryPoint, FunctionCallOutsideFunctionBody) {
  448. std::string spirv = R"(
  449. OpCapability Shader
  450. %1 = OpExtInstImport "GLSL.std.450"
  451. OpMemoryModel Logical GLSL450
  452. OpName %variableName "variableName"
  453. %34 = OpFunctionCall %variableName %1
  454. )";
  455. CompileSuccessfully(spirv);
  456. EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions());
  457. EXPECT_THAT(getDiagnosticString(),
  458. HasSubstr("FunctionCall must happen within a function body."));
  459. }
  460. // Valid. Module with a function but no entry point is valid when Linkage
  461. // Capability is used.
  462. TEST_F(ValidateEntryPoint, NoEntryPointWithLinkageCapGood) {
  463. std::string spirv = R"(
  464. OpCapability Shader
  465. OpCapability Linkage
  466. OpMemoryModel Logical GLSL450
  467. %voidt = OpTypeVoid
  468. %funct = OpTypeFunction %voidt
  469. %foo = OpFunction %voidt None %funct
  470. %entry = OpLabel
  471. OpReturn
  472. OpFunctionEnd
  473. )";
  474. CompileSuccessfully(spirv);
  475. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  476. }
  477. TEST_F(ValidateLayout, ModuleProcessedInvalidIn10) {
  478. char str[] = R"(
  479. OpCapability Shader
  480. OpCapability Linkage
  481. OpMemoryModel Logical GLSL450
  482. OpName %void "void"
  483. OpModuleProcessed "this is ok in 1.1 and later"
  484. %void = OpTypeVoid
  485. )";
  486. CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1);
  487. ASSERT_EQ(SPV_ERROR_WRONG_VERSION,
  488. ValidateInstructions(SPV_ENV_UNIVERSAL_1_0));
  489. // In a 1.0 environment the version check fails.
  490. EXPECT_THAT(getDiagnosticString(),
  491. HasSubstr("Invalid SPIR-V binary version 1.1 for target "
  492. "environment SPIR-V 1.0."));
  493. }
  494. TEST_F(ValidateLayout, ModuleProcessedValidIn11) {
  495. char str[] = R"(
  496. OpCapability Shader
  497. OpCapability Linkage
  498. OpMemoryModel Logical GLSL450
  499. OpName %void "void"
  500. OpModuleProcessed "this is ok in 1.1 and later"
  501. %void = OpTypeVoid
  502. )";
  503. CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1);
  504. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
  505. EXPECT_THAT(getDiagnosticString(), Eq(""));
  506. }
  507. TEST_F(ValidateLayout, LayoutOrderMixedUp) {
  508. char str[] = R"(
  509. OpCapability Shader
  510. OpCapability Linkage
  511. OpMemoryModel Logical GLSL450
  512. OpEntryPoint Fragment %fragmentFloat "fragmentFloat"
  513. OpExecutionMode %fragmentFloat OriginUpperLeft
  514. OpEntryPoint Fragment %fragmentUint "fragmentUint"
  515. OpExecutionMode %fragmentUint OriginUpperLeft
  516. )";
  517. CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1);
  518. ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT,
  519. ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
  520. // By the mechanics of the validator, we assume ModuleProcessed is in the
  521. // right spot, but then that OpName is in the wrong spot.
  522. EXPECT_THAT(getDiagnosticString(),
  523. HasSubstr("EntryPoint is in an invalid layout section"));
  524. }
  525. TEST_F(ValidateLayout, ModuleProcessedBeforeLastNameIsTooEarly) {
  526. char str[] = R"(
  527. OpCapability Shader
  528. OpCapability Linkage
  529. OpMemoryModel Logical GLSL450
  530. OpModuleProcessed "this is too early"
  531. OpName %void "void"
  532. %void = OpTypeVoid
  533. )";
  534. CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1);
  535. ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT,
  536. ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
  537. // By the mechanics of the validator, we assume ModuleProcessed is in the
  538. // right spot, but then that OpName is in the wrong spot.
  539. EXPECT_THAT(getDiagnosticString(),
  540. HasSubstr("Name is in an invalid layout section"));
  541. }
  542. TEST_F(ValidateLayout, ModuleProcessedInvalidAfterFirstAnnotation) {
  543. char str[] = R"(
  544. OpCapability Shader
  545. OpCapability Linkage
  546. OpMemoryModel Logical GLSL450
  547. OpDecorate %void Volatile ; this is bogus, but keeps the example short
  548. OpModuleProcessed "this is too late"
  549. %void = OpTypeVoid
  550. )";
  551. CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1);
  552. ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT,
  553. ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
  554. EXPECT_THAT(getDiagnosticString(),
  555. HasSubstr("ModuleProcessed is in an invalid layout section"));
  556. }
  557. TEST_F(ValidateLayout, ModuleProcessedInvalidInFunctionBeforeLabel) {
  558. char str[] = R"(
  559. OpCapability Shader
  560. OpMemoryModel Logical GLSL450
  561. OpEntryPoint GLCompute %main "main"
  562. %void = OpTypeVoid
  563. %voidfn = OpTypeFunction %void
  564. %main = OpFunction %void None %voidfn
  565. OpModuleProcessed "this is too late, in function before label"
  566. %entry = OpLabel
  567. OpReturn
  568. OpFunctionEnd
  569. )";
  570. CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1);
  571. ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT,
  572. ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
  573. EXPECT_THAT(
  574. getDiagnosticString(),
  575. HasSubstr("ModuleProcessed cannot appear in a function declaration"));
  576. }
  577. TEST_F(ValidateLayout, ModuleProcessedInvalidInBasicBlock) {
  578. char str[] = R"(
  579. OpCapability Shader
  580. OpMemoryModel Logical GLSL450
  581. OpEntryPoint GLCompute %main "main"
  582. %void = OpTypeVoid
  583. %voidfn = OpTypeFunction %void
  584. %main = OpFunction %void None %voidfn
  585. %entry = OpLabel
  586. OpModuleProcessed "this is too late, in basic block"
  587. OpReturn
  588. OpFunctionEnd
  589. )";
  590. CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1);
  591. ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT,
  592. ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
  593. EXPECT_THAT(
  594. getDiagnosticString(),
  595. HasSubstr("ModuleProcessed cannot appear in a function declaration"));
  596. }
  597. // TODO(umar): Test optional instructions
  598. TEST_F(ValidateLayout, ValidNVBindlessTexturelayout) {
  599. std::string str = R"(
  600. OpCapability Shader
  601. OpCapability BindlessTextureNV
  602. OpExtension "SPV_NV_bindless_texture"
  603. OpMemoryModel Logical GLSL450
  604. OpSamplerImageAddressingModeNV 64
  605. OpEntryPoint GLCompute %func "main"
  606. %voidt = OpTypeVoid
  607. %uintt = OpTypeInt 32 0
  608. %funct = OpTypeFunction %voidt
  609. %func = OpFunction %voidt None %funct
  610. %entry = OpLabel
  611. %udef = OpUndef %uintt
  612. OpReturn
  613. OpFunctionEnd
  614. )";
  615. CompileSuccessfully(str);
  616. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  617. }
  618. TEST_F(ValidateLayout, InvalidValidNVBindlessTexturelayout) {
  619. std::string str = R"(
  620. OpCapability Shader
  621. OpCapability BindlessTextureNV
  622. OpExtension "SPV_NV_bindless_texture"
  623. OpMemoryModel Logical GLSL450
  624. OpEntryPoint GLCompute %func "main"
  625. OpSamplerImageAddressingModeNV 64
  626. %voidt = OpTypeVoid
  627. %uintt = OpTypeInt 32 0
  628. %funct = OpTypeFunction %voidt
  629. %func = OpFunction %voidt None %funct
  630. %entry = OpLabel
  631. %udef = OpUndef %uintt
  632. OpReturn
  633. OpFunctionEnd
  634. )";
  635. CompileSuccessfully(str);
  636. ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT,
  637. ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
  638. EXPECT_THAT(
  639. getDiagnosticString(),
  640. HasSubstr(
  641. "SamplerImageAddressingModeNV is in an invalid layout section"));
  642. }
  643. TEST_F(ValidateLayout, MissingNVBindlessAddressModeFromLayout) {
  644. std::string str = R"(
  645. OpCapability Shader
  646. OpCapability BindlessTextureNV
  647. OpExtension "SPV_NV_bindless_texture"
  648. OpMemoryModel Logical GLSL450
  649. OpEntryPoint GLCompute %func "main"
  650. %voidt = OpTypeVoid
  651. %uintt = OpTypeInt 32 0
  652. %funct = OpTypeFunction %voidt
  653. %func = OpFunction %voidt None %funct
  654. %entry = OpLabel
  655. %udef = OpUndef %uintt
  656. OpReturn
  657. OpFunctionEnd
  658. )";
  659. CompileSuccessfully(str);
  660. ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT,
  661. ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
  662. EXPECT_THAT(
  663. getDiagnosticString(),
  664. HasSubstr("Missing required OpSamplerImageAddressingModeNV instruction"));
  665. }
  666. TEST_F(ValidateLayout, NVBindlessAddressModeFromLayoutSpecifiedTwice) {
  667. std::string str = R"(
  668. OpCapability Shader
  669. OpCapability BindlessTextureNV
  670. OpExtension "SPV_NV_bindless_texture"
  671. OpMemoryModel Logical GLSL450
  672. OpSamplerImageAddressingModeNV 64
  673. OpSamplerImageAddressingModeNV 64
  674. )";
  675. CompileSuccessfully(str);
  676. ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT,
  677. ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
  678. EXPECT_THAT(
  679. getDiagnosticString(),
  680. HasSubstr("OpSamplerImageAddressingModeNV should only be provided once"));
  681. }
  682. } // namespace
  683. } // namespace val
  684. } // namespace spvtools