Path: blob/main/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/Arena.cpp
35266 views
//===-- Arena.cpp ---------------------------------------------------------===//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/Arena.h"9#include "clang/Analysis/FlowSensitive/Formula.h"10#include "clang/Analysis/FlowSensitive/Value.h"11#include "llvm/Support/Error.h"12#include <string>1314namespace clang::dataflow {1516static std::pair<const Formula *, const Formula *>17canonicalFormulaPair(const Formula &LHS, const Formula &RHS) {18auto Res = std::make_pair(&LHS, &RHS);19if (&RHS < &LHS) // FIXME: use a deterministic order instead20std::swap(Res.first, Res.second);21return Res;22}2324template <class Key, class ComputeFunc>25const Formula &cached(llvm::DenseMap<Key, const Formula *> &Cache, Key K,26ComputeFunc &&Compute) {27auto [It, Inserted] = Cache.try_emplace(std::forward<Key>(K));28if (Inserted)29It->second = Compute();30return *It->second;31}3233const Formula &Arena::makeAtomRef(Atom A) {34return cached(AtomRefs, A, [&] {35return &Formula::create(Alloc, Formula::AtomRef, {},36static_cast<unsigned>(A));37});38}3940const Formula &Arena::makeAnd(const Formula &LHS, const Formula &RHS) {41return cached(Ands, canonicalFormulaPair(LHS, RHS), [&] {42if (&LHS == &RHS)43return &LHS;44if (LHS.kind() == Formula::Literal)45return LHS.literal() ? &RHS : &LHS;46if (RHS.kind() == Formula::Literal)47return RHS.literal() ? &LHS : &RHS;4849return &Formula::create(Alloc, Formula::And, {&LHS, &RHS});50});51}5253const Formula &Arena::makeOr(const Formula &LHS, const Formula &RHS) {54return cached(Ors, canonicalFormulaPair(LHS, RHS), [&] {55if (&LHS == &RHS)56return &LHS;57if (LHS.kind() == Formula::Literal)58return LHS.literal() ? &LHS : &RHS;59if (RHS.kind() == Formula::Literal)60return RHS.literal() ? &RHS : &LHS;6162return &Formula::create(Alloc, Formula::Or, {&LHS, &RHS});63});64}6566const Formula &Arena::makeNot(const Formula &Val) {67return cached(Nots, &Val, [&] {68if (Val.kind() == Formula::Not)69return Val.operands()[0];70if (Val.kind() == Formula::Literal)71return &makeLiteral(!Val.literal());7273return &Formula::create(Alloc, Formula::Not, {&Val});74});75}7677const Formula &Arena::makeImplies(const Formula &LHS, const Formula &RHS) {78return cached(Implies, std::make_pair(&LHS, &RHS), [&] {79if (&LHS == &RHS)80return &makeLiteral(true);81if (LHS.kind() == Formula::Literal)82return LHS.literal() ? &RHS : &makeLiteral(true);83if (RHS.kind() == Formula::Literal)84return RHS.literal() ? &RHS : &makeNot(LHS);8586return &Formula::create(Alloc, Formula::Implies, {&LHS, &RHS});87});88}8990const Formula &Arena::makeEquals(const Formula &LHS, const Formula &RHS) {91return cached(Equals, canonicalFormulaPair(LHS, RHS), [&] {92if (&LHS == &RHS)93return &makeLiteral(true);94if (LHS.kind() == Formula::Literal)95return LHS.literal() ? &RHS : &makeNot(RHS);96if (RHS.kind() == Formula::Literal)97return RHS.literal() ? &LHS : &makeNot(LHS);9899return &Formula::create(Alloc, Formula::Equal, {&LHS, &RHS});100});101}102103IntegerValue &Arena::makeIntLiteral(llvm::APInt Value) {104auto [It, Inserted] = IntegerLiterals.try_emplace(Value, nullptr);105106if (Inserted)107It->second = &create<IntegerValue>();108return *It->second;109}110111BoolValue &Arena::makeBoolValue(const Formula &F) {112auto [It, Inserted] = FormulaValues.try_emplace(&F);113if (Inserted)114It->second = (F.kind() == Formula::AtomRef)115? (BoolValue *)&create<AtomicBoolValue>(F)116: &create<FormulaBoolValue>(F);117return *It->second;118}119120namespace {121const Formula *parse(Arena &A, llvm::StringRef &In) {122auto EatSpaces = [&] { In = In.ltrim(' '); };123EatSpaces();124125if (In.consume_front("!")) {126if (auto *Arg = parse(A, In))127return &A.makeNot(*Arg);128return nullptr;129}130131if (In.consume_front("(")) {132auto *Arg1 = parse(A, In);133if (!Arg1)134return nullptr;135136EatSpaces();137decltype(&Arena::makeOr) Op;138if (In.consume_front("|"))139Op = &Arena::makeOr;140else if (In.consume_front("&"))141Op = &Arena::makeAnd;142else if (In.consume_front("=>"))143Op = &Arena::makeImplies;144else if (In.consume_front("="))145Op = &Arena::makeEquals;146else147return nullptr;148149auto *Arg2 = parse(A, In);150if (!Arg2)151return nullptr;152153EatSpaces();154if (!In.consume_front(")"))155return nullptr;156157return &(A.*Op)(*Arg1, *Arg2);158}159160// For now, only support unnamed variables V0, V1 etc.161// FIXME: parse e.g. "X" by allocating an atom and storing a name somewhere.162if (In.consume_front("V")) {163std::underlying_type_t<Atom> At;164if (In.consumeInteger(10, At))165return nullptr;166return &A.makeAtomRef(static_cast<Atom>(At));167}168169if (In.consume_front("true"))170return &A.makeLiteral(true);171if (In.consume_front("false"))172return &A.makeLiteral(false);173174return nullptr;175}176177class FormulaParseError : public llvm::ErrorInfo<FormulaParseError> {178std::string Formula;179unsigned Offset;180181public:182static char ID;183FormulaParseError(llvm::StringRef Formula, unsigned Offset)184: Formula(Formula), Offset(Offset) {}185186void log(raw_ostream &OS) const override {187OS << "bad formula at offset " << Offset << "\n";188OS << Formula << "\n";189OS.indent(Offset) << "^";190}191192std::error_code convertToErrorCode() const override {193return std::make_error_code(std::errc::invalid_argument);194}195};196197char FormulaParseError::ID = 0;198199} // namespace200201llvm::Expected<const Formula &> Arena::parseFormula(llvm::StringRef In) {202llvm::StringRef Rest = In;203auto *Result = parse(*this, Rest);204if (!Result) // parse() hit something unparseable205return llvm::make_error<FormulaParseError>(In, In.size() - Rest.size());206Rest = Rest.ltrim();207if (!Rest.empty()) // parse didn't consume all the input208return llvm::make_error<FormulaParseError>(In, In.size() - Rest.size());209return *Result;210}211212} // namespace clang::dataflow213214215