• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* -*- mesa-c++  -*-
2  *
3  * Copyright (c) 2022 Collabora LTD
4  *
5  * Author: Gert Wollny <gert.wollny@collabora.com>
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * on the rights to use, copy, modify, merge, publish, distribute, sub
11  * license, and/or sell copies of the Software, and to permit persons to whom
12  * the Software is furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the next
15  * paragraph) shall be included in all copies or substantial portions of the
16  * Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21  * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
22  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24  * USE OR OTHER DEALINGS IN THE SOFTWARE.
25  */
26 
27 #include "sfn_nir_lower_alu.h"
28 
29 #include "sfn_nir.h"
30 
31 namespace r600 {
32 
33 class Lower2x16 : public NirLowerInstruction {
34 private:
35    bool filter(const nir_instr *instr) const override;
36    nir_def *lower(nir_instr *instr) override;
37 };
38 
39 bool
filter(const nir_instr * instr) const40 Lower2x16::filter(const nir_instr *instr) const
41 {
42    if (instr->type != nir_instr_type_alu)
43       return false;
44    auto alu = nir_instr_as_alu(instr);
45    switch (alu->op) {
46    case nir_op_unpack_half_2x16:
47    case nir_op_pack_half_2x16:
48       return true;
49    default:
50       return false;
51    }
52 }
53 
54 nir_def *
lower(nir_instr * instr)55 Lower2x16::lower(nir_instr *instr)
56 {
57    nir_alu_instr *alu = nir_instr_as_alu(instr);
58 
59    switch (alu->op) {
60    case nir_op_unpack_half_2x16: {
61       nir_def *packed = nir_ssa_for_alu_src(b, alu, 0);
62       return nir_vec2(b,
63                       nir_unpack_half_2x16_split_x(b, packed),
64                       nir_unpack_half_2x16_split_y(b, packed));
65    }
66    case nir_op_pack_half_2x16: {
67       nir_def *src_vec2 = nir_ssa_for_alu_src(b, alu, 0);
68       return nir_pack_half_2x16_split(b,
69                                       nir_channel(b, src_vec2, 0),
70                                       nir_channel(b, src_vec2, 1));
71    }
72    default:
73       unreachable("Lower2x16 filter doesn't filter correctly");
74    }
75 }
76 
77 class LowerSinCos : public NirLowerInstruction {
78 public:
LowerSinCos(amd_gfx_level gxf_level)79    LowerSinCos(amd_gfx_level gxf_level):
80        m_gxf_level(gxf_level)
81    {
82    }
83 
84 private:
85    bool filter(const nir_instr *instr) const override;
86    nir_def *lower(nir_instr *instr) override;
87    amd_gfx_level m_gxf_level;
88 };
89 
90 bool
filter(const nir_instr * instr) const91 LowerSinCos::filter(const nir_instr *instr) const
92 {
93    if (instr->type != nir_instr_type_alu)
94       return false;
95 
96    auto alu = nir_instr_as_alu(instr);
97    switch (alu->op) {
98    case nir_op_fsin:
99    case nir_op_fcos:
100       return true;
101    default:
102       return false;
103    }
104 }
105 
106 nir_def *
lower(nir_instr * instr)107 LowerSinCos::lower(nir_instr *instr)
108 {
109    auto alu = nir_instr_as_alu(instr);
110 
111    assert(alu->op == nir_op_fsin || alu->op == nir_op_fcos);
112 
113    auto fract = nir_ffract(b,
114                            nir_ffma_imm12(b,
115                                           nir_ssa_for_alu_src(b, alu, 0),
116                                           0.15915494,
117                                           0.5));
118 
119    auto normalized =
120       m_gxf_level != R600
121          ? nir_fadd_imm(b, fract, -0.5)
122          : nir_ffma_imm12(b, fract, 2.0f * M_PI, -M_PI);
123 
124    if (alu->op == nir_op_fsin)
125       return nir_fsin_amd(b, normalized);
126    else
127       return nir_fcos_amd(b, normalized);
128 }
129 
130 class FixKcacheIndirectRead : public NirLowerInstruction {
131 private:
132    bool filter(const nir_instr *instr) const override;
133    nir_def *lower(nir_instr *instr) override;
134 };
135 
filter(const nir_instr * instr) const136 bool FixKcacheIndirectRead::filter(const nir_instr *instr) const
137 {
138    if (instr->type != nir_instr_type_intrinsic)
139       return false;
140 
141    auto intr = nir_instr_as_intrinsic(instr);
142    if (intr->intrinsic != nir_intrinsic_load_ubo)
143       return false;
144 
145    return nir_src_as_const_value(intr->src[0]) == nullptr;
146 }
147 
lower(nir_instr * instr)148 nir_def *FixKcacheIndirectRead::lower(nir_instr *instr)
149 {
150    auto intr = nir_instr_as_intrinsic(instr);
151    assert(nir_src_as_const_value(intr->src[0]) == nullptr);
152 
153    nir_def *result = &intr->def;
154    for (unsigned i = 14; i < b->shader->info.num_ubos; ++i) {
155       auto test_bufid = nir_imm_int(b, i);
156       auto direct_value =
157 	    nir_load_ubo(b, intr->num_components,
158 			 intr->def.bit_size,
159 			 test_bufid,
160 			 intr->src[1].ssa);
161       auto direct_load = nir_instr_as_intrinsic(direct_value->parent_instr);
162       nir_intrinsic_copy_const_indices(direct_load, intr);
163       result = nir_bcsel(b,
164 			 nir_ieq(b, test_bufid, intr->src[0].ssa),
165 	                 direct_value,
166 	                 result);
167    }
168    return result;
169 }
170 
171 } // namespace r600
172 
173 bool
r600_nir_lower_pack_unpack_2x16(nir_shader * shader)174 r600_nir_lower_pack_unpack_2x16(nir_shader *shader)
175 {
176    return r600::Lower2x16().run(shader);
177 }
178 
179 bool
r600_nir_lower_trigen(nir_shader * shader,amd_gfx_level gfx_level)180 r600_nir_lower_trigen(nir_shader *shader, amd_gfx_level gfx_level)
181 {
182    return r600::LowerSinCos(gfx_level).run(shader);
183 }
184 
185 bool
r600_nir_fix_kcache_indirect_access(nir_shader * shader)186 r600_nir_fix_kcache_indirect_access(nir_shader *shader)
187 {
188    return shader->info.num_ubos > 14 ?
189 	    r600::FixKcacheIndirectRead().run(shader) : false;
190 }
191