106c3fb27SDimitry Andric //===-- Arena.cpp ---------------------------------------------------------===// 206c3fb27SDimitry Andric // 306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 606c3fb27SDimitry Andric // 706c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 806c3fb27SDimitry Andric 906c3fb27SDimitry Andric #include "clang/Analysis/FlowSensitive/Arena.h" 10*5f757f3fSDimitry Andric #include "clang/Analysis/FlowSensitive/Formula.h" 1106c3fb27SDimitry Andric #include "clang/Analysis/FlowSensitive/Value.h" 12*5f757f3fSDimitry Andric #include "llvm/Support/Error.h" 13*5f757f3fSDimitry Andric #include <string> 1406c3fb27SDimitry Andric 1506c3fb27SDimitry Andric namespace clang::dataflow { 1606c3fb27SDimitry Andric 1706c3fb27SDimitry Andric static std::pair<const Formula *, const Formula *> 1806c3fb27SDimitry Andric canonicalFormulaPair(const Formula &LHS, const Formula &RHS) { 1906c3fb27SDimitry Andric auto Res = std::make_pair(&LHS, &RHS); 2006c3fb27SDimitry Andric if (&RHS < &LHS) // FIXME: use a deterministic order instead 2106c3fb27SDimitry Andric std::swap(Res.first, Res.second); 2206c3fb27SDimitry Andric return Res; 2306c3fb27SDimitry Andric } 2406c3fb27SDimitry Andric 25*5f757f3fSDimitry Andric template <class Key, class ComputeFunc> 26*5f757f3fSDimitry Andric const Formula &cached(llvm::DenseMap<Key, const Formula *> &Cache, Key K, 27*5f757f3fSDimitry Andric ComputeFunc &&Compute) { 28*5f757f3fSDimitry Andric auto [It, Inserted] = Cache.try_emplace(std::forward<Key>(K)); 2906c3fb27SDimitry Andric if (Inserted) 30*5f757f3fSDimitry Andric It->second = Compute(); 3106c3fb27SDimitry Andric return *It->second; 3206c3fb27SDimitry Andric } 3306c3fb27SDimitry Andric 34*5f757f3fSDimitry Andric const Formula &Arena::makeAtomRef(Atom A) { 35*5f757f3fSDimitry Andric return cached(AtomRefs, A, [&] { 36*5f757f3fSDimitry Andric return &Formula::create(Alloc, Formula::AtomRef, {}, 37*5f757f3fSDimitry Andric static_cast<unsigned>(A)); 38*5f757f3fSDimitry Andric }); 39*5f757f3fSDimitry Andric } 40*5f757f3fSDimitry Andric 4106c3fb27SDimitry Andric const Formula &Arena::makeAnd(const Formula &LHS, const Formula &RHS) { 42*5f757f3fSDimitry Andric return cached(Ands, canonicalFormulaPair(LHS, RHS), [&] { 4306c3fb27SDimitry Andric if (&LHS == &RHS) 44*5f757f3fSDimitry Andric return &LHS; 45*5f757f3fSDimitry Andric if (LHS.kind() == Formula::Literal) 46*5f757f3fSDimitry Andric return LHS.literal() ? &RHS : &LHS; 47*5f757f3fSDimitry Andric if (RHS.kind() == Formula::Literal) 48*5f757f3fSDimitry Andric return RHS.literal() ? &LHS : &RHS; 4906c3fb27SDimitry Andric 50*5f757f3fSDimitry Andric return &Formula::create(Alloc, Formula::And, {&LHS, &RHS}); 51*5f757f3fSDimitry Andric }); 5206c3fb27SDimitry Andric } 5306c3fb27SDimitry Andric 5406c3fb27SDimitry Andric const Formula &Arena::makeOr(const Formula &LHS, const Formula &RHS) { 55*5f757f3fSDimitry Andric return cached(Ors, canonicalFormulaPair(LHS, RHS), [&] { 5606c3fb27SDimitry Andric if (&LHS == &RHS) 57*5f757f3fSDimitry Andric return &LHS; 58*5f757f3fSDimitry Andric if (LHS.kind() == Formula::Literal) 59*5f757f3fSDimitry Andric return LHS.literal() ? &LHS : &RHS; 60*5f757f3fSDimitry Andric if (RHS.kind() == Formula::Literal) 61*5f757f3fSDimitry Andric return RHS.literal() ? &RHS : &LHS; 6206c3fb27SDimitry Andric 63*5f757f3fSDimitry Andric return &Formula::create(Alloc, Formula::Or, {&LHS, &RHS}); 64*5f757f3fSDimitry Andric }); 6506c3fb27SDimitry Andric } 6606c3fb27SDimitry Andric 6706c3fb27SDimitry Andric const Formula &Arena::makeNot(const Formula &Val) { 68*5f757f3fSDimitry Andric return cached(Nots, &Val, [&] { 69*5f757f3fSDimitry Andric if (Val.kind() == Formula::Not) 70*5f757f3fSDimitry Andric return Val.operands()[0]; 71*5f757f3fSDimitry Andric if (Val.kind() == Formula::Literal) 72*5f757f3fSDimitry Andric return &makeLiteral(!Val.literal()); 73*5f757f3fSDimitry Andric 74*5f757f3fSDimitry Andric return &Formula::create(Alloc, Formula::Not, {&Val}); 75*5f757f3fSDimitry Andric }); 7606c3fb27SDimitry Andric } 7706c3fb27SDimitry Andric 7806c3fb27SDimitry Andric const Formula &Arena::makeImplies(const Formula &LHS, const Formula &RHS) { 79*5f757f3fSDimitry Andric return cached(Implies, std::make_pair(&LHS, &RHS), [&] { 8006c3fb27SDimitry Andric if (&LHS == &RHS) 81*5f757f3fSDimitry Andric return &makeLiteral(true); 82*5f757f3fSDimitry Andric if (LHS.kind() == Formula::Literal) 83*5f757f3fSDimitry Andric return LHS.literal() ? &RHS : &makeLiteral(true); 84*5f757f3fSDimitry Andric if (RHS.kind() == Formula::Literal) 85*5f757f3fSDimitry Andric return RHS.literal() ? &RHS : &makeNot(LHS); 8606c3fb27SDimitry Andric 87*5f757f3fSDimitry Andric return &Formula::create(Alloc, Formula::Implies, {&LHS, &RHS}); 88*5f757f3fSDimitry Andric }); 8906c3fb27SDimitry Andric } 9006c3fb27SDimitry Andric 9106c3fb27SDimitry Andric const Formula &Arena::makeEquals(const Formula &LHS, const Formula &RHS) { 92*5f757f3fSDimitry Andric return cached(Equals, canonicalFormulaPair(LHS, RHS), [&] { 9306c3fb27SDimitry Andric if (&LHS == &RHS) 94*5f757f3fSDimitry Andric return &makeLiteral(true); 95*5f757f3fSDimitry Andric if (LHS.kind() == Formula::Literal) 96*5f757f3fSDimitry Andric return LHS.literal() ? &RHS : &makeNot(RHS); 97*5f757f3fSDimitry Andric if (RHS.kind() == Formula::Literal) 98*5f757f3fSDimitry Andric return RHS.literal() ? &LHS : &makeNot(LHS); 9906c3fb27SDimitry Andric 100*5f757f3fSDimitry Andric return &Formula::create(Alloc, Formula::Equal, {&LHS, &RHS}); 101*5f757f3fSDimitry Andric }); 10206c3fb27SDimitry Andric } 10306c3fb27SDimitry Andric 10406c3fb27SDimitry Andric IntegerValue &Arena::makeIntLiteral(llvm::APInt Value) { 10506c3fb27SDimitry Andric auto [It, Inserted] = IntegerLiterals.try_emplace(Value, nullptr); 10606c3fb27SDimitry Andric 10706c3fb27SDimitry Andric if (Inserted) 10806c3fb27SDimitry Andric It->second = &create<IntegerValue>(); 10906c3fb27SDimitry Andric return *It->second; 11006c3fb27SDimitry Andric } 11106c3fb27SDimitry Andric 11206c3fb27SDimitry Andric BoolValue &Arena::makeBoolValue(const Formula &F) { 11306c3fb27SDimitry Andric auto [It, Inserted] = FormulaValues.try_emplace(&F); 11406c3fb27SDimitry Andric if (Inserted) 11506c3fb27SDimitry Andric It->second = (F.kind() == Formula::AtomRef) 11606c3fb27SDimitry Andric ? (BoolValue *)&create<AtomicBoolValue>(F) 11706c3fb27SDimitry Andric : &create<FormulaBoolValue>(F); 11806c3fb27SDimitry Andric return *It->second; 11906c3fb27SDimitry Andric } 12006c3fb27SDimitry Andric 121*5f757f3fSDimitry Andric namespace { 122*5f757f3fSDimitry Andric const Formula *parse(Arena &A, llvm::StringRef &In) { 123*5f757f3fSDimitry Andric auto EatSpaces = [&] { In = In.ltrim(' '); }; 124*5f757f3fSDimitry Andric EatSpaces(); 125*5f757f3fSDimitry Andric 126*5f757f3fSDimitry Andric if (In.consume_front("!")) { 127*5f757f3fSDimitry Andric if (auto *Arg = parse(A, In)) 128*5f757f3fSDimitry Andric return &A.makeNot(*Arg); 129*5f757f3fSDimitry Andric return nullptr; 130*5f757f3fSDimitry Andric } 131*5f757f3fSDimitry Andric 132*5f757f3fSDimitry Andric if (In.consume_front("(")) { 133*5f757f3fSDimitry Andric auto *Arg1 = parse(A, In); 134*5f757f3fSDimitry Andric if (!Arg1) 135*5f757f3fSDimitry Andric return nullptr; 136*5f757f3fSDimitry Andric 137*5f757f3fSDimitry Andric EatSpaces(); 138*5f757f3fSDimitry Andric decltype(&Arena::makeOr) Op; 139*5f757f3fSDimitry Andric if (In.consume_front("|")) 140*5f757f3fSDimitry Andric Op = &Arena::makeOr; 141*5f757f3fSDimitry Andric else if (In.consume_front("&")) 142*5f757f3fSDimitry Andric Op = &Arena::makeAnd; 143*5f757f3fSDimitry Andric else if (In.consume_front("=>")) 144*5f757f3fSDimitry Andric Op = &Arena::makeImplies; 145*5f757f3fSDimitry Andric else if (In.consume_front("=")) 146*5f757f3fSDimitry Andric Op = &Arena::makeEquals; 147*5f757f3fSDimitry Andric else 148*5f757f3fSDimitry Andric return nullptr; 149*5f757f3fSDimitry Andric 150*5f757f3fSDimitry Andric auto *Arg2 = parse(A, In); 151*5f757f3fSDimitry Andric if (!Arg2) 152*5f757f3fSDimitry Andric return nullptr; 153*5f757f3fSDimitry Andric 154*5f757f3fSDimitry Andric EatSpaces(); 155*5f757f3fSDimitry Andric if (!In.consume_front(")")) 156*5f757f3fSDimitry Andric return nullptr; 157*5f757f3fSDimitry Andric 158*5f757f3fSDimitry Andric return &(A.*Op)(*Arg1, *Arg2); 159*5f757f3fSDimitry Andric } 160*5f757f3fSDimitry Andric 161*5f757f3fSDimitry Andric // For now, only support unnamed variables V0, V1 etc. 162*5f757f3fSDimitry Andric // FIXME: parse e.g. "X" by allocating an atom and storing a name somewhere. 163*5f757f3fSDimitry Andric if (In.consume_front("V")) { 164*5f757f3fSDimitry Andric std::underlying_type_t<Atom> At; 165*5f757f3fSDimitry Andric if (In.consumeInteger(10, At)) 166*5f757f3fSDimitry Andric return nullptr; 167*5f757f3fSDimitry Andric return &A.makeAtomRef(static_cast<Atom>(At)); 168*5f757f3fSDimitry Andric } 169*5f757f3fSDimitry Andric 170*5f757f3fSDimitry Andric if (In.consume_front("true")) 171*5f757f3fSDimitry Andric return &A.makeLiteral(true); 172*5f757f3fSDimitry Andric if (In.consume_front("false")) 173*5f757f3fSDimitry Andric return &A.makeLiteral(false); 174*5f757f3fSDimitry Andric 175*5f757f3fSDimitry Andric return nullptr; 176*5f757f3fSDimitry Andric } 177*5f757f3fSDimitry Andric 178*5f757f3fSDimitry Andric class FormulaParseError : public llvm::ErrorInfo<FormulaParseError> { 179*5f757f3fSDimitry Andric std::string Formula; 180*5f757f3fSDimitry Andric unsigned Offset; 181*5f757f3fSDimitry Andric 182*5f757f3fSDimitry Andric public: 183*5f757f3fSDimitry Andric static char ID; 184*5f757f3fSDimitry Andric FormulaParseError(llvm::StringRef Formula, unsigned Offset) 185*5f757f3fSDimitry Andric : Formula(Formula), Offset(Offset) {} 186*5f757f3fSDimitry Andric 187*5f757f3fSDimitry Andric void log(raw_ostream &OS) const override { 188*5f757f3fSDimitry Andric OS << "bad formula at offset " << Offset << "\n"; 189*5f757f3fSDimitry Andric OS << Formula << "\n"; 190*5f757f3fSDimitry Andric OS.indent(Offset) << "^"; 191*5f757f3fSDimitry Andric } 192*5f757f3fSDimitry Andric 193*5f757f3fSDimitry Andric std::error_code convertToErrorCode() const override { 194*5f757f3fSDimitry Andric return std::make_error_code(std::errc::invalid_argument); 195*5f757f3fSDimitry Andric } 196*5f757f3fSDimitry Andric }; 197*5f757f3fSDimitry Andric 198*5f757f3fSDimitry Andric char FormulaParseError::ID = 0; 199*5f757f3fSDimitry Andric 200*5f757f3fSDimitry Andric } // namespace 201*5f757f3fSDimitry Andric 202*5f757f3fSDimitry Andric llvm::Expected<const Formula &> Arena::parseFormula(llvm::StringRef In) { 203*5f757f3fSDimitry Andric llvm::StringRef Rest = In; 204*5f757f3fSDimitry Andric auto *Result = parse(*this, Rest); 205*5f757f3fSDimitry Andric if (!Result) // parse() hit something unparseable 206*5f757f3fSDimitry Andric return llvm::make_error<FormulaParseError>(In, In.size() - Rest.size()); 207*5f757f3fSDimitry Andric Rest = Rest.ltrim(); 208*5f757f3fSDimitry Andric if (!Rest.empty()) // parse didn't consume all the input 209*5f757f3fSDimitry Andric return llvm::make_error<FormulaParseError>(In, In.size() - Rest.size()); 210*5f757f3fSDimitry Andric return *Result; 211*5f757f3fSDimitry Andric } 212*5f757f3fSDimitry Andric 21306c3fb27SDimitry Andric } // namespace clang::dataflow 214