xref: /llvm-project/clang/lib/Analysis/FlowSensitive/SimplifyConstraints.cpp (revision 1b1b5251479c42c793b14fb9588545f9619b85d6)
17c636728Smartinboehme //===-- SimplifyConstraints.cpp ---------------------------------*- C++ -*-===//
27c636728Smartinboehme //
37c636728Smartinboehme // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47c636728Smartinboehme // See https://llvm.org/LICENSE.txt for license information.
57c636728Smartinboehme // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67c636728Smartinboehme //
77c636728Smartinboehme //===----------------------------------------------------------------------===//
87c636728Smartinboehme 
97c636728Smartinboehme #include "clang/Analysis/FlowSensitive/SimplifyConstraints.h"
107c636728Smartinboehme #include "llvm/ADT/EquivalenceClasses.h"
117c636728Smartinboehme 
127c636728Smartinboehme namespace clang {
137c636728Smartinboehme namespace dataflow {
147c636728Smartinboehme 
157c636728Smartinboehme // Substitutes all occurrences of a given atom in `F` by a given formula and
167c636728Smartinboehme // returns the resulting formula.
177c636728Smartinboehme static const Formula &
substitute(const Formula & F,const llvm::DenseMap<Atom,const Formula * > & Substitutions,Arena & arena)187c636728Smartinboehme substitute(const Formula &F,
197c636728Smartinboehme            const llvm::DenseMap<Atom, const Formula *> &Substitutions,
207c636728Smartinboehme            Arena &arena) {
217c636728Smartinboehme   switch (F.kind()) {
227c636728Smartinboehme   case Formula::AtomRef:
237c636728Smartinboehme     if (auto iter = Substitutions.find(F.getAtom());
247c636728Smartinboehme         iter != Substitutions.end())
257c636728Smartinboehme       return *iter->second;
267c636728Smartinboehme     return F;
277c636728Smartinboehme   case Formula::Literal:
287c636728Smartinboehme     return F;
297c636728Smartinboehme   case Formula::Not:
307c636728Smartinboehme     return arena.makeNot(substitute(*F.operands()[0], Substitutions, arena));
317c636728Smartinboehme   case Formula::And:
327c636728Smartinboehme     return arena.makeAnd(substitute(*F.operands()[0], Substitutions, arena),
337c636728Smartinboehme                          substitute(*F.operands()[1], Substitutions, arena));
347c636728Smartinboehme   case Formula::Or:
357c636728Smartinboehme     return arena.makeOr(substitute(*F.operands()[0], Substitutions, arena),
367c636728Smartinboehme                         substitute(*F.operands()[1], Substitutions, arena));
377c636728Smartinboehme   case Formula::Implies:
387c636728Smartinboehme     return arena.makeImplies(
397c636728Smartinboehme         substitute(*F.operands()[0], Substitutions, arena),
407c636728Smartinboehme         substitute(*F.operands()[1], Substitutions, arena));
417c636728Smartinboehme   case Formula::Equal:
427c636728Smartinboehme     return arena.makeEquals(substitute(*F.operands()[0], Substitutions, arena),
437c636728Smartinboehme                             substitute(*F.operands()[1], Substitutions, arena));
447c636728Smartinboehme   }
4524060db3SAaron Ballman   llvm_unreachable("Unknown formula kind");
467c636728Smartinboehme }
477c636728Smartinboehme 
487c636728Smartinboehme // Returns the result of replacing atoms in `Atoms` with the leader of their
497c636728Smartinboehme // equivalence class in `EquivalentAtoms`.
507c636728Smartinboehme // Atoms that don't have an equivalence class in `EquivalentAtoms` are inserted
517c636728Smartinboehme // into it as single-member equivalence classes.
527c636728Smartinboehme static llvm::DenseSet<Atom>
projectToLeaders(const llvm::DenseSet<Atom> & Atoms,llvm::EquivalenceClasses<Atom> & EquivalentAtoms)537c636728Smartinboehme projectToLeaders(const llvm::DenseSet<Atom> &Atoms,
547c636728Smartinboehme                  llvm::EquivalenceClasses<Atom> &EquivalentAtoms) {
557c636728Smartinboehme   llvm::DenseSet<Atom> Result;
567c636728Smartinboehme 
577c636728Smartinboehme   for (Atom Atom : Atoms)
587c636728Smartinboehme     Result.insert(EquivalentAtoms.getOrInsertLeaderValue(Atom));
597c636728Smartinboehme 
607c636728Smartinboehme   return Result;
617c636728Smartinboehme }
627c636728Smartinboehme 
637c636728Smartinboehme // Returns the atoms in the equivalence class for the leader identified by
647c636728Smartinboehme // `LeaderIt`.
657c636728Smartinboehme static llvm::SmallVector<Atom>
atomsInEquivalenceClass(const llvm::EquivalenceClasses<Atom> & EquivalentAtoms,llvm::EquivalenceClasses<Atom>::iterator LeaderIt)667c636728Smartinboehme atomsInEquivalenceClass(const llvm::EquivalenceClasses<Atom> &EquivalentAtoms,
677c636728Smartinboehme                         llvm::EquivalenceClasses<Atom>::iterator LeaderIt) {
687c636728Smartinboehme   llvm::SmallVector<Atom> Result;
697c636728Smartinboehme   for (auto MemberIt = EquivalentAtoms.member_begin(LeaderIt);
707c636728Smartinboehme        MemberIt != EquivalentAtoms.member_end(); ++MemberIt)
717c636728Smartinboehme     Result.push_back(*MemberIt);
727c636728Smartinboehme   return Result;
737c636728Smartinboehme }
747c636728Smartinboehme 
simplifyConstraints(llvm::SetVector<const Formula * > & Constraints,Arena & arena,SimplifyConstraintsInfo * Info)757c636728Smartinboehme void simplifyConstraints(llvm::SetVector<const Formula *> &Constraints,
767c636728Smartinboehme                          Arena &arena, SimplifyConstraintsInfo *Info) {
777c636728Smartinboehme   auto contradiction = [&]() {
787c636728Smartinboehme     Constraints.clear();
797c636728Smartinboehme     Constraints.insert(&arena.makeLiteral(false));
807c636728Smartinboehme   };
817c636728Smartinboehme 
827c636728Smartinboehme   llvm::EquivalenceClasses<Atom> EquivalentAtoms;
837c636728Smartinboehme   llvm::DenseSet<Atom> TrueAtoms;
847c636728Smartinboehme   llvm::DenseSet<Atom> FalseAtoms;
857c636728Smartinboehme 
867c636728Smartinboehme   while (true) {
877c636728Smartinboehme     for (const auto *Constraint : Constraints) {
887c636728Smartinboehme       switch (Constraint->kind()) {
897c636728Smartinboehme       case Formula::AtomRef:
907c636728Smartinboehme         TrueAtoms.insert(Constraint->getAtom());
917c636728Smartinboehme         break;
927c636728Smartinboehme       case Formula::Not:
937c636728Smartinboehme         if (Constraint->operands()[0]->kind() == Formula::AtomRef)
947c636728Smartinboehme           FalseAtoms.insert(Constraint->operands()[0]->getAtom());
957c636728Smartinboehme         break;
967c636728Smartinboehme       case Formula::Equal: {
977c636728Smartinboehme         ArrayRef<const Formula *> operands = Constraint->operands();
987c636728Smartinboehme         if (operands[0]->kind() == Formula::AtomRef &&
997c636728Smartinboehme             operands[1]->kind() == Formula::AtomRef) {
1007c636728Smartinboehme           EquivalentAtoms.unionSets(operands[0]->getAtom(),
1017c636728Smartinboehme                                     operands[1]->getAtom());
1027c636728Smartinboehme         }
1037c636728Smartinboehme         break;
1047c636728Smartinboehme       }
1057c636728Smartinboehme       default:
1067c636728Smartinboehme         break;
1077c636728Smartinboehme       }
1087c636728Smartinboehme     }
1097c636728Smartinboehme 
1107c636728Smartinboehme     TrueAtoms = projectToLeaders(TrueAtoms, EquivalentAtoms);
1117c636728Smartinboehme     FalseAtoms = projectToLeaders(FalseAtoms, EquivalentAtoms);
1127c636728Smartinboehme 
1137c636728Smartinboehme     llvm::DenseMap<Atom, const Formula *> Substitutions;
1147c636728Smartinboehme     for (auto It = EquivalentAtoms.begin(); It != EquivalentAtoms.end(); ++It) {
1157c636728Smartinboehme       Atom TheAtom = It->getData();
1167c636728Smartinboehme       Atom Leader = EquivalentAtoms.getLeaderValue(TheAtom);
1177c636728Smartinboehme       if (TrueAtoms.contains(Leader)) {
1187c636728Smartinboehme         if (FalseAtoms.contains(Leader)) {
1197c636728Smartinboehme           contradiction();
1207c636728Smartinboehme           return;
1217c636728Smartinboehme         }
1227c636728Smartinboehme         Substitutions.insert({TheAtom, &arena.makeLiteral(true)});
1237c636728Smartinboehme       } else if (FalseAtoms.contains(Leader)) {
1247c636728Smartinboehme         Substitutions.insert({TheAtom, &arena.makeLiteral(false)});
1257c636728Smartinboehme       } else if (TheAtom != Leader) {
1267c636728Smartinboehme         Substitutions.insert({TheAtom, &arena.makeAtomRef(Leader)});
1277c636728Smartinboehme       }
1287c636728Smartinboehme     }
1297c636728Smartinboehme 
1307c636728Smartinboehme     llvm::SetVector<const Formula *> NewConstraints;
1317c636728Smartinboehme     for (const auto *Constraint : Constraints) {
1327c636728Smartinboehme       const Formula &NewConstraint =
1337c636728Smartinboehme           substitute(*Constraint, Substitutions, arena);
134*1b1b5251Smartinboehme       if (NewConstraint.isLiteral(true))
1357c636728Smartinboehme         continue;
136*1b1b5251Smartinboehme       if (NewConstraint.isLiteral(false)) {
1377c636728Smartinboehme         contradiction();
1387c636728Smartinboehme         return;
1397c636728Smartinboehme       }
1407c636728Smartinboehme       if (NewConstraint.kind() == Formula::And) {
1417c636728Smartinboehme         NewConstraints.insert(NewConstraint.operands()[0]);
1427c636728Smartinboehme         NewConstraints.insert(NewConstraint.operands()[1]);
1437c636728Smartinboehme         continue;
1447c636728Smartinboehme       }
1457c636728Smartinboehme       NewConstraints.insert(&NewConstraint);
1467c636728Smartinboehme     }
1477c636728Smartinboehme 
1487c636728Smartinboehme     if (NewConstraints == Constraints)
1497c636728Smartinboehme       break;
1507c636728Smartinboehme     Constraints = std::move(NewConstraints);
1517c636728Smartinboehme   }
1527c636728Smartinboehme 
1537c636728Smartinboehme   if (Info) {
1547c636728Smartinboehme     for (auto It = EquivalentAtoms.begin(), End = EquivalentAtoms.end();
1557c636728Smartinboehme          It != End; ++It) {
1567c636728Smartinboehme       if (!It->isLeader())
1577c636728Smartinboehme         continue;
1587c636728Smartinboehme       Atom At = *EquivalentAtoms.findLeader(It);
1597c636728Smartinboehme       if (TrueAtoms.contains(At) || FalseAtoms.contains(At))
1607c636728Smartinboehme         continue;
1617c636728Smartinboehme       llvm::SmallVector<Atom> Atoms =
1627c636728Smartinboehme           atomsInEquivalenceClass(EquivalentAtoms, It);
1637c636728Smartinboehme       if (Atoms.size() == 1)
1647c636728Smartinboehme         continue;
1657c636728Smartinboehme       std::sort(Atoms.begin(), Atoms.end());
1667c636728Smartinboehme       Info->EquivalentAtoms.push_back(std::move(Atoms));
1677c636728Smartinboehme     }
1687c636728Smartinboehme     for (Atom At : TrueAtoms)
1697c636728Smartinboehme       Info->TrueAtoms.append(atomsInEquivalenceClass(
1707c636728Smartinboehme           EquivalentAtoms, EquivalentAtoms.findValue(At)));
1717c636728Smartinboehme     std::sort(Info->TrueAtoms.begin(), Info->TrueAtoms.end());
1727c636728Smartinboehme     for (Atom At : FalseAtoms)
1737c636728Smartinboehme       Info->FalseAtoms.append(atomsInEquivalenceClass(
1747c636728Smartinboehme           EquivalentAtoms, EquivalentAtoms.findValue(At)));
1757c636728Smartinboehme     std::sort(Info->FalseAtoms.begin(), Info->FalseAtoms.end());
1767c636728Smartinboehme   }
1777c636728Smartinboehme }
1787c636728Smartinboehme 
1797c636728Smartinboehme } // namespace dataflow
1807c636728Smartinboehme } // namespace clang
181