1 /*
2 * Copyright 2023 Pavel Ondračka <pavel.ondracka@gmail.com>
3 * SPDX-License-Identifier: MIT
4 */
5
6 #ifndef R300_NIR_H
7 #define R300_NIR_H
8
9 #include <math.h>
10
11 #include "compiler/nir/nir.h"
12 #include "pipe/p_screen.h"
13
14 static inline bool
is_ubo_or_input(UNUSED struct hash_table * ht,const nir_alu_instr * instr,unsigned src,unsigned num_components,const uint8_t * swizzle)15 is_ubo_or_input(UNUSED struct hash_table *ht, const nir_alu_instr *instr, unsigned src,
16 unsigned num_components, const uint8_t *swizzle)
17 {
18 nir_instr *parent = instr->src[src].src.ssa->parent_instr;
19 if (parent->type != nir_instr_type_intrinsic)
20 return false;
21
22 nir_intrinsic_instr *intrinsic = nir_instr_as_intrinsic(parent);
23
24 switch (intrinsic->intrinsic) {
25 case nir_intrinsic_load_ubo_vec4:
26 case nir_intrinsic_load_input:
27 case nir_intrinsic_load_interpolated_input:
28 return true;
29 default:
30 return false;
31 }
32 }
33
34 static inline bool
is_not_used_in_single_if(const nir_alu_instr * instr)35 is_not_used_in_single_if(const nir_alu_instr *instr)
36 {
37 unsigned if_uses = 0;
38 nir_foreach_use (src, &instr->def) {
39 if (nir_src_is_if(src))
40 if_uses++;
41 else
42 return true;
43 }
44 return if_uses != 1;
45 }
46
47 static inline bool
is_only_used_by_intrinsic(const nir_alu_instr * instr,nir_intrinsic_op op)48 is_only_used_by_intrinsic(const nir_alu_instr *instr, nir_intrinsic_op op)
49 {
50 bool is_used = false;
51 nir_foreach_use(src, &instr->def) {
52 is_used = true;
53
54 nir_instr *user_instr = nir_src_parent_instr(src);
55 if (user_instr->type != nir_instr_type_intrinsic)
56 return false;
57
58 const nir_intrinsic_instr *const user_intrinsic = nir_instr_as_intrinsic(user_instr);
59
60 if (user_intrinsic->intrinsic != op)
61 return false;
62 }
63 return is_used;
64 }
65
66 static inline bool
is_only_used_by_load_ubo_vec4(const nir_alu_instr * instr)67 is_only_used_by_load_ubo_vec4(const nir_alu_instr *instr)
68 {
69 return is_only_used_by_intrinsic(instr, nir_intrinsic_load_ubo_vec4);
70 }
71
72 static inline bool
is_only_used_by_terminate_if(const nir_alu_instr * instr)73 is_only_used_by_terminate_if(const nir_alu_instr *instr)
74 {
75 return is_only_used_by_intrinsic(instr, nir_intrinsic_terminate_if);
76 }
77
78 static inline bool
check_instr_and_src_value(nir_op op,nir_instr ** instr,double value)79 check_instr_and_src_value(nir_op op, nir_instr **instr, double value)
80 {
81 if ((*instr)->type != nir_instr_type_alu)
82 return false;
83 nir_alu_instr *alu = nir_instr_as_alu(*instr);
84 if (alu->op != op)
85 return false;
86 unsigned i;
87 for (i = 0; i <= 2; i++) {
88 if (i == 2) {
89 return false;
90 }
91 nir_alu_src src = alu->src[i];
92 if (nir_src_is_const(src.src)) {
93 /* All components must be reading the same value. */
94 for (unsigned j = 0; j < alu->def.num_components - 1; j++) {
95 if (src.swizzle[j] != src.swizzle[j + 1]) {
96 return false;
97 }
98 }
99 if (fabs(nir_src_comp_as_float(src.src, src.swizzle[0]) - value) < 1e-5) {
100 break;
101 }
102 }
103 }
104 *instr = alu->src[1 - i].src.ssa->parent_instr;
105 return true;
106 }
107
108 static inline bool
needs_vs_trig_input_fixup(UNUSED struct hash_table * ht,const nir_alu_instr * instr,unsigned src,unsigned num_components,const uint8_t * swizzle)109 needs_vs_trig_input_fixup(UNUSED struct hash_table *ht, const nir_alu_instr *instr, unsigned src,
110 unsigned num_components, const uint8_t *swizzle)
111 {
112 /* We are checking for fadd(fmul(ffract(a), 2*pi), -pi) pattern
113 * emitted by us and also some wined3d shaders.
114 * Start with check for fadd(a, -pi).
115 */
116 nir_instr *parent = instr->src[src].src.ssa->parent_instr;
117 if (!check_instr_and_src_value(nir_op_fadd, &parent, -3.141592))
118 return true;
119 /* Now check for fmul(a, 2 * pi). */
120 if (!check_instr_and_src_value(nir_op_fmul, &parent, 6.283185))
121 return true;
122
123 /* Finally check for ffract(a). */
124 if (parent->type != nir_instr_type_alu)
125 return true;
126 nir_alu_instr *fract = nir_instr_as_alu(parent);
127 if (fract->op != nir_op_ffract)
128 return true;
129 return false;
130 }
131
132 bool r300_is_only_used_as_float(const nir_alu_instr *instr);
133
134 char *r300_finalize_nir(struct pipe_screen *pscreen, struct nir_shader *nir);
135
136 extern bool r300_transform_vs_trig_input(struct nir_shader *shader);
137
138 extern bool r300_transform_fs_trig_input(struct nir_shader *shader);
139
140 extern bool r300_nir_fuse_fround_d3d9(struct nir_shader *shader);
141
142 extern bool r300_nir_lower_bool_to_float(struct nir_shader *shader);
143
144 extern bool r300_nir_lower_bool_to_float_fs(struct nir_shader *shader);
145
146 extern bool r300_nir_prepare_presubtract(struct nir_shader *shader);
147
148 extern bool r300_nir_opt_algebraic_late(struct nir_shader *shader);
149
150 extern bool r300_nir_post_integer_lowering(struct nir_shader *shader);
151
152 extern bool r300_nir_lower_fcsel_r500(nir_shader *shader);
153
154 extern bool r300_nir_lower_fcsel_r300(nir_shader *shader);
155
156 extern bool r300_nir_lower_flrp(nir_shader *shader);
157
158 extern bool r300_nir_lower_comparison_fs(nir_shader *shader);
159
160 #endif /* R300_NIR_H */
161