1 // Copyright (c) 2019 Valve Corporation
2 // Copyright (c) 2019 LunarG Inc.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 
16 // Convert Relaxed to Half tests
17 
18 #include <string>
19 #include <vector>
20 
21 #include "test/opt/assembly_builder.h"
22 #include "test/opt/pass_fixture.h"
23 #include "test/opt/pass_utils.h"
24 
25 namespace spvtools {
26 namespace opt {
27 namespace {
28 
29 using ConvertToHalfTest = PassTest<::testing::Test>;
30 
TEST_F(ConvertToHalfTest, ConvertToHalfBasic)31 TEST_F(ConvertToHalfTest, ConvertToHalfBasic) {
32   // The resulting SPIR-V was processed with --relax-float-ops.
33   //
34   // clang-format off
35   //
36   // SamplerState       g_sSamp : register(s0);
37   // uniform Texture1D <float4> g_tTex1df4 : register(t0);
38   //
39   // struct PS_INPUT
40   // {
41   //   float Tex0 : TEXCOORD0;
42   // };
43   //
44   // struct PS_OUTPUT
45   // {
46   //   float4 Color : SV_Target0;
47   // };
48   //
49   // cbuffer cbuff{
50   //   float c;
51   // }
52   //
53   // PS_OUTPUT main(PS_INPUT i)
54   // {
55   //   PS_OUTPUT psout;
56   //   psout.Color = g_tTex1df4.Sample(g_sSamp, i.Tex0) * c;
57   //   return psout;
58   // }
59   //
60   // clang-format on
61 
62   const std::string defs_before =
63       R"(OpCapability Shader
64 OpCapability Sampled1D
65 %1 = OpExtInstImport "GLSL.std.450"
66 OpMemoryModel Logical GLSL450
67 OpEntryPoint Fragment %main "main" %i_Tex0 %_entryPointOutput_Color
68 OpExecutionMode %main OriginUpperLeft
69 OpSource HLSL 500
70 OpName %main "main"
71 OpName %g_tTex1df4 "g_tTex1df4"
72 OpName %g_sSamp "g_sSamp"
73 OpName %cbuff "cbuff"
74 OpMemberName %cbuff 0 "c"
75 OpName %_ ""
76 OpName %i_Tex0 "i.Tex0"
77 OpName %_entryPointOutput_Color "@entryPointOutput.Color"
78 OpDecorate %g_tTex1df4 DescriptorSet 0
79 OpDecorate %g_tTex1df4 Binding 0
80 OpDecorate %g_sSamp DescriptorSet 0
81 OpDecorate %g_sSamp Binding 0
82 OpMemberDecorate %cbuff 0 Offset 0
83 OpDecorate %cbuff Block
84 OpDecorate %_ DescriptorSet 0
85 OpDecorate %_ Binding 1
86 OpDecorate %i_Tex0 Location 0
87 OpDecorate %_entryPointOutput_Color Location 0
88 OpDecorate %48 RelaxedPrecision
89 OpDecorate %63 RelaxedPrecision
90 OpDecorate %65 RelaxedPrecision
91 OpDecorate %66 RelaxedPrecision
92 %void = OpTypeVoid
93 %3 = OpTypeFunction %void
94 %float = OpTypeFloat 32
95 %v4float = OpTypeVector %float 4
96 %int = OpTypeInt 32 1
97 %int_0 = OpConstant %int 0
98 %19 = OpTypeImage %float 1D 0 0 0 1 Unknown
99 %_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
100 %g_tTex1df4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
101 %23 = OpTypeSampler
102 %_ptr_UniformConstant_23 = OpTypePointer UniformConstant %23
103 %g_sSamp = OpVariable %_ptr_UniformConstant_23 UniformConstant
104 %27 = OpTypeSampledImage %19
105 %cbuff = OpTypeStruct %float
106 %_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff
107 %_ = OpVariable %_ptr_Uniform_cbuff Uniform
108 %_ptr_Uniform_float = OpTypePointer Uniform %float
109 %_ptr_Input_float = OpTypePointer Input %float
110 %i_Tex0 = OpVariable %_ptr_Input_float Input
111 %_ptr_Output_v4float = OpTypePointer Output %v4float
112 %_entryPointOutput_Color = OpVariable %_ptr_Output_v4float Output
113 )";
114 
115   const std::string defs_after =
116       R"(OpCapability Shader
117 OpCapability Sampled1D
118 OpCapability Float16
119 %1 = OpExtInstImport "GLSL.std.450"
120 OpMemoryModel Logical GLSL450
121 OpEntryPoint Fragment %main "main" %i_Tex0 %_entryPointOutput_Color
122 OpExecutionMode %main OriginUpperLeft
123 OpSource HLSL 500
124 OpName %main "main"
125 OpName %g_tTex1df4 "g_tTex1df4"
126 OpName %g_sSamp "g_sSamp"
127 OpName %cbuff "cbuff"
128 OpMemberName %cbuff 0 "c"
129 OpName %_ ""
130 OpName %i_Tex0 "i.Tex0"
131 OpName %_entryPointOutput_Color "@entryPointOutput.Color"
132 OpDecorate %g_tTex1df4 DescriptorSet 0
133 OpDecorate %g_tTex1df4 Binding 0
134 OpDecorate %g_sSamp DescriptorSet 0
135 OpDecorate %g_sSamp Binding 0
136 OpMemberDecorate %cbuff 0 Offset 0
137 OpDecorate %cbuff Block
138 OpDecorate %_ DescriptorSet 0
139 OpDecorate %_ Binding 1
140 OpDecorate %i_Tex0 Location 0
141 OpDecorate %_entryPointOutput_Color Location 0
142 %void = OpTypeVoid
143 %3 = OpTypeFunction %void
144 %float = OpTypeFloat 32
145 %v4float = OpTypeVector %float 4
146 %int = OpTypeInt 32 1
147 %int_0 = OpConstant %int 0
148 %19 = OpTypeImage %float 1D 0 0 0 1 Unknown
149 %_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
150 %g_tTex1df4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
151 %23 = OpTypeSampler
152 %_ptr_UniformConstant_23 = OpTypePointer UniformConstant %23
153 %g_sSamp = OpVariable %_ptr_UniformConstant_23 UniformConstant
154 %27 = OpTypeSampledImage %19
155 %cbuff = OpTypeStruct %float
156 %_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff
157 %_ = OpVariable %_ptr_Uniform_cbuff Uniform
158 %_ptr_Uniform_float = OpTypePointer Uniform %float
159 %_ptr_Input_float = OpTypePointer Input %float
160 %i_Tex0 = OpVariable %_ptr_Input_float Input
161 %_ptr_Output_v4float = OpTypePointer Output %v4float
162 %_entryPointOutput_Color = OpVariable %_ptr_Output_v4float Output
163 %half = OpTypeFloat 16
164 %v4half = OpTypeVector %half 4
165 )";
166 
167   const std::string func_before =
168       R"(%main = OpFunction %void None %3
169 %5 = OpLabel
170 %48 = OpLoad %float %i_Tex0
171 %58 = OpLoad %19 %g_tTex1df4
172 %59 = OpLoad %23 %g_sSamp
173 %60 = OpSampledImage %27 %58 %59
174 %63 = OpImageSampleImplicitLod %v4float %60 %48
175 %64 = OpAccessChain %_ptr_Uniform_float %_ %int_0
176 %65 = OpLoad %float %64
177 %66 = OpVectorTimesScalar %v4float %63 %65
178 OpStore %_entryPointOutput_Color %66
179 OpReturn
180 OpFunctionEnd
181 )";
182 
183   const std::string func_after =
184       R"(%main = OpFunction %void None %3
185 %5 = OpLabel
186 %48 = OpLoad %float %i_Tex0
187 %58 = OpLoad %19 %g_tTex1df4
188 %59 = OpLoad %23 %g_sSamp
189 %60 = OpSampledImage %27 %58 %59
190 %63 = OpImageSampleImplicitLod %v4float %60 %48
191 %64 = OpAccessChain %_ptr_Uniform_float %_ %int_0
192 %65 = OpLoad %float %64
193 %69 = OpFConvert %v4half %63
194 %70 = OpFConvert %half %65
195 %66 = OpVectorTimesScalar %v4half %69 %70
196 %71 = OpFConvert %v4float %66
197 OpStore %_entryPointOutput_Color %71
198 OpReturn
199 OpFunctionEnd
200 )";
201 
202   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
203   SinglePassRunAndCheck<ConvertToHalfPass>(defs_before + func_before,
204                                            defs_after + func_after, true, true);
205 }
206 
TEST_F(ConvertToHalfTest, ConvertToHalfForLinkage)207 TEST_F(ConvertToHalfTest, ConvertToHalfForLinkage) {
208   const std::string before =
209       R"(OpCapability Shader
210 OpCapability Linkage
211 OpMemoryModel Logical GLSL450
212 OpSource HLSL 630
213 OpName %type_cbuff "type.cbuff"
214 OpMemberName %type_cbuff 0 "c"
215 OpName %cbuff "cbuff"
216 OpName %main "main"
217 OpName %BaseColor "BaseColor"
218 OpName %bb_entry "bb.entry"
219 OpName %v "v"
220 OpDecorate %main LinkageAttributes "main" Export
221 OpDecorate %cbuff DescriptorSet 0
222 OpDecorate %cbuff Binding 0
223 OpMemberDecorate %type_cbuff 0 Offset 0
224 OpDecorate %type_cbuff Block
225 OpDecorate %18 RelaxedPrecision
226 %int = OpTypeInt 32 1
227 %int_0 = OpConstant %int 0
228 %float = OpTypeFloat 32
229 %type_cbuff = OpTypeStruct %float
230 %_ptr_Uniform_type_cbuff = OpTypePointer Uniform %type_cbuff
231 %v4float = OpTypeVector %float 4
232 %_ptr_Function_v4float = OpTypePointer Function %v4float
233 %9 = OpTypeFunction %v4float %_ptr_Function_v4float
234 %_ptr_Uniform_float = OpTypePointer Uniform %float
235 %cbuff = OpVariable %_ptr_Uniform_type_cbuff Uniform
236 %main = OpFunction %v4float None %9
237 %BaseColor = OpFunctionParameter %_ptr_Function_v4float
238 %bb_entry = OpLabel
239 %v = OpVariable %_ptr_Function_v4float Function
240 %14 = OpLoad %v4float %BaseColor
241 %16 = OpAccessChain %_ptr_Uniform_float %cbuff %int_0
242 %17 = OpLoad %float %16
243 %18 = OpVectorTimesScalar %v4float %14 %17
244 OpStore %v %18
245 %19 = OpLoad %v4float %v
246 OpReturnValue %19
247 OpFunctionEnd
248 )";
249 
250   const std::string after =
251       R"(OpCapability Shader
252 OpCapability Linkage
253 OpCapability Float16
254 OpMemoryModel Logical GLSL450
255 OpSource HLSL 630
256 OpName %type_cbuff "type.cbuff"
257 OpMemberName %type_cbuff 0 "c"
258 OpName %cbuff "cbuff"
259 OpName %main "main"
260 OpName %BaseColor "BaseColor"
261 OpName %bb_entry "bb.entry"
262 OpName %v "v"
263 OpDecorate %main LinkageAttributes "main" Export
264 OpDecorate %cbuff DescriptorSet 0
265 OpDecorate %cbuff Binding 0
266 OpMemberDecorate %type_cbuff 0 Offset 0
267 OpDecorate %type_cbuff Block
268 %int = OpTypeInt 32 1
269 %int_0 = OpConstant %int 0
270 %float = OpTypeFloat 32
271 %type_cbuff = OpTypeStruct %float
272 %_ptr_Uniform_type_cbuff = OpTypePointer Uniform %type_cbuff
273 %v4float = OpTypeVector %float 4
274 %_ptr_Function_v4float = OpTypePointer Function %v4float
275 %14 = OpTypeFunction %v4float %_ptr_Function_v4float
276 %_ptr_Uniform_float = OpTypePointer Uniform %float
277 %cbuff = OpVariable %_ptr_Uniform_type_cbuff Uniform
278 %half = OpTypeFloat 16
279 %v4half = OpTypeVector %half 4
280 %main = OpFunction %v4float None %14
281 %BaseColor = OpFunctionParameter %_ptr_Function_v4float
282 %bb_entry = OpLabel
283 %v = OpVariable %_ptr_Function_v4float Function
284 %16 = OpLoad %v4float %BaseColor
285 %17 = OpAccessChain %_ptr_Uniform_float %cbuff %int_0
286 %18 = OpLoad %float %17
287 %22 = OpFConvert %v4half %16
288 %23 = OpFConvert %half %18
289 %7 = OpVectorTimesScalar %v4half %22 %23
290 %24 = OpFConvert %v4float %7
291 OpStore %v %24
292 %19 = OpLoad %v4float %v
293 OpReturnValue %19
294 OpFunctionEnd
295 )";
296 
297   SinglePassRunAndCheck<ConvertToHalfPass>(before, after, true, true);
298 }
TEST_F(ConvertToHalfTest, ConvertToHalfWithDrefSample)299 TEST_F(ConvertToHalfTest, ConvertToHalfWithDrefSample) {
300   // The resulting SPIR-V was processed with --relax-float-ops.
301   //
302   // clang-format off
303   //
304   // SamplerComparisonState       g_sSamp : register(s0);
305   // uniform Texture1D <float4> g_tTex1df4 : register(t0);
306   //
307   // cbuffer cbuff{
308   //   float c1;
309   // float c2;
310   // };
311   //
312   // struct PS_INPUT
313   // {
314   //   float Tex0 : TEXCOORD0;
315   //   float Tex1 : TEXCOORD1;
316   // };
317   //
318   // struct PS_OUTPUT
319   // {
320   //   float Color : SV_Target0;
321   // };
322   //
323   // PS_OUTPUT main(PS_INPUT i)
324   // {
325   //   PS_OUTPUT psout;
326   //   float txval10 = g_tTex1df4.SampleCmp(g_sSamp, i.Tex0 * 0.1, c1 + 0.1);
327   //   float txval11 = g_tTex1df4.SampleCmp(g_sSamp, i.Tex1 * 0.2, c2 + 0.2);
328   //   float t = txval10 + txval11;
329   //   float t2 = t / 2.0;
330   //   psout.Color = t2;
331   //   return psout;
332   // }
333   //
334   // clang-format on
335 
336   const std::string defs_before =
337       R"(OpCapability Shader
338 OpCapability Sampled1D
339 %1 = OpExtInstImport "GLSL.std.450"
340 OpMemoryModel Logical GLSL450
341 OpEntryPoint Fragment %main "main" %i_Tex0 %i_Tex1 %_entryPointOutput_Color
342 OpExecutionMode %main OriginUpperLeft
343 OpSource HLSL 500
344 OpName %main "main"
345 OpName %g_tTex1df4 "g_tTex1df4"
346 OpName %g_sSamp "g_sSamp"
347 OpName %cbuff "cbuff"
348 OpMemberName %cbuff 0 "c1"
349 OpMemberName %cbuff 1 "c2"
350 OpName %_ ""
351 OpName %i_Tex0 "i.Tex0"
352 OpName %i_Tex1 "i.Tex1"
353 OpName %_entryPointOutput_Color "@entryPointOutput.Color"
354 OpDecorate %g_tTex1df4 DescriptorSet 0
355 OpDecorate %g_tTex1df4 Binding 0
356 OpDecorate %g_sSamp DescriptorSet 0
357 OpDecorate %g_sSamp Binding 0
358 OpMemberDecorate %cbuff 0 Offset 0
359 OpMemberDecorate %cbuff 1 Offset 4
360 OpDecorate %cbuff Block
361 OpDecorate %_ DescriptorSet 0
362 OpDecorate %_ Binding 1
363 OpDecorate %i_Tex0 Location 0
364 OpDecorate %i_Tex1 Location 1
365 OpDecorate %_entryPointOutput_Color Location 0
366 OpDecorate %100 RelaxedPrecision
367 OpDecorate %76 RelaxedPrecision
368 OpDecorate %79 RelaxedPrecision
369 OpDecorate %98 RelaxedPrecision
370 OpDecorate %101 RelaxedPrecision
371 OpDecorate %110 RelaxedPrecision
372 OpDecorate %102 RelaxedPrecision
373 OpDecorate %112 RelaxedPrecision
374 OpDecorate %104 RelaxedPrecision
375 OpDecorate %113 RelaxedPrecision
376 OpDecorate %114 RelaxedPrecision
377 OpDecorate %116 RelaxedPrecision
378 OpDecorate %119 RelaxedPrecision
379 OpDecorate %121 RelaxedPrecision
380 %void = OpTypeVoid
381 %3 = OpTypeFunction %void
382 %float = OpTypeFloat 32
383 %16 = OpTypeImage %float 1D 1 0 0 1 Unknown
384 %_ptr_UniformConstant_16 = OpTypePointer UniformConstant %16
385 %g_tTex1df4 = OpVariable %_ptr_UniformConstant_16 UniformConstant
386 %20 = OpTypeSampler
387 %_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20
388 %g_sSamp = OpVariable %_ptr_UniformConstant_20 UniformConstant
389 %24 = OpTypeSampledImage %16
390 %int = OpTypeInt 32 1
391 %int_0 = OpConstant %int 0
392 %float_0_100000001 = OpConstant %float 0.100000001
393 %cbuff = OpTypeStruct %float %float
394 %_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff
395 %_ = OpVariable %_ptr_Uniform_cbuff Uniform
396 %_ptr_Uniform_float = OpTypePointer Uniform %float
397 %v2float = OpTypeVector %float 2
398 %int_1 = OpConstant %int 1
399 %float_0_200000003 = OpConstant %float 0.200000003
400 %_ptr_Input_float = OpTypePointer Input %float
401 %i_Tex0 = OpVariable %_ptr_Input_float Input
402 %i_Tex1 = OpVariable %_ptr_Input_float Input
403 %_ptr_Output_float = OpTypePointer Output %float
404 %_entryPointOutput_Color = OpVariable %_ptr_Output_float Output
405 %float_0_5 = OpConstant %float 0.5
406 )";
407 
408   const std::string defs_after =
409       R"(OpCapability Shader
410 OpCapability Sampled1D
411 OpCapability Float16
412 %1 = OpExtInstImport "GLSL.std.450"
413 OpMemoryModel Logical GLSL450
414 OpEntryPoint Fragment %main "main" %i_Tex0 %i_Tex1 %_entryPointOutput_Color
415 OpExecutionMode %main OriginUpperLeft
416 OpSource HLSL 500
417 OpName %main "main"
418 OpName %g_tTex1df4 "g_tTex1df4"
419 OpName %g_sSamp "g_sSamp"
420 OpName %cbuff "cbuff"
421 OpMemberName %cbuff 0 "c1"
422 OpMemberName %cbuff 1 "c2"
423 OpName %_ ""
424 OpName %i_Tex0 "i.Tex0"
425 OpName %i_Tex1 "i.Tex1"
426 OpName %_entryPointOutput_Color "@entryPointOutput.Color"
427 OpDecorate %g_tTex1df4 DescriptorSet 0
428 OpDecorate %g_tTex1df4 Binding 0
429 OpDecorate %g_sSamp DescriptorSet 0
430 OpDecorate %g_sSamp Binding 0
431 OpMemberDecorate %cbuff 0 Offset 0
432 OpMemberDecorate %cbuff 1 Offset 4
433 OpDecorate %cbuff Block
434 OpDecorate %_ DescriptorSet 0
435 OpDecorate %_ Binding 1
436 OpDecorate %i_Tex0 Location 0
437 OpDecorate %i_Tex1 Location 1
438 OpDecorate %_entryPointOutput_Color Location 0
439 %void = OpTypeVoid
440 %25 = OpTypeFunction %void
441 %float = OpTypeFloat 32
442 %27 = OpTypeImage %float 1D 1 0 0 1 Unknown
443 %_ptr_UniformConstant_27 = OpTypePointer UniformConstant %27
444 %g_tTex1df4 = OpVariable %_ptr_UniformConstant_27 UniformConstant
445 %29 = OpTypeSampler
446 %_ptr_UniformConstant_29 = OpTypePointer UniformConstant %29
447 %g_sSamp = OpVariable %_ptr_UniformConstant_29 UniformConstant
448 %31 = OpTypeSampledImage %27
449 %int = OpTypeInt 32 1
450 %int_0 = OpConstant %int 0
451 %float_0_100000001 = OpConstant %float 0.100000001
452 %cbuff = OpTypeStruct %float %float
453 %_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff
454 %_ = OpVariable %_ptr_Uniform_cbuff Uniform
455 %_ptr_Uniform_float = OpTypePointer Uniform %float
456 %v2float = OpTypeVector %float 2
457 %int_1 = OpConstant %int 1
458 %float_0_200000003 = OpConstant %float 0.200000003
459 %_ptr_Input_float = OpTypePointer Input %float
460 %i_Tex0 = OpVariable %_ptr_Input_float Input
461 %i_Tex1 = OpVariable %_ptr_Input_float Input
462 %_ptr_Output_float = OpTypePointer Output %float
463 %_entryPointOutput_Color = OpVariable %_ptr_Output_float Output
464 %float_0_5 = OpConstant %float 0.5
465 %half = OpTypeFloat 16
466 %v2half = OpTypeVector %half 2
467 )";
468 
469   const std::string func_before =
470       R"(%main = OpFunction %void None %3
471 %5 = OpLabel
472 %76 = OpLoad %float %i_Tex0
473 %79 = OpLoad %float %i_Tex1
474 %93 = OpLoad %16 %g_tTex1df4
475 %94 = OpLoad %20 %g_sSamp
476 %95 = OpSampledImage %24 %93 %94
477 %98 = OpFMul %float %76 %float_0_100000001
478 %99 = OpAccessChain %_ptr_Uniform_float %_ %int_0
479 %100 = OpLoad %float %99
480 %101 = OpFAdd %float %100 %float_0_100000001
481 %102 = OpCompositeConstruct %v2float %98 %101
482 %104 = OpImageSampleDrefImplicitLod %float %95 %102 %101
483 %105 = OpLoad %16 %g_tTex1df4
484 %106 = OpLoad %20 %g_sSamp
485 %107 = OpSampledImage %24 %105 %106
486 %110 = OpFMul %float %79 %float_0_200000003
487 %111 = OpAccessChain %_ptr_Uniform_float %_ %int_1
488 %112 = OpLoad %float %111
489 %113 = OpFAdd %float %112 %float_0_200000003
490 %114 = OpCompositeConstruct %v2float %110 %113
491 %116 = OpImageSampleDrefImplicitLod %float %107 %114 %113
492 %119 = OpFAdd %float %104 %116
493 %121 = OpFMul %float %119 %float_0_5
494 OpStore %_entryPointOutput_Color %121
495 OpReturn
496 OpFunctionEnd
497 )";
498 
499   const std::string func_after =
500       R"(%main = OpFunction %void None %25
501 %43 = OpLabel
502 %11 = OpLoad %float %i_Tex0
503 %12 = OpLoad %float %i_Tex1
504 %44 = OpLoad %27 %g_tTex1df4
505 %45 = OpLoad %29 %g_sSamp
506 %46 = OpSampledImage %31 %44 %45
507 %53 = OpFConvert %half %11
508 %54 = OpFConvert %half %float_0_100000001
509 %13 = OpFMul %half %53 %54
510 %47 = OpAccessChain %_ptr_Uniform_float %_ %int_0
511 %10 = OpLoad %float %47
512 %55 = OpFConvert %half %10
513 %56 = OpFConvert %half %float_0_100000001
514 %14 = OpFAdd %half %55 %56
515 %16 = OpCompositeConstruct %v2half %13 %14
516 %58 = OpFConvert %float %14
517 %18 = OpImageSampleDrefImplicitLod %float %46 %16 %58
518 %48 = OpLoad %27 %g_tTex1df4
519 %49 = OpLoad %29 %g_sSamp
520 %50 = OpSampledImage %31 %48 %49
521 %59 = OpFConvert %half %12
522 %60 = OpFConvert %half %float_0_200000003
523 %15 = OpFMul %half %59 %60
524 %51 = OpAccessChain %_ptr_Uniform_float %_ %int_1
525 %17 = OpLoad %float %51
526 %61 = OpFConvert %half %17
527 %62 = OpFConvert %half %float_0_200000003
528 %19 = OpFAdd %half %61 %62
529 %20 = OpCompositeConstruct %v2half %15 %19
530 %63 = OpFConvert %float %19
531 %21 = OpImageSampleDrefImplicitLod %float %50 %20 %63
532 %64 = OpFConvert %half %18
533 %65 = OpFConvert %half %21
534 %22 = OpFAdd %half %64 %65
535 %66 = OpFConvert %half %float_0_5
536 %23 = OpFMul %half %22 %66
537 %67 = OpFConvert %float %23
538 OpStore %_entryPointOutput_Color %67
539 OpReturn
540 OpFunctionEnd
541 )";
542 
543   SinglePassRunAndCheck<ConvertToHalfPass>(defs_before + func_before,
544                                            defs_after + func_after, true, true);
545 }
546 
TEST_F(ConvertToHalfTest, ConvertToHalfWithVectorMatrixMult)547 TEST_F(ConvertToHalfTest, ConvertToHalfWithVectorMatrixMult) {
548   // The resulting SPIR-V was processed with --relax-float-ops.
549   //
550   // clang-format off
551   //
552   // SamplerState       g_sSamp : register(s0);
553   // uniform Texture1D <float4> g_tTex1df4 : register(t0);
554   //
555   // struct PS_OUTPUT
556   // {
557   //   float4 Color : SV_Target0;
558   // };
559   //
560   // cbuffer cbuff{
561   //   float4x4 M;
562   // }
563   //
564   // PS_OUTPUT main()
565   // {
566   //  PS_OUTPUT psout;
567   //  float4 txval10 = g_tTex1df4.Sample(g_sSamp, 0.1);
568   //  float4 t = mul(txval10, M);
569   //  psout.Color = t;
570   //  return psout;
571   //}
572   //
573   // clang-format on
574 
575   const std::string defs_before =
576       R"(OpCapability Shader
577 OpCapability Sampled1D
578 %1 = OpExtInstImport "GLSL.std.450"
579 OpMemoryModel Logical GLSL450
580 OpEntryPoint Fragment %main "main" %_entryPointOutput_Color
581 OpExecutionMode %main OriginUpperLeft
582 OpSource HLSL 500
583 OpName %main "main"
584 OpName %g_tTex1df4 "g_tTex1df4"
585 OpName %g_sSamp "g_sSamp"
586 OpName %cbuff "cbuff"
587 OpMemberName %cbuff 0 "M"
588 OpName %_ ""
589 OpName %_entryPointOutput_Color "@entryPointOutput.Color"
590 OpDecorate %g_tTex1df4 DescriptorSet 0
591 OpDecorate %g_tTex1df4 Binding 0
592 OpDecorate %g_sSamp DescriptorSet 0
593 OpDecorate %g_sSamp Binding 0
594 OpMemberDecorate %cbuff 0 RowMajor
595 OpMemberDecorate %cbuff 0 Offset 0
596 OpMemberDecorate %cbuff 0 MatrixStride 16
597 OpDecorate %cbuff Block
598 OpDecorate %_ DescriptorSet 0
599 OpDecorate %_ Binding 1
600 OpDecorate %_entryPointOutput_Color Location 0
601 OpDecorate %56 RelaxedPrecision
602 OpDecorate %58 RelaxedPrecision
603 OpDecorate %60 RelaxedPrecision
604 %void = OpTypeVoid
605 %3 = OpTypeFunction %void
606 %float = OpTypeFloat 32
607 %v4float = OpTypeVector %float 4
608 %14 = OpTypeImage %float 1D 0 0 0 1 Unknown
609 %_ptr_UniformConstant_14 = OpTypePointer UniformConstant %14
610 %g_tTex1df4 = OpVariable %_ptr_UniformConstant_14 UniformConstant
611 %18 = OpTypeSampler
612 %_ptr_UniformConstant_18 = OpTypePointer UniformConstant %18
613 %g_sSamp = OpVariable %_ptr_UniformConstant_18 UniformConstant
614 %22 = OpTypeSampledImage %14
615 %float_0_100000001 = OpConstant %float 0.100000001
616 %mat4v4float = OpTypeMatrix %v4float 4
617 %cbuff = OpTypeStruct %mat4v4float
618 %_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff
619 %_ = OpVariable %_ptr_Uniform_cbuff Uniform
620 %int = OpTypeInt 32 1
621 %int_0 = OpConstant %int 0
622 %_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float
623 %_ptr_Output_v4float = OpTypePointer Output %v4float
624 %_entryPointOutput_Color = OpVariable %_ptr_Output_v4float Output
625 )";
626 
627   const std::string defs_after =
628       R"(OpCapability Shader
629 OpCapability Sampled1D
630 OpCapability Float16
631 %1 = OpExtInstImport "GLSL.std.450"
632 OpMemoryModel Logical GLSL450
633 OpEntryPoint Fragment %main "main" %_entryPointOutput_Color
634 OpExecutionMode %main OriginUpperLeft
635 OpSource HLSL 500
636 OpName %main "main"
637 OpName %g_tTex1df4 "g_tTex1df4"
638 OpName %g_sSamp "g_sSamp"
639 OpName %cbuff "cbuff"
640 OpMemberName %cbuff 0 "M"
641 OpName %_ ""
642 OpName %_entryPointOutput_Color "@entryPointOutput.Color"
643 OpDecorate %g_tTex1df4 DescriptorSet 0
644 OpDecorate %g_tTex1df4 Binding 0
645 OpDecorate %g_sSamp DescriptorSet 0
646 OpDecorate %g_sSamp Binding 0
647 OpMemberDecorate %cbuff 0 RowMajor
648 OpMemberDecorate %cbuff 0 Offset 0
649 OpMemberDecorate %cbuff 0 MatrixStride 16
650 OpDecorate %cbuff Block
651 OpDecorate %_ DescriptorSet 0
652 OpDecorate %_ Binding 1
653 OpDecorate %_entryPointOutput_Color Location 0
654 %void = OpTypeVoid
655 %3 = OpTypeFunction %void
656 %float = OpTypeFloat 32
657 %v4float = OpTypeVector %float 4
658 %14 = OpTypeImage %float 1D 0 0 0 1 Unknown
659 %_ptr_UniformConstant_14 = OpTypePointer UniformConstant %14
660 %g_tTex1df4 = OpVariable %_ptr_UniformConstant_14 UniformConstant
661 %18 = OpTypeSampler
662 %_ptr_UniformConstant_18 = OpTypePointer UniformConstant %18
663 %g_sSamp = OpVariable %_ptr_UniformConstant_18 UniformConstant
664 %22 = OpTypeSampledImage %14
665 %float_0_100000001 = OpConstant %float 0.100000001
666 %mat4v4float = OpTypeMatrix %v4float 4
667 %cbuff = OpTypeStruct %mat4v4float
668 %_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff
669 %_ = OpVariable %_ptr_Uniform_cbuff Uniform
670 %int = OpTypeInt 32 1
671 %int_0 = OpConstant %int 0
672 %_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float
673 %_ptr_Output_v4float = OpTypePointer Output %v4float
674 %_entryPointOutput_Color = OpVariable %_ptr_Output_v4float Output
675 %half = OpTypeFloat 16
676 %v4half = OpTypeVector %half 4
677 %mat4v4half = OpTypeMatrix %v4half 4
678 )";
679 
680   const std::string func_before =
681       R"(%main = OpFunction %void None %3
682 %5 = OpLabel
683 %53 = OpLoad %14 %g_tTex1df4
684 %54 = OpLoad %18 %g_sSamp
685 %55 = OpSampledImage %22 %53 %54
686 %56 = OpImageSampleImplicitLod %v4float %55 %float_0_100000001
687 %57 = OpAccessChain %_ptr_Uniform_mat4v4float %_ %int_0
688 %58 = OpLoad %mat4v4float %57
689 %60 = OpMatrixTimesVector %v4float %58 %56
690 OpStore %_entryPointOutput_Color %60
691 OpReturn
692 OpFunctionEnd
693 )";
694 
695   const std::string func_after =
696       R"(%main = OpFunction %void None %3
697 %5 = OpLabel
698 %53 = OpLoad %14 %g_tTex1df4
699 %54 = OpLoad %18 %g_sSamp
700 %55 = OpSampledImage %22 %53 %54
701 %56 = OpImageSampleImplicitLod %v4float %55 %float_0_100000001
702 %57 = OpAccessChain %_ptr_Uniform_mat4v4float %_ %int_0
703 %58 = OpLoad %mat4v4float %57
704 %67 = OpCompositeExtract %v4float %58 0
705 %68 = OpFConvert %v4half %67
706 %69 = OpCompositeExtract %v4float %58 1
707 %70 = OpFConvert %v4half %69
708 %71 = OpCompositeExtract %v4float %58 2
709 %72 = OpFConvert %v4half %71
710 %73 = OpCompositeExtract %v4float %58 3
711 %74 = OpFConvert %v4half %73
712 %75 = OpCompositeConstruct %mat4v4half %68 %70 %72 %74
713 %64 = OpCopyObject %mat4v4float %58
714 %65 = OpFConvert %v4half %56
715 %60 = OpMatrixTimesVector %v4half %75 %65
716 %66 = OpFConvert %v4float %60
717 OpStore %_entryPointOutput_Color %66
718 OpReturn
719 OpFunctionEnd
720 )";
721 
722   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
723   SinglePassRunAndCheck<ConvertToHalfPass>(defs_before + func_before,
724                                            defs_after + func_after, true, true);
725 }
726 
TEST_F(ConvertToHalfTest, ConvertToHalfWithPhi)727 TEST_F(ConvertToHalfTest, ConvertToHalfWithPhi) {
728   // The resulting SPIR-V was processed with --relax-float-ops.
729   //
730   // clang-format off
731   //
732   // SamplerState       g_sSamp : register(s0);
733   // uniform Texture1D <float4> g_tTex1df4 : register(t0);
734   //
735   // struct PS_OUTPUT
736   // {
737   //   float4 Color : SV_Target0;
738   // };
739   //
740   // cbuffer cbuff{
741   //   bool b;
742   //   float4x4 M;
743   // }
744   //
745   // PS_OUTPUT main()
746   // {
747   //   PS_OUTPUT psout;
748   //   float4 t;
749   //
750   //   if (b)
751   //     t = g_tTex1df4.Sample(g_sSamp, 0.1);
752   //   else
753   //     t = float4(0.0, 0.0, 0.0, 0.0);
754   //
755   //   float4 t2 = t * 2.0;
756   //   psout.Color = t2;
757   //   return psout;
758   // }
759   //
760   // clang-format on
761 
762   const std::string defs_before =
763       R"(OpCapability Shader
764 OpCapability Sampled1D
765 %1 = OpExtInstImport "GLSL.std.450"
766 OpMemoryModel Logical GLSL450
767 OpEntryPoint Fragment %main "main" %_entryPointOutput_Color
768 OpExecutionMode %main OriginUpperLeft
769 OpSource HLSL 500
770 OpName %main "main"
771 OpName %cbuff "cbuff"
772 OpMemberName %cbuff 0 "b"
773 OpMemberName %cbuff 1 "M"
774 OpName %_ ""
775 OpName %g_tTex1df4 "g_tTex1df4"
776 OpName %g_sSamp "g_sSamp"
777 OpName %_entryPointOutput_Color "@entryPointOutput.Color"
778 OpMemberDecorate %cbuff 0 Offset 0
779 OpMemberDecorate %cbuff 1 RowMajor
780 OpMemberDecorate %cbuff 1 Offset 16
781 OpMemberDecorate %cbuff 1 MatrixStride 16
782 OpDecorate %cbuff Block
783 OpDecorate %_ DescriptorSet 0
784 OpDecorate %_ Binding 1
785 OpDecorate %g_tTex1df4 DescriptorSet 0
786 OpDecorate %g_tTex1df4 Binding 0
787 OpDecorate %g_sSamp DescriptorSet 0
788 OpDecorate %g_sSamp Binding 0
789 OpDecorate %_entryPointOutput_Color Location 0
790 OpDecorate %72 RelaxedPrecision
791 OpDecorate %85 RelaxedPrecision
792 OpDecorate %74 RelaxedPrecision
793 %void = OpTypeVoid
794 %3 = OpTypeFunction %void
795 %float = OpTypeFloat 32
796 %v4float = OpTypeVector %float 4
797 %uint = OpTypeInt 32 0
798 %mat4v4float = OpTypeMatrix %v4float 4
799 %cbuff = OpTypeStruct %uint %mat4v4float
800 %_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff
801 %_ = OpVariable %_ptr_Uniform_cbuff Uniform
802 %int = OpTypeInt 32 1
803 %int_0 = OpConstant %int 0
804 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
805 %bool = OpTypeBool
806 %uint_0 = OpConstant %uint 0
807 %29 = OpTypeImage %float 1D 0 0 0 1 Unknown
808 %_ptr_UniformConstant_29 = OpTypePointer UniformConstant %29
809 %g_tTex1df4 = OpVariable %_ptr_UniformConstant_29 UniformConstant
810 %33 = OpTypeSampler
811 %_ptr_UniformConstant_33 = OpTypePointer UniformConstant %33
812 %g_sSamp = OpVariable %_ptr_UniformConstant_33 UniformConstant
813 %37 = OpTypeSampledImage %29
814 %float_0_100000001 = OpConstant %float 0.100000001
815 %float_0 = OpConstant %float 0
816 %43 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
817 %float_2 = OpConstant %float 2
818 %_ptr_Output_v4float = OpTypePointer Output %v4float
819 %_entryPointOutput_Color = OpVariable %_ptr_Output_v4float Output
820 )";
821 
822   const std::string defs_after =
823       R"(OpCapability Shader
824 OpCapability Sampled1D
825 OpCapability Float16
826 %1 = OpExtInstImport "GLSL.std.450"
827 OpMemoryModel Logical GLSL450
828 OpEntryPoint Fragment %main "main" %_entryPointOutput_Color
829 OpExecutionMode %main OriginUpperLeft
830 OpSource HLSL 500
831 OpName %main "main"
832 OpName %cbuff "cbuff"
833 OpMemberName %cbuff 0 "b"
834 OpMemberName %cbuff 1 "M"
835 OpName %_ ""
836 OpName %g_tTex1df4 "g_tTex1df4"
837 OpName %g_sSamp "g_sSamp"
838 OpName %_entryPointOutput_Color "@entryPointOutput.Color"
839 OpMemberDecorate %cbuff 0 Offset 0
840 OpMemberDecorate %cbuff 1 RowMajor
841 OpMemberDecorate %cbuff 1 Offset 16
842 OpMemberDecorate %cbuff 1 MatrixStride 16
843 OpDecorate %cbuff Block
844 OpDecorate %_ DescriptorSet 0
845 OpDecorate %_ Binding 1
846 OpDecorate %g_tTex1df4 DescriptorSet 0
847 OpDecorate %g_tTex1df4 Binding 0
848 OpDecorate %g_sSamp DescriptorSet 0
849 OpDecorate %g_sSamp Binding 0
850 OpDecorate %_entryPointOutput_Color Location 0
851 %void = OpTypeVoid
852 %3 = OpTypeFunction %void
853 %float = OpTypeFloat 32
854 %v4float = OpTypeVector %float 4
855 %uint = OpTypeInt 32 0
856 %mat4v4float = OpTypeMatrix %v4float 4
857 %cbuff = OpTypeStruct %uint %mat4v4float
858 %_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff
859 %_ = OpVariable %_ptr_Uniform_cbuff Uniform
860 %int = OpTypeInt 32 1
861 %int_0 = OpConstant %int 0
862 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
863 %bool = OpTypeBool
864 %uint_0 = OpConstant %uint 0
865 %29 = OpTypeImage %float 1D 0 0 0 1 Unknown
866 %_ptr_UniformConstant_29 = OpTypePointer UniformConstant %29
867 %g_tTex1df4 = OpVariable %_ptr_UniformConstant_29 UniformConstant
868 %33 = OpTypeSampler
869 %_ptr_UniformConstant_33 = OpTypePointer UniformConstant %33
870 %g_sSamp = OpVariable %_ptr_UniformConstant_33 UniformConstant
871 %37 = OpTypeSampledImage %29
872 %float_0_100000001 = OpConstant %float 0.100000001
873 %float_0 = OpConstant %float 0
874 %43 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
875 %float_2 = OpConstant %float 2
876 %_ptr_Output_v4float = OpTypePointer Output %v4float
877 %_entryPointOutput_Color = OpVariable %_ptr_Output_v4float Output
878 %half = OpTypeFloat 16
879 %v4half = OpTypeVector %half 4
880 )";
881 
882   const std::string func_before =
883       R"(%main = OpFunction %void None %3
884 %5 = OpLabel
885 %63 = OpAccessChain %_ptr_Uniform_uint %_ %int_0
886 %64 = OpLoad %uint %63
887 %65 = OpINotEqual %bool %64 %uint_0
888 OpSelectionMerge %66 None
889 OpBranchConditional %65 %67 %68
890 %67 = OpLabel
891 %69 = OpLoad %29 %g_tTex1df4
892 %70 = OpLoad %33 %g_sSamp
893 %71 = OpSampledImage %37 %69 %70
894 %72 = OpImageSampleImplicitLod %v4float %71 %float_0_100000001
895 OpBranch %66
896 %68 = OpLabel
897 OpBranch %66
898 %66 = OpLabel
899 %85 = OpPhi %v4float %72 %67 %43 %68
900 %74 = OpVectorTimesScalar %v4float %85 %float_2
901 OpStore %_entryPointOutput_Color %74
902 OpReturn
903 OpFunctionEnd
904 )";
905 
906   const std::string func_after =
907       R"(%main = OpFunction %void None %3
908 %5 = OpLabel
909 %63 = OpAccessChain %_ptr_Uniform_uint %_ %int_0
910 %64 = OpLoad %uint %63
911 %65 = OpINotEqual %bool %64 %uint_0
912 OpSelectionMerge %66 None
913 OpBranchConditional %65 %67 %68
914 %67 = OpLabel
915 %69 = OpLoad %29 %g_tTex1df4
916 %70 = OpLoad %33 %g_sSamp
917 %71 = OpSampledImage %37 %69 %70
918 %72 = OpImageSampleImplicitLod %v4float %71 %float_0_100000001
919 %88 = OpFConvert %v4half %72
920 OpBranch %66
921 %68 = OpLabel
922 %89 = OpFConvert %v4half %43
923 OpBranch %66
924 %66 = OpLabel
925 %85 = OpPhi %v4half %88 %67 %89 %68
926 %90 = OpFConvert %half %float_2
927 %74 = OpVectorTimesScalar %v4half %85 %90
928 %91 = OpFConvert %v4float %74
929 OpStore %_entryPointOutput_Color %91
930 OpReturn
931 OpFunctionEnd
932 )";
933 
934   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
935   SinglePassRunAndCheck<ConvertToHalfPass>(defs_before + func_before,
936                                            defs_after + func_after, true, true);
937 }
938 
TEST_F(ConvertToHalfTest, ConvertToHalfWithLoopAndFConvert)939 TEST_F(ConvertToHalfTest, ConvertToHalfWithLoopAndFConvert) {
940   // The resulting SPIR-V was processed with --relax-float-ops.
941   //
942   // The loop causes an FConvert to be generated at the bottom of the loop
943   // for the Phi. The FConvert is later processed and turned into a (dead)
944   // copy.
945   //
946   // clang-format off
947   //
948   // struct PS_OUTPUT
949   // {
950   //   float4 Color : SV_Target0;
951   // };
952   //
953   // cbuffer cbuff{
954   //   float4 a[10];
955   // }
956   //
957   // PS_OUTPUT main()
958   // {
959   //   PS_OUTPUT psout;
960   //   float4 t = 0.0;;
961   //
962   //   for (int i = 0; i<10; ++i)
963   //     t = t + a[i];
964   //
965   //   float4 t2 = t / 10.0;
966   //   psout.Color = t2;
967   //   return psout;
968   // }
969   //
970   // clang-format on
971 
972   const std::string defs_before =
973       R"(OpCapability Shader
974 %1 = OpExtInstImport "GLSL.std.450"
975 OpMemoryModel Logical GLSL450
976 OpEntryPoint Fragment %main "main" %_entryPointOutput_Color
977 OpExecutionMode %main OriginUpperLeft
978 OpSource HLSL 500
979 OpName %main "main"
980 OpName %cbuff "cbuff"
981 OpMemberName %cbuff 0 "a"
982 OpName %_ ""
983 OpName %_entryPointOutput_Color "@entryPointOutput.Color"
984 OpDecorate %_arr_v4float_uint_10 ArrayStride 16
985 OpMemberDecorate %cbuff 0 Offset 0
986 OpDecorate %cbuff Block
987 OpDecorate %_ DescriptorSet 0
988 OpDecorate %_ Binding 0
989 OpDecorate %_entryPointOutput_Color Location 0
990 OpDecorate %96 RelaxedPrecision
991 OpDecorate %81 RelaxedPrecision
992 OpDecorate %75 RelaxedPrecision
993 OpDecorate %76 RelaxedPrecision
994 %void = OpTypeVoid
995 %3 = OpTypeFunction %void
996 %float = OpTypeFloat 32
997 %v4float = OpTypeVector %float 4
998 %float_0 = OpConstant %float 0
999 %15 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
1000 %int = OpTypeInt 32 1
1001 %int_0 = OpConstant %int 0
1002 %int_10 = OpConstant %int 10
1003 %bool = OpTypeBool
1004 %uint = OpTypeInt 32 0
1005 %uint_10 = OpConstant %uint 10
1006 %_arr_v4float_uint_10 = OpTypeArray %v4float %uint_10
1007 %cbuff = OpTypeStruct %_arr_v4float_uint_10
1008 %_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff
1009 %_ = OpVariable %_ptr_Uniform_cbuff Uniform
1010 %_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
1011 %int_1 = OpConstant %int 1
1012 %_ptr_Output_v4float = OpTypePointer Output %v4float
1013 %_entryPointOutput_Color = OpVariable %_ptr_Output_v4float Output
1014 %float_0_100000001 = OpConstant %float 0.100000001
1015 %94 = OpConstantComposite %v4float %float_0_100000001 %float_0_100000001 %float_0_100000001 %float_0_100000001
1016 )";
1017 
1018   const std::string defs_after =
1019       R"(OpCapability Shader
1020 OpCapability Float16
1021 %1 = OpExtInstImport "GLSL.std.450"
1022 OpMemoryModel Logical GLSL450
1023 OpEntryPoint Fragment %main "main" %_entryPointOutput_Color
1024 OpExecutionMode %main OriginUpperLeft
1025 OpSource HLSL 500
1026 OpName %main "main"
1027 OpName %cbuff "cbuff"
1028 OpMemberName %cbuff 0 "a"
1029 OpName %_ ""
1030 OpName %_entryPointOutput_Color "@entryPointOutput.Color"
1031 OpDecorate %_arr_v4float_uint_10 ArrayStride 16
1032 OpMemberDecorate %cbuff 0 Offset 0
1033 OpDecorate %cbuff Block
1034 OpDecorate %_ DescriptorSet 0
1035 OpDecorate %_ Binding 0
1036 OpDecorate %_entryPointOutput_Color Location 0
1037 %void = OpTypeVoid
1038 %3 = OpTypeFunction %void
1039 %float = OpTypeFloat 32
1040 %v4float = OpTypeVector %float 4
1041 %float_0 = OpConstant %float 0
1042 %15 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
1043 %int = OpTypeInt 32 1
1044 %int_0 = OpConstant %int 0
1045 %int_10 = OpConstant %int 10
1046 %bool = OpTypeBool
1047 %uint = OpTypeInt 32 0
1048 %uint_10 = OpConstant %uint 10
1049 %_arr_v4float_uint_10 = OpTypeArray %v4float %uint_10
1050 %cbuff = OpTypeStruct %_arr_v4float_uint_10
1051 %_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff
1052 %_ = OpVariable %_ptr_Uniform_cbuff Uniform
1053 %_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
1054 %int_1 = OpConstant %int 1
1055 %_ptr_Output_v4float = OpTypePointer Output %v4float
1056 %_entryPointOutput_Color = OpVariable %_ptr_Output_v4float Output
1057 %float_0_100000001 = OpConstant %float 0.100000001
1058 %94 = OpConstantComposite %v4float %float_0_100000001 %float_0_100000001 %float_0_100000001 %float_0_100000001
1059 %half = OpTypeFloat 16
1060 %v4half = OpTypeVector %half 4
1061 )";
1062 
1063   const std::string func_before =
1064       R"(%main = OpFunction %void None %3
1065 %5 = OpLabel
1066 OpBranch %65
1067 %65 = OpLabel
1068 %96 = OpPhi %v4float %15 %5 %76 %71
1069 %95 = OpPhi %int %int_0 %5 %78 %71
1070 %70 = OpSLessThan %bool %95 %int_10
1071 OpLoopMerge %66 %71 None
1072 OpBranchConditional %70 %71 %66
1073 %71 = OpLabel
1074 %74 = OpAccessChain %_ptr_Uniform_v4float %_ %int_0 %95
1075 %75 = OpLoad %v4float %74
1076 %76 = OpFAdd %v4float %96 %75
1077 %78 = OpIAdd %int %95 %int_1
1078 OpBranch %65
1079 %66 = OpLabel
1080 %81 = OpFMul %v4float %96 %94
1081 OpStore %_entryPointOutput_Color %81
1082 OpReturn
1083 OpFunctionEnd
1084 )";
1085 
1086   const std::string func_after =
1087       R"(%main = OpFunction %void None %3
1088 %5 = OpLabel
1089 %99 = OpFConvert %v4half %15
1090 OpBranch %65
1091 %65 = OpLabel
1092 %96 = OpPhi %v4half %99 %5 %100 %71
1093 %95 = OpPhi %int %int_0 %5 %78 %71
1094 %70 = OpSLessThan %bool %95 %int_10
1095 OpLoopMerge %66 %71 None
1096 OpBranchConditional %70 %71 %66
1097 %71 = OpLabel
1098 %74 = OpAccessChain %_ptr_Uniform_v4float %_ %int_0 %95
1099 %75 = OpLoad %v4float %74
1100 %103 = OpFConvert %v4half %75
1101 %76 = OpFAdd %v4half %96 %103
1102 %78 = OpIAdd %int %95 %int_1
1103 %100 = OpCopyObject %v4half %76
1104 OpBranch %65
1105 %66 = OpLabel
1106 %101 = OpFConvert %v4half %94
1107 %81 = OpFMul %v4half %96 %101
1108 %102 = OpFConvert %v4float %81
1109 OpStore %_entryPointOutput_Color %102
1110 OpReturn
1111 OpFunctionEnd
1112 )";
1113 
1114   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1115   SinglePassRunAndCheck<ConvertToHalfPass>(defs_before + func_before,
1116                                            defs_after + func_after, true, true);
1117 }
1118 
TEST_F(ConvertToHalfTest, ConvertToHalfWithExtracts)1119 TEST_F(ConvertToHalfTest, ConvertToHalfWithExtracts) {
1120   // The resulting SPIR-V was processed with --relax-float-ops.
1121   //
1122   // The extra converts in the func_after can be DCE'd.
1123   //
1124   // clang-format off
1125   //
1126   // SamplerState       g_sSamp : register(s0);
1127   // uniform Texture1D <float4> g_tTex1df4 : register(t0);
1128   //
1129   // struct PS_INPUT
1130   // {
1131   //   float Tex0 : TEXCOORD0;
1132   // };
1133   //
1134   // struct PS_OUTPUT
1135   // {
1136   //   float4 Color : SV_Target0;
1137   // };
1138   //
1139   // cbuffer cbuff{
1140   //   float c;
1141   // }
1142   //
1143   // PS_OUTPUT main(PS_INPUT i)
1144   // {
1145   //   PS_OUTPUT psout;
1146   //   float4 tx = g_tTex1df4.Sample(g_sSamp, i.Tex0);
1147   //   float4 t = float4(tx.y, tx.z, tx.x, tx.w) * c;
1148   //   psout.Color = t;
1149   //   return psout;
1150   // }
1151   //
1152   // clang-format on
1153 
1154   const std::string defs_before =
1155       R"(OpCapability Shader
1156 OpCapability Sampled1D
1157 %1 = OpExtInstImport "GLSL.std.450"
1158 OpMemoryModel Logical GLSL450
1159 OpEntryPoint Fragment %main "main" %i_Tex0 %_entryPointOutput_Color
1160 OpExecutionMode %main OriginUpperLeft
1161 OpSource HLSL 500
1162 OpName %main "main"
1163 OpName %g_tTex1df4 "g_tTex1df4"
1164 OpName %g_sSamp "g_sSamp"
1165 OpName %cbuff "cbuff"
1166 OpMemberName %cbuff 0 "c"
1167 OpName %_ ""
1168 OpName %i_Tex0 "i.Tex0"
1169 OpName %_entryPointOutput_Color "@entryPointOutput.Color"
1170 OpDecorate %g_tTex1df4 DescriptorSet 0
1171 OpDecorate %g_tTex1df4 Binding 0
1172 OpDecorate %g_sSamp DescriptorSet 0
1173 OpDecorate %g_sSamp Binding 0
1174 OpMemberDecorate %cbuff 0 Offset 0
1175 OpDecorate %cbuff Block
1176 OpDecorate %_ DescriptorSet 0
1177 OpDecorate %_ Binding 1
1178 OpDecorate %i_Tex0 Location 0
1179 OpDecorate %_entryPointOutput_Color Location 0
1180 OpDecorate %65 RelaxedPrecision
1181 OpDecorate %82 RelaxedPrecision
1182 OpDecorate %84 RelaxedPrecision
1183 OpDecorate %86 RelaxedPrecision
1184 OpDecorate %88 RelaxedPrecision
1185 OpDecorate %90 RelaxedPrecision
1186 OpDecorate %91 RelaxedPrecision
1187 OpDecorate %93 RelaxedPrecision
1188 OpDecorate %94 RelaxedPrecision
1189 %void = OpTypeVoid
1190 %3 = OpTypeFunction %void
1191 %float = OpTypeFloat 32
1192 %v4float = OpTypeVector %float 4
1193 %17 = OpTypeImage %float 1D 0 0 0 1 Unknown
1194 %_ptr_UniformConstant_17 = OpTypePointer UniformConstant %17
1195 %g_tTex1df4 = OpVariable %_ptr_UniformConstant_17 UniformConstant
1196 %21 = OpTypeSampler
1197 %_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21
1198 %g_sSamp = OpVariable %_ptr_UniformConstant_21 UniformConstant
1199 %25 = OpTypeSampledImage %17
1200 %int = OpTypeInt 32 1
1201 %int_0 = OpConstant %int 0
1202 %cbuff = OpTypeStruct %float
1203 %_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff
1204 %_ = OpVariable %_ptr_Uniform_cbuff Uniform
1205 %_ptr_Uniform_float = OpTypePointer Uniform %float
1206 %_ptr_Input_float = OpTypePointer Input %float
1207 %i_Tex0 = OpVariable %_ptr_Input_float Input
1208 %_ptr_Output_v4float = OpTypePointer Output %v4float
1209 %_entryPointOutput_Color = OpVariable %_ptr_Output_v4float Output
1210 )";
1211 
1212   const std::string defs_after =
1213       R"(OpCapability Shader
1214 OpCapability Sampled1D
1215 OpCapability Float16
1216 %1 = OpExtInstImport "GLSL.std.450"
1217 OpMemoryModel Logical GLSL450
1218 OpEntryPoint Fragment %main "main" %i_Tex0 %_entryPointOutput_Color
1219 OpExecutionMode %main OriginUpperLeft
1220 OpSource HLSL 500
1221 OpName %main "main"
1222 OpName %g_tTex1df4 "g_tTex1df4"
1223 OpName %g_sSamp "g_sSamp"
1224 OpName %cbuff "cbuff"
1225 OpMemberName %cbuff 0 "c"
1226 OpName %_ ""
1227 OpName %i_Tex0 "i.Tex0"
1228 OpName %_entryPointOutput_Color "@entryPointOutput.Color"
1229 OpDecorate %g_tTex1df4 DescriptorSet 0
1230 OpDecorate %g_tTex1df4 Binding 0
1231 OpDecorate %g_sSamp DescriptorSet 0
1232 OpDecorate %g_sSamp Binding 0
1233 OpMemberDecorate %cbuff 0 Offset 0
1234 OpDecorate %cbuff Block
1235 OpDecorate %_ DescriptorSet 0
1236 OpDecorate %_ Binding 1
1237 OpDecorate %i_Tex0 Location 0
1238 OpDecorate %_entryPointOutput_Color Location 0
1239 %void = OpTypeVoid
1240 %3 = OpTypeFunction %void
1241 %float = OpTypeFloat 32
1242 %v4float = OpTypeVector %float 4
1243 %17 = OpTypeImage %float 1D 0 0 0 1 Unknown
1244 %_ptr_UniformConstant_17 = OpTypePointer UniformConstant %17
1245 %g_tTex1df4 = OpVariable %_ptr_UniformConstant_17 UniformConstant
1246 %21 = OpTypeSampler
1247 %_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21
1248 %g_sSamp = OpVariable %_ptr_UniformConstant_21 UniformConstant
1249 %25 = OpTypeSampledImage %17
1250 %int = OpTypeInt 32 1
1251 %int_0 = OpConstant %int 0
1252 %cbuff = OpTypeStruct %float
1253 %_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff
1254 %_ = OpVariable %_ptr_Uniform_cbuff Uniform
1255 %_ptr_Uniform_float = OpTypePointer Uniform %float
1256 %_ptr_Input_float = OpTypePointer Input %float
1257 %i_Tex0 = OpVariable %_ptr_Input_float Input
1258 %_ptr_Output_v4float = OpTypePointer Output %v4float
1259 %_entryPointOutput_Color = OpVariable %_ptr_Output_v4float Output
1260 %half = OpTypeFloat 16
1261 %v4half = OpTypeVector %half 4
1262 )";
1263 
1264   const std::string func_before =
1265       R"(%main = OpFunction %void None %3
1266 %5 = OpLabel
1267 %65 = OpLoad %float %i_Tex0
1268 %77 = OpLoad %17 %g_tTex1df4
1269 %78 = OpLoad %21 %g_sSamp
1270 %79 = OpSampledImage %25 %77 %78
1271 %82 = OpImageSampleImplicitLod %v4float %79 %65
1272 %84 = OpCompositeExtract %float %82 1
1273 %86 = OpCompositeExtract %float %82 2
1274 %88 = OpCompositeExtract %float %82 0
1275 %90 = OpCompositeExtract %float %82 3
1276 %91 = OpCompositeConstruct %v4float %84 %86 %88 %90
1277 %92 = OpAccessChain %_ptr_Uniform_float %_ %int_0
1278 %93 = OpLoad %float %92
1279 %94 = OpVectorTimesScalar %v4float %91 %93
1280 OpStore %_entryPointOutput_Color %94
1281 OpReturn
1282 OpFunctionEnd
1283 )";
1284 
1285   const std::string func_after =
1286       R"(%main = OpFunction %void None %3
1287 %5 = OpLabel
1288 %65 = OpLoad %float %i_Tex0
1289 %77 = OpLoad %17 %g_tTex1df4
1290 %78 = OpLoad %21 %g_sSamp
1291 %79 = OpSampledImage %25 %77 %78
1292 %82 = OpImageSampleImplicitLod %v4float %79 %65
1293 %97 = OpFConvert %v4half %82
1294 %84 = OpCompositeExtract %half %97 1
1295 %98 = OpFConvert %v4half %82
1296 %86 = OpCompositeExtract %half %98 2
1297 %99 = OpFConvert %v4half %82
1298 %88 = OpCompositeExtract %half %99 0
1299 %100 = OpFConvert %v4half %82
1300 %90 = OpCompositeExtract %half %100 3
1301 %91 = OpCompositeConstruct %v4half %84 %86 %88 %90
1302 %92 = OpAccessChain %_ptr_Uniform_float %_ %int_0
1303 %93 = OpLoad %float %92
1304 %101 = OpFConvert %half %93
1305 %94 = OpVectorTimesScalar %v4half %91 %101
1306 %102 = OpFConvert %v4float %94
1307 OpStore %_entryPointOutput_Color %102
1308 OpReturn
1309 OpFunctionEnd
1310 )";
1311 
1312   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1313   SinglePassRunAndCheck<ConvertToHalfPass>(defs_before + func_before,
1314                                            defs_after + func_after, true, true);
1315 }
1316 
TEST_F(ConvertToHalfTest, ConvertToHalfWithClosure)1317 TEST_F(ConvertToHalfTest, ConvertToHalfWithClosure) {
1318   // Include as many contiguous composite instructions as possible into
1319   // half-precision computations
1320   //
1321   // Compiled with glslang -V -Os
1322   //
1323   // clang-format off
1324   //
1325   // #version 410 core
1326   //
1327   //   precision mediump float;
1328   //
1329   // layout(location = 1) in vec3 foo;
1330   // layout(location = 2) in mat2 bar;
1331   // layout(location = 1) out vec3 res;
1332   //
1333   // vec3 func(vec3 tap, mat2 M) {
1334   //   return vec3(M * tap.xy, 1.0);
1335   // }
1336   //
1337   // void main() {
1338   //   res = func(foo, bar);
1339   // }
1340   //
1341   // clang-format on
1342 
1343   const std::string defs =
1344       R"(OpCapability Shader
1345 ; CHECK: OpCapability Float16
1346 %1 = OpExtInstImport "GLSL.std.450"
1347 OpMemoryModel Logical GLSL450
1348 OpEntryPoint Fragment %main "main" %res %foo %bar
1349 OpExecutionMode %main OriginUpperLeft
1350 OpSource GLSL 410
1351 OpName %main "main"
1352 OpName %res "res"
1353 OpName %foo "foo"
1354 OpName %bar "bar"
1355 OpDecorate %res RelaxedPrecision
1356 ; CHECK-NOT: OpDecorate %res RelaxedPrecision
1357 OpDecorate %res Location 1
1358 OpDecorate %foo RelaxedPrecision
1359 ; CHECK-NOT: OpDecorate %foo RelaxedPrecision
1360 OpDecorate %foo Location 1
1361 OpDecorate %bar RelaxedPrecision
1362 ; CHECK-NOT: OpDecorate %bar RelaxedPrecision
1363 OpDecorate %bar Location 2
1364 OpDecorate %34 RelaxedPrecision
1365 OpDecorate %36 RelaxedPrecision
1366 OpDecorate %41 RelaxedPrecision
1367 OpDecorate %42 RelaxedPrecision
1368 ; CHECK-NOT: OpDecorate %34 RelaxedPrecision
1369 ; CHECK-NOT: OpDecorate %36 RelaxedPrecision
1370 ; CHECK-NOT: OpDecorate %41 RelaxedPrecision
1371 ; CHECK-NOT: OpDecorate %42 RelaxedPrecision
1372 %void = OpTypeVoid
1373 %3 = OpTypeFunction %void
1374 %float = OpTypeFloat 32
1375 %v3float = OpTypeVector %float 3
1376 %v2float = OpTypeVector %float 2
1377 %mat2v2float = OpTypeMatrix %v2float 2
1378 %float_1 = OpConstant %float 1
1379 %_ptr_Output_v3float = OpTypePointer Output %v3float
1380 %res = OpVariable %_ptr_Output_v3float Output
1381 %_ptr_Input_v3float = OpTypePointer Input %v3float
1382 %foo = OpVariable %_ptr_Input_v3float Input
1383 %_ptr_Input_mat2v2float = OpTypePointer Input %mat2v2float
1384 %bar = OpVariable %_ptr_Input_mat2v2float Input
1385 )";
1386 
1387   const std::string func =
1388       R"(%main = OpFunction %void None %3
1389 %5 = OpLabel
1390 %34 = OpLoad %v3float %foo
1391 %36 = OpLoad %mat2v2float %bar
1392 ; CHECK: %48 = OpFConvert %v3half %34
1393 ; CHECK: %49 = OpFConvert %v3half %34
1394 %41 = OpVectorShuffle %v2float %34 %34 0 1
1395 ; CHECK-NOT: %41 = OpVectorShuffle %v2float %34 %34 0 1
1396 ; CHECK: %41 = OpVectorShuffle %v2half %48 %49 0 1
1397 %42 = OpMatrixTimesVector %v2float %36 %41
1398 ; CHECK-NOT: %42 = OpMatrixTimesVector %v2float %36 %41
1399 ; CHECK: %55 = OpCompositeExtract %v2float %36 0
1400 ; CHECK: %56 = OpFConvert %v2half %55
1401 ; CHECK: %57 = OpCompositeExtract %v2float %36 1
1402 ; CHECK: %58 = OpFConvert %v2half %57
1403 ; CHECK: %59 = OpCompositeConstruct %mat2v2half %56 %58
1404 ; CHECK: %52 = OpCopyObject %mat2v2float %36
1405 ; CHECK: %42 = OpMatrixTimesVector %v2half %59 %41
1406 %43 = OpCompositeExtract %float %42 0
1407 %44 = OpCompositeExtract %float %42 1
1408 ; CHECK-NOT: %43 = OpCompositeExtract %float %42 0
1409 ; CHECK-NOT: %44 = OpCompositeExtract %float %42 1
1410 ; CHECK: %43 = OpCompositeExtract %half %42 0
1411 ; CHECK: %44 = OpCompositeExtract %half %42 1
1412 %45 = OpCompositeConstruct %v3float %43 %44 %float_1
1413 ; CHECK-NOT: %45 = OpCompositeConstruct %v3float %43 %44 %float_1
1414 ; CHECK: %53 = OpFConvert %float %43
1415 ; CHECK: %54 = OpFConvert %float %44
1416 ; CHECK: %45 = OpCompositeConstruct %v3float %53 %54 %float_1
1417 OpStore %res %45
1418 OpReturn
1419 OpFunctionEnd
1420 )";
1421 
1422   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1423   SinglePassRunAndMatch<ConvertToHalfPass>(defs + func, true);
1424 }
1425 
TEST_F(ConvertToHalfTest, RemoveRelaxDec)1426 TEST_F(ConvertToHalfTest, RemoveRelaxDec) {
1427   // See https://github.com/KhronosGroup/SPIRV-Tools/issues/4117
1428 
1429   // This test is a case where the relax precision decorations need to be
1430   // removed, but the body of the function does not change because there are not
1431   // arithmetic operations.  So, there is not need for the Float16 capability.
1432   const std::string test =
1433       R"(
1434 ; CHECK-NOT: OpCapability Float16
1435 ; GLSL seems to generate this decoration on the load of a texture, which seems odd to me.
1436 ; This pass does not currently remove it, and I'm not sure what we should do with it, so I will leave it.
1437 ; CHECK: OpDecorate [[tex:%\w+]] RelaxedPrecision
1438 ; CHECK-NOT: OpDecorate {{%\w+}} RelaxedPrecision
1439 ; CHECK: OpLabel
1440 ; CHECK: [[tex]] = OpLoad {{%\w+}} %sTexture
1441 ; CHECK: [[coord:%\w+]] = OpLoad %v2float
1442 ; CHECK: [[retval:%\w+]] = OpImageSampleImplicitLod %v4float {{%\w+}} [[coord]]
1443 ; CHECK: OpStore %outFragColor [[retval]]
1444                OpCapability Shader
1445           %1 = OpExtInstImport "GLSL.std.450"
1446                OpMemoryModel Logical GLSL450
1447                OpEntryPoint Fragment %main "main" %outFragColor %v_texcoord
1448                OpExecutionMode %main OriginUpperLeft
1449                OpSource ESSL 310
1450                OpName %main "main"
1451                OpName %outFragColor "outFragColor"
1452                OpName %sTexture "sTexture"
1453                OpName %v_texcoord "v_texcoord"
1454                OpDecorate %outFragColor RelaxedPrecision
1455                OpDecorate %outFragColor Location 0
1456                OpDecorate %sTexture RelaxedPrecision
1457                OpDecorate %sTexture DescriptorSet 0
1458                OpDecorate %sTexture Binding 0
1459                OpDecorate %14 RelaxedPrecision
1460                OpDecorate %v_texcoord RelaxedPrecision
1461                OpDecorate %v_texcoord Location 0
1462                OpDecorate %18 RelaxedPrecision
1463                OpDecorate %19 RelaxedPrecision
1464        %void = OpTypeVoid
1465           %3 = OpTypeFunction %void
1466       %float = OpTypeFloat 32
1467     %v4float = OpTypeVector %float 4
1468 %_ptr_Output_v4float = OpTypePointer Output %v4float
1469 %outFragColor = OpVariable %_ptr_Output_v4float Output
1470          %10 = OpTypeImage %float 2D 0 0 0 1 Unknown
1471          %11 = OpTypeSampledImage %10
1472 %_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11
1473    %sTexture = OpVariable %_ptr_UniformConstant_11 UniformConstant
1474     %v2float = OpTypeVector %float 2
1475 %_ptr_Input_v2float = OpTypePointer Input %v2float
1476  %v_texcoord = OpVariable %_ptr_Input_v2float Input
1477        %main = OpFunction %void None %3
1478           %5 = OpLabel
1479          %14 = OpLoad %11 %sTexture
1480          %18 = OpLoad %v2float %v_texcoord
1481          %19 = OpImageSampleImplicitLod %v4float %14 %18
1482                OpStore %outFragColor %19
1483                OpReturn
1484                OpFunctionEnd
1485 )";
1486 
1487   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1488   auto result = SinglePassRunAndMatch<ConvertToHalfPass>(test, true);
1489   EXPECT_EQ(Pass::Status::SuccessWithChange, std::get<1>(result));
1490 }
1491 
TEST_F(ConvertToHalfTest, HandleNonRelaxedPhi)1492 TEST_F(ConvertToHalfTest, HandleNonRelaxedPhi) {
1493   // See https://github.com/KhronosGroup/SPIRV-Tools/issues/4452
1494 
1495   // This test is a case with a non-relaxed phi with a relaxed operand.
1496   // A convert must be inserted at the end of the block associated with
1497   // the operand.
1498   const std::string test =
1499       R"(
1500 ; CHECK: [[fcvt:%\w+]] = OpFConvert %v3float {{%\w+}}
1501 ; CHECK-NEXT: OpSelectionMerge {{%\w+}} None
1502 ; CHECK: {{%\w+}} = OpPhi %v3float [[fcvt]] {{%\w+}} {{%\w+}} {{%\w+}}
1503                OpCapability Shader
1504           %1 = OpExtInstImport "GLSL.std.450"
1505                OpMemoryModel Logical GLSL450
1506                OpEntryPoint Fragment %main "main" %output_color
1507                OpExecutionMode %main OriginUpperLeft
1508                OpSource GLSL 450
1509                OpName %main "main"
1510                OpName %MaterialParams "MaterialParams"
1511                OpMemberName %MaterialParams 0 "foo"
1512                OpName %materialParams "materialParams"
1513                OpName %output_color "output_color"
1514                OpMemberDecorate %MaterialParams 0 Offset 0
1515                OpDecorate %MaterialParams Block
1516                OpDecorate %materialParams DescriptorSet 0
1517                OpDecorate %materialParams Binding 5
1518                OpDecorate %output_color Location 0
1519                OpDecorate %57 RelaxedPrecision
1520        %void = OpTypeVoid
1521           %3 = OpTypeFunction %void
1522       %float = OpTypeFloat 32
1523     %v3float = OpTypeVector %float 3
1524 %MaterialParams = OpTypeStruct %float
1525 %_ptr_Uniform_MaterialParams = OpTypePointer Uniform %MaterialParams
1526 %materialParams = OpVariable %_ptr_Uniform_MaterialParams Uniform
1527         %int = OpTypeInt 32 1
1528       %int_0 = OpConstant %int 0
1529 %_ptr_Uniform_float = OpTypePointer Uniform %float
1530     %float_0 = OpConstant %float 0
1531        %bool = OpTypeBool
1532     %v4float = OpTypeVector %float 4
1533 %_ptr_Output_v4float = OpTypePointer Output %v4float
1534 %output_color = OpVariable %_ptr_Output_v4float Output
1535        %uint = OpTypeInt 32 0
1536      %uint_0 = OpConstant %uint 0
1537 %_ptr_Output_float = OpTypePointer Output %float
1538      %uint_1 = OpConstant %uint 1
1539      %uint_2 = OpConstant %uint 2
1540   %float_0_5 = OpConstant %float 0.5
1541          %61 = OpConstantComposite %v3float %float_0_5 %float_0_5 %float_0_5
1542        %main = OpFunction %void None %3
1543           %5 = OpLabel
1544          %55 = OpAccessChain %_ptr_Uniform_float %materialParams %int_0
1545          %56 = OpLoad %float %55
1546          %57 = OpCompositeConstruct %v3float %56 %56 %56
1547          %31 = OpFOrdGreaterThan %bool %56 %float_0
1548                OpSelectionMerge %33 None
1549                OpBranchConditional %31 %32 %33
1550          %32 = OpLabel
1551          %37 = OpFMul %v3float %57 %61
1552                OpBranch %33
1553          %33 = OpLabel
1554          %58 = OpPhi %v3float %57 %5 %37 %32
1555          %45 = OpAccessChain %_ptr_Output_float %output_color %uint_0
1556          %46 = OpCompositeExtract %float %58 0
1557                OpStore %45 %46
1558          %48 = OpAccessChain %_ptr_Output_float %output_color %uint_1
1559          %49 = OpCompositeExtract %float %58 1
1560                OpStore %48 %49
1561          %51 = OpAccessChain %_ptr_Output_float %output_color %uint_2
1562          %52 = OpCompositeExtract %float %58 2
1563                OpStore %51 %52
1564                OpReturn
1565                OpFunctionEnd
1566 )";
1567 
1568   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1569   auto result = SinglePassRunAndMatch<ConvertToHalfPass>(test, true);
1570   EXPECT_EQ(Pass::Status::SuccessWithChange, std::get<1>(result));
1571 }
1572 
TEST_F(ConvertToHalfTest, DoNotReplaceStructMember)1573 TEST_F(ConvertToHalfTest, DoNotReplaceStructMember) {
1574   // See https://github.com/KhronosGroup/SPIRV-Tools/issues/4814
1575 
1576   // This test is a case with a non-relaxed phi with a relaxed operand.
1577   // A convert must be inserted at the end of the block associated with
1578   // the operand.
1579   const std::string test =
1580       R"(OpCapability Shader
1581 OpMemoryModel Logical GLSL450
1582 OpEntryPoint Fragment %PSMain "PSMain" %out_var_SV_TARGET %MyConstants
1583 OpExecutionMode %PSMain OriginUpperLeft
1584 OpSource HLSL 600
1585 OpName %type_ConstantBuffer_myStruct "type.ConstantBuffer.myStruct"
1586 OpMemberName %type_ConstantBuffer_myStruct 0 "f"
1587 OpName %MyConstants "MyConstants"
1588 OpName %out_var_SV_TARGET "out.var.SV_TARGET"
1589 OpName %PSMain "PSMain"
1590 OpDecorate %out_var_SV_TARGET Location 0
1591 OpDecorate %MyConstants DescriptorSet 1
1592 OpDecorate %MyConstants Binding 2
1593 OpMemberDecorate %type_ConstantBuffer_myStruct 0 Offset 0
1594 OpDecorate %type_ConstantBuffer_myStruct Block
1595 %float = OpTypeFloat 32
1596 %type_ConstantBuffer_myStruct = OpTypeStruct %float
1597 %_ptr_Uniform_type_ConstantBuffer_myStruct = OpTypePointer Uniform %type_ConstantBuffer_myStruct
1598 %_ptr_Output_float = OpTypePointer Output %float
1599 %void = OpTypeVoid
1600 %9 = OpTypeFunction %void
1601 %MyConstants = OpVariable %_ptr_Uniform_type_ConstantBuffer_myStruct Uniform
1602 %out_var_SV_TARGET = OpVariable %_ptr_Output_float Output
1603 %PSMain = OpFunction %void None %9
1604 %10 = OpLabel
1605 %11 = OpLoad %type_ConstantBuffer_myStruct %MyConstants
1606 %12 = OpCompositeExtract %float %11 0
1607 OpStore %out_var_SV_TARGET %12
1608 OpReturn
1609 OpFunctionEnd
1610 )";
1611 
1612   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1613   SinglePassRunAndCheck<ConvertToHalfPass>(test, test, true);
1614 }
1615 
TEST_F(ConvertToHalfTest, PreserveImageOperandPrecision)1616 TEST_F(ConvertToHalfTest, PreserveImageOperandPrecision) {
1617   // Ensure that a non-relaxed texture coordinate does not get relaxed nor
1618   // converted to half precision if the image instruction is marked relaxed.
1619 
1620   // Also ensure that a relaxed local variable does get converted to half
1621   // precision before being passed to an image opeartor.
1622 
1623   // #version 310 es
1624   //
1625   // precision mediump float;
1626   //
1627   // layout(location = 10) in highp vec4 vertex_uv01;
1628   // layout(binding = 0, set = 3) uniform sampler2D materialParams_baseColorMap;
1629   //
1630   // layout(location = 0) out vec4 fragColor;
1631   //
1632   // void main() {
1633   //   vec4 uv = vec4(2.0);
1634   //   fragColor = texture(materialParams_baseColorMap, uv.xy);
1635   //   fragColor = texture(materialParams_baseColorMap, vertex_uv01.xy);
1636   // }
1637   const std::string test = R"(
1638                OpCapability Shader
1639                OpCapability Float16
1640           %1 = OpExtInstImport "GLSL.std.450"
1641                OpMemoryModel Logical GLSL450
1642                OpEntryPoint Fragment %4 "main" %13 %25
1643                OpExecutionMode %4 OriginUpperLeft
1644                OpSource ESSL 310
1645                OpDecorate %9 RelaxedPrecision
1646 ;CHECK: OpDecorate [[uv:%\w+]] RelaxedPrecision
1647                OpDecorate %13 Location 0
1648                OpDecorate %17 DescriptorSet 3
1649                OpDecorate %17 Binding 0
1650                OpDecorate %18 RelaxedPrecision
1651                OpDecorate %23 RelaxedPrecision
1652                OpDecorate %25 Location 10
1653           %2 = OpTypeVoid
1654           %3 = OpTypeFunction %2
1655           %6 = OpTypeFloat 32
1656 ;CHECK: [[float32_t:%\w+]] = OpTypeFloat 32
1657           %7 = OpTypeVector %6 4
1658 ;CHECK: [[vec4_t:%\w+]] = OpTypeVector [[float32_t]] 4
1659           %8 = OpTypePointer Function %7
1660          %10 = OpConstant %6 2
1661          %11 = OpConstantComposite %7 %10 %10 %10 %10
1662          %12 = OpTypePointer Output %7
1663 ;CHECK: [[output_ptr_t:%\w+]] = OpTypePointer Output [[vec4_t]]
1664          %13 = OpVariable %12 Output
1665 ;CHECK: [[output:%\w+]] = OpVariable [[output_ptr_t]] Output
1666          %14 = OpTypeImage %6 2D 0 0 0 1 Unknown
1667          %15 = OpTypeSampledImage %14
1668          %16 = OpTypePointer UniformConstant %15
1669          %17 = OpVariable %16 UniformConstant
1670          %19 = OpTypeVector %6 2
1671 ;CHECK: [[vec2_t:%\w+]] = OpTypeVector [[float32_t]] 2
1672          %24 = OpTypePointer Input %7
1673 ;CHECK: [[input_ptr_t:%\w+]] = OpTypePointer Input [[vec4_t]]
1674          %25 = OpVariable %24 Input
1675          %29 = OpTypeFloat 16
1676 ;CHECK: [[float16_t:%\w+]] = OpTypeFloat 16
1677          %30 = OpTypeVector %29 4
1678          %33 = OpTypeVector %29 2
1679 ;CHECK: [[vec2_16b_t:%\w+]] = OpTypeVector [[float16_t]] 2
1680           %4 = OpFunction %2 None %3
1681           %5 = OpLabel
1682 
1683 ; The only Function storage variable is marked as relaxed
1684           %9 = OpVariable %8 Function
1685 ;CHECK: [[uv]] = OpVariable {{%\w+}} Function
1686                OpStore %9 %11
1687          %18 = OpLoad %15 %17
1688          %20 = OpLoad %7 %9
1689          %31 = OpFConvert %30 %20
1690          %32 = OpFConvert %30 %20
1691 
1692 ; The first sample op should get a 16b coordinate
1693          %21 = OpVectorShuffle %33 %31 %32 0 1
1694 ;CHECK: [[uv_16b:%\w+]] = OpVectorShuffle [[vec2_16b_t]]
1695          %22 = OpImageSampleImplicitLod %7 %18 %21
1696 ;CHECK: OpImageSampleImplicitLod [[vec4_t]] {{%\w+}} [[uv_16b]]
1697 
1698                OpStore %13 %22
1699          %23 = OpLoad %15 %17
1700          %26 = OpLoad %7 %25
1701 
1702 ; The second sample op should get a 32b coordinate
1703          %27 = OpVectorShuffle %19 %26 %26 0 1
1704 ;CHECK: [[uv_32b:%\w+]] = OpVectorShuffle [[vec2_t]]
1705          %28 = OpImageSampleImplicitLod %7 %23 %27
1706 ;CHECK: OpImageSampleImplicitLod [[vec4_t]] {{%\w+}} [[uv_32b]]
1707 
1708                OpStore %13 %28
1709                OpReturn
1710                OpFunctionEnd
1711   )";
1712 
1713   SinglePassRunAndMatch<ConvertToHalfPass>(test, true);
1714 }
1715 
1716 }  // namespace
1717 }  // namespace opt
1718 }  // namespace spvtools
1719