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 <memory>
16 #include <sstream>
17 #include <string>
18 #include <vector>
19 
20 #include "function_utils.h"
21 #include "gmock/gmock.h"
22 #include "gtest/gtest.h"
23 #include "source/opt/build_module.h"
24 #include "source/opt/ir_context.h"
25 
26 namespace spvtools {
27 namespace opt {
28 namespace {
29 
30 using ::testing::Eq;
31 
TEST(FunctionTest,IsNotRecursive)32 TEST(FunctionTest, IsNotRecursive) {
33   const std::string text = R"(
34 OpCapability Shader
35 OpMemoryModel Logical GLSL450
36 OpEntryPoint Fragment %1 "main"
37 OpExecutionMode %1 OriginUpperLeft
38 OpDecorate %2 DescriptorSet 439418829
39 %void = OpTypeVoid
40 %4 = OpTypeFunction %void
41 %float = OpTypeFloat 32
42 %_struct_6 = OpTypeStruct %float %float
43 %7 = OpTypeFunction %_struct_6
44 %1 = OpFunction %void Pure|Const %4
45 %8 = OpLabel
46 %2 = OpFunctionCall %_struct_6 %9
47 OpKill
48 OpFunctionEnd
49 %9 = OpFunction %_struct_6 None %7
50 %10 = OpLabel
51 %11 = OpFunctionCall %_struct_6 %12
52 OpUnreachable
53 OpFunctionEnd
54 %12 = OpFunction %_struct_6 None %7
55 %13 = OpLabel
56 OpUnreachable
57 OpFunctionEnd
58 )";
59 
60   std::unique_ptr<IRContext> ctx =
61       spvtools::BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
62                             SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
63   auto* func = spvtest::GetFunction(ctx->module(), 9);
64   EXPECT_FALSE(func->IsRecursive());
65 
66   func = spvtest::GetFunction(ctx->module(), 12);
67   EXPECT_FALSE(func->IsRecursive());
68 }
69 
TEST(FunctionTest,IsDirectlyRecursive)70 TEST(FunctionTest, IsDirectlyRecursive) {
71   const std::string text = R"(
72 OpCapability Shader
73 OpMemoryModel Logical GLSL450
74 OpEntryPoint Fragment %1 "main"
75 OpExecutionMode %1 OriginUpperLeft
76 OpDecorate %2 DescriptorSet 439418829
77 %void = OpTypeVoid
78 %4 = OpTypeFunction %void
79 %float = OpTypeFloat 32
80 %_struct_6 = OpTypeStruct %float %float
81 %7 = OpTypeFunction %_struct_6
82 %1 = OpFunction %void Pure|Const %4
83 %8 = OpLabel
84 %2 = OpFunctionCall %_struct_6 %9
85 OpKill
86 OpFunctionEnd
87 %9 = OpFunction %_struct_6 None %7
88 %10 = OpLabel
89 %11 = OpFunctionCall %_struct_6 %9
90 OpUnreachable
91 OpFunctionEnd
92 )";
93 
94   std::unique_ptr<IRContext> ctx =
95       spvtools::BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
96                             SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
97   auto* func = spvtest::GetFunction(ctx->module(), 9);
98   EXPECT_TRUE(func->IsRecursive());
99 }
100 
TEST(FunctionTest,IsIndirectlyRecursive)101 TEST(FunctionTest, IsIndirectlyRecursive) {
102   const std::string text = R"(
103 OpCapability Shader
104 OpMemoryModel Logical GLSL450
105 OpEntryPoint Fragment %1 "main"
106 OpExecutionMode %1 OriginUpperLeft
107 OpDecorate %2 DescriptorSet 439418829
108 %void = OpTypeVoid
109 %4 = OpTypeFunction %void
110 %float = OpTypeFloat 32
111 %_struct_6 = OpTypeStruct %float %float
112 %7 = OpTypeFunction %_struct_6
113 %1 = OpFunction %void Pure|Const %4
114 %8 = OpLabel
115 %2 = OpFunctionCall %_struct_6 %9
116 OpKill
117 OpFunctionEnd
118 %9 = OpFunction %_struct_6 None %7
119 %10 = OpLabel
120 %11 = OpFunctionCall %_struct_6 %12
121 OpUnreachable
122 OpFunctionEnd
123 %12 = OpFunction %_struct_6 None %7
124 %13 = OpLabel
125 %14 = OpFunctionCall %_struct_6 %9
126 OpUnreachable
127 OpFunctionEnd
128 )";
129 
130   std::unique_ptr<IRContext> ctx =
131       spvtools::BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
132                             SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
133   auto* func = spvtest::GetFunction(ctx->module(), 9);
134   EXPECT_TRUE(func->IsRecursive());
135 
136   func = spvtest::GetFunction(ctx->module(), 12);
137   EXPECT_TRUE(func->IsRecursive());
138 }
139 
TEST(FunctionTest,IsNotRecuriseCallingRecursive)140 TEST(FunctionTest, IsNotRecuriseCallingRecursive) {
141   const std::string text = R"(
142 OpCapability Shader
143 OpMemoryModel Logical GLSL450
144 OpEntryPoint Fragment %1 "main"
145 OpExecutionMode %1 OriginUpperLeft
146 OpDecorate %2 DescriptorSet 439418829
147 %void = OpTypeVoid
148 %4 = OpTypeFunction %void
149 %float = OpTypeFloat 32
150 %_struct_6 = OpTypeStruct %float %float
151 %7 = OpTypeFunction %_struct_6
152 %1 = OpFunction %void Pure|Const %4
153 %8 = OpLabel
154 %2 = OpFunctionCall %_struct_6 %9
155 OpKill
156 OpFunctionEnd
157 %9 = OpFunction %_struct_6 None %7
158 %10 = OpLabel
159 %11 = OpFunctionCall %_struct_6 %9
160 OpUnreachable
161 OpFunctionEnd
162 )";
163 
164   std::unique_ptr<IRContext> ctx =
165       spvtools::BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
166                             SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
167   auto* func = spvtest::GetFunction(ctx->module(), 1);
168   EXPECT_FALSE(func->IsRecursive());
169 }
170 
171 }  // namespace
172 }  // namespace opt
173 }  // namespace spvtools
174