1 // Copyright 2020 The Tint Authors.
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 "gmock/gmock.h"
16 #include "src/reader/spirv/function.h"
17 #include "src/reader/spirv/parser_impl_test_helper.h"
18 #include "src/reader/spirv/spirv_tools_helpers_test.h"
19
20 namespace tint {
21 namespace reader {
22 namespace spirv {
23 namespace {
24
25 using ::testing::Eq;
26 using ::testing::HasSubstr;
27
Preamble()28 std::string Preamble() {
29 return R"(
30 OpCapability Shader
31 OpMemoryModel Logical Simple
32 OpEntryPoint Fragment %100 "x_100"
33 OpExecutionMode %100 OriginUpperLeft
34 )";
35 }
36
TEST_F(SpvParserTest,EmitStatement_VoidCallNoParams)37 TEST_F(SpvParserTest, EmitStatement_VoidCallNoParams) {
38 auto p = parser(test::Assemble(Preamble() + R"(
39 %void = OpTypeVoid
40 %voidfn = OpTypeFunction %void
41
42 %50 = OpFunction %void None %voidfn
43 %entry_50 = OpLabel
44 OpReturn
45 OpFunctionEnd
46
47 %100 = OpFunction %void None %voidfn
48 %entry = OpLabel
49 %1 = OpFunctionCall %void %50
50 OpReturn
51 OpFunctionEnd
52 )"));
53 ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error();
54 const auto got = test::ToString(p->program());
55 const char* expect = R"(fn x_50() {
56 return;
57 }
58
59 fn x_100_1() {
60 x_50();
61 return;
62 }
63
64 [[stage(fragment)]]
65 fn x_100() {
66 x_100_1();
67 }
68 )";
69 EXPECT_EQ(expect, got);
70 }
71
TEST_F(SpvParserTest,EmitStatement_ScalarCallNoParams)72 TEST_F(SpvParserTest, EmitStatement_ScalarCallNoParams) {
73 auto p = parser(test::Assemble(Preamble() + R"(
74 %void = OpTypeVoid
75 %voidfn = OpTypeFunction %void
76 %uint = OpTypeInt 32 0
77 %uintfn = OpTypeFunction %uint
78 %val = OpConstant %uint 42
79
80 %50 = OpFunction %uint None %uintfn
81 %entry_50 = OpLabel
82 OpReturnValue %val
83 OpFunctionEnd
84
85 %100 = OpFunction %void None %voidfn
86 %entry = OpLabel
87 %1 = OpFunctionCall %uint %50
88 OpReturn
89 OpFunctionEnd
90 )"));
91 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
92 ast::StatementList f100;
93 {
94 auto fe = p->function_emitter(100);
95 EXPECT_TRUE(fe.EmitBody()) << p->error();
96 f100 = fe.ast_body();
97 }
98 ast::StatementList f50;
99 {
100 auto fe = p->function_emitter(50);
101 EXPECT_TRUE(fe.EmitBody()) << p->error();
102 f50 = fe.ast_body();
103 }
104 auto program = p->program();
105 EXPECT_THAT(test::ToString(program, f100),
106 HasSubstr("let x_1 : u32 = x_50();\nreturn;"));
107 EXPECT_THAT(test::ToString(program, f50), HasSubstr("return 42u;"));
108 }
109
TEST_F(SpvParserTest,EmitStatement_ScalarCallNoParamsUsedTwice)110 TEST_F(SpvParserTest, EmitStatement_ScalarCallNoParamsUsedTwice) {
111 auto p = parser(test::Assemble(Preamble() + R"(
112 %void = OpTypeVoid
113 %voidfn = OpTypeFunction %void
114 %uint = OpTypeInt 32 0
115 %uintfn = OpTypeFunction %uint
116 %val = OpConstant %uint 42
117 %ptr_uint = OpTypePointer Function %uint
118
119 %50 = OpFunction %uint None %uintfn
120 %entry_50 = OpLabel
121 OpReturnValue %val
122 OpFunctionEnd
123
124 %100 = OpFunction %void None %voidfn
125 %entry = OpLabel
126 %10 = OpVariable %ptr_uint Function
127 %1 = OpFunctionCall %uint %50
128 OpStore %10 %1
129 OpStore %10 %1
130 OpReturn
131 OpFunctionEnd
132 )"));
133 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
134 ast::StatementList f100;
135 {
136 auto fe = p->function_emitter(100);
137 EXPECT_TRUE(fe.EmitBody()) << p->error();
138 f100 = fe.ast_body();
139 }
140 ast::StatementList f50;
141 {
142 auto fe = p->function_emitter(50);
143 EXPECT_TRUE(fe.EmitBody()) << p->error();
144 f50 = fe.ast_body();
145 }
146 auto program = p->program();
147 EXPECT_EQ(test::ToString(program, f100), R"(var x_10 : u32;
148 let x_1 : u32 = x_50();
149 x_10 = x_1;
150 x_10 = x_1;
151 return;
152 )");
153 EXPECT_THAT(test::ToString(program, f50), HasSubstr("return 42u;"));
154 }
155
TEST_F(SpvParserTest,EmitStatement_CallWithParams)156 TEST_F(SpvParserTest, EmitStatement_CallWithParams) {
157 auto p = parser(test::Assemble(Preamble() + R"(
158 %void = OpTypeVoid
159 %voidfn = OpTypeFunction %void
160 %uint = OpTypeInt 32 0
161 %uintfn_uint_uint = OpTypeFunction %uint %uint %uint
162 %val = OpConstant %uint 42
163 %val2 = OpConstant %uint 84
164
165 %50 = OpFunction %uint None %uintfn_uint_uint
166 %51 = OpFunctionParameter %uint
167 %52 = OpFunctionParameter %uint
168 %entry_50 = OpLabel
169 %sum = OpIAdd %uint %51 %52
170 OpReturnValue %sum
171 OpFunctionEnd
172
173 %100 = OpFunction %void None %voidfn
174 %entry = OpLabel
175 %1 = OpFunctionCall %uint %50 %val %val2
176 OpReturn
177 OpFunctionEnd
178 )"));
179 ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error();
180 EXPECT_TRUE(p->error().empty());
181 const auto program_ast_str = test::ToString(p->program());
182 const std::string expected = R"(fn x_50(x_51 : u32, x_52 : u32) -> u32 {
183 return (x_51 + x_52);
184 }
185
186 fn x_100_1() {
187 let x_1 : u32 = x_50(42u, 84u);
188 return;
189 }
190
191 [[stage(fragment)]]
192 fn x_100() {
193 x_100_1();
194 }
195 )";
196 EXPECT_EQ(program_ast_str, expected);
197 }
198
199 } // namespace
200 } // namespace spirv
201 } // namespace reader
202 } // namespace tint
203