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