souffle  2.0.2-371-g6315b36
ChoiceConversion.cpp
Go to the documentation of this file.
1 /*
2  * Souffle - A Datalog Compiler
3  * Copyright (c) 2018, The Souffle Developers. All rights reserved
4  * Licensed under the Universal Permissive License v 1.0 as shown at:
5  * - https://opensource.org/licenses/UPL
6  * - <souffle root>/licenses/SOUFFLE-UPL.txt
7  */
8 
9 /************************************************************************
10  *
11  * @file ChoiceConversion.cpp
12  *
13  ***********************************************************************/
14 
16 #include "ram/Condition.h"
17 #include "ram/Expression.h"
18 #include "ram/Node.h"
19 #include "ram/Operation.h"
20 #include "ram/Program.h"
21 #include "ram/Relation.h"
22 #include "ram/Statement.h"
23 #include "ram/utility/Visitor.h"
25 #include <algorithm>
26 #include <functional>
27 #include <utility>
28 #include <vector>
29 
31 
33  bool transformTuple = false;
34 
35  // Check that Filter follows the Scan in the loop nest
36  if (const auto* filter = dynamic_cast<const Filter*>(&scan->getOperation())) {
37  // Check that the Filter uses the identifier in the Scan
38  if (rla->getLevel(&filter->getCondition()) == scan->getTupleId()) {
39  transformTuple = true;
40 
41  // Check that the filter is not referred to after
42  const auto* nextNode = dynamic_cast<const Node*>(&filter->getOperation());
43 
44  visitDepthFirst(*nextNode, [&](const TupleElement& element) {
45  if (element.getTupleId() == scan->getTupleId()) {
46  transformTuple = false;
47  }
48  });
49  }
50  }
51 
52  // Convert the Scan/If pair into a Choice
53  if (transformTuple) {
54  VecOwn<Expression> newValues;
55  const auto* filter = dynamic_cast<const Filter*>(&scan->getOperation());
56  const int identifier = scan->getTupleId();
57 
58  return mk<Choice>(scan->getRelation(), identifier, souffle::clone(&filter->getCondition()),
59  souffle::clone(&filter->getOperation()), scan->getProfileText());
60  }
61  return nullptr;
62 }
63 
65  bool transformTuple = false;
66 
67  // Check that Filter follows the IndexScan in the loop nest
68  if (const auto* filter = dynamic_cast<const Filter*>(&indexScan->getOperation())) {
69  // Check that the Filter uses the identifier in the IndexScan
70  if (rla->getLevel(&filter->getCondition()) == indexScan->getTupleId()) {
71  transformTuple = true;
72 
73  // Check that the filter is not referred to after
74  const auto* nextNode = dynamic_cast<const Node*>(&filter->getOperation());
75 
76  visitDepthFirst(*nextNode, [&](const TupleElement& element) {
77  if (element.getTupleId() == indexScan->getTupleId()) {
78  transformTuple = false;
79  }
80  });
81  }
82  }
83 
84  // Convert the IndexScan/If pair into an IndexChoice
85  if (transformTuple) {
86  RamPattern newValues;
87  const auto* filter = dynamic_cast<const Filter*>(&indexScan->getOperation());
88  const int identifier = indexScan->getTupleId();
89  const std::string& rel = indexScan->getRelation();
90 
91  for (auto& cur : indexScan->getRangePattern().first) {
92  Expression* val = nullptr;
93  if (cur != nullptr) {
94  val = cur->clone();
95  }
96  newValues.first.emplace_back(val);
97  }
98  for (auto& cur : indexScan->getRangePattern().second) {
99  Expression* val = nullptr;
100  if (cur != nullptr) {
101  val = cur->clone();
102  }
103  newValues.second.emplace_back(val);
104  }
105 
106  return mk<IndexChoice>(rel, identifier, souffle::clone(&filter->getCondition()), std::move(newValues),
107  souffle::clone(&filter->getOperation()), indexScan->getProfileText());
108  }
109  return nullptr;
110 }
111 
112 bool ChoiceConversionTransformer::convertScans(Program& program) {
113  bool changed = false;
114  visitDepthFirst(program, [&](const Query& query) {
115  std::function<Own<Node>(Own<Node>)> scanRewriter = [&](Own<Node> node) -> Own<Node> {
116  if (const Scan* scan = dynamic_cast<Scan*>(node.get())) {
117  if (Own<Operation> op = rewriteScan(scan)) {
118  changed = true;
119  node = std::move(op);
120  }
121  } else if (const IndexScan* indexScan = dynamic_cast<IndexScan*>(node.get())) {
122  if (Own<Operation> op = rewriteIndexScan(indexScan)) {
123  changed = true;
124  node = std::move(op);
125  }
126  }
127  node->apply(makeLambdaRamMapper(scanRewriter));
128 
129  return node;
130  };
131  const_cast<Query*>(&query)->apply(makeLambdaRamMapper(scanRewriter));
132  });
133 
134  return changed;
135 }
136 
137 } // namespace souffle::ram::transform
souffle::ram::transform
Definition: ChoiceConversion.cpp:30
souffle::ram::analysis::LevelAnalysis::getLevel
int getLevel(const Node *value) const
Get level of a RAM expression/condition.
Definition: Level.cpp:64
ChoiceConversion.h
souffle::ram::transform::Transformer::apply
bool apply(TranslationUnit &translationUnit)
@Brief apply the transformer to a translation unit @Param translationUnit that will be transformed.
Definition: Transformer.cpp:39
souffle::ram::NestedOperation::getOperation
Operation & getOperation() const
Get nested operation.
Definition: NestedOperation.h:62
souffle::Own
std::unique_ptr< A > Own
Definition: ContainerUtil.h:42
MiscUtil.h
souffle::identifier
std::string identifier(std::string id)
Valid C++ identifier, note that this does not ensure the uniqueness of identifiers returned.
Definition: StringUtil.h:387
souffle::ram::RelationOperation::getRelation
const std::string & getRelation() const
Get search relation.
Definition: RelationOperation.h:49
souffle::ram::TupleElement
Access element from the current tuple in a tuple environment.
Definition: TupleElement.h:42
souffle::ram::transform::ChoiceConversionTransformer::rewriteIndexScan
Own< Operation > rewriteIndexScan(const IndexScan *indexScan)
Rewrite IndexScan operations.
Definition: ChoiceConversion.cpp:68
Program.h
souffle::ram::Filter
Checks whether a given condition holds.
Definition: Filter.h:49
souffle::ram::Node
Node is a superclass for all RAM IR classes.
Definition: Node.h:42
Visitor.h
souffle::clone
auto clone(const std::vector< A * > &xs)
Definition: ContainerUtil.h:172
souffle::filter
std::vector< A > filter(std::vector< A > xs, F &&f)
Filter a vector to include certain elements.
Definition: FunctionalUtil.h:155
souffle::ram::NestedOperation::getProfileText
const std::string & getProfileText() const
Get profile text.
Definition: NestedOperation.h:67
Relation.h
souffle::ram::transform::ChoiceConversionTransformer::rla
analysis::LevelAnalysis * rla
Definition: ChoiceConversion.h:101
Condition.h
souffle::ram::transform::ChoiceConversionTransformer::convertScans
bool convertScans(Program &program)
Apply choice-conversion to the whole program.
Definition: ChoiceConversion.cpp:116
souffle::ram::TupleOperation::getTupleId
int getTupleId() const
Get identifier.
Definition: TupleOperation.h:43
souffle::ram::Scan
Iterate all tuples of a relation.
Definition: Scan.h:47
souffle::ram::IndexScan
Search for tuples of a relation matching a criteria.
Definition: IndexScan.h:52
souffle::ram::Expression::clone
Expression * clone() const override=0
Create a clone (i.e.
souffle::ram::transform::ChoiceConversionTransformer::rewriteScan
Own< Operation > rewriteScan(const Scan *scan)
Rewrite Scan operations.
Definition: ChoiceConversion.cpp:36
Node.h
Operation.h
souffle::ram::RamPattern
std::pair< RamBound, RamBound > RamPattern
Definition: IndexOperation.h:42
Statement.h
Expression.h
souffle::ram::visitDepthFirst
void visitDepthFirst(const Node &root, Visitor< R, Ps... > &visitor, Args &... args)
A utility function visiting all nodes within the RAM fragments rooted by the given node recursively i...
Definition: Visitor.h:357
rel
void rel(size_t limit, bool showLimit=true)
Definition: Tui.h:1086
souffle::VecOwn
std::vector< Own< A > > VecOwn
Definition: ContainerUtil.h:45
souffle::ram::Expression
Abstract class for describing scalar values in RAM.
Definition: Expression.h:33
souffle::ram::TupleElement::getTupleId
int getTupleId() const
Get identifier.
Definition: TupleElement.h:46
souffle::ram::makeLambdaRamMapper
LambdaNodeMapper< Lambda > makeLambdaRamMapper(const Lambda &lambda)
Creates a node mapper based on a corresponding lambda expression.
Definition: LambdaNodeMapper.h:67