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