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
30using namespace ir_builder;
31
32namespace lower_64bit {
33void expand_source(ir_factory &body,
34                   ir_rvalue *val,
35                   ir_variable **expanded_src);
36
37ir_dereference_variable *compact_destination(ir_factory &body,
38                                             const glsl_type *type,
39                                             ir_variable *result[4]);
40
41ir_rvalue *lower_op_to_function_call(ir_instruction *base_ir,
42                                     ir_expression *ir,
43                                     ir_function_signature *callee);
44};
45
46class expand_source : public ::testing::Test {
47public:
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
57void
58expand_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
69void
70expand_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
81static ir_dereference_variable *
82create_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
91static ir_expression *
92create_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
98static void
99check_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
125static void
126check_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
193TEST_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
204TEST_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
215TEST_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
233TEST_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
244TEST_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
255TEST_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
266TEST_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
277TEST_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
288TEST_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
299TEST_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
310TEST_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
321TEST_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
332TEST_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
343TEST_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
354TEST_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
365TEST_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
376class compact_destination : public ::testing::Test {
377public:
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
387void
388compact_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
397void
398compact_destination::TearDown()
399{
400   delete body;
401   body = NULL;
402
403   ralloc_free(mem_ctx);
404   mem_ctx = NULL;
405}
406
407TEST_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