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