/* // traditional "naiive" loops forall( [M], [N], [P] ) void matmul( array(float, M, P) & src1, array(float, P, N) & src2, array(float, M, N) & tgt ) { for (i; M) for (j; N) { tgt[i][j] = 0; for (k; P) tgt[i][j] += src1[i][k] * src2[k][j]; } } */ #if defined BADBOUNDS #define BOUND(X) 17 #else #define BOUND(X) X #endif #include using namespace std; #ifndef TESTCASE #define TESTCASE 1 #endif #if TESTCASE==1 float f( vector & a ) { float result = 0; for( int i = 0; i < BOUND(a.size()); i++ ) { result += a.at(i); // hillarious that, while writing THIS VERY DEMO, on first go, I actaully wrote it a[i] } return result; } #ifdef WITHHARNESS #include int main( int argc, char ** argv ) { vector v(5); v.at(0) = 3.14; v.at(1) = 3.14; v.at(2) = 3.14; v.at(3) = 3.14; v.at(4) = 3.14; float answer = f(v); cout << "answer: " << answer << endl; } #endif // g++ array-boundcheck-removal-stdvec.cpp -DWITHHARNESS -DBADBOUNDS // ./a.out // Aborted: terminate called after throwing an instance of 'std::out_of_range' // g++ array-boundcheck-removal-stdvec.cpp -DWITHHARNESS // ./a.out // answer: 15.7 // g++ array-boundcheck-removal-stdvec.cpp -S -O2 -DBADBOUNDS // loop has cmp-jmp // jmp target has call _ZSt24__throw_out_of_range_fmtPKcz@PLT // g++ array-boundcheck-removal-stdvec.cpp -S -O2 // loop is clean #elif TESTCASE==2 //#include #define assert(prop) if (!prop) return typedef vector > mat; void matmul( mat & a, mat & b, mat & rslt ) { size_t m = rslt.size(); assert( m == a.size() ); size_t p = b.size(); for ( int i = 0; i < BOUND(m); i++ ) { assert( p == a.at(i).size() ); size_t n = rslt.at(i).size(); for ( int j = 0; j < BOUND(n); j++ ) { rslt.at(i).at(j) = 0.0; for ( int k = 0; k < BOUND(p); k++ ) { assert(b.at(k).size() == n); // asking to check it too often rslt.at(i).at(j) += a.at(i).at(k) * b.at(k).at(j); } } } } #ifdef WITHHARNESS #include int main( int argc, char ** argv ) { mat a(5, vector(6)); mat b(6, vector(7)); mat r(5, vector(7)); matmul(a, b, r); } #endif // (modify the declarations in main to be off by one, each of the 6 values at a time) // g++ array-boundcheck-removal-stdvec.cpp -DWITHHARNESS -DTESTCASE=2 // ./a.out // (see an assertion failure) // g++ array-boundcheck-removal-stdvec.cpp -DWITHHARNESS -DTESTCASE=2 // ./a.out // (runs fine) // g++ array-boundcheck-removal-stdvec.cpp -S -O2 -DTESTCASE=2 // hypothesis: loop bound checks are clean because the assertions took care of it // actual so far: both assertions and bound checks survived #endif