xref: /aosp_15_r20/external/mesa3d/src/nouveau/compiler/nak/legalize.rs (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1*61046927SAndroid Build Coastguard Worker // Copyright © 2022 Collabora, Ltd.
2*61046927SAndroid Build Coastguard Worker // SPDX-License-Identifier: MIT
3*61046927SAndroid Build Coastguard Worker 
4*61046927SAndroid Build Coastguard Worker use crate::api::{GetDebugFlags, DEBUG};
5*61046927SAndroid Build Coastguard Worker use crate::ir::*;
6*61046927SAndroid Build Coastguard Worker use crate::liveness::{BlockLiveness, Liveness, SimpleLiveness};
7*61046927SAndroid Build Coastguard Worker 
8*61046927SAndroid Build Coastguard Worker use std::collections::{HashMap, HashSet};
9*61046927SAndroid Build Coastguard Worker 
10*61046927SAndroid Build Coastguard Worker pub type LegalizeBuilder<'a> = SSAInstrBuilder<'a>;
11*61046927SAndroid Build Coastguard Worker 
src_is_upred_reg(src: &Src) -> bool12*61046927SAndroid Build Coastguard Worker pub fn src_is_upred_reg(src: &Src) -> bool {
13*61046927SAndroid Build Coastguard Worker     match &src.src_ref {
14*61046927SAndroid Build Coastguard Worker         SrcRef::True | SrcRef::False => false,
15*61046927SAndroid Build Coastguard Worker         SrcRef::SSA(ssa) => {
16*61046927SAndroid Build Coastguard Worker             assert!(ssa.comps() == 1);
17*61046927SAndroid Build Coastguard Worker             match ssa[0].file() {
18*61046927SAndroid Build Coastguard Worker                 RegFile::Pred => false,
19*61046927SAndroid Build Coastguard Worker                 RegFile::UPred => true,
20*61046927SAndroid Build Coastguard Worker                 _ => panic!("Not a predicate source"),
21*61046927SAndroid Build Coastguard Worker             }
22*61046927SAndroid Build Coastguard Worker         }
23*61046927SAndroid Build Coastguard Worker         SrcRef::Reg(_) => panic!("Not in SSA form"),
24*61046927SAndroid Build Coastguard Worker         _ => panic!("Not a predicate source"),
25*61046927SAndroid Build Coastguard Worker     }
26*61046927SAndroid Build Coastguard Worker }
27*61046927SAndroid Build Coastguard Worker 
src_is_reg(src: &Src, reg_file: RegFile) -> bool28*61046927SAndroid Build Coastguard Worker pub fn src_is_reg(src: &Src, reg_file: RegFile) -> bool {
29*61046927SAndroid Build Coastguard Worker     match src.src_ref {
30*61046927SAndroid Build Coastguard Worker         SrcRef::Zero | SrcRef::True | SrcRef::False => true,
31*61046927SAndroid Build Coastguard Worker         SrcRef::SSA(ssa) => ssa.file() == Some(reg_file),
32*61046927SAndroid Build Coastguard Worker         SrcRef::Imm32(_) | SrcRef::CBuf(_) => false,
33*61046927SAndroid Build Coastguard Worker         SrcRef::Reg(_) => panic!("Not in SSA form"),
34*61046927SAndroid Build Coastguard Worker     }
35*61046927SAndroid Build Coastguard Worker }
36*61046927SAndroid Build Coastguard Worker 
swap_srcs_if_not_reg( x: &mut Src, y: &mut Src, reg_file: RegFile, ) -> bool37*61046927SAndroid Build Coastguard Worker pub fn swap_srcs_if_not_reg(
38*61046927SAndroid Build Coastguard Worker     x: &mut Src,
39*61046927SAndroid Build Coastguard Worker     y: &mut Src,
40*61046927SAndroid Build Coastguard Worker     reg_file: RegFile,
41*61046927SAndroid Build Coastguard Worker ) -> bool {
42*61046927SAndroid Build Coastguard Worker     if !src_is_reg(x, reg_file) && src_is_reg(y, reg_file) {
43*61046927SAndroid Build Coastguard Worker         std::mem::swap(x, y);
44*61046927SAndroid Build Coastguard Worker         true
45*61046927SAndroid Build Coastguard Worker     } else {
46*61046927SAndroid Build Coastguard Worker         false
47*61046927SAndroid Build Coastguard Worker     }
48*61046927SAndroid Build Coastguard Worker }
49*61046927SAndroid Build Coastguard Worker 
src_is_imm(src: &Src) -> bool50*61046927SAndroid Build Coastguard Worker fn src_is_imm(src: &Src) -> bool {
51*61046927SAndroid Build Coastguard Worker     matches!(src.src_ref, SrcRef::Imm32(_))
52*61046927SAndroid Build Coastguard Worker }
53*61046927SAndroid Build Coastguard Worker 
54*61046927SAndroid Build Coastguard Worker pub trait LegalizeBuildHelpers: SSABuilder {
copy_ssa(&mut self, ssa: &mut SSAValue, reg_file: RegFile)55*61046927SAndroid Build Coastguard Worker     fn copy_ssa(&mut self, ssa: &mut SSAValue, reg_file: RegFile) {
56*61046927SAndroid Build Coastguard Worker         let tmp = self.alloc_ssa(reg_file, 1)[0];
57*61046927SAndroid Build Coastguard Worker         self.copy_to(tmp.into(), (*ssa).into());
58*61046927SAndroid Build Coastguard Worker         *ssa = tmp;
59*61046927SAndroid Build Coastguard Worker     }
60*61046927SAndroid Build Coastguard Worker 
copy_ssa_ref(&mut self, vec: &mut SSARef, reg_file: RegFile)61*61046927SAndroid Build Coastguard Worker     fn copy_ssa_ref(&mut self, vec: &mut SSARef, reg_file: RegFile) {
62*61046927SAndroid Build Coastguard Worker         for ssa in &mut vec[..] {
63*61046927SAndroid Build Coastguard Worker             self.copy_ssa(ssa, reg_file);
64*61046927SAndroid Build Coastguard Worker         }
65*61046927SAndroid Build Coastguard Worker     }
66*61046927SAndroid Build Coastguard Worker 
copy_pred_ssa_if_uniform(&mut self, ssa: &mut SSAValue)67*61046927SAndroid Build Coastguard Worker     fn copy_pred_ssa_if_uniform(&mut self, ssa: &mut SSAValue) {
68*61046927SAndroid Build Coastguard Worker         match ssa.file() {
69*61046927SAndroid Build Coastguard Worker             RegFile::Pred => (),
70*61046927SAndroid Build Coastguard Worker             RegFile::UPred => self.copy_ssa(ssa, RegFile::Pred),
71*61046927SAndroid Build Coastguard Worker             _ => panic!("Not a predicate value"),
72*61046927SAndroid Build Coastguard Worker         }
73*61046927SAndroid Build Coastguard Worker     }
74*61046927SAndroid Build Coastguard Worker 
copy_pred_if_upred(&mut self, pred: &mut Pred)75*61046927SAndroid Build Coastguard Worker     fn copy_pred_if_upred(&mut self, pred: &mut Pred) {
76*61046927SAndroid Build Coastguard Worker         match &mut pred.pred_ref {
77*61046927SAndroid Build Coastguard Worker             PredRef::None => (),
78*61046927SAndroid Build Coastguard Worker             PredRef::SSA(ssa) => {
79*61046927SAndroid Build Coastguard Worker                 self.copy_pred_ssa_if_uniform(ssa);
80*61046927SAndroid Build Coastguard Worker             }
81*61046927SAndroid Build Coastguard Worker             PredRef::Reg(_) => panic!("Not in SSA form"),
82*61046927SAndroid Build Coastguard Worker         }
83*61046927SAndroid Build Coastguard Worker     }
84*61046927SAndroid Build Coastguard Worker 
copy_src_if_upred(&mut self, src: &mut Src)85*61046927SAndroid Build Coastguard Worker     fn copy_src_if_upred(&mut self, src: &mut Src) {
86*61046927SAndroid Build Coastguard Worker         match &mut src.src_ref {
87*61046927SAndroid Build Coastguard Worker             SrcRef::True | SrcRef::False => (),
88*61046927SAndroid Build Coastguard Worker             SrcRef::SSA(ssa) => {
89*61046927SAndroid Build Coastguard Worker                 assert!(ssa.comps() == 1);
90*61046927SAndroid Build Coastguard Worker                 self.copy_pred_ssa_if_uniform(&mut ssa[0]);
91*61046927SAndroid Build Coastguard Worker             }
92*61046927SAndroid Build Coastguard Worker             SrcRef::Reg(_) => panic!("Not in SSA form"),
93*61046927SAndroid Build Coastguard Worker             _ => panic!("Not a predicate source"),
94*61046927SAndroid Build Coastguard Worker         }
95*61046927SAndroid Build Coastguard Worker     }
96*61046927SAndroid Build Coastguard Worker 
copy_src_if_not_same_file(&mut self, src: &mut Src)97*61046927SAndroid Build Coastguard Worker     fn copy_src_if_not_same_file(&mut self, src: &mut Src) {
98*61046927SAndroid Build Coastguard Worker         let SrcRef::SSA(vec) = &mut src.src_ref else {
99*61046927SAndroid Build Coastguard Worker             return;
100*61046927SAndroid Build Coastguard Worker         };
101*61046927SAndroid Build Coastguard Worker 
102*61046927SAndroid Build Coastguard Worker         if vec.comps() == 1 {
103*61046927SAndroid Build Coastguard Worker             return;
104*61046927SAndroid Build Coastguard Worker         }
105*61046927SAndroid Build Coastguard Worker 
106*61046927SAndroid Build Coastguard Worker         let mut all_same = true;
107*61046927SAndroid Build Coastguard Worker         let file = vec[0].file();
108*61046927SAndroid Build Coastguard Worker         for i in 1..vec.comps() {
109*61046927SAndroid Build Coastguard Worker             let c_file = vec[usize::from(i)].file();
110*61046927SAndroid Build Coastguard Worker             if c_file != file {
111*61046927SAndroid Build Coastguard Worker                 debug_assert!(c_file.to_warp() == file.to_warp());
112*61046927SAndroid Build Coastguard Worker                 all_same = false;
113*61046927SAndroid Build Coastguard Worker             }
114*61046927SAndroid Build Coastguard Worker         }
115*61046927SAndroid Build Coastguard Worker 
116*61046927SAndroid Build Coastguard Worker         if !all_same {
117*61046927SAndroid Build Coastguard Worker             self.copy_ssa_ref(vec, file.to_warp());
118*61046927SAndroid Build Coastguard Worker         }
119*61046927SAndroid Build Coastguard Worker     }
120*61046927SAndroid Build Coastguard Worker 
copy_alu_src( &mut self, src: &mut Src, reg_file: RegFile, src_type: SrcType, )121*61046927SAndroid Build Coastguard Worker     fn copy_alu_src(
122*61046927SAndroid Build Coastguard Worker         &mut self,
123*61046927SAndroid Build Coastguard Worker         src: &mut Src,
124*61046927SAndroid Build Coastguard Worker         reg_file: RegFile,
125*61046927SAndroid Build Coastguard Worker         src_type: SrcType,
126*61046927SAndroid Build Coastguard Worker     ) {
127*61046927SAndroid Build Coastguard Worker         let val = match src_type {
128*61046927SAndroid Build Coastguard Worker             SrcType::GPR
129*61046927SAndroid Build Coastguard Worker             | SrcType::ALU
130*61046927SAndroid Build Coastguard Worker             | SrcType::F32
131*61046927SAndroid Build Coastguard Worker             | SrcType::F16
132*61046927SAndroid Build Coastguard Worker             | SrcType::F16v2
133*61046927SAndroid Build Coastguard Worker             | SrcType::I32
134*61046927SAndroid Build Coastguard Worker             | SrcType::B32 => self.alloc_ssa(reg_file, 1),
135*61046927SAndroid Build Coastguard Worker             SrcType::F64 => self.alloc_ssa(reg_file, 2),
136*61046927SAndroid Build Coastguard Worker             SrcType::Pred => self.alloc_ssa(reg_file, 1),
137*61046927SAndroid Build Coastguard Worker             _ => panic!("Unknown source type"),
138*61046927SAndroid Build Coastguard Worker         };
139*61046927SAndroid Build Coastguard Worker 
140*61046927SAndroid Build Coastguard Worker         if DEBUG.annotate() {
141*61046927SAndroid Build Coastguard Worker             self.push_instr(Instr::new_boxed(OpAnnotate {
142*61046927SAndroid Build Coastguard Worker                 annotation: "copy generated by legalizer".into(),
143*61046927SAndroid Build Coastguard Worker             }));
144*61046927SAndroid Build Coastguard Worker         }
145*61046927SAndroid Build Coastguard Worker 
146*61046927SAndroid Build Coastguard Worker         if val.comps() == 1 {
147*61046927SAndroid Build Coastguard Worker             self.copy_to(val.into(), src.src_ref.into());
148*61046927SAndroid Build Coastguard Worker         } else {
149*61046927SAndroid Build Coastguard Worker             match src.src_ref {
150*61046927SAndroid Build Coastguard Worker                 SrcRef::Imm32(u) => {
151*61046927SAndroid Build Coastguard Worker                     // Immediates go in the top bits
152*61046927SAndroid Build Coastguard Worker                     self.copy_to(val[0].into(), 0.into());
153*61046927SAndroid Build Coastguard Worker                     self.copy_to(val[1].into(), u.into());
154*61046927SAndroid Build Coastguard Worker                 }
155*61046927SAndroid Build Coastguard Worker                 SrcRef::CBuf(cb) => {
156*61046927SAndroid Build Coastguard Worker                     // CBufs load 8B
157*61046927SAndroid Build Coastguard Worker                     self.copy_to(val[0].into(), cb.into());
158*61046927SAndroid Build Coastguard Worker                     self.copy_to(val[1].into(), cb.offset(4).into());
159*61046927SAndroid Build Coastguard Worker                 }
160*61046927SAndroid Build Coastguard Worker                 SrcRef::SSA(vec) => {
161*61046927SAndroid Build Coastguard Worker                     assert!(vec.comps() == 2);
162*61046927SAndroid Build Coastguard Worker                     self.copy_to(val[0].into(), vec[0].into());
163*61046927SAndroid Build Coastguard Worker                     self.copy_to(val[1].into(), vec[1].into());
164*61046927SAndroid Build Coastguard Worker                 }
165*61046927SAndroid Build Coastguard Worker                 _ => panic!("Invalid 64-bit SrcRef"),
166*61046927SAndroid Build Coastguard Worker             }
167*61046927SAndroid Build Coastguard Worker         }
168*61046927SAndroid Build Coastguard Worker 
169*61046927SAndroid Build Coastguard Worker         src.src_ref = val.into();
170*61046927SAndroid Build Coastguard Worker     }
171*61046927SAndroid Build Coastguard Worker 
copy_alu_src_if_not_reg( &mut self, src: &mut Src, reg_file: RegFile, src_type: SrcType, )172*61046927SAndroid Build Coastguard Worker     fn copy_alu_src_if_not_reg(
173*61046927SAndroid Build Coastguard Worker         &mut self,
174*61046927SAndroid Build Coastguard Worker         src: &mut Src,
175*61046927SAndroid Build Coastguard Worker         reg_file: RegFile,
176*61046927SAndroid Build Coastguard Worker         src_type: SrcType,
177*61046927SAndroid Build Coastguard Worker     ) {
178*61046927SAndroid Build Coastguard Worker         if !src_is_reg(src, reg_file) {
179*61046927SAndroid Build Coastguard Worker             self.copy_alu_src(src, reg_file, src_type);
180*61046927SAndroid Build Coastguard Worker         }
181*61046927SAndroid Build Coastguard Worker     }
182*61046927SAndroid Build Coastguard Worker 
copy_alu_src_if_not_reg_or_imm( &mut self, src: &mut Src, reg_file: RegFile, src_type: SrcType, )183*61046927SAndroid Build Coastguard Worker     fn copy_alu_src_if_not_reg_or_imm(
184*61046927SAndroid Build Coastguard Worker         &mut self,
185*61046927SAndroid Build Coastguard Worker         src: &mut Src,
186*61046927SAndroid Build Coastguard Worker         reg_file: RegFile,
187*61046927SAndroid Build Coastguard Worker         src_type: SrcType,
188*61046927SAndroid Build Coastguard Worker     ) {
189*61046927SAndroid Build Coastguard Worker         if !src_is_reg(src, reg_file)
190*61046927SAndroid Build Coastguard Worker             && !matches!(&src.src_ref, SrcRef::Imm32(_))
191*61046927SAndroid Build Coastguard Worker         {
192*61046927SAndroid Build Coastguard Worker             self.copy_alu_src(src, reg_file, src_type);
193*61046927SAndroid Build Coastguard Worker         }
194*61046927SAndroid Build Coastguard Worker     }
195*61046927SAndroid Build Coastguard Worker 
copy_alu_src_if_imm( &mut self, src: &mut Src, reg_file: RegFile, src_type: SrcType, )196*61046927SAndroid Build Coastguard Worker     fn copy_alu_src_if_imm(
197*61046927SAndroid Build Coastguard Worker         &mut self,
198*61046927SAndroid Build Coastguard Worker         src: &mut Src,
199*61046927SAndroid Build Coastguard Worker         reg_file: RegFile,
200*61046927SAndroid Build Coastguard Worker         src_type: SrcType,
201*61046927SAndroid Build Coastguard Worker     ) {
202*61046927SAndroid Build Coastguard Worker         if src_is_imm(src) {
203*61046927SAndroid Build Coastguard Worker             self.copy_alu_src(src, reg_file, src_type);
204*61046927SAndroid Build Coastguard Worker         }
205*61046927SAndroid Build Coastguard Worker     }
206*61046927SAndroid Build Coastguard Worker 
copy_alu_src_if_ineg_imm( &mut self, src: &mut Src, reg_file: RegFile, src_type: SrcType, )207*61046927SAndroid Build Coastguard Worker     fn copy_alu_src_if_ineg_imm(
208*61046927SAndroid Build Coastguard Worker         &mut self,
209*61046927SAndroid Build Coastguard Worker         src: &mut Src,
210*61046927SAndroid Build Coastguard Worker         reg_file: RegFile,
211*61046927SAndroid Build Coastguard Worker         src_type: SrcType,
212*61046927SAndroid Build Coastguard Worker     ) {
213*61046927SAndroid Build Coastguard Worker         assert!(src_type == SrcType::I32);
214*61046927SAndroid Build Coastguard Worker         if src_is_imm(src) && src.src_mod.is_ineg() {
215*61046927SAndroid Build Coastguard Worker             self.copy_alu_src(src, reg_file, src_type);
216*61046927SAndroid Build Coastguard Worker         }
217*61046927SAndroid Build Coastguard Worker     }
218*61046927SAndroid Build Coastguard Worker 
copy_alu_src_if_both_not_reg( &mut self, src1: &Src, src2: &mut Src, reg_file: RegFile, src_type: SrcType, )219*61046927SAndroid Build Coastguard Worker     fn copy_alu_src_if_both_not_reg(
220*61046927SAndroid Build Coastguard Worker         &mut self,
221*61046927SAndroid Build Coastguard Worker         src1: &Src,
222*61046927SAndroid Build Coastguard Worker         src2: &mut Src,
223*61046927SAndroid Build Coastguard Worker         reg_file: RegFile,
224*61046927SAndroid Build Coastguard Worker         src_type: SrcType,
225*61046927SAndroid Build Coastguard Worker     ) {
226*61046927SAndroid Build Coastguard Worker         if !src_is_reg(src1, reg_file) && !src_is_reg(src2, reg_file) {
227*61046927SAndroid Build Coastguard Worker             self.copy_alu_src(src2, reg_file, src_type);
228*61046927SAndroid Build Coastguard Worker         }
229*61046927SAndroid Build Coastguard Worker     }
230*61046927SAndroid Build Coastguard Worker 
copy_alu_src_and_lower_fmod( &mut self, src: &mut Src, src_type: SrcType, )231*61046927SAndroid Build Coastguard Worker     fn copy_alu_src_and_lower_fmod(
232*61046927SAndroid Build Coastguard Worker         &mut self,
233*61046927SAndroid Build Coastguard Worker         src: &mut Src,
234*61046927SAndroid Build Coastguard Worker         src_type: SrcType,
235*61046927SAndroid Build Coastguard Worker     ) {
236*61046927SAndroid Build Coastguard Worker         match src_type {
237*61046927SAndroid Build Coastguard Worker             SrcType::F16 | SrcType::F16v2 => {
238*61046927SAndroid Build Coastguard Worker                 let val = self.alloc_ssa(RegFile::GPR, 1);
239*61046927SAndroid Build Coastguard Worker                 self.push_op(OpHAdd2 {
240*61046927SAndroid Build Coastguard Worker                     dst: val.into(),
241*61046927SAndroid Build Coastguard Worker                     srcs: [Src::new_zero().fneg(), *src],
242*61046927SAndroid Build Coastguard Worker                     saturate: false,
243*61046927SAndroid Build Coastguard Worker                     ftz: false,
244*61046927SAndroid Build Coastguard Worker                     f32: false,
245*61046927SAndroid Build Coastguard Worker                 });
246*61046927SAndroid Build Coastguard Worker                 *src = val.into();
247*61046927SAndroid Build Coastguard Worker             }
248*61046927SAndroid Build Coastguard Worker             SrcType::F32 => {
249*61046927SAndroid Build Coastguard Worker                 let val = self.alloc_ssa(RegFile::GPR, 1);
250*61046927SAndroid Build Coastguard Worker                 self.push_op(OpFAdd {
251*61046927SAndroid Build Coastguard Worker                     dst: val.into(),
252*61046927SAndroid Build Coastguard Worker                     srcs: [Src::new_zero().fneg(), *src],
253*61046927SAndroid Build Coastguard Worker                     saturate: false,
254*61046927SAndroid Build Coastguard Worker                     rnd_mode: FRndMode::NearestEven,
255*61046927SAndroid Build Coastguard Worker                     ftz: false,
256*61046927SAndroid Build Coastguard Worker                 });
257*61046927SAndroid Build Coastguard Worker                 *src = val.into();
258*61046927SAndroid Build Coastguard Worker             }
259*61046927SAndroid Build Coastguard Worker             SrcType::F64 => {
260*61046927SAndroid Build Coastguard Worker                 let val = self.alloc_ssa(RegFile::GPR, 2);
261*61046927SAndroid Build Coastguard Worker                 self.push_op(OpDAdd {
262*61046927SAndroid Build Coastguard Worker                     dst: val.into(),
263*61046927SAndroid Build Coastguard Worker                     srcs: [Src::new_zero().fneg(), *src],
264*61046927SAndroid Build Coastguard Worker                     rnd_mode: FRndMode::NearestEven,
265*61046927SAndroid Build Coastguard Worker                 });
266*61046927SAndroid Build Coastguard Worker                 *src = val.into();
267*61046927SAndroid Build Coastguard Worker             }
268*61046927SAndroid Build Coastguard Worker             _ => panic!("Invalid ffabs srouce type"),
269*61046927SAndroid Build Coastguard Worker         }
270*61046927SAndroid Build Coastguard Worker     }
271*61046927SAndroid Build Coastguard Worker 
copy_ssa_ref_if_uniform(&mut self, ssa_ref: &mut SSARef)272*61046927SAndroid Build Coastguard Worker     fn copy_ssa_ref_if_uniform(&mut self, ssa_ref: &mut SSARef) {
273*61046927SAndroid Build Coastguard Worker         for ssa in &mut ssa_ref[..] {
274*61046927SAndroid Build Coastguard Worker             if ssa.is_uniform() {
275*61046927SAndroid Build Coastguard Worker                 let warp = self.alloc_ssa(ssa.file().to_warp(), 1)[0];
276*61046927SAndroid Build Coastguard Worker                 self.copy_to(warp.into(), (*ssa).into());
277*61046927SAndroid Build Coastguard Worker                 *ssa = warp;
278*61046927SAndroid Build Coastguard Worker             }
279*61046927SAndroid Build Coastguard Worker         }
280*61046927SAndroid Build Coastguard Worker     }
281*61046927SAndroid Build Coastguard Worker }
282*61046927SAndroid Build Coastguard Worker 
283*61046927SAndroid Build Coastguard Worker impl LegalizeBuildHelpers for LegalizeBuilder<'_> {}
284*61046927SAndroid Build Coastguard Worker 
legalize_instr( sm: &dyn ShaderModel, b: &mut LegalizeBuilder, bl: &impl BlockLiveness, block_uniform: bool, pinned: &HashSet<SSARef>, ip: usize, instr: &mut Instr, )285*61046927SAndroid Build Coastguard Worker fn legalize_instr(
286*61046927SAndroid Build Coastguard Worker     sm: &dyn ShaderModel,
287*61046927SAndroid Build Coastguard Worker     b: &mut LegalizeBuilder,
288*61046927SAndroid Build Coastguard Worker     bl: &impl BlockLiveness,
289*61046927SAndroid Build Coastguard Worker     block_uniform: bool,
290*61046927SAndroid Build Coastguard Worker     pinned: &HashSet<SSARef>,
291*61046927SAndroid Build Coastguard Worker     ip: usize,
292*61046927SAndroid Build Coastguard Worker     instr: &mut Instr,
293*61046927SAndroid Build Coastguard Worker ) {
294*61046927SAndroid Build Coastguard Worker     // Handle a few no-op cases up-front
295*61046927SAndroid Build Coastguard Worker     match &instr.op {
296*61046927SAndroid Build Coastguard Worker         Op::Undef(_)
297*61046927SAndroid Build Coastguard Worker         | Op::PhiSrcs(_)
298*61046927SAndroid Build Coastguard Worker         | Op::PhiDsts(_)
299*61046927SAndroid Build Coastguard Worker         | Op::Pin(_)
300*61046927SAndroid Build Coastguard Worker         | Op::Unpin(_)
301*61046927SAndroid Build Coastguard Worker         | Op::RegOut(_) => {
302*61046927SAndroid Build Coastguard Worker             // These are implemented by RA and can take pretty much anything
303*61046927SAndroid Build Coastguard Worker             // you can throw at them.
304*61046927SAndroid Build Coastguard Worker             debug_assert!(instr.pred.is_true());
305*61046927SAndroid Build Coastguard Worker             return;
306*61046927SAndroid Build Coastguard Worker         }
307*61046927SAndroid Build Coastguard Worker         Op::Copy(_) => {
308*61046927SAndroid Build Coastguard Worker             // OpCopy is implemented in a lowering pass and can handle anything
309*61046927SAndroid Build Coastguard Worker             return;
310*61046927SAndroid Build Coastguard Worker         }
311*61046927SAndroid Build Coastguard Worker         Op::SrcBar(_) => {
312*61046927SAndroid Build Coastguard Worker             // This is turned into a nop by calc_instr_deps
313*61046927SAndroid Build Coastguard Worker             return;
314*61046927SAndroid Build Coastguard Worker         }
315*61046927SAndroid Build Coastguard Worker         Op::Swap(_) | Op::ParCopy(_) => {
316*61046927SAndroid Build Coastguard Worker             // These are generated by RA and should not exist yet
317*61046927SAndroid Build Coastguard Worker             panic!("Unsupported instruction");
318*61046927SAndroid Build Coastguard Worker         }
319*61046927SAndroid Build Coastguard Worker         _ => (),
320*61046927SAndroid Build Coastguard Worker     }
321*61046927SAndroid Build Coastguard Worker 
322*61046927SAndroid Build Coastguard Worker     if !instr.is_uniform() {
323*61046927SAndroid Build Coastguard Worker         b.copy_pred_if_upred(&mut instr.pred);
324*61046927SAndroid Build Coastguard Worker     }
325*61046927SAndroid Build Coastguard Worker 
326*61046927SAndroid Build Coastguard Worker     let src_types = instr.src_types();
327*61046927SAndroid Build Coastguard Worker     for (i, src) in instr.srcs_mut().iter_mut().enumerate() {
328*61046927SAndroid Build Coastguard Worker         *src = src.fold_imm(src_types[i]);
329*61046927SAndroid Build Coastguard Worker         b.copy_src_if_not_same_file(src);
330*61046927SAndroid Build Coastguard Worker 
331*61046927SAndroid Build Coastguard Worker         if !block_uniform {
332*61046927SAndroid Build Coastguard Worker             // In non-uniform control-flow, we can't collect uniform vectors so
333*61046927SAndroid Build Coastguard Worker             // we need to insert copies to warp regs which we can collect.
334*61046927SAndroid Build Coastguard Worker             match &mut src.src_ref {
335*61046927SAndroid Build Coastguard Worker                 SrcRef::SSA(vec) => {
336*61046927SAndroid Build Coastguard Worker                     if vec.is_uniform()
337*61046927SAndroid Build Coastguard Worker                         && vec.comps() > 1
338*61046927SAndroid Build Coastguard Worker                         && !pinned.contains(vec)
339*61046927SAndroid Build Coastguard Worker                     {
340*61046927SAndroid Build Coastguard Worker                         b.copy_ssa_ref(vec, vec.file().unwrap().to_warp());
341*61046927SAndroid Build Coastguard Worker                     }
342*61046927SAndroid Build Coastguard Worker                 }
343*61046927SAndroid Build Coastguard Worker                 SrcRef::CBuf(CBufRef {
344*61046927SAndroid Build Coastguard Worker                     buf: CBuf::BindlessSSA(handle),
345*61046927SAndroid Build Coastguard Worker                     ..
346*61046927SAndroid Build Coastguard Worker                 }) => assert!(pinned.contains(handle)),
347*61046927SAndroid Build Coastguard Worker                 _ => (),
348*61046927SAndroid Build Coastguard Worker             }
349*61046927SAndroid Build Coastguard Worker         }
350*61046927SAndroid Build Coastguard Worker     }
351*61046927SAndroid Build Coastguard Worker 
352*61046927SAndroid Build Coastguard Worker     // OpBreak and OpBSsy impose additional RA constraints
353*61046927SAndroid Build Coastguard Worker     match &mut instr.op {
354*61046927SAndroid Build Coastguard Worker         Op::Break(OpBreak {
355*61046927SAndroid Build Coastguard Worker             bar_in, bar_out, ..
356*61046927SAndroid Build Coastguard Worker         })
357*61046927SAndroid Build Coastguard Worker         | Op::BSSy(OpBSSy {
358*61046927SAndroid Build Coastguard Worker             bar_in, bar_out, ..
359*61046927SAndroid Build Coastguard Worker         }) => {
360*61046927SAndroid Build Coastguard Worker             let bar_in_ssa = bar_in.src_ref.as_ssa().unwrap();
361*61046927SAndroid Build Coastguard Worker             if !bar_out.is_none() && bl.is_live_after_ip(&bar_in_ssa[0], ip) {
362*61046927SAndroid Build Coastguard Worker                 let gpr = b.bmov_to_gpr(*bar_in);
363*61046927SAndroid Build Coastguard Worker                 let tmp = b.bmov_to_bar(gpr.into());
364*61046927SAndroid Build Coastguard Worker                 *bar_in = tmp.into();
365*61046927SAndroid Build Coastguard Worker             }
366*61046927SAndroid Build Coastguard Worker         }
367*61046927SAndroid Build Coastguard Worker         _ => (),
368*61046927SAndroid Build Coastguard Worker     }
369*61046927SAndroid Build Coastguard Worker 
370*61046927SAndroid Build Coastguard Worker     sm.legalize_op(b, &mut instr.op);
371*61046927SAndroid Build Coastguard Worker 
372*61046927SAndroid Build Coastguard Worker     let mut vec_src_map: HashMap<SSARef, SSARef> = HashMap::new();
373*61046927SAndroid Build Coastguard Worker     let mut vec_comps = HashSet::new();
374*61046927SAndroid Build Coastguard Worker     for src in instr.srcs_mut() {
375*61046927SAndroid Build Coastguard Worker         if let SrcRef::SSA(vec) = &src.src_ref {
376*61046927SAndroid Build Coastguard Worker             if vec.comps() == 1 {
377*61046927SAndroid Build Coastguard Worker                 continue;
378*61046927SAndroid Build Coastguard Worker             }
379*61046927SAndroid Build Coastguard Worker 
380*61046927SAndroid Build Coastguard Worker             // If the same vector shows up twice in one instruction, that's
381*61046927SAndroid Build Coastguard Worker             // okay. Just make it look the same as the previous source we
382*61046927SAndroid Build Coastguard Worker             // fixed up.
383*61046927SAndroid Build Coastguard Worker             if let Some(new_vec) = vec_src_map.get(vec) {
384*61046927SAndroid Build Coastguard Worker                 src.src_ref = (*new_vec).into();
385*61046927SAndroid Build Coastguard Worker                 continue;
386*61046927SAndroid Build Coastguard Worker             }
387*61046927SAndroid Build Coastguard Worker 
388*61046927SAndroid Build Coastguard Worker             let mut new_vec = *vec;
389*61046927SAndroid Build Coastguard Worker             for c in 0..vec.comps() {
390*61046927SAndroid Build Coastguard Worker                 let ssa = vec[usize::from(c)];
391*61046927SAndroid Build Coastguard Worker                 // If the same SSA value shows up in multiple non-identical
392*61046927SAndroid Build Coastguard Worker                 // vector sources or as multiple components in the same
393*61046927SAndroid Build Coastguard Worker                 // source, we need to make a copy so it can get assigned to
394*61046927SAndroid Build Coastguard Worker                 // multiple different registers.
395*61046927SAndroid Build Coastguard Worker                 if vec_comps.get(&ssa).is_some() {
396*61046927SAndroid Build Coastguard Worker                     let copy = b.alloc_ssa(ssa.file(), 1)[0];
397*61046927SAndroid Build Coastguard Worker                     b.copy_to(copy.into(), ssa.into());
398*61046927SAndroid Build Coastguard Worker                     new_vec[usize::from(c)] = copy;
399*61046927SAndroid Build Coastguard Worker                 } else {
400*61046927SAndroid Build Coastguard Worker                     vec_comps.insert(ssa);
401*61046927SAndroid Build Coastguard Worker                 }
402*61046927SAndroid Build Coastguard Worker             }
403*61046927SAndroid Build Coastguard Worker 
404*61046927SAndroid Build Coastguard Worker             vec_src_map.insert(*vec, new_vec);
405*61046927SAndroid Build Coastguard Worker             src.src_ref = new_vec.into();
406*61046927SAndroid Build Coastguard Worker         }
407*61046927SAndroid Build Coastguard Worker     }
408*61046927SAndroid Build Coastguard Worker }
409*61046927SAndroid Build Coastguard Worker 
410*61046927SAndroid Build Coastguard Worker impl Shader<'_> {
legalize(&mut self)411*61046927SAndroid Build Coastguard Worker     pub fn legalize(&mut self) {
412*61046927SAndroid Build Coastguard Worker         let sm = self.sm;
413*61046927SAndroid Build Coastguard Worker         for f in &mut self.functions {
414*61046927SAndroid Build Coastguard Worker             let live = SimpleLiveness::for_function(f);
415*61046927SAndroid Build Coastguard Worker             let mut pinned = HashSet::new();
416*61046927SAndroid Build Coastguard Worker 
417*61046927SAndroid Build Coastguard Worker             for (bi, b) in f.blocks.iter_mut().enumerate() {
418*61046927SAndroid Build Coastguard Worker                 let bl = live.block_live(bi);
419*61046927SAndroid Build Coastguard Worker                 let bu = b.uniform;
420*61046927SAndroid Build Coastguard Worker 
421*61046927SAndroid Build Coastguard Worker                 let mut instrs = Vec::new();
422*61046927SAndroid Build Coastguard Worker                 for (ip, mut instr) in b.instrs.drain(..).enumerate() {
423*61046927SAndroid Build Coastguard Worker                     if let Op::Pin(pin) = &instr.op {
424*61046927SAndroid Build Coastguard Worker                         if let Dst::SSA(ssa) = &pin.dst {
425*61046927SAndroid Build Coastguard Worker                             pinned.insert(*ssa);
426*61046927SAndroid Build Coastguard Worker                         }
427*61046927SAndroid Build Coastguard Worker                     }
428*61046927SAndroid Build Coastguard Worker 
429*61046927SAndroid Build Coastguard Worker                     let mut b = SSAInstrBuilder::new(sm, &mut f.ssa_alloc);
430*61046927SAndroid Build Coastguard Worker                     legalize_instr(sm, &mut b, bl, bu, &pinned, ip, &mut instr);
431*61046927SAndroid Build Coastguard Worker                     b.push_instr(instr);
432*61046927SAndroid Build Coastguard Worker                     instrs.append(&mut b.as_vec());
433*61046927SAndroid Build Coastguard Worker                 }
434*61046927SAndroid Build Coastguard Worker                 b.instrs = instrs;
435*61046927SAndroid Build Coastguard Worker             }
436*61046927SAndroid Build Coastguard Worker         }
437*61046927SAndroid Build Coastguard Worker     }
438*61046927SAndroid Build Coastguard Worker }
439