1 | //! Determining which types has float. |
2 | |
3 | use super::{generate_dependencies, ConstrainResult, MonotoneFramework}; |
4 | use crate::ir::comp::Field; |
5 | use crate::ir::comp::FieldMethods; |
6 | use crate::ir::context::{BindgenContext, ItemId}; |
7 | use crate::ir::traversal::EdgeKind; |
8 | use crate::ir::ty::TypeKind; |
9 | use crate::{HashMap, HashSet}; |
10 | |
11 | /// 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)] |
25 | pub(crate) struct HasFloat<'ctx> { |
26 | ctx: &'ctx BindgenContext, |
27 | |
28 | // The incremental result of this analysis's computation. Everything in this |
29 | // set has float. |
30 | has_float: HashSet<ItemId>, |
31 | |
32 | // 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. |
39 | dependencies: HashMap<ItemId, Vec<ItemId>>, |
40 | } |
41 | |
42 | impl<'ctx> HasFloat<'ctx> { |
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 {:?} into the has_float set" , id); |
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 {:?} twice because if it was \ |
72 | already in the set, `constrain` should have exited early." , |
73 | id |
74 | ); |
75 | |
76 | ConstrainResult::Changed |
77 | } |
78 | } |
79 | |
80 | impl<'ctx> MonotoneFramework for HasFloat<'ctx> { |
81 | type Node = ItemId; |
82 | type Extra = &'ctx BindgenContext; |
83 | type Output = HashSet<ItemId>; |
84 | |
85 | fn new(ctx: &'ctx BindgenContext) -> HasFloat<'ctx> { |
86 | let has_float = HashSet::default(); |
87 | let dependencies = generate_dependencies(ctx, Self::consider_edge); |
88 | |
89 | HasFloat { |
90 | ctx, |
91 | has_float, |
92 | dependencies, |
93 | } |
94 | } |
95 | |
96 | fn initial_worklist(&self) -> Vec<ItemId> { |
97 | self.ctx.allowlisted_items().iter().cloned().collect() |
98 | } |
99 | |
100 | fn constrain(&mut self, id: ItemId) -> ConstrainResult { |
101 | trace!("constrain: {:?}" , id); |
102 | |
103 | if self.has_float.contains(&id) { |
104 | trace!(" already know it do not have float" ); |
105 | return ConstrainResult::Same; |
106 | } |
107 | |
108 | let item = self.ctx.resolve_item(id); |
109 | let ty = match item.as_type() { |
110 | Some(ty) => ty, |
111 | None => { |
112 | trace!(" not a type; ignoring" ); |
113 | return ConstrainResult::Same; |
114 | } |
115 | }; |
116 | |
117 | match *ty.kind() { |
118 | TypeKind::Void | |
119 | TypeKind::NullPtr | |
120 | TypeKind::Int(..) | |
121 | TypeKind::Function(..) | |
122 | TypeKind::Enum(..) | |
123 | TypeKind::Reference(..) | |
124 | TypeKind::TypeParam | |
125 | TypeKind::Opaque | |
126 | TypeKind::Pointer(..) | |
127 | TypeKind::UnresolvedTypeRef(..) | |
128 | TypeKind::ObjCInterface(..) | |
129 | TypeKind::ObjCId | |
130 | TypeKind::ObjCSel => { |
131 | trace!(" simple type that do not have float" ); |
132 | ConstrainResult::Same |
133 | } |
134 | |
135 | TypeKind::Float(..) | TypeKind::Complex(..) => { |
136 | trace!(" float type has float" ); |
137 | self.insert(id) |
138 | } |
139 | |
140 | TypeKind::Array(t, _) => { |
141 | if self.has_float.contains(&t.into()) { |
142 | trace!( |
143 | " Array with type T that has float also has float" |
144 | ); |
145 | return self.insert(id); |
146 | } |
147 | trace!(" Array with type T that do not have float also do not have float" ); |
148 | ConstrainResult::Same |
149 | } |
150 | TypeKind::Vector(t, _) => { |
151 | if self.has_float.contains(&t.into()) { |
152 | trace!( |
153 | " Vector with type T that has float also has float" |
154 | ); |
155 | return self.insert(id); |
156 | } |
157 | trace!(" Vector with type T that do not have float also do not have float" ); |
158 | ConstrainResult::Same |
159 | } |
160 | |
161 | TypeKind::ResolvedTypeRef(t) | |
162 | TypeKind::TemplateAlias(t, _) | |
163 | TypeKind::Alias(t) | |
164 | TypeKind::BlockPointer(t) => { |
165 | if self.has_float.contains(&t.into()) { |
166 | trace!( |
167 | " aliases and type refs to T which have float \ |
168 | also have float" |
169 | ); |
170 | self.insert(id) |
171 | } else { |
172 | trace!(" aliases and type refs to T which do not have float \ |
173 | also do not have floaarrayt" ); |
174 | ConstrainResult::Same |
175 | } |
176 | } |
177 | |
178 | TypeKind::Comp(ref info) => { |
179 | let bases_have = info |
180 | .base_members() |
181 | .iter() |
182 | .any(|base| self.has_float.contains(&base.ty.into())); |
183 | if bases_have { |
184 | trace!(" bases have float, so we also have" ); |
185 | return self.insert(id); |
186 | } |
187 | let fields_have = info.fields().iter().any(|f| match *f { |
188 | Field::DataMember(ref data) => { |
189 | self.has_float.contains(&data.ty().into()) |
190 | } |
191 | Field::Bitfields(ref bfu) => bfu |
192 | .bitfields() |
193 | .iter() |
194 | .any(|b| self.has_float.contains(&b.ty().into())), |
195 | }); |
196 | if fields_have { |
197 | trace!(" fields have float, so we also have" ); |
198 | return self.insert(id); |
199 | } |
200 | |
201 | trace!(" comp doesn't have float" ); |
202 | ConstrainResult::Same |
203 | } |
204 | |
205 | TypeKind::TemplateInstantiation(ref template) => { |
206 | let args_have = template |
207 | .template_arguments() |
208 | .iter() |
209 | .any(|arg| self.has_float.contains(&arg.into())); |
210 | if args_have { |
211 | trace!( |
212 | " template args have float, so \ |
213 | insantiation also has float" |
214 | ); |
215 | return self.insert(id); |
216 | } |
217 | |
218 | let def_has = self |
219 | .has_float |
220 | .contains(&template.template_definition().into()); |
221 | if def_has { |
222 | trace!( |
223 | " template definition has float, so \ |
224 | insantiation also has" |
225 | ); |
226 | return self.insert(id); |
227 | } |
228 | |
229 | trace!(" template instantiation do not have float" ); |
230 | ConstrainResult::Same |
231 | } |
232 | } |
233 | } |
234 | |
235 | fn each_depending_on<F>(&self, id: ItemId, mut f: F) |
236 | where |
237 | F: FnMut(ItemId), |
238 | { |
239 | if let Some(edges) = self.dependencies.get(&id) { |
240 | for item in edges { |
241 | trace!("enqueue {:?} into worklist" , item); |
242 | f(*item); |
243 | } |
244 | } |
245 | } |
246 | } |
247 | |
248 | impl<'ctx> From<HasFloat<'ctx>> for HashSet<ItemId> { |
249 | fn from(analysis: HasFloat<'ctx>) -> Self { |
250 | analysis.has_float |
251 | } |
252 | } |
253 | |