Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/codegen/src/machinst/pcc.rs
1693 views
1
//! Common helpers for ISA-specific proof-carrying-code implementations.
2
3
use crate::ir::pcc::{Fact, FactContext, PccError, PccResult};
4
use crate::machinst::{Reg, VCode, VCodeInst, Writable};
5
use crate::trace;
6
7
pub(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
18
pub(crate) fn has_fact<I: VCodeInst>(vcode: &VCode<I>, reg: Reg) -> bool {
19
vcode.vreg_fact(reg.into()).is_some()
20
}
21
22
pub(crate) fn fail_if_missing(fact: Option<Fact>) -> PccResult<Fact> {
23
fact.ok_or(PccError::UnsupportedFact)
24
}
25
26
pub(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
56
pub(crate) fn check_subsumes(ctx: &FactContext, subsumer: &Fact, subsumee: &Fact) -> PccResult<()> {
57
check_subsumes_optionals(ctx, Some(subsumer), Some(subsumee))
58
}
59
60
pub(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
77
pub(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
103
pub(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
117
pub(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
133
pub(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
150
/// The operation we're checking against an amode: either
151
///
152
/// - a *load*, and we need to validate that the field's fact subsumes
153
/// the load result's fact, OR
154
///
155
/// - a *store*, and we need to validate that the stored data's fact
156
/// subsumes the field's fact.
157
pub(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
}
167
168