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
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   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
67void
68expand_source::TearDown()
69{
70   delete body;
71   body = NULL;
72
73   ralloc_free(mem_ctx);
74   mem_ctx = NULL;
75}
76
77static ir_dereference_variable *
78create_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
87static ir_expression *
88create_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
94static void
95check_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
121static void
122check_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
189TEST_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
200TEST_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
211TEST_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
229TEST_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
240TEST_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
251TEST_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
262TEST_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
273TEST_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
284TEST_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
295TEST_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
306TEST_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
317TEST_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
328TEST_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
339TEST_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
350TEST_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
361TEST_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
372class compact_destination : public ::testing::Test {
373public:
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
383void
384compact_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
393void
394compact_destination::TearDown()
395{
396   delete body;
397   body = NULL;
398
399   ralloc_free(mem_ctx);
400   mem_ctx = NULL;
401}
402
403TEST_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