Skip to content

Conversation

@MathiasVP
Copy link
Contributor

During the work on range analysis I learnt how to structure non-linear recursion so that it's as efficient as possible: ensure that as many tuples as possible are filtered away before the recursive result is joined onto the pipeline. In practice, this is done by transforming code such as:

predicate nonlinear(a) {
  condition(a) and
  nonlinear(a.getFirst()) and
  nonlinear(a.getSecond())
}

into

pragma[nomagic]
predicate nonlinear0(a, isFirst) {
  condition(a) and
  (
    isFirst = true and
    nonlinear(a.getFirst())
    or
    isFirst = false and
    nonlinear(a.getSecond())
  )
}

predicate nonlinear(a) {
  nonlinear0(a, true) and
  nonlinear0(a, false)
}

this ensures that we only join the a's for which condition(a) holds onto the pipeline. This trick is used all throughout the new range analysis library to achieve good performance, and there's no reason why our GVN library shouldn't use the same tricks.

Finally, I also ran Schacks magic regexp to find bad early joins with #prev and applied the standard fix for those.

Since GVN is generally quite fast already, I don't expect this PR to have a super big impact.

@MathiasVP MathiasVP added the no-change-note-required This PR does not need a change note label Mar 31, 2023
@MathiasVP MathiasVP requested review from a team as code owners March 31, 2023 20:21
Copy link
Contributor

@jketema jketema left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@jketema jketema merged commit e5c7c88 into github:main Apr 3, 2023
@hvitved
Copy link
Contributor

hvitved commented Apr 11, 2023

Actually, it is better to do

pragma[nomagic]
predicate nonlinearFirst(a) {
  condition(a) and
  nonlinear(a.getFirst())
}

pragma[nomagic]
predicate nonlinearSecond(a) {
  condition(a) and
  nonlinear(a.getSecond())
}

predicate nonlinear(a) {
  nonlinearFirst(a) and
  nonlinearSecond(a)
}

since otherwise, the prev relation will include a row for each of the two children.

@MathiasVP
Copy link
Contributor Author

Shouldn't that (hopefully) be handled by the optimizer? As in: I would hope that the optimizer did a join with prev where the isFirst column was the constant true for the first join, and the constant false for the second join?

@hvitved
Copy link
Contributor

hvitved commented Apr 11, 2023

Shouldn't that (hopefully) be handled by the optimizer? As in: I would hope that the optimizer did a join with prev where the isFirst column was the constant true for the first join, and the constant false for the second join?

Maybe it is OK, perhaps worth checking out the DIL. I would normally structure the code as in my example to make sure that the prev relations become as small as possible for non-linear recursion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

C# C++ no-change-note-required This PR does not need a change note

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants