3 BlockIdxOutOfRange, BlockParamIdxOutOfRange, Error, InstIdxOutOfRange,
4 OperandIdxOutOfRange, Result, SSAValIdxOutOfRange,
7 BlockIdx, BlockParamIdx, IndexTy, InstIdx, InstRange, OperandIdx, RangeIter, SSAValIdx,
9 interned::{GlobalState, Intern, Interned},
10 loc::{BaseTy, Loc, Ty},
13 use arbitrary::Arbitrary;
16 use hashbrown::HashSet;
19 visit::{GraphBase, GraphProp, IntoNeighbors, VisitMap, Visitable},
22 use serde::{Deserialize, Serialize};
23 use smallvec::SmallVec;
25 collections::{btree_map, BTreeMap, BTreeSet},
28 ops::{Index, IndexMut},
31 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)]
35 param_idx: BlockParamIdx,
39 operand_idx: OperandIdx,
44 pub const fn invalid() -> Self {
45 SSAValDef::BlockParam {
46 block: BlockIdx::ENTRY_BLOCK,
47 param_idx: BlockParamIdx::new(!0),
52 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Serialize, Deserialize)]
53 pub struct BranchSuccParamUse {
54 pub branch_inst: InstIdx,
56 pub param_idx: BlockParamIdx,
59 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Serialize, Deserialize)]
60 pub struct OperandUse {
62 pub operand_idx: OperandIdx,
65 #[derive(Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)]
68 #[serde(skip, default = "SSAValDef::invalid")]
71 pub operand_uses: BTreeSet<OperandUse>,
73 pub branch_succ_param_uses: BTreeSet<BranchSuccParamUse>,
77 fn validate(&self, ssa_val_idx: SSAValIdx, func: &FnFields) -> Result<()> {
82 branch_succ_param_uses,
85 SSAValDef::BlockParam { block, param_idx } => {
86 let block_param = func.try_get_block_param(block, param_idx)?;
87 if ssa_val_idx != block_param {
88 return Err(Error::MismatchedBlockParamDef {
95 SSAValDef::Operand { inst, operand_idx } => {
96 let operand = func.try_get_operand(inst, operand_idx)?;
97 if ssa_val_idx != operand.ssa_val {
98 return Err(Error::SSAValDefIsNotOperandsSSAVal {
106 for &OperandUse { inst, operand_idx } in operand_uses {
107 let operand = func.try_get_operand(inst, operand_idx)?;
108 if ssa_val_idx != operand.ssa_val {
109 return Err(Error::SSAValUseIsNotOperandsSSAVal {
116 for &BranchSuccParamUse {
120 } in branch_succ_param_uses
122 if ssa_val_idx != func.try_get_branch_target_param(branch_inst, succ, param_idx)? {
123 return Err(Error::MismatchedBranchTargetBlockParamUse {
155 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
156 #[serde(try_from = "SerializedProgPoint", into = "SerializedProgPoint")]
157 pub struct ProgPoint(usize);
160 pub const fn new(inst: InstIdx, stage: InstStage) -> Self {
161 const_unwrap_res!(Self::try_new(inst, stage))
163 pub const fn try_new(inst: InstIdx, stage: InstStage) -> Result<Self> {
164 let Some(inst) = inst.get().checked_shl(1) else {
165 return Err(Error::InstIdxTooBig);
167 Ok(Self(inst | stage as usize))
169 pub const fn inst(self) -> InstIdx {
170 InstIdx::new(self.0 >> 1)
172 pub const fn stage(self) -> InstStage {
179 pub const fn next(self) -> Self {
182 pub const fn prev(self) -> Self {
187 impl fmt::Debug for ProgPoint {
188 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
189 f.debug_struct("ProgPoint")
190 .field("inst", &self.inst())
191 .field("stage", &self.stage())
196 #[derive(Serialize, Deserialize)]
197 struct SerializedProgPoint {
202 impl From<ProgPoint> for SerializedProgPoint {
203 fn from(value: ProgPoint) -> Self {
206 stage: value.stage(),
211 impl TryFrom<SerializedProgPoint> for ProgPoint {
214 fn try_from(value: SerializedProgPoint) -> Result<Self, Self::Error> {
215 ProgPoint::try_new(value.inst, value.stage)
234 pub enum OperandKind {
240 Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Serialize, Deserialize, Arbitrary,
242 pub enum Constraint {
243 /// any register or stack location
247 /// r2,r4,r6,r8,...r126
253 /// any stack location
259 pub fn is_any(&self) -> bool {
260 matches!(self, Self::Any)
262 pub fn fixed_loc(&self) -> Option<Loc> {
265 | Constraint::BaseGpr
266 | Constraint::SVExtra2VGpr
267 | Constraint::SVExtra2SGpr
268 | Constraint::SVExtra3Gpr
269 | Constraint::Stack => None,
270 Constraint::FixedLoc(v) => Some(v),
273 pub fn non_fixed_choices_for_ty(ty: Ty) -> &'static [Constraint] {
274 match (ty.base_ty, ty.reg_len.get()) {
275 (BaseTy::Bits64, 1) => &[
278 Constraint::SVExtra2SGpr,
279 Constraint::SVExtra2VGpr,
280 Constraint::SVExtra3Gpr,
283 (BaseTy::Bits64, _) => &[
285 Constraint::SVExtra2VGpr,
286 Constraint::SVExtra3Gpr,
289 (BaseTy::Ca, _) | (BaseTy::VlMaxvl, _) => &[Constraint::Any, Constraint::Stack],
292 pub fn arbitrary_with_ty(
294 u: &mut arbitrary::Unstructured<'_>,
295 ) -> arbitrary::Result<Self> {
296 let non_fixed_choices = Self::non_fixed_choices_for_ty(ty);
297 if let Some(&retval) = non_fixed_choices.get(u.choose_index(non_fixed_choices.len() + 1)?) {
300 Ok(Constraint::FixedLoc(Loc::arbitrary_with_ty(ty, u)?))
303 pub fn check_for_ty_mismatch(&self, ty: Ty) -> Result<(), ()> {
305 Constraint::Any | Constraint::Stack => {}
306 Constraint::BaseGpr | Constraint::SVExtra2SGpr => {
307 if ty != Ty::scalar(BaseTy::Bits64) {
311 Constraint::SVExtra2VGpr | Constraint::SVExtra3Gpr => {
312 if ty.base_ty != BaseTy::Bits64 {
316 Constraint::FixedLoc(loc) => {
326 impl Default for Constraint {
327 fn default() -> Self {
333 Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Serialize, Deserialize, Default,
335 #[serde(try_from = "OperandKind", into = "OperandKind")]
336 pub struct OperandKindDefOnly;
338 impl TryFrom<OperandKind> for OperandKindDefOnly {
341 fn try_from(value: OperandKind) -> Result<Self, Self::Error> {
343 OperandKind::Use => Err(Error::OperandKindMustBeDef),
344 OperandKind::Def => Ok(Self),
349 impl From<OperandKindDefOnly> for OperandKind {
350 fn from(_value: OperandKindDefOnly) -> Self {
355 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Serialize, Deserialize)]
357 pub enum KindAndConstraint {
359 kind: OperandKindDefOnly,
360 reuse_operand_idx: OperandIdx,
364 #[serde(default, skip_serializing_if = "Constraint::is_any")]
365 constraint: Constraint,
369 impl KindAndConstraint {
370 pub fn kind(self) -> OperandKind {
372 Self::Reuse { .. } => OperandKind::Def,
373 Self::Constraint { kind, .. } => kind,
376 pub fn is_reuse(self) -> bool {
377 matches!(self, Self::Reuse { .. })
381 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)]
383 pub ssa_val: SSAValIdx,
385 pub kind_and_constraint: KindAndConstraint,
386 pub stage: InstStage,
390 pub fn try_get_reuse_src<'f>(
394 ) -> Result<Option<&'f Operand>> {
395 if let KindAndConstraint::Reuse {
396 reuse_operand_idx, ..
397 } = self.kind_and_constraint
399 Ok(Some(func.try_get_operand(inst, reuse_operand_idx)?))
404 pub fn try_constraint(&self, inst: InstIdx, func: &FnFields) -> Result<Constraint> {
405 Ok(match self.kind_and_constraint {
406 KindAndConstraint::Reuse {
410 let operand = func.try_get_operand(inst, reuse_operand_idx)?;
411 match operand.kind_and_constraint {
412 KindAndConstraint::Reuse { .. }
413 | KindAndConstraint::Constraint {
414 kind: OperandKind::Def,
417 return Err(Error::ReuseTargetOperandMustBeUse {
419 reuse_target_operand_idx: reuse_operand_idx,
422 KindAndConstraint::Constraint {
423 kind: OperandKind::Use,
428 KindAndConstraint::Constraint { constraint, .. } => constraint,
431 pub fn constraint(&self, inst: InstIdx, func: &Function) -> Constraint {
432 self.try_constraint(inst, func).unwrap()
438 operand_idx: OperandIdx,
440 global_state: &GlobalState,
443 ssa_val: ssa_val_idx,
449 .try_index(ssa_val_idx)
450 .map_err(|e| e.with_block_inst_and_operand(block, inst, operand_idx))?;
451 match kind_and_constraint.kind() {
452 OperandKind::Use => {
455 .contains(&OperandUse { inst, operand_idx })
457 return Err(Error::MissingOperandUse {
464 OperandKind::Def => {
465 let def = SSAValDef::Operand { inst, operand_idx };
466 if ssa_val.def != def {
467 return Err(Error::OperandDefIsNotSSAValDef {
475 if let KindAndConstraint::Reuse {
478 } = self.kind_and_constraint
480 let reuse_src = func.try_get_operand(inst, reuse_operand_idx)?;
481 let reuse_src_ssa_val = func
483 .try_index(reuse_src.ssa_val)
484 .map_err(|e| e.with_block_inst_and_operand(block, inst, reuse_operand_idx))?;
485 if ssa_val.ty != reuse_src_ssa_val.ty {
486 return Err(Error::ReuseOperandTyMismatch {
488 tgt_operand_idx: operand_idx,
489 src_operand_idx: reuse_operand_idx,
490 src_ty: reuse_src_ssa_val.ty,
495 let constraint = self.try_constraint(inst, func)?;
497 .check_for_ty_mismatch(ssa_val.ty)
498 .map_err(|()| Error::ConstraintTyMismatch {
503 if let Some(fixed_loc) = constraint.fixed_loc() {
509 .conflicts_with(fixed_loc, global_state)
511 return Err(Error::FixedLocConflictsWithClobbers { inst, operand_idx });
518 /// copy concatenates all `srcs` together and de-concatenates the result into all `dests`.
519 #[derive(Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)]
520 pub struct CopyInstKind {
521 pub src_operand_idxs: Vec<OperandIdx>,
522 pub dest_operand_idxs: Vec<OperandIdx>,
528 operand_idxs: &[OperandIdx],
531 ) -> Result<Option<Ty>> {
532 let mut retval: Option<Ty> = None;
533 for &operand_idx in operand_idxs {
534 let operand = func.try_get_operand(inst, operand_idx)?;
537 .try_index(operand.ssa_val)
538 .map_err(|e| e.with_inst_and_operand(inst, operand_idx))?;
539 retval = Some(match retval {
540 Some(retval) => retval.try_concat(ssa_val.ty)?,
548 #[derive(Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)]
549 pub struct BlockTermInstKind {
550 pub succs_and_params: BTreeMap<BlockIdx, Vec<SSAValIdx>>,
553 #[derive(Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)]
557 BlockTerm(BlockTermInstKind),
561 pub fn is_normal(&self) -> bool {
562 matches!(self, Self::Normal)
564 pub fn is_block_term(&self) -> bool {
565 matches!(self, Self::BlockTerm { .. })
567 pub fn is_copy(&self) -> bool {
568 matches!(self, Self::Copy { .. })
570 pub fn block_term(&self) -> Option<&BlockTermInstKind> {
572 InstKind::BlockTerm(v) => Some(v),
576 pub fn block_term_mut(&mut self) -> Option<&mut BlockTermInstKind> {
578 InstKind::BlockTerm(v) => Some(v),
582 pub fn copy(&self) -> Option<&CopyInstKind> {
584 InstKind::Copy(v) => Some(v),
590 impl Default for InstKind {
591 fn default() -> Self {
596 fn loc_set_is_empty(clobbers: &Interned<LocSet>) -> bool {
600 fn empty_loc_set() -> Interned<LocSet> {
601 GlobalState::get(|global_state| LocSet::default().into_interned(global_state))
604 #[derive(Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)]
606 #[serde(default, skip_serializing_if = "InstKind::is_normal")]
608 pub operands: Vec<Operand>,
609 #[serde(default = "empty_loc_set", skip_serializing_if = "loc_set_is_empty")]
610 pub clobbers: Interned<LocSet>,
619 global_state: &GlobalState,
626 let is_at_end_of_block = func.blocks[block].insts.last() == Some(inst);
627 if kind.is_block_term() != is_at_end_of_block {
628 return Err(if is_at_end_of_block {
629 Error::BlocksLastInstMustBeTerm { term_idx: inst }
631 Error::TermInstOnlyAllowedAtBlockEnd { inst_idx: inst }
634 for (operand_idx, operand) in operands.entries() {
635 operand.validate(block, inst, operand_idx, func, global_state)?;
638 InstKind::Normal => {}
639 InstKind::Copy(CopyInstKind {
644 let mut seen_dest_operands = SmallVec::<[bool; 16]>::new();
645 seen_dest_operands.resize(operands.len(), false);
646 for &dest_operand_idx in dest_operand_idxs {
647 let seen_dest_operand = seen_dest_operands
648 .get_mut(dest_operand_idx.get())
650 OperandIdxOutOfRange {
651 idx: dest_operand_idx,
655 if mem::replace(seen_dest_operand, true) {
656 return Err(Error::DupCopyDestOperand {
658 operand_idx: dest_operand_idx,
662 if Some(*copy_ty) != CopyInstKind::calc_copy_ty(&src_operand_idxs, inst, func)? {
663 return Err(Error::CopySrcTyMismatch { inst });
665 if Some(*copy_ty) != CopyInstKind::calc_copy_ty(&dest_operand_idxs, inst, func)? {
666 return Err(Error::CopyDestTyMismatch { inst });
669 InstKind::BlockTerm(BlockTermInstKind { succs_and_params }) => {
670 for (&succ_idx, params) in succs_and_params {
671 let succ = func.blocks.try_index(succ_idx)?;
672 if !succ.preds.contains(&block) {
673 return Err(Error::SrcBlockMissingFromBranchTgtBlocksPreds {
679 if succ.params.len() != params.len() {
680 return Err(Error::BranchSuccParamCountMismatch {
683 block_param_count: succ.params.len(),
684 branch_param_count: params.len(),
687 for ((param_idx, &branch_ssa_val_idx), &block_ssa_val_idx) in
688 params.entries().zip(&succ.params)
690 let branch_ssa_val = func
692 .try_index(branch_ssa_val_idx)
693 .map_err(|e| e.with_inst_succ_and_param(inst, succ_idx, param_idx))?;
694 let block_ssa_val = func
696 .try_index(block_ssa_val_idx)
697 .map_err(|e| e.with_block_and_param(succ_idx, param_idx))?;
699 .branch_succ_param_uses
700 .contains(&BranchSuccParamUse {
706 return Err(Error::MissingBranchSuccParamUse {
707 ssa_val_idx: branch_ssa_val_idx,
713 if block_ssa_val.ty != branch_ssa_val.ty {
714 return Err(Error::BranchSuccParamTyMismatch {
718 block_param_ty: block_ssa_val.ty,
719 branch_param_ty: branch_ssa_val.ty,
728 pub fn try_get_operand(&self, inst: InstIdx, operand_idx: OperandIdx) -> Result<&Operand> {
730 .try_index(operand_idx)
731 .map_err(|e| e.with_inst(inst).into())
735 #[derive(Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)]
737 pub params: Vec<SSAValIdx>,
738 pub insts: InstRange,
739 pub preds: BTreeSet<BlockIdx>,
740 pub immediate_dominator: Option<BlockIdx>,
744 fn validate(&self, block: BlockIdx, func: &FnFields, global_state: &GlobalState) -> Result<()> {
749 immediate_dominator: _, // validated by Function::new_with_global_state
751 const _: () = assert!(BlockIdx::ENTRY_BLOCK.get() == 0);
752 let expected_start = if block == BlockIdx::ENTRY_BLOCK {
755 func.blocks[block.prev()].insts.end
757 if insts.start != expected_start {
758 return Err(Error::BlockHasInvalidStart {
763 let term_inst_idx = insts.last().ok_or(Error::BlockIsEmpty { block })?;
765 .get(term_inst_idx.get())
766 .ok_or(Error::BlockEndOutOfRange { end: insts.end })?;
767 if block.get() == func.blocks.len() - 1 && insts.end.get() != func.insts.len() {
768 return Err(Error::InstHasNoBlock { inst: insts.end });
770 if block == BlockIdx::ENTRY_BLOCK {
771 if !params.is_empty() {
772 return Err(Error::EntryBlockCantHaveParams);
774 if !preds.is_empty() {
775 return Err(Error::EntryBlockCantHavePreds);
779 func.insts[inst].validate(block, inst, func, global_state)?;
781 for (param_idx, &ssa_val_idx) in params.entries() {
784 .try_index(ssa_val_idx)
785 .map_err(|e| e.with_block_and_param(block, param_idx))?;
786 let def = SSAValDef::BlockParam { block, param_idx };
787 if ssa_val.def != def {
788 return Err(Error::MismatchedBlockParamDef {
796 let (term_inst, BlockTermInstKind { succs_and_params }) =
797 func.try_get_block_term_inst_and_kind(pred)?;
798 if !succs_and_params.contains_key(&block) {
799 return Err(Error::PredMissingFromPredsTermBranchsTargets {
801 branch_inst: term_inst,
805 if preds.len() > 1 && succs_and_params.len() > 1 {
806 return Err(Error::CriticalEdgeNotAllowed {
808 branch_inst: term_inst,
818 #[fields_ty = FnFields]
819 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
820 pub struct Function {
821 pub ssa_vals: Vec<SSAVal>,
822 pub insts: Vec<Inst>,
823 pub blocks: Vec<Block>,
825 /// map from blocks' start instruction's index to their block index, doesn't contain the entry block
826 pub start_inst_to_block_map: BTreeMap<InstIdx, BlockIdx>,
831 pub fn new(fields: FnFields) -> Result<Self> {
832 GlobalState::get(|global_state| Self::new_with_global_state(fields, global_state))
834 pub fn new_with_global_state(mut fields: FnFields, global_state: &GlobalState) -> Result<Self> {
835 fields.fill_start_inst_to_block_map();
836 fields.fill_ssa_defs_uses()?;
841 start_inst_to_block_map: _,
844 .get(BlockIdx::ENTRY_BLOCK.get())
845 .ok_or(Error::MissingEntryBlock)?;
846 for (block_idx, block) in blocks.entries() {
847 block.validate(block_idx, &fields, global_state)?;
849 let dominators = dominators::simple_fast(&fields, BlockIdx::ENTRY_BLOCK);
850 for (block_idx, block) in blocks.entries() {
851 let expected = dominators.immediate_dominator(block_idx);
852 if block.immediate_dominator != expected {
853 return Err(Error::IncorrectImmediateDominator {
855 found: block.immediate_dominator,
860 for (ssa_val_idx, ssa_val) in ssa_vals.entries() {
861 ssa_val.validate(ssa_val_idx, &fields)?;
865 pub fn entry_block(&self) -> &Block {
868 pub fn block_term_kind(&self, block: BlockIdx) -> &BlockTermInstKind {
869 self.insts[self.blocks[block].insts.last().unwrap()]
877 pub fn fill_start_inst_to_block_map(&mut self) {
878 self.start_inst_to_block_map.clear();
879 for (block_idx, block) in self.blocks.entries() {
880 if block_idx != BlockIdx::ENTRY_BLOCK {
881 self.start_inst_to_block_map
882 .insert(block.insts.start, block_idx);
886 pub fn fill_ssa_defs_uses(&mut self) -> Result<()> {
887 for ssa_val in &mut self.ssa_vals {
888 ssa_val.branch_succ_param_uses.clear();
889 ssa_val.operand_uses.clear();
890 ssa_val.def = SSAValDef::invalid();
892 for (block_idx, block) in self.blocks.entries() {
893 for (param_idx, ¶m) in block.params.entries() {
895 .try_index_mut(param)
896 .map_err(|e| e.with_block_and_param(block_idx, param_idx))?
897 .def = SSAValDef::BlockParam {
903 for (inst_idx, inst) in self.insts.entries() {
904 for (operand_idx, operand) in inst.operands.entries() {
907 .try_index_mut(operand.ssa_val)
908 .map_err(|e| e.with_inst_and_operand(inst_idx, operand_idx))?;
909 match operand.kind_and_constraint.kind() {
910 OperandKind::Use => {
911 ssa_val.operand_uses.insert(OperandUse {
916 OperandKind::Def => {
917 ssa_val.def = SSAValDef::Operand {
925 InstKind::Normal | InstKind::Copy(_) => {}
926 InstKind::BlockTerm(BlockTermInstKind { succs_and_params }) => {
927 for (&succ, params) in succs_and_params {
928 for (param_idx, ¶m) in params.entries() {
929 let ssa_val = self.ssa_vals.try_index_mut(param).map_err(|e| {
930 e.with_inst_succ_and_param(inst_idx, succ, param_idx)
932 ssa_val.branch_succ_param_uses.insert(BranchSuccParamUse {
933 branch_inst: inst_idx,
944 pub fn try_get_operand(&self, inst: InstIdx, operand_idx: OperandIdx) -> Result<&Operand> {
949 .try_index(operand_idx)
950 .map_err(|e| e.with_inst(inst))?)
952 pub fn try_get_block_param(
955 param_idx: BlockParamIdx,
956 ) -> Result<SSAValIdx> {
961 .try_index(param_idx)
962 .map_err(|e| e.with_block(block))?)
964 pub fn try_get_block_term_inst_idx(&self, block: BlockIdx) -> Result<InstIdx> {
969 .ok_or(Error::BlockIsEmpty { block })
971 pub fn try_get_block_term_inst_and_kind(
974 ) -> Result<(InstIdx, &BlockTermInstKind)> {
975 let term_idx = self.try_get_block_term_inst_idx(block)?;
978 .try_index(term_idx)?
981 .ok_or(Error::BlocksLastInstMustBeTerm { term_idx })?;
982 Ok((term_idx, term_kind))
984 pub fn try_get_block_term_inst_and_kind_mut(
987 ) -> Result<(InstIdx, &mut BlockTermInstKind)> {
988 let term_idx = self.try_get_block_term_inst_idx(block)?;
991 .try_index_mut(term_idx)?
994 .ok_or(Error::BlocksLastInstMustBeTerm { term_idx })?;
995 Ok((term_idx, term_kind))
997 pub fn try_get_branch_target_params(
999 branch_inst: InstIdx,
1001 ) -> Result<&[SSAValIdx]> {
1002 let inst = self.insts.try_index(branch_inst)?;
1003 let BlockTermInstKind { succs_and_params } = inst
1006 .ok_or(Error::InstIsNotBlockTerm { inst: branch_inst })?;
1009 .ok_or(Error::BranchTargetNotFound {
1014 pub fn try_get_branch_target_param(
1016 branch_inst: InstIdx,
1018 param_idx: BlockParamIdx,
1019 ) -> Result<SSAValIdx> {
1021 .try_get_branch_target_params(branch_inst, succ)?
1022 .try_index(param_idx)
1023 .map_err(|e: BlockParamIdxOutOfRange| e.with_inst_and_succ(branch_inst, succ))?)
1025 pub fn inst_to_block(&self, inst: InstIdx) -> BlockIdx {
1026 self.start_inst_to_block_map
1030 .unwrap_or(BlockIdx::ENTRY_BLOCK)
1034 pub trait Entries<'a, I>: Index<I>
1039 type Iter: Iterator<Item = (I, &'a Self::Output)>
1040 + DoubleEndedIterator
1043 fn entries(&'a self) -> Self::Iter;
1044 fn keys(&'a self) -> RangeIter<I>;
1047 pub trait EntriesMut<'a, I>: Entries<'a, I> + IndexMut<I>
1052 type IterMut: Iterator<Item = (I, &'a mut Self::Output)>
1053 + DoubleEndedIterator
1056 fn entries_mut(&'a mut self) -> Self::IterMut;
1059 pub trait TryIndex<I>: for<'a> Entries<'a, I>
1064 fn try_index(&self, idx: I) -> Result<&Self::Output, Self::Error>;
1067 pub trait TryIndexMut<I>: TryIndex<I> + for<'a> EntriesMut<'a, I>
1071 fn try_index_mut(&mut self, idx: I) -> Result<&mut Self::Output, Self::Error>;
1074 macro_rules! impl_index {
1076 #[error = $Error:ident, iter = $Iter:ident, iter_mut = $IterMut:ident]
1077 impl Index<$I:ty> for Vec<$T:ty> {}
1079 #[derive(Clone, Debug)]
1080 pub struct $Iter<'a> {
1081 iter: std::iter::Enumerate<std::slice::Iter<'a, $T>>,
1084 impl<'a> Iterator for $Iter<'a> {
1085 type Item = ($I, &'a $T);
1087 fn next(&mut self) -> Option<Self::Item> {
1088 self.iter.next().map(|(i, v)| (<$I>::new(i), v))
1091 fn size_hint(&self) -> (usize, Option<usize>) {
1092 self.iter.size_hint()
1095 fn fold<B, F>(self, init: B, mut f: F) -> B
1097 F: FnMut(B, Self::Item) -> B,
1100 .fold(init, move |a, (i, v)| f(a, (<$I>::new(i), v)))
1104 impl DoubleEndedIterator for $Iter<'_> {
1105 fn next_back(&mut self) -> Option<Self::Item> {
1106 self.iter.next_back().map(|(i, v)| (<$I>::new(i), v))
1109 fn rfold<B, F>(self, init: B, mut f: F) -> B
1111 F: FnMut(B, Self::Item) -> B,
1114 .rfold(init, move |a, (i, v)| f(a, (<$I>::new(i), v)))
1118 impl ExactSizeIterator for $Iter<'_> {
1119 fn len(&self) -> usize {
1124 impl FusedIterator for $Iter<'_> {}
1127 pub struct $IterMut<'a> {
1128 iter: std::iter::Enumerate<std::slice::IterMut<'a, $T>>,
1131 impl<'a> Iterator for $IterMut<'a> {
1132 type Item = ($I, &'a mut $T);
1134 fn next(&mut self) -> Option<Self::Item> {
1135 self.iter.next().map(|(i, v)| (<$I>::new(i), v))
1138 fn size_hint(&self) -> (usize, Option<usize>) {
1139 self.iter.size_hint()
1142 fn fold<B, F>(self, init: B, mut f: F) -> B
1144 F: FnMut(B, Self::Item) -> B,
1147 .fold(init, move |a, (i, v)| f(a, (<$I>::new(i), v)))
1151 impl DoubleEndedIterator for $IterMut<'_> {
1152 fn next_back(&mut self) -> Option<Self::Item> {
1153 self.iter.next_back().map(|(i, v)| (<$I>::new(i), v))
1156 fn rfold<B, F>(self, init: B, mut f: F) -> B
1158 F: FnMut(B, Self::Item) -> B,
1161 .rfold(init, move |a, (i, v)| f(a, (<$I>::new(i), v)))
1165 impl ExactSizeIterator for $IterMut<'_> {
1166 fn len(&self) -> usize {
1171 impl FusedIterator for $IterMut<'_> {}
1173 impl Index<$I> for Vec<$T> {
1176 fn index(&self, index: $I) -> &Self::Output {
1181 impl IndexMut<$I> for Vec<$T> {
1182 fn index_mut(&mut self, index: $I) -> &mut Self::Output {
1183 &mut self[index.get()]
1187 impl<'a> Entries<'a, $I> for Vec<$T> {
1188 type Iter = $Iter<'a>;
1189 fn entries(&'a self) -> Self::Iter {
1191 iter: (**self).iter().enumerate(),
1194 fn keys(&'a self) -> RangeIter<$I> {
1195 RangeIter::from_usize_range(0..self.len())
1199 impl<'a> EntriesMut<'a, $I> for Vec<$T> {
1200 type IterMut = $IterMut<'a>;
1201 fn entries_mut(&'a mut self) -> Self::IterMut {
1203 iter: (**self).iter_mut().enumerate(),
1208 impl TryIndex<$I> for Vec<$T> {
1209 type Error = $Error;
1211 fn try_index(&self, idx: $I) -> Result<&Self::Output, Self::Error> {
1212 self.get(idx.get()).ok_or($Error { idx })
1216 impl TryIndexMut<$I> for Vec<$T> {
1217 fn try_index_mut(&mut self, idx: $I) -> Result<&mut Self::Output, Self::Error> {
1218 self.get_mut(idx.get()).ok_or($Error { idx })
1222 impl Index<$I> for [$T] {
1225 fn index(&self, index: $I) -> &Self::Output {
1230 impl IndexMut<$I> for [$T] {
1231 fn index_mut(&mut self, index: $I) -> &mut Self::Output {
1232 &mut self[index.get()]
1236 impl<'a> Entries<'a, $I> for [$T] {
1237 type Iter = $Iter<'a>;
1238 fn entries(&'a self) -> Self::Iter {
1240 iter: self.iter().enumerate(),
1243 fn keys(&'a self) -> RangeIter<$I> {
1244 RangeIter::from_usize_range(0..self.len())
1248 impl<'a> EntriesMut<'a, $I> for [$T] {
1249 type IterMut = $IterMut<'a>;
1250 fn entries_mut(&'a mut self) -> Self::IterMut {
1252 iter: self.iter_mut().enumerate(),
1257 impl TryIndex<$I> for [$T] {
1258 type Error = $Error;
1260 fn try_index(&self, idx: $I) -> Result<&Self::Output, Self::Error> {
1261 self.get(idx.get()).ok_or($Error { idx })
1265 impl TryIndexMut<$I> for [$T] {
1266 fn try_index_mut(&mut self, idx: $I) -> Result<&mut Self::Output, Self::Error> {
1267 self.get_mut(idx.get()).ok_or($Error { idx })
1274 #[error = SSAValIdxOutOfRange, iter = SSAValEntriesIter, iter_mut = SSAValEntriesIterMut]
1275 impl Index<SSAValIdx> for Vec<SSAVal> {}
1279 #[error = BlockParamIdxOutOfRange, iter = BlockParamEntriesIter, iter_mut = BlockParamEntriesIterMut]
1280 impl Index<BlockParamIdx> for Vec<SSAValIdx> {}
1284 #[error = OperandIdxOutOfRange, iter = OperandEntriesIter, iter_mut = OperandEntriesIterMut]
1285 impl Index<OperandIdx> for Vec<Operand> {}
1289 #[error = InstIdxOutOfRange, iter = InstEntriesIter, iter_mut = InstEntriesIterMut]
1290 impl Index<InstIdx> for Vec<Inst> {}
1294 #[error = BlockIdxOutOfRange, iter = BlockEntriesIter, iter_mut = BlockEntriesIterMut]
1295 impl Index<BlockIdx> for Vec<Block> {}
1298 impl GraphBase for FnFields {
1299 type EdgeId = (BlockIdx, BlockIdx);
1300 type NodeId = BlockIdx;
1303 pub struct Neighbors<'a> {
1304 iter: Option<btree_map::Keys<'a, BlockIdx, Vec<SSAValIdx>>>,
1307 impl Iterator for Neighbors<'_> {
1308 type Item = BlockIdx;
1310 fn next(&mut self) -> Option<Self::Item> {
1311 Some(*self.iter.as_mut()?.next()?)
1315 impl<'a> IntoNeighbors for &'a FnFields {
1316 type Neighbors = Neighbors<'a>;
1318 fn neighbors(self, block_idx: Self::NodeId) -> Self::Neighbors {
1321 .try_get_block_term_inst_and_kind(block_idx)
1323 .map(|(_, BlockTermInstKind { succs_and_params })| succs_and_params.keys()),
1328 pub struct VisitedMap(HashSet<BlockIdx>);
1330 impl VisitMap<BlockIdx> for VisitedMap {
1331 fn visit(&mut self, block: BlockIdx) -> bool {
1332 self.0.insert(block)
1335 fn is_visited(&self, block: &BlockIdx) -> bool {
1336 self.0.contains(block)
1340 impl Visitable for FnFields {
1341 type Map = VisitedMap;
1343 fn visit_map(&self) -> Self::Map {
1344 VisitedMap(HashSet::new())
1347 fn reset_map(&self, map: &mut Self::Map) {
1352 impl GraphProp for FnFields {
1353 type EdgeType = Directed;
1359 use crate::loc::TyFields;
1360 use std::num::NonZeroU32;
1363 fn test_constraint_non_fixed_choices_for_ty() {
1366 enum ConstraintWithoutFixedLoc {
1371 #[allow(non_snake_case)]
1377 fn add(&mut self, constraint: &Constraint) {
1379 Constraint::FixedLoc(_) => {}
1380 $(Constraint::$field => self.$field = true,)*
1384 $(assert!(self.$field, "never seen field: {}", stringify!($field));)*
1390 enum ConstraintWithoutFixedLoc {
1399 let mut seen = Seen::default();
1400 for base_ty in 0..BaseTy::LENGTH {
1401 let base_ty = BaseTy::from_usize(base_ty);
1402 for reg_len in [1, 2, 100] {
1403 let reg_len = NonZeroU32::new(reg_len).unwrap();
1404 let ty = Ty::new_or_scalar(TyFields { base_ty, reg_len });
1405 let non_fixed_choices = Constraint::non_fixed_choices_for_ty(ty);
1406 assert_eq!(non_fixed_choices.first(), Some(&Constraint::Any));
1407 assert_eq!(non_fixed_choices.last(), Some(&Constraint::Stack));
1408 for constraint in non_fixed_choices {
1409 assert_eq!(constraint.fixed_loc(), None);
1410 seen.add(constraint);
1411 if constraint.check_for_ty_mismatch(ty).is_err() {
1412 panic!("constraint ty mismatch: constraint={constraint:?} ty={ty:?}");