1use crate::linker::ipo::CallGraph;
53use crate::spirv_type_constraints::{self, InstSig, StorageClassPat, TyListPat, TyPat};
54use indexmap::{IndexMap, IndexSet};
55use rspirv::dr::{Builder, Function, Instruction, Module, Operand};
56use rspirv::spirv::{Op, StorageClass, Word};
57use rustc_data_structures::fx::{FxHashMap, FxHashSet};
58use smallvec::SmallVec;
59use std::collections::{BTreeMap, VecDeque};
60use std::ops::{Range, RangeTo};
61use std::{fmt, io, iter, mem, slice};
62use tracing::{debug, error};
63
64struct FmtBy<F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result>(F);
66
67impl<F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result> fmt::Debug for FmtBy<F> {
68 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69 self.0(f)
70 }
71}
72
73impl<F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result> fmt::Display for FmtBy<F> {
74 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75 self.0(f)
76 }
77}
78
79pub trait Specialization {
80 fn specialize_operand(&self, operand: &Operand) -> bool;
83
84 fn concrete_fallback(&self) -> Operand;
90}
91
92pub struct SimpleSpecialization<SO: Fn(&Operand) -> bool> {
95 pub specialize_operand: SO,
96 pub concrete_fallback: Operand,
97}
98
99impl<SO: Fn(&Operand) -> bool> Specialization for SimpleSpecialization<SO> {
100 fn specialize_operand(&self, operand: &Operand) -> bool {
101 (self.specialize_operand)(operand)
102 }
103 fn concrete_fallback(&self) -> Operand {
104 self.concrete_fallback.clone()
105 }
106}
107
108pub fn specialize(
109 opts: &super::Options,
110 module: Module,
111 specialization: impl Specialization,
112) -> Module {
113 let dump_instances = &opts.specializer_dump_instances;
114
115 let mut debug_names = FxHashMap::default();
116 if dump_instances.is_some() {
117 debug_names = module
118 .debug_names
119 .iter()
120 .filter(|inst| inst.class.opcode == Op::Name)
121 .map(|inst| {
122 (
123 inst.operands[0].unwrap_id_ref(),
124 inst.operands[1].unwrap_literal_string().to_string(),
125 )
126 })
127 .collect();
128 }
129
130 let mut specializer = Specializer {
131 specialization,
132 debug_names,
133 generics: IndexMap::new(),
134 int_consts: FxHashMap::default(),
135 };
136
137 specializer.collect_generics(&module);
138
139 let mut interface_concrete_instances = IndexSet::new();
145 for inst in &module.entry_points {
146 for interface_operand in &inst.operands[3..] {
147 let interface_id = interface_operand.unwrap_id_ref();
148 if let Some(generic) = specializer.generics.get(&interface_id)
149 && let Some(param_values) = &generic.param_values
150 && param_values.iter().all(|v| matches!(v, Value::Known(_)))
151 {
152 interface_concrete_instances.insert(Instance {
153 generic_id: interface_id,
154 generic_args: param_values
155 .iter()
156 .copied()
157 .map(|v| match v {
158 Value::Known(v) => v,
159 _ => unreachable!(),
160 })
161 .collect(),
162 });
163 }
164 }
165 }
166
167 let call_graph = CallGraph::collect(&module);
168 let mut non_generic_replacements = vec![];
169 for func_idx in call_graph.post_order() {
170 if let Some(replacements) = specializer.infer_function(&module.functions[func_idx]) {
171 non_generic_replacements.push((func_idx, replacements));
172 }
173 }
174
175 let mut expander = Expander::new(&specializer, module);
176
177 for interface_instance in interface_concrete_instances {
179 expander.alloc_instance_id(interface_instance);
180 }
181
182 debug!("non-generic replacements:");
186 for (func_idx, replacements) in non_generic_replacements {
187 let mut func = mem::replace(
188 &mut expander.builder.module_mut().functions[func_idx],
189 Function::new(),
190 );
191 let empty =
192 replacements.with_instance.is_empty() && replacements.with_concrete_or_param.is_empty();
193 if !empty {
194 debug!(" in %{}:", func.def_id().unwrap());
195 }
196 for (loc, operand) in
197 replacements.to_concrete(&[], |instance| expander.alloc_instance_id(instance))
198 {
199 debug!(" {operand} -> {loc:?}");
200 func.index_set(loc, operand.into());
201 }
202 expander.builder.module_mut().functions[func_idx] = func;
203 }
204 expander.propagate_instances();
205
206 if let Some(path) = dump_instances {
207 expander
208 .dump_instances(&mut std::fs::File::create(path).unwrap())
209 .unwrap();
210 }
211
212 expander.expand_module()
213}
214
215#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
218enum CopyOperand {
219 IdRef(Word),
220 StorageClass(StorageClass),
221}
222
223#[derive(Debug)]
224struct NotSupportedAsCopyOperand(
225 #[allow(dead_code)] Operand,
227);
228
229impl TryFrom<&Operand> for CopyOperand {
230 type Error = NotSupportedAsCopyOperand;
231 fn try_from(operand: &Operand) -> Result<Self, Self::Error> {
232 match *operand {
233 Operand::IdRef(id) => Ok(Self::IdRef(id)),
234 Operand::StorageClass(s) => Ok(Self::StorageClass(s)),
235 _ => Err(NotSupportedAsCopyOperand(operand.clone())),
236 }
237 }
238}
239
240impl From<CopyOperand> for Operand {
241 fn from(op: CopyOperand) -> Self {
242 match op {
243 CopyOperand::IdRef(id) => Self::IdRef(id),
244 CopyOperand::StorageClass(s) => Self::StorageClass(s),
245 }
246 }
247}
248
249impl fmt::Display for CopyOperand {
250 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
251 match self {
252 Self::IdRef(id) => write!(f, "%{id}"),
253 Self::StorageClass(s) => write!(f, "{s:?}"),
254 }
255 }
256}
257
258#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
261enum Value<T> {
262 Unknown,
264
265 Known(CopyOperand),
267
268 SameAs(T),
274}
275
276impl<T> Value<T> {
277 fn map_var<U>(self, f: impl FnOnce(T) -> U) -> Value<U> {
278 match self {
279 Value::Unknown => Value::Unknown,
280 Value::Known(o) => Value::Known(o),
281 Value::SameAs(var) => Value::SameAs(f(var)),
282 }
283 }
284}
285
286#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
289struct Param(u32);
290
291impl fmt::Display for Param {
292 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
293 write!(f, "${}", self.0)
294 }
295}
296
297impl Param {
298 fn range_iter(range: &Range<Self>) -> impl Iterator<Item = Self> + Clone {
301 (range.start.0..range.end.0).map(Self)
302 }
303}
304
305#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
307struct Instance<GA> {
308 generic_id: Word,
309 generic_args: GA,
310}
311
312impl<GA> Instance<GA> {
313 fn as_ref(&self) -> Instance<&GA> {
314 Instance {
315 generic_id: self.generic_id,
316 generic_args: &self.generic_args,
317 }
318 }
319
320 fn map_generic_args<T, U, GA2>(self, f: impl FnMut(T) -> U) -> Instance<GA2>
321 where
322 GA: IntoIterator<Item = T>,
323 GA2: std::iter::FromIterator<U>,
324 {
325 Instance {
326 generic_id: self.generic_id,
327 generic_args: self.generic_args.into_iter().map(f).collect(),
328 }
329 }
330
331 fn display<'a, T: fmt::Display, GAI: Iterator<Item = T> + Clone>(
333 &'a self,
334 f: impl FnOnce(&'a GA) -> GAI,
335 ) -> impl fmt::Display {
336 let &Self {
337 generic_id,
338 ref generic_args,
339 } = self;
340 let generic_args_iter = f(generic_args);
341 FmtBy(move |f| {
342 write!(f, "%{generic_id}<")?;
343 for (i, arg) in generic_args_iter.clone().enumerate() {
344 if i != 0 {
345 write!(f, ", ")?;
346 }
347 write!(f, "{arg}")?;
348 }
349 write!(f, ">")
350 })
351 }
352}
353
354#[derive(Copy, Clone, Debug, PartialEq, Eq)]
355enum InstructionLocation {
356 Module,
357 FnParam(usize),
358 FnBody {
359 block_idx: usize,
361
362 inst_idx: usize,
364 },
365}
366
367trait OperandIndexGetSet<I> {
368 #[allow(dead_code)]
370 fn index_get(&self, index: I) -> Operand;
371 fn index_set(&mut self, index: I, operand: Operand);
372}
373
374#[derive(Copy, Clone, Debug, PartialEq, Eq)]
375enum OperandIdx {
376 ResultType,
377 Input(usize),
378}
379
380impl OperandIndexGetSet<OperandIdx> for Instruction {
381 fn index_get(&self, idx: OperandIdx) -> Operand {
382 match idx {
383 OperandIdx::ResultType => Operand::IdRef(self.result_type.unwrap()),
384 OperandIdx::Input(i) => self.operands[i].clone(),
385 }
386 }
387 fn index_set(&mut self, idx: OperandIdx, operand: Operand) {
388 match idx {
389 OperandIdx::ResultType => self.result_type = Some(operand.unwrap_id_ref()),
390 OperandIdx::Input(i) => self.operands[i] = operand,
391 }
392 }
393}
394
395#[derive(Copy, Clone, Debug, PartialEq, Eq)]
396struct OperandLocation {
397 inst_loc: InstructionLocation,
398 operand_idx: OperandIdx,
399}
400
401impl OperandIndexGetSet<OperandLocation> for Instruction {
402 fn index_get(&self, loc: OperandLocation) -> Operand {
403 assert_eq!(loc.inst_loc, InstructionLocation::Module);
404 self.index_get(loc.operand_idx)
405 }
406 fn index_set(&mut self, loc: OperandLocation, operand: Operand) {
407 assert_eq!(loc.inst_loc, InstructionLocation::Module);
408 self.index_set(loc.operand_idx, operand);
409 }
410}
411
412impl OperandIndexGetSet<OperandLocation> for Function {
413 fn index_get(&self, loc: OperandLocation) -> Operand {
414 let inst = match loc.inst_loc {
415 InstructionLocation::Module => self.def.as_ref().unwrap(),
416 InstructionLocation::FnParam(i) => &self.parameters[i],
417 InstructionLocation::FnBody {
418 block_idx,
419 inst_idx,
420 } => &self.blocks[block_idx].instructions[inst_idx],
421 };
422 inst.index_get(loc.operand_idx)
423 }
424 fn index_set(&mut self, loc: OperandLocation, operand: Operand) {
425 let inst = match loc.inst_loc {
426 InstructionLocation::Module => self.def.as_mut().unwrap(),
427 InstructionLocation::FnParam(i) => &mut self.parameters[i],
428 InstructionLocation::FnBody {
429 block_idx,
430 inst_idx,
431 } => &mut self.blocks[block_idx].instructions[inst_idx],
432 };
433 inst.index_set(loc.operand_idx, operand);
434 }
435}
436
437#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
440enum ConcreteOrParam {
441 Concrete(CopyOperand),
442 Param(Param),
443}
444
445impl ConcreteOrParam {
446 fn apply_generic_args(self, generic_args: &[CopyOperand]) -> CopyOperand {
448 match self {
449 Self::Concrete(x) => x,
450 Self::Param(Param(i)) => generic_args[i as usize],
451 }
452 }
453}
454
455#[derive(Debug)]
456struct Replacements {
457 with_instance: IndexMap<Instance<SmallVec<[ConcreteOrParam; 4]>>, Vec<OperandLocation>>,
461
462 with_concrete_or_param: Vec<(OperandLocation, ConcreteOrParam)>,
464}
465
466impl Replacements {
467 fn to_concrete<'a>(
473 &'a self,
474 generic_args: &'a [CopyOperand],
475 mut concrete_instance_id: impl FnMut(Instance<SmallVec<[CopyOperand; 4]>>) -> Word + 'a,
476 ) -> impl Iterator<Item = (OperandLocation, CopyOperand)> + 'a {
477 self.with_instance
478 .iter()
479 .flat_map(move |(instance, locations)| {
480 let concrete = CopyOperand::IdRef(concrete_instance_id(
481 instance
482 .as_ref()
483 .map_generic_args(|x| x.apply_generic_args(generic_args)),
484 ));
485 locations.iter().map(move |&loc| (loc, concrete))
486 })
487 .chain(
488 self.with_concrete_or_param
489 .iter()
490 .map(move |&(loc, x)| (loc, x.apply_generic_args(generic_args))),
491 )
492 }
493}
494
495struct Generic {
502 param_count: u32,
503
504 def: Instruction,
510
511 param_values: Option<Vec<Value<Param>>>,
518
519 replacements: Replacements,
523}
524
525struct Specializer<S: Specialization> {
526 specialization: S,
527
528 debug_names: FxHashMap<Word, String>,
530
531 generics: IndexMap<Word, Generic>,
533
534 int_consts: FxHashMap<Word, u32>,
537}
538
539impl<S: Specialization> Specializer<S> {
540 fn params_needed_by(&self, operand: &Operand) -> (u32, Option<&Generic>) {
544 if self.specialization.specialize_operand(operand) {
545 (1, None)
547 } else if let Operand::IdRef(id) = operand {
548 self.generics
549 .get(id)
550 .map_or((0, None), |generic| (generic.param_count, Some(generic)))
551 } else {
552 (0, None)
553 }
554 }
555
556 fn collect_generics(&mut self, module: &Module) {
557 let types_global_values_and_functions = module
562 .types_global_values
563 .iter()
564 .chain(module.functions.iter().filter_map(|f| f.def.as_ref()));
565
566 let mut forward_declared_pointers = FxHashSet::default();
567 for inst in types_global_values_and_functions {
568 let result_id = if inst.class.opcode == Op::TypeForwardPointer {
569 forward_declared_pointers.insert(inst.operands[0].unwrap_id_ref());
570 inst.operands[0].unwrap_id_ref()
571 } else {
572 let result_id = inst.result_id.unwrap_or_else(|| {
573 unreachable!(
574 "Op{:?} is in `types_global_values` but not have a result ID",
575 inst.class.opcode
576 );
577 });
578 if forward_declared_pointers.remove(&result_id) {
579 assert_eq!(inst.class.opcode, Op::TypePointer);
584 continue;
585 }
586 result_id
587 };
588
589 if inst.class.opcode == Op::Constant
591 && let Operand::LiteralBit32(x) = inst.operands[0]
592 {
593 self.int_consts.insert(result_id, x);
594 }
595
596 let (param_count, param_values, replacements) = {
599 let mut infer_cx = InferCx::new(self);
600 infer_cx.instantiate_instruction(inst, InstructionLocation::Module);
601
602 let param_count = infer_cx.infer_var_values.len() as u32;
603
604 let param_values = infer_cx
606 .infer_var_values
607 .iter()
608 .map(|v| v.map_var(|InferVar(i)| Param(i)));
609 let param_values = if param_values.clone().any(|v| v != Value::Unknown) {
611 Some(param_values.collect())
612 } else {
613 None
614 };
615
616 (
617 param_count,
618 param_values,
619 infer_cx.into_replacements(..Param(param_count)),
620 )
621 };
622
623 if param_count > 0 {
625 self.generics.insert(
626 result_id,
627 Generic {
628 param_count,
629 def: inst.clone(),
630 param_values,
631 replacements,
632 },
633 );
634 }
635 }
636 }
637
638 fn infer_function(&mut self, func: &Function) -> Option<Replacements> {
642 let func_id = func.def_id().unwrap();
643
644 let param_count = self
645 .generics
646 .get(&func_id)
647 .map_or(0, |generic| generic.param_count);
648
649 let (param_values, replacements) = {
650 let mut infer_cx = InferCx::new(self);
651 infer_cx.instantiate_function(func);
652
653 let param_values = infer_cx.infer_var_values[..param_count as usize]
655 .iter()
656 .map(|v| v.map_var(|InferVar(i)| Param(i)));
657 let param_values = if param_values.clone().any(|v| v != Value::Unknown) {
659 Some(param_values.collect())
660 } else {
661 None
662 };
663
664 (
665 param_values,
666 infer_cx.into_replacements(..Param(param_count)),
667 )
668 };
669
670 if let Some(generic) = self.generics.get_mut(&func_id) {
671 assert!(generic.param_values.is_none());
675
676 generic.param_values = param_values;
677 generic.replacements = replacements;
678
679 None
680 } else {
681 Some(replacements)
682 }
683 }
684}
685
686#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
689struct InferVar(u32);
690
691impl fmt::Display for InferVar {
692 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
693 write!(f, "?{}", self.0)
694 }
695}
696
697impl InferVar {
698 fn range_iter(range: &Range<Self>) -> impl Iterator<Item = Self> + Clone {
701 (range.start.0..range.end.0).map(Self)
702 }
703}
704
705struct InferCx<'a, S: Specialization> {
706 specializer: &'a Specializer<S>,
707
708 infer_var_values: Vec<Value<InferVar>>,
714
715 type_of_result: IndexMap<Word, InferOperand>,
722
723 instantiated_operands: Vec<(OperandLocation, Instance<Range<InferVar>>)>,
726
727 inferred_operands: Vec<(OperandLocation, InferVar)>,
729}
730
731impl<'a, S: Specialization> InferCx<'a, S> {
732 fn new(specializer: &'a Specializer<S>) -> Self {
733 InferCx {
734 specializer,
735
736 infer_var_values: vec![],
737 type_of_result: IndexMap::new(),
738 instantiated_operands: vec![],
739 inferred_operands: vec![],
740 }
741 }
742}
743
744#[derive(Clone, Debug, PartialEq, Eq)]
745enum InferOperand {
746 Unknown,
747 Var(InferVar),
748 Concrete(CopyOperand),
749 Instance(Instance<Range<InferVar>>),
750}
751
752impl InferOperand {
753 fn from_operand_and_generic_args(
757 operand: &Operand,
758 generic_args: Range<InferVar>,
759 cx: &InferCx<'_, impl Specialization>,
760 ) -> (Self, Range<InferVar>) {
761 let (needed, generic) = cx.specializer.params_needed_by(operand);
762 let split = InferVar(generic_args.start.0 + needed);
763 let (generic_args, rest) = (generic_args.start..split, split..generic_args.end);
764 (
765 if generic.is_some() {
766 Self::Instance(Instance {
767 generic_id: operand.unwrap_id_ref(),
768 generic_args,
769 })
770 } else if needed == 0 {
771 CopyOperand::try_from(operand).map_or(Self::Unknown, Self::Concrete)
772 } else {
773 assert_eq!(needed, 1);
774 Self::Var(generic_args.start)
775 },
776 rest,
777 )
778 }
779
780 fn display_with_infer_var_values<'a>(
781 &'a self,
782 infer_var_value: impl Fn(InferVar) -> Value<InferVar> + Copy + 'a,
783 ) -> impl fmt::Display + '_ {
784 FmtBy(move |f| {
785 let var_with_value = |v| {
786 FmtBy(move |f| {
787 write!(f, "{v}")?;
788 match infer_var_value(v) {
789 Value::Unknown => Ok(()),
790 Value::Known(o) => write!(f, " = {o}"),
791 Value::SameAs(v) => write!(f, " = {v}"),
792 }
793 })
794 };
795 match self {
796 Self::Unknown => write!(f, "_"),
797 Self::Var(v) => write!(f, "{}", var_with_value(*v)),
798 Self::Concrete(o) => write!(f, "{o}"),
799 Self::Instance(instance) => write!(
800 f,
801 "{}",
802 instance.display(|generic_args| {
803 InferVar::range_iter(generic_args).map(var_with_value)
804 })
805 ),
806 }
807 })
808 }
809
810 fn display_with_infer_cx<'a>(
811 &'a self,
812 cx: &'a InferCx<'_, impl Specialization>,
813 ) -> impl fmt::Display + '_ {
814 self.display_with_infer_var_values(move |v| {
815 let get = |v: InferVar| cx.infer_var_values[v.0 as usize];
818 let mut value = get(v);
819 while let Value::SameAs(v) = value {
820 let next = get(v);
821 if next == Value::Unknown {
822 break;
823 }
824 value = next;
825 }
826 value
827 })
828 }
829}
830
831impl fmt::Display for InferOperand {
832 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
833 self.display_with_infer_var_values(|_| Value::Unknown)
834 .fmt(f)
835 }
836}
837
838#[derive(Copy, Clone, PartialEq, Eq)]
843enum InferOperandListTransform {
844 TypeOfId,
850}
851
852#[derive(Clone, PartialEq)]
853struct InferOperandList<'a> {
854 operands: &'a [Operand],
855
856 all_generic_args: Range<InferVar>,
859
860 transform: Option<InferOperandListTransform>,
861}
862
863impl<'a> InferOperandList<'a> {
864 fn split_first(
865 &self,
866 cx: &InferCx<'_, impl Specialization>,
867 ) -> Option<(InferOperand, InferOperandList<'a>)> {
868 let mut list = self.clone();
869 loop {
870 let (first_operand, rest) = list.operands.split_first()?;
871 list.operands = rest;
872
873 let (first, rest_args) = InferOperand::from_operand_and_generic_args(
874 first_operand,
875 list.all_generic_args.clone(),
876 cx,
877 );
878 list.all_generic_args = rest_args;
879
880 match self.transform {
882 Some(InferOperandListTransform::TypeOfId)
884 if first_operand.id_ref_any().is_none() =>
885 {
886 continue;
887 }
888 None | Some(InferOperandListTransform::TypeOfId) => {}
889 }
890
891 let first = match self.transform {
893 None => first,
894
895 Some(InferOperandListTransform::TypeOfId) => match first {
897 InferOperand::Concrete(CopyOperand::IdRef(id)) => cx
898 .type_of_result
899 .get(&id)
900 .cloned()
901 .unwrap_or(InferOperand::Unknown),
902 InferOperand::Unknown | InferOperand::Var(_) | InferOperand::Concrete(_) => {
903 InferOperand::Unknown
904 }
905 InferOperand::Instance(instance) => {
906 let generic = &cx.specializer.generics[&instance.generic_id];
907
908 let type_of_result = match generic.def.class.opcode {
915 Op::Function => Some(generic.def.operands[1].unwrap_id_ref()),
916 _ => generic.def.result_type,
917 };
918
919 match type_of_result {
920 Some(type_of_result) => {
921 InferOperand::from_operand_and_generic_args(
922 &Operand::IdRef(type_of_result),
923 instance.generic_args,
924 cx,
925 )
926 .0
927 }
928 None => InferOperand::Unknown,
929 }
930 }
931 },
932 };
933
934 return Some((first, list));
935 }
936 }
937
938 fn iter<'b>(
939 &self,
940 cx: &'b InferCx<'_, impl Specialization>,
941 ) -> impl Iterator<Item = InferOperand> + 'b
942 where
943 'a: 'b,
944 {
945 let mut list = self.clone();
946 iter::from_fn(move || {
947 let (next, rest) = list.split_first(cx)?;
948 list = rest;
949 Some(next)
950 })
951 }
952
953 fn display_with_infer_cx<'b>(
954 &'b self,
955 cx: &'b InferCx<'a, impl Specialization>,
956 ) -> impl fmt::Display + '_ {
957 FmtBy(move |f| {
958 f.debug_list()
959 .entries(self.iter(cx).map(|operand| {
960 FmtBy(move |f| write!(f, "{}", operand.display_with_infer_cx(cx)))
961 }))
962 .finish()
963 })
964 }
965}
966
967#[derive(Default)]
969struct SmallIntMap<A: smallvec::Array>(SmallVec<A>);
970
971impl<A: smallvec::Array> SmallIntMap<A> {
972 fn get(&self, i: usize) -> Option<&A::Item> {
973 self.0.get(i)
974 }
975
976 fn get_mut_or_default(&mut self, i: usize) -> &mut A::Item
977 where
978 A::Item: Default,
979 {
980 let needed = i + 1;
981 if self.0.len() < needed {
982 self.0.resize_with(needed, Default::default);
983 }
984 &mut self.0[i]
985 }
986}
987
988impl<A: smallvec::Array> IntoIterator for SmallIntMap<A> {
989 type Item = (usize, A::Item);
990 type IntoIter = iter::Enumerate<smallvec::IntoIter<A>>;
991 fn into_iter(self) -> Self::IntoIter {
992 self.0.into_iter().enumerate()
993 }
994}
995
996impl<'a, A: smallvec::Array> IntoIterator for &'a mut SmallIntMap<A> {
997 type Item = (usize, &'a mut A::Item);
998 type IntoIter = iter::Enumerate<slice::IterMut<'a, A::Item>>;
999 fn into_iter(self) -> Self::IntoIter {
1000 self.0.iter_mut().enumerate()
1001 }
1002}
1003
1004#[derive(PartialEq)]
1005struct IndexCompositeMatch<'a> {
1006 indices: &'a [Operand],
1008
1009 leaf: InferOperand,
1011}
1012
1013#[must_use]
1015#[derive(Default)]
1016struct Match<'a> {
1017 ambiguous: bool,
1023
1024 storage_class_var_found: SmallIntMap<[SmallVec<[InferOperand; 2]>; 1]>,
1029
1030 ty_var_found: SmallIntMap<[SmallVec<[InferOperand; 4]>; 1]>,
1033
1034 index_composite_ty_var_found: SmallIntMap<[SmallVec<[IndexCompositeMatch<'a>; 1]>; 1]>,
1037
1038 ty_list_var_found: SmallIntMap<[SmallVec<[InferOperandList<'a>; 2]>; 1]>,
1041}
1042
1043impl<'a> Match<'a> {
1044 fn and(mut self, other: Self) -> Self {
1047 let Match {
1048 ambiguous,
1049 storage_class_var_found,
1050 ty_var_found,
1051 index_composite_ty_var_found,
1052 ty_list_var_found,
1053 } = &mut self;
1054
1055 *ambiguous |= other.ambiguous;
1056 for (i, other_found) in other.storage_class_var_found {
1057 storage_class_var_found
1058 .get_mut_or_default(i)
1059 .extend(other_found);
1060 }
1061 for (i, other_found) in other.ty_var_found {
1062 ty_var_found.get_mut_or_default(i).extend(other_found);
1063 }
1064 for (i, other_found) in other.index_composite_ty_var_found {
1065 index_composite_ty_var_found
1066 .get_mut_or_default(i)
1067 .extend(other_found);
1068 }
1069 for (i, other_found) in other.ty_list_var_found {
1070 ty_list_var_found.get_mut_or_default(i).extend(other_found);
1071 }
1072 self
1073 }
1074
1075 fn or(mut self, other: Self) -> Self {
1078 let Match {
1079 ambiguous,
1080 storage_class_var_found,
1081 ty_var_found,
1082 index_composite_ty_var_found,
1083 ty_list_var_found,
1084 } = &mut self;
1085
1086 *ambiguous |= other.ambiguous;
1087 for (i, self_found) in storage_class_var_found {
1088 let other_found = other
1089 .storage_class_var_found
1090 .get(i)
1091 .map_or(&[][..], |xs| &xs[..]);
1092 self_found.retain(|x| other_found.contains(x));
1093 }
1094 for (i, self_found) in ty_var_found {
1095 let other_found = other.ty_var_found.get(i).map_or(&[][..], |xs| &xs[..]);
1096 self_found.retain(|x| other_found.contains(x));
1097 }
1098 for (i, self_found) in index_composite_ty_var_found {
1099 let other_found = other
1100 .index_composite_ty_var_found
1101 .get(i)
1102 .map_or(&[][..], |xs| &xs[..]);
1103 self_found.retain(|x| other_found.contains(x));
1104 }
1105 for (i, self_found) in ty_list_var_found {
1106 let other_found = other.ty_list_var_found.get(i).map_or(&[][..], |xs| &xs[..]);
1107 self_found.retain(|x| other_found.contains(x));
1108 }
1109 self
1110 }
1111
1112 fn debug_with_infer_cx<'b, T: Specialization>(
1113 &'b self,
1114 cx: &'b InferCx<'a, T>,
1115 ) -> impl fmt::Debug + use<'a, 'b, T> {
1116 fn debug_var_found<'a, A: smallvec::Array<Item = T> + 'a, T: 'a, TD: fmt::Display>(
1117 var_found: &'a SmallIntMap<impl smallvec::Array<Item = SmallVec<A>>>,
1118 display: &'a impl Fn(&'a T) -> TD,
1119 ) -> impl Iterator<Item = impl fmt::Debug + 'a> + 'a {
1120 var_found
1121 .0
1122 .iter()
1123 .filter(|found| !found.is_empty())
1124 .map(move |found| {
1125 FmtBy(move |f| {
1126 let mut found = found.iter().map(display);
1127 write!(f, "{}", found.next().unwrap())?;
1128 for x in found {
1129 write!(f, " = {x}")?;
1130 }
1131 Ok(())
1132 })
1133 })
1134 }
1135 FmtBy(move |f| {
1136 let Self {
1137 ambiguous,
1138 storage_class_var_found,
1139 ty_var_found,
1140 index_composite_ty_var_found,
1141 ty_list_var_found,
1142 } = self;
1143 write!(f, "Match{} ", if *ambiguous { " (ambiguous)" } else { "" })?;
1144 let mut list = f.debug_list();
1145 list.entries(debug_var_found(storage_class_var_found, &move |operand| {
1146 operand.display_with_infer_cx(cx)
1147 }));
1148 list.entries(debug_var_found(ty_var_found, &move |operand| {
1149 operand.display_with_infer_cx(cx)
1150 }));
1151 list.entries(
1152 index_composite_ty_var_found
1153 .0
1154 .iter()
1155 .enumerate()
1156 .filter(|(_, found)| !found.is_empty())
1157 .flat_map(|(i, found)| found.iter().map(move |x| (i, x)))
1158 .map(move |(i, IndexCompositeMatch { indices, leaf })| {
1159 FmtBy(move |f| {
1160 match ty_var_found.get(i) {
1161 Some(found) if found.len() == 1 => {
1162 write!(f, "{}", found[0].display_with_infer_cx(cx))?;
1163 }
1164 found => {
1165 let found = found.map_or(&[][..], |xs| &xs[..]);
1166 write!(f, "(")?;
1167 for (j, operand) in found.iter().enumerate() {
1168 if j != 0 {
1169 write!(f, " = ")?;
1170 }
1171 write!(f, "{}", operand.display_with_infer_cx(cx))?;
1172 }
1173 write!(f, ")")?;
1174 }
1175 }
1176 for operand in &indices[..] {
1177 let maybe_idx = match operand {
1180 Operand::IdRef(id) => cx.specializer.int_consts.get(id),
1181 Operand::LiteralBit32(idx) => Some(idx),
1182 _ => None,
1183 };
1184 match maybe_idx {
1185 Some(idx) => write!(f, ".{idx}")?,
1186 None => write!(f, "[{operand}]")?,
1187 }
1188 }
1189 write!(f, " = {}", leaf.display_with_infer_cx(cx))
1190 })
1191 }),
1192 );
1193 list.entries(debug_var_found(ty_list_var_found, &move |list| {
1194 list.display_with_infer_cx(cx)
1195 }));
1196 list.finish()
1197 })
1198 }
1199}
1200
1201struct Unapplicable;
1203
1204impl<'a, S: Specialization> InferCx<'a, S> {
1205 #[allow(clippy::unused_self)] fn match_storage_class_pat(
1208 &self,
1209 pat: &StorageClassPat,
1210 storage_class: InferOperand,
1211 ) -> Match<'a> {
1212 match pat {
1213 StorageClassPat::Any => Match::default(),
1214 StorageClassPat::Var(i) => {
1215 let mut m = Match::default();
1216 m.storage_class_var_found
1217 .get_mut_or_default(*i)
1218 .push(storage_class);
1219 m
1220 }
1221 }
1222 }
1223
1224 fn match_ty_pat(&self, pat: &TyPat<'_>, ty: InferOperand) -> Result<Match<'a>, Unapplicable> {
1226 match pat {
1227 TyPat::Any => Ok(Match::default()),
1228 TyPat::Var(i) => {
1229 let mut m = Match::default();
1230 m.ty_var_found.get_mut_or_default(*i).push(ty);
1231 Ok(m)
1232 }
1233 TyPat::Either(a, b) => match self.match_ty_pat(a, ty.clone()) {
1234 Ok(m) if !m.ambiguous => Ok(m),
1235 a_result => match (a_result, self.match_ty_pat(b, ty)) {
1236 (Ok(ma), Ok(mb)) => Ok(ma.or(mb)),
1237 (Ok(m), _) | (_, Ok(m)) => Ok(m),
1238 (Err(Unapplicable), Err(Unapplicable)) => Err(Unapplicable),
1239 },
1240 },
1241 TyPat::IndexComposite(composite_pat) => match composite_pat {
1242 TyPat::Var(i) => {
1243 let mut m = Match::default();
1244 m.index_composite_ty_var_found.get_mut_or_default(*i).push(
1245 IndexCompositeMatch {
1246 indices: &[],
1250 leaf: ty,
1251 },
1252 );
1253 Ok(m)
1254 }
1255 _ => unreachable!(
1256 "`IndexComposite({:?})` isn't supported, only type variable
1257 patterns are (for the composite type), e.g. `IndexComposite(T)`",
1258 composite_pat
1259 ),
1260 },
1261 _ => {
1262 let instance = match ty {
1263 InferOperand::Unknown | InferOperand::Concrete(_) => {
1264 return Ok(Match {
1265 ambiguous: true,
1266 ..Match::default()
1267 });
1268 }
1269 InferOperand::Var(_) => return Err(Unapplicable),
1270 InferOperand::Instance(instance) => instance,
1271 };
1272 let generic = &self.specializer.generics[&instance.generic_id];
1273
1274 let ty_operands = InferOperandList {
1275 operands: &generic.def.operands,
1276 all_generic_args: instance.generic_args,
1277 transform: None,
1278 };
1279 let simple = |op, inner_pat| {
1280 if generic.def.class.opcode == op {
1281 self.match_ty_pat(inner_pat, ty_operands.split_first(self).unwrap().0)
1282 } else {
1283 Err(Unapplicable)
1284 }
1285 };
1286 match pat {
1287 TyPat::Any | TyPat::Var(_) | TyPat::Either(..) | TyPat::IndexComposite(_) => {
1288 unreachable!()
1289 }
1290
1291 TyPat::Void => unreachable!(),
1294
1295 TyPat::Pointer(storage_class_pat, pointee_pat) => {
1296 let mut ty_operands = ty_operands.iter(self);
1297 let (storage_class, pointee_ty) =
1298 (ty_operands.next().unwrap(), ty_operands.next().unwrap());
1299 Ok(self
1300 .match_storage_class_pat(storage_class_pat, storage_class)
1301 .and(self.match_ty_pat(pointee_pat, pointee_ty)?))
1302 }
1303 TyPat::Array(pat) => simple(Op::TypeArray, pat),
1304 TyPat::Vector(pat) => simple(Op::TypeVector, pat),
1305 TyPat::Vector4(pat) => match ty_operands.operands {
1306 [_, Operand::LiteralBit32(4)] => simple(Op::TypeVector, pat),
1307 _ => Err(Unapplicable),
1308 },
1309 TyPat::Matrix(pat) => simple(Op::TypeMatrix, pat),
1310 TyPat::Image(pat) => simple(Op::TypeImage, pat),
1311 TyPat::Pipe(_pat) => {
1312 if generic.def.class.opcode == Op::TypePipe {
1313 Ok(Match::default())
1314 } else {
1315 Err(Unapplicable)
1316 }
1317 }
1318 TyPat::SampledImage(pat) => simple(Op::TypeSampledImage, pat),
1319 TyPat::Struct(fields_pat) => {
1320 if generic.def.class.opcode == Op::TypeStruct {
1321 self.match_ty_list_pat(fields_pat, ty_operands)
1322 } else {
1323 Err(Unapplicable)
1324 }
1325 }
1326 TyPat::Function(ret_pat, params_pat) => {
1327 let (ret_ty, params_ty_list) = ty_operands.split_first(self).unwrap();
1328 Ok(self
1329 .match_ty_pat(ret_pat, ret_ty)?
1330 .and(self.match_ty_list_pat(params_pat, params_ty_list)?))
1331 }
1332 }
1333 }
1334 }
1335 }
1336
1337 fn match_ty_list_pat(
1339 &self,
1340 mut list_pat: &TyListPat<'_>,
1341 mut ty_list: InferOperandList<'a>,
1342 ) -> Result<Match<'a>, Unapplicable> {
1343 let mut m = Match::default();
1344
1345 while let TyListPat::Cons { first: pat, suffix } = list_pat {
1346 list_pat = suffix;
1347
1348 let (ty, rest) = ty_list.split_first(self).ok_or(Unapplicable)?;
1349 ty_list = rest;
1350
1351 m = m.and(self.match_ty_pat(pat, ty)?);
1352 }
1353
1354 match list_pat {
1355 TyListPat::Cons { .. } => unreachable!(),
1356
1357 TyListPat::Any => {}
1358 TyListPat::Var(i) => {
1359 m.ty_list_var_found.get_mut_or_default(*i).push(ty_list);
1360 }
1361 TyListPat::Repeat(repeat_list_pat) => {
1362 let mut tys = ty_list.iter(self).peekable();
1363 loop {
1364 let mut list_pat = repeat_list_pat;
1365 while let TyListPat::Cons { first: pat, suffix } = list_pat {
1366 m = m.and(self.match_ty_pat(pat, tys.next().ok_or(Unapplicable)?)?);
1367 list_pat = suffix;
1368 }
1369 assert!(matches!(list_pat, TyListPat::Nil));
1370 if tys.peek().is_none() {
1371 break;
1372 }
1373 }
1374 }
1375 TyListPat::Nil => {
1376 if ty_list.split_first(self).is_some() {
1377 return Err(Unapplicable);
1378 }
1379 }
1380 }
1381
1382 Ok(m)
1383 }
1384
1385 fn match_inst_sig(
1388 &self,
1389 sig: &InstSig<'_>,
1390 inst: &'a Instruction,
1391 inputs_generic_args: Range<InferVar>,
1392 result_type: Option<InferOperand>,
1393 ) -> Result<Match<'a>, Unapplicable> {
1394 let mut m = Match::default();
1395
1396 if let Some(pat) = sig.storage_class {
1397 let all_operands = InferOperandList {
1401 operands: &inst.operands,
1402 all_generic_args: inputs_generic_args.clone(),
1403 transform: None,
1404 };
1405 let storage_class = all_operands
1406 .iter(self)
1407 .zip(&inst.operands)
1408 .filter(|(_, original)| matches!(original, Operand::StorageClass(_)))
1409 .map(|(operand, _)| operand)
1410 .next()
1411 .ok_or(Unapplicable)?;
1412 m = m.and(self.match_storage_class_pat(pat, storage_class));
1413 }
1414
1415 let input_ty_list = InferOperandList {
1416 operands: &inst.operands,
1417 all_generic_args: inputs_generic_args,
1418 transform: Some(InferOperandListTransform::TypeOfId),
1419 };
1420
1421 m = m.and(self.match_ty_list_pat(sig.input_types, input_ty_list.clone())?);
1422
1423 match (sig.output_type, result_type) {
1424 (Some(pat), Some(result_type)) => {
1425 m = m.and(self.match_ty_pat(pat, result_type)?);
1426 }
1427 (None, None) => {}
1428 _ => return Err(Unapplicable),
1429 }
1430
1431 if !m.index_composite_ty_var_found.0.is_empty() {
1432 let composite_indices = {
1433 let mut ty_list = input_ty_list;
1435 let mut list_pat = sig.input_types;
1436 while let TyListPat::Cons { first: _, suffix } = list_pat {
1437 list_pat = suffix;
1438 ty_list = ty_list.split_first(self).ok_or(Unapplicable)?.1;
1439 }
1440
1441 assert_eq!(
1442 list_pat,
1443 &TyListPat::Any,
1444 "`IndexComposite` must have input types end in `..`"
1445 );
1446
1447 ty_list.operands
1452 };
1453
1454 for (_, found) in &mut m.index_composite_ty_var_found {
1456 for index_composite_match in found {
1457 let empty = mem::replace(&mut index_composite_match.indices, composite_indices);
1458 assert_eq!(empty, &[]);
1459 }
1460 }
1461 }
1462
1463 Ok(m)
1464 }
1465
1466 fn match_inst_sigs(
1469 &self,
1470 sigs: &[InstSig<'_>],
1471 inst: &'a Instruction,
1472 inputs_generic_args: Range<InferVar>,
1473 result_type: Option<InferOperand>,
1474 ) -> Result<Match<'a>, Unapplicable> {
1475 let mut result = Err(Unapplicable);
1476 for sig in sigs {
1477 result = match (
1478 result,
1479 self.match_inst_sig(sig, inst, inputs_generic_args.clone(), result_type.clone()),
1480 ) {
1481 (Err(Unapplicable), Ok(m)) if !m.ambiguous => return Ok(m),
1482 (Ok(a), Ok(b)) => Ok(a.or(b)),
1483 (Ok(m), _) | (_, Ok(m)) => Ok(m),
1484 (Err(Unapplicable), Err(Unapplicable)) => Err(Unapplicable),
1485 };
1486 }
1487 result
1488 }
1489}
1490
1491enum InferError {
1492 Conflict(InferOperand, InferOperand),
1495}
1496
1497impl InferError {
1498 fn report(self, inst: &Instruction) {
1499 match self {
1501 Self::Conflict(a, b) => {
1502 error!("inference conflict: {a:?} vs {b:?}");
1503 }
1504 }
1505 error!(" in ");
1506 if let Some(result_id) = inst.result_id {
1508 error!("%{result_id} = ");
1509 }
1510 error!("Op{:?}", inst.class.opcode);
1511 for operand in inst
1512 .result_type
1513 .map(Operand::IdRef)
1514 .iter()
1515 .chain(inst.operands.iter())
1516 {
1517 error!(" {operand}");
1518 }
1519 error!("");
1520
1521 std::process::exit(1);
1522 }
1523}
1524
1525impl<'a, S: Specialization> InferCx<'a, S> {
1526 fn resolve_infer_var(&mut self, v: InferVar) -> InferVar {
1530 match self.infer_var_values[v.0 as usize] {
1531 Value::Unknown | Value::Known(_) => v,
1532 Value::SameAs(next) => {
1533 let resolved = self.resolve_infer_var(next);
1534 if resolved != next {
1535 self.infer_var_values[v.0 as usize] = Value::SameAs(resolved);
1538 }
1539 resolved
1540 }
1541 }
1542 }
1543
1544 fn equate_infer_vars(&mut self, a: InferVar, b: InferVar) -> Result<InferVar, InferError> {
1547 let (a, b) = (self.resolve_infer_var(a), self.resolve_infer_var(b));
1548
1549 if a == b {
1550 return Ok(a);
1551 }
1552
1553 let (older, newer) = (a.min(b), a.max(b));
1555 let newer_value = mem::replace(
1556 &mut self.infer_var_values[newer.0 as usize],
1557 Value::SameAs(older),
1558 );
1559 match (self.infer_var_values[older.0 as usize], newer_value) {
1560 (Value::SameAs(_), _) | (_, Value::SameAs(_)) => unreachable!(),
1562
1563 (Value::Known(x), Value::Known(y)) => {
1565 if x != y {
1566 return Err(InferError::Conflict(
1567 InferOperand::Concrete(x),
1568 InferOperand::Concrete(y),
1569 ));
1570 }
1571 }
1572
1573 (Value::Unknown, Value::Known(_)) => {
1575 self.infer_var_values[older.0 as usize] = newer_value;
1576 }
1577
1578 (_, Value::Unknown) => {}
1579 }
1580
1581 Ok(older)
1582 }
1583
1584 fn equate_infer_var_ranges(
1586 &mut self,
1587 a: Range<InferVar>,
1588 b: Range<InferVar>,
1589 ) -> Result<Range<InferVar>, InferError> {
1590 if a == b {
1591 return Ok(a);
1592 }
1593
1594 assert_eq!(a.end.0 - a.start.0, b.end.0 - b.start.0);
1595
1596 for (a, b) in InferVar::range_iter(&a).zip(InferVar::range_iter(&b)) {
1597 self.equate_infer_vars(a, b)?;
1598 }
1599
1600 Ok(if a.start < b.start { a } else { b })
1604 }
1605
1606 fn equate_infer_operands(
1608 &mut self,
1609 a: InferOperand,
1610 b: InferOperand,
1611 ) -> Result<InferOperand, InferError> {
1612 if a == b {
1613 return Ok(a);
1614 }
1615
1616 #[allow(clippy::match_same_arms)]
1617 Ok(match (a.clone(), b.clone()) {
1618 (
1621 InferOperand::Instance(Instance {
1622 generic_id: a_id,
1623 generic_args: a_args,
1624 }),
1625 InferOperand::Instance(Instance {
1626 generic_id: b_id,
1627 generic_args: b_args,
1628 }),
1629 ) => {
1630 if a_id != b_id {
1631 return Err(InferError::Conflict(a, b));
1632 }
1633 InferOperand::Instance(Instance {
1634 generic_id: a_id,
1635 generic_args: self.equate_infer_var_ranges(a_args, b_args)?,
1636 })
1637 }
1638
1639 (InferOperand::Instance(_), _) | (_, InferOperand::Instance(_)) => {
1641 return Err(InferError::Conflict(a, b));
1642 }
1643
1644 (InferOperand::Var(a), InferOperand::Var(b)) => {
1646 InferOperand::Var(self.equate_infer_vars(a, b)?)
1647 }
1648
1649 (InferOperand::Var(v), InferOperand::Concrete(new))
1651 | (InferOperand::Concrete(new), InferOperand::Var(v)) => {
1652 let v = self.resolve_infer_var(v);
1653 match &mut self.infer_var_values[v.0 as usize] {
1654 Value::SameAs(_) => unreachable!(),
1656
1657 &mut Value::Known(old) => {
1658 if new != old {
1659 return Err(InferError::Conflict(
1660 InferOperand::Concrete(old),
1661 InferOperand::Concrete(new),
1662 ));
1663 }
1664 }
1665
1666 value @ Value::Unknown => *value = Value::Known(new),
1667 }
1668 InferOperand::Var(v)
1669 }
1670
1671 (InferOperand::Concrete(_), InferOperand::Concrete(_)) => {
1673 return Err(InferError::Conflict(a, b));
1675 }
1676
1677 (InferOperand::Unknown, x) | (x, InferOperand::Unknown) => x,
1680 })
1681 }
1682
1683 fn index_composite(&self, composite_ty: InferOperand, indices: &[Operand]) -> InferOperand {
1688 let mut ty = composite_ty;
1689 for idx in indices {
1690 let instance = match ty {
1691 InferOperand::Unknown | InferOperand::Concrete(_) | InferOperand::Var(_) => {
1692 return InferOperand::Unknown;
1693 }
1694 InferOperand::Instance(instance) => instance,
1695 };
1696 let generic = &self.specializer.generics[&instance.generic_id];
1697
1698 let ty_opcode = generic.def.class.opcode;
1699 let ty_operands = InferOperandList {
1700 operands: &generic.def.operands,
1701 all_generic_args: instance.generic_args,
1702 transform: None,
1703 };
1704
1705 let ty_operands_idx = match ty_opcode {
1706 Op::TypeArray | Op::TypeRuntimeArray | Op::TypeVector | Op::TypeMatrix => 0,
1707 Op::TypeStruct => match idx {
1708 Operand::IdRef(id) => {
1709 *self.specializer.int_consts.get(id).unwrap_or_else(|| {
1710 unreachable!("non-constant `OpTypeStruct` field index {}", id);
1711 })
1712 }
1713 &Operand::LiteralBit32(i) => i,
1714 _ => {
1715 unreachable!("invalid `OpTypeStruct` field index operand {:?}", idx);
1716 }
1717 },
1718 _ => unreachable!("indexing non-composite type `Op{:?}`", ty_opcode),
1719 };
1720
1721 ty = ty_operands
1722 .iter(self)
1723 .nth(ty_operands_idx as usize)
1724 .unwrap_or_else(|| {
1725 unreachable!(
1726 "out of bounds index {} for `Op{:?}`",
1727 ty_operands_idx, ty_opcode
1728 );
1729 });
1730 }
1731 ty
1732 }
1733
1734 fn equate_match_findings(&mut self, m: Match<'_>) -> Result<(), InferError> {
1737 let Match {
1738 ambiguous: _,
1739
1740 storage_class_var_found,
1741 ty_var_found,
1742 index_composite_ty_var_found,
1743 ty_list_var_found,
1744 } = m;
1745
1746 for (_, found) in storage_class_var_found {
1747 let mut found = found.into_iter();
1748 if let Some(first) = found.next() {
1749 found.try_fold(first, |a, b| self.equate_infer_operands(a, b))?;
1750 }
1751 }
1752
1753 for (i, found) in ty_var_found {
1754 let mut found = found.into_iter();
1755 if let Some(first) = found.next() {
1756 let equated_ty = found.try_fold(first, |a, b| self.equate_infer_operands(a, b))?;
1757
1758 let index_composite_found = index_composite_ty_var_found
1761 .get(i)
1762 .map_or(&[][..], |xs| &xs[..]);
1763 for IndexCompositeMatch { indices, leaf } in index_composite_found {
1764 let indexing_result_ty = self.index_composite(equated_ty.clone(), indices);
1765 self.equate_infer_operands(indexing_result_ty, leaf.clone())?;
1766 }
1767 }
1768 }
1769
1770 for (_, mut found) in ty_list_var_found {
1771 if let Some((first_list, other_lists)) = found.split_first_mut() {
1772 while let Some((first, rest)) = first_list.split_first(self) {
1775 *first_list = rest;
1776
1777 other_lists.iter_mut().try_fold(first, |a, b_list| {
1778 let (b, rest) = b_list
1779 .split_first(self)
1780 .expect("list length mismatch (invalid SPIR-V?)");
1781 *b_list = rest;
1782 self.equate_infer_operands(a, b)
1783 })?;
1784 }
1785
1786 for other_list in other_lists {
1787 assert!(
1788 other_list.split_first(self).is_none(),
1789 "list length mismatch (invalid SPIR-V?)"
1790 );
1791 }
1792 }
1793 }
1794
1795 Ok(())
1796 }
1797
1798 fn record_instantiated_operand(&mut self, loc: OperandLocation, operand: InferOperand) {
1801 match operand {
1802 InferOperand::Var(v) => {
1803 self.inferred_operands.push((loc, v));
1804 }
1805 InferOperand::Instance(instance) => {
1806 self.instantiated_operands.push((loc, instance));
1807 }
1808 InferOperand::Unknown | InferOperand::Concrete(_) => {}
1809 }
1810 }
1811
1812 fn instantiate_instruction(&mut self, inst: &'a Instruction, inst_loc: InstructionLocation) {
1816 let mut all_generic_args = {
1817 let next_infer_var = InferVar(self.infer_var_values.len().try_into().unwrap());
1818 next_infer_var..next_infer_var
1819 };
1820
1821 let (instantiate_result_type, record_fn_ret_ty, type_of_result) = match inst.class.opcode {
1828 Op::Function => (
1829 None,
1830 inst.result_type,
1831 Some(inst.operands[1].unwrap_id_ref()),
1832 ),
1833 _ => (inst.result_type, None, inst.result_type),
1834 };
1835
1836 for (operand_idx, operand) in instantiate_result_type
1837 .map(Operand::IdRef)
1838 .iter()
1839 .map(|o| (OperandIdx::ResultType, o))
1840 .chain(
1841 inst.operands
1842 .iter()
1843 .enumerate()
1844 .map(|(i, o)| (OperandIdx::Input(i), o)),
1845 )
1846 {
1847 let (operand, rest) = InferOperand::from_operand_and_generic_args(
1849 operand,
1850 all_generic_args.end..InferVar(u32::MAX),
1851 self,
1852 );
1853 let generic_args = all_generic_args.end..rest.start;
1854 all_generic_args.end = generic_args.end;
1855
1856 let generic = match &operand {
1857 InferOperand::Instance(instance) => {
1858 Some(&self.specializer.generics[&instance.generic_id])
1859 }
1860 _ => None,
1861 };
1862
1863 match generic {
1866 Some(Generic {
1867 param_values: Some(values),
1868 ..
1869 }) => self.infer_var_values.extend(
1870 values
1871 .iter()
1872 .map(|v| v.map_var(|Param(p)| InferVar(generic_args.start.0 + p))),
1873 ),
1874
1875 _ => {
1876 self.infer_var_values
1877 .extend(InferVar::range_iter(&generic_args).map(|_| Value::Unknown));
1878 }
1879 }
1880
1881 self.record_instantiated_operand(
1882 OperandLocation {
1883 inst_loc,
1884 operand_idx,
1885 },
1886 operand,
1887 );
1888 }
1889
1890 if let Some(ret_ty) = record_fn_ret_ty {
1892 let (ret_ty, _) = InferOperand::from_operand_and_generic_args(
1893 &Operand::IdRef(ret_ty),
1894 all_generic_args.clone(),
1895 self,
1896 );
1897 self.record_instantiated_operand(
1898 OperandLocation {
1899 inst_loc,
1900 operand_idx: OperandIdx::ResultType,
1901 },
1902 ret_ty,
1903 );
1904 }
1905
1906 let (type_of_result, inputs_generic_args) = match type_of_result {
1908 Some(type_of_result) => {
1909 let (type_of_result, rest) = InferOperand::from_operand_and_generic_args(
1910 &Operand::IdRef(type_of_result),
1911 all_generic_args.clone(),
1912 self,
1913 );
1914 (
1915 Some(type_of_result),
1916 match inst.class.opcode {
1918 Op::Function => all_generic_args,
1919 _ => rest,
1920 },
1921 )
1922 }
1923 None => (None, all_generic_args),
1924 };
1925
1926 let debug_dump_if_enabled = |cx: &Self, prefix| {
1927 let result_type = match inst.class.opcode {
1928 Op::Function => Some(
1930 InferOperand::from_operand_and_generic_args(
1931 &Operand::IdRef(inst.result_type.unwrap()),
1932 inputs_generic_args.clone(),
1933 cx,
1934 )
1935 .0,
1936 ),
1937 _ => type_of_result.clone(),
1938 };
1939 let inputs = InferOperandList {
1940 operands: &inst.operands,
1941 all_generic_args: inputs_generic_args.clone(),
1942 transform: None,
1943 };
1944
1945 if inst_loc != InstructionLocation::Module {
1946 debug!(" ");
1947 }
1948 debug!("{prefix}");
1949 if let Some(result_id) = inst.result_id {
1950 debug!("%{result_id} = ");
1951 }
1952 debug!("Op{:?}", inst.class.opcode);
1953 for operand in result_type.into_iter().chain(inputs.iter(cx)) {
1954 debug!(" {}", operand.display_with_infer_cx(cx));
1955 }
1956 debug!("");
1957 };
1958
1959 if let Some(sigs) = spirv_type_constraints::instruction_signatures(inst.class.opcode) {
1961 assert_ne!(inst.class.opcode, Op::Function);
1964
1965 debug_dump_if_enabled(self, " -> ");
1966
1967 let m = match self.match_inst_sigs(
1968 sigs,
1969 inst,
1970 inputs_generic_args.clone(),
1971 type_of_result.clone(),
1972 ) {
1973 Ok(m) => m,
1974
1975 Err(Unapplicable) => unreachable!(
1981 "spirv_type_constraints(Op{:?}) = `{:?}` doesn't match `{:?}`",
1982 inst.class.opcode, sigs, inst
1983 ),
1984 };
1985
1986 if inst_loc != InstructionLocation::Module {
1987 debug!(" ");
1988 }
1989 debug!(" found {:?}", m.debug_with_infer_cx(self));
1990
1991 if let Err(e) = self.equate_match_findings(m) {
1992 e.report(inst);
1993 }
1994
1995 debug_dump_if_enabled(self, " <- ");
1996 } else {
1997 debug_dump_if_enabled(self, "");
1998 }
1999
2000 if let Some(type_of_result) = type_of_result {
2001 match type_of_result {
2004 InferOperand::Var(_) | InferOperand::Instance(_) => {
2005 self.type_of_result
2006 .insert(inst.result_id.unwrap(), type_of_result);
2007 }
2008 InferOperand::Unknown | InferOperand::Concrete(_) => {}
2009 }
2010 }
2011 }
2012
2013 fn instantiate_function(&mut self, func: &'a Function) {
2016 let func_id = func.def_id().unwrap();
2017
2018 debug!("");
2019 debug!("specializer::instantiate_function(%{func_id}");
2020 if let Some(name) = self.specializer.debug_names.get(&func_id) {
2021 debug!(" {name}");
2022 }
2023 debug!("):");
2024
2025 assert!(self.infer_var_values.is_empty());
2029 self.instantiate_instruction(func.def.as_ref().unwrap(), InstructionLocation::Module);
2030
2031 debug!("infer body {{");
2032
2033 let ret_ty = match self.type_of_result.get(&func_id).cloned() {
2036 Some(InferOperand::Instance(instance)) => {
2037 let generic = &self.specializer.generics[&instance.generic_id];
2038 assert_eq!(generic.def.class.opcode, Op::TypeFunction);
2039
2040 let (ret_ty, mut params_ty_list) = InferOperandList {
2041 operands: &generic.def.operands,
2042 all_generic_args: instance.generic_args,
2043 transform: None,
2044 }
2045 .split_first(self)
2046 .unwrap();
2047
2048 let mut params = func.parameters.iter().enumerate();
2050 while let Some((param_ty, rest)) = params_ty_list.split_first(self) {
2051 params_ty_list = rest;
2052
2053 let (i, param) = params.next().unwrap();
2054 assert_eq!(param.class.opcode, Op::FunctionParameter);
2055
2056 debug!(
2057 " %{} = Op{:?} {}",
2058 param.result_id.unwrap(),
2059 param.class.opcode,
2060 param_ty.display_with_infer_cx(self)
2061 );
2062
2063 self.record_instantiated_operand(
2064 OperandLocation {
2065 inst_loc: InstructionLocation::FnParam(i),
2066 operand_idx: OperandIdx::ResultType,
2067 },
2068 param_ty.clone(),
2069 );
2070 match param_ty {
2071 InferOperand::Var(_) | InferOperand::Instance(_) => {
2072 self.type_of_result
2073 .insert(param.result_id.unwrap(), param_ty);
2074 }
2075 InferOperand::Unknown | InferOperand::Concrete(_) => {}
2076 }
2077 }
2078 assert_eq!(params.next(), None);
2079
2080 Some(ret_ty)
2081 }
2082
2083 _ => None,
2084 };
2085
2086 for (block_idx, block) in func.blocks.iter().enumerate() {
2087 for (inst_idx, inst) in block.instructions.iter().enumerate() {
2088 match inst.class.opcode {
2091 Op::ReturnValue => {
2092 let ret_val_id = inst.operands[0].unwrap_id_ref();
2093 if let (Some(expected), Some(found)) = (
2094 ret_ty.clone(),
2095 self.type_of_result.get(&ret_val_id).cloned(),
2096 ) && let Err(e) = self.equate_infer_operands(expected, found)
2097 {
2098 e.report(inst);
2099 }
2100 }
2101
2102 Op::Return => {}
2103
2104 _ => self.instantiate_instruction(
2105 inst,
2106 InstructionLocation::FnBody {
2107 block_idx,
2108 inst_idx,
2109 },
2110 ),
2111 }
2112 }
2113 }
2114
2115 debug!("}}");
2116 if let Some(func_ty) = self.type_of_result.get(&func_id) {
2117 debug!(" -> %{}: {}", func_id, func_ty.display_with_infer_cx(self));
2118 }
2119 debug!("");
2120 }
2121
2122 fn resolve_infer_var_to_concrete_or_param(
2128 &mut self,
2129 v: InferVar,
2130 generic_params: RangeTo<Param>,
2131 ) -> ConcreteOrParam {
2132 let v = self.resolve_infer_var(v);
2133 let InferVar(i) = v;
2134 match self.infer_var_values[i as usize] {
2135 Value::SameAs(_) => unreachable!(),
2137
2138 Value::Unknown => {
2139 if i < generic_params.end.0 {
2140 ConcreteOrParam::Param(Param(i))
2141 } else {
2142 ConcreteOrParam::Concrete(
2143 CopyOperand::try_from(&self.specializer.specialization.concrete_fallback())
2144 .unwrap(),
2145 )
2146 }
2147 }
2148 Value::Known(x) => ConcreteOrParam::Concrete(x),
2149 }
2150 }
2151
2152 fn into_replacements(mut self, generic_params: RangeTo<Param>) -> Replacements {
2157 let mut with_instance: IndexMap<_, Vec<_>> = IndexMap::new();
2158 for (loc, instance) in mem::take(&mut self.instantiated_operands) {
2159 with_instance
2160 .entry(Instance {
2161 generic_id: instance.generic_id,
2162 generic_args: InferVar::range_iter(&instance.generic_args)
2163 .map(|v| self.resolve_infer_var_to_concrete_or_param(v, generic_params))
2164 .collect(),
2165 })
2166 .or_default()
2167 .push(loc);
2168 }
2169
2170 let with_concrete_or_param = mem::take(&mut self.inferred_operands)
2171 .into_iter()
2172 .map(|(loc, v)| {
2173 (
2174 loc,
2175 self.resolve_infer_var_to_concrete_or_param(v, generic_params),
2176 )
2177 })
2178 .collect();
2179
2180 Replacements {
2181 with_instance,
2182 with_concrete_or_param,
2183 }
2184 }
2185}
2186
2187struct Expander<'a, S: Specialization> {
2192 specializer: &'a Specializer<S>,
2193
2194 builder: Builder,
2195
2196 instances: BTreeMap<Instance<SmallVec<[CopyOperand; 4]>>, Word>,
2202
2203 propagate_instances_queue: VecDeque<Instance<SmallVec<[CopyOperand; 4]>>>,
2207}
2208
2209impl<'a, S: Specialization> Expander<'a, S> {
2210 fn new(specializer: &'a Specializer<S>, module: Module) -> Self {
2211 Expander {
2212 specializer,
2213
2214 builder: Builder::new_from_module(module),
2215
2216 instances: BTreeMap::new(),
2217 propagate_instances_queue: VecDeque::new(),
2218 }
2219 }
2220
2221 fn all_instances_of(
2226 &self,
2227 generic_id: Word,
2228 ) -> std::collections::btree_map::Range<'_, Instance<SmallVec<[CopyOperand; 4]>>, Word> {
2229 let first_instance_of = |generic_id| Instance {
2230 generic_id,
2231 generic_args: SmallVec::new(),
2232 };
2233 self.instances
2234 .range(first_instance_of(generic_id)..first_instance_of(generic_id + 1))
2235 }
2236
2237 fn alloc_instance_id(&mut self, instance: Instance<SmallVec<[CopyOperand; 4]>>) -> Word {
2241 use std::collections::btree_map::Entry;
2242
2243 match self.instances.entry(instance) {
2244 Entry::Occupied(entry) => *entry.get(),
2245 Entry::Vacant(entry) => {
2246 let instance = entry.key().clone();
2249
2250 self.propagate_instances_queue.push_back(instance);
2251 *entry.insert(self.builder.id())
2252 }
2253 }
2254 }
2255
2256 fn propagate_instances(&mut self) {
2263 while let Some(instance) = self.propagate_instances_queue.pop_back() {
2264 for _ in self.specializer.generics[&instance.generic_id]
2266 .replacements
2267 .to_concrete(&instance.generic_args, |i| self.alloc_instance_id(i))
2268 {}
2269 }
2270 }
2271
2272 fn expand_module(mut self) -> Module {
2276 self.propagate_instances();
2279
2280 let module = self.builder.module_mut();
2282 let mut entry_points = mem::take(&mut module.entry_points);
2283 let debug_names = mem::take(&mut module.debug_names);
2284 let annotations = mem::take(&mut module.annotations);
2285 let types_global_values = mem::take(&mut module.types_global_values);
2286 let functions = mem::take(&mut module.functions);
2287
2288 for inst in &mut entry_points {
2291 let func_id = inst.operands[1].unwrap_id_ref();
2292 assert!(
2293 !self.specializer.generics.contains_key(&func_id),
2294 "entry-point %{func_id} shouldn't be \"generic\""
2295 );
2296
2297 for interface_operand in &mut inst.operands[3..] {
2298 let interface_id = interface_operand.unwrap_id_ref();
2299 let mut instances = self.all_instances_of(interface_id);
2300 match (instances.next(), instances.next()) {
2301 (None, _) => unreachable!(
2302 "entry-point %{} has overly-\"generic\" \
2303 interface variable %{}, with no instances",
2304 func_id, interface_id
2305 ),
2306 (Some(_), Some(_)) => unreachable!(
2307 "entry-point %{} has overly-\"generic\" \
2308 interface variable %{}, with too many instances: {:?}",
2309 func_id,
2310 interface_id,
2311 FmtBy(|f| f
2312 .debug_list()
2313 .entries(self.all_instances_of(interface_id).map(
2314 |(instance, _)| FmtBy(move |f| write!(
2315 f,
2316 "{}",
2317 instance.display(|generic_args| generic_args.iter().copied())
2318 ))
2319 ))
2320 .finish())
2321 ),
2322 (Some((_, &instance_id)), None) => {
2323 *interface_operand = Operand::IdRef(instance_id);
2324 }
2325 }
2326 }
2327 }
2328
2329 let expand_debug_or_annotation = |insts: Vec<Instruction>| {
2334 let mut expanded_insts = Vec::with_capacity(insts.len().next_power_of_two());
2335 for inst in insts {
2336 if let [Operand::IdRef(target), ..] = inst.operands[..]
2337 && self.specializer.generics.contains_key(&target)
2338 {
2339 expanded_insts.extend(self.all_instances_of(target).map(
2340 |(_, &instance_id)| {
2341 let mut expanded_inst = inst.clone();
2342 expanded_inst.operands[0] = Operand::IdRef(instance_id);
2343 expanded_inst
2344 },
2345 ));
2346 continue;
2347 }
2348 expanded_insts.push(inst);
2349 }
2350 expanded_insts
2351 };
2352
2353 let expanded_debug_names = expand_debug_or_annotation(debug_names);
2355
2356 let mut expanded_annotations = expand_debug_or_annotation(annotations);
2358
2359 let mut expanded_types_global_values =
2361 Vec::with_capacity(types_global_values.len().next_power_of_two());
2362 for inst in types_global_values {
2363 if let Some(result_id) = inst.result_id
2364 && let Some(generic) = self.specializer.generics.get(&result_id)
2365 {
2366 expanded_types_global_values.extend(self.all_instances_of(result_id).map(
2367 |(instance, &instance_id)| {
2368 let mut expanded_inst = inst.clone();
2369 expanded_inst.result_id = Some(instance_id);
2370 for (loc, operand) in generic
2371 .replacements
2372 .to_concrete(&instance.generic_args, |i| self.instances[&i])
2373 {
2374 expanded_inst.index_set(loc, operand.into());
2375 }
2376 expanded_inst
2377 },
2378 ));
2379 continue;
2380 }
2381 expanded_types_global_values.push(inst);
2382 }
2383
2384 let mut expanded_functions = Vec::with_capacity(functions.len().next_power_of_two());
2386 for func in functions {
2387 let func_id = func.def_id().unwrap();
2388 if let Some(generic) = self.specializer.generics.get(&func_id) {
2389 let old_expanded_functions_len = expanded_functions.len();
2390 expanded_functions.extend(self.all_instances_of(func_id).map(
2391 |(instance, &instance_id)| {
2392 let mut expanded_func = func.clone();
2393 expanded_func.def.as_mut().unwrap().result_id = Some(instance_id);
2394 for (loc, operand) in generic
2395 .replacements
2396 .to_concrete(&instance.generic_args, |i| self.instances[&i])
2397 {
2398 expanded_func.index_set(loc, operand.into());
2399 }
2400 expanded_func
2401 },
2402 ));
2403
2404 let newly_expanded_functions =
2411 &mut expanded_functions[old_expanded_functions_len..];
2412 if newly_expanded_functions.len() > 1 {
2413 let mut rewrite_rules = FxHashMap::default();
2416
2417 for func in newly_expanded_functions {
2418 rewrite_rules.clear();
2419
2420 rewrite_rules.extend(func.parameters.iter_mut().map(|param| {
2421 let old_id = param.result_id.unwrap();
2422 let new_id = self.builder.id();
2423
2424 param.result_id = Some(new_id);
2428
2429 (old_id, new_id)
2430 }));
2431 rewrite_rules.extend(
2432 func.blocks
2433 .iter()
2434 .flat_map(|b| b.label.iter().chain(b.instructions.iter()))
2435 .filter_map(|inst| inst.result_id)
2436 .map(|old_id| (old_id, self.builder.id())),
2437 );
2438
2439 super::apply_rewrite_rules(&rewrite_rules, &mut func.blocks);
2440
2441 for annotation_idx in 0..expanded_annotations.len() {
2443 let inst = &expanded_annotations[annotation_idx];
2444 if let [Operand::IdRef(target), ..] = inst.operands[..]
2445 && let Some(&rewritten_target) = rewrite_rules.get(&target)
2446 {
2447 let mut expanded_inst = inst.clone();
2448 expanded_inst.operands[0] = Operand::IdRef(rewritten_target);
2449 expanded_annotations.push(expanded_inst);
2450 }
2451 }
2452 }
2453 }
2454
2455 continue;
2456 }
2457 expanded_functions.push(func);
2458 }
2459
2460 assert!(self.propagate_instances_queue.is_empty());
2463
2464 let module = self.builder.module_mut();
2465 module.entry_points = entry_points;
2466 module.debug_names = expanded_debug_names;
2467 module.annotations = expanded_annotations;
2468 module.types_global_values = expanded_types_global_values;
2469 module.functions = expanded_functions;
2470
2471 self.builder.module()
2472 }
2473
2474 fn dump_instances(&self, w: &mut impl io::Write) -> io::Result<()> {
2475 writeln!(w, "; All specializer \"generic\"s and their instances:")?;
2476 writeln!(w)?;
2477
2478 for (&generic_id, generic) in &self.specializer.generics {
2480 if let Some(name) = self.specializer.debug_names.get(&generic_id) {
2481 writeln!(w, "; {name}")?;
2482 }
2483
2484 write!(
2485 w,
2486 "{} = Op{:?}",
2487 Instance {
2488 generic_id,
2489 generic_args: Param(0)..Param(generic.param_count)
2490 }
2491 .display(Param::range_iter),
2492 generic.def.class.opcode
2493 )?;
2494 let mut next_param = Param(0);
2495 for operand in generic
2496 .def
2497 .result_type
2498 .map(Operand::IdRef)
2499 .iter()
2500 .chain(generic.def.operands.iter())
2501 {
2502 write!(w, " ")?;
2503 let (needed, used_generic) = self.specializer.params_needed_by(operand);
2504 let params = next_param..Param(next_param.0 + needed);
2505
2506 if generic.def.class.opcode != Op::Function {
2508 next_param = params.end;
2509 }
2510
2511 if used_generic.is_some() {
2512 write!(
2513 w,
2514 "{}",
2515 Instance {
2516 generic_id: operand.unwrap_id_ref(),
2517 generic_args: params
2518 }
2519 .display(Param::range_iter)
2520 )?;
2521 } else if needed == 1 {
2522 write!(w, "{}", params.start)?;
2523 } else {
2524 write!(w, "{operand}")?;
2525 }
2526 }
2527 writeln!(w)?;
2528
2529 if let Some(param_values) = &generic.param_values {
2530 write!(w, " where")?;
2531 for (i, v) in param_values.iter().enumerate() {
2532 let p = Param(i as u32);
2533 match v {
2534 Value::Unknown => {}
2535 Value::Known(o) => write!(w, " {p} = {o},")?,
2536 Value::SameAs(q) => write!(w, " {p} = {q},")?,
2537 }
2538 }
2539 writeln!(w)?;
2540 }
2541
2542 for (instance, instance_id) in self.all_instances_of(generic_id) {
2543 assert_eq!(instance.generic_id, generic_id);
2544 writeln!(
2545 w,
2546 " %{} = {}",
2547 instance_id,
2548 instance.display(|generic_args| generic_args.iter().copied())
2549 )?;
2550 }
2551
2552 writeln!(w)?;
2553 }
2554 Ok(())
2555 }
2556}