1 #include "brw_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_variable replace1_0_0 = {
35 { nir_search_value_variable, 0 },
36 0, /* x */
37 false,
38 nir_type_invalid,
39 NULL,
40 };
41 static const nir_search_expression replace1_0 = {
42 { nir_search_value_expression, 0 },
43 false,
44 nir_op_fcos,
45 { &replace1_0_0.value },
46 NULL,
47 };
48
49 static const nir_search_constant replace1_1 = {
50 { nir_search_value_constant, 0 },
51 nir_type_float, { 0x3fefffc115df6556 /* 0.99997 */ },
52 };
53 static const nir_search_expression replace1 = {
54 { nir_search_value_expression, 0 },
55 false,
56 nir_op_fmul,
57 { &replace1_0.value, &replace1_1.value },
58 NULL,
59 };
60
61 static const struct transform brw_nir_apply_trig_workarounds_fcos_xforms[] = {
62 { &search1, &replace1.value, 0 },
63 };
64
65 static const nir_search_variable search0_0 = {
66 { nir_search_value_variable, 0 },
67 0, /* x */
68 false,
69 nir_type_invalid,
70 NULL,
71 };
72 static const nir_search_expression search0 = {
73 { nir_search_value_expression, 0 },
74 false,
75 nir_op_fsin,
76 { &search0_0.value },
77 NULL,
78 };
79
80 static const nir_search_variable replace0_0_0 = {
81 { nir_search_value_variable, 0 },
82 0, /* x */
83 false,
84 nir_type_invalid,
85 NULL,
86 };
87 static const nir_search_expression replace0_0 = {
88 { nir_search_value_expression, 0 },
89 false,
90 nir_op_fsin,
91 { &replace0_0_0.value },
92 NULL,
93 };
94
95 static const nir_search_constant replace0_1 = {
96 { nir_search_value_constant, 0 },
97 nir_type_float, { 0x3fefffc115df6556 /* 0.99997 */ },
98 };
99 static const nir_search_expression replace0 = {
100 { nir_search_value_expression, 0 },
101 false,
102 nir_op_fmul,
103 { &replace0_0.value, &replace0_1.value },
104 NULL,
105 };
106
107 static const struct transform brw_nir_apply_trig_workarounds_fsin_xforms[] = {
108 { &search0, &replace0.value, 0 },
109 };
110
111 static bool
brw_nir_apply_trig_workarounds_block(nir_block * block,const bool * condition_flags,void * mem_ctx)112 brw_nir_apply_trig_workarounds_block(nir_block *block, const bool *condition_flags,
113 void *mem_ctx)
114 {
115 bool progress = false;
116
117 nir_foreach_instr_reverse_safe(instr, block) {
118 if (instr->type != nir_instr_type_alu)
119 continue;
120
121 nir_alu_instr *alu = nir_instr_as_alu(instr);
122 if (!alu->dest.dest.is_ssa)
123 continue;
124
125 switch (alu->op) {
126 case nir_op_fcos:
127 for (unsigned i = 0; i < ARRAY_SIZE(brw_nir_apply_trig_workarounds_fcos_xforms); i++) {
128 const struct transform *xform = &brw_nir_apply_trig_workarounds_fcos_xforms[i];
129 if (condition_flags[xform->condition_offset] &&
130 nir_replace_instr(alu, xform->search, xform->replace,
131 mem_ctx)) {
132 progress = true;
133 break;
134 }
135 }
136 break;
137 case nir_op_fsin:
138 for (unsigned i = 0; i < ARRAY_SIZE(brw_nir_apply_trig_workarounds_fsin_xforms); i++) {
139 const struct transform *xform = &brw_nir_apply_trig_workarounds_fsin_xforms[i];
140 if (condition_flags[xform->condition_offset] &&
141 nir_replace_instr(alu, xform->search, xform->replace,
142 mem_ctx)) {
143 progress = true;
144 break;
145 }
146 }
147 break;
148 default:
149 break;
150 }
151 }
152
153 return progress;
154 }
155
156 static bool
brw_nir_apply_trig_workarounds_impl(nir_function_impl * impl,const bool * condition_flags)157 brw_nir_apply_trig_workarounds_impl(nir_function_impl *impl, const bool *condition_flags)
158 {
159 void *mem_ctx = ralloc_parent(impl);
160 bool progress = false;
161
162 nir_foreach_block_reverse(block, impl) {
163 progress |= brw_nir_apply_trig_workarounds_block(block, condition_flags, mem_ctx);
164 }
165
166 if (progress)
167 nir_metadata_preserve(impl, nir_metadata_block_index |
168 nir_metadata_dominance);
169
170 return progress;
171 }
172
173
174 bool
brw_nir_apply_trig_workarounds(nir_shader * shader)175 brw_nir_apply_trig_workarounds(nir_shader *shader)
176 {
177 bool progress = false;
178 bool condition_flags[1];
179 const nir_shader_compiler_options *options = shader->options;
180 (void) options;
181
182 condition_flags[0] = true;
183
184 nir_foreach_function(function, shader) {
185 if (function->impl)
186 progress |= brw_nir_apply_trig_workarounds_impl(function->impl, condition_flags);
187 }
188
189 return progress;
190 }
191
192