1 /*
2 * Copyright © 2013 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23 #include <gtest/gtest.h>
24 #include "util/compiler.h"
25 #include "main/macros.h"
26 #include "ir.h"
27 #include "ir_builder.h"
28
29 using namespace ir_builder;
30
31 namespace lower_64bit {
32 void expand_source(ir_factory &body,
33 ir_rvalue *val,
34 ir_variable **expanded_src);
35
36 ir_dereference_variable *compact_destination(ir_factory &body,
37 const glsl_type *type,
38 ir_variable *result[4]);
39
40 ir_rvalue *lower_op_to_function_call(ir_instruction *base_ir,
41 ir_expression *ir,
42 ir_function_signature *callee);
43 };
44
45 class expand_source : public ::testing::Test {
46 public:
47 virtual void SetUp();
48 virtual void TearDown();
49
50 exec_list instructions;
51 ir_factory *body;
52 ir_variable *expanded_src[4];
53 void *mem_ctx;
54 };
55
56 void
SetUp()57 expand_source::SetUp()
58 {
59 glsl_type_singleton_init_or_ref();
60
61 mem_ctx = ralloc_context(NULL);
62
63 memset(expanded_src, 0, sizeof(expanded_src));
64 instructions.make_empty();
65 body = new ir_factory(&instructions, mem_ctx);
66 }
67
68 void
TearDown()69 expand_source::TearDown()
70 {
71 delete body;
72 body = NULL;
73
74 ralloc_free(mem_ctx);
75 mem_ctx = NULL;
76
77 glsl_type_singleton_decref();
78 }
79
80 static ir_dereference_variable *
create_variable(void * mem_ctx,const glsl_type * type)81 create_variable(void *mem_ctx, const glsl_type *type)
82 {
83 ir_variable *var = new(mem_ctx) ir_variable(type,
84 "variable",
85 ir_var_temporary);
86
87 return new(mem_ctx) ir_dereference_variable(var);
88 }
89
90 static ir_expression *
create_expression(void * mem_ctx,const glsl_type * type)91 create_expression(void *mem_ctx, const glsl_type *type)
92 {
93 return new(mem_ctx) ir_expression(ir_unop_neg,
94 create_variable(mem_ctx, type));
95 }
96
97 static void
check_expanded_source(const glsl_type * type,ir_variable * expanded_src[4])98 check_expanded_source(const glsl_type *type,
99 ir_variable *expanded_src[4])
100 {
101 const glsl_type *const expanded_type =
102 type->base_type == GLSL_TYPE_UINT64
103 ? glsl_type::uvec2_type :glsl_type::ivec2_type;
104
105 for (int i = 0; i < type->vector_elements; i++) {
106 EXPECT_EQ(expanded_type, expanded_src[i]->type);
107
108 /* All elements that are part of the vector must be unique. */
109 for (int j = i - 1; j >= 0; j--) {
110 EXPECT_NE(expanded_src[i], expanded_src[j])
111 << " Element " << i << " is the same as element " << j;
112 }
113 }
114
115 /* All elements that are not part of the vector must be the same as element
116 * 0. This is primarily for scalars (where every element is the same).
117 */
118 for (int i = type->vector_elements; i < 4; i++) {
119 EXPECT_EQ(expanded_src[0], expanded_src[i])
120 << " Element " << i << " should be the same as element 0";
121 }
122 }
123
124 static void
check_instructions(exec_list * instructions,const glsl_type * type,const ir_instruction * source)125 check_instructions(exec_list *instructions,
126 const glsl_type *type,
127 const ir_instruction *source)
128 {
129 const glsl_type *const expanded_type =
130 type->base_type == GLSL_TYPE_UINT64
131 ? glsl_type::uvec2_type : glsl_type::ivec2_type;
132
133 const ir_expression_operation unpack_opcode =
134 type->base_type == GLSL_TYPE_UINT64
135 ? ir_unop_unpack_uint_2x32 : ir_unop_unpack_int_2x32;
136
137 ir_instruction *ir;
138
139 /* The instruction list should contain IR to represent:
140 *
141 * type tmp1;
142 * tmp1 = source;
143 * uvec2 tmp2;
144 * tmp2 = unpackUint2x32(tmp1.x);
145 * uvec2 tmp3;
146 * tmp3 = unpackUint2x32(tmp1.y);
147 * uvec2 tmp4;
148 * tmp4 = unpackUint2x32(tmp1.z);
149 * uvec2 tmp5;
150 * tmp5 = unpackUint2x32(tmp1.w);
151 */
152 ASSERT_FALSE(instructions->is_empty());
153 ir = (ir_instruction *) instructions->pop_head();
154 ir_variable *const tmp1 = ir->as_variable();
155 EXPECT_EQ(ir_type_variable, ir->ir_type);
156 EXPECT_EQ(type, tmp1->type) <<
157 " Got " <<
158 tmp1->type->name <<
159 ", expected " <<
160 type->name;
161
162 ASSERT_FALSE(instructions->is_empty());
163 ir = (ir_instruction *) instructions->pop_head();
164 ir_assignment *const assign1 = ir->as_assignment();
165 EXPECT_EQ(ir_type_assignment, ir->ir_type);
166 ASSERT_NE((void *)0, assign1);
167 EXPECT_EQ(tmp1, assign1->lhs->variable_referenced());
168 EXPECT_EQ(source, assign1->rhs);
169
170 for (unsigned i = 0; i < type->vector_elements; i++) {
171 ASSERT_FALSE(instructions->is_empty());
172 ir = (ir_instruction *) instructions->pop_head();
173 ir_variable *const tmp2 = ir->as_variable();
174 EXPECT_EQ(ir_type_variable, ir->ir_type);
175 EXPECT_EQ(expanded_type, tmp2->type);
176
177 ASSERT_FALSE(instructions->is_empty());
178 ir = (ir_instruction *) instructions->pop_head();
179 ir_assignment *const assign2 = ir->as_assignment();
180 EXPECT_EQ(ir_type_assignment, ir->ir_type);
181 ASSERT_NE((void *)0, assign2);
182 EXPECT_EQ(tmp2, assign2->lhs->variable_referenced());
183 ir_expression *unpack = assign2->rhs->as_expression();
184 ASSERT_NE((void *)0, unpack);
185 EXPECT_EQ(unpack_opcode, unpack->operation);
186 EXPECT_EQ(tmp1, unpack->operands[0]->variable_referenced());
187 }
188
189 EXPECT_TRUE(instructions->is_empty());
190 }
191
TEST_F(expand_source,uint64_variable)192 TEST_F(expand_source, uint64_variable)
193 {
194 const glsl_type *const type = glsl_type::uint64_t_type;
195 ir_dereference_variable *const deref = create_variable(mem_ctx, type);
196
197 lower_64bit::expand_source(*body, deref, expanded_src);
198
199 check_expanded_source(type, expanded_src);
200 check_instructions(&instructions, type, deref);
201 }
202
TEST_F(expand_source,u64vec2_variable)203 TEST_F(expand_source, u64vec2_variable)
204 {
205 const glsl_type *const type = glsl_type::u64vec2_type;
206 ir_dereference_variable *const deref = create_variable(mem_ctx, type);
207
208 lower_64bit::expand_source(*body, deref, expanded_src);
209
210 check_expanded_source(type, expanded_src);
211 check_instructions(&instructions, type, deref);
212 }
213
TEST_F(expand_source,u64vec3_variable)214 TEST_F(expand_source, u64vec3_variable)
215 {
216 const glsl_type *const type = glsl_type::u64vec3_type;
217
218 /* Generate an operand that is a scalar variable dereference. */
219 ir_variable *const var = new(mem_ctx) ir_variable(type,
220 "variable",
221 ir_var_temporary);
222
223 ir_dereference_variable *const deref =
224 new(mem_ctx) ir_dereference_variable(var);
225
226 lower_64bit::expand_source(*body, deref, expanded_src);
227
228 check_expanded_source(type, expanded_src);
229 check_instructions(&instructions, type, deref);
230 }
231
TEST_F(expand_source,u64vec4_variable)232 TEST_F(expand_source, u64vec4_variable)
233 {
234 const glsl_type *const type = glsl_type::u64vec4_type;
235 ir_dereference_variable *const deref = create_variable(mem_ctx, type);
236
237 lower_64bit::expand_source(*body, deref, expanded_src);
238
239 check_expanded_source(type, expanded_src);
240 check_instructions(&instructions, type, deref);
241 }
242
TEST_F(expand_source,int64_variable)243 TEST_F(expand_source, int64_variable)
244 {
245 const glsl_type *const type = glsl_type::int64_t_type;
246 ir_dereference_variable *const deref = create_variable(mem_ctx, type);
247
248 lower_64bit::expand_source(*body, deref, expanded_src);
249
250 check_expanded_source(type, expanded_src);
251 check_instructions(&instructions, type, deref);
252 }
253
TEST_F(expand_source,i64vec2_variable)254 TEST_F(expand_source, i64vec2_variable)
255 {
256 const glsl_type *const type = glsl_type::i64vec2_type;
257 ir_dereference_variable *const deref = create_variable(mem_ctx, type);
258
259 lower_64bit::expand_source(*body, deref, expanded_src);
260
261 check_expanded_source(type, expanded_src);
262 check_instructions(&instructions, type, deref);
263 }
264
TEST_F(expand_source,i64vec3_variable)265 TEST_F(expand_source, i64vec3_variable)
266 {
267 const glsl_type *const type = glsl_type::i64vec3_type;
268 ir_dereference_variable *const deref = create_variable(mem_ctx, type);
269
270 lower_64bit::expand_source(*body, deref, expanded_src);
271
272 check_expanded_source(type, expanded_src);
273 check_instructions(&instructions, type, deref);
274 }
275
TEST_F(expand_source,i64vec4_variable)276 TEST_F(expand_source, i64vec4_variable)
277 {
278 const glsl_type *const type = glsl_type::i64vec4_type;
279 ir_dereference_variable *const deref = create_variable(mem_ctx, type);
280
281 lower_64bit::expand_source(*body, deref, expanded_src);
282
283 check_expanded_source(type, expanded_src);
284 check_instructions(&instructions, type, deref);
285 }
286
TEST_F(expand_source,uint64_expression)287 TEST_F(expand_source, uint64_expression)
288 {
289 const glsl_type *const type = glsl_type::uint64_t_type;
290 ir_expression *const expr = create_expression(mem_ctx, type);
291
292 lower_64bit::expand_source(*body, expr, expanded_src);
293
294 check_expanded_source(type, expanded_src);
295 check_instructions(&instructions, type, expr);
296 }
297
TEST_F(expand_source,u64vec2_expression)298 TEST_F(expand_source, u64vec2_expression)
299 {
300 const glsl_type *const type = glsl_type::u64vec2_type;
301 ir_expression *const expr = create_expression(mem_ctx, type);
302
303 lower_64bit::expand_source(*body, expr, expanded_src);
304
305 check_expanded_source(type, expanded_src);
306 check_instructions(&instructions, type, expr);
307 }
308
TEST_F(expand_source,u64vec3_expression)309 TEST_F(expand_source, u64vec3_expression)
310 {
311 const glsl_type *const type = glsl_type::u64vec3_type;
312 ir_expression *const expr = create_expression(mem_ctx, type);
313
314 lower_64bit::expand_source(*body, expr, expanded_src);
315
316 check_expanded_source(type, expanded_src);
317 check_instructions(&instructions, type, expr);
318 }
319
TEST_F(expand_source,u64vec4_expression)320 TEST_F(expand_source, u64vec4_expression)
321 {
322 const glsl_type *const type = glsl_type::u64vec4_type;
323 ir_expression *const expr = create_expression(mem_ctx, type);
324
325 lower_64bit::expand_source(*body, expr, expanded_src);
326
327 check_expanded_source(type, expanded_src);
328 check_instructions(&instructions, type, expr);
329 }
330
TEST_F(expand_source,int64_expression)331 TEST_F(expand_source, int64_expression)
332 {
333 const glsl_type *const type = glsl_type::int64_t_type;
334 ir_expression *const expr = create_expression(mem_ctx, type);
335
336 lower_64bit::expand_source(*body, expr, expanded_src);
337
338 check_expanded_source(type, expanded_src);
339 check_instructions(&instructions, type, expr);
340 }
341
TEST_F(expand_source,i64vec2_expression)342 TEST_F(expand_source, i64vec2_expression)
343 {
344 const glsl_type *const type = glsl_type::i64vec2_type;
345 ir_expression *const expr = create_expression(mem_ctx, type);
346
347 lower_64bit::expand_source(*body, expr, expanded_src);
348
349 check_expanded_source(type, expanded_src);
350 check_instructions(&instructions, type, expr);
351 }
352
TEST_F(expand_source,i64vec3_expression)353 TEST_F(expand_source, i64vec3_expression)
354 {
355 const glsl_type *const type = glsl_type::i64vec3_type;
356 ir_expression *const expr = create_expression(mem_ctx, type);
357
358 lower_64bit::expand_source(*body, expr, expanded_src);
359
360 check_expanded_source(type, expanded_src);
361 check_instructions(&instructions, type, expr);
362 }
363
TEST_F(expand_source,i64vec4_expression)364 TEST_F(expand_source, i64vec4_expression)
365 {
366 const glsl_type *const type = glsl_type::i64vec4_type;
367 ir_expression *const expr = create_expression(mem_ctx, type);
368
369 lower_64bit::expand_source(*body, expr, expanded_src);
370
371 check_expanded_source(type, expanded_src);
372 check_instructions(&instructions, type, expr);
373 }
374
375 class compact_destination : public ::testing::Test {
376 public:
377 virtual void SetUp();
378 virtual void TearDown();
379
380 exec_list instructions;
381 ir_factory *body;
382 ir_variable *expanded_src[4];
383 void *mem_ctx;
384 };
385
386 void
SetUp()387 compact_destination::SetUp()
388 {
389 mem_ctx = ralloc_context(NULL);
390
391 memset(expanded_src, 0, sizeof(expanded_src));
392 instructions.make_empty();
393 body = new ir_factory(&instructions, mem_ctx);
394 }
395
396 void
TearDown()397 compact_destination::TearDown()
398 {
399 delete body;
400 body = NULL;
401
402 ralloc_free(mem_ctx);
403 mem_ctx = NULL;
404 }
405
TEST_F(compact_destination,uint64)406 TEST_F(compact_destination, uint64)
407 {
408 const glsl_type *const type = glsl_type::uint64_t_type;
409
410 for (unsigned i = 0; i < type->vector_elements; i++) {
411 expanded_src[i] = new(mem_ctx) ir_variable(glsl_type::uvec2_type,
412 "result",
413 ir_var_temporary);
414 }
415
416 ir_dereference_variable *deref =
417 lower_64bit::compact_destination(*body,
418 type,
419 expanded_src);
420
421 ASSERT_EQ(ir_type_dereference_variable, deref->ir_type);
422 EXPECT_EQ(type, deref->var->type) <<
423 " Got " <<
424 deref->var->type->name <<
425 ", expected " <<
426 type->name;
427
428 ir_instruction *ir;
429
430 ASSERT_FALSE(instructions.is_empty());
431 ir = (ir_instruction *) instructions.pop_head();
432 ir_variable *const var = ir->as_variable();
433 ASSERT_NE((void *)0, var);
434 EXPECT_EQ(deref->var, var);
435
436 for (unsigned i = 0; i < type->vector_elements; i++) {
437 ASSERT_FALSE(instructions.is_empty());
438 ir = (ir_instruction *) instructions.pop_head();
439 ir_assignment *const assign = ir->as_assignment();
440 ASSERT_NE((void *)0, assign);
441 EXPECT_EQ(deref->var, assign->lhs->variable_referenced());
442 }
443 }
444