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