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,
42 from_bits,
43 to_bits
44 );
45 Ok(fact
46 .and_then(|f| ctx.uextend(&f, from_bits, to_bits))
47 .or_else(|| {
48 let result = Fact::Range {
49 bit_width: to_bits,
50 min: 0,
51 max,
52 };
53 trace!(" -> clamping to {:?}", result);
54 Some(result)
55 }))
56}
57
58pub(crate) fn check_subsumes(ctx: &FactContext, subsumer: &Fact, subsumee: &Fact) -> PccResult<()> {
59 check_subsumes_optionals(ctx, Some(subsumer), Some(subsumee))
60}
61
62pub(crate) fn check_subsumes_optionals(
63 ctx: &FactContext,
64 subsumer: Option<&Fact>,
65 subsumee: Option<&Fact>,
66) -> PccResult<()> {
67 trace!(
68 "checking if derived fact {:?} subsumes stated fact {:?}",
69 subsumer,
70 subsumee
71 );
72
73 if ctx.subsumes_fact_optionals(subsumer, subsumee) {
74 Ok(())
75 } else {
76 Err(PccError::UnsupportedFact)
77 }
78}
79
80pub(crate) fn check_output<I: VCodeInst, F: FnOnce(&VCode<I>) -> PccResult<Option<Fact>>>(
81 ctx: &FactContext,
82 vcode: &mut VCode<I>,
83 out: Writable<Reg>,
84 ins: &[Reg],
85 f: F,
86) -> PccResult<()> {
87 if let Some(fact) = vcode.vreg_fact(out.to_reg().into()) {
88 let result = f(vcode)?;
89 check_subsumes_optionals(ctx, result.as_ref(), Some(fact))
90 } else if ins.iter().any(|r| {
91 vcode
92 .vreg_fact(r.into())
93 .map(|fact| fact.propagates())
94 .unwrap_or(false)
95 }) {
96 if let Ok(Some(fact)) = f(vcode) {
97 trace!("setting vreg {:?} to {:?}", out, fact);
98 vcode.set_vreg_fact(out.to_reg().into(), fact);
99 }
100 Ok(())
101 } else {
102 Ok(())
103 }
104}
105
106pub(crate) fn check_unop<I: VCodeInst, F: FnOnce(&Fact) -> PccResult<Option<Fact>>>(
107 ctx: &FactContext,
108 vcode: &mut VCode<I>,
109 reg_width: u16,
110 out: Writable<Reg>,
111 ra: Reg,
112 f: F,
113) -> PccResult<()> {
114 check_output(ctx, vcode, out, &[ra], |vcode| {
115 let ra = get_fact_or_default(vcode, ra, reg_width);
116 f(&ra)
117 })
118}
119
120pub(crate) fn check_binop<I: VCodeInst, F: FnOnce(&Fact, &Fact) -> PccResult<Option<Fact>>>(
121 ctx: &FactContext,
122 vcode: &mut VCode<I>,
123 reg_width: u16,
124 out: Writable<Reg>,
125 ra: Reg,
126 rb: Reg,
127 f: F,
128) -> PccResult<()> {
129 check_output(ctx, vcode, out, &[ra, rb], |vcode| {
130 let ra = get_fact_or_default(vcode, ra, reg_width);
131 let rb = get_fact_or_default(vcode, rb, reg_width);
132 f(&ra, &rb)
133 })
134}
135
136pub(crate) fn check_constant<I: VCodeInst>(
137 ctx: &FactContext,
138 vcode: &mut VCode<I>,
139 out: Writable<Reg>,
140 bit_width: u16,
141 value: u64,
142) -> PccResult<()> {
143 let result = Fact::constant(bit_width, value);
144 if let Some(fact) = vcode.vreg_fact(out.to_reg().into()) {
145 check_subsumes(ctx, &result, fact)
146 } else {
147 trace!("setting vreg {:?} to {:?}", out, result);
148 vcode.set_vreg_fact(out.to_reg().into(), result);
149 Ok(())
150 }
151}
152
153pub(crate) enum LoadOrStore<'a> {
161 Load {
162 result_fact: Option<&'a Fact>,
163 from_bits: u16,
164 to_bits: u16,
165 },
166 Store {
167 stored_fact: Option<&'a Fact>,
168 },
169}