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