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> { consider_edge(kind: EdgeKind) -> bool43 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 insert<Id: Into<ItemId>>(&mut self, id: Id) -> ConstrainResult64 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 new(ctx: &'ctx BindgenContext) -> HasFloat<'ctx>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 initial_worklist(&self) -> Vec<ItemId>96 fn initial_worklist(&self) -> Vec<ItemId> { 97 self.ctx.allowlisted_items().iter().cloned().collect() 98 } 99 constrain(&mut self, id: ItemId) -> ConstrainResult100 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 each_depending_on<F>(&self, id: ItemId, mut f: F) where F: FnMut(ItemId),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> { from(analysis: HasFloat<'ctx>) -> Self249 fn from(analysis: HasFloat<'ctx>) -> Self { 250 analysis.has_float 251 } 252 } 253