souffle  2.0.2-371-g6315b36
Public Member Functions | Protected Member Functions | Protected Attributes
souffle::ram::transform::HoistConditionsTransformer Class Reference

Hosts conditions in a loop-nest to the most-outer/semantically-correct loop. More...

#include <HoistConditions.h>

Inheritance diagram for souffle::ram::transform::HoistConditionsTransformer:
Inheritance graph
Collaboration diagram for souffle::ram::transform::HoistConditionsTransformer:
Collaboration graph

Public Member Functions

std::string getName () const override
 @Brief get name of the transformer More...
 
bool hoistConditions (Program &program)
 Hoist filter operations. More...
 
- Public Member Functions inherited from souffle::ram::transform::Transformer
bool apply (TranslationUnit &translationUnit)
 @Brief apply the transformer to a translation unit @Param translationUnit that will be transformed. More...
 
virtual ~Transformer ()=default
 

Protected Member Functions

bool transform (TranslationUnit &translationUnit) override
 @Brief transform the translation unit / used by apply @Param translationUnit that will be transformed. More...
 

Protected Attributes

analysis::LevelAnalysisrla {nullptr}
 

Detailed Description

Hosts conditions in a loop-nest to the most-outer/semantically-correct loop.

Hoists the conditions to the earliest point in the loop nest where their evaluation is still semantically correct.

The transformations assumes that filter operations are stored verbose, i.e. a conjunction is expressed by two consecutive filter operations. For example ..

QUERY
...
IF C1 /\ C2 then
...

should be rewritten / or produced by the translator as

QUERY
...
IF C1
IF C2
...

otherwise the levelling becomes imprecise, i.e., for both conditions the most outer-level is sought rather than considered separately.

If there are transformers prior to hoistConditions() that introduce conjunction, another transformer is required that splits the filter operations. However, at the moment this is not necessary because the translator delivers already the right RAM format.

TODO: break-up conditions while transforming so that this requirement is removed.

Definition at line 68 of file HoistConditions.h.

Member Function Documentation

◆ getName()

std::string souffle::ram::transform::HoistConditionsTransformer::getName ( ) const
inlineoverridevirtual

@Brief get name of the transformer

Implements souffle::ram::transform::Transformer.

Definition at line 70 of file HoistConditions.h.

83  :
84  analysis::LevelAnalysis* rla{nullptr};

◆ hoistConditions()

bool souffle::ram::transform::HoistConditionsTransformer::hoistConditions ( Program program)

Hoist filter operations.

Parameters
programthat is transformed
Returns
Flag showing whether the program has been changed by the transformation

There are two types of conditions in filter operations. The first type depends on tuples of TupleOperation operations. The second type are independent of tuple access. Both types of conditions will be hoisted to the most out-scope such that the program is still valid.

Definition at line 34 of file HoistConditions.cpp.

34  {
35  if (condition == nullptr) {
36  return c;
37  } else {
38  return mk<Conjunction>(std::move(condition), std::move(c));
39  }
40  };
41 
42  // hoist conditions to the most outer scope if they
43  // don't depend on TupleOperations
44  visitDepthFirst(program, [&](const Query& query) {
45  Own<Condition> newCondition;
46  std::function<Own<Node>(Own<Node>)> filterRewriter = [&](Own<Node> node) -> Own<Node> {
47  if (auto* filter = dynamic_cast<Filter*>(node.get())) {
48  const Condition& condition = filter->getCondition();
49  // if filter condition is independent of any TupleOperation,
50  // delete the filter operation and collect condition
51  if (rla->getLevel(&condition) == -1) {
52  changed = true;
53  newCondition = addCondition(std::move(newCondition), souffle::clone(&condition));
54  node->apply(makeLambdaRamMapper(filterRewriter));
55  return souffle::clone(&filter->getOperation());
56  }
57  }
58  node->apply(makeLambdaRamMapper(filterRewriter));
59  return node;
60  };
61  auto* mQuery = const_cast<Query*>(&query);
62  mQuery->apply(makeLambdaRamMapper(filterRewriter));
63  if (newCondition != nullptr) {
64  // insert new filter operation at outer-most level of the query
65  changed = true;
66  auto* nestedOp = const_cast<Operation*>(&mQuery->getOperation());
67  mQuery->rewrite(nestedOp, mk<Filter>(std::move(newCondition), souffle::clone(nestedOp)));
68  }
69  });
70 
71  // hoist conditions for each TupleOperation operation
72  visitDepthFirst(program, [&](const TupleOperation& search) {
73  Own<Condition> newCondition;
74  std::function<Own<Node>(Own<Node>)> filterRewriter = [&](Own<Node> node) -> Own<Node> {
75  if (auto* filter = dynamic_cast<Filter*>(node.get())) {
76  const Condition& condition = filter->getCondition();
77  // if filter condition matches level of TupleOperation,
78  // delete the filter operation and collect condition
79  if (rla->getLevel(&condition) == search.getTupleId()) {
80  changed = true;
81  newCondition = addCondition(std::move(newCondition), souffle::clone(&condition));
82  node->apply(makeLambdaRamMapper(filterRewriter));
83  return souffle::clone(&filter->getOperation());
84  }
85  }
86  node->apply(makeLambdaRamMapper(filterRewriter));
87  return node;
88  };
89  auto* tupleOp = const_cast<TupleOperation*>(&search);
90  tupleOp->apply(makeLambdaRamMapper(filterRewriter));
91  if (newCondition != nullptr) {
92  // insert new filter operation after the search operation
93  changed = true;
94  tupleOp->rewrite(&tupleOp->getOperation(),
95  mk<Filter>(std::move(newCondition), souffle::clone(&tupleOp->getOperation())));
96  }
97  });
98  return changed;
99 }
100 
101 } // namespace souffle::ram::transform

◆ transform()

bool souffle::ram::transform::HoistConditionsTransformer::transform ( TranslationUnit translationUnit)
inlineoverrideprotectedvirtual

@Brief transform the translation unit / used by apply @Param translationUnit that will be transformed.

@Return flag reporting whether the RAM program has changed

Implements souffle::ram::transform::Transformer.

Definition at line 90 of file HoistConditions.h.

Field Documentation

◆ rla

analysis::LevelAnalysis* souffle::ram::transform::HoistConditionsTransformer::rla {nullptr}
protected

Definition at line 88 of file HoistConditions.h.


The documentation for this class was generated from the following files:
souffle::ram::analysis::LevelAnalysis::getLevel
int getLevel(const Node *value) const
Get level of a RAM expression/condition.
Definition: Level.cpp:64
souffle::ram::transform::HoistConditionsTransformer::rla
analysis::LevelAnalysis * rla
Definition: HoistConditions.h:88
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::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
souffle::ram::makeLambdaRamMapper
LambdaNodeMapper< Lambda > makeLambdaRamMapper(const Lambda &lambda)
Creates a node mapper based on a corresponding lambda expression.
Definition: LambdaNodeMapper.h:67