Skip to content

Commit 80f8578

Browse files
authored
Merge pull request #2423 from stan-dev/feature/no-op-bounds-checks
adds macro for making bounds checks a no-op
2 parents 0288827 + 2f2fe23 commit 80f8578

14 files changed

+135
-50
lines changed

.github/workflows/header_checks.yml

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@ jobs:
2424
token: ${{ secrets.GITHUB_TOKEN }}
2525
workflow: c-cpp.yml
2626
if: "!startsWith(github.ref, 'refs/tags/') && github.ref != 'refs/heads/master' && github.ref != 'refs/heads/develop'"
27-
27+
2828
- uses: actions/checkout@v2
2929
- uses: actions/setup-python@v2
3030
with:
3131
python-version: '2.x'
32-
32+
3333
- name: Print g++/mingw32-make version and path
3434
run: |
3535
g++ --version
@@ -41,7 +41,7 @@ jobs:
4141
- name: Build Math libs
4242
shell: powershell
4343
run: mingw32-make -f make/standalone math-libs
44-
44+
4545
- name: Run header tests
4646
shell: powershell
4747
run: make -j2 test-headers
@@ -56,10 +56,27 @@ jobs:
5656
token: ${{ secrets.GITHUB_TOKEN }}
5757
workflow: c-cpp.yml
5858
if: "!startsWith(github.ref, 'refs/tags/') && github.ref != 'refs/heads/master' && github.ref != 'refs/heads/develop'"
59-
59+
6060
- uses: actions/checkout@v2
61-
61+
6262
- name: Run header tests
6363
run: |
6464
echo "STAN_OPENCL=true" > make/local
65-
make -j2 test-headers
65+
make -j2 test-headers
66+
no_range_checks:
67+
name: NoRange
68+
runs-on: ubuntu-latest
69+
70+
steps:
71+
- uses: n1hility/cancel-previous-runs@v2
72+
with:
73+
token: ${{ secrets.GITHUB_TOKEN }}
74+
workflow: c-cpp.yml
75+
if: "!startsWith(github.ref, 'refs/tags/') && github.ref != 'refs/heads/master' && github.ref != 'refs/heads/develop'"
76+
77+
- uses: actions/checkout@v2
78+
79+
- name: Run header tests
80+
run: |
81+
echo "CXXFLAGS+=-DSTAN_NO_RANGE_CHECKS" > make/local
82+
./runTests.py -j2 ./test/unit/math/prim/err/

stan/math/prim/err/check_range.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ namespace math {
2323
*/
2424
inline void check_range(const char* function, const char* name, int max,
2525
int index, int nested_level, const char* error_msg) {
26+
STAN_NO_RANGE_CHECKS_RETURN;
2627
if (!((index >= stan::error_index::value)
2728
&& (index < max + stan::error_index::value))) {
2829
[&]() STAN_COLD_PATH {
@@ -47,6 +48,7 @@ inline void check_range(const char* function, const char* name, int max,
4748
*/
4849
inline void check_range(const char* function, const char* name, int max,
4950
int index, const char* error_msg) {
51+
STAN_NO_RANGE_CHECKS_RETURN;
5052
if (!((index >= stan::error_index::value)
5153
&& (index < max + stan::error_index::value))) {
5254
[&]() STAN_COLD_PATH { out_of_range(function, max, index, error_msg); }();
@@ -65,6 +67,7 @@ inline void check_range(const char* function, const char* name, int max,
6567
*/
6668
inline void check_range(const char* function, const char* name, int max,
6769
int index) {
70+
STAN_NO_RANGE_CHECKS_RETURN;
6871
if (!((index >= stan::error_index::value)
6972
&& (index < max + stan::error_index::value))) {
7073
[&]() STAN_COLD_PATH { out_of_range(function, max, index); }();

stan/math/prim/err/check_row_index.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ namespace math {
2424
template <typename T_y, typename = require_eigen_t<T_y>>
2525
inline void check_row_index(const char* function, const char* name,
2626
const T_y& y, size_t i) {
27+
STAN_NO_RANGE_CHECKS_RETURN;
2728
if (!(i >= stan::error_index::value
2829
&& i < static_cast<size_t>(y.rows()) + stan::error_index::value)) {
2930
[&]() STAN_COLD_PATH {

stan/math/prim/err/check_std_vector_index.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ namespace math {
2525
template <typename T>
2626
inline void check_std_vector_index(const char* function, const char* name,
2727
const std::vector<T>& y, int i) {
28+
STAN_NO_RANGE_CHECKS_RETURN;
2829
if (!(i >= static_cast<int>(stan::error_index::value)
2930
&& i < static_cast<int>(y.size() + stan::error_index::value))) {
3031
[&]() STAN_COLD_PATH {

stan/math/prim/err/check_vector.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ template <typename Mat,
3131
is_prim_or_rev_kernel_expression<Mat>>* = nullptr>
3232
inline void check_vector(const char* function, const char* name, const Mat& x) {
3333
if (!(x.rows() == 1 || x.cols() == 1)) {
34+
STAN_NO_RANGE_CHECKS_RETURN;
3435
[&]() STAN_COLD_PATH {
3536
std::ostringstream msg;
3637
msg << ") has " << x.rows() << " rows and " << x.cols()

stan/math/prim/err/check_vector_index.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ template <typename T,
2626
is_prim_or_rev_kernel_expression<T>>* = nullptr>
2727
inline void check_vector_index(const char* function, const char* name,
2828
const T& y, size_t i) {
29+
STAN_NO_RANGE_CHECKS_RETURN;
2930
if (!(i >= stan::error_index::value
3031
&& i < static_cast<size_t>(y.size()) + stan::error_index::value)) {
3132
[&]() STAN_COLD_PATH {

stan/math/prim/meta.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,11 +171,11 @@
171171
* `require` type traits to detect types used with OpenCL.
172172
*/
173173

174+
#include <stan/math/prim/meta/compiler_attributes.hpp>
174175
#include <stan/math/prim/meta/ad_promotable.hpp>
175176
#include <stan/math/prim/meta/append_return_type.hpp>
176177
#include <stan/math/prim/meta/base_type.hpp>
177178
#include <stan/math/prim/meta/child_type.hpp>
178-
#include <stan/math/prim/meta/compiler_attributes.hpp>
179179
#include <stan/math/prim/meta/contains_fvar.hpp>
180180
#include <stan/math/prim/meta/contains_std_vector.hpp>
181181
#include <stan/math/prim/meta/error_index.hpp>

stan/math/prim/meta/compiler_attributes.hpp

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,48 @@
22
#define STAN_MATH_PRIM_META_COMPILER_ATTRIBUTES_HPP
33

44
#ifdef __GNUC__
5+
#ifndef likely
56
#define likely(x) __builtin_expect(!!(x), 1)
7+
#endif
8+
#ifndef unlikely
69
#define unlikely(x) __builtin_expect(!!(x), 0)
10+
#endif
11+
#ifdef __has_attribute
12+
#if __has_attribute(noinline) && __has_attribute(cold)
13+
#ifndef STAN_COLD_PATH
14+
/**
15+
* Functions tagged with this attribute are not inlined and moved
16+
* to a cold branch to tell the CPU to not attempt to pre-fetch
17+
* the associated function.
18+
*/
719
#define STAN_COLD_PATH __attribute__((noinline, cold))
8-
#else
9-
#define likely(x) (x)
10-
#define unlikely(x) (x)
20+
#endif
21+
#endif
22+
#endif
23+
#endif
24+
#ifndef STAN_COLD_PATH
1125
#define STAN_COLD_PATH
1226
#endif
27+
#ifndef likely
28+
#define likely(x) x
29+
#endif
30+
#ifndef unlikely
31+
#define unlikely(x) x
32+
#endif
33+
34+
/**
35+
* Turns all range and size checks into no-ops
36+
*/
37+
#ifndef STAN_NO_RANGE_CHECKS_RETURN
38+
/**
39+
* If defined, will turn off all range and size checks.
40+
*/
41+
#ifdef STAN_NO_RANGE_CHECKS
42+
#define STAN_NO_RANGE_CHECKS_RETURN return
43+
#endif
44+
#ifndef STAN_NO_RANGE_CHECKS_RETURN
45+
#define STAN_NO_RANGE_CHECKS_RETURN
46+
#endif
47+
#endif
1348

1449
#endif

test/unit/math/prim/err/check_range_test.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <stan/math/prim.hpp>
22
#include <gtest/gtest.h>
33
#include <test/unit/util.hpp>
4+
#include <test/unit/math/prim/err/util.hpp>
45
#include <string>
56
#include <vector>
67

@@ -20,16 +21,16 @@ TEST(ErrorHandlingMatrix, checkRange_6_arg_std_vector) {
2021
"index 12 out of range; "
2122
"expecting index to be between 1 and 4; "
2223
"index position = 4";
23-
EXPECT_THROW_MSG(check_range("function", "x", 4, 12, 4, ""),
24-
std::out_of_range, expected_message);
24+
STAN_EXPECT_THROW_MSG(check_range("function", "x", 4, 12, 4, ""),
25+
std::out_of_range, expected_message);
2526

2627
std::string expected_message_empty_container
2728
= "function: accessing element out of range. "
2829
"index 0 out of range; "
2930
"container is empty and cannot be indexed; "
3031
"index position = 4";
31-
EXPECT_THROW_MSG(check_range("function", "x", 0, 0, 4, ""), std::out_of_range,
32-
expected_message_empty_container);
32+
STAN_EXPECT_THROW_MSG(check_range("function", "x", 0, 0, 4, ""),
33+
std::out_of_range, expected_message_empty_container);
3334
}
3435

3536
TEST(ErrorHandlingMatrix, checkRange_4_arg_std_vector) {
@@ -47,13 +48,13 @@ TEST(ErrorHandlingMatrix, checkRange_4_arg_std_vector) {
4748
= "function: accessing element out of range. "
4849
"index 12 out of range; "
4950
"expecting index to be between 1 and 4";
50-
EXPECT_THROW_MSG(check_range("function", "x", 4, 12), std::out_of_range,
51-
expected_message);
51+
STAN_EXPECT_THROW_MSG(check_range("function", "x", 4, 12), std::out_of_range,
52+
expected_message);
5253

5354
std::string expected_message_empty_container
5455
= "function: accessing element out of range. "
5556
"index 0 out of range; "
5657
"container is empty and cannot be indexed";
57-
EXPECT_THROW_MSG(check_range("function", "x", 0, 0), std::out_of_range,
58-
expected_message_empty_container);
58+
STAN_EXPECT_THROW_MSG(check_range("function", "x", 0, 0), std::out_of_range,
59+
expected_message_empty_container);
5960
}

test/unit/math/prim/err/check_row_index_test.cpp

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include <stan/math/prim.hpp>
22
#include <gtest/gtest.h>
3+
#include <test/unit/math/prim/err/util.hpp>
34
#include <limits>
45

56
TEST(ErrorHandlingMatrix, checkRowIndexMatrix) {
@@ -15,12 +16,14 @@ TEST(ErrorHandlingMatrix, checkRowIndexMatrix) {
1516
stan::math::check_row_index("checkRowIndexMatrix", "i", y, i));
1617

1718
y.resize(2, 3);
18-
EXPECT_THROW(stan::math::check_row_index("checkRowIndexMatrix", "i", y, i),
19-
std::out_of_range);
19+
STAN_EXPECT_THROW(
20+
stan::math::check_row_index("checkRowIndexMatrix", "i", y, i),
21+
std::out_of_range);
2022

2123
i = 0;
22-
EXPECT_THROW(stan::math::check_row_index("checkRowIndexMatrix", "i", y, i),
23-
std::out_of_range);
24+
STAN_EXPECT_THROW(
25+
stan::math::check_row_index("checkRowIndexMatrix", "i", y, i),
26+
std::out_of_range);
2427
}
2528

2629
TEST(ErrorHandlingMatrix, checkRowIndexMatrix_nan) {
@@ -39,10 +42,12 @@ TEST(ErrorHandlingMatrix, checkRowIndexMatrix_nan) {
3942

4043
y.resize(2, 3);
4144
y << nan, nan, nan, nan, nan, nan;
42-
EXPECT_THROW(stan::math::check_row_index("checkRowIndexMatrix", "i", y, i),
43-
std::out_of_range);
45+
STAN_EXPECT_THROW(
46+
stan::math::check_row_index("checkRowIndexMatrix", "i", y, i),
47+
std::out_of_range);
4448

4549
i = 0;
46-
EXPECT_THROW(stan::math::check_row_index("checkRowIndexMatrix", "i", y, i),
47-
std::out_of_range);
50+
STAN_EXPECT_THROW(
51+
stan::math::check_row_index("checkRowIndexMatrix", "i", y, i),
52+
std::out_of_range);
4853
}

test/unit/math/prim/err/check_std_vector_index_test.cpp

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include <stan/math/prim.hpp>
22
#include <gtest/gtest.h>
3+
#include <test/unit/math/prim/err/util.hpp>
34
#include <limits>
45
#include <vector>
56

@@ -20,14 +21,14 @@ TEST(ErrorHandlingMatrix, checkStdVectorIndexMatrix) {
2021
"checkStdVectorIndexMatrix", "i", y, i));
2122

2223
y.resize(2);
23-
EXPECT_THROW(stan::math::check_std_vector_index("checkStdVectorIndexMatrix",
24-
"i", y, i),
25-
std::out_of_range);
24+
STAN_EXPECT_THROW(stan::math::check_std_vector_index(
25+
"checkStdVectorIndexMatrix", "i", y, i),
26+
std::out_of_range);
2627

2728
i = 0;
28-
EXPECT_THROW(stan::math::check_std_vector_index("checkStdVectorIndexMatrix",
29-
"i", y, i),
30-
std::out_of_range);
29+
STAN_EXPECT_THROW(stan::math::check_std_vector_index(
30+
"checkStdVectorIndexMatrix", "i", y, i),
31+
std::out_of_range);
3132
}
3233

3334
TEST(ErrorHandlingMatrix, checkStdVectorIndexMatrix_nan) {
@@ -48,12 +49,12 @@ TEST(ErrorHandlingMatrix, checkStdVectorIndexMatrix_nan) {
4849
"checkStdVectorIndexMatrix", "i", y, i));
4950

5051
y.resize(2);
51-
EXPECT_THROW(stan::math::check_std_vector_index("checkStdVectorIndexMatrix",
52-
"i", y, i),
53-
std::out_of_range);
52+
STAN_EXPECT_THROW(stan::math::check_std_vector_index(
53+
"checkStdVectorIndexMatrix", "i", y, i),
54+
std::out_of_range);
5455

5556
i = 0;
56-
EXPECT_THROW(stan::math::check_std_vector_index("checkStdVectorIndexMatrix",
57-
"i", y, i),
58-
std::out_of_range);
57+
STAN_EXPECT_THROW(stan::math::check_std_vector_index(
58+
"checkStdVectorIndexMatrix", "i", y, i),
59+
std::out_of_range);
5960
}

test/unit/math/prim/err/check_vector_index_test.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include <stan/math/prim.hpp>
22
#include <gtest/gtest.h>
3+
#include <test/unit/math/prim/err/util.hpp>
34
#include <limits>
45

56
TEST(ErrorHandlingMatrix, checkVectorIndexColumnVector) {
@@ -18,12 +19,12 @@ TEST(ErrorHandlingMatrix, checkVectorIndexColumnVector) {
1819

1920
y.resize(2);
2021
y << nan, nan;
21-
EXPECT_THROW(
22+
STAN_EXPECT_THROW(
2223
stan::math::check_vector_index("checkVectorIndexMatrix", "i", y, i),
2324
std::out_of_range);
2425

2526
i = 0;
26-
EXPECT_THROW(
27+
STAN_EXPECT_THROW(
2728
stan::math::check_vector_index("checkVectorIndexMatrix", "i", y, i),
2829
std::out_of_range);
2930
}
@@ -44,12 +45,12 @@ TEST(ErrorHandlingMatrix, checkVectorIndexRowVector) {
4445

4546
y.resize(2);
4647
y << nan, nan;
47-
EXPECT_THROW(
48+
STAN_EXPECT_THROW(
4849
stan::math::check_vector_index("checkVectorIndexMatrix", "i", y, i),
4950
std::out_of_range);
5051

5152
i = 0;
52-
EXPECT_THROW(
53+
STAN_EXPECT_THROW(
5354
stan::math::check_vector_index("checkVectorIndexMatrix", "i", y, i),
5455
std::out_of_range);
5556
}

test/unit/math/prim/err/check_vector_test.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
#include <stan/math/prim.hpp>
22
#include <gtest/gtest.h>
3+
#include <test/unit/math/prim/err/util.hpp>
34
#include <limits>
45

56
TEST(ErrorHandlingMatrix, checkVectorMatrix) {
67
Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> x;
78

89
x.resize(3, 3);
9-
EXPECT_THROW(stan::math::check_vector("checkVector", "x", x),
10-
std::invalid_argument);
10+
STAN_EXPECT_THROW(stan::math::check_vector("checkVector", "x", x),
11+
std::invalid_argument);
1112
x.resize(0, 0);
12-
EXPECT_THROW(stan::math::check_vector("checkVector", "x", x),
13-
std::invalid_argument);
13+
STAN_EXPECT_THROW(stan::math::check_vector("checkVector", "x", x),
14+
std::invalid_argument);
1415

1516
x.resize(1, 5);
1617
EXPECT_NO_THROW(stan::math::check_vector("checkVector", "x", x));
@@ -25,11 +26,11 @@ TEST(ErrorHandlingMatrix, checkVectorMatrix_nan) {
2526

2627
x.resize(3, 3);
2728
x << nan, nan, nan, nan, nan, nan, nan, nan, nan;
28-
EXPECT_THROW(stan::math::check_vector("checkVector", "x", x),
29-
std::invalid_argument);
29+
STAN_EXPECT_THROW(stan::math::check_vector("checkVector", "x", x),
30+
std::invalid_argument);
3031
x.resize(0, 0);
31-
EXPECT_THROW(stan::math::check_vector("checkVector", "x", x),
32-
std::invalid_argument);
32+
STAN_EXPECT_THROW(stan::math::check_vector("checkVector", "x", x),
33+
std::invalid_argument);
3334

3435
x.resize(1, 5);
3536
x << nan, nan, nan, nan, nan;

0 commit comments

Comments
 (0)