1 #include "ir3_nir.h"
2
3 #include "nir.h"
4 #include "nir_search.h"
5 #include "nir_search_helpers.h"
6
7 #ifndef NIR_OPT_ALGEBRAIC_STRUCT_DEFS
8 #define NIR_OPT_ALGEBRAIC_STRUCT_DEFS
9
10 struct transform {
11 const nir_search_expression *search;
12 const nir_search_value *replace;
13 unsigned condition_offset;
14 };
15
16 #endif
17
18
19 static const nir_search_variable search1_0 = {
20 { nir_search_value_variable, 0 },
21 0, /* x */
22 false,
23 nir_type_invalid,
24 NULL,
25 };
26 static const nir_search_expression search1 = {
27 { nir_search_value_expression, 0 },
28 false,
29 nir_op_fcos,
30 { &search1_0.value },
31 NULL,
32 };
33
34 static const nir_search_constant replace1_0_0_0 = {
35 { nir_search_value_constant, 0 },
36 nir_type_float, { 0x401921fb3fa6defc /* 6.283185 */ },
37 };
38
39 static const nir_search_constant replace1_0_0_1_0_0_0 = {
40 { nir_search_value_constant, 0 },
41 nir_type_float, { 0x3fc45f30e7ff583a /* 0.159155 */ },
42 };
43
44 static const nir_search_variable replace1_0_0_1_0_0_1 = {
45 { nir_search_value_variable, 0 },
46 0, /* x */
47 false,
48 nir_type_invalid,
49 NULL,
50 };
51 static const nir_search_expression replace1_0_0_1_0_0 = {
52 { nir_search_value_expression, 0 },
53 false,
54 nir_op_fmul,
55 { &replace1_0_0_1_0_0_0.value, &replace1_0_0_1_0_0_1.value },
56 NULL,
57 };
58
59 static const nir_search_constant replace1_0_0_1_0_1 = {
60 { nir_search_value_constant, 0 },
61 nir_type_float, { 0x3fe0000000000000 /* 0.5 */ },
62 };
63 static const nir_search_expression replace1_0_0_1_0 = {
64 { nir_search_value_expression, 0 },
65 false,
66 nir_op_fadd,
67 { &replace1_0_0_1_0_0.value, &replace1_0_0_1_0_1.value },
68 NULL,
69 };
70 static const nir_search_expression replace1_0_0_1 = {
71 { nir_search_value_expression, 0 },
72 false,
73 nir_op_ffract,
74 { &replace1_0_0_1_0.value },
75 NULL,
76 };
77 static const nir_search_expression replace1_0_0 = {
78 { nir_search_value_expression, 0 },
79 false,
80 nir_op_fmul,
81 { &replace1_0_0_0.value, &replace1_0_0_1.value },
82 NULL,
83 };
84
85 static const nir_search_constant replace1_0_1 = {
86 { nir_search_value_constant, 0 },
87 nir_type_float, { 0x400921fb82c2bd7f /* 3.141593 */ },
88 };
89 static const nir_search_expression replace1_0 = {
90 { nir_search_value_expression, 0 },
91 false,
92 nir_op_fsub,
93 { &replace1_0_0.value, &replace1_0_1.value },
94 NULL,
95 };
96 static const nir_search_expression replace1 = {
97 { nir_search_value_expression, 0 },
98 false,
99 nir_op_fcos,
100 { &replace1_0.value },
101 NULL,
102 };
103
104 static const struct transform ir3_nir_apply_trig_workarounds_fcos_xforms[] = {
105 { &search1, &replace1.value, 0 },
106 };
107
108 static const nir_search_variable search0_0 = {
109 { nir_search_value_variable, 0 },
110 0, /* x */
111 false,
112 nir_type_invalid,
113 NULL,
114 };
115 static const nir_search_expression search0 = {
116 { nir_search_value_expression, 0 },
117 false,
118 nir_op_fsin,
119 { &search0_0.value },
120 NULL,
121 };
122
123 static const nir_search_constant replace0_0_0_0 = {
124 { nir_search_value_constant, 0 },
125 nir_type_float, { 0x401921fb3fa6defc /* 6.283185 */ },
126 };
127
128 static const nir_search_constant replace0_0_0_1_0_0_0 = {
129 { nir_search_value_constant, 0 },
130 nir_type_float, { 0x3fc45f30e7ff583a /* 0.159155 */ },
131 };
132
133 static const nir_search_variable replace0_0_0_1_0_0_1 = {
134 { nir_search_value_variable, 0 },
135 0, /* x */
136 false,
137 nir_type_invalid,
138 NULL,
139 };
140 static const nir_search_expression replace0_0_0_1_0_0 = {
141 { nir_search_value_expression, 0 },
142 false,
143 nir_op_fmul,
144 { &replace0_0_0_1_0_0_0.value, &replace0_0_0_1_0_0_1.value },
145 NULL,
146 };
147
148 static const nir_search_constant replace0_0_0_1_0_1 = {
149 { nir_search_value_constant, 0 },
150 nir_type_float, { 0x3fe0000000000000 /* 0.5 */ },
151 };
152 static const nir_search_expression replace0_0_0_1_0 = {
153 { nir_search_value_expression, 0 },
154 false,
155 nir_op_fadd,
156 { &replace0_0_0_1_0_0.value, &replace0_0_0_1_0_1.value },
157 NULL,
158 };
159 static const nir_search_expression replace0_0_0_1 = {
160 { nir_search_value_expression, 0 },
161 false,
162 nir_op_ffract,
163 { &replace0_0_0_1_0.value },
164 NULL,
165 };
166 static const nir_search_expression replace0_0_0 = {
167 { nir_search_value_expression, 0 },
168 false,
169 nir_op_fmul,
170 { &replace0_0_0_0.value, &replace0_0_0_1.value },
171 NULL,
172 };
173
174 static const nir_search_constant replace0_0_1 = {
175 { nir_search_value_constant, 0 },
176 nir_type_float, { 0x400921fb82c2bd7f /* 3.141593 */ },
177 };
178 static const nir_search_expression replace0_0 = {
179 { nir_search_value_expression, 0 },
180 false,
181 nir_op_fsub,
182 { &replace0_0_0.value, &replace0_0_1.value },
183 NULL,
184 };
185 static const nir_search_expression replace0 = {
186 { nir_search_value_expression, 0 },
187 false,
188 nir_op_fsin,
189 { &replace0_0.value },
190 NULL,
191 };
192
193 static const struct transform ir3_nir_apply_trig_workarounds_fsin_xforms[] = {
194 { &search0, &replace0.value, 0 },
195 };
196
197 static bool
ir3_nir_apply_trig_workarounds_block(nir_block * block,const bool * condition_flags,void * mem_ctx)198 ir3_nir_apply_trig_workarounds_block(nir_block *block, const bool *condition_flags,
199 void *mem_ctx)
200 {
201 bool progress = false;
202
203 nir_foreach_instr_reverse_safe(instr, block) {
204 if (instr->type != nir_instr_type_alu)
205 continue;
206
207 nir_alu_instr *alu = nir_instr_as_alu(instr);
208 if (!alu->dest.dest.is_ssa)
209 continue;
210
211 switch (alu->op) {
212 case nir_op_fcos:
213 for (unsigned i = 0; i < ARRAY_SIZE(ir3_nir_apply_trig_workarounds_fcos_xforms); i++) {
214 const struct transform *xform = &ir3_nir_apply_trig_workarounds_fcos_xforms[i];
215 if (condition_flags[xform->condition_offset] &&
216 nir_replace_instr(alu, xform->search, xform->replace,
217 mem_ctx)) {
218 progress = true;
219 break;
220 }
221 }
222 break;
223 case nir_op_fsin:
224 for (unsigned i = 0; i < ARRAY_SIZE(ir3_nir_apply_trig_workarounds_fsin_xforms); i++) {
225 const struct transform *xform = &ir3_nir_apply_trig_workarounds_fsin_xforms[i];
226 if (condition_flags[xform->condition_offset] &&
227 nir_replace_instr(alu, xform->search, xform->replace,
228 mem_ctx)) {
229 progress = true;
230 break;
231 }
232 }
233 break;
234 default:
235 break;
236 }
237 }
238
239 return progress;
240 }
241
242 static bool
ir3_nir_apply_trig_workarounds_impl(nir_function_impl * impl,const bool * condition_flags)243 ir3_nir_apply_trig_workarounds_impl(nir_function_impl *impl, const bool *condition_flags)
244 {
245 void *mem_ctx = ralloc_parent(impl);
246 bool progress = false;
247
248 nir_foreach_block_reverse(block, impl) {
249 progress |= ir3_nir_apply_trig_workarounds_block(block, condition_flags, mem_ctx);
250 }
251
252 if (progress)
253 nir_metadata_preserve(impl, nir_metadata_block_index |
254 nir_metadata_dominance);
255
256 return progress;
257 }
258
259
260 bool
ir3_nir_apply_trig_workarounds(nir_shader * shader)261 ir3_nir_apply_trig_workarounds(nir_shader *shader)
262 {
263 bool progress = false;
264 bool condition_flags[1];
265 const nir_shader_compiler_options *options = shader->options;
266 (void) options;
267
268 condition_flags[0] = true;
269
270 nir_foreach_function(function, shader) {
271 if (function->impl)
272 progress |= ir3_nir_apply_trig_workarounds_impl(function->impl, condition_flags);
273 }
274
275 return progress;
276 }
277
278