xref: /freebsd/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/SimplifyConstraints.cpp (revision 7a6dacaca14b62ca4b74406814becb87a3fefac0)
15f757f3fSDimitry Andric //===-- SimplifyConstraints.cpp ---------------------------------*- C++ -*-===//
25f757f3fSDimitry Andric //
35f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65f757f3fSDimitry Andric //
75f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
85f757f3fSDimitry Andric 
95f757f3fSDimitry Andric #include "clang/Analysis/FlowSensitive/SimplifyConstraints.h"
105f757f3fSDimitry Andric #include "llvm/ADT/EquivalenceClasses.h"
115f757f3fSDimitry Andric 
125f757f3fSDimitry Andric namespace clang {
135f757f3fSDimitry Andric namespace dataflow {
145f757f3fSDimitry Andric 
155f757f3fSDimitry Andric // Substitutes all occurrences of a given atom in `F` by a given formula and
165f757f3fSDimitry Andric // returns the resulting formula.
175f757f3fSDimitry Andric static const Formula &
185f757f3fSDimitry Andric substitute(const Formula &F,
195f757f3fSDimitry Andric            const llvm::DenseMap<Atom, const Formula *> &Substitutions,
205f757f3fSDimitry Andric            Arena &arena) {
215f757f3fSDimitry Andric   switch (F.kind()) {
225f757f3fSDimitry Andric   case Formula::AtomRef:
235f757f3fSDimitry Andric     if (auto iter = Substitutions.find(F.getAtom());
245f757f3fSDimitry Andric         iter != Substitutions.end())
255f757f3fSDimitry Andric       return *iter->second;
265f757f3fSDimitry Andric     return F;
275f757f3fSDimitry Andric   case Formula::Literal:
285f757f3fSDimitry Andric     return F;
295f757f3fSDimitry Andric   case Formula::Not:
305f757f3fSDimitry Andric     return arena.makeNot(substitute(*F.operands()[0], Substitutions, arena));
315f757f3fSDimitry Andric   case Formula::And:
325f757f3fSDimitry Andric     return arena.makeAnd(substitute(*F.operands()[0], Substitutions, arena),
335f757f3fSDimitry Andric                          substitute(*F.operands()[1], Substitutions, arena));
345f757f3fSDimitry Andric   case Formula::Or:
355f757f3fSDimitry Andric     return arena.makeOr(substitute(*F.operands()[0], Substitutions, arena),
365f757f3fSDimitry Andric                         substitute(*F.operands()[1], Substitutions, arena));
375f757f3fSDimitry Andric   case Formula::Implies:
385f757f3fSDimitry Andric     return arena.makeImplies(
395f757f3fSDimitry Andric         substitute(*F.operands()[0], Substitutions, arena),
405f757f3fSDimitry Andric         substitute(*F.operands()[1], Substitutions, arena));
415f757f3fSDimitry Andric   case Formula::Equal:
425f757f3fSDimitry Andric     return arena.makeEquals(substitute(*F.operands()[0], Substitutions, arena),
435f757f3fSDimitry Andric                             substitute(*F.operands()[1], Substitutions, arena));
445f757f3fSDimitry Andric   }
455f757f3fSDimitry Andric   llvm_unreachable("Unknown formula kind");
465f757f3fSDimitry Andric }
475f757f3fSDimitry Andric 
485f757f3fSDimitry Andric // Returns the result of replacing atoms in `Atoms` with the leader of their
495f757f3fSDimitry Andric // equivalence class in `EquivalentAtoms`.
505f757f3fSDimitry Andric // Atoms that don't have an equivalence class in `EquivalentAtoms` are inserted
515f757f3fSDimitry Andric // into it as single-member equivalence classes.
525f757f3fSDimitry Andric static llvm::DenseSet<Atom>
535f757f3fSDimitry Andric projectToLeaders(const llvm::DenseSet<Atom> &Atoms,
545f757f3fSDimitry Andric                  llvm::EquivalenceClasses<Atom> &EquivalentAtoms) {
555f757f3fSDimitry Andric   llvm::DenseSet<Atom> Result;
565f757f3fSDimitry Andric 
575f757f3fSDimitry Andric   for (Atom Atom : Atoms)
585f757f3fSDimitry Andric     Result.insert(EquivalentAtoms.getOrInsertLeaderValue(Atom));
595f757f3fSDimitry Andric 
605f757f3fSDimitry Andric   return Result;
615f757f3fSDimitry Andric }
625f757f3fSDimitry Andric 
635f757f3fSDimitry Andric // Returns the atoms in the equivalence class for the leader identified by
645f757f3fSDimitry Andric // `LeaderIt`.
655f757f3fSDimitry Andric static llvm::SmallVector<Atom>
665f757f3fSDimitry Andric atomsInEquivalenceClass(const llvm::EquivalenceClasses<Atom> &EquivalentAtoms,
675f757f3fSDimitry Andric                         llvm::EquivalenceClasses<Atom>::iterator LeaderIt) {
685f757f3fSDimitry Andric   llvm::SmallVector<Atom> Result;
695f757f3fSDimitry Andric   for (auto MemberIt = EquivalentAtoms.member_begin(LeaderIt);
705f757f3fSDimitry Andric        MemberIt != EquivalentAtoms.member_end(); ++MemberIt)
715f757f3fSDimitry Andric     Result.push_back(*MemberIt);
725f757f3fSDimitry Andric   return Result;
735f757f3fSDimitry Andric }
745f757f3fSDimitry Andric 
755f757f3fSDimitry Andric void simplifyConstraints(llvm::SetVector<const Formula *> &Constraints,
765f757f3fSDimitry Andric                          Arena &arena, SimplifyConstraintsInfo *Info) {
775f757f3fSDimitry Andric   auto contradiction = [&]() {
785f757f3fSDimitry Andric     Constraints.clear();
795f757f3fSDimitry Andric     Constraints.insert(&arena.makeLiteral(false));
805f757f3fSDimitry Andric   };
815f757f3fSDimitry Andric 
825f757f3fSDimitry Andric   llvm::EquivalenceClasses<Atom> EquivalentAtoms;
835f757f3fSDimitry Andric   llvm::DenseSet<Atom> TrueAtoms;
845f757f3fSDimitry Andric   llvm::DenseSet<Atom> FalseAtoms;
855f757f3fSDimitry Andric 
865f757f3fSDimitry Andric   while (true) {
875f757f3fSDimitry Andric     for (const auto *Constraint : Constraints) {
885f757f3fSDimitry Andric       switch (Constraint->kind()) {
895f757f3fSDimitry Andric       case Formula::AtomRef:
905f757f3fSDimitry Andric         TrueAtoms.insert(Constraint->getAtom());
915f757f3fSDimitry Andric         break;
925f757f3fSDimitry Andric       case Formula::Not:
935f757f3fSDimitry Andric         if (Constraint->operands()[0]->kind() == Formula::AtomRef)
945f757f3fSDimitry Andric           FalseAtoms.insert(Constraint->operands()[0]->getAtom());
955f757f3fSDimitry Andric         break;
965f757f3fSDimitry Andric       case Formula::Equal: {
975f757f3fSDimitry Andric         ArrayRef<const Formula *> operands = Constraint->operands();
985f757f3fSDimitry Andric         if (operands[0]->kind() == Formula::AtomRef &&
995f757f3fSDimitry Andric             operands[1]->kind() == Formula::AtomRef) {
1005f757f3fSDimitry Andric           EquivalentAtoms.unionSets(operands[0]->getAtom(),
1015f757f3fSDimitry Andric                                     operands[1]->getAtom());
1025f757f3fSDimitry Andric         }
1035f757f3fSDimitry Andric         break;
1045f757f3fSDimitry Andric       }
1055f757f3fSDimitry Andric       default:
1065f757f3fSDimitry Andric         break;
1075f757f3fSDimitry Andric       }
1085f757f3fSDimitry Andric     }
1095f757f3fSDimitry Andric 
1105f757f3fSDimitry Andric     TrueAtoms = projectToLeaders(TrueAtoms, EquivalentAtoms);
1115f757f3fSDimitry Andric     FalseAtoms = projectToLeaders(FalseAtoms, EquivalentAtoms);
1125f757f3fSDimitry Andric 
1135f757f3fSDimitry Andric     llvm::DenseMap<Atom, const Formula *> Substitutions;
1145f757f3fSDimitry Andric     for (auto It = EquivalentAtoms.begin(); It != EquivalentAtoms.end(); ++It) {
1155f757f3fSDimitry Andric       Atom TheAtom = It->getData();
1165f757f3fSDimitry Andric       Atom Leader = EquivalentAtoms.getLeaderValue(TheAtom);
1175f757f3fSDimitry Andric       if (TrueAtoms.contains(Leader)) {
1185f757f3fSDimitry Andric         if (FalseAtoms.contains(Leader)) {
1195f757f3fSDimitry Andric           contradiction();
1205f757f3fSDimitry Andric           return;
1215f757f3fSDimitry Andric         }
1225f757f3fSDimitry Andric         Substitutions.insert({TheAtom, &arena.makeLiteral(true)});
1235f757f3fSDimitry Andric       } else if (FalseAtoms.contains(Leader)) {
1245f757f3fSDimitry Andric         Substitutions.insert({TheAtom, &arena.makeLiteral(false)});
1255f757f3fSDimitry Andric       } else if (TheAtom != Leader) {
1265f757f3fSDimitry Andric         Substitutions.insert({TheAtom, &arena.makeAtomRef(Leader)});
1275f757f3fSDimitry Andric       }
1285f757f3fSDimitry Andric     }
1295f757f3fSDimitry Andric 
1305f757f3fSDimitry Andric     llvm::SetVector<const Formula *> NewConstraints;
1315f757f3fSDimitry Andric     for (const auto *Constraint : Constraints) {
1325f757f3fSDimitry Andric       const Formula &NewConstraint =
1335f757f3fSDimitry Andric           substitute(*Constraint, Substitutions, arena);
134*7a6dacacSDimitry Andric       if (NewConstraint.isLiteral(true))
1355f757f3fSDimitry Andric         continue;
136*7a6dacacSDimitry Andric       if (NewConstraint.isLiteral(false)) {
1375f757f3fSDimitry Andric         contradiction();
1385f757f3fSDimitry Andric         return;
1395f757f3fSDimitry Andric       }
1405f757f3fSDimitry Andric       if (NewConstraint.kind() == Formula::And) {
1415f757f3fSDimitry Andric         NewConstraints.insert(NewConstraint.operands()[0]);
1425f757f3fSDimitry Andric         NewConstraints.insert(NewConstraint.operands()[1]);
1435f757f3fSDimitry Andric         continue;
1445f757f3fSDimitry Andric       }
1455f757f3fSDimitry Andric       NewConstraints.insert(&NewConstraint);
1465f757f3fSDimitry Andric     }
1475f757f3fSDimitry Andric 
1485f757f3fSDimitry Andric     if (NewConstraints == Constraints)
1495f757f3fSDimitry Andric       break;
1505f757f3fSDimitry Andric     Constraints = std::move(NewConstraints);
1515f757f3fSDimitry Andric   }
1525f757f3fSDimitry Andric 
1535f757f3fSDimitry Andric   if (Info) {
1545f757f3fSDimitry Andric     for (auto It = EquivalentAtoms.begin(), End = EquivalentAtoms.end();
1555f757f3fSDimitry Andric          It != End; ++It) {
1565f757f3fSDimitry Andric       if (!It->isLeader())
1575f757f3fSDimitry Andric         continue;
1585f757f3fSDimitry Andric       Atom At = *EquivalentAtoms.findLeader(It);
1595f757f3fSDimitry Andric       if (TrueAtoms.contains(At) || FalseAtoms.contains(At))
1605f757f3fSDimitry Andric         continue;
1615f757f3fSDimitry Andric       llvm::SmallVector<Atom> Atoms =
1625f757f3fSDimitry Andric           atomsInEquivalenceClass(EquivalentAtoms, It);
1635f757f3fSDimitry Andric       if (Atoms.size() == 1)
1645f757f3fSDimitry Andric         continue;
1655f757f3fSDimitry Andric       std::sort(Atoms.begin(), Atoms.end());
1665f757f3fSDimitry Andric       Info->EquivalentAtoms.push_back(std::move(Atoms));
1675f757f3fSDimitry Andric     }
1685f757f3fSDimitry Andric     for (Atom At : TrueAtoms)
1695f757f3fSDimitry Andric       Info->TrueAtoms.append(atomsInEquivalenceClass(
1705f757f3fSDimitry Andric           EquivalentAtoms, EquivalentAtoms.findValue(At)));
1715f757f3fSDimitry Andric     std::sort(Info->TrueAtoms.begin(), Info->TrueAtoms.end());
1725f757f3fSDimitry Andric     for (Atom At : FalseAtoms)
1735f757f3fSDimitry Andric       Info->FalseAtoms.append(atomsInEquivalenceClass(
1745f757f3fSDimitry Andric           EquivalentAtoms, EquivalentAtoms.findValue(At)));
1755f757f3fSDimitry Andric     std::sort(Info->FalseAtoms.begin(), Info->FalseAtoms.end());
1765f757f3fSDimitry Andric   }
1775f757f3fSDimitry Andric }
1785f757f3fSDimitry Andric 
1795f757f3fSDimitry Andric } // namespace dataflow
1805f757f3fSDimitry Andric } // namespace clang
181