summaryrefslogtreecommitdiffstats
path: root/third_party/rust/bindgen/ir/analysis/has_float.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/bindgen/ir/analysis/has_float.rs')
-rw-r--r--third_party/rust/bindgen/ir/analysis/has_float.rs252
1 files changed, 252 insertions, 0 deletions
diff --git a/third_party/rust/bindgen/ir/analysis/has_float.rs b/third_party/rust/bindgen/ir/analysis/has_float.rs
new file mode 100644
index 0000000000..bbf2126f70
--- /dev/null
+++ b/third_party/rust/bindgen/ir/analysis/has_float.rs
@@ -0,0 +1,252 @@
+//! Determining which types has float.
+
+use super::{generate_dependencies, ConstrainResult, MonotoneFramework};
+use crate::ir::comp::Field;
+use crate::ir::comp::FieldMethods;
+use crate::ir::context::{BindgenContext, ItemId};
+use crate::ir::traversal::EdgeKind;
+use crate::ir::ty::TypeKind;
+use crate::{HashMap, HashSet};
+
+/// An analysis that finds for each IR item whether it has float or not.
+///
+/// We use the monotone constraint function `has_float`,
+/// defined as follows:
+///
+/// * If T is float or complex float, T trivially has.
+/// * If T is a type alias, a templated alias or an indirection to another type,
+/// it has float if the type T refers to has.
+/// * If T is a compound type, it has float if any of base memter or field
+/// has.
+/// * If T is an instantiation of an abstract template definition, T has
+/// float if any of the template arguments or template definition
+/// has.
+#[derive(Debug, Clone)]
+pub struct HasFloat<'ctx> {
+ ctx: &'ctx BindgenContext,
+
+ // The incremental result of this analysis's computation. Everything in this
+ // set has float.
+ has_float: HashSet<ItemId>,
+
+ // Dependencies saying that if a key ItemId has been inserted into the
+ // `has_float` set, then each of the ids in Vec<ItemId> need to be
+ // considered again.
+ //
+ // This is a subset of the natural IR graph with reversed edges, where we
+ // only include the edges from the IR graph that can affect whether a type
+ // has float or not.
+ dependencies: HashMap<ItemId, Vec<ItemId>>,
+}
+
+impl<'ctx> HasFloat<'ctx> {
+ fn consider_edge(kind: EdgeKind) -> bool {
+ match kind {
+ EdgeKind::BaseMember |
+ EdgeKind::Field |
+ EdgeKind::TypeReference |
+ EdgeKind::VarType |
+ EdgeKind::TemplateArgument |
+ EdgeKind::TemplateDeclaration |
+ EdgeKind::TemplateParameterDefinition => true,
+
+ EdgeKind::Constructor |
+ EdgeKind::Destructor |
+ EdgeKind::FunctionReturn |
+ EdgeKind::FunctionParameter |
+ EdgeKind::InnerType |
+ EdgeKind::InnerVar |
+ EdgeKind::Method => false,
+ EdgeKind::Generic => false,
+ }
+ }
+
+ fn insert<Id: Into<ItemId>>(&mut self, id: Id) -> ConstrainResult {
+ let id = id.into();
+ trace!("inserting {:?} into the has_float set", id);
+
+ let was_not_already_in_set = self.has_float.insert(id);
+ assert!(
+ was_not_already_in_set,
+ "We shouldn't try and insert {:?} twice because if it was \
+ already in the set, `constrain` should have exited early.",
+ id
+ );
+
+ ConstrainResult::Changed
+ }
+}
+
+impl<'ctx> MonotoneFramework for HasFloat<'ctx> {
+ type Node = ItemId;
+ type Extra = &'ctx BindgenContext;
+ type Output = HashSet<ItemId>;
+
+ fn new(ctx: &'ctx BindgenContext) -> HasFloat<'ctx> {
+ let has_float = HashSet::default();
+ let dependencies = generate_dependencies(ctx, Self::consider_edge);
+
+ HasFloat {
+ ctx,
+ has_float,
+ dependencies,
+ }
+ }
+
+ fn initial_worklist(&self) -> Vec<ItemId> {
+ self.ctx.allowlisted_items().iter().cloned().collect()
+ }
+
+ fn constrain(&mut self, id: ItemId) -> ConstrainResult {
+ trace!("constrain: {:?}", id);
+
+ if self.has_float.contains(&id) {
+ trace!(" already know it do not have float");
+ return ConstrainResult::Same;
+ }
+
+ let item = self.ctx.resolve_item(id);
+ let ty = match item.as_type() {
+ Some(ty) => ty,
+ None => {
+ trace!(" not a type; ignoring");
+ return ConstrainResult::Same;
+ }
+ };
+
+ match *ty.kind() {
+ TypeKind::Void |
+ TypeKind::NullPtr |
+ TypeKind::Int(..) |
+ TypeKind::Function(..) |
+ TypeKind::Enum(..) |
+ TypeKind::Reference(..) |
+ TypeKind::TypeParam |
+ TypeKind::Opaque |
+ TypeKind::Pointer(..) |
+ TypeKind::UnresolvedTypeRef(..) |
+ TypeKind::ObjCInterface(..) |
+ TypeKind::ObjCId |
+ TypeKind::ObjCSel => {
+ trace!(" simple type that do not have float");
+ ConstrainResult::Same
+ }
+
+ TypeKind::Float(..) | TypeKind::Complex(..) => {
+ trace!(" float type has float");
+ self.insert(id)
+ }
+
+ TypeKind::Array(t, _) => {
+ if self.has_float.contains(&t.into()) {
+ trace!(
+ " Array with type T that has float also has float"
+ );
+ return self.insert(id);
+ }
+ trace!(" Array with type T that do not have float also do not have float");
+ ConstrainResult::Same
+ }
+ TypeKind::Vector(t, _) => {
+ if self.has_float.contains(&t.into()) {
+ trace!(
+ " Vector with type T that has float also has float"
+ );
+ return self.insert(id);
+ }
+ trace!(" Vector with type T that do not have float also do not have float");
+ ConstrainResult::Same
+ }
+
+ TypeKind::ResolvedTypeRef(t) |
+ TypeKind::TemplateAlias(t, _) |
+ TypeKind::Alias(t) |
+ TypeKind::BlockPointer(t) => {
+ if self.has_float.contains(&t.into()) {
+ trace!(
+ " aliases and type refs to T which have float \
+ also have float"
+ );
+ self.insert(id)
+ } else {
+ trace!(" aliases and type refs to T which do not have float \
+ also do not have floaarrayt");
+ ConstrainResult::Same
+ }
+ }
+
+ TypeKind::Comp(ref info) => {
+ let bases_have = info
+ .base_members()
+ .iter()
+ .any(|base| self.has_float.contains(&base.ty.into()));
+ if bases_have {
+ trace!(" bases have float, so we also have");
+ return self.insert(id);
+ }
+ let fields_have = info.fields().iter().any(|f| match *f {
+ Field::DataMember(ref data) => {
+ self.has_float.contains(&data.ty().into())
+ }
+ Field::Bitfields(ref bfu) => bfu
+ .bitfields()
+ .iter()
+ .any(|b| self.has_float.contains(&b.ty().into())),
+ });
+ if fields_have {
+ trace!(" fields have float, so we also have");
+ return self.insert(id);
+ }
+
+ trace!(" comp doesn't have float");
+ ConstrainResult::Same
+ }
+
+ TypeKind::TemplateInstantiation(ref template) => {
+ let args_have = template
+ .template_arguments()
+ .iter()
+ .any(|arg| self.has_float.contains(&arg.into()));
+ if args_have {
+ trace!(
+ " template args have float, so \
+ insantiation also has float"
+ );
+ return self.insert(id);
+ }
+
+ let def_has = self
+ .has_float
+ .contains(&template.template_definition().into());
+ if def_has {
+ trace!(
+ " template definition has float, so \
+ insantiation also has"
+ );
+ return self.insert(id);
+ }
+
+ trace!(" template instantiation do not have float");
+ ConstrainResult::Same
+ }
+ }
+ }
+
+ fn each_depending_on<F>(&self, id: ItemId, mut f: F)
+ where
+ F: FnMut(ItemId),
+ {
+ if let Some(edges) = self.dependencies.get(&id) {
+ for item in edges {
+ trace!("enqueue {:?} into worklist", item);
+ f(*item);
+ }
+ }
+ }
+}
+
+impl<'ctx> From<HasFloat<'ctx>> for HashSet<ItemId> {
+ fn from(analysis: HasFloat<'ctx>) -> Self {
+ analysis.has_float
+ }
+}