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