xref: /aosp_15_r20/external/mesa3d/src/nouveau/compiler/nak/opt_bar_prop.rs (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 // Copyright © 2023 Collabora, Ltd.
2 // SPDX-License-Identifier: MIT
3 
4 use crate::api::{GetDebugFlags, DEBUG};
5 use crate::ir::*;
6 
7 use compiler::bitset::BitSet;
8 use std::collections::HashMap;
9 
10 struct PhiMap {
11     phi_ssa: HashMap<u32, Vec<SSAValue>>,
12     ssa_phi: HashMap<SSAValue, u32>,
13 }
14 
15 impl PhiMap {
new() -> PhiMap16     pub fn new() -> PhiMap {
17         PhiMap {
18             ssa_phi: HashMap::new(),
19             phi_ssa: HashMap::new(),
20         }
21     }
22 
add_phi_srcs(&mut self, op: &OpPhiSrcs)23     fn add_phi_srcs(&mut self, op: &OpPhiSrcs) {
24         for (idx, src) in op.srcs.iter() {
25             if let SrcRef::SSA(ssa) = &src.src_ref {
26                 assert!(ssa.comps() == 1);
27                 let phi_srcs = self.phi_ssa.entry(*idx).or_default();
28                 phi_srcs.push(ssa[0]);
29             }
30         }
31     }
32 
add_phi_dsts(&mut self, op: &OpPhiDsts)33     fn add_phi_dsts(&mut self, op: &OpPhiDsts) {
34         for (idx, dst) in op.dsts.iter() {
35             if let Dst::SSA(ssa) = dst {
36                 assert!(ssa.comps() == 1);
37                 self.ssa_phi.insert(ssa[0], *idx);
38             }
39         }
40     }
41 
get_phi(&self, ssa: &SSAValue) -> Option<&u32>42     fn get_phi(&self, ssa: &SSAValue) -> Option<&u32> {
43         self.ssa_phi.get(ssa)
44     }
45 
phi_srcs(&self, idx: &u32) -> &[SSAValue]46     fn phi_srcs(&self, idx: &u32) -> &[SSAValue] {
47         self.phi_ssa.get(idx).unwrap()
48     }
49 }
50 
51 struct BarPropPass {
52     ssa_map: HashMap<SSAValue, SSAValue>,
53     phi_is_bar: BitSet,
54     phi_is_not_bar: BitSet,
55 }
56 
57 impl BarPropPass {
new() -> BarPropPass58     pub fn new() -> BarPropPass {
59         BarPropPass {
60             ssa_map: HashMap::new(),
61             phi_is_bar: BitSet::new(),
62             phi_is_not_bar: BitSet::new(),
63         }
64     }
65 
add_copy(&mut self, dst: SSAValue, src: SSAValue)66     fn add_copy(&mut self, dst: SSAValue, src: SSAValue) {
67         assert!(dst.file() == RegFile::Bar || src.file() == RegFile::Bar);
68         self.ssa_map.insert(dst, src);
69     }
70 
is_bar(&self, ssa: &SSAValue) -> bool71     fn is_bar(&self, ssa: &SSAValue) -> bool {
72         ssa.file() == RegFile::Bar || self.ssa_map.contains_key(ssa)
73     }
74 
map_bar<'a>(&'a self, ssa: &'a SSAValue) -> Option<&SSAValue>75     fn map_bar<'a>(&'a self, ssa: &'a SSAValue) -> Option<&SSAValue> {
76         let mut ssa = ssa;
77         let mut last_bar = None;
78         loop {
79             let Some(mapped) = self.ssa_map.get(ssa) else {
80                 break;
81             };
82 
83             if mapped.file() == RegFile::Bar {
84                 last_bar = Some(mapped);
85             }
86             ssa = mapped;
87         }
88 
89         last_bar
90     }
91 
phi_can_be_bar_recur( &mut self, phi_map: &PhiMap, seen: &mut BitSet, phi: u32, ) -> bool92     fn phi_can_be_bar_recur(
93         &mut self,
94         phi_map: &PhiMap,
95         seen: &mut BitSet,
96         phi: u32,
97     ) -> bool {
98         if self.phi_is_not_bar.get(phi.try_into().unwrap()) {
99             return false;
100         }
101 
102         if seen.get(phi.try_into().unwrap()) {
103             // If we've hit a cycle, that's not a fail
104             return true;
105         }
106 
107         seen.insert(phi.try_into().unwrap());
108 
109         for src_ssa in phi_map.phi_srcs(&phi) {
110             if self.is_bar(src_ssa) {
111                 continue;
112             }
113 
114             if let Some(src_phi) = phi_map.get_phi(src_ssa) {
115                 if self.phi_can_be_bar_recur(phi_map, seen, *src_phi) {
116                     continue;
117                 }
118             }
119 
120             self.phi_is_not_bar.insert(phi.try_into().unwrap());
121             return false;
122         }
123 
124         true
125     }
126 
add_phi_recur( &mut self, ssa_alloc: &mut SSAValueAllocator, phi_map: &PhiMap, needs_bar: &mut BitSet, phi: u32, ssa: SSAValue, )127     fn add_phi_recur(
128         &mut self,
129         ssa_alloc: &mut SSAValueAllocator,
130         phi_map: &PhiMap,
131         needs_bar: &mut BitSet,
132         phi: u32,
133         ssa: SSAValue,
134     ) {
135         if !needs_bar.get(phi.try_into().unwrap()) {
136             return;
137         }
138 
139         let bar = ssa_alloc.alloc(RegFile::Bar);
140         self.ssa_map.insert(ssa, bar);
141         self.phi_is_bar.insert(phi.try_into().unwrap());
142         needs_bar.remove(phi.try_into().unwrap());
143 
144         for src_ssa in phi_map.phi_srcs(&phi) {
145             if let Some(src_phi) = phi_map.get_phi(src_ssa) {
146                 self.add_phi_recur(
147                     ssa_alloc, phi_map, needs_bar, *src_phi, *src_ssa,
148                 );
149             }
150         }
151     }
152 
try_add_phi( &mut self, ssa_alloc: &mut SSAValueAllocator, phi_map: &PhiMap, phi: u32, ssa: SSAValue, )153     fn try_add_phi(
154         &mut self,
155         ssa_alloc: &mut SSAValueAllocator,
156         phi_map: &PhiMap,
157         phi: u32,
158         ssa: SSAValue,
159     ) {
160         if self.phi_is_bar.get(phi.try_into().unwrap()) {
161             return;
162         }
163 
164         let mut seen = BitSet::new();
165         if self.phi_can_be_bar_recur(phi_map, &mut seen, phi) {
166             self.add_phi_recur(ssa_alloc, phi_map, &mut seen, phi, ssa);
167             assert!(seen.is_empty());
168         }
169     }
170 
run(&mut self, f: &mut Function)171     fn run(&mut self, f: &mut Function) {
172         let mut phi_map = PhiMap::new();
173         let mut phis_want_bar = Vec::new();
174         for b in &f.blocks {
175             for instr in &b.instrs {
176                 match &instr.op {
177                     Op::PhiSrcs(op) => {
178                         phi_map.add_phi_srcs(op);
179                     }
180                     Op::PhiDsts(op) => {
181                         phi_map.add_phi_dsts(op);
182                     }
183                     Op::BMov(op) => {
184                         assert!(!op.clear);
185                         assert!(op.src.src_mod.is_none());
186                         let dst = op.dst.as_ssa().unwrap();
187                         let src = op.src.as_ssa().unwrap();
188                         assert!(dst.comps() == 1 && src.comps() == 1);
189 
190                         self.add_copy(dst[0], src[0]);
191 
192                         if let Some(phi) = phi_map.get_phi(&src[0]) {
193                             phis_want_bar.push((*phi, src[0]));
194                         }
195                     }
196                     _ => (),
197                 }
198             }
199         }
200 
201         for (phi, ssa) in phis_want_bar.drain(..) {
202             self.try_add_phi(&mut f.ssa_alloc, &phi_map, phi, ssa);
203         }
204 
205         f.map_instrs(|mut instr, _| {
206             match &mut instr.op {
207                 Op::PhiSrcs(op) => {
208                     for (idx, src) in op.srcs.iter_mut() {
209                         if self.phi_is_bar.get((*idx).try_into().unwrap()) {
210                             // Barrier immediates don't exist
211                             let ssa = src.as_ssa().unwrap();
212                             let bar = *self.map_bar(&ssa[0]).unwrap();
213                             *src = bar.into();
214                         }
215                     }
216                     MappedInstrs::One(instr)
217                 }
218                 Op::PhiDsts(op) => {
219                     let mut bmovs = Vec::new();
220                     for (idx, dst) in op.dsts.iter_mut() {
221                         if self.phi_is_bar.get((*idx).try_into().unwrap()) {
222                             let ssa = *dst.as_ssa().unwrap();
223                             let bar = *self.ssa_map.get(&ssa[0]).unwrap();
224                             *dst = bar.into();
225 
226                             // On the off chance that someone still wants the
227                             // GPR version of this barrier, insert an OpBMov to
228                             // copy into the GPR.  DCE will clean it up if it's
229                             // never used.
230                             bmovs.push(Instr::new_boxed(OpBMov {
231                                 dst: ssa.into(),
232                                 src: bar.into(),
233                                 clear: false,
234                             }));
235                         }
236                     }
237                     if bmovs.is_empty() {
238                         MappedInstrs::One(instr)
239                     } else {
240                         if DEBUG.annotate() {
241                             bmovs.insert(
242                                 0,
243                                 Instr::new_boxed(OpAnnotate {
244                                     annotation: "generated by opt_bar_prop"
245                                         .into(),
246                                 }),
247                             );
248                         }
249                         bmovs.insert(1, instr);
250                         MappedInstrs::Many(bmovs)
251                     }
252                 }
253                 _ => {
254                     let src_types = instr.src_types();
255                     for (i, src) in instr.srcs_mut().iter_mut().enumerate() {
256                         if src_types[i] != SrcType::Bar {
257                             continue;
258                         }
259                         if let SrcRef::SSA(ssa) = &src.src_ref {
260                             if let Some(bar) = self.map_bar(&ssa[0]) {
261                                 *src = (*bar).into();
262                             }
263                         };
264                     }
265                     MappedInstrs::One(instr)
266                 }
267             }
268         });
269     }
270 }
271 
272 impl Shader<'_> {
opt_bar_prop(&mut self)273     pub fn opt_bar_prop(&mut self) {
274         for f in &mut self.functions {
275             BarPropPass::new().run(f);
276         }
277     }
278 }
279