Path: blob/main/cranelift/codegen/src/machinst/pcc.rs
1693 views
//! Common helpers for ISA-specific proof-carrying-code implementations.12use crate::ir::pcc::{Fact, FactContext, PccError, PccResult};3use crate::machinst::{Reg, VCode, VCodeInst, Writable};4use crate::trace;56pub(crate) fn get_fact_or_default<I: VCodeInst>(vcode: &VCode<I>, reg: Reg, width: u16) -> Fact {7trace!(8"get_fact_or_default: reg {reg:?} -> {:?}",9vcode.vreg_fact(reg.into())10);11vcode12.vreg_fact(reg.into())13.cloned()14.unwrap_or_else(|| Fact::max_range_for_width(width))15}1617pub(crate) fn has_fact<I: VCodeInst>(vcode: &VCode<I>, reg: Reg) -> bool {18vcode.vreg_fact(reg.into()).is_some()19}2021pub(crate) fn fail_if_missing(fact: Option<Fact>) -> PccResult<Fact> {22fact.ok_or(PccError::UnsupportedFact)23}2425pub(crate) fn clamp_range(26ctx: &FactContext,27to_bits: u16,28from_bits: u16,29fact: Option<Fact>,30) -> PccResult<Option<Fact>> {31let max = if from_bits > 64 {32return Ok(None);33} else if from_bits == 64 {34u64::MAX35} else {36(1u64 << from_bits) - 137};38trace!(39"clamp_range: fact {:?} from {} to {}",40fact, from_bits, to_bits41);42Ok(fact43.and_then(|f| ctx.uextend(&f, from_bits, to_bits))44.or_else(|| {45let result = Fact::Range {46bit_width: to_bits,47min: 0,48max,49};50trace!(" -> clamping to {:?}", result);51Some(result)52}))53}5455pub(crate) fn check_subsumes(ctx: &FactContext, subsumer: &Fact, subsumee: &Fact) -> PccResult<()> {56check_subsumes_optionals(ctx, Some(subsumer), Some(subsumee))57}5859pub(crate) fn check_subsumes_optionals(60ctx: &FactContext,61subsumer: Option<&Fact>,62subsumee: Option<&Fact>,63) -> PccResult<()> {64trace!(65"checking if derived fact {:?} subsumes stated fact {:?}",66subsumer, subsumee67);6869if ctx.subsumes_fact_optionals(subsumer, subsumee) {70Ok(())71} else {72Err(PccError::UnsupportedFact)73}74}7576pub(crate) fn check_output<I: VCodeInst, F: FnOnce(&VCode<I>) -> PccResult<Option<Fact>>>(77ctx: &FactContext,78vcode: &mut VCode<I>,79out: Writable<Reg>,80ins: &[Reg],81f: F,82) -> PccResult<()> {83if let Some(fact) = vcode.vreg_fact(out.to_reg().into()) {84let result = f(vcode)?;85check_subsumes_optionals(ctx, result.as_ref(), Some(fact))86} else if ins.iter().any(|r| {87vcode88.vreg_fact(r.into())89.map(|fact| fact.propagates())90.unwrap_or(false)91}) {92if let Ok(Some(fact)) = f(vcode) {93trace!("setting vreg {:?} to {:?}", out, fact);94vcode.set_vreg_fact(out.to_reg().into(), fact);95}96Ok(())97} else {98Ok(())99}100}101102pub(crate) fn check_unop<I: VCodeInst, F: FnOnce(&Fact) -> PccResult<Option<Fact>>>(103ctx: &FactContext,104vcode: &mut VCode<I>,105reg_width: u16,106out: Writable<Reg>,107ra: Reg,108f: F,109) -> PccResult<()> {110check_output(ctx, vcode, out, &[ra], |vcode| {111let ra = get_fact_or_default(vcode, ra, reg_width);112f(&ra)113})114}115116pub(crate) fn check_binop<I: VCodeInst, F: FnOnce(&Fact, &Fact) -> PccResult<Option<Fact>>>(117ctx: &FactContext,118vcode: &mut VCode<I>,119reg_width: u16,120out: Writable<Reg>,121ra: Reg,122rb: Reg,123f: F,124) -> PccResult<()> {125check_output(ctx, vcode, out, &[ra, rb], |vcode| {126let ra = get_fact_or_default(vcode, ra, reg_width);127let rb = get_fact_or_default(vcode, rb, reg_width);128f(&ra, &rb)129})130}131132pub(crate) fn check_constant<I: VCodeInst>(133ctx: &FactContext,134vcode: &mut VCode<I>,135out: Writable<Reg>,136bit_width: u16,137value: u64,138) -> PccResult<()> {139let result = Fact::constant(bit_width, value);140if let Some(fact) = vcode.vreg_fact(out.to_reg().into()) {141check_subsumes(ctx, &result, fact)142} else {143trace!("setting vreg {:?} to {:?}", out, result);144vcode.set_vreg_fact(out.to_reg().into(), result);145Ok(())146}147}148149/// The operation we're checking against an amode: either150///151/// - a *load*, and we need to validate that the field's fact subsumes152/// the load result's fact, OR153///154/// - a *store*, and we need to validate that the stored data's fact155/// subsumes the field's fact.156pub(crate) enum LoadOrStore<'a> {157Load {158result_fact: Option<&'a Fact>,159from_bits: u16,160to_bits: u16,161},162Store {163stored_fact: Option<&'a Fact>,164},165}166167168