1fe013be4SDimitry Andric //===- Formula.cpp ----------------------------------------------*- C++ -*-===//
2fe013be4SDimitry Andric //
3fe013be4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fe013be4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5fe013be4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fe013be4SDimitry Andric //
7fe013be4SDimitry Andric //===----------------------------------------------------------------------===//
8fe013be4SDimitry Andric
9fe013be4SDimitry Andric #include "clang/Analysis/FlowSensitive/Formula.h"
10fe013be4SDimitry Andric #include "clang/Basic/LLVM.h"
11fe013be4SDimitry Andric #include "llvm/ADT/STLExtras.h"
12fe013be4SDimitry Andric #include "llvm/ADT/StringRef.h"
13fe013be4SDimitry Andric #include "llvm/Support/Allocator.h"
14fe013be4SDimitry Andric #include "llvm/Support/ErrorHandling.h"
15fe013be4SDimitry Andric #include <cassert>
16*c9157d92SDimitry Andric #include <type_traits>
17fe013be4SDimitry Andric
18fe013be4SDimitry Andric namespace clang::dataflow {
19fe013be4SDimitry Andric
create(llvm::BumpPtrAllocator & Alloc,Kind K,ArrayRef<const Formula * > Operands,unsigned Value)20*c9157d92SDimitry Andric const Formula &Formula::create(llvm::BumpPtrAllocator &Alloc, Kind K,
21*c9157d92SDimitry Andric ArrayRef<const Formula *> Operands,
22*c9157d92SDimitry Andric unsigned Value) {
23fe013be4SDimitry Andric assert(Operands.size() == numOperands(K));
24fe013be4SDimitry Andric if (Value != 0) // Currently, formulas have values or operands, not both.
25fe013be4SDimitry Andric assert(numOperands(K) == 0);
26fe013be4SDimitry Andric void *Mem = Alloc.Allocate(sizeof(Formula) +
27fe013be4SDimitry Andric Operands.size() * sizeof(Operands.front()),
28fe013be4SDimitry Andric alignof(Formula));
29fe013be4SDimitry Andric Formula *Result = new (Mem) Formula();
30fe013be4SDimitry Andric Result->FormulaKind = K;
31fe013be4SDimitry Andric Result->Value = Value;
32fe013be4SDimitry Andric // Operands are stored as `const Formula *`s after the formula itself.
33fe013be4SDimitry Andric // We don't need to construct an object as pointers are trivial types.
34fe013be4SDimitry Andric // Formula is alignas(const Formula *), so alignment is satisfied.
35fe013be4SDimitry Andric llvm::copy(Operands, reinterpret_cast<const Formula **>(Result + 1));
36fe013be4SDimitry Andric return *Result;
37fe013be4SDimitry Andric }
38fe013be4SDimitry Andric
sigil(Formula::Kind K)39fe013be4SDimitry Andric static llvm::StringLiteral sigil(Formula::Kind K) {
40fe013be4SDimitry Andric switch (K) {
41fe013be4SDimitry Andric case Formula::AtomRef:
42*c9157d92SDimitry Andric case Formula::Literal:
43fe013be4SDimitry Andric return "";
44fe013be4SDimitry Andric case Formula::Not:
45fe013be4SDimitry Andric return "!";
46fe013be4SDimitry Andric case Formula::And:
47fe013be4SDimitry Andric return " & ";
48fe013be4SDimitry Andric case Formula::Or:
49fe013be4SDimitry Andric return " | ";
50fe013be4SDimitry Andric case Formula::Implies:
51fe013be4SDimitry Andric return " => ";
52fe013be4SDimitry Andric case Formula::Equal:
53fe013be4SDimitry Andric return " = ";
54fe013be4SDimitry Andric }
55fe013be4SDimitry Andric llvm_unreachable("unhandled formula kind");
56fe013be4SDimitry Andric }
57fe013be4SDimitry Andric
print(llvm::raw_ostream & OS,const AtomNames * Names) const58fe013be4SDimitry Andric void Formula::print(llvm::raw_ostream &OS, const AtomNames *Names) const {
59fe013be4SDimitry Andric if (Names && kind() == AtomRef)
60fe013be4SDimitry Andric if (auto It = Names->find(getAtom()); It != Names->end()) {
61fe013be4SDimitry Andric OS << It->second;
62fe013be4SDimitry Andric return;
63fe013be4SDimitry Andric }
64fe013be4SDimitry Andric
65fe013be4SDimitry Andric switch (numOperands(kind())) {
66fe013be4SDimitry Andric case 0:
67*c9157d92SDimitry Andric switch (kind()) {
68*c9157d92SDimitry Andric case AtomRef:
69fe013be4SDimitry Andric OS << getAtom();
70fe013be4SDimitry Andric break;
71*c9157d92SDimitry Andric case Literal:
72*c9157d92SDimitry Andric OS << (literal() ? "true" : "false");
73*c9157d92SDimitry Andric break;
74*c9157d92SDimitry Andric default:
75*c9157d92SDimitry Andric llvm_unreachable("unhandled formula kind");
76*c9157d92SDimitry Andric }
77*c9157d92SDimitry Andric break;
78fe013be4SDimitry Andric case 1:
79fe013be4SDimitry Andric OS << sigil(kind());
80fe013be4SDimitry Andric operands()[0]->print(OS, Names);
81fe013be4SDimitry Andric break;
82fe013be4SDimitry Andric case 2:
83fe013be4SDimitry Andric OS << '(';
84fe013be4SDimitry Andric operands()[0]->print(OS, Names);
85fe013be4SDimitry Andric OS << sigil(kind());
86fe013be4SDimitry Andric operands()[1]->print(OS, Names);
87fe013be4SDimitry Andric OS << ')';
88fe013be4SDimitry Andric break;
89fe013be4SDimitry Andric default:
90fe013be4SDimitry Andric llvm_unreachable("unhandled formula arity");
91fe013be4SDimitry Andric }
92fe013be4SDimitry Andric }
93fe013be4SDimitry Andric
94fe013be4SDimitry Andric } // namespace clang::dataflow