From 8c8fee3ccb158acdfd658c8ed52301c94ac3fed2 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Fri, 23 Aug 2019 14:19:56 +0200 Subject: [PATCH] C++/C#/Java: localFlowStep performance fix --- .../cpp/dataflow/internal/DataFlowImpl.qll | 18 +++++++++++++++++- .../cpp/dataflow/internal/DataFlowImpl2.qll | 18 +++++++++++++++++- .../cpp/dataflow/internal/DataFlowImpl3.qll | 18 +++++++++++++++++- .../cpp/dataflow/internal/DataFlowImpl4.qll | 18 +++++++++++++++++- .../cpp/ir/dataflow/internal/DataFlowImpl.qll | 18 +++++++++++++++++- .../cpp/ir/dataflow/internal/DataFlowImpl2.qll | 18 +++++++++++++++++- .../cpp/ir/dataflow/internal/DataFlowImpl3.qll | 18 +++++++++++++++++- .../cpp/ir/dataflow/internal/DataFlowImpl4.qll | 18 +++++++++++++++++- .../csharp/dataflow/internal/DataFlowImpl.qll | 18 +++++++++++++++++- .../csharp/dataflow/internal/DataFlowImpl2.qll | 18 +++++++++++++++++- .../csharp/dataflow/internal/DataFlowImpl3.qll | 18 +++++++++++++++++- .../csharp/dataflow/internal/DataFlowImpl4.qll | 18 +++++++++++++++++- .../csharp/dataflow/internal/DataFlowImpl5.qll | 18 +++++++++++++++++- .../java/dataflow/internal/DataFlowImpl.qll | 18 +++++++++++++++++- .../java/dataflow/internal/DataFlowImpl2.qll | 18 +++++++++++++++++- .../java/dataflow/internal/DataFlowImpl3.qll | 18 +++++++++++++++++- .../java/dataflow/internal/DataFlowImpl4.qll | 18 +++++++++++++++++- .../java/dataflow/internal/DataFlowImpl5.qll | 18 +++++++++++++++++- 18 files changed, 306 insertions(+), 18 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index 931ab2e63f16..c0791da787b6 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -179,11 +179,27 @@ private predicate isAdditionalFlowStep( callable1 = node1.getEnclosingCallable() } +// This predicate guides the optimizer to select the optimal column order in +// the body of `localFlowStep`. Without pulling out this predicate, the +// optimizer will at the time of writing do a SCAN to put the `Configuration` +// column on the very left in the intermediate results and later `SCAN` to move +// it to the very right. This is very slow when there is a single +// `Configuration` that uses both full barriers and out-barriers. +// +// With this predicate added, the RA contains only a single SCAN that adds the +// `Configuration` on the right from the beginning. This speeds up the +// predicate(s) by up to 10x. +pragma[noinline] +private predicate localFlowStep0(Node node1, Node node2, Configuration config) { + simpleLocalFlowStep(node1, node2) and + config = config +} + /** * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + localFlowStep0(node1, node2, config) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index 931ab2e63f16..c0791da787b6 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -179,11 +179,27 @@ private predicate isAdditionalFlowStep( callable1 = node1.getEnclosingCallable() } +// This predicate guides the optimizer to select the optimal column order in +// the body of `localFlowStep`. Without pulling out this predicate, the +// optimizer will at the time of writing do a SCAN to put the `Configuration` +// column on the very left in the intermediate results and later `SCAN` to move +// it to the very right. This is very slow when there is a single +// `Configuration` that uses both full barriers and out-barriers. +// +// With this predicate added, the RA contains only a single SCAN that adds the +// `Configuration` on the right from the beginning. This speeds up the +// predicate(s) by up to 10x. +pragma[noinline] +private predicate localFlowStep0(Node node1, Node node2, Configuration config) { + simpleLocalFlowStep(node1, node2) and + config = config +} + /** * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + localFlowStep0(node1, node2, config) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index 931ab2e63f16..c0791da787b6 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -179,11 +179,27 @@ private predicate isAdditionalFlowStep( callable1 = node1.getEnclosingCallable() } +// This predicate guides the optimizer to select the optimal column order in +// the body of `localFlowStep`. Without pulling out this predicate, the +// optimizer will at the time of writing do a SCAN to put the `Configuration` +// column on the very left in the intermediate results and later `SCAN` to move +// it to the very right. This is very slow when there is a single +// `Configuration` that uses both full barriers and out-barriers. +// +// With this predicate added, the RA contains only a single SCAN that adds the +// `Configuration` on the right from the beginning. This speeds up the +// predicate(s) by up to 10x. +pragma[noinline] +private predicate localFlowStep0(Node node1, Node node2, Configuration config) { + simpleLocalFlowStep(node1, node2) and + config = config +} + /** * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + localFlowStep0(node1, node2, config) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index 931ab2e63f16..c0791da787b6 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -179,11 +179,27 @@ private predicate isAdditionalFlowStep( callable1 = node1.getEnclosingCallable() } +// This predicate guides the optimizer to select the optimal column order in +// the body of `localFlowStep`. Without pulling out this predicate, the +// optimizer will at the time of writing do a SCAN to put the `Configuration` +// column on the very left in the intermediate results and later `SCAN` to move +// it to the very right. This is very slow when there is a single +// `Configuration` that uses both full barriers and out-barriers. +// +// With this predicate added, the RA contains only a single SCAN that adds the +// `Configuration` on the right from the beginning. This speeds up the +// predicate(s) by up to 10x. +pragma[noinline] +private predicate localFlowStep0(Node node1, Node node2, Configuration config) { + simpleLocalFlowStep(node1, node2) and + config = config +} + /** * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + localFlowStep0(node1, node2, config) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index 931ab2e63f16..c0791da787b6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -179,11 +179,27 @@ private predicate isAdditionalFlowStep( callable1 = node1.getEnclosingCallable() } +// This predicate guides the optimizer to select the optimal column order in +// the body of `localFlowStep`. Without pulling out this predicate, the +// optimizer will at the time of writing do a SCAN to put the `Configuration` +// column on the very left in the intermediate results and later `SCAN` to move +// it to the very right. This is very slow when there is a single +// `Configuration` that uses both full barriers and out-barriers. +// +// With this predicate added, the RA contains only a single SCAN that adds the +// `Configuration` on the right from the beginning. This speeds up the +// predicate(s) by up to 10x. +pragma[noinline] +private predicate localFlowStep0(Node node1, Node node2, Configuration config) { + simpleLocalFlowStep(node1, node2) and + config = config +} + /** * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + localFlowStep0(node1, node2, config) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index 931ab2e63f16..c0791da787b6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -179,11 +179,27 @@ private predicate isAdditionalFlowStep( callable1 = node1.getEnclosingCallable() } +// This predicate guides the optimizer to select the optimal column order in +// the body of `localFlowStep`. Without pulling out this predicate, the +// optimizer will at the time of writing do a SCAN to put the `Configuration` +// column on the very left in the intermediate results and later `SCAN` to move +// it to the very right. This is very slow when there is a single +// `Configuration` that uses both full barriers and out-barriers. +// +// With this predicate added, the RA contains only a single SCAN that adds the +// `Configuration` on the right from the beginning. This speeds up the +// predicate(s) by up to 10x. +pragma[noinline] +private predicate localFlowStep0(Node node1, Node node2, Configuration config) { + simpleLocalFlowStep(node1, node2) and + config = config +} + /** * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + localFlowStep0(node1, node2, config) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index 931ab2e63f16..c0791da787b6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -179,11 +179,27 @@ private predicate isAdditionalFlowStep( callable1 = node1.getEnclosingCallable() } +// This predicate guides the optimizer to select the optimal column order in +// the body of `localFlowStep`. Without pulling out this predicate, the +// optimizer will at the time of writing do a SCAN to put the `Configuration` +// column on the very left in the intermediate results and later `SCAN` to move +// it to the very right. This is very slow when there is a single +// `Configuration` that uses both full barriers and out-barriers. +// +// With this predicate added, the RA contains only a single SCAN that adds the +// `Configuration` on the right from the beginning. This speeds up the +// predicate(s) by up to 10x. +pragma[noinline] +private predicate localFlowStep0(Node node1, Node node2, Configuration config) { + simpleLocalFlowStep(node1, node2) and + config = config +} + /** * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + localFlowStep0(node1, node2, config) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index 931ab2e63f16..c0791da787b6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -179,11 +179,27 @@ private predicate isAdditionalFlowStep( callable1 = node1.getEnclosingCallable() } +// This predicate guides the optimizer to select the optimal column order in +// the body of `localFlowStep`. Without pulling out this predicate, the +// optimizer will at the time of writing do a SCAN to put the `Configuration` +// column on the very left in the intermediate results and later `SCAN` to move +// it to the very right. This is very slow when there is a single +// `Configuration` that uses both full barriers and out-barriers. +// +// With this predicate added, the RA contains only a single SCAN that adds the +// `Configuration` on the right from the beginning. This speeds up the +// predicate(s) by up to 10x. +pragma[noinline] +private predicate localFlowStep0(Node node1, Node node2, Configuration config) { + simpleLocalFlowStep(node1, node2) and + config = config +} + /** * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + localFlowStep0(node1, node2, config) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index 931ab2e63f16..c0791da787b6 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -179,11 +179,27 @@ private predicate isAdditionalFlowStep( callable1 = node1.getEnclosingCallable() } +// This predicate guides the optimizer to select the optimal column order in +// the body of `localFlowStep`. Without pulling out this predicate, the +// optimizer will at the time of writing do a SCAN to put the `Configuration` +// column on the very left in the intermediate results and later `SCAN` to move +// it to the very right. This is very slow when there is a single +// `Configuration` that uses both full barriers and out-barriers. +// +// With this predicate added, the RA contains only a single SCAN that adds the +// `Configuration` on the right from the beginning. This speeds up the +// predicate(s) by up to 10x. +pragma[noinline] +private predicate localFlowStep0(Node node1, Node node2, Configuration config) { + simpleLocalFlowStep(node1, node2) and + config = config +} + /** * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + localFlowStep0(node1, node2, config) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll index 931ab2e63f16..c0791da787b6 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -179,11 +179,27 @@ private predicate isAdditionalFlowStep( callable1 = node1.getEnclosingCallable() } +// This predicate guides the optimizer to select the optimal column order in +// the body of `localFlowStep`. Without pulling out this predicate, the +// optimizer will at the time of writing do a SCAN to put the `Configuration` +// column on the very left in the intermediate results and later `SCAN` to move +// it to the very right. This is very slow when there is a single +// `Configuration` that uses both full barriers and out-barriers. +// +// With this predicate added, the RA contains only a single SCAN that adds the +// `Configuration` on the right from the beginning. This speeds up the +// predicate(s) by up to 10x. +pragma[noinline] +private predicate localFlowStep0(Node node1, Node node2, Configuration config) { + simpleLocalFlowStep(node1, node2) and + config = config +} + /** * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + localFlowStep0(node1, node2, config) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll index 931ab2e63f16..c0791da787b6 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -179,11 +179,27 @@ private predicate isAdditionalFlowStep( callable1 = node1.getEnclosingCallable() } +// This predicate guides the optimizer to select the optimal column order in +// the body of `localFlowStep`. Without pulling out this predicate, the +// optimizer will at the time of writing do a SCAN to put the `Configuration` +// column on the very left in the intermediate results and later `SCAN` to move +// it to the very right. This is very slow when there is a single +// `Configuration` that uses both full barriers and out-barriers. +// +// With this predicate added, the RA contains only a single SCAN that adds the +// `Configuration` on the right from the beginning. This speeds up the +// predicate(s) by up to 10x. +pragma[noinline] +private predicate localFlowStep0(Node node1, Node node2, Configuration config) { + simpleLocalFlowStep(node1, node2) and + config = config +} + /** * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + localFlowStep0(node1, node2, config) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll index 931ab2e63f16..c0791da787b6 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -179,11 +179,27 @@ private predicate isAdditionalFlowStep( callable1 = node1.getEnclosingCallable() } +// This predicate guides the optimizer to select the optimal column order in +// the body of `localFlowStep`. Without pulling out this predicate, the +// optimizer will at the time of writing do a SCAN to put the `Configuration` +// column on the very left in the intermediate results and later `SCAN` to move +// it to the very right. This is very slow when there is a single +// `Configuration` that uses both full barriers and out-barriers. +// +// With this predicate added, the RA contains only a single SCAN that adds the +// `Configuration` on the right from the beginning. This speeds up the +// predicate(s) by up to 10x. +pragma[noinline] +private predicate localFlowStep0(Node node1, Node node2, Configuration config) { + simpleLocalFlowStep(node1, node2) and + config = config +} + /** * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + localFlowStep0(node1, node2, config) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll index 931ab2e63f16..c0791da787b6 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -179,11 +179,27 @@ private predicate isAdditionalFlowStep( callable1 = node1.getEnclosingCallable() } +// This predicate guides the optimizer to select the optimal column order in +// the body of `localFlowStep`. Without pulling out this predicate, the +// optimizer will at the time of writing do a SCAN to put the `Configuration` +// column on the very left in the intermediate results and later `SCAN` to move +// it to the very right. This is very slow when there is a single +// `Configuration` that uses both full barriers and out-barriers. +// +// With this predicate added, the RA contains only a single SCAN that adds the +// `Configuration` on the right from the beginning. This speeds up the +// predicate(s) by up to 10x. +pragma[noinline] +private predicate localFlowStep0(Node node1, Node node2, Configuration config) { + simpleLocalFlowStep(node1, node2) and + config = config +} + /** * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + localFlowStep0(node1, node2, config) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll index 931ab2e63f16..c0791da787b6 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -179,11 +179,27 @@ private predicate isAdditionalFlowStep( callable1 = node1.getEnclosingCallable() } +// This predicate guides the optimizer to select the optimal column order in +// the body of `localFlowStep`. Without pulling out this predicate, the +// optimizer will at the time of writing do a SCAN to put the `Configuration` +// column on the very left in the intermediate results and later `SCAN` to move +// it to the very right. This is very slow when there is a single +// `Configuration` that uses both full barriers and out-barriers. +// +// With this predicate added, the RA contains only a single SCAN that adds the +// `Configuration` on the right from the beginning. This speeds up the +// predicate(s) by up to 10x. +pragma[noinline] +private predicate localFlowStep0(Node node1, Node node2, Configuration config) { + simpleLocalFlowStep(node1, node2) and + config = config +} + /** * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + localFlowStep0(node1, node2, config) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index 931ab2e63f16..c0791da787b6 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -179,11 +179,27 @@ private predicate isAdditionalFlowStep( callable1 = node1.getEnclosingCallable() } +// This predicate guides the optimizer to select the optimal column order in +// the body of `localFlowStep`. Without pulling out this predicate, the +// optimizer will at the time of writing do a SCAN to put the `Configuration` +// column on the very left in the intermediate results and later `SCAN` to move +// it to the very right. This is very slow when there is a single +// `Configuration` that uses both full barriers and out-barriers. +// +// With this predicate added, the RA contains only a single SCAN that adds the +// `Configuration` on the right from the beginning. This speeds up the +// predicate(s) by up to 10x. +pragma[noinline] +private predicate localFlowStep0(Node node1, Node node2, Configuration config) { + simpleLocalFlowStep(node1, node2) and + config = config +} + /** * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + localFlowStep0(node1, node2, config) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index 931ab2e63f16..c0791da787b6 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -179,11 +179,27 @@ private predicate isAdditionalFlowStep( callable1 = node1.getEnclosingCallable() } +// This predicate guides the optimizer to select the optimal column order in +// the body of `localFlowStep`. Without pulling out this predicate, the +// optimizer will at the time of writing do a SCAN to put the `Configuration` +// column on the very left in the intermediate results and later `SCAN` to move +// it to the very right. This is very slow when there is a single +// `Configuration` that uses both full barriers and out-barriers. +// +// With this predicate added, the RA contains only a single SCAN that adds the +// `Configuration` on the right from the beginning. This speeds up the +// predicate(s) by up to 10x. +pragma[noinline] +private predicate localFlowStep0(Node node1, Node node2, Configuration config) { + simpleLocalFlowStep(node1, node2) and + config = config +} + /** * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + localFlowStep0(node1, node2, config) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index 931ab2e63f16..c0791da787b6 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -179,11 +179,27 @@ private predicate isAdditionalFlowStep( callable1 = node1.getEnclosingCallable() } +// This predicate guides the optimizer to select the optimal column order in +// the body of `localFlowStep`. Without pulling out this predicate, the +// optimizer will at the time of writing do a SCAN to put the `Configuration` +// column on the very left in the intermediate results and later `SCAN` to move +// it to the very right. This is very slow when there is a single +// `Configuration` that uses both full barriers and out-barriers. +// +// With this predicate added, the RA contains only a single SCAN that adds the +// `Configuration` on the right from the beginning. This speeds up the +// predicate(s) by up to 10x. +pragma[noinline] +private predicate localFlowStep0(Node node1, Node node2, Configuration config) { + simpleLocalFlowStep(node1, node2) and + config = config +} + /** * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + localFlowStep0(node1, node2, config) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index 931ab2e63f16..c0791da787b6 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -179,11 +179,27 @@ private predicate isAdditionalFlowStep( callable1 = node1.getEnclosingCallable() } +// This predicate guides the optimizer to select the optimal column order in +// the body of `localFlowStep`. Without pulling out this predicate, the +// optimizer will at the time of writing do a SCAN to put the `Configuration` +// column on the very left in the intermediate results and later `SCAN` to move +// it to the very right. This is very slow when there is a single +// `Configuration` that uses both full barriers and out-barriers. +// +// With this predicate added, the RA contains only a single SCAN that adds the +// `Configuration` on the right from the beginning. This speeds up the +// predicate(s) by up to 10x. +pragma[noinline] +private predicate localFlowStep0(Node node1, Node node2, Configuration config) { + simpleLocalFlowStep(node1, node2) and + config = config +} + /** * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + localFlowStep0(node1, node2, config) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and