1 // Copyright (c) 2018 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 
15 #include <string>
16 
17 #include "gmock/gmock.h"
18 #include "test/unit_spirv.h"
19 #include "test/val/val_fixtures.h"
20 
21 namespace spvtools {
22 namespace val {
23 namespace {
24 
25 using ::testing::HasSubstr;
26 
27 using ValidateInterfacesTest = spvtest::ValidateBase<bool>;
28 
TEST_F(ValidateInterfacesTest,EntryPointMissingInput)29 TEST_F(ValidateInterfacesTest, EntryPointMissingInput) {
30   std::string text = R"(
31 OpCapability Shader
32 OpMemoryModel Logical GLSL450
33 OpEntryPoint Fragment %1 "func"
34 OpExecutionMode %1 OriginUpperLeft
35 %2 = OpTypeVoid
36 %3 = OpTypeInt 32 0
37 %4 = OpTypePointer Input %3
38 %5 = OpVariable %4 Input
39 %6 = OpTypeFunction %2
40 %1 = OpFunction %2 None %6
41 %7 = OpLabel
42 %8 = OpLoad %3 %5
43 OpReturn
44 OpFunctionEnd
45 )";
46 
47   CompileSuccessfully(text);
48   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
49   EXPECT_THAT(
50       getDiagnosticString(),
51       HasSubstr("Input variable id <5> is used by entry point 'func' id <1>, "
52                 "but is not listed as an interface"));
53 }
54 
TEST_F(ValidateInterfacesTest,EntryPointMissingOutput)55 TEST_F(ValidateInterfacesTest, EntryPointMissingOutput) {
56   std::string text = R"(
57 OpCapability Shader
58 OpMemoryModel Logical GLSL450
59 OpEntryPoint Fragment %1 "func"
60 OpExecutionMode %1 OriginUpperLeft
61 %2 = OpTypeVoid
62 %3 = OpTypeInt 32 0
63 %4 = OpTypePointer Output %3
64 %5 = OpVariable %4 Output
65 %6 = OpTypeFunction %2
66 %1 = OpFunction %2 None %6
67 %7 = OpLabel
68 %8 = OpLoad %3 %5
69 OpReturn
70 OpFunctionEnd
71 )";
72 
73   CompileSuccessfully(text);
74   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
75   EXPECT_THAT(
76       getDiagnosticString(),
77       HasSubstr("Output variable id <5> is used by entry point 'func' id <1>, "
78                 "but is not listed as an interface"));
79 }
80 
TEST_F(ValidateInterfacesTest,InterfaceMissingUseInSubfunction)81 TEST_F(ValidateInterfacesTest, InterfaceMissingUseInSubfunction) {
82   std::string text = R"(
83 OpCapability Shader
84 OpMemoryModel Logical GLSL450
85 OpEntryPoint Fragment %1 "func"
86 OpExecutionMode %1 OriginUpperLeft
87 %2 = OpTypeVoid
88 %3 = OpTypeInt 32 0
89 %4 = OpTypePointer Input %3
90 %5 = OpVariable %4 Input
91 %6 = OpTypeFunction %2
92 %1 = OpFunction %2 None %6
93 %7 = OpLabel
94 %8 = OpFunctionCall %2 %9
95 OpReturn
96 OpFunctionEnd
97 %9 = OpFunction %2 None %6
98 %10 = OpLabel
99 %11 = OpLoad %3 %5
100 OpReturn
101 OpFunctionEnd
102 )";
103 
104   CompileSuccessfully(text);
105   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
106   EXPECT_THAT(
107       getDiagnosticString(),
108       HasSubstr("Input variable id <5> is used by entry point 'func' id <1>, "
109                 "but is not listed as an interface"));
110 }
111 
TEST_F(ValidateInterfacesTest,TwoEntryPointsOneFunction)112 TEST_F(ValidateInterfacesTest, TwoEntryPointsOneFunction) {
113   std::string text = R"(
114 OpCapability Shader
115 OpMemoryModel Logical GLSL450
116 OpEntryPoint Fragment %1 "func" %2
117 OpEntryPoint Fragment %1 "func2"
118 OpExecutionMode %1 OriginUpperLeft
119 %3 = OpTypeVoid
120 %4 = OpTypeInt 32 0
121 %5 = OpTypePointer Input %4
122 %2 = OpVariable %5 Input
123 %6 = OpTypeFunction %3
124 %1 = OpFunction %3 None %6
125 %7 = OpLabel
126 %8 = OpLoad %4 %2
127 OpReturn
128 OpFunctionEnd
129 )";
130 
131   CompileSuccessfully(text);
132   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
133   EXPECT_THAT(
134       getDiagnosticString(),
135       HasSubstr("Input variable id <2> is used by entry point 'func2' id <1>, "
136                 "but is not listed as an interface"));
137 }
138 
TEST_F(ValidateInterfacesTest,MissingInterfaceThroughInitializer)139 TEST_F(ValidateInterfacesTest, MissingInterfaceThroughInitializer) {
140   const std::string text = R"(
141 OpCapability Shader
142 OpCapability VariablePointers
143 OpMemoryModel Logical GLSL450
144 OpEntryPoint Fragment %1 "func"
145 OpExecutionMode %1 OriginUpperLeft
146 %2 = OpTypeVoid
147 %3 = OpTypeInt 32 0
148 %4 = OpTypePointer Input %3
149 %5 = OpTypePointer Function %4
150 %6 = OpVariable %4 Input
151 %7 = OpTypeFunction %2
152 %1 = OpFunction %2 None %7
153 %8 = OpLabel
154 %9 = OpVariable %5 Function %6
155 OpReturn
156 OpFunctionEnd
157 )";
158 
159   CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
160   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
161   EXPECT_THAT(
162       getDiagnosticString(),
163       HasSubstr("Input variable id <6> is used by entry point 'func' id <1>, "
164                 "but is not listed as an interface"));
165 }
166 
167 }  // namespace
168 }  // namespace val
169 }  // namespace spvtools
170