1 /*
2     Copyright (c) 2005-2020 Intel Corporation
3 
4     Licensed under the Apache License, Version 2.0 (the "License");
5     you may not use this file except in compliance with the License.
6     You may obtain a copy of the License at
7 
8         http://www.apache.org/licenses/LICENSE-2.0
9 
10     Unless required by applicable law or agreed to in writing, software
11     distributed under the License is distributed on an "AS IS" BASIS,
12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13     See the License for the specific language governing permissions and
14     limitations under the License.
15 */
16 
17 // Program for basic correctness testing of assembly-language routines.
18 #include "harness_defs.h"
19 //for ICC builtins mode the test will be skipped as
20 //macro __TBB_GCC_BUILTIN_ATOMICS_PRESENT used to define __TBB_TEST_SKIP_GCC_BUILTINS_MODE
21 //will not be defined (it is explicitly disabled for ICC)
22 #if __TBB_TEST_SKIP_GCC_BUILTINS_MODE
23 #include "harness.h"
TestMain()24 int TestMain() {
25     REPORT("Known issue: GCC builtins aren't available\n");
26     return Harness::Skipped;
27 }
28 #else
29 
30 #include "tbb/task.h"
31 
32 #include <new>
33 #include "harness.h"
34 
35 using tbb::internal::reference_count;
36 
37 //TODO: remove this function when atomic function __TBB_XXX are dropped
38 //! Test __TBB_CompareAndSwapW
TestCompareExchange()39 static void TestCompareExchange() {
40     ASSERT( intptr_t(-10)<10, "intptr_t not a signed integral type?" );
41     REMARK("testing __TBB_CompareAndSwapW\n");
42     for( intptr_t a=-10; a<10; ++a )
43         for( intptr_t b=-10; b<10; ++b )
44             for( intptr_t c=-10; c<10; ++c ) {
45 // Workaround for a bug in GCC 4.3.0; and one more is below.
46 #if __TBB_GCC_OPTIMIZER_ORDERING_BROKEN
47                 intptr_t x;
48                 __TBB_store_with_release( x, a );
49 #else
50                 intptr_t x = a;
51 #endif
52                 intptr_t y = __TBB_CompareAndSwapW(&x,b,c);
53                 ASSERT( y==a, NULL );
54                 if( a==c )
55                     ASSERT( x==b, NULL );
56                 else
57                     ASSERT( x==a, NULL );
58             }
59 }
60 
61 //TODO: remove this function when atomic function __TBB_XXX are dropped
62 //! Test __TBB___TBB_FetchAndIncrement and __TBB___TBB_FetchAndDecrement
TestAtomicCounter()63 static void TestAtomicCounter() {
64     // "canary" is a value used to detect illegal overwrites.
65     const reference_count canary = ~(uintptr_t)0/3;
66     REMARK("testing __TBB_FetchAndIncrement\n");
67     struct {
68         reference_count prefix, i, suffix;
69     } x;
70     x.prefix = canary;
71     x.i = 0;
72     x.suffix = canary;
73     for( int k=0; k<10; ++k ) {
74         reference_count j = __TBB_FetchAndIncrementWacquire((volatile void *)&x.i);
75         ASSERT( x.prefix==canary, NULL );
76         ASSERT( x.suffix==canary, NULL );
77         ASSERT( x.i==k+1, NULL );
78         ASSERT( j==k, NULL );
79     }
80     REMARK("testing __TBB_FetchAndDecrement\n");
81     x.i = 10;
82     for( int k=10; k>0; --k ) {
83         reference_count j = __TBB_FetchAndDecrementWrelease((volatile void *)&x.i);
84         ASSERT( j==k, NULL );
85         ASSERT( x.i==k-1, NULL );
86         ASSERT( x.prefix==canary, NULL );
87         ASSERT( x.suffix==canary, NULL );
88     }
89 }
90 
TestTinyLock()91 static void TestTinyLock() {
92     REMARK("testing __TBB_LockByte\n");
93     __TBB_atomic_flag flags[16];
94     for( unsigned int i=0; i<16; ++i )
95         flags[i] = (__TBB_Flag)i;
96 #if __TBB_GCC_OPTIMIZER_ORDERING_BROKEN
97     __TBB_store_with_release( flags[8], 0 );
98 #else
99     flags[8] = 0;
100 #endif
101     __TBB_LockByte(flags[8]);
102     for( unsigned int i=0; i<16; ++i )
103         #ifdef __sparc
104         ASSERT( flags[i]==(i==8?0xff:i), NULL );
105         #else
106         ASSERT( flags[i]==(i==8?1:i), NULL );
107         #endif
108     __TBB_UnlockByte(flags[8]);
109     for( unsigned int i=0; i<16; ++i )
110         ASSERT( flags[i] == (i==8?0:i), NULL );
111 }
112 
TestLog2()113 static void TestLog2() {
114     REMARK("testing __TBB_Log2\n");
115     for( uintptr_t i=1; i; i<<=1 ) {
116         for( uintptr_t j=1; j<1<<16; ++j ) {
117             if( uintptr_t k = i*j ) {
118                 uintptr_t actual = __TBB_Log2(k);
119                 const uintptr_t ONE = 1; // warning suppression again
120                 ASSERT( k >= ONE<<actual, NULL );
121                 ASSERT( k>>1 < ONE<<actual, NULL );
122             }
123         }
124     }
125 }
126 
TestPause()127 static void TestPause() {
128     REMARK("testing __TBB_Pause\n");
129     __TBB_Pause(1);
130 }
131 
TestTimeStamp()132 static void TestTimeStamp() {
133     REMARK("testing __TBB_time_stamp");
134 #if defined(__TBB_time_stamp)
135     tbb::internal::machine_tsc_t prev = __TBB_time_stamp();
136     for ( int i=0; i<1000; ++i ) {
137         tbb::internal::machine_tsc_t curr = __TBB_time_stamp();
138         ASSERT(curr>prev, "__TBB_time_stamp has returned non-monotonically increasing quantity");
139         prev=curr;
140     }
141     REMARK("\n");
142 #else
143     REMARK(" skipped\n");
144 #endif
145 }
146 
TestMain()147 int TestMain () {
148     __TBB_TRY {
149         TestLog2();
150         TestTinyLock();
151         TestCompareExchange();
152         TestAtomicCounter();
153         TestPause();
154         TestTimeStamp();
155     } __TBB_CATCH(...) {
156         ASSERT(0,"unexpected exception");
157     }
158     return Harness::Done;
159 }
160 #endif // __TBB_TEST_SKIP_BUILTINS_MODE
161