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},
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 copy(&self) -> Option<&CopyInstKind> {
452 InstKind::Copy(v) => Some(v),
458 impl Default for InstKind {
459 fn default() -> Self {
464 fn loc_set_is_empty(clobbers: &Interned<LocSet>) -> bool {
468 fn empty_loc_set() -> Interned<LocSet> {
469 GlobalState::get(|global_state| LocSet::default().into_interned(global_state))
472 #[derive(Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)]
474 #[serde(default, skip_serializing_if = "InstKind::is_normal")]
476 pub operands: Vec<Operand>,
477 #[serde(default = "empty_loc_set", skip_serializing_if = "loc_set_is_empty")]
478 pub clobbers: Interned<LocSet>,
487 global_state: &GlobalState,
494 let is_at_end_of_block = func.blocks[block].insts.last() == Some(inst);
495 if kind.is_block_term() != is_at_end_of_block {
496 return Err(if is_at_end_of_block {
497 Error::BlocksLastInstMustBeTerm { term_idx: inst }
499 Error::TermInstOnlyAllowedAtBlockEnd { inst_idx: inst }
502 for (idx, operand) in operands.iter().enumerate() {
503 operand.validate(block, inst, idx, func, global_state)?;
506 InstKind::Normal => {}
507 InstKind::Copy(CopyInstKind {
512 let mut seen_dest_operands = SmallVec::<[bool; 16]>::new();
513 seen_dest_operands.resize(operands.len(), false);
514 for &dest_operand_idx in dest_operand_idxs {
515 let seen_dest_operand = seen_dest_operands.get_mut(dest_operand_idx).ok_or(
516 Error::OperandIndexOutOfRange {
518 operand_idx: dest_operand_idx,
521 if mem::replace(seen_dest_operand, true) {
522 return Err(Error::DupCopyDestOperand {
524 operand_idx: dest_operand_idx,
528 if Some(*copy_ty) != CopyInstKind::calc_copy_ty(&src_operand_idxs, inst, func)? {
529 return Err(Error::CopySrcTyMismatch { inst });
531 if Some(*copy_ty) != CopyInstKind::calc_copy_ty(&dest_operand_idxs, inst, func)? {
532 return Err(Error::CopyDestTyMismatch { inst });
535 InstKind::BlockTerm(BlockTermInstKind { succs_and_params }) => {
536 for (&succ_idx, params) in succs_and_params {
537 let succ = func.try_get_block(succ_idx)?;
538 if !succ.preds.contains(&block) {
539 return Err(Error::SrcBlockMissingFromBranchTgtBlocksPreds {
545 if succ.params.len() != params.len() {
546 return Err(Error::BranchSuccParamCountMismatch {
549 block_param_count: succ.params.len(),
550 branch_param_count: params.len(),
553 for (param_idx, (&branch_ssa_val_idx, &block_ssa_val_idx)) in
554 params.iter().zip(&succ.params).enumerate()
556 let branch_ssa_val = func.try_get_ssa_val(branch_ssa_val_idx)?;
557 let block_ssa_val = func.try_get_ssa_val(block_ssa_val_idx)?;
559 .branch_succ_param_uses
560 .contains(&BranchSuccParamUse {
566 return Err(Error::MissingBranchSuccParamUse {
567 ssa_val_idx: branch_ssa_val_idx,
573 if block_ssa_val.ty != branch_ssa_val.ty {
574 return Err(Error::BranchSuccParamTyMismatch {
578 block_param_ty: block_ssa_val.ty,
579 branch_param_ty: branch_ssa_val.ty,
588 pub fn try_get_operand(&self, inst: InstIdx, operand_idx: usize) -> Result<&Operand> {
591 .ok_or(Error::OperandIndexOutOfRange { inst, operand_idx })
595 #[derive(Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)]
597 pub params: Vec<SSAValIdx>,
598 pub insts: InstRange,
599 pub preds: BTreeSet<BlockIdx>,
600 pub immediate_dominator: Option<BlockIdx>,
604 fn validate(&self, block: BlockIdx, func: &FnFields, global_state: &GlobalState) -> Result<()> {
609 immediate_dominator: _,
611 const _: () = assert!(BlockIdx::ENTRY_BLOCK.get() == 0);
612 let expected_start = if block == BlockIdx::ENTRY_BLOCK {
615 func.blocks[block.prev()].insts.end
617 if insts.start != expected_start {
618 return Err(Error::BlockHasInvalidStart {
623 let term_inst_idx = insts.last().ok_or(Error::BlockIsEmpty { block })?;
625 .get(term_inst_idx.get())
626 .ok_or(Error::BlockEndOutOfRange { end: insts.end })?;
627 if block.get() == func.blocks.len() - 1 && insts.end.get() != func.insts.len() {
628 return Err(Error::InstHasNoBlock { inst: insts.end });
630 if block == BlockIdx::ENTRY_BLOCK {
631 if !params.is_empty() {
632 return Err(Error::EntryBlockCantHaveParams);
634 if !preds.is_empty() {
635 return Err(Error::EntryBlockCantHavePreds);
639 func.insts[inst].validate(block, inst, func, global_state)?;
641 for (param_idx, &ssa_val_idx) in params.iter().enumerate() {
642 let ssa_val = func.try_get_ssa_val(ssa_val_idx)?;
643 let def = SSAValDef::BlockParam { block, param_idx };
644 if ssa_val.def != def {
645 return Err(Error::MismatchedBlockParamDef {
653 let (term_inst, BlockTermInstKind { succs_and_params }) =
654 func.try_get_block_term_inst_and_kind(pred)?;
655 if !succs_and_params.contains_key(&pred) {
656 return Err(Error::PredMissingFromPredsTermBranchsTargets {
658 branch_inst: term_inst,
668 #[fields_ty = FnFields]
669 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
670 pub struct Function {
671 pub ssa_vals: Vec<SSAVal>,
672 pub insts: Vec<Inst>,
673 pub blocks: Vec<Block>,
675 /// map from blocks' start instruction's index to their block index, doesn't contain the entry block
676 pub start_inst_to_block_map: BTreeMap<InstIdx, BlockIdx>,
681 pub fn new(fields: FnFields) -> Result<Self> {
682 GlobalState::get(|global_state| Self::new_with_global_state(fields, global_state))
684 pub fn new_with_global_state(mut fields: FnFields, global_state: &GlobalState) -> Result<Self> {
685 fields.fill_start_inst_to_block_map();
690 start_inst_to_block_map: _,
693 .get(BlockIdx::ENTRY_BLOCK.get())
694 .ok_or(Error::MissingEntryBlock)?;
695 for (idx, block) in blocks.iter().enumerate() {
696 block.validate(BlockIdx::new(idx), &fields, global_state)?;
698 let dominators = dominators::simple_fast(&fields, BlockIdx::ENTRY_BLOCK);
699 for (idx, block) in blocks.iter().enumerate() {
700 let block_idx = BlockIdx::new(idx);
701 let expected = dominators.immediate_dominator(block_idx);
702 if block.immediate_dominator != expected {
703 return Err(Error::IncorrectImmediateDominator {
705 found: block.immediate_dominator,
710 for (idx, ssa_val) in ssa_vals.iter().enumerate() {
711 ssa_val.validate(SSAValIdx::new(idx), &fields)?;
715 pub fn entry_block(&self) -> &Block {
718 pub fn block_term_kind(&self, block: BlockIdx) -> &BlockTermInstKind {
719 self.insts[self.blocks[block].insts.last().unwrap()]
727 pub fn fill_start_inst_to_block_map(&mut self) {
728 self.start_inst_to_block_map.clear();
729 for (idx, block) in self.blocks.iter().enumerate() {
730 let block_idx = BlockIdx::new(idx);
731 if block_idx != BlockIdx::ENTRY_BLOCK {
732 self.start_inst_to_block_map
733 .insert(block.insts.start, block_idx);
737 pub fn try_get_ssa_val(&self, idx: SSAValIdx) -> Result<&SSAVal> {
740 .ok_or(Error::SSAValIdxOutOfRange { idx })
742 pub fn try_get_inst(&self, idx: InstIdx) -> Result<&Inst> {
745 .ok_or(Error::InstIdxOutOfRange { idx })
747 pub fn try_get_operand(&self, inst: InstIdx, operand_idx: usize) -> Result<&Operand> {
748 self.try_get_inst(inst)?.try_get_operand(inst, operand_idx)
750 pub fn try_get_block(&self, idx: BlockIdx) -> Result<&Block> {
753 .ok_or(Error::BlockIdxOutOfRange { idx })
755 pub fn try_get_block_param(&self, block: BlockIdx, param_idx: usize) -> Result<SSAValIdx> {
756 self.try_get_block(block)?
760 .ok_or(Error::BlockParamIdxOutOfRange { block, param_idx })
762 pub fn try_get_block_term_inst_idx(&self, block: BlockIdx) -> Result<InstIdx> {
763 self.try_get_block(block)?
766 .ok_or(Error::BlockIsEmpty { block })
768 pub fn try_get_block_term_inst_and_kind(
771 ) -> Result<(InstIdx, &BlockTermInstKind)> {
772 let term_idx = self.try_get_block_term_inst_idx(block)?;
774 .try_get_inst(term_idx)?
777 .ok_or(Error::BlocksLastInstMustBeTerm { term_idx })?;
778 Ok((term_idx, term_kind))
780 pub fn try_get_branch_target_params(
782 branch_inst: InstIdx,
784 ) -> Result<&[SSAValIdx]> {
785 let inst = self.try_get_inst(branch_inst)?;
786 let BlockTermInstKind { succs_and_params } = inst
789 .ok_or(Error::InstIsNotBlockTerm { inst: branch_inst })?;
792 .ok_or(Error::BranchTargetNotFound {
797 pub fn try_get_branch_target_param(
799 branch_inst: InstIdx,
802 ) -> Result<SSAValIdx> {
804 .try_get_branch_target_params(branch_inst, succ)?
806 .ok_or(Error::BranchTargetParamIdxOutOfRange {
812 pub fn inst_to_block(&self, inst: InstIdx) -> BlockIdx {
813 self.start_inst_to_block_map
817 .unwrap_or(BlockIdx::ENTRY_BLOCK)
821 impl Index<SSAValIdx> for Vec<SSAVal> {
822 type Output = SSAVal;
824 fn index(&self, index: SSAValIdx) -> &Self::Output {
829 impl Index<InstIdx> for Vec<Inst> {
832 fn index(&self, index: InstIdx) -> &Self::Output {
837 impl Index<BlockIdx> for Vec<Block> {
840 fn index(&self, index: BlockIdx) -> &Self::Output {
845 impl GraphBase for FnFields {
846 type EdgeId = (BlockIdx, BlockIdx);
847 type NodeId = BlockIdx;
850 pub struct Neighbors<'a> {
851 iter: Option<btree_map::Keys<'a, BlockIdx, Vec<SSAValIdx>>>,
854 impl Iterator for Neighbors<'_> {
855 type Item = BlockIdx;
857 fn next(&mut self) -> Option<Self::Item> {
858 Some(*self.iter.as_mut()?.next()?)
862 impl<'a> IntoNeighbors for &'a FnFields {
863 type Neighbors = Neighbors<'a>;
865 fn neighbors(self, block_idx: Self::NodeId) -> Self::Neighbors {
868 .try_get_block_term_inst_and_kind(block_idx)
870 .map(|(_, BlockTermInstKind { succs_and_params })| succs_and_params.keys()),
875 pub struct VisitedMap(HashSet<BlockIdx>);
877 impl VisitMap<BlockIdx> for VisitedMap {
878 fn visit(&mut self, block: BlockIdx) -> bool {
882 fn is_visited(&self, block: &BlockIdx) -> bool {
883 self.0.contains(block)
887 impl Visitable for FnFields {
888 type Map = VisitedMap;
890 fn visit_map(&self) -> Self::Map {
891 VisitedMap(HashSet::new())
894 fn reset_map(&self, map: &mut Self::Map) {
899 impl GraphProp for FnFields {
900 type EdgeType = Directed;