• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <unordered_set>
16 
17 #include "gtest/gtest.h"
18 #include "src/reader/wgsl/parser.h"
19 #include "src/writer/wgsl/generator.h"
20 
21 namespace tint {
22 namespace ast {
23 namespace {
24 
TEST(ModuleCloneTest,Clone)25 TEST(ModuleCloneTest, Clone) {
26 #if TINT_BUILD_WGSL_READER && TINT_BUILD_WGSL_WRITER
27   // Shader that exercises the bulk of the AST nodes and types.
28   // See also fuzzers/tint_ast_clone_fuzzer.cc for further coverage of cloning.
29   Source::File file("test.wgsl", R"([[block]]
30 struct S0 {
31   [[size(4)]]
32   m0 : u32;
33   m1 : array<u32>;
34 };
35 
36 [[block]] struct S1 {
37   [[size(4)]]
38   m0 : u32;
39   m1 : array<u32, 6>;
40 };
41 
42 let c0 : i32 = 10;
43 let c1 : bool = true;
44 
45 type t0 = [[stride(16)]] array<vec4<f32>>;
46 type t1 = array<vec4<f32>>;
47 
48 var<private> g0 : u32 = 20u;
49 var<private> g1 : f32 = 123.0;
50 [[group(0), binding(0)]] var g2 : texture_2d<f32>;
51 [[group(1), binding(0)]] var g3 : texture_depth_2d;
52 [[group(2), binding(0)]] var g4 : texture_storage_2d<rg32float, write>;
53 [[group(3), binding(0)]] var g5 : texture_depth_cube_array;
54 [[group(4), binding(0)]] var g6 : texture_external;
55 
56 var<private> g7 : vec3<f32>;
57 [[group(0), binding(1)]] var<storage, write> g8 : S0;
58 [[group(1), binding(1)]] var<storage, read> g9 : S0;
59 [[group(2), binding(1)]] var<storage, read_write> g10 : S0;
60 
61 fn f0(p0 : bool) -> f32 {
62   if (p0) {
63     return 1.0;
64   }
65   return 0.0;
66 }
67 
68 fn f1(p0 : f32, p1 : i32) -> f32 {
69   var l0 : i32 = 3;
70   var l1 : f32 = 8.0;
71   var l2 : u32 = bitcast<u32>(4);
72   var l3 : vec2<u32> = vec2<u32>(u32(l0), u32(l1));
73   var l4 : S1;
74   var l5 : u32 = l4.m1[5];
75   let l6 : ptr<private, u32> = &g0;
76   loop {
77     l0 = (p1 + 2);
78     if (((l0 % 4) == 0)) {
79       break;
80     }
81 
82     continuing {
83       if (1 == 2) {
84         l0 = l0 - 1;
85       } else {
86         l0 = l0 - 2;
87       }
88     }
89   }
90   switch(l2) {
91     case 0u: {
92       break;
93     }
94     case 1u: {
95       return f0(true);
96     }
97     default: {
98       discard;
99     }
100   }
101   return 1.0;
102 }
103 
104 [[stage(fragment)]]
105 fn main() {
106   f1(1.0, 2);
107 }
108 
109 let declaration_order_check_0 : i32 = 1;
110 
111 type declaration_order_check_1 = f32;
112 
113 fn declaration_order_check_2() {}
114 
115 type declaration_order_check_3 = f32;
116 
117 let declaration_order_check_4 : i32 = 1;
118 
119 )");
120 
121   // Parse the wgsl, create the src program
122   auto src = reader::wgsl::Parse(&file);
123 
124   ASSERT_TRUE(src.IsValid()) << diag::Formatter().format(src.Diagnostics());
125 
126   // Clone the src program to dst
127   Program dst(src.Clone());
128 
129   ASSERT_TRUE(dst.IsValid()) << diag::Formatter().format(dst.Diagnostics());
130 
131   // Expect the printed strings to match
132   EXPECT_EQ(Program::printer(&src), Program::printer(&dst));
133 
134   // Check that none of the AST nodes or type pointers in dst are found in src
135   std::unordered_set<ast::Node*> src_nodes;
136   for (auto* src_node : src.ASTNodes().Objects()) {
137     src_nodes.emplace(src_node);
138   }
139   std::unordered_set<sem::Type*> src_types;
140   for (auto* src_type : src.Types()) {
141     src_types.emplace(src_type);
142   }
143   for (auto* dst_node : dst.ASTNodes().Objects()) {
144     ASSERT_EQ(src_nodes.count(dst_node), 0u);
145   }
146   for (auto* dst_type : dst.Types()) {
147     ASSERT_EQ(src_types.count(dst_type), 0u);
148   }
149 
150   // Regenerate the wgsl for the src program. We use this instead of the
151   // original source so that reformatting doesn't impact the final wgsl
152   // comparison.
153   writer::wgsl::Options options;
154   std::string src_wgsl;
155   {
156     auto result = writer::wgsl::Generate(&src, options);
157     ASSERT_TRUE(result.success) << result.error;
158     src_wgsl = result.wgsl;
159 
160     // Move the src program to a temporary that'll be dropped, so that the src
161     // program is released before we attempt to print the dst program. This
162     // guarantee that all the source program nodes and types are destructed and
163     // freed. ASAN should error if there's any remaining references in dst when
164     // we try to reconstruct the WGSL.
165     auto tmp = std::move(src);
166   }
167 
168   // Print the dst module, check it matches the original source
169   auto result = writer::wgsl::Generate(&dst, options);
170   ASSERT_TRUE(result.success);
171   auto dst_wgsl = result.wgsl;
172   ASSERT_EQ(src_wgsl, dst_wgsl);
173 
174 #else  // #if TINT_BUILD_WGSL_READER && TINT_BUILD_WGSL_WRITER
175   GTEST_SKIP() << "ModuleCloneTest requires TINT_BUILD_WGSL_READER and "
176                   "TINT_BUILD_WGSL_WRITER to be enabled";
177 #endif
178 }
179 
180 }  // namespace
181 }  // namespace ast
182 }  // namespace tint
183