1//! Determining which types has float.
2
3use 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/// 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,
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
42impl<'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
80impl<'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
248impl<'ctx> From<HasFloat<'ctx>> for HashSet<ItemId> {
249 fn from(analysis: HasFloat<'ctx>) -> Self {
250 analysis.has_float
251 }
252}
253