1*5f757f3fSDimitry Andric //===-- SimplifyConstraints.cpp ---------------------------------*- C++ -*-===// 2*5f757f3fSDimitry Andric // 3*5f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*5f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*5f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*5f757f3fSDimitry Andric // 7*5f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 8*5f757f3fSDimitry Andric 9*5f757f3fSDimitry Andric #include "clang/Analysis/FlowSensitive/SimplifyConstraints.h" 10*5f757f3fSDimitry Andric #include "llvm/ADT/EquivalenceClasses.h" 11*5f757f3fSDimitry Andric 12*5f757f3fSDimitry Andric namespace clang { 13*5f757f3fSDimitry Andric namespace dataflow { 14*5f757f3fSDimitry Andric 15*5f757f3fSDimitry Andric // Substitutes all occurrences of a given atom in `F` by a given formula and 16*5f757f3fSDimitry Andric // returns the resulting formula. 17*5f757f3fSDimitry Andric static const Formula & 18*5f757f3fSDimitry Andric substitute(const Formula &F, 19*5f757f3fSDimitry Andric const llvm::DenseMap<Atom, const Formula *> &Substitutions, 20*5f757f3fSDimitry Andric Arena &arena) { 21*5f757f3fSDimitry Andric switch (F.kind()) { 22*5f757f3fSDimitry Andric case Formula::AtomRef: 23*5f757f3fSDimitry Andric if (auto iter = Substitutions.find(F.getAtom()); 24*5f757f3fSDimitry Andric iter != Substitutions.end()) 25*5f757f3fSDimitry Andric return *iter->second; 26*5f757f3fSDimitry Andric return F; 27*5f757f3fSDimitry Andric case Formula::Literal: 28*5f757f3fSDimitry Andric return F; 29*5f757f3fSDimitry Andric case Formula::Not: 30*5f757f3fSDimitry Andric return arena.makeNot(substitute(*F.operands()[0], Substitutions, arena)); 31*5f757f3fSDimitry Andric case Formula::And: 32*5f757f3fSDimitry Andric return arena.makeAnd(substitute(*F.operands()[0], Substitutions, arena), 33*5f757f3fSDimitry Andric substitute(*F.operands()[1], Substitutions, arena)); 34*5f757f3fSDimitry Andric case Formula::Or: 35*5f757f3fSDimitry Andric return arena.makeOr(substitute(*F.operands()[0], Substitutions, arena), 36*5f757f3fSDimitry Andric substitute(*F.operands()[1], Substitutions, arena)); 37*5f757f3fSDimitry Andric case Formula::Implies: 38*5f757f3fSDimitry Andric return arena.makeImplies( 39*5f757f3fSDimitry Andric substitute(*F.operands()[0], Substitutions, arena), 40*5f757f3fSDimitry Andric substitute(*F.operands()[1], Substitutions, arena)); 41*5f757f3fSDimitry Andric case Formula::Equal: 42*5f757f3fSDimitry Andric return arena.makeEquals(substitute(*F.operands()[0], Substitutions, arena), 43*5f757f3fSDimitry Andric substitute(*F.operands()[1], Substitutions, arena)); 44*5f757f3fSDimitry Andric } 45*5f757f3fSDimitry Andric llvm_unreachable("Unknown formula kind"); 46*5f757f3fSDimitry Andric } 47*5f757f3fSDimitry Andric 48*5f757f3fSDimitry Andric // Returns the result of replacing atoms in `Atoms` with the leader of their 49*5f757f3fSDimitry Andric // equivalence class in `EquivalentAtoms`. 50*5f757f3fSDimitry Andric // Atoms that don't have an equivalence class in `EquivalentAtoms` are inserted 51*5f757f3fSDimitry Andric // into it as single-member equivalence classes. 52*5f757f3fSDimitry Andric static llvm::DenseSet<Atom> 53*5f757f3fSDimitry Andric projectToLeaders(const llvm::DenseSet<Atom> &Atoms, 54*5f757f3fSDimitry Andric llvm::EquivalenceClasses<Atom> &EquivalentAtoms) { 55*5f757f3fSDimitry Andric llvm::DenseSet<Atom> Result; 56*5f757f3fSDimitry Andric 57*5f757f3fSDimitry Andric for (Atom Atom : Atoms) 58*5f757f3fSDimitry Andric Result.insert(EquivalentAtoms.getOrInsertLeaderValue(Atom)); 59*5f757f3fSDimitry Andric 60*5f757f3fSDimitry Andric return Result; 61*5f757f3fSDimitry Andric } 62*5f757f3fSDimitry Andric 63*5f757f3fSDimitry Andric // Returns the atoms in the equivalence class for the leader identified by 64*5f757f3fSDimitry Andric // `LeaderIt`. 65*5f757f3fSDimitry Andric static llvm::SmallVector<Atom> 66*5f757f3fSDimitry Andric atomsInEquivalenceClass(const llvm::EquivalenceClasses<Atom> &EquivalentAtoms, 67*5f757f3fSDimitry Andric llvm::EquivalenceClasses<Atom>::iterator LeaderIt) { 68*5f757f3fSDimitry Andric llvm::SmallVector<Atom> Result; 69*5f757f3fSDimitry Andric for (auto MemberIt = EquivalentAtoms.member_begin(LeaderIt); 70*5f757f3fSDimitry Andric MemberIt != EquivalentAtoms.member_end(); ++MemberIt) 71*5f757f3fSDimitry Andric Result.push_back(*MemberIt); 72*5f757f3fSDimitry Andric return Result; 73*5f757f3fSDimitry Andric } 74*5f757f3fSDimitry Andric 75*5f757f3fSDimitry Andric void simplifyConstraints(llvm::SetVector<const Formula *> &Constraints, 76*5f757f3fSDimitry Andric Arena &arena, SimplifyConstraintsInfo *Info) { 77*5f757f3fSDimitry Andric auto contradiction = [&]() { 78*5f757f3fSDimitry Andric Constraints.clear(); 79*5f757f3fSDimitry Andric Constraints.insert(&arena.makeLiteral(false)); 80*5f757f3fSDimitry Andric }; 81*5f757f3fSDimitry Andric 82*5f757f3fSDimitry Andric llvm::EquivalenceClasses<Atom> EquivalentAtoms; 83*5f757f3fSDimitry Andric llvm::DenseSet<Atom> TrueAtoms; 84*5f757f3fSDimitry Andric llvm::DenseSet<Atom> FalseAtoms; 85*5f757f3fSDimitry Andric 86*5f757f3fSDimitry Andric while (true) { 87*5f757f3fSDimitry Andric for (const auto *Constraint : Constraints) { 88*5f757f3fSDimitry Andric switch (Constraint->kind()) { 89*5f757f3fSDimitry Andric case Formula::AtomRef: 90*5f757f3fSDimitry Andric TrueAtoms.insert(Constraint->getAtom()); 91*5f757f3fSDimitry Andric break; 92*5f757f3fSDimitry Andric case Formula::Not: 93*5f757f3fSDimitry Andric if (Constraint->operands()[0]->kind() == Formula::AtomRef) 94*5f757f3fSDimitry Andric FalseAtoms.insert(Constraint->operands()[0]->getAtom()); 95*5f757f3fSDimitry Andric break; 96*5f757f3fSDimitry Andric case Formula::Equal: { 97*5f757f3fSDimitry Andric ArrayRef<const Formula *> operands = Constraint->operands(); 98*5f757f3fSDimitry Andric if (operands[0]->kind() == Formula::AtomRef && 99*5f757f3fSDimitry Andric operands[1]->kind() == Formula::AtomRef) { 100*5f757f3fSDimitry Andric EquivalentAtoms.unionSets(operands[0]->getAtom(), 101*5f757f3fSDimitry Andric operands[1]->getAtom()); 102*5f757f3fSDimitry Andric } 103*5f757f3fSDimitry Andric break; 104*5f757f3fSDimitry Andric } 105*5f757f3fSDimitry Andric default: 106*5f757f3fSDimitry Andric break; 107*5f757f3fSDimitry Andric } 108*5f757f3fSDimitry Andric } 109*5f757f3fSDimitry Andric 110*5f757f3fSDimitry Andric TrueAtoms = projectToLeaders(TrueAtoms, EquivalentAtoms); 111*5f757f3fSDimitry Andric FalseAtoms = projectToLeaders(FalseAtoms, EquivalentAtoms); 112*5f757f3fSDimitry Andric 113*5f757f3fSDimitry Andric llvm::DenseMap<Atom, const Formula *> Substitutions; 114*5f757f3fSDimitry Andric for (auto It = EquivalentAtoms.begin(); It != EquivalentAtoms.end(); ++It) { 115*5f757f3fSDimitry Andric Atom TheAtom = It->getData(); 116*5f757f3fSDimitry Andric Atom Leader = EquivalentAtoms.getLeaderValue(TheAtom); 117*5f757f3fSDimitry Andric if (TrueAtoms.contains(Leader)) { 118*5f757f3fSDimitry Andric if (FalseAtoms.contains(Leader)) { 119*5f757f3fSDimitry Andric contradiction(); 120*5f757f3fSDimitry Andric return; 121*5f757f3fSDimitry Andric } 122*5f757f3fSDimitry Andric Substitutions.insert({TheAtom, &arena.makeLiteral(true)}); 123*5f757f3fSDimitry Andric } else if (FalseAtoms.contains(Leader)) { 124*5f757f3fSDimitry Andric Substitutions.insert({TheAtom, &arena.makeLiteral(false)}); 125*5f757f3fSDimitry Andric } else if (TheAtom != Leader) { 126*5f757f3fSDimitry Andric Substitutions.insert({TheAtom, &arena.makeAtomRef(Leader)}); 127*5f757f3fSDimitry Andric } 128*5f757f3fSDimitry Andric } 129*5f757f3fSDimitry Andric 130*5f757f3fSDimitry Andric llvm::SetVector<const Formula *> NewConstraints; 131*5f757f3fSDimitry Andric for (const auto *Constraint : Constraints) { 132*5f757f3fSDimitry Andric const Formula &NewConstraint = 133*5f757f3fSDimitry Andric substitute(*Constraint, Substitutions, arena); 134*5f757f3fSDimitry Andric if (&NewConstraint == &arena.makeLiteral(true)) 135*5f757f3fSDimitry Andric continue; 136*5f757f3fSDimitry Andric if (&NewConstraint == &arena.makeLiteral(false)) { 137*5f757f3fSDimitry Andric contradiction(); 138*5f757f3fSDimitry Andric return; 139*5f757f3fSDimitry Andric } 140*5f757f3fSDimitry Andric if (NewConstraint.kind() == Formula::And) { 141*5f757f3fSDimitry Andric NewConstraints.insert(NewConstraint.operands()[0]); 142*5f757f3fSDimitry Andric NewConstraints.insert(NewConstraint.operands()[1]); 143*5f757f3fSDimitry Andric continue; 144*5f757f3fSDimitry Andric } 145*5f757f3fSDimitry Andric NewConstraints.insert(&NewConstraint); 146*5f757f3fSDimitry Andric } 147*5f757f3fSDimitry Andric 148*5f757f3fSDimitry Andric if (NewConstraints == Constraints) 149*5f757f3fSDimitry Andric break; 150*5f757f3fSDimitry Andric Constraints = std::move(NewConstraints); 151*5f757f3fSDimitry Andric } 152*5f757f3fSDimitry Andric 153*5f757f3fSDimitry Andric if (Info) { 154*5f757f3fSDimitry Andric for (auto It = EquivalentAtoms.begin(), End = EquivalentAtoms.end(); 155*5f757f3fSDimitry Andric It != End; ++It) { 156*5f757f3fSDimitry Andric if (!It->isLeader()) 157*5f757f3fSDimitry Andric continue; 158*5f757f3fSDimitry Andric Atom At = *EquivalentAtoms.findLeader(It); 159*5f757f3fSDimitry Andric if (TrueAtoms.contains(At) || FalseAtoms.contains(At)) 160*5f757f3fSDimitry Andric continue; 161*5f757f3fSDimitry Andric llvm::SmallVector<Atom> Atoms = 162*5f757f3fSDimitry Andric atomsInEquivalenceClass(EquivalentAtoms, It); 163*5f757f3fSDimitry Andric if (Atoms.size() == 1) 164*5f757f3fSDimitry Andric continue; 165*5f757f3fSDimitry Andric std::sort(Atoms.begin(), Atoms.end()); 166*5f757f3fSDimitry Andric Info->EquivalentAtoms.push_back(std::move(Atoms)); 167*5f757f3fSDimitry Andric } 168*5f757f3fSDimitry Andric for (Atom At : TrueAtoms) 169*5f757f3fSDimitry Andric Info->TrueAtoms.append(atomsInEquivalenceClass( 170*5f757f3fSDimitry Andric EquivalentAtoms, EquivalentAtoms.findValue(At))); 171*5f757f3fSDimitry Andric std::sort(Info->TrueAtoms.begin(), Info->TrueAtoms.end()); 172*5f757f3fSDimitry Andric for (Atom At : FalseAtoms) 173*5f757f3fSDimitry Andric Info->FalseAtoms.append(atomsInEquivalenceClass( 174*5f757f3fSDimitry Andric EquivalentAtoms, EquivalentAtoms.findValue(At))); 175*5f757f3fSDimitry Andric std::sort(Info->FalseAtoms.begin(), Info->FalseAtoms.end()); 176*5f757f3fSDimitry Andric } 177*5f757f3fSDimitry Andric } 178*5f757f3fSDimitry Andric 179*5f757f3fSDimitry Andric } // namespace dataflow 180*5f757f3fSDimitry Andric } // namespace clang 181