2 error::{Error, Result},
3 index::{BlockIdx, InstIdx, InstRange, SSAValIdx},
4 interned::{GlobalState, Intern, Interned},
5 loc::{BaseTy, Loc, Ty},
9 use hashbrown::HashSet;
12 visit::{GraphBase, GraphProp, IntoNeighbors, VisitMap, Visitable},
15 use serde::{Deserialize, Serialize};
16 use smallvec::SmallVec;
18 collections::{btree_map, BTreeMap, BTreeSet},
20 ops::{Index, IndexMut},
23 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)]
25 BlockParam { block: BlockIdx, param_idx: usize },
26 Operand { inst: InstIdx, operand_idx: usize },
29 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Serialize, Deserialize)]
30 pub struct BranchSuccParamUse {
36 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Serialize, Deserialize)]
37 pub struct OperandUse {
42 #[derive(Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)]
46 pub operand_uses: BTreeSet<OperandUse>,
47 pub branch_succ_param_uses: BTreeSet<BranchSuccParamUse>,
51 fn validate(&self, ssa_val_idx: SSAValIdx, func: &FnFields) -> Result<()> {
56 branch_succ_param_uses,
59 SSAValDef::BlockParam { block, param_idx } => {
60 let block_param = func.try_get_block_param(block, param_idx)?;
61 if ssa_val_idx != block_param {
62 return Err(Error::MismatchedBlockParamDef {
69 SSAValDef::Operand { inst, operand_idx } => {
70 let operand = func.try_get_operand(inst, operand_idx)?;
71 if ssa_val_idx != operand.ssa_val {
72 return Err(Error::SSAValDefIsNotOperandsSSAVal {
80 for &OperandUse { inst, operand_idx } in operand_uses {
81 let operand = func.try_get_operand(inst, operand_idx)?;
82 if ssa_val_idx != operand.ssa_val {
83 return Err(Error::SSAValUseIsNotOperandsSSAVal {
90 for &BranchSuccParamUse {
94 } in branch_succ_param_uses
96 if ssa_val_idx != func.try_get_branch_target_param(branch_inst, succ, param_idx)? {
97 return Err(Error::MismatchedBranchTargetBlockParamUse {
109 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Serialize, Deserialize)]
116 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
117 #[serde(try_from = "SerializedProgPoint", into = "SerializedProgPoint")]
118 pub struct ProgPoint(usize);
121 pub const fn new(inst: InstIdx, stage: InstStage) -> Self {
122 const_unwrap_res!(Self::try_new(inst, stage))
124 pub const fn try_new(inst: InstIdx, stage: InstStage) -> Result<Self> {
125 let Some(inst) = inst.get().checked_shl(1) else {
126 return Err(Error::InstIdxTooBig);
128 Ok(Self(inst | stage as usize))
130 pub const fn inst(self) -> InstIdx {
131 InstIdx::new(self.0 >> 1)
133 pub const fn stage(self) -> InstStage {
140 pub const fn next(self) -> Self {
143 pub const fn prev(self) -> Self {
148 impl fmt::Debug for ProgPoint {
149 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150 f.debug_struct("ProgPoint")
151 .field("inst", &self.inst())
152 .field("stage", &self.stage())
157 #[derive(Serialize, Deserialize)]
158 struct SerializedProgPoint {
163 impl From<ProgPoint> for SerializedProgPoint {
164 fn from(value: ProgPoint) -> Self {
167 stage: value.stage(),
172 impl TryFrom<SerializedProgPoint> for ProgPoint {
175 fn try_from(value: SerializedProgPoint) -> Result<Self, Self::Error> {
176 ProgPoint::try_new(value.inst, value.stage)
180 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Serialize, Deserialize)]
182 pub enum OperandKind {
187 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Serialize, Deserialize)]
188 pub enum Constraint {
189 /// any register or stack location
193 /// r2,r4,r6,r8,...r126
199 /// any stack location
205 pub fn is_any(&self) -> bool {
206 matches!(self, Self::Any)
210 impl Default for Constraint {
211 fn default() -> Self {
217 Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Serialize, Deserialize, Default,
219 #[serde(try_from = "OperandKind", into = "OperandKind")]
220 pub struct OperandKindDefOnly;
222 impl TryFrom<OperandKind> for OperandKindDefOnly {
225 fn try_from(value: OperandKind) -> Result<Self, Self::Error> {
227 OperandKind::Use => Err(Error::OperandKindMustBeDef),
228 OperandKind::Def => Ok(Self),
233 impl From<OperandKindDefOnly> for OperandKind {
234 fn from(_value: OperandKindDefOnly) -> Self {
239 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Serialize, Deserialize)]
241 pub enum KindAndConstraint {
243 kind: OperandKindDefOnly,
244 reuse_operand_idx: usize,
248 #[serde(default, skip_serializing_if = "Constraint::is_any")]
249 constraint: Constraint,
253 impl KindAndConstraint {
254 pub fn kind(self) -> OperandKind {
256 Self::Reuse { .. } => OperandKind::Def,
257 Self::Constraint { kind, .. } => kind,
260 pub fn is_reuse(self) -> bool {
261 matches!(self, Self::Reuse { .. })
265 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)]
267 pub ssa_val: SSAValIdx,
269 pub kind_and_constraint: KindAndConstraint,
270 pub stage: InstStage,
274 pub fn try_get_reuse_src<'f>(
278 ) -> Result<Option<&'f Operand>> {
279 if let KindAndConstraint::Reuse {
280 reuse_operand_idx, ..
281 } = self.kind_and_constraint
283 Ok(Some(func.try_get_operand(inst, reuse_operand_idx)?))
288 pub fn try_constraint(&self, inst: InstIdx, func: &FnFields) -> Result<Constraint> {
289 Ok(match self.kind_and_constraint {
290 KindAndConstraint::Reuse {
294 let operand = func.try_get_operand(inst, reuse_operand_idx)?;
295 match operand.kind_and_constraint {
296 KindAndConstraint::Reuse { .. }
297 | KindAndConstraint::Constraint {
298 kind: OperandKind::Def,
301 return Err(Error::ReuseTargetOperandMustBeUse {
303 reuse_target_operand_idx: reuse_operand_idx,
306 KindAndConstraint::Constraint {
307 kind: OperandKind::Use,
312 KindAndConstraint::Constraint { constraint, .. } => constraint,
315 pub fn constraint(&self, inst: InstIdx, func: &Function) -> Constraint {
316 self.try_constraint(inst, func).unwrap()
324 global_state: &GlobalState,
327 ssa_val: ssa_val_idx,
331 let ssa_val = func.try_get_ssa_val(ssa_val_idx)?;
332 match kind_and_constraint.kind() {
333 OperandKind::Use => {
336 .contains(&OperandUse { inst, operand_idx })
338 return Err(Error::MissingOperandUse {
345 OperandKind::Def => {
346 let def = SSAValDef::Operand { inst, operand_idx };
347 if ssa_val.def != def {
348 return Err(Error::OperandDefIsNotSSAValDef {
356 let constraint = self.try_constraint(inst, func)?;
358 Constraint::Any | Constraint::Stack => {}
359 Constraint::BaseGpr | Constraint::SVExtra2SGpr => {
360 if ssa_val.ty != Ty::scalar(BaseTy::Bits64) {
361 return Err(Error::ConstraintTyMismatch {
368 Constraint::SVExtra2VGpr | Constraint::SVExtra3Gpr => {
369 if ssa_val.ty.base_ty != BaseTy::Bits64 {
370 return Err(Error::ConstraintTyMismatch {
377 Constraint::FixedLoc(loc) => {
382 .conflicts_with(loc, global_state)
384 return Err(Error::FixedLocConflictsWithClobbers { inst, operand_idx });
386 if ssa_val.ty != loc.ty() {
387 return Err(Error::ConstraintTyMismatch {
399 /// copy concatenates all `srcs` together and de-concatenates the result into all `dests`.
400 #[derive(Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)]
401 pub struct CopyInstKind {
402 pub src_operand_idxs: Vec<usize>,
403 pub dest_operand_idxs: Vec<usize>,
408 fn calc_copy_ty(operand_idxs: &[usize], inst: InstIdx, func: &FnFields) -> Result<Option<Ty>> {
409 let mut retval: Option<Ty> = None;
410 for &operand_idx in operand_idxs {
411 let operand = func.try_get_operand(inst, operand_idx)?;
412 let ssa_val = func.try_get_ssa_val(operand.ssa_val)?;
413 retval = Some(match retval {
414 Some(retval) => retval.try_concat(ssa_val.ty)?,
422 #[derive(Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)]
423 pub struct BlockTermInstKind {
424 pub succs_and_params: BTreeMap<BlockIdx, Vec<SSAValIdx>>,
427 #[derive(Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)]
431 BlockTerm(BlockTermInstKind),
435 pub fn is_normal(&self) -> bool {
436 matches!(self, Self::Normal)
438 pub fn is_block_term(&self) -> bool {
439 matches!(self, Self::BlockTerm { .. })
441 pub fn is_copy(&self) -> bool {
442 matches!(self, Self::Copy { .. })
444 pub fn block_term(&self) -> Option<&BlockTermInstKind> {
446 InstKind::BlockTerm(v) => Some(v),
450 pub fn block_term_mut(&mut self) -> Option<&mut BlockTermInstKind> {
452 InstKind::BlockTerm(v) => Some(v),
456 pub fn copy(&self) -> Option<&CopyInstKind> {
458 InstKind::Copy(v) => Some(v),
464 impl Default for InstKind {
465 fn default() -> Self {
470 fn loc_set_is_empty(clobbers: &Interned<LocSet>) -> bool {
474 fn empty_loc_set() -> Interned<LocSet> {
475 GlobalState::get(|global_state| LocSet::default().into_interned(global_state))
478 #[derive(Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)]
480 #[serde(default, skip_serializing_if = "InstKind::is_normal")]
482 pub operands: Vec<Operand>,
483 #[serde(default = "empty_loc_set", skip_serializing_if = "loc_set_is_empty")]
484 pub clobbers: Interned<LocSet>,
493 global_state: &GlobalState,
500 let is_at_end_of_block = func.blocks[block].insts.last() == Some(inst);
501 if kind.is_block_term() != is_at_end_of_block {
502 return Err(if is_at_end_of_block {
503 Error::BlocksLastInstMustBeTerm { term_idx: inst }
505 Error::TermInstOnlyAllowedAtBlockEnd { inst_idx: inst }
508 for (idx, operand) in operands.iter().enumerate() {
509 operand.validate(block, inst, idx, func, global_state)?;
512 InstKind::Normal => {}
513 InstKind::Copy(CopyInstKind {
518 let mut seen_dest_operands = SmallVec::<[bool; 16]>::new();
519 seen_dest_operands.resize(operands.len(), false);
520 for &dest_operand_idx in dest_operand_idxs {
521 let seen_dest_operand = seen_dest_operands.get_mut(dest_operand_idx).ok_or(
522 Error::OperandIndexOutOfRange {
524 operand_idx: dest_operand_idx,
527 if mem::replace(seen_dest_operand, true) {
528 return Err(Error::DupCopyDestOperand {
530 operand_idx: dest_operand_idx,
534 if Some(*copy_ty) != CopyInstKind::calc_copy_ty(&src_operand_idxs, inst, func)? {
535 return Err(Error::CopySrcTyMismatch { inst });
537 if Some(*copy_ty) != CopyInstKind::calc_copy_ty(&dest_operand_idxs, inst, func)? {
538 return Err(Error::CopyDestTyMismatch { inst });
541 InstKind::BlockTerm(BlockTermInstKind { succs_and_params }) => {
542 for (&succ_idx, params) in succs_and_params {
543 let succ = func.try_get_block(succ_idx)?;
544 if !succ.preds.contains(&block) {
545 return Err(Error::SrcBlockMissingFromBranchTgtBlocksPreds {
551 if succ.params.len() != params.len() {
552 return Err(Error::BranchSuccParamCountMismatch {
555 block_param_count: succ.params.len(),
556 branch_param_count: params.len(),
559 for (param_idx, (&branch_ssa_val_idx, &block_ssa_val_idx)) in
560 params.iter().zip(&succ.params).enumerate()
562 let branch_ssa_val = func.try_get_ssa_val(branch_ssa_val_idx)?;
563 let block_ssa_val = func.try_get_ssa_val(block_ssa_val_idx)?;
565 .branch_succ_param_uses
566 .contains(&BranchSuccParamUse {
572 return Err(Error::MissingBranchSuccParamUse {
573 ssa_val_idx: branch_ssa_val_idx,
579 if block_ssa_val.ty != branch_ssa_val.ty {
580 return Err(Error::BranchSuccParamTyMismatch {
584 block_param_ty: block_ssa_val.ty,
585 branch_param_ty: branch_ssa_val.ty,
594 pub fn try_get_operand(&self, inst: InstIdx, operand_idx: usize) -> Result<&Operand> {
597 .ok_or(Error::OperandIndexOutOfRange { inst, operand_idx })
601 #[derive(Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)]
603 pub params: Vec<SSAValIdx>,
604 pub insts: InstRange,
605 pub preds: BTreeSet<BlockIdx>,
606 pub immediate_dominator: Option<BlockIdx>,
610 fn validate(&self, block: BlockIdx, func: &FnFields, global_state: &GlobalState) -> Result<()> {
615 immediate_dominator: _, // validated by Function::new_with_global_state
617 const _: () = assert!(BlockIdx::ENTRY_BLOCK.get() == 0);
618 let expected_start = if block == BlockIdx::ENTRY_BLOCK {
621 func.blocks[block.prev()].insts.end
623 if insts.start != expected_start {
624 return Err(Error::BlockHasInvalidStart {
629 let term_inst_idx = insts.last().ok_or(Error::BlockIsEmpty { block })?;
631 .get(term_inst_idx.get())
632 .ok_or(Error::BlockEndOutOfRange { end: insts.end })?;
633 if block.get() == func.blocks.len() - 1 && insts.end.get() != func.insts.len() {
634 return Err(Error::InstHasNoBlock { inst: insts.end });
636 if block == BlockIdx::ENTRY_BLOCK {
637 if !params.is_empty() {
638 return Err(Error::EntryBlockCantHaveParams);
640 if !preds.is_empty() {
641 return Err(Error::EntryBlockCantHavePreds);
645 func.insts[inst].validate(block, inst, func, global_state)?;
647 for (param_idx, &ssa_val_idx) in params.iter().enumerate() {
648 let ssa_val = func.try_get_ssa_val(ssa_val_idx)?;
649 let def = SSAValDef::BlockParam { block, param_idx };
650 if ssa_val.def != def {
651 return Err(Error::MismatchedBlockParamDef {
659 let (term_inst, BlockTermInstKind { succs_and_params }) =
660 func.try_get_block_term_inst_and_kind(pred)?;
661 if !succs_and_params.contains_key(&pred) {
662 return Err(Error::PredMissingFromPredsTermBranchsTargets {
664 branch_inst: term_inst,
668 if preds.len() > 1 && succs_and_params.len() > 1 {
669 return Err(Error::CriticalEdgeNotAllowed {
671 branch_inst: term_inst,
681 #[fields_ty = FnFields]
682 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
683 pub struct Function {
684 pub ssa_vals: Vec<SSAVal>,
685 pub insts: Vec<Inst>,
686 pub blocks: Vec<Block>,
688 /// map from blocks' start instruction's index to their block index, doesn't contain the entry block
689 pub start_inst_to_block_map: BTreeMap<InstIdx, BlockIdx>,
694 pub fn new(fields: FnFields) -> Result<Self> {
695 GlobalState::get(|global_state| Self::new_with_global_state(fields, global_state))
697 pub fn new_with_global_state(mut fields: FnFields, global_state: &GlobalState) -> Result<Self> {
698 fields.fill_start_inst_to_block_map();
703 start_inst_to_block_map: _,
706 .get(BlockIdx::ENTRY_BLOCK.get())
707 .ok_or(Error::MissingEntryBlock)?;
708 for (idx, block) in blocks.iter().enumerate() {
709 block.validate(BlockIdx::new(idx), &fields, global_state)?;
711 let dominators = dominators::simple_fast(&fields, BlockIdx::ENTRY_BLOCK);
712 for (idx, block) in blocks.iter().enumerate() {
713 let block_idx = BlockIdx::new(idx);
714 let expected = dominators.immediate_dominator(block_idx);
715 if block.immediate_dominator != expected {
716 return Err(Error::IncorrectImmediateDominator {
718 found: block.immediate_dominator,
723 for (idx, ssa_val) in ssa_vals.iter().enumerate() {
724 ssa_val.validate(SSAValIdx::new(idx), &fields)?;
728 pub fn entry_block(&self) -> &Block {
731 pub fn block_term_kind(&self, block: BlockIdx) -> &BlockTermInstKind {
732 self.insts[self.blocks[block].insts.last().unwrap()]
740 pub fn fill_start_inst_to_block_map(&mut self) {
741 self.start_inst_to_block_map.clear();
742 for (idx, block) in self.blocks.iter().enumerate() {
743 let block_idx = BlockIdx::new(idx);
744 if block_idx != BlockIdx::ENTRY_BLOCK {
745 self.start_inst_to_block_map
746 .insert(block.insts.start, block_idx);
750 pub fn try_get_ssa_val(&self, idx: SSAValIdx) -> Result<&SSAVal> {
753 .ok_or(Error::SSAValIdxOutOfRange { idx })
755 pub fn try_get_inst(&self, idx: InstIdx) -> Result<&Inst> {
758 .ok_or(Error::InstIdxOutOfRange { idx })
760 pub fn try_get_inst_mut(&mut self, idx: InstIdx) -> Result<&mut Inst> {
763 .ok_or(Error::InstIdxOutOfRange { idx })
765 pub fn try_get_operand(&self, inst: InstIdx, operand_idx: usize) -> Result<&Operand> {
766 self.try_get_inst(inst)?.try_get_operand(inst, operand_idx)
768 pub fn try_get_block(&self, idx: BlockIdx) -> Result<&Block> {
771 .ok_or(Error::BlockIdxOutOfRange { idx })
773 pub fn try_get_block_param(&self, block: BlockIdx, param_idx: usize) -> Result<SSAValIdx> {
774 self.try_get_block(block)?
778 .ok_or(Error::BlockParamIdxOutOfRange { block, param_idx })
780 pub fn try_get_block_term_inst_idx(&self, block: BlockIdx) -> Result<InstIdx> {
781 self.try_get_block(block)?
784 .ok_or(Error::BlockIsEmpty { block })
786 pub fn try_get_block_term_inst_and_kind(
789 ) -> Result<(InstIdx, &BlockTermInstKind)> {
790 let term_idx = self.try_get_block_term_inst_idx(block)?;
792 .try_get_inst(term_idx)?
795 .ok_or(Error::BlocksLastInstMustBeTerm { term_idx })?;
796 Ok((term_idx, term_kind))
798 pub fn try_get_block_term_inst_and_kind_mut(
801 ) -> Result<(InstIdx, &mut BlockTermInstKind)> {
802 let term_idx = self.try_get_block_term_inst_idx(block)?;
804 .try_get_inst_mut(term_idx)?
807 .ok_or(Error::BlocksLastInstMustBeTerm { term_idx })?;
808 Ok((term_idx, term_kind))
810 pub fn try_get_branch_target_params(
812 branch_inst: InstIdx,
814 ) -> Result<&[SSAValIdx]> {
815 let inst = self.try_get_inst(branch_inst)?;
816 let BlockTermInstKind { succs_and_params } = inst
819 .ok_or(Error::InstIsNotBlockTerm { inst: branch_inst })?;
822 .ok_or(Error::BranchTargetNotFound {
827 pub fn try_get_branch_target_param(
829 branch_inst: InstIdx,
832 ) -> Result<SSAValIdx> {
834 .try_get_branch_target_params(branch_inst, succ)?
836 .ok_or(Error::BranchTargetParamIdxOutOfRange {
842 pub fn inst_to_block(&self, inst: InstIdx) -> BlockIdx {
843 self.start_inst_to_block_map
847 .unwrap_or(BlockIdx::ENTRY_BLOCK)
851 impl Index<SSAValIdx> for Vec<SSAVal> {
852 type Output = SSAVal;
854 fn index(&self, index: SSAValIdx) -> &Self::Output {
859 impl IndexMut<SSAValIdx> for Vec<SSAVal> {
860 fn index_mut(&mut self, index: SSAValIdx) -> &mut Self::Output {
861 &mut self[index.get()]
865 impl Index<InstIdx> for Vec<Inst> {
868 fn index(&self, index: InstIdx) -> &Self::Output {
873 impl IndexMut<InstIdx> for Vec<Inst> {
874 fn index_mut(&mut self, index: InstIdx) -> &mut Self::Output {
875 &mut self[index.get()]
879 impl Index<BlockIdx> for Vec<Block> {
882 fn index(&self, index: BlockIdx) -> &Self::Output {
887 impl IndexMut<BlockIdx> for Vec<Block> {
888 fn index_mut(&mut self, index: BlockIdx) -> &mut Self::Output {
889 &mut self[index.get()]
893 impl GraphBase for FnFields {
894 type EdgeId = (BlockIdx, BlockIdx);
895 type NodeId = BlockIdx;
898 pub struct Neighbors<'a> {
899 iter: Option<btree_map::Keys<'a, BlockIdx, Vec<SSAValIdx>>>,
902 impl Iterator for Neighbors<'_> {
903 type Item = BlockIdx;
905 fn next(&mut self) -> Option<Self::Item> {
906 Some(*self.iter.as_mut()?.next()?)
910 impl<'a> IntoNeighbors for &'a FnFields {
911 type Neighbors = Neighbors<'a>;
913 fn neighbors(self, block_idx: Self::NodeId) -> Self::Neighbors {
916 .try_get_block_term_inst_and_kind(block_idx)
918 .map(|(_, BlockTermInstKind { succs_and_params })| succs_and_params.keys()),
923 pub struct VisitedMap(HashSet<BlockIdx>);
925 impl VisitMap<BlockIdx> for VisitedMap {
926 fn visit(&mut self, block: BlockIdx) -> bool {
930 fn is_visited(&self, block: &BlockIdx) -> bool {
931 self.0.contains(block)
935 impl Visitable for FnFields {
936 type Map = VisitedMap;
938 fn visit_map(&self) -> Self::Map {
939 VisitedMap(HashSet::new())
942 fn reset_map(&self, map: &mut Self::Map) {
947 impl GraphProp for FnFields {
948 type EdgeType = Directed;