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
29using namespace ir_builder;
30
31namespace lower_64bit {
32void expand_source(ir_factory &body,
33                   ir_rvalue *val,
34                   ir_variable **expanded_src);
35
36ir_dereference_variable *compact_destination(ir_factory &body,
37                                             const glsl_type *type,
38                                             ir_variable *result[4]);
39
40ir_rvalue *lower_op_to_function_call(ir_instruction *base_ir,
41                                     ir_expression *ir,
42                                     ir_function_signature *callee);
43};
44
45class expand_source : public ::testing::Test {
46public:
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
56void
57expand_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
68void
69expand_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
80static ir_dereference_variable *
81create_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
90static ir_expression *
91create_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
97static void
98check_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
124static void
125check_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
192TEST_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
203TEST_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
214TEST_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
232TEST_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
243TEST_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
254TEST_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
265TEST_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
276TEST_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
287TEST_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
298TEST_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
309TEST_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
320TEST_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
331TEST_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
342TEST_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
353TEST_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
364TEST_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
375class compact_destination : public ::testing::Test {
376public:
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
386void
387compact_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
396void
397compact_destination::TearDown()
398{
399   delete body;
400   body = NULL;
401
402   ralloc_free(mem_ctx);
403   mem_ctx = NULL;
404}
405
406TEST_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