bindgen/ir/analysis/
has_float.rs1use 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};
10
11#[derive(Debug, Clone)]
25pub(crate) struct HasFloat<'ctx> {
26 ctx: &'ctx BindgenContext,
27
28 has_float: HashSet<ItemId>,
31
32 dependencies: HashMap<ItemId, Vec<ItemId>>,
40}
41
42impl HasFloat<'_> {
43 fn consider_edge(kind: EdgeKind) -> bool {
44 match kind {
45 EdgeKind::BaseMember |
46 EdgeKind::Field |
47 EdgeKind::TypeReference |
48 EdgeKind::VarType |
49 EdgeKind::TemplateArgument |
50 EdgeKind::TemplateDeclaration |
51 EdgeKind::TemplateParameterDefinition => true,
52
53 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 }
63
64 fn insert<Id: Into<ItemId>>(&mut self, id: Id) -> ConstrainResult {
65 let id = id.into();
66 trace!("inserting {id:?} into the has_float set");
67
68 let was_not_already_in_set = self.has_float.insert(id);
69 assert!(
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 );
74
75 ConstrainResult::Changed
76 }
77}
78
79impl<'ctx> MonotoneFramework for HasFloat<'ctx> {
80 type Node = ItemId;
81 type Extra = &'ctx BindgenContext;
82 type Output = HashSet<ItemId>;
83
84 fn new(ctx: &'ctx BindgenContext) -> HasFloat<'ctx> {
85 let has_float = HashSet::default();
86 let dependencies = generate_dependencies(ctx, Self::consider_edge);
87
88 HasFloat {
89 ctx,
90 has_float,
91 dependencies,
92 }
93 }
94
95 fn initial_worklist(&self) -> Vec<ItemId> {
96 self.ctx.allowlisted_items().iter().copied().collect()
97 }
98
99 fn constrain(&mut self, id: ItemId) -> ConstrainResult {
100 trace!("constrain: {id:?}");
101
102 if self.has_float.contains(&id) {
103 trace!(" already know it do not have float");
104 return ConstrainResult::Same;
105 }
106
107 let item = self.ctx.resolve_item(id);
108 let Some(ty) = item.as_type() else {
109 trace!(" not a type; ignoring");
110 return ConstrainResult::Same;
111 };
112
113 match *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 => {
127 trace!(" simple type that do not have float");
128 ConstrainResult::Same
129 }
130
131 TypeKind::Float(..) | TypeKind::Complex(..) => {
132 trace!(" float type has float");
133 self.insert(id)
134 }
135
136 TypeKind::Array(t, _) => {
137 if self.has_float.contains(&t.into()) {
138 trace!(
139 " Array with type T that has float also has float"
140 );
141 return self.insert(id);
142 }
143 trace!(" Array with type T that do not have float also do not have float");
144 ConstrainResult::Same
145 }
146 TypeKind::Vector(t, _) => {
147 if self.has_float.contains(&t.into()) {
148 trace!(
149 " Vector with type T that has float also has float"
150 );
151 return self.insert(id);
152 }
153 trace!(" Vector with type T that do not have float also do not have float");
154 ConstrainResult::Same
155 }
156
157 TypeKind::ResolvedTypeRef(t) |
158 TypeKind::TemplateAlias(t, _) |
159 TypeKind::Alias(t) |
160 TypeKind::BlockPointer(t) => {
161 if self.has_float.contains(&t.into()) {
162 trace!(
163 " aliases and type refs to T which have float \
164 also have float"
165 );
166 self.insert(id)
167 } else {
168 trace!(" aliases and type refs to T which do not have float \
169 also do not have floaarrayt");
170 ConstrainResult::Same
171 }
172 }
173
174 TypeKind::Comp(ref info) => {
175 let bases_have = info
176 .base_members()
177 .iter()
178 .any(|base| self.has_float.contains(&base.ty.into()));
179 if bases_have {
180 trace!(" bases have float, so we also have");
181 return self.insert(id);
182 }
183 let fields_have = info.fields().iter().any(|f| match *f {
184 Field::DataMember(ref data) => {
185 self.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 });
192 if fields_have {
193 trace!(" fields have float, so we also have");
194 return self.insert(id);
195 }
196
197 trace!(" comp doesn't have float");
198 ConstrainResult::Same
199 }
200
201 TypeKind::TemplateInstantiation(ref template) => {
202 let args_have = template
203 .template_arguments()
204 .iter()
205 .any(|arg| self.has_float.contains(&arg.into()));
206 if args_have {
207 trace!(
208 " template args have float, so \
209 instantiation also has float"
210 );
211 return self.insert(id);
212 }
213
214 let def_has = self
215 .has_float
216 .contains(&template.template_definition().into());
217 if def_has {
218 trace!(
219 " template definition has float, so \
220 instantiation also has"
221 );
222 return self.insert(id);
223 }
224
225 trace!(" template instantiation do not have float");
226 ConstrainResult::Same
227 }
228 }
229 }
230
231 fn each_depending_on<F>(&self, id: ItemId, mut f: F)
232 where
233 F: FnMut(ItemId),
234 {
235 if let Some(edges) = self.dependencies.get(&id) {
236 for item in edges {
237 trace!("enqueue {item:?} into worklist");
238 f(*item);
239 }
240 }
241 }
242}
243
244impl<'ctx> From<HasFloat<'ctx>> for HashSet<ItemId> {
245 fn from(analysis: HasFloat<'ctx>) -> Self {
246 analysis.has_float
247 }
248}