cranelift_codegen/machinst/
pcc.rs1use crate::ir::pcc::{Fact, FactContext, PccError, PccResult};
4use crate::machinst::{Reg, VCode, VCodeInst, Writable};
5use crate::trace;
6
7pub(crate) fn get_fact_or_default<I: VCodeInst>(vcode: &VCode<I>, reg: Reg, width: u16) -> Fact {
8 trace!(
9 "get_fact_or_default: reg {reg:?} -> {:?}",
10 vcode.vreg_fact(reg.into())
11 );
12 vcode
13 .vreg_fact(reg.into())
14 .cloned()
15 .unwrap_or_else(|| Fact::max_range_for_width(width))
16}
17
18pub(crate) fn has_fact<I: VCodeInst>(vcode: &VCode<I>, reg: Reg) -> bool {
19 vcode.vreg_fact(reg.into()).is_some()
20}
21
22pub(crate) fn fail_if_missing(fact: Option<Fact>) -> PccResult<Fact> {
23 fact.ok_or(PccError::UnsupportedFact)
24}
25
26pub(crate) fn clamp_range(
27 ctx: &FactContext,
28 to_bits: u16,
29 from_bits: u16,
30 fact: Option<Fact>,
31) -> PccResult<Option<Fact>> {
32 let max = if from_bits > 64 {
33 return Ok(None);
34 } else if from_bits == 64 {
35 u64::MAX
36 } else {
37 (1u64 << from_bits) - 1
38 };
39 trace!(
40 "clamp_range: fact {:?} from {} to {}",
41 fact, from_bits, to_bits
42 );
43 Ok(fact
44 .and_then(|f| ctx.uextend(&f, from_bits, to_bits))
45 .or_else(|| {
46 let result = Fact::Range {
47 bit_width: to_bits,
48 min: 0,
49 max,
50 };
51 trace!(" -> clamping to {:?}", result);
52 Some(result)
53 }))
54}
55
56pub(crate) fn check_subsumes(ctx: &FactContext, subsumer: &Fact, subsumee: &Fact) -> PccResult<()> {
57 check_subsumes_optionals(ctx, Some(subsumer), Some(subsumee))
58}
59
60pub(crate) fn check_subsumes_optionals(
61 ctx: &FactContext,
62 subsumer: Option<&Fact>,
63 subsumee: Option<&Fact>,
64) -> PccResult<()> {
65 trace!(
66 "checking if derived fact {:?} subsumes stated fact {:?}",
67 subsumer, subsumee
68 );
69
70 if ctx.subsumes_fact_optionals(subsumer, subsumee) {
71 Ok(())
72 } else {
73 Err(PccError::UnsupportedFact)
74 }
75}
76
77pub(crate) fn check_output<I: VCodeInst, F: FnOnce(&VCode<I>) -> PccResult<Option<Fact>>>(
78 ctx: &FactContext,
79 vcode: &mut VCode<I>,
80 out: Writable<Reg>,
81 ins: &[Reg],
82 f: F,
83) -> PccResult<()> {
84 if let Some(fact) = vcode.vreg_fact(out.to_reg().into()) {
85 let result = f(vcode)?;
86 check_subsumes_optionals(ctx, result.as_ref(), Some(fact))
87 } else if ins.iter().any(|r| {
88 vcode
89 .vreg_fact(r.into())
90 .map(|fact| fact.propagates())
91 .unwrap_or(false)
92 }) {
93 if let Ok(Some(fact)) = f(vcode) {
94 trace!("setting vreg {:?} to {:?}", out, fact);
95 vcode.set_vreg_fact(out.to_reg().into(), fact);
96 }
97 Ok(())
98 } else {
99 Ok(())
100 }
101}
102
103pub(crate) fn check_unop<I: VCodeInst, F: FnOnce(&Fact) -> PccResult<Option<Fact>>>(
104 ctx: &FactContext,
105 vcode: &mut VCode<I>,
106 reg_width: u16,
107 out: Writable<Reg>,
108 ra: Reg,
109 f: F,
110) -> PccResult<()> {
111 check_output(ctx, vcode, out, &[ra], |vcode| {
112 let ra = get_fact_or_default(vcode, ra, reg_width);
113 f(&ra)
114 })
115}
116
117pub(crate) fn check_binop<I: VCodeInst, F: FnOnce(&Fact, &Fact) -> PccResult<Option<Fact>>>(
118 ctx: &FactContext,
119 vcode: &mut VCode<I>,
120 reg_width: u16,
121 out: Writable<Reg>,
122 ra: Reg,
123 rb: Reg,
124 f: F,
125) -> PccResult<()> {
126 check_output(ctx, vcode, out, &[ra, rb], |vcode| {
127 let ra = get_fact_or_default(vcode, ra, reg_width);
128 let rb = get_fact_or_default(vcode, rb, reg_width);
129 f(&ra, &rb)
130 })
131}
132
133pub(crate) fn check_constant<I: VCodeInst>(
134 ctx: &FactContext,
135 vcode: &mut VCode<I>,
136 out: Writable<Reg>,
137 bit_width: u16,
138 value: u64,
139) -> PccResult<()> {
140 let result = Fact::constant(bit_width, value);
141 if let Some(fact) = vcode.vreg_fact(out.to_reg().into()) {
142 check_subsumes(ctx, &result, fact)
143 } else {
144 trace!("setting vreg {:?} to {:?}", out, result);
145 vcode.set_vreg_fact(out.to_reg().into(), result);
146 Ok(())
147 }
148}
149
150pub(crate) enum LoadOrStore<'a> {
158 Load {
159 result_fact: Option<&'a Fact>,
160 from_bits: u16,
161 to_bits: u16,
162 },
163 Store {
164 stored_fact: Option<&'a Fact>,
165 },
166}