xref: /freebsd/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/SimplifyConstraints.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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