| /* |
| * Copyright © 2012 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 "brw_vec4.h" |
| #include "brw_vs.h" |
| #include "program/program.h" |
| |
| using namespace brw; |
| |
| int ret = 0; |
| |
| #define register_coalesce(v) _register_coalesce(v, __func__) |
| |
| class register_coalesce_test : public ::testing::Test { |
| virtual void SetUp(); |
| |
| public: |
| struct brw_compiler *compiler; |
| struct gen_device_info *devinfo; |
| struct gl_context *ctx; |
| struct gl_shader_program *shader_prog; |
| struct brw_vue_prog_data *prog_data; |
| vec4_visitor *v; |
| }; |
| |
| |
| class register_coalesce_vec4_visitor : public vec4_visitor |
| { |
| public: |
| register_coalesce_vec4_visitor(struct brw_compiler *compiler, |
| nir_shader *shader, |
| struct brw_vue_prog_data *prog_data) |
| : vec4_visitor(compiler, NULL, NULL, prog_data, shader, NULL, |
| false /* no_spills */, -1) |
| { |
| prog_data->dispatch_mode = DISPATCH_MODE_4X2_DUAL_OBJECT; |
| } |
| |
| protected: |
| virtual dst_reg *make_reg_for_system_value(int location) |
| { |
| unreachable("Not reached"); |
| } |
| |
| virtual void setup_payload() |
| { |
| unreachable("Not reached"); |
| } |
| |
| virtual void emit_prolog() |
| { |
| unreachable("Not reached"); |
| } |
| |
| virtual void emit_thread_end() |
| { |
| unreachable("Not reached"); |
| } |
| |
| virtual void emit_urb_write_header(int mrf) |
| { |
| unreachable("Not reached"); |
| } |
| |
| virtual vec4_instruction *emit_urb_write_opcode(bool complete) |
| { |
| unreachable("Not reached"); |
| } |
| }; |
| |
| |
| void register_coalesce_test::SetUp() |
| { |
| ctx = (struct gl_context *)calloc(1, sizeof(*ctx)); |
| compiler = (struct brw_compiler *)calloc(1, sizeof(*compiler)); |
| devinfo = (struct gen_device_info *)calloc(1, sizeof(*devinfo)); |
| prog_data = (struct brw_vue_prog_data *)calloc(1, sizeof(*prog_data)); |
| compiler->devinfo = devinfo; |
| |
| nir_shader *shader = |
| nir_shader_create(NULL, MESA_SHADER_VERTEX, NULL, NULL); |
| |
| v = new register_coalesce_vec4_visitor(compiler, shader, prog_data); |
| |
| devinfo->gen = 4; |
| } |
| |
| static void |
| _register_coalesce(vec4_visitor *v, const char *func) |
| { |
| bool print = false; |
| |
| if (print) { |
| printf("%s: instructions before:\n", func); |
| v->dump_instructions(); |
| } |
| |
| v->calculate_cfg(); |
| v->opt_register_coalesce(); |
| |
| if (print) { |
| printf("%s: instructions after:\n", func); |
| v->dump_instructions(); |
| } |
| } |
| |
| TEST_F(register_coalesce_test, test_compute_to_mrf) |
| { |
| src_reg something = src_reg(v, glsl_type::float_type); |
| dst_reg temp = dst_reg(v, glsl_type::float_type); |
| dst_reg init; |
| |
| dst_reg m0 = dst_reg(MRF, 0); |
| m0.writemask = WRITEMASK_X; |
| m0.type = BRW_REGISTER_TYPE_F; |
| |
| vec4_instruction *mul = v->emit(v->MUL(temp, something, brw_imm_f(1.0f))); |
| v->emit(v->MOV(m0, src_reg(temp))); |
| |
| register_coalesce(v); |
| |
| EXPECT_EQ(mul->dst.file, MRF); |
| } |
| |
| |
| TEST_F(register_coalesce_test, test_multiple_use) |
| { |
| src_reg something = src_reg(v, glsl_type::float_type); |
| dst_reg temp = dst_reg(v, glsl_type::vec4_type); |
| dst_reg init; |
| |
| dst_reg m0 = dst_reg(MRF, 0); |
| m0.writemask = WRITEMASK_X; |
| m0.type = BRW_REGISTER_TYPE_F; |
| |
| dst_reg m1 = dst_reg(MRF, 1); |
| m1.writemask = WRITEMASK_XYZW; |
| m1.type = BRW_REGISTER_TYPE_F; |
| |
| src_reg src = src_reg(temp); |
| vec4_instruction *mul = v->emit(v->MUL(temp, something, brw_imm_f(1.0f))); |
| src.swizzle = BRW_SWIZZLE_XXXX; |
| v->emit(v->MOV(m0, src)); |
| src.swizzle = BRW_SWIZZLE_XYZW; |
| v->emit(v->MOV(m1, src)); |
| |
| register_coalesce(v); |
| |
| EXPECT_NE(mul->dst.file, MRF); |
| } |
| |
| TEST_F(register_coalesce_test, test_dp4_mrf) |
| { |
| src_reg some_src_1 = src_reg(v, glsl_type::vec4_type); |
| src_reg some_src_2 = src_reg(v, glsl_type::vec4_type); |
| dst_reg init; |
| |
| dst_reg m0 = dst_reg(MRF, 0); |
| m0.writemask = WRITEMASK_Y; |
| m0.type = BRW_REGISTER_TYPE_F; |
| |
| dst_reg temp = dst_reg(v, glsl_type::float_type); |
| |
| vec4_instruction *dp4 = v->emit(v->DP4(temp, some_src_1, some_src_2)); |
| v->emit(v->MOV(m0, src_reg(temp))); |
| |
| register_coalesce(v); |
| |
| EXPECT_EQ(dp4->dst.file, MRF); |
| EXPECT_EQ(dp4->dst.writemask, WRITEMASK_Y); |
| } |
| |
| TEST_F(register_coalesce_test, test_dp4_grf) |
| { |
| src_reg some_src_1 = src_reg(v, glsl_type::vec4_type); |
| src_reg some_src_2 = src_reg(v, glsl_type::vec4_type); |
| dst_reg init; |
| |
| dst_reg to = dst_reg(v, glsl_type::vec4_type); |
| dst_reg temp = dst_reg(v, glsl_type::float_type); |
| |
| vec4_instruction *dp4 = v->emit(v->DP4(temp, some_src_1, some_src_2)); |
| to.writemask = WRITEMASK_Y; |
| v->emit(v->MOV(to, src_reg(temp))); |
| |
| /* if we don't do something with the result, the automatic dead code |
| * elimination will remove all our instructions. |
| */ |
| src_reg src = src_reg(to); |
| src.negate = true; |
| v->emit(v->MOV(dst_reg(MRF, 0), src)); |
| |
| register_coalesce(v); |
| |
| EXPECT_EQ(dp4->dst.nr, to.nr); |
| EXPECT_EQ(dp4->dst.writemask, WRITEMASK_Y); |
| } |
| |
| TEST_F(register_coalesce_test, test_channel_mul_grf) |
| { |
| src_reg some_src_1 = src_reg(v, glsl_type::vec4_type); |
| src_reg some_src_2 = src_reg(v, glsl_type::vec4_type); |
| dst_reg init; |
| |
| dst_reg to = dst_reg(v, glsl_type::vec4_type); |
| dst_reg temp = dst_reg(v, glsl_type::float_type); |
| |
| vec4_instruction *mul = v->emit(v->MUL(temp, some_src_1, some_src_2)); |
| to.writemask = WRITEMASK_Y; |
| v->emit(v->MOV(to, src_reg(temp))); |
| |
| /* if we don't do something with the result, the automatic dead code |
| * elimination will remove all our instructions. |
| */ |
| src_reg src = src_reg(to); |
| src.negate = true; |
| v->emit(v->MOV(dst_reg(MRF, 0), src)); |
| |
| register_coalesce(v); |
| |
| EXPECT_EQ(mul->dst.nr, to.nr); |
| } |