mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-02-11 05:10:27 +01:00
This will allow us later to store builtin names in a different way. Reviewed-by: Adam Jackson <ajax@redhat.com> Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/25191>
443 lines
13 KiB
C++
443 lines
13 KiB
C++
/*
|
|
* Copyright © 2013 Intel Corporation
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice (including the next
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
* Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
#include <gtest/gtest.h>
|
|
#include "util/compiler.h"
|
|
#include "main/macros.h"
|
|
#include "ir.h"
|
|
#include "ir_builder.h"
|
|
|
|
using namespace ir_builder;
|
|
|
|
namespace lower_64bit {
|
|
void expand_source(ir_factory &body,
|
|
ir_rvalue *val,
|
|
ir_variable **expanded_src);
|
|
|
|
ir_dereference_variable *compact_destination(ir_factory &body,
|
|
const glsl_type *type,
|
|
ir_variable *result[4]);
|
|
|
|
ir_rvalue *lower_op_to_function_call(ir_instruction *base_ir,
|
|
ir_expression *ir,
|
|
ir_function_signature *callee);
|
|
};
|
|
|
|
class expand_source : public ::testing::Test {
|
|
public:
|
|
virtual void SetUp();
|
|
virtual void TearDown();
|
|
|
|
exec_list instructions;
|
|
ir_factory *body;
|
|
ir_variable *expanded_src[4];
|
|
void *mem_ctx;
|
|
};
|
|
|
|
void
|
|
expand_source::SetUp()
|
|
{
|
|
glsl_type_singleton_init_or_ref();
|
|
|
|
mem_ctx = ralloc_context(NULL);
|
|
|
|
memset(expanded_src, 0, sizeof(expanded_src));
|
|
instructions.make_empty();
|
|
body = new ir_factory(&instructions, mem_ctx);
|
|
}
|
|
|
|
void
|
|
expand_source::TearDown()
|
|
{
|
|
delete body;
|
|
body = NULL;
|
|
|
|
ralloc_free(mem_ctx);
|
|
mem_ctx = NULL;
|
|
|
|
glsl_type_singleton_decref();
|
|
}
|
|
|
|
static ir_dereference_variable *
|
|
create_variable(void *mem_ctx, const glsl_type *type)
|
|
{
|
|
ir_variable *var = new(mem_ctx) ir_variable(type,
|
|
"variable",
|
|
ir_var_temporary);
|
|
|
|
return new(mem_ctx) ir_dereference_variable(var);
|
|
}
|
|
|
|
static ir_expression *
|
|
create_expression(void *mem_ctx, const glsl_type *type)
|
|
{
|
|
return new(mem_ctx) ir_expression(ir_unop_neg,
|
|
create_variable(mem_ctx, type));
|
|
}
|
|
|
|
static void
|
|
check_expanded_source(const glsl_type *type,
|
|
ir_variable *expanded_src[4])
|
|
{
|
|
const glsl_type *const expanded_type =
|
|
type->base_type == GLSL_TYPE_UINT64
|
|
? glsl_type::uvec2_type :glsl_type::ivec2_type;
|
|
|
|
for (int i = 0; i < type->vector_elements; i++) {
|
|
EXPECT_EQ(expanded_type, expanded_src[i]->type);
|
|
|
|
/* All elements that are part of the vector must be unique. */
|
|
for (int j = i - 1; j >= 0; j--) {
|
|
EXPECT_NE(expanded_src[i], expanded_src[j])
|
|
<< " Element " << i << " is the same as element " << j;
|
|
}
|
|
}
|
|
|
|
/* All elements that are not part of the vector must be the same as element
|
|
* 0. This is primarily for scalars (where every element is the same).
|
|
*/
|
|
for (int i = type->vector_elements; i < 4; i++) {
|
|
EXPECT_EQ(expanded_src[0], expanded_src[i])
|
|
<< " Element " << i << " should be the same as element 0";
|
|
}
|
|
}
|
|
|
|
static void
|
|
check_instructions(exec_list *instructions,
|
|
const glsl_type *type,
|
|
const ir_instruction *source)
|
|
{
|
|
const glsl_type *const expanded_type =
|
|
type->base_type == GLSL_TYPE_UINT64
|
|
? glsl_type::uvec2_type : glsl_type::ivec2_type;
|
|
|
|
const ir_expression_operation unpack_opcode =
|
|
type->base_type == GLSL_TYPE_UINT64
|
|
? ir_unop_unpack_uint_2x32 : ir_unop_unpack_int_2x32;
|
|
|
|
ir_instruction *ir;
|
|
|
|
/* The instruction list should contain IR to represent:
|
|
*
|
|
* type tmp1;
|
|
* tmp1 = source;
|
|
* uvec2 tmp2;
|
|
* tmp2 = unpackUint2x32(tmp1.x);
|
|
* uvec2 tmp3;
|
|
* tmp3 = unpackUint2x32(tmp1.y);
|
|
* uvec2 tmp4;
|
|
* tmp4 = unpackUint2x32(tmp1.z);
|
|
* uvec2 tmp5;
|
|
* tmp5 = unpackUint2x32(tmp1.w);
|
|
*/
|
|
ASSERT_FALSE(instructions->is_empty());
|
|
ir = (ir_instruction *) instructions->pop_head();
|
|
ir_variable *const tmp1 = ir->as_variable();
|
|
EXPECT_EQ(ir_type_variable, ir->ir_type);
|
|
EXPECT_EQ(type, tmp1->type) <<
|
|
" Got " <<
|
|
glsl_get_type_name(tmp1->type) <<
|
|
", expected " <<
|
|
glsl_get_type_name(type);
|
|
|
|
ASSERT_FALSE(instructions->is_empty());
|
|
ir = (ir_instruction *) instructions->pop_head();
|
|
ir_assignment *const assign1 = ir->as_assignment();
|
|
EXPECT_EQ(ir_type_assignment, ir->ir_type);
|
|
ASSERT_NE((void *)0, assign1);
|
|
EXPECT_EQ(tmp1, assign1->lhs->variable_referenced());
|
|
EXPECT_EQ(source, assign1->rhs);
|
|
|
|
for (unsigned i = 0; i < type->vector_elements; i++) {
|
|
ASSERT_FALSE(instructions->is_empty());
|
|
ir = (ir_instruction *) instructions->pop_head();
|
|
ir_variable *const tmp2 = ir->as_variable();
|
|
EXPECT_EQ(ir_type_variable, ir->ir_type);
|
|
EXPECT_EQ(expanded_type, tmp2->type);
|
|
|
|
ASSERT_FALSE(instructions->is_empty());
|
|
ir = (ir_instruction *) instructions->pop_head();
|
|
ir_assignment *const assign2 = ir->as_assignment();
|
|
EXPECT_EQ(ir_type_assignment, ir->ir_type);
|
|
ASSERT_NE((void *)0, assign2);
|
|
EXPECT_EQ(tmp2, assign2->lhs->variable_referenced());
|
|
ir_expression *unpack = assign2->rhs->as_expression();
|
|
ASSERT_NE((void *)0, unpack);
|
|
EXPECT_EQ(unpack_opcode, unpack->operation);
|
|
EXPECT_EQ(tmp1, unpack->operands[0]->variable_referenced());
|
|
}
|
|
|
|
EXPECT_TRUE(instructions->is_empty());
|
|
}
|
|
|
|
TEST_F(expand_source, uint64_variable)
|
|
{
|
|
const glsl_type *const type = glsl_type::uint64_t_type;
|
|
ir_dereference_variable *const deref = create_variable(mem_ctx, type);
|
|
|
|
lower_64bit::expand_source(*body, deref, expanded_src);
|
|
|
|
check_expanded_source(type, expanded_src);
|
|
check_instructions(&instructions, type, deref);
|
|
}
|
|
|
|
TEST_F(expand_source, u64vec2_variable)
|
|
{
|
|
const glsl_type *const type = glsl_type::u64vec2_type;
|
|
ir_dereference_variable *const deref = create_variable(mem_ctx, type);
|
|
|
|
lower_64bit::expand_source(*body, deref, expanded_src);
|
|
|
|
check_expanded_source(type, expanded_src);
|
|
check_instructions(&instructions, type, deref);
|
|
}
|
|
|
|
TEST_F(expand_source, u64vec3_variable)
|
|
{
|
|
const glsl_type *const type = glsl_type::u64vec3_type;
|
|
|
|
/* Generate an operand that is a scalar variable dereference. */
|
|
ir_variable *const var = new(mem_ctx) ir_variable(type,
|
|
"variable",
|
|
ir_var_temporary);
|
|
|
|
ir_dereference_variable *const deref =
|
|
new(mem_ctx) ir_dereference_variable(var);
|
|
|
|
lower_64bit::expand_source(*body, deref, expanded_src);
|
|
|
|
check_expanded_source(type, expanded_src);
|
|
check_instructions(&instructions, type, deref);
|
|
}
|
|
|
|
TEST_F(expand_source, u64vec4_variable)
|
|
{
|
|
const glsl_type *const type = glsl_type::u64vec4_type;
|
|
ir_dereference_variable *const deref = create_variable(mem_ctx, type);
|
|
|
|
lower_64bit::expand_source(*body, deref, expanded_src);
|
|
|
|
check_expanded_source(type, expanded_src);
|
|
check_instructions(&instructions, type, deref);
|
|
}
|
|
|
|
TEST_F(expand_source, int64_variable)
|
|
{
|
|
const glsl_type *const type = glsl_type::int64_t_type;
|
|
ir_dereference_variable *const deref = create_variable(mem_ctx, type);
|
|
|
|
lower_64bit::expand_source(*body, deref, expanded_src);
|
|
|
|
check_expanded_source(type, expanded_src);
|
|
check_instructions(&instructions, type, deref);
|
|
}
|
|
|
|
TEST_F(expand_source, i64vec2_variable)
|
|
{
|
|
const glsl_type *const type = glsl_type::i64vec2_type;
|
|
ir_dereference_variable *const deref = create_variable(mem_ctx, type);
|
|
|
|
lower_64bit::expand_source(*body, deref, expanded_src);
|
|
|
|
check_expanded_source(type, expanded_src);
|
|
check_instructions(&instructions, type, deref);
|
|
}
|
|
|
|
TEST_F(expand_source, i64vec3_variable)
|
|
{
|
|
const glsl_type *const type = glsl_type::i64vec3_type;
|
|
ir_dereference_variable *const deref = create_variable(mem_ctx, type);
|
|
|
|
lower_64bit::expand_source(*body, deref, expanded_src);
|
|
|
|
check_expanded_source(type, expanded_src);
|
|
check_instructions(&instructions, type, deref);
|
|
}
|
|
|
|
TEST_F(expand_source, i64vec4_variable)
|
|
{
|
|
const glsl_type *const type = glsl_type::i64vec4_type;
|
|
ir_dereference_variable *const deref = create_variable(mem_ctx, type);
|
|
|
|
lower_64bit::expand_source(*body, deref, expanded_src);
|
|
|
|
check_expanded_source(type, expanded_src);
|
|
check_instructions(&instructions, type, deref);
|
|
}
|
|
|
|
TEST_F(expand_source, uint64_expression)
|
|
{
|
|
const glsl_type *const type = glsl_type::uint64_t_type;
|
|
ir_expression *const expr = create_expression(mem_ctx, type);
|
|
|
|
lower_64bit::expand_source(*body, expr, expanded_src);
|
|
|
|
check_expanded_source(type, expanded_src);
|
|
check_instructions(&instructions, type, expr);
|
|
}
|
|
|
|
TEST_F(expand_source, u64vec2_expression)
|
|
{
|
|
const glsl_type *const type = glsl_type::u64vec2_type;
|
|
ir_expression *const expr = create_expression(mem_ctx, type);
|
|
|
|
lower_64bit::expand_source(*body, expr, expanded_src);
|
|
|
|
check_expanded_source(type, expanded_src);
|
|
check_instructions(&instructions, type, expr);
|
|
}
|
|
|
|
TEST_F(expand_source, u64vec3_expression)
|
|
{
|
|
const glsl_type *const type = glsl_type::u64vec3_type;
|
|
ir_expression *const expr = create_expression(mem_ctx, type);
|
|
|
|
lower_64bit::expand_source(*body, expr, expanded_src);
|
|
|
|
check_expanded_source(type, expanded_src);
|
|
check_instructions(&instructions, type, expr);
|
|
}
|
|
|
|
TEST_F(expand_source, u64vec4_expression)
|
|
{
|
|
const glsl_type *const type = glsl_type::u64vec4_type;
|
|
ir_expression *const expr = create_expression(mem_ctx, type);
|
|
|
|
lower_64bit::expand_source(*body, expr, expanded_src);
|
|
|
|
check_expanded_source(type, expanded_src);
|
|
check_instructions(&instructions, type, expr);
|
|
}
|
|
|
|
TEST_F(expand_source, int64_expression)
|
|
{
|
|
const glsl_type *const type = glsl_type::int64_t_type;
|
|
ir_expression *const expr = create_expression(mem_ctx, type);
|
|
|
|
lower_64bit::expand_source(*body, expr, expanded_src);
|
|
|
|
check_expanded_source(type, expanded_src);
|
|
check_instructions(&instructions, type, expr);
|
|
}
|
|
|
|
TEST_F(expand_source, i64vec2_expression)
|
|
{
|
|
const glsl_type *const type = glsl_type::i64vec2_type;
|
|
ir_expression *const expr = create_expression(mem_ctx, type);
|
|
|
|
lower_64bit::expand_source(*body, expr, expanded_src);
|
|
|
|
check_expanded_source(type, expanded_src);
|
|
check_instructions(&instructions, type, expr);
|
|
}
|
|
|
|
TEST_F(expand_source, i64vec3_expression)
|
|
{
|
|
const glsl_type *const type = glsl_type::i64vec3_type;
|
|
ir_expression *const expr = create_expression(mem_ctx, type);
|
|
|
|
lower_64bit::expand_source(*body, expr, expanded_src);
|
|
|
|
check_expanded_source(type, expanded_src);
|
|
check_instructions(&instructions, type, expr);
|
|
}
|
|
|
|
TEST_F(expand_source, i64vec4_expression)
|
|
{
|
|
const glsl_type *const type = glsl_type::i64vec4_type;
|
|
ir_expression *const expr = create_expression(mem_ctx, type);
|
|
|
|
lower_64bit::expand_source(*body, expr, expanded_src);
|
|
|
|
check_expanded_source(type, expanded_src);
|
|
check_instructions(&instructions, type, expr);
|
|
}
|
|
|
|
class compact_destination : public ::testing::Test {
|
|
public:
|
|
virtual void SetUp();
|
|
virtual void TearDown();
|
|
|
|
exec_list instructions;
|
|
ir_factory *body;
|
|
ir_variable *expanded_src[4];
|
|
void *mem_ctx;
|
|
};
|
|
|
|
void
|
|
compact_destination::SetUp()
|
|
{
|
|
mem_ctx = ralloc_context(NULL);
|
|
|
|
memset(expanded_src, 0, sizeof(expanded_src));
|
|
instructions.make_empty();
|
|
body = new ir_factory(&instructions, mem_ctx);
|
|
}
|
|
|
|
void
|
|
compact_destination::TearDown()
|
|
{
|
|
delete body;
|
|
body = NULL;
|
|
|
|
ralloc_free(mem_ctx);
|
|
mem_ctx = NULL;
|
|
}
|
|
|
|
TEST_F(compact_destination, uint64)
|
|
{
|
|
const glsl_type *const type = glsl_type::uint64_t_type;
|
|
|
|
for (unsigned i = 0; i < type->vector_elements; i++) {
|
|
expanded_src[i] = new(mem_ctx) ir_variable(glsl_type::uvec2_type,
|
|
"result",
|
|
ir_var_temporary);
|
|
}
|
|
|
|
ir_dereference_variable *deref =
|
|
lower_64bit::compact_destination(*body,
|
|
type,
|
|
expanded_src);
|
|
|
|
ASSERT_EQ(ir_type_dereference_variable, deref->ir_type);
|
|
EXPECT_EQ(type, deref->var->type) <<
|
|
" Got " <<
|
|
glsl_get_type_name(deref->var->type) <<
|
|
", expected " <<
|
|
glsl_get_type_name(type);
|
|
|
|
ir_instruction *ir;
|
|
|
|
ASSERT_FALSE(instructions.is_empty());
|
|
ir = (ir_instruction *) instructions.pop_head();
|
|
ir_variable *const var = ir->as_variable();
|
|
ASSERT_NE((void *)0, var);
|
|
EXPECT_EQ(deref->var, var);
|
|
|
|
for (unsigned i = 0; i < type->vector_elements; i++) {
|
|
ASSERT_FALSE(instructions.is_empty());
|
|
ir = (ir_instruction *) instructions.pop_head();
|
|
ir_assignment *const assign = ir->as_assignment();
|
|
ASSERT_NE((void *)0, assign);
|
|
EXPECT_EQ(deref->var, assign->lhs->variable_referenced());
|
|
}
|
|
}
|