1 /* -*- mesa-c++ -*-
2 * Copyright 2022 Collabora LTD
3 * Author: Gert Wollny <[email protected]>
4 * SPDX-License-Identifier: MIT
5 */
6
7 #include "sfn_nir_lower_alu.h"
8
9 #include "sfn_nir.h"
10
11 namespace r600 {
12
13 class Lower2x16 : public NirLowerInstruction {
14 private:
15 bool filter(const nir_instr *instr) const override;
16 nir_def *lower(nir_instr *instr) override;
17 };
18
19 bool
filter(const nir_instr * instr) const20 Lower2x16::filter(const nir_instr *instr) const
21 {
22 if (instr->type != nir_instr_type_alu)
23 return false;
24 auto alu = nir_instr_as_alu(instr);
25 switch (alu->op) {
26 case nir_op_unpack_half_2x16:
27 case nir_op_pack_half_2x16:
28 return true;
29 default:
30 return false;
31 }
32 }
33
34 nir_def *
lower(nir_instr * instr)35 Lower2x16::lower(nir_instr *instr)
36 {
37 nir_alu_instr *alu = nir_instr_as_alu(instr);
38
39 switch (alu->op) {
40 case nir_op_unpack_half_2x16: {
41 nir_def *packed = nir_ssa_for_alu_src(b, alu, 0);
42 return nir_vec2(b,
43 nir_unpack_half_2x16_split_x(b, packed),
44 nir_unpack_half_2x16_split_y(b, packed));
45 }
46 case nir_op_pack_half_2x16: {
47 nir_def *src_vec2 = nir_ssa_for_alu_src(b, alu, 0);
48 return nir_pack_half_2x16_split(b,
49 nir_channel(b, src_vec2, 0),
50 nir_channel(b, src_vec2, 1));
51 }
52 default:
53 unreachable("Lower2x16 filter doesn't filter correctly");
54 }
55 }
56
57 class LowerSinCos : public NirLowerInstruction {
58 public:
LowerSinCos(amd_gfx_level gxf_level)59 LowerSinCos(amd_gfx_level gxf_level):
60 m_gxf_level(gxf_level)
61 {
62 }
63
64 private:
65 bool filter(const nir_instr *instr) const override;
66 nir_def *lower(nir_instr *instr) override;
67 amd_gfx_level m_gxf_level;
68 };
69
70 bool
filter(const nir_instr * instr) const71 LowerSinCos::filter(const nir_instr *instr) const
72 {
73 if (instr->type != nir_instr_type_alu)
74 return false;
75
76 auto alu = nir_instr_as_alu(instr);
77 switch (alu->op) {
78 case nir_op_fsin:
79 case nir_op_fcos:
80 return true;
81 default:
82 return false;
83 }
84 }
85
86 nir_def *
lower(nir_instr * instr)87 LowerSinCos::lower(nir_instr *instr)
88 {
89 auto alu = nir_instr_as_alu(instr);
90
91 assert(alu->op == nir_op_fsin || alu->op == nir_op_fcos);
92
93 auto fract = nir_ffract(b,
94 nir_ffma_imm12(b,
95 nir_ssa_for_alu_src(b, alu, 0),
96 0.15915494,
97 0.5));
98
99 auto normalized =
100 m_gxf_level != R600
101 ? nir_fadd_imm(b, fract, -0.5)
102 : nir_ffma_imm12(b, fract, 2.0f * M_PI, -M_PI);
103
104 if (alu->op == nir_op_fsin)
105 return nir_fsin_amd(b, normalized);
106 else
107 return nir_fcos_amd(b, normalized);
108 }
109
110 class FixKcacheIndirectRead : public NirLowerInstruction {
111 private:
112 bool filter(const nir_instr *instr) const override;
113 nir_def *lower(nir_instr *instr) override;
114 };
115
filter(const nir_instr * instr) const116 bool FixKcacheIndirectRead::filter(const nir_instr *instr) const
117 {
118 if (instr->type != nir_instr_type_intrinsic)
119 return false;
120
121 auto intr = nir_instr_as_intrinsic(instr);
122 if (intr->intrinsic != nir_intrinsic_load_ubo)
123 return false;
124
125 return nir_src_as_const_value(intr->src[0]) == nullptr;
126 }
127
lower(nir_instr * instr)128 nir_def *FixKcacheIndirectRead::lower(nir_instr *instr)
129 {
130 auto intr = nir_instr_as_intrinsic(instr);
131 assert(nir_src_as_const_value(intr->src[0]) == nullptr);
132
133 nir_def *result = &intr->def;
134 for (unsigned i = 14; i < b->shader->info.num_ubos; ++i) {
135 auto test_bufid = nir_imm_int(b, i);
136 auto direct_value =
137 nir_load_ubo(b, intr->num_components,
138 intr->def.bit_size,
139 test_bufid,
140 intr->src[1].ssa);
141 auto direct_load = nir_instr_as_intrinsic(direct_value->parent_instr);
142 nir_intrinsic_copy_const_indices(direct_load, intr);
143 result = nir_bcsel(b,
144 nir_ieq(b, test_bufid, intr->src[0].ssa),
145 direct_value,
146 result);
147 }
148 return result;
149 }
150
151 } // namespace r600
152
153 bool
r600_nir_lower_pack_unpack_2x16(nir_shader * shader)154 r600_nir_lower_pack_unpack_2x16(nir_shader *shader)
155 {
156 return r600::Lower2x16().run(shader);
157 }
158
159 bool
r600_nir_lower_trigen(nir_shader * shader,amd_gfx_level gfx_level)160 r600_nir_lower_trigen(nir_shader *shader, amd_gfx_level gfx_level)
161 {
162 return r600::LowerSinCos(gfx_level).run(shader);
163 }
164
165 bool
r600_nir_fix_kcache_indirect_access(nir_shader * shader)166 r600_nir_fix_kcache_indirect_access(nir_shader *shader)
167 {
168 return shader->info.num_ubos > 14 ?
169 r600::FixKcacheIndirectRead().run(shader) : false;
170 }
171