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 &
substitute(const Formula & F,const llvm::DenseMap<Atom,const Formula * > & Substitutions,Arena & arena)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>
projectToLeaders(const llvm::DenseSet<Atom> & Atoms,llvm::EquivalenceClasses<Atom> & EquivalentAtoms)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>
atomsInEquivalenceClass(const llvm::EquivalenceClasses<Atom> & EquivalentAtoms,llvm::EquivalenceClasses<Atom>::iterator LeaderIt)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
simplifyConstraints(llvm::SetVector<const Formula * > & Constraints,Arena & arena,SimplifyConstraintsInfo * Info)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