1//! Determining which types has float.
23use super::{generate_dependencies, ConstrainResult, MonotoneFramework};
4use crate::ir::comp::Field;
5use crate::ir::comp::FieldMethods;
6use crate::ir::context::{BindgenContext, ItemId};
7use crate::ir::traversal::EdgeKind;
8use crate::ir::ty::TypeKind;
9use crate::{HashMap, HashSet};
1011/// An analysis that finds for each IR item whether it has float or not.
12///
13/// We use the monotone constraint function `has_float`,
14/// defined as follows:
15///
16/// * If T is float or complex float, T trivially has.
17/// * If T is a type alias, a templated alias or an indirection to another type,
18/// it has float if the type T refers to has.
19/// * If T is a compound type, it has float if any of base memter or field
20/// has.
21/// * If T is an instantiation of an abstract template definition, T has
22/// float if any of the template arguments or template definition
23/// has.
24#[derive(Debug, Clone)]
25pub(crate) struct HasFloat<'ctx> {
26 ctx: &'ctx BindgenContext,
2728// The incremental result of this analysis's computation. Everything in this
29 // set has float.
30has_float: HashSet<ItemId>,
3132// Dependencies saying that if a key ItemId has been inserted into the
33 // `has_float` set, then each of the ids in Vec<ItemId> need to be
34 // considered again.
35 //
36 // This is a subset of the natural IR graph with reversed edges, where we
37 // only include the edges from the IR graph that can affect whether a type
38 // has float or not.
39dependencies: HashMap<ItemId, Vec<ItemId>>,
40}
4142impl HasFloat<'_> {
43fn consider_edge(kind: EdgeKind) -> bool {
44match kind {
45 EdgeKind::BaseMember |
46 EdgeKind::Field |
47 EdgeKind::TypeReference |
48 EdgeKind::VarType |
49 EdgeKind::TemplateArgument |
50 EdgeKind::TemplateDeclaration |
51 EdgeKind::TemplateParameterDefinition => true,
5253 EdgeKind::Constructor |
54 EdgeKind::Destructor |
55 EdgeKind::FunctionReturn |
56 EdgeKind::FunctionParameter |
57 EdgeKind::InnerType |
58 EdgeKind::InnerVar |
59 EdgeKind::Method => false,
60 EdgeKind::Generic => false,
61 }
62 }
6364fn insert<Id: Into<ItemId>>(&mut self, id: Id) -> ConstrainResult {
65let id = id.into();
66trace!("inserting {id:?} into the has_float set");
6768let was_not_already_in_set = self.has_float.insert(id);
69assert!(
70 was_not_already_in_set,
71"We shouldn't try and insert {id:?} twice because if it was \
72 already in the set, `constrain` should have exited early."
73);
7475 ConstrainResult::Changed
76 }
77}
7879impl<'ctx> MonotoneFramework for HasFloat<'ctx> {
80type Node = ItemId;
81type Extra = &'ctx BindgenContext;
82type Output = HashSet<ItemId>;
8384fn new(ctx: &'ctx BindgenContext) -> HasFloat<'ctx> {
85let has_float = HashSet::default();
86let dependencies = generate_dependencies(ctx, Self::consider_edge);
8788 HasFloat {
89 ctx,
90 has_float,
91 dependencies,
92 }
93 }
9495fn initial_worklist(&self) -> Vec<ItemId> {
96self.ctx.allowlisted_items().iter().copied().collect()
97 }
9899fn constrain(&mut self, id: ItemId) -> ConstrainResult {
100trace!("constrain: {id:?}");
101102if self.has_float.contains(&id) {
103trace!(" already know it do not have float");
104return ConstrainResult::Same;
105 }
106107let item = self.ctx.resolve_item(id);
108let Some(ty) = item.as_type() else {
109trace!(" not a type; ignoring");
110return ConstrainResult::Same;
111 };
112113match *ty.kind() {
114 TypeKind::Void |
115 TypeKind::NullPtr |
116 TypeKind::Int(..) |
117 TypeKind::Function(..) |
118 TypeKind::Enum(..) |
119 TypeKind::Reference(..) |
120 TypeKind::TypeParam |
121 TypeKind::Opaque |
122 TypeKind::Pointer(..) |
123 TypeKind::UnresolvedTypeRef(..) |
124 TypeKind::ObjCInterface(..) |
125 TypeKind::ObjCId |
126 TypeKind::ObjCSel => {
127trace!(" simple type that do not have float");
128 ConstrainResult::Same
129 }
130131 TypeKind::Float(..) | TypeKind::Complex(..) => {
132trace!(" float type has float");
133self.insert(id)
134 }
135136 TypeKind::Array(t, _) => {
137if self.has_float.contains(&t.into()) {
138trace!(
139" Array with type T that has float also has float"
140);
141return self.insert(id);
142 }
143trace!(" Array with type T that do not have float also do not have float");
144 ConstrainResult::Same
145 }
146 TypeKind::Vector(t, _) => {
147if self.has_float.contains(&t.into()) {
148trace!(
149" Vector with type T that has float also has float"
150);
151return self.insert(id);
152 }
153trace!(" Vector with type T that do not have float also do not have float");
154 ConstrainResult::Same
155 }
156157 TypeKind::ResolvedTypeRef(t) |
158 TypeKind::TemplateAlias(t, _) |
159 TypeKind::Alias(t) |
160 TypeKind::BlockPointer(t) => {
161if self.has_float.contains(&t.into()) {
162trace!(
163" aliases and type refs to T which have float \
164 also have float"
165);
166self.insert(id)
167 } else {
168trace!(" aliases and type refs to T which do not have float \
169 also do not have floaarrayt");
170 ConstrainResult::Same
171 }
172 }
173174 TypeKind::Comp(ref info) => {
175let bases_have = info
176 .base_members()
177 .iter()
178 .any(|base| self.has_float.contains(&base.ty.into()));
179if bases_have {
180trace!(" bases have float, so we also have");
181return self.insert(id);
182 }
183let fields_have = info.fields().iter().any(|f| match *f {
184 Field::DataMember(ref data) => {
185self.has_float.contains(&data.ty().into())
186 }
187 Field::Bitfields(ref bfu) => bfu
188 .bitfields()
189 .iter()
190 .any(|b| self.has_float.contains(&b.ty().into())),
191 });
192if fields_have {
193trace!(" fields have float, so we also have");
194return self.insert(id);
195 }
196197trace!(" comp doesn't have float");
198 ConstrainResult::Same
199 }
200201 TypeKind::TemplateInstantiation(ref template) => {
202let args_have = template
203 .template_arguments()
204 .iter()
205 .any(|arg| self.has_float.contains(&arg.into()));
206if args_have {
207trace!(
208" template args have float, so \
209 instantiation also has float"
210);
211return self.insert(id);
212 }
213214let def_has = self
215.has_float
216 .contains(&template.template_definition().into());
217if def_has {
218trace!(
219" template definition has float, so \
220 instantiation also has"
221);
222return self.insert(id);
223 }
224225trace!(" template instantiation do not have float");
226 ConstrainResult::Same
227 }
228 }
229 }
230231fn each_depending_on<F>(&self, id: ItemId, mut f: F)
232where
233F: FnMut(ItemId),
234 {
235if let Some(edges) = self.dependencies.get(&id) {
236for item in edges {
237trace!("enqueue {item:?} into worklist");
238 f(*item);
239 }
240 }
241 }
242}
243244impl<'ctx> From<HasFloat<'ctx>> for HashSet<ItemId> {
245fn from(analysis: HasFloat<'ctx>) -> Self {
246 analysis.has_float
247 }
248}