val_layout_test.cpp 27 KB

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