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